Version 1.23.0-dev.0.0

Merge 7993dac4f18fb2540a2444dc06a5b86b82835006 into dev
diff --git a/.gitignore b/.gitignore
index 8cdeac8..4313fda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@
 *.iml
 .idea
 CMakeLists.txt
+.clang_complete
 
 # Built by chromebot and downloaded from Google Storage
 client/tests/drt
@@ -75,3 +76,6 @@
 editor/util/testing/mac/DartEditor.suite/Results
 editor/util/testing/mac/Samples.suite/Results
 .test-outcome.log
+/outline.dill
+/generated/
+/crash_logs/
diff --git a/.packages b/.packages
index 8900db8..fdf45db 100644
--- a/.packages
+++ b/.packages
@@ -9,6 +9,7 @@
 analysis_server:pkg/analysis_server/lib
 analyzer:pkg/analyzer/lib
 analyzer_cli:pkg/analyzer_cli/lib
+analyzer_plugin:pkg/analyzer_plugin/lib
 args:third_party/pkg/args/lib
 async:third_party/pkg/async/lib
 async_helper:pkg/async_helper/lib
@@ -27,7 +28,6 @@
 convert:third_party/pkg/convert/lib
 crypto:third_party/pkg/crypto/lib
 csslib:third_party/pkg/csslib/lib
-dart2js_incremental:pkg/dart2js_incremental/lib
 dart2js_info:third_party/pkg/dart2js_info/lib
 dart_messages:pkg/dart_messages/lib
 dart_style:third_party/pkg_tested/dart_style/lib
@@ -89,7 +89,8 @@
 stream_channel:third_party/pkg/stream_channel/lib
 string_scanner:third_party/pkg/string_scanner/lib
 test:third_party/pkg/test/lib
-testing:third_party/testing/lib
+test_dart:tools/testing/dart
+testing:pkg/testing/lib
 test_reflective_loader:third_party/pkg/test_reflective_loader/lib
 typed_data:third_party/pkg/typed_data/lib
 typed_mock:pkg/typed_mock/lib
diff --git a/.travis.yml b/.travis.yml
index 7e4d785..24d69ac 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -78,7 +78,10 @@
   - ANALYZER=master
   - ANALYZER=master DDC_BROWSERS=Firefox
   - ANALYZER=master DDC_BROWSERS=ChromeCanaryTravis
-  - ANALYZER=master CXX=clang++
+  # TODO(vsm): We don't get much value from this for DDC & it eats up travis
+  # cycles.  Consider adding back at some point to test the built dartdevc
+  # snapshot.
+  # - ANALYZER=master CXX=clang++
   - TEST=coverage
   - TEST=package
 matrix:
diff --git a/BUILD.gn b/BUILD.gn
index 033a324..d97f0a7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -45,6 +45,19 @@
   ]
 }
 
+group("runtime_kernel") {
+  if (defined(is_fuchsia) && (is_fuchsia || is_fuchsia_host)) {
+    # Fuchsia has run_vm_tests marked testonly.
+    testonly = true
+  }
+  deps = [
+    ":runtime",
+
+    # TODO(rmacnak): Link this into 'dart'
+    "utils/kernel-service:kernel-service",
+  ]
+}
+
 group("runtime_precompiled") {
   deps = [
     "runtime/bin:dart_bootstrap($host_toolchain)",
@@ -122,9 +135,7 @@
     rebase_path("$root_gen_dir"),
   ]
   if (defined(is_fuchsia) && is_fuchsia_host) {
-    args += [
-      "--copy_libs"
-    ]
+    args += [ "--copy_libs" ]
   }
 }
 
@@ -173,11 +184,10 @@
   ]
 }
 
-
 # The rules below build a qemu Fuchsia OS image that includes the Dart tree
 # under /system/test/dart. Building this image is gated by the GN argument
 # 'dart_build_fuchsia_test_image' because building the image is slow.
-if (defined(is_fuchsia) && (is_fuchsia)) {
+if (defined(is_fuchsia) && is_fuchsia) {
   declare_args() {
     dart_build_fuchsia_test_image = false
   }
@@ -217,10 +227,10 @@
     action("generate_dart_test_image") {
       testonly = true
       deps = [
-        "runtime/bin:dart",
-        "runtime/bin:run_vm_tests",
-        "runtime/bin:process_test",
         ":generate_dart_test_manifest",
+        "runtime/bin:dart",
+        "runtime/bin:process_test",
+        "runtime/bin:run_vm_tests",
       ]
 
       input = "$target_gen_dir/dart_test_tree.manifest"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3fce2e6..57fbfc4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,13 @@
-## 1.22.0
+## 1.23.0
+
+### Core library changes
+* `dart:core`: Added `Uri.isScheme` function to check the scheme of a URI.
+   Example: `uri.isScheme("http")`. Ignores case when comparing.
+* `dart:io`: Added functions `File.lastAccessed`, `File.lastAccessedSync`,
+  `File.setLastModified`, `File.setLastModifiedSync`, `File.setLastAccessed`,
+  and `File.setLastAccessedSync`.
+
+## 1.22.0 - 2017-02-14
 
 ### Language
 
@@ -76,7 +85,7 @@
 
     ```dart
     Predator predator = new Cat(); // Upcast.
-    predator(new Seal()); // Cats can't eat seals!
+    predator.chaseAndEat(new Seal()); // Cats can't eat seals!
     ```
 
     To preserve soundness in strong mode, in the body of a method that uses a
diff --git a/DEPS b/DEPS
index 156d98c..50498e5 100644
--- a/DEPS
+++ b/DEPS
@@ -27,10 +27,8 @@
   # Only use this temporarily while waiting for a mirror for a new package.
   "github_dartlang": "https://github.com/dart-lang/%s.git",
 
-  "github_testing": "https://github.com/peter-ahe-google/testing.git",
-
   "gyp_rev": "@6ee91ad8659871916f9aa840d42e1513befdf638",
-  "co19_rev": "@cf831f58ac65f68f14824c0b1515f6b7814d94b8",
+  "co19_rev": "@4af9ef149be554216c5bb16cbac8e50d4c28cdf1",
 
   # Revisions of GN related dependencies.
   "buildtools_revision": "@39b1db2ab4aa4b2ccaa263c29bdf63e7c1ee28aa",
@@ -57,7 +55,7 @@
   "convert_tag": "@2.0.1",
   "crypto_tag" : "@2.0.1",
   "csslib_tag" : "@0.13.2",
-  "dart2js_info_tag" : "@0.5.0",
+  "dart2js_info_tag" : "@0.5.3+1",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
   "dart_style_tag": "@0.2.16",
   "dartdoc_tag" : "@v0.9.8+1",
@@ -72,7 +70,7 @@
   "idl_parser_rev": "@7fbe68cab90c38147dee4f48c30ad0d496c17915",
   "initialize_tag": "@v0.6.2+2",
   "intl_tag": "@0.14.0",
-  "isolate_tag": "@0.2.3",
+  "isolate_tag": "@1.0.0",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@2.0.2",
   "linter_rev": "@89f93362c5b48ef5192d77e9a28cf9590542669b",
@@ -111,7 +109,6 @@
   "stream_channel_tag": "@1.5.0",
   "string_scanner_tag": "@1.0.0",
   "sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
-  "testing_rev": "@2e196d51c147411a93a949109656be93626bda49",
   "test_reflective_loader_tag": "@0.1.0",
   "test_tag": "@0.12.15+6",
   "typed_data_tag": "@1.1.3",
@@ -318,8 +315,6 @@
       Var("sunflower_rev"),
   Var("dart_root") + "/third_party/pkg/test":
       (Var("github_mirror") % "test") + Var("test_tag"),
-  Var("dart_root") + "/third_party/testing":
-      Var("github_testing") + Var("testing_rev"),
   Var("dart_root") + "/third_party/pkg/test_reflective_loader":
       (Var("github_mirror") % "test_reflective_loader") +
       Var("test_reflective_loader_tag"),
diff --git a/client/idea/.idea/.name b/client/idea/.idea/.name
new file mode 100644
index 0000000..ca18b64
--- /dev/null
+++ b/client/idea/.idea/.name
@@ -0,0 +1 @@
+SDK repo
\ No newline at end of file
diff --git a/client/idea/.idea/inspectionProfiles/Project_Default.xml b/client/idea/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..9b0c20c
--- /dev/null
+++ b/client/idea/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,10 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="DartOutdatedDependencies" enabled="false" level="WARNING" enabled_by_default="false" />
+    <inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
+      <option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
+      <option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
+    </inspection_tool>
+  </profile>
+</component>
\ No newline at end of file
diff --git a/client/idea/.idea/modules.xml b/client/idea/.idea/modules.xml
new file mode 100644
index 0000000..549209e
--- /dev/null
+++ b/client/idea/.idea/modules.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/../../pkg/analysis_server/analysis_server.iml" filepath="$PROJECT_DIR$/../../pkg/analysis_server/analysis_server.iml" />
+      <module fileurl="file://$PROJECT_DIR$/../../pkg/analyzer/analyzer.iml" filepath="$PROJECT_DIR$/../../pkg/analyzer/analyzer.iml" />
+      <module fileurl="file://$PROJECT_DIR$/../../pkg/analyzer_cli/analyzer_cli.iml" filepath="$PROJECT_DIR$/../../pkg/analyzer_cli/analyzer_cli.iml" />
+      <module fileurl="file://$PROJECT_DIR$/../../pkg/analyzer_plugin/analyzer_plugin.iml" filepath="$PROJECT_DIR$/../../pkg/analyzer_plugin/analyzer_plugin.iml" />
+      <module fileurl="file://$PROJECT_DIR$/../../pkg/front_end/front_end.iml" filepath="$PROJECT_DIR$/../../pkg/front_end/front_end.iml" />
+      <module fileurl="file://$PROJECT_DIR$/../../pkg/meta/meta.iml" filepath="$PROJECT_DIR$/../../pkg/meta/meta.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/client/idea/.idea/vcs.xml b/client/idea/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/client/idea/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/client/idea/readme.md b/client/idea/readme.md
new file mode 100644
index 0000000..f463828
--- /dev/null
+++ b/client/idea/readme.md
@@ -0,0 +1,20 @@
+# Working on the SDK repo using IntelliJ
+
+To work on Dart code in the SDK repo, we recommend either IntelliJ Community
+Edition or IntelliJ Ultimate.
+
+## Opening from IntelliJ
+
+To open the sdk repo using IntelliJ, choose `File` > `Open...` and select the
+`<sdk>/client/idea` directory.
+
+## Opening from the command-line
+
+To open from the command-line, type:
+
+```
+idea <sdk>/client/idea
+```
+
+This depends on having previously set up the IntelliJ command-line launcher. To
+do this, from the `Tools` menu, select `Create Command-line Launcher...`.
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 158a10f..b0c749c 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -27,6 +27,8 @@
 % - An await-for loop only pauses the subscription if it does something async.
 % - Assert statements may now also include a "message" operand.
 % - The Null type is now considered a subtype of all types in most cases.
+% - Specify what NEWLINE means in multiline strings.
+% - Specified the FutureOf type.
 %
 % 1.14
 % - The call "C()" where "C" is a class name, is a now compile-time error.
@@ -2807,7 +2809,7 @@
 \end{grammar}
 
 \LMHash{}
-A string can be either a sequence of single line strings or a multiline string.
+A string can be a sequence of single line strings and multiline strings.
 
 \begin{grammar}
  {\bf singleLineString:}`{\escapegrammar \code{"}}' stringContentDQ* `{\escapegrammar \code{"}}';
@@ -2828,10 +2830,7 @@
 }
 
 \LMHash{}
-Adjacent
-%single line
-strings are implicitly concatenated to form a single string literal.
-%, and so are adjacent multiline strings, but the two forms may not be mixed.
+Adjacent strings are implicitly concatenated to form a single string literal.
 
 
 \commentary{Here is an example}
@@ -2851,7 +2850,7 @@
 \end{dartCode}
 
 \rationale{ which this prints  'A simple sum: 2 + 2 = 22' rather than 'A simple sum: 2 + 2 = 4'.
-However, the use the concatenation operation is still  discouraged for efficiency reasons. Instead, the recommended Dart idiom is to use string interpolation.
+However, the use of the concatenation operation is still discouraged for efficiency reasons. Instead, the recommended Dart idiom is to use string interpolation.
 }
 
 \begin{dartCode}
@@ -2876,22 +2875,22 @@
 
 
 \begin{grammar}
- {\bf multilineString:}`{\escapegrammar \texttt{"""}}' stringContentTDQ*   `{\escapegrammar \texttt{"""}}';
-      `{\escapegrammar \code{'}\code{'}\code{'}}' stringContentTSQ* `{\escapegrammar \code{'}\code{'}\code{'}}';
-      `r' `{\escapegrammar \texttt{"""}}'  (\~{} `{\escapegrammar \texttt{"""}}')*   `{\escapegrammar \texttt{"""}}';
-      `r' `{\escapegrammar \code{'}\code{'}\code{'}}' (\~{} `{\escapegrammar \code{'}\code{'}\code{'}}')* `{\escapegrammar \code{'}\code{'}\code{'}}'
-    .
+  {\bf multilineString:}`{\escapegrammar \texttt{"""}}' stringContentTDQ* `{\escapegrammar \texttt{"""}}';
+    `{\escapegrammar \code{'}\code{'}\code{'}}' stringContentTSQ* `{\escapegrammar \code{'}\code{'}\code{'}}';
+    `r' `{\escapegrammar \texttt{"""}}' (\~{} `{\escapegrammar \texttt{"""}}')* `{\escapegrammar \texttt{"""}}';
+    `r' `{\escapegrammar \code{'}\code{'}\code{'}}' (\~{} `{\escapegrammar \code{'}\code{'}\code{'}}')* `{\escapegrammar \code{'}\code{'}\code{'}}'
+  .
 
 
-    {\bf ESCAPE\_SEQUENCE:} `$\backslash$ n';
+  {\bf ESCAPE\_SEQUENCE:}`$\backslash$ n';
     `$\backslash$ r';
-   `$\backslash$ f';
-   `$\backslash$ b';
-  `$\backslash$ t';
-   `$\backslash$ v';
-  `$\backslash$ x' HEX\_DIGIT HEX\_DIGIT;
-   `$\backslash$ u' HEX\_DIGIT HEX\_DIGIT HEX\_DIGIT HEX\_DIGIT;
-   `$\backslash$ u\{' HEX\_DIGIT\_SEQUENCE `\}'
+    `$\backslash$ f';
+    `$\backslash$ b';
+    `$\backslash$ t';
+    `$\backslash$ v';
+    `$\backslash$ x' HEX\_DIGIT HEX\_DIGIT;
+    `$\backslash$ u' HEX\_DIGIT HEX\_DIGIT HEX\_DIGIT HEX\_DIGIT;
+    `$\backslash$ u\{' HEX\_DIGIT\_SEQUENCE `\}'
   .
 
 {\bf HEX\_DIGIT\_SEQUENCE:}
@@ -2901,12 +2900,11 @@
 \end{grammar}
 
 \LMHash{}
-Multiline strings are delimited by either matching triples of single quotes or matching triples of double quotes. If the first line of a multiline string consists solely of the whitespace characters defined by the production {\em WHITESPACE}  \ref{lexicalRules}), possibly prefixed by $\backslash$, then that line is ignored, including the new line at its end.
+Multiline strings are delimited by either matching triples of single quotes or matching triples of double quotes. If the first line of a multiline string consists solely of the whitespace characters defined by the production {\em WHITESPACE} \ref{lexicalRules}), possibly prefixed by $\backslash$, then that line is ignored, including the line break at its end.
 
-
- \rationale{
- The idea is to ignore whitespace, where whitespace is defined as tabs, spaces and newlines. These can be represented directly, but since for most characters prefixing by backslash is an identity, we allow those forms as well.
- }
+\rationale{
+The idea is to ignore a whitespace-only first line of a multiline string, where whitespace is defined as tabs, spaces and the final line break. These can be represented directly, but since for most characters prefixing by backslash is an identity in a non-raw string, we allow those forms as well.
+}
 
  % could be clearer. Is the first line in  """\t
  %    """ ignored not. It depends if we mean whitespace before escapes are interpreted,
@@ -2915,7 +2913,7 @@
 \LMHash{}
 Strings support escape sequences for special characters. The escapes are:
 \begin{itemize}
-\item  $\backslash$n for newline, equivalent to $\backslash$x0A.
+\item $\backslash$n for newline, equivalent to $\backslash$x0A.
 \item $\backslash$r for carriage return, equivalent to $\backslash$x0D.
 \item $\backslash$f for form feed, equivalent to $\backslash$x0C.
 \item $\backslash$b for backspace, equivalent to $\backslash$x08.
@@ -2934,6 +2932,10 @@
 Any string may be prefixed with the character `r', indicating that it is a {\em raw string}, in which case no escapes or interpolations are recognized.
 
 \LMHash{}
+Line breaks in a multiline string are represented by the {\em NEWLINE} production.
+A line break introduces a single newline character into the string value.
+
+\LMHash{}
 It is a compile-time error if a non-raw string literal contains a character sequence of the form $\backslash$x that is not followed by a sequence of two hexadecimal digits. It is a compile-time error if a non-raw string literal  contains a character sequence of the form $\backslash$u that is not followed by either a sequence of four hexadecimal digits, or by curly brace delimited sequence of hexadecimal digits.
 
 
@@ -2959,7 +2961,8 @@
     .
 
 {\bf NEWLINE:}$\backslash$ n;
-      $\backslash$ r
+      $\backslash$ r;
+      $\backslash$ r $\backslash$ n
     .
 
  \end{grammar}
@@ -7226,11 +7229,11 @@
     .
 
 {\bf typeArguments:}
-      '<' typeList '>'
+      `<' typeList `>'
     .
 
 {\bf typeList:}
-      type (',' type)*
+      type (`,' type)*
     .
  \end{grammar}
 
@@ -7651,6 +7654,29 @@
 \LMHash{}
 The name \DYNAMIC{} denotes a \cd{Type} object even though \DYNAMIC{} is not a class.
 
+\LMHash{}
+The built-in type declaration \code{FutureOr},
+which is declared in the library \code{dart:async},
+defines a generic type with one type parameter (\ref{generics}).
+If the \code{FutureOr} type, optionally followed by type arguments,
+is used as a type, it denotes the \DYNAMIC{} type.
+As such, the \code{FutureOr} type cannot be used where \DYNAMIC{} cannot be
+used as a type.
+If the type arguments applied to \code{FutureOr} would issue static warnings
+if applied to a normal generic class with one type parameter,
+the same warnings are issued for \code{FutureOr},
+even though the type arguments are otherwise ignored.
+The name \code{FutureOr} as an expression
+denotes the same \cd{Type} object as \DYNAMIC{}.
+
+\rationale{
+The \code{FutureOr} type is reserved for future use,
+for cases where a value can be either an instance of the type \metavar{type}
+or the type \code{Future<\metavar{type}>}. Such cases occur naturally
+in asynchronous code.
+Using \code{FutureOr} instead of \DYNAMIC{} will allow some tools
+to provide a more precise type analysis.
+}
 %\rationale {
 %Type objects reify the runtime types of instances. No instance ever has type \DYNAMIC{}.
 %}
diff --git a/pkg/analysis_server/.gitignore b/pkg/analysis_server/.gitignore
deleted file mode 100644
index 16a1724..0000000
--- a/pkg/analysis_server/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.packages
diff --git a/pkg/analysis_server/CONTRIBUTING.md b/pkg/analysis_server/CONTRIBUTING.md
index 6f5e0ea..242f214 100644
--- a/pkg/analysis_server/CONTRIBUTING.md
+++ b/pkg/analysis_server/CONTRIBUTING.md
@@ -1,33 +1,40 @@
-Want to contribute? Great! First, read this page (including the small print at
-the end).
+## Contributing
 
-### Before you contribute
-Before we can use your code, you must sign the
-[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
-(CLA), which you can do online. The CLA is necessary mainly because you own the
-copyright to your changes, even after your contribution becomes part of our
-codebase, so we need your permission to use and distribute your code. We also
-need to be sure of various other things—for instance that you'll tell us if you
-know that your code infringes on other people's patents. You don't have to sign
-the CLA until after you've submitted your code for review and a member has
-approved it, but you must do it before we can put your code into our codebase.
+Contributions welcome! Please follow the guide in [Contributing][contributing].
 
-Before you start working on a larger contribution, you should get in touch with
-us first through the issue tracker with your idea so that we can help out and
-possibly guide you. Coordinating up front makes it much easier to avoid
-frustration later on.
+## Building
 
-### Code reviews
-All submissions, including submissions by project members, require review.
+If you want to build Dart yourself, here is a guide to
+[getting the source, preparing your machine to build the SDK, and
+building][building].
 
-### File headers
-All files in the project must start with the following header.
+There are more documents on our [wiki](https://github.com/dart-lang/sdk/wiki).
+Once set up to build the SDK, run:
 
-    // 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.
+```
+./tools/build.py -mrelease create_sdk
+```
 
-### The small print
-Contributions made by corporations are covered by a different agreement than the
-one above, the
-[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate).
+## Running tests
+
+To run analyzer tests:
+
+```
+./tools/test.py -mrelease pkg/analyzer/test/
+```
+
+To run all analysis server tests:
+
+```
+./tools/test.py -mrelease pkg/analysis_server/test/
+```
+
+To run just the analysis server integration tests:
+
+```
+./tools/test.py -mrelease pkg/analysis_server/test/integration/
+```
+
+
+[building]: https://github.com/dart-lang/sdk/wiki/Building
+[contributing]: https://github.com/dart-lang/sdk/wiki/Contributing
diff --git a/pkg/analysis_server/analysis_server.iml b/pkg/analysis_server/analysis_server.iml
new file mode 100644
index 0000000..2cf6a6c
--- /dev/null
+++ b/pkg/analysis_server/analysis_server.iml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.pub" />
+      <excludeFolder url="file://$MODULE_DIR$/benchmark/integration/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/benchmark/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/benchmark/perf/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/bin/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/analysis/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/channel/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/edit/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/analysis/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/completion/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/execution/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/search/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/server/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/operation/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/plugin/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/search/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/completion/dart/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/completion/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/correction/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/dependencies/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/index/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/linter/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/refactoring/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/services/search/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/source/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/plugin/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/utilities/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/stress/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/stress/replay/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/stress/utilities/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/timing/completion/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/timing/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/instrumentation/log/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/instrumentation/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/instrumentation/page/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/spec/generated/java/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/spec/generated/java/types/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/spec/generated/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/spec/packages" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Dart SDK" level="application" />
+    <orderEntry type="library" name="Dart SDK" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 0f5bcc7..e6ad6ea 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -3477,12 +3477,12 @@
           </dd><dt class="field"><b>offset (int)</b></dt><dd>
             
             <p>
-              The offset of the region from which the user can navigate.
+              The offset of the region to which the user can navigate.
             </p>
           </dd><dt class="field"><b>length (int)</b></dt><dd>
             
             <p>
-              The length of the region from which the user can navigate.
+              The length of the region to which the user can navigate.
             </p>
           </dd><dt class="field"><b>startLine (int)</b></dt><dd>
             
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index 7b5d3d5..d2159d2 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -13,7 +13,9 @@
     show getExportedElement;
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_context.dart';
 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/dart.dart' show LIBRARY_ELEMENT4;
@@ -31,6 +33,11 @@
  */
 abstract class DartFixContext implements FixContext {
   /**
+   * The provider for parsed or resolved ASTs.
+   */
+  AstProvider get astProvider;
+
+  /**
    * The function to get top-level declarations from.
    */
   GetTopLevelDeclarations get getTopLevelDeclarations;
@@ -65,7 +72,10 @@
       return Fix.EMPTY_LIST;
     }
     DartFixContext dartContext = new DartFixContextImpl(
-        context, _getTopLevelDeclarations(analysisContext), unit);
+        context,
+        _getTopLevelDeclarations(analysisContext),
+        new AstProviderForContext(analysisContext),
+        unit);
     return internalComputeFixes(dartContext);
   }
 
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index 2f69d0a..9a11d6a 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -12555,12 +12555,12 @@
   }
 
   /**
-   * The offset of the region from which the user can navigate.
+   * The offset of the region to which the user can navigate.
    */
   int get offset => _offset;
 
   /**
-   * The offset of the region from which the user can navigate.
+   * The offset of the region to which the user can navigate.
    */
   void set offset(int value) {
     assert(value != null);
@@ -12568,12 +12568,12 @@
   }
 
   /**
-   * The length of the region from which the user can navigate.
+   * The length of the region to which the user can navigate.
    */
   int get length => _length;
 
   /**
-   * The length of the region from which the user can navigate.
+   * The length of the region to which the user can navigate.
    */
   void set length(int value) {
     assert(value != null);
@@ -15537,7 +15537,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ConvertGetterToMethodFeedback {
+class ConvertGetterToMethodFeedback extends RefactoringFeedback {
   @override
   bool operator==(other) {
     if (other is ConvertGetterToMethodFeedback) {
@@ -15556,7 +15556,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ConvertGetterToMethodOptions {
+class ConvertGetterToMethodOptions extends RefactoringOptions {
   @override
   bool operator==(other) {
     if (other is ConvertGetterToMethodOptions) {
@@ -15575,7 +15575,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ConvertMethodToGetterFeedback {
+class ConvertMethodToGetterFeedback extends RefactoringFeedback {
   @override
   bool operator==(other) {
     if (other is ConvertMethodToGetterFeedback) {
@@ -15594,7 +15594,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ConvertMethodToGetterOptions {
+class ConvertMethodToGetterOptions extends RefactoringOptions {
   @override
   bool operator==(other) {
     if (other is ConvertMethodToGetterOptions) {
@@ -15622,7 +15622,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ExtractLocalVariableFeedback extends RefactoringFeedback implements HasToJson {
+class ExtractLocalVariableFeedback extends RefactoringFeedback {
   List<int> _coveringExpressionOffsets;
 
   List<int> _coveringExpressionLengths;
@@ -15804,7 +15804,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ExtractLocalVariableOptions extends RefactoringOptions implements HasToJson {
+class ExtractLocalVariableOptions extends RefactoringOptions {
   String _name;
 
   bool _extractAll;
@@ -15918,7 +15918,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ExtractMethodFeedback extends RefactoringFeedback implements HasToJson {
+class ExtractMethodFeedback extends RefactoringFeedback {
   int _offset;
 
   int _length;
@@ -16182,7 +16182,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class ExtractMethodOptions extends RefactoringOptions implements HasToJson {
+class ExtractMethodOptions extends RefactoringOptions {
   String _returnType;
 
   bool _createGetter;
@@ -16383,7 +16383,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class InlineLocalVariableFeedback extends RefactoringFeedback implements HasToJson {
+class InlineLocalVariableFeedback extends RefactoringFeedback {
   String _name;
 
   int _occurrences;
@@ -16474,7 +16474,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class InlineLocalVariableOptions {
+class InlineLocalVariableOptions extends RefactoringOptions {
   @override
   bool operator==(other) {
     if (other is InlineLocalVariableOptions) {
@@ -16500,7 +16500,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class InlineMethodFeedback extends RefactoringFeedback implements HasToJson {
+class InlineMethodFeedback extends RefactoringFeedback {
   String _className;
 
   String _methodName;
@@ -16625,7 +16625,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class InlineMethodOptions extends RefactoringOptions implements HasToJson {
+class InlineMethodOptions extends RefactoringOptions {
   bool _deleteSource;
 
   bool _inlineAll;
@@ -16725,7 +16725,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class MoveFileFeedback {
+class MoveFileFeedback extends RefactoringFeedback {
   @override
   bool operator==(other) {
     if (other is MoveFileFeedback) {
@@ -16749,7 +16749,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class MoveFileOptions extends RefactoringOptions implements HasToJson {
+class MoveFileOptions extends RefactoringOptions {
   String _newFile;
 
   /**
@@ -16828,7 +16828,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class RenameFeedback extends RefactoringFeedback implements HasToJson {
+class RenameFeedback extends RefactoringFeedback {
   int _offset;
 
   int _length;
@@ -16976,7 +16976,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-class RenameOptions extends RefactoringOptions implements HasToJson {
+class RenameOptions extends RefactoringOptions {
   String _newName;
 
   /**
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index dcce078..1ea9e8d 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -37,12 +37,15 @@
 import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/pub_package_map_provider.dart';
 import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_context.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart' as nd;
 import 'package:analyzer/src/dart/analysis/file_byte_store.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart' as nd;
 import 'package:analyzer/src/dart/analysis/status.dart' as nd;
 import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -379,7 +382,7 @@
     }
     if (resourceProvider is PhysicalResourceProvider) {
       byteStore = new MemoryCachingByteStore(
-          new FileByteStore(
+          new EvictingFileByteStore(
               resourceProvider.getStateLocation('.analysis-driver').path,
               1024 * 1024 * 1024 /*1 GiB*/),
           64 * 1024 * 1024 /*64 MiB*/);
@@ -427,7 +430,7 @@
     if (options.enableNewAnalysisDriver) {
       searchEngine = new SearchEngineImpl2(driverMap.values);
     } else if (index != null) {
-      searchEngine = new SearchEngineImpl(index);
+      searchEngine = new SearchEngineImpl(index, getAstProvider);
     }
     pubSummaryManager =
         new PubSummaryManager(resourceProvider, '${io.pid}.temp');
@@ -634,6 +637,19 @@
     }
   }
 
+  /**
+   * Return the [AstProvider] for the given [path].
+   */
+  AstProvider getAstProvider(String path) {
+    if (options.enableNewAnalysisDriver) {
+      var analysisDriver = getAnalysisDriver(path);
+      return new AstProviderForDriver(analysisDriver);
+    } else {
+      var analysisContext = getAnalysisContext(path);
+      return new AstProviderForContext(analysisContext);
+    }
+  }
+
   CompilationUnitElement getCompilationUnitElement(String file) {
     ContextSourcePair pair = getContextSourcePair(file);
     if (pair == null) {
@@ -821,6 +837,23 @@
     return null;
   }
 
+// TODO(brianwilkerson) Add the following method after 'prioritySources' has
+// been added to InternalAnalysisContext.
+//  /**
+//   * Return a list containing the full names of all of the sources that are
+//   * priority sources.
+//   */
+//  List<String> getPriorityFiles() {
+//    List<String> priorityFiles = new List<String>();
+//    folderMap.values.forEach((ContextDirectory directory) {
+//      InternalAnalysisContext context = directory.context;
+//      context.prioritySources.forEach((Source source) {
+//        priorityFiles.add(source.fullName);
+//      });
+//    });
+//    return priorityFiles;
+//  }
+
   /**
    * Return a [Future] that completes with the resolved [CompilationUnit] for
    * the Dart file with the given [path], or with `null` if the file is not a
@@ -846,23 +879,6 @@
     });
   }
 
-// TODO(brianwilkerson) Add the following method after 'prioritySources' has
-// been added to InternalAnalysisContext.
-//  /**
-//   * Return a list containing the full names of all of the sources that are
-//   * priority sources.
-//   */
-//  List<String> getPriorityFiles() {
-//    List<String> priorityFiles = new List<String>();
-//    folderMap.values.forEach((ContextDirectory directory) {
-//      InternalAnalysisContext context = directory.context;
-//      context.prioritySources.forEach((Source source) {
-//        priorityFiles.add(source.fullName);
-//      });
-//    });
-//    return priorityFiles;
-//  }
-
   /**
    * Handle a [request] that was read from the communication channel.
    */
@@ -1820,9 +1836,6 @@
   nd.AnalysisDriver addAnalysisDriver(Folder folder, AnalysisOptions options) {
     ContextBuilder builder = createContextBuilder(folder, options);
     nd.AnalysisDriver analysisDriver = builder.buildDriver(folder.path);
-    analysisDriver.status.listen((status) {
-      // TODO(scheglov) send server status
-    });
     analysisDriver.results.listen((result) {
       new_sendErrorNotification(analysisServer, result);
       String path = result.path;
@@ -1868,8 +1881,11 @@
       // IMPLEMENTED
     });
     analysisDriver.exceptions.listen((nd.ExceptionResult result) {
-      AnalysisEngine.instance.logger
-          .logError('Analysis failed: ${result.path}', result.exception);
+      String message = 'Analysis failed: ${result.path}';
+      if (result.contextKey != null) {
+        message += ' context: ${result.contextKey}';
+      }
+      AnalysisEngine.instance.logger.logError(message, result.exception);
     });
     analysisServer.driverMap[folder] = analysisDriver;
     return analysisDriver;
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 1e3b807..5648d88 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -82,7 +82,9 @@
         AstNode parent = expression.parent;
         DartType staticType = null;
         DartType propagatedType = expression.propagatedType;
-        if (element == null || element is VariableElement) {
+        if (element is ParameterElement) {
+          staticType = element.type;
+        } else if (element == null || element is VariableElement) {
           staticType = expression.staticType;
         }
         if (parent is MethodInvocation && parent.methodName == expression) {
@@ -106,6 +108,9 @@
   }
 
   String _computeDocumentation(Element element) {
+    if (element is FieldFormalParameterElement) {
+      element = (element as FieldFormalParameterElement).field;
+    }
     if (element is ParameterElement) {
       element = element.enclosingElement;
     }
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index c8faf13..d564850 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -705,10 +705,12 @@
     var analyzer = options[AnalyzerOptions.analyzer];
     if (analyzer is Map) {
       // Set ignore patterns.
-      YamlList exclude = analyzer[AnalyzerOptions.exclude];
-      List<String> excludeList = toStringList(exclude);
-      if (excludeList != null) {
-        setIgnorePatternsForContext(info, excludeList);
+      var exclude = analyzer[AnalyzerOptions.exclude];
+      if (exclude is YamlList) {
+        List<String> excludeList = toStringList(exclude);
+        if (excludeList != null) {
+          setIgnorePatternsForContext(info, excludeList);
+        }
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 424815d..391f299 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -173,6 +173,7 @@
         server.onFileAnalysisComplete(file);
     if (analysisFuture == null) {
       server.sendResponse(new Response.getNavigationInvalidFile(request));
+      return;
     }
     analysisFuture.then((AnalysisDoneReason reason) async {
       switch (reason) {
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 436254e..2afb7d4 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -19,7 +19,7 @@
 
 /**
  * Instances of the class [CompletionDomainHandler] implement a [RequestHandler]
- * that handles requests in the search domain.
+ * that handles requests in the completion domain.
  */
 class CompletionDomainHandler implements RequestHandler {
   /**
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index 5524426..29449c5 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 
@@ -97,10 +98,23 @@
       return new Response.invalidParameter(request, 'id',
           'There is no execution context with an id of $contextId');
     }
-    AnalysisContext context = server.getContainingContext(path);
-    if (context == null) {
-      return new Response.invalidExecutionContext(request, contextId);
+
+    SourceFactory sourceFactory;
+    AnalysisDriver driver;
+    if (server.options.enableNewAnalysisDriver) {
+      driver = server.getAnalysisDriver(path);
+      if (driver == null) {
+        return new Response.invalidExecutionContext(request, contextId);
+      }
+      sourceFactory = driver.sourceFactory;
+    } else {
+      AnalysisContext context = server.getContainingContext(path);
+      if (context == null) {
+        return new Response.invalidExecutionContext(request, contextId);
+      }
+      sourceFactory = context.sourceFactory;
     }
+
     String file = params.file;
     String uri = params.uri;
     if (file != null) {
@@ -115,16 +129,22 @@
         return new Response.invalidParameter(
             request, 'file', 'Must not refer to a directory');
       }
-      ContextSourcePair contextSource = server.getContextSourcePair(file);
-      Source source = contextSource.source;
+
+      Source source;
+      if (server.options.enableNewAnalysisDriver) {
+        source = driver.fsState.getFileForPath(file).source;
+      } else {
+        ContextSourcePair contextSource = server.getContextSourcePair(file);
+        source = contextSource.source;
+      }
       if (source.uriKind != UriKind.FILE_URI) {
         uri = source.uri.toString();
       } else {
-        uri = context.sourceFactory.restoreUri(source).toString();
+        uri = sourceFactory.restoreUri(source).toString();
       }
       return new ExecutionMapUriResult(uri: uri).toResponse(request.id);
     } else if (uri != null) {
-      Source source = context.sourceFactory.forUri(uri);
+      Source source = sourceFactory.forUri(uri);
       if (source == null) {
         return new Response.invalidParameter(request, 'uri', 'Invalid URI');
       }
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index e848fbe..9c66d24 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -29,6 +29,7 @@
 import 'package:analyzer/error/error.dart' as engine;
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart' as engine;
 import 'package:analyzer/src/error/codes.dart' as engine;
 import 'package:analyzer/src/generated/engine.dart' as engine;
@@ -195,6 +196,7 @@
                 server.resourceProvider,
                 result.driver.getTopLevelNameDeclarations,
                 resolutionMap.elementDeclaredByCompilationUnit(unit).context,
+                server.getAstProvider(file),
                 unit,
                 error);
             List<Fix> fixes =
@@ -420,7 +422,7 @@
         // try CONVERT_METHOD_TO_GETTER
         if (element is ExecutableElement) {
           Refactoring refactoring = new ConvertMethodToGetterRefactoring(
-              searchEngine, _getResolvedUnit, element);
+              searchEngine, server.getAstProvider(file), element);
           RefactoringStatus status = await refactoring.checkInitialConditions();
           if (!status.hasFatalError) {
             kinds.add(RefactoringKind.CONVERT_METHOD_TO_GETTER);
@@ -428,8 +430,8 @@
         }
         // try RENAME
         {
-          RenameRefactoring renameRefactoring =
-              new RenameRefactoring(searchEngine, element);
+          RenameRefactoring renameRefactoring = new RenameRefactoring(
+              searchEngine, server.getAstProvider(file), element);
           if (renameRefactoring != null) {
             kinds.add(RefactoringKind.RENAME);
           }
@@ -453,17 +455,11 @@
     return Response.DELAYED_RESPONSE;
   }
 
-  Future<CompilationUnit> _getResolvedUnit(Element element) {
-    String path = element.source.fullName;
-    return server.getResolvedCompilationUnit(path);
-  }
-
   /**
    * Initializes [refactoringManager] with a new instance.
    */
   void _newRefactoringManager() {
-    refactoringManager =
-        new _RefactoringManager(server, _getResolvedUnit, searchEngine);
+    refactoringManager = new _RefactoringManager(server, searchEngine);
   }
 
   static int _getNumberOfScanParseErrors(List<engine.AnalysisError> errors) {
@@ -516,13 +512,16 @@
   final engine.AnalysisContext analysisContext;
 
   @override
+  final AstProvider astProvider;
+
+  @override
   final CompilationUnit unit;
 
   @override
   final engine.AnalysisError error;
 
   _DartFixContextImpl(this.resourceProvider, this.getTopLevelDeclarations,
-      this.analysisContext, this.unit, this.error);
+      this.analysisContext, this.astProvider, this.unit, this.error);
 }
 
 /**
@@ -540,7 +539,6 @@
       const <RefactoringProblem>[];
 
   final AnalysisServer server;
-  final GetResolvedUnit getResolvedUnit;
   final SearchEngine searchEngine;
   StreamSubscription subscriptionToReset;
 
@@ -557,7 +555,7 @@
   Request request;
   EditGetRefactoringResult result;
 
-  _RefactoringManager(this.server, this.getResolvedUnit, this.searchEngine) {
+  _RefactoringManager(this.server, this.searchEngine) {
     _reset();
   }
 
@@ -587,8 +585,10 @@
    * Cancels processing of the current request and cleans up.
    */
   void cancel() {
-    server.sendResponse(new Response.refactoringRequestCancelled(request));
-    request = null;
+    if (request != null) {
+      server.sendResponse(new Response.refactoringRequestCancelled(request));
+      request = null;
+    }
     _reset();
   }
 
@@ -739,8 +739,8 @@
       if (element != null) {
         if (element is ExecutableElement) {
           _resetOnAnalysisStarted();
-          refactoring =
-              new ConvertGetterToMethodRefactoring(searchEngine, element);
+          refactoring = new ConvertGetterToMethodRefactoring(
+              searchEngine, server.getAstProvider(file), element);
         }
       }
     }
@@ -750,7 +750,7 @@
         if (element is ExecutableElement) {
           _resetOnAnalysisStarted();
           refactoring = new ConvertMethodToGetterRefactoring(
-              searchEngine, getResolvedUnit, element);
+              searchEngine, server.getAstProvider(file), element);
         }
       }
     }
@@ -779,7 +779,8 @@
       CompilationUnit unit = await server.getResolvedCompilationUnit(file);
       if (unit != null) {
         _resetOnFileResolutionChanged(file);
-        refactoring = new InlineLocalRefactoring(searchEngine, unit, offset);
+        refactoring = new InlineLocalRefactoring(
+            searchEngine, server.getAstProvider(file), unit, offset);
       }
     }
     if (kind == RefactoringKind.INLINE_METHOD) {
@@ -787,7 +788,7 @@
       if (unit != null) {
         _resetOnAnalysisStarted();
         refactoring = new InlineMethodRefactoring(
-            searchEngine, getResolvedUnit, unit, offset);
+            searchEngine, server.getAstProvider(file), unit, offset);
       }
     }
     if (kind == RefactoringKind.MOVE_FILE) {
@@ -813,7 +814,8 @@
         }
         // do create the refactoring
         _resetOnAnalysisStarted();
-        refactoring = new RenameRefactoring(searchEngine, element);
+        refactoring = new RenameRefactoring(
+            searchEngine, server.getAstProvider(file), element);
         feedback =
             new RenameFeedback(node.offset, node.length, 'kind', 'oldName');
       }
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_locator.dart b/pkg/analysis_server/lib/src/plugin/plugin_locator.dart
new file mode 100644
index 0000000..ac7c1f0
--- /dev/null
+++ b/pkg/analysis_server/lib/src/plugin/plugin_locator.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * An object used to locate a plugin within a package.
+ */
+class PluginLocator {
+  /**
+   * The key used in the `pubspec.yaml` file to specify the location of the
+   * analysis plugin.
+   */
+  static const String analysisPluginKey = 'analysis_plugin';
+
+  /**
+   * The name of the default plugin directory, located within the `tools`
+   * directory.
+   */
+  static const String defaultPluginFolderName = 'analysis_plugin';
+
+  /**
+   * The name of the `pubspec.yaml` file.
+   */
+  static const String pubspecFileName = 'pubspec.yaml';
+
+  /**
+   * The name of the `tools` directory, in which the default plugin directory is
+   * located.
+   */
+  static const String toolsFolderName = 'tools';
+
+  /**
+   * The resource provider used to access the file system.
+   */
+  final ResourceProvider resourceProvider;
+
+  /**
+   * Initialize a newly created plugin locator to use the given
+   * [resourceProvider] to access the file system.
+   */
+  PluginLocator(this.resourceProvider);
+
+  /**
+   * Given the root directory of a package (the [packageRoot]), return the path
+   * to the plugin associated with the package, or `null` if there is no plugin
+   * associated with the package.
+   *
+   * This will look first in the `pubspec.yaml` file in the package root for a
+   * key indicating where the plugin is located. If such a key is not defined,
+   * then it will fall back to a well known location within the package.
+   *
+   * This method does not validate the content of the plugin directory before
+   * returning it.
+   */
+  String findPlugin(String packageRoot) {
+    Folder packageFolder = resourceProvider.getFolder(packageRoot);
+    File pubspecFile = packageFolder.getChildAssumingFile(pubspecFileName);
+    if (pubspecFile.exists) {
+      try {
+        YamlDocument document = loadYamlDocument(pubspecFile.readAsStringSync(),
+            sourceUrl: pubspecFile.toUri());
+        YamlNode contents = document.contents;
+        if (contents is YamlMap) {
+          String pluginPath = contents[analysisPluginKey];
+          Folder pluginFolder =
+              packageFolder.getChildAssumingFolder(pluginPath);
+          if (pluginFolder.exists) {
+            return pluginFolder.path;
+          }
+        }
+      } catch (exception) {
+        // If we can't read the file, or if it isn't valid YAML, then ignore it.
+      }
+    }
+    Folder pluginFolder = packageFolder
+        .getChildAssumingFolder(toolsFolderName)
+        .getChildAssumingFolder(defaultPluginFolderName);
+    if (pluginFolder.exists) {
+      return pluginFolder.path;
+    }
+    return null;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/plugin/result_collector.dart b/pkg/analysis_server/lib/src/plugin/result_collector.dart
new file mode 100644
index 0000000..f89e5d3
--- /dev/null
+++ b/pkg/analysis_server/lib/src/plugin/result_collector.dart
@@ -0,0 +1,124 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A function used to determine whether results should be collected for the
+ * file with the given [path].
+ */
+typedef bool ShouldCollectPredicate(String path);
+
+/**
+ * An object used to collect partial results (of type [E]) where the partial
+ * results are contributed by plugins.
+ */
+class ResultCollector<E> {
+  /**
+   * The id used as a plugin id for contributions from the server.
+   */
+  final String serverId;
+
+  /**
+   * A function used to determine whether results should be collected for the
+   * file whose path is passed in as an argument.
+   */
+  final ShouldCollectPredicate _shouldCollect;
+
+  /**
+   * A multi-keyed map, where the first key is the (normalized and absolute)
+   * path to the file associated with the results, and the second is the id of
+   * the plugin that provided the partial results. The value is the partial
+   * results contrinuted by the plugin for the file.
+   */
+  Map<String, Map<String, E>> resultMap = <String, Map<String, E>>{};
+
+  /**
+   * Initialize a newly created result manager.
+   */
+  ResultCollector(this.serverId, {ShouldCollectPredicate predicate})
+      : _shouldCollect = predicate;
+
+  /**
+   * Clear any results that have been contributed for the file with the given
+   * [filePath], but continue to collect results for the file. This is used when
+   * the results for the specified file are known to be invalid, typically
+   * because the content of the file has been modified.
+   */
+  void clearResultsForFile(String filePath) {
+    resultMap[filePath]?.clear();
+  }
+
+  /**
+   * Clear any results that have been contributed by the plugin with the given
+   * [pluginId].
+   */
+  void clearResultsFromPlugin(String pluginId) {
+    for (Map<String, E> partialResults in resultMap.values) {
+      partialResults.remove(pluginId);
+    }
+  }
+
+  /**
+   * Return an iterator producing the partial results that have been contributed
+   * for the given [filePath].
+   */
+  List<E> getResults(String filePath) {
+    Map<String, E> partialResultMap = resultMap[filePath];
+    if (partialResultMap == null) {
+      return <E>[];
+    }
+    List<E> values = partialResultMap.values.toList();
+    //
+    // Ensure that the server's contributions are always first in the list.
+    //
+    E serverContributions = partialResultMap[serverId];
+    if (serverContributions != null && values.remove(serverContributions)) {
+      values.insert(0, serverContributions);
+    }
+    return values;
+  }
+
+  /**
+   * Return `true` if this collector is collecting results associated with the
+   * given [filePath].
+   */
+  bool isCollectingFor(String filePath) {
+    if (_shouldCollect != null) {
+      return _shouldCollect(filePath);
+    }
+    return resultMap.containsKey(filePath);
+  }
+
+  /**
+   * Record the [partialResults] as having been contributed for the given
+   * [filePath] by the plugin with the given [pluginId].
+   */
+  void putResults(String filePath, String pluginId, E partialResults) {
+    Map<String, E> fileResults = resultMap[filePath];
+    if (fileResults == null) {
+      if (_shouldCollect != null && _shouldCollect(filePath)) {
+        resultMap[filePath] = <String, E>{pluginId: partialResults};
+      }
+    } else {
+      fileResults[pluginId] = partialResults;
+    }
+  }
+
+  /**
+   * Start collecting results contributed for the file with the given
+   * [filePath]. Unless the collector is told to collect results for a file, any
+   * results that are contributed for that file are discarded.
+   */
+  void startCollectingFor(String filePath) {
+    resultMap.putIfAbsent(filePath, () => <String, E>{});
+  }
+
+  /**
+   * Stop collecting results contributed for the file with the given [filePath].
+   * Until the collector is told to start collecting results for the file, any
+   * results that are contributed for the file are discarded.
+   */
+  void stopCollectingFor(String filePath) {
+    resultMap.remove(filePath);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/plugin/result_converter.dart b/pkg/analysis_server/lib/src/plugin/result_converter.dart
new file mode 100644
index 0000000..a2d0994
--- /dev/null
+++ b/pkg/analysis_server/lib/src/plugin/result_converter.dart
@@ -0,0 +1,92 @@
+// 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:analysis_server/plugin/protocol/protocol.dart' as server;
+import 'package:analysis_server/src/protocol/protocol_internal.dart' as server;
+import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+
+/**
+ * An object used to convert between similar objects defined by both the plugin
+ * protocol and the server protocol.
+ */
+class ResultConverter {
+  /**
+   * The decoder used to decode Json representations of server objects.
+   */
+  static final server.ResponseDecoder decoder =
+      new server.ResponseDecoder(null);
+
+  server.AnalysisError convertAnalysisError(plugin.AnalysisError error) {
+    return new server.AnalysisError.fromJson(decoder, '', error.toJson());
+  }
+
+  server.AnalysisErrorFixes convertAnalysisErrorFixes(
+      plugin.AnalysisErrorFixes fixes) {
+    List<server.SourceChange> changes = fixes.fixes
+        .map((plugin.PrioritizedSourceChange change) =>
+            convertPrioritizedSourceChange(change))
+        .toList();
+    return new server.AnalysisErrorFixes(convertAnalysisError(fixes.error),
+        fixes: changes);
+  }
+
+  server.AnalysisNavigationParams convertAnalysisNavigationParams(
+      plugin.AnalysisNavigationParams params) {
+    return new server.AnalysisNavigationParams.fromJson(
+        decoder, '', params.toJson());
+  }
+
+  server.CompletionSuggestion convertCompletionSuggestion(
+      plugin.CompletionSuggestion suggestion) {
+    return new server.CompletionSuggestion.fromJson(
+        decoder, '', suggestion.toJson());
+  }
+
+  server.EditGetRefactoringResult convertEditGetRefactoringResult(
+      plugin.RefactoringKind kind, plugin.EditGetRefactoringResult result) {
+    return new server.EditGetRefactoringResult.fromJson(
+        new server.ResponseDecoder(convertRefactoringKind(kind)),
+        '',
+        result.toJson());
+  }
+
+  server.FoldingRegion convertFoldingRegion(plugin.FoldingRegion region) {
+    return new server.FoldingRegion.fromJson(decoder, '', region.toJson());
+  }
+
+  server.HighlightRegion convertHighlightRegion(plugin.HighlightRegion region) {
+    return new server.HighlightRegion.fromJson(decoder, '', region.toJson());
+  }
+
+  server.Occurrences convertOccurrences(plugin.Occurrences occurrences) {
+    return new server.Occurrences.fromJson(decoder, '', occurrences.toJson());
+  }
+
+  server.Outline convertOutline(plugin.Outline outline) {
+    return new server.Outline.fromJson(decoder, '', outline.toJson());
+  }
+
+  server.SourceChange convertPrioritizedSourceChange(
+      plugin.PrioritizedSourceChange change) {
+    return convertSourceChange(change.change);
+  }
+
+  server.RefactoringFeedback convertRefactoringFeedback(
+      plugin.RefactoringKind kind, plugin.RefactoringFeedback feedback) {
+    return new server.RefactoringFeedback.fromJson(
+        new server.ResponseDecoder(convertRefactoringKind(kind)),
+        '',
+        feedback.toJson(),
+        null);
+  }
+
+  server.RefactoringKind convertRefactoringKind(
+      plugin.RefactoringKind feedback) {
+    return new server.RefactoringKind.fromJson(decoder, '', feedback.toJson());
+  }
+
+  server.SourceChange convertSourceChange(plugin.SourceChange change) {
+    return new server.SourceChange.fromJson(decoder, '', change.toJson());
+  }
+}
diff --git a/pkg/analysis_server/lib/src/plugin/result_merger.dart b/pkg/analysis_server/lib/src/plugin/result_merger.dart
new file mode 100644
index 0000000..b76656d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/plugin/result_merger.dart
@@ -0,0 +1,827 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart'
+    hide AnalysisErrorFixes;
+import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:meta/meta.dart';
+
+/**
+ * An object used to merge partial lists of results that were contributed by
+ * plugins.
+ *
+ * All of the methods in this class assume that the contributions from the
+ * analysis server are the first partial result in the list of partial results
+ * to be merged.
+ */
+class ResultMerger {
+  /**
+   * Return a list of fixes composed by merging the lists of fixes in the
+   * [partialResultList].
+   *
+   * The resulting list of fixes will contain exactly one fix for every analysis
+   * error for which there are fixes. If two or more plugins contribute the same
+   * fix for a given error, the resulting list will contain duplications.
+   */
+  List<plugin.AnalysisErrorFixes> mergeAnalysisErrorFixes(
+      List<List<plugin.AnalysisErrorFixes>> partialResultList) {
+    /**
+     * Return a key encoding the unique attributes of the given [error].
+     */
+    String computeKey(plugin.AnalysisError error) {
+      StringBuffer buffer = new StringBuffer();
+      buffer.write(error.location.offset);
+      buffer.write(';');
+      buffer.write(error.code);
+      buffer.write(';');
+      buffer.write(error.message);
+      buffer.write(';');
+      buffer.write(error.correction);
+      return buffer.toString();
+    }
+
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <plugin.AnalysisErrorFixes>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    Map<String, plugin.AnalysisErrorFixes> fixesMap =
+        <String, plugin.AnalysisErrorFixes>{};
+    for (plugin.AnalysisErrorFixes fix in partialResultList[0]) {
+      fixesMap[computeKey(fix.error)] = fix;
+    }
+    for (int i = 1; i < count; i++) {
+      for (plugin.AnalysisErrorFixes fix in partialResultList[i]) {
+        String key = computeKey(fix.error);
+        plugin.AnalysisErrorFixes mergedFix = fixesMap[key];
+        if (mergedFix == null) {
+          fixesMap[key] = fix;
+        } else {
+          // If more than two plugins contribute fixes for the same error, this
+          // will result in extra copy operations.
+          List<plugin.PrioritizedSourceChange> mergedChanges =
+              mergedFix.fixes.toList();
+          mergedChanges.addAll(fix.fixes);
+          plugin.AnalysisErrorFixes copiedFix = new plugin.AnalysisErrorFixes(
+              mergedFix.error,
+              fixes: mergedChanges);
+          fixesMap[key] = copiedFix;
+        }
+      }
+    }
+    List<plugin.AnalysisErrorFixes> mergedFixes = fixesMap.values.toList();
+    for (plugin.AnalysisErrorFixes fixes in mergedFixes) {
+      fixes.fixes.sort((first, second) => first.priority - second.priority);
+    }
+    return mergedFixes;
+  }
+
+  /**
+   * Return a list of errors composed by merging the lists of errors in the
+   * [partialResultList].
+   *
+   * The resulting list will contain all of the analysis errors from all of the
+   * plugins. If two or more plugins contribute the same error the resulting
+   * list will contain duplications.
+   */
+  List<AnalysisError> mergeAnalysisErrors(
+      List<List<AnalysisError>> partialResultList) {
+    // TODO(brianwilkerson) Consider merging duplicate errors (same code,
+    // location, and messages). If we do that, we should return the logical-or
+    // of the hasFix fields from the merged errors.
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <AnalysisError>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<AnalysisError> mergedErrors = <AnalysisError>[];
+    for (List<AnalysisError> partialResults in partialResultList) {
+      mergedErrors.addAll(partialResults);
+    }
+    return mergedErrors;
+  }
+
+  /**
+   * Return a list of suggestions composed by merging the lists of suggestions
+   * in the [partialResultList].
+   *
+   * The resulting list will contain all of the suggestions from all of the
+   * plugins. If two or more plugins contribute the same suggestion the
+   * resulting list will contain duplications.
+   */
+  List<CompletionSuggestion> mergeCompletionSuggestions(
+      List<List<CompletionSuggestion>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <CompletionSuggestion>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<CompletionSuggestion> mergedSuggestions = <CompletionSuggestion>[];
+    for (List<CompletionSuggestion> partialResults in partialResultList) {
+      mergedSuggestions.addAll(partialResults);
+    }
+    return mergedSuggestions;
+  }
+
+  /**
+   * Return a list of regions composed by merging the lists of regions in the
+   * [partialResultList].
+   *
+   * The resulting list will contain all of the folding regions from all of the
+   * plugins. If a plugin contributes a folding region that overlaps a region
+   * from a previous plugin, the overlapping region will be omitted. (For these
+   * purposes, if either region is fully contained within the other they are not
+   * considered to be overlapping.)
+   */
+  List<FoldingRegion> mergeFoldingRegions(
+      List<List<FoldingRegion>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <FoldingRegion>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<FoldingRegion> mergedRegions = partialResultList[0].toList();
+
+    /**
+     * Return `true` if the [newRegion] does not overlap any of the regions in
+     * the collection of [mergedRegions].
+     */
+    bool isNonOverlapping(FoldingRegion newRegion) {
+      int newStart = newRegion.offset;
+      int newEnd = newStart + newRegion.length;
+      for (FoldingRegion existingRegion in mergedRegions) {
+        int existingStart = existingRegion.offset;
+        int existingEnd = existingStart + existingRegion.length;
+        if (overlaps(newStart, newEnd, existingStart, existingEnd,
+            allowNesting: true)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    for (int i = 1; i < count; i++) {
+      List<FoldingRegion> partialResults = partialResultList[i];
+      for (FoldingRegion region in partialResults) {
+        if (isNonOverlapping(region)) {
+          mergedRegions.add(region);
+        }
+      }
+    }
+    return mergedRegions;
+  }
+
+  /**
+   * Return a list of regions composed by merging the lists of regions in the
+   * [partialResultList].
+   *
+   * The resulting list will contain all of the highlight regions from all of
+   * the plugins. If two or more plugins contribute the same highlight region
+   * the resulting list will contain duplications.
+   */
+  List<HighlightRegion> mergeHighlightRegions(
+      List<List<HighlightRegion>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <HighlightRegion>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<HighlightRegion> mergedRegions = <HighlightRegion>[];
+    for (List<HighlightRegion> partialResults in partialResultList) {
+      mergedRegions.addAll(partialResults);
+    }
+    return mergedRegions;
+  }
+
+  /**
+   * Return navigation notification parameters composed by merging the
+   * parameters in the [partialResultList].
+   *
+   * The resulting list will contain all of the navigation regions from all of
+   * the plugins. If a plugin contributes a navigation region that overlaps a
+   * region from a previous plugin, the overlapping region will be omitted. (For
+   * these purposes, nested regions are considered to be overlapping.)
+   */
+  AnalysisNavigationParams mergeNavigation(
+      List<AnalysisNavigationParams> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return null;
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    AnalysisNavigationParams base = partialResultList[0];
+    String file = base.file;
+    List<NavigationRegion> mergedRegions = base.regions.toList();
+    List<NavigationTarget> mergedTargets = base.targets.toList();
+    List<String> mergedFiles = base.files.toList();
+
+    /**
+     * Return `true` if the [newRegion] does not overlap any of the regions in
+     * the collection of [mergedRegions].
+     */
+    bool isNonOverlapping(NavigationRegion newRegion) {
+      int newStart = newRegion.offset;
+      int newEnd = newStart + newRegion.length;
+      for (NavigationRegion mergedRegion in mergedRegions) {
+        int mergedStart = mergedRegion.offset;
+        int mergedEnd = mergedStart + mergedRegion.length;
+        if (overlaps(newStart, newEnd, mergedStart, mergedEnd)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    /**
+     * Return the index of the region in the collection of [mergedRegions] that
+     * covers exactly the same region as the [newRegion], or `-1` if there is no
+     * such region.
+     */
+    int matchingRegion(newRegion) {
+      int newOffset = newRegion.offset;
+      int newLength = newRegion.length;
+      for (int i = 0; i < mergedRegions.length; i++) {
+        NavigationRegion mergedRegion = mergedRegions[i];
+        if (newOffset == mergedRegion.offset &&
+            newLength == mergedRegion.length) {
+          return i;
+        }
+      }
+      return -1;
+    }
+
+    for (int i = 1; i < count; i++) {
+      // For now we take the optimistic approach of assuming that most or all of
+      // the regions will not overlap and that we therefore don't need to remove
+      // any unreferenced files or targets from the lists. If that isn't true
+      // then this could result in server sending more data to the client than
+      // is necessary.
+      AnalysisNavigationParams result = partialResultList[i];
+      List<NavigationRegion> regions = result.regions;
+      List<NavigationTarget> targets = result.targets;
+      List<String> files = result.files;
+      //
+      // Merge the file data.
+      //
+      Map<int, int> fileMap = <int, int>{};
+      for (int j = 0; j < files.length; j++) {
+        String file = files[j];
+        int index = mergedFiles.indexOf(file);
+        if (index < 0) {
+          index = mergedFiles.length;
+          mergedFiles.add(file);
+        }
+        fileMap[j] = index;
+      }
+      //
+      // Merge the target data.
+      //
+      Map<int, int> targetMap = <int, int>{};
+      for (int j = 0; j < targets.length; j++) {
+        NavigationTarget target = targets[j];
+        int newIndex = fileMap[target.fileIndex];
+        if (target.fileIndex != newIndex) {
+          target = new NavigationTarget(target.kind, newIndex, target.offset,
+              target.length, target.startLine, target.startColumn);
+        }
+        int index = mergedTargets.indexOf(target);
+        if (index < 0) {
+          index = mergedTargets.length;
+          mergedTargets.add(target);
+        }
+        targetMap[j] = index;
+      }
+      //
+      // Merge the region data.
+      //
+      for (int j = 0; j < regions.length; j++) {
+        NavigationRegion region = regions[j];
+        List<int> newTargets = region.targets
+            .map((int oldTarget) => targetMap[oldTarget])
+            .toList();
+        if (region.targets != newTargets) {
+          region =
+              new NavigationRegion(region.offset, region.length, newTargets);
+        }
+        int index = matchingRegion(region);
+        if (index >= 0) {
+          NavigationRegion mergedRegion = mergedRegions[index];
+          List<int> mergedTargets = mergedRegion.targets;
+          bool added = false;
+          for (int target in region.targets) {
+            if (!mergedTargets.contains(target)) {
+              if (added) {
+                mergedTargets.add(target);
+              } else {
+                //
+                // This is potentially inefficient. If a merged region matches
+                // regions from multiple plugins it will be copied multiple
+                // times. The likelihood seems small enough to not warrant
+                // optimizing this further.
+                //
+                mergedTargets = mergedTargets.toList();
+                mergedTargets.add(target);
+                mergedRegion = new NavigationRegion(
+                    mergedRegion.offset, mergedRegion.length, mergedTargets);
+                mergedRegions[index] = mergedRegion;
+                added = true;
+              }
+            }
+          }
+          if (added) {
+            mergedTargets.sort();
+          }
+        } else if (isNonOverlapping(region)) {
+          mergedRegions.add(region);
+        }
+      }
+    }
+    return new AnalysisNavigationParams(
+        file, mergedRegions, mergedTargets, mergedFiles);
+  }
+
+  /**
+   * Return a list of occurrences composed by merging the lists of occurrences
+   * in the [partialResultList].
+   *
+   * The resulting list of occurrences will contain exactly one occurrences for
+   * every element for which there is at least one occurrences. If two or more
+   * plugins contribute an occurrences for the same element, the resulting
+   * occurrences for that element will include all of the locations from all of
+   * the plugins without duplications.
+   */
+  List<Occurrences> mergeOccurrences(
+      List<List<Occurrences>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <Occurrences>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    Map<Element, Set<int>> elementMap = <Element, Set<int>>{};
+    for (List<Occurrences> partialResults in partialResultList) {
+      for (Occurrences occurances in partialResults) {
+        Element element = occurances.element;
+        Set<int> offsets =
+            elementMap.putIfAbsent(element, () => new HashSet<int>());
+        offsets.addAll(occurances.offsets);
+      }
+    }
+    List<Occurrences> mergedOccurrences = <Occurrences>[];
+    elementMap.forEach((Element element, Set<int> offsets) {
+      List<int> sortedOffsets = offsets.toList();
+      sortedOffsets.sort();
+      mergedOccurrences
+          .add(new Occurrences(element, sortedOffsets, element.name.length));
+    });
+    return mergedOccurrences;
+  }
+
+  /**
+   * Return a list of outlines composed by merging the lists of outlines in the
+   * [partialResultList].
+   *
+   * The resulting list of outlines will contain ...
+   *
+   * Throw an exception if any of the outlines are associated with an element
+   * that does not have a location.
+   *
+   * Throw an exception if any outline has children that are also children of
+   * another outline. No exception is thrown if a plugin contributes a top-level
+   * outline that is a child of an outline contributed by a different plugin.
+   */
+  List<Outline> mergeOutline(List<List<Outline>> partialResultList) {
+    /**
+     * Return a key encoding the unique attributes of the given [element].
+     */
+    String computeKey(Element element) {
+      Location location = element.location;
+      if (location == null) {
+        throw new StateError(
+            'Elements in an outline are expected to have a location');
+      }
+      StringBuffer buffer = new StringBuffer();
+      buffer.write(location.offset);
+      buffer.write(';');
+      buffer.write(element.kind.name);
+      return buffer.toString();
+    }
+
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <Outline>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<Outline> mergedOutlines = partialResultList[0].toList();
+    Map<String, Outline> outlineMap = <String, Outline>{};
+    Map<Outline, Outline> copyMap = <Outline, Outline>{};
+
+    /**
+     * Add the given [outline] and all of its children to the [outlineMap].
+     */
+    void addToMap(Outline outline) {
+      String key = computeKey(outline.element);
+      if (outlineMap.containsKey(key)) {
+        // TODO(brianwilkerson) Decide how to handle this more gracefully.
+        throw new StateError('Inconsistent outlines');
+      }
+      outlineMap[key] = outline;
+      outline.children?.forEach(addToMap);
+    }
+
+    /**
+     * Merge the children of the [newOutline] into the list of children of the
+     * [mergedOutline].
+     */
+    void mergeChildren(Outline mergedOutline, Outline newOutline) {
+      for (Outline newChild in newOutline.children) {
+        Outline mergedChild = outlineMap[computeKey(newChild.element)];
+        if (mergedChild == null) {
+          // The [newChild] isn't in the existing list.
+          Outline copiedOutline = copyMap.putIfAbsent(
+              mergedOutline,
+              () => new Outline(mergedOutline.element, mergedOutline.offset,
+                  mergedOutline.length,
+                  children: mergedOutline.children.toList()));
+          copiedOutline.children.add(newChild);
+          addToMap(newChild);
+        } else {
+          mergeChildren(mergedChild, newChild);
+        }
+      }
+    }
+
+    mergedOutlines.forEach(addToMap);
+    for (int i = 1; i < count; i++) {
+      for (Outline outline in partialResultList[i]) {
+        Outline mergedOutline = outlineMap[computeKey(outline.element)];
+        if (mergedOutline == null) {
+          // The [outline] does not correspond to any previously merged outline.
+          mergedOutlines.add(outline);
+          addToMap(outline);
+        } else {
+          // The [outline] corresponds to a previously merged outline, so we
+          // just need to add its children to the merged outline's children.
+          mergeChildren(mergedOutline, outline);
+        }
+      }
+    }
+
+    /**
+     * Perform a depth first traversal of the outline structure rooted at the
+     * given [outline] item, re-building each item if any of its children have
+     * been updated by the merge process.
+     */
+    Outline traverse(Outline outline) {
+      Outline copiedOutline = copyMap[outline];
+      bool isCopied = copiedOutline != null;
+      copiedOutline ??= outline;
+      List<Outline> currentChildren = copiedOutline.children;
+      if (currentChildren == null || currentChildren.isEmpty) {
+        return outline;
+      }
+      List<Outline> updatedChildren =
+          currentChildren.map((Outline child) => traverse(child)).toList();
+      if (currentChildren != updatedChildren) {
+        if (!isCopied) {
+          return new Outline(
+              copiedOutline.element, copiedOutline.offset, copiedOutline.length,
+              children: updatedChildren);
+        }
+        copiedOutline.children = updatedChildren;
+        return copiedOutline;
+      }
+      return outline;
+    }
+
+    for (int i = 0; i < mergedOutlines.length; i++) {
+      mergedOutlines[i] = traverse(mergedOutlines[i]);
+    }
+    return mergedOutlines;
+  }
+
+  /**
+   * Return a list of source changes composed by merging the lists of source
+   * changes in the [partialResultList].
+   *
+   * The resulting list will contain all of the source changes from all of the
+   * plugins. If two or more plugins contribute the same source change the
+   * resulting list will contain duplications.
+   */
+  List<plugin.PrioritizedSourceChange> mergePrioritizedSourceChanges(
+      List<List<plugin.PrioritizedSourceChange>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <plugin.PrioritizedSourceChange>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<plugin.PrioritizedSourceChange> mergedChanges =
+        <plugin.PrioritizedSourceChange>[];
+    for (List<plugin.PrioritizedSourceChange> partialResults
+        in partialResultList) {
+      mergedChanges.addAll(partialResults);
+    }
+    mergedChanges.sort((first, second) => first.priority - second.priority);
+    return mergedChanges;
+  }
+
+  /**
+   * Return a refactoring feedback composed by merging the refactoring feedbacks
+   * in the [partialResultList].
+   *
+   * The content of the resulting feedback depends on the kind of feedbacks
+   * being merged.
+   *
+   * Throw an exception if the refactoring feedbacks are of an unhandled type.
+   *
+   * The feedbacks in the [partialResultList] are expected to all be of the same
+   * type. If that expectation is violated, and exception might be thrown.
+   */
+  RefactoringFeedback mergeRefactoringFeedbacks(
+      List<RefactoringFeedback> feedbacks) {
+    int count = feedbacks.length;
+    if (count == 0) {
+      return null;
+    } else if (count == 1) {
+      return feedbacks[0];
+    }
+    RefactoringFeedback first = feedbacks[0];
+    if (first is ConvertGetterToMethodFeedback) {
+      // The feedbacks are empty, so there's nothing to merge.
+      return first;
+    } else if (first is ConvertMethodToGetterFeedback) {
+      // The feedbacks are empty, so there's nothing to merge.
+      return first;
+    } else if (first is ExtractLocalVariableFeedback) {
+      List<int> coveringExpressionOffsets =
+          first.coveringExpressionOffsets == null
+              ? <int>[]
+              : first.coveringExpressionOffsets.toList();
+      List<int> coveringExpressionLengths =
+          first.coveringExpressionLengths == null
+              ? <int>[]
+              : first.coveringExpressionLengths.toList();
+      List<String> names = first.names.toList();
+      List<int> offsets = first.offsets.toList();
+      List<int> lengths = first.lengths.toList();
+      for (int i = 1; i < count; i++) {
+        ExtractLocalVariableFeedback feedback = feedbacks[i];
+        // TODO(brianwilkerson) This doesn't ensure that the covering data is in
+        // the right order and consistent.
+        if (feedback.coveringExpressionOffsets != null) {
+          coveringExpressionOffsets.addAll(feedback.coveringExpressionOffsets);
+        }
+        if (feedback.coveringExpressionLengths != null) {
+          coveringExpressionLengths.addAll(feedback.coveringExpressionLengths);
+        }
+        for (String name in feedback.names) {
+          if (!names.contains(name)) {
+            names.add(name);
+          }
+        }
+        offsets.addAll(feedback.offsets);
+        lengths.addAll(feedback.lengths);
+      }
+      return new ExtractLocalVariableFeedback(names.toList(), offsets, lengths,
+          coveringExpressionOffsets: (coveringExpressionOffsets.isEmpty
+              ? null
+              : coveringExpressionOffsets),
+          coveringExpressionLengths: (coveringExpressionLengths.isEmpty
+              ? null
+              : coveringExpressionLengths));
+    } else if (first is ExtractMethodFeedback) {
+      int offset = first.offset;
+      int length = first.length;
+      String returnType = first.returnType;
+      List<String> names = first.names.toList();
+      bool canCreateGetter = first.canCreateGetter;
+      List<RefactoringMethodParameter> parameters = first.parameters;
+      List<int> offsets = first.offsets.toList();
+      List<int> lengths = first.lengths.toList();
+      for (int i = 1; i < count; i++) {
+        ExtractMethodFeedback feedback = feedbacks[i];
+        if (returnType.isEmpty) {
+          returnType = feedback.returnType;
+        }
+        for (String name in feedback.names) {
+          if (!names.contains(name)) {
+            names.add(name);
+          }
+        }
+        canCreateGetter = canCreateGetter && feedback.canCreateGetter;
+        // TODO(brianwilkerson) This doesn't allow plugins to add parameters.
+        // TODO(brianwilkerson) This doesn't check for duplicate offsets.
+        offsets.addAll(feedback.offsets);
+        lengths.addAll(feedback.lengths);
+      }
+      return new ExtractMethodFeedback(offset, length, returnType,
+          names.toList(), canCreateGetter, parameters, offsets, lengths);
+    } else if (first is InlineLocalVariableFeedback) {
+      int occurrences = first.occurrences;
+      for (int i = 1; i < count; i++) {
+        occurrences +=
+            (feedbacks[i] as InlineLocalVariableFeedback).occurrences;
+      }
+      return new InlineLocalVariableFeedback(first.name, occurrences);
+    } else if (first is InlineMethodFeedback) {
+      // There is nothing in the feedback that can reasonably be extended or
+      // modified by other plugins.
+      return first;
+    } else if (first is MoveFileFeedback) {
+      // The feedbacks are empty, so there's nothing to merge.
+      return first;
+    } else if (first is RenameFeedback) {
+      // There is nothing in the feedback that can reasonably be extended or
+      // modified by other plugins.
+      return first;
+    }
+    throw new StateError(
+        'Unsupported class of refactoring feedback: ${first.runtimeType}');
+  }
+
+  /**
+   * Return a list of refactoring kinds composed by merging the lists of
+   * refactoring kinds in the [partialResultList].
+   *
+   * The resulting list will contain all of the refactoring kinds from all of
+   * the plugins, but will not contain duplicate elements.
+   */
+  List<RefactoringKind> mergeRefactoringKinds(
+      List<List<RefactoringKind>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <RefactoringKind>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    Set<RefactoringKind> mergedKinds = new HashSet<RefactoringKind>();
+    for (List<RefactoringKind> partialResults in partialResultList) {
+      mergedKinds.addAll(partialResults);
+    }
+    return mergedKinds.toList();
+  }
+
+  /**
+   * Return the result for a getRefactorings request composed by merging the
+   * results in the [partialResultList].
+   *
+   * The returned result will contain the concatenation of the initial, options,
+   * and final problems. If two or more plugins produce the same problem, then
+   * the resulting list of problems will contain duplications.
+   *
+   * The returned result will contain a merged list of refactoring feedbacks (as
+   * defined by [mergeRefactoringFeedbacks]) and a merged list of source changes
+   * (as defined by [mergeChanges]).
+   *
+   * The returned result will contain the concatenation of the potential edits.
+   * If two or more plugins produce the same potential edit, then the resulting
+   * list of potential edits will contain duplications.
+   */
+  EditGetRefactoringResult mergeRefactorings(
+      List<EditGetRefactoringResult> partialResultList) {
+    /**
+     * Return the result of merging the given list of source [changes] into a
+     * single source change.
+     *
+     * The resulting change will have the first non-null message and the first
+     * non-null selection. The linked edit groups will be a concatenation of all
+     * of the individual linked edit groups because there's no way to determine
+     * when two such groups should be merged. The resulting list of edits will
+     * be merged at the level of the file being edited, but will be a
+     * concatenation of the individual edits within each file, even if multiple
+     * plugins contribute duplicate or conflicting edits.
+     */
+    SourceChange mergeChanges(List<SourceChange> changes) {
+      int count = changes.length;
+      if (count == 0) {
+        return null;
+      } else if (count == 1) {
+        return changes[0];
+      }
+      SourceChange first = changes[0];
+      String message = first.message;
+      Map<String, SourceFileEdit> editMap = <String, SourceFileEdit>{};
+      for (SourceFileEdit edit in first.edits) {
+        editMap[edit.file] = edit;
+      }
+      List<LinkedEditGroup> linkedEditGroups = first.linkedEditGroups.toList();
+      Position selection = first.selection;
+      for (int i = 1; i < count; i++) {
+        SourceChange change = changes[i];
+        for (SourceFileEdit edit in change.edits) {
+          SourceFileEdit mergedEdit = editMap[edit.file];
+          if (mergedEdit == null) {
+            editMap[edit.file] = edit;
+          } else {
+            // This doesn't detect if multiple plugins contribute the same (or
+            // conflicting) edits.
+            List<SourceEdit> edits = mergedEdit.edits.toList();
+            edits.addAll(edit.edits);
+            editMap[edit.file] = new SourceFileEdit(
+                mergedEdit.file, mergedEdit.fileStamp,
+                edits: edits);
+          }
+        }
+        linkedEditGroups.addAll(change.linkedEditGroups);
+        message ??= change.message;
+        selection ??= change.selection;
+      }
+      return new SourceChange(message,
+          edits: editMap.values.toList(),
+          linkedEditGroups: linkedEditGroups,
+          selection: selection);
+    }
+
+    int count = partialResultList.length;
+    if (count == 0) {
+      return null;
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    EditGetRefactoringResult result = partialResultList[0];
+    List<RefactoringProblem> initialProblems = result.initialProblems.toList();
+    List<RefactoringProblem> optionsProblems = result.optionsProblems.toList();
+    List<RefactoringProblem> finalProblems = result.finalProblems.toList();
+    List<RefactoringFeedback> feedbacks = <RefactoringFeedback>[];
+    if (result.feedback != null) {
+      feedbacks.add(result.feedback);
+    }
+    List<SourceChange> changes = <SourceChange>[];
+    if (result.change != null) {
+      changes.add(result.change);
+    }
+    List<String> potentialEdits = result.potentialEdits.toList();
+    for (int i = 1; i < count; i++) {
+      EditGetRefactoringResult result = partialResultList[1];
+      initialProblems.addAll(result.initialProblems);
+      optionsProblems.addAll(result.optionsProblems);
+      finalProblems.addAll(result.finalProblems);
+      if (result.feedback != null) {
+        feedbacks.add(result.feedback);
+      }
+      if (result.change != null) {
+        changes.add(result.change);
+      }
+      potentialEdits.addAll(result.potentialEdits);
+    }
+    return new EditGetRefactoringResult(
+        initialProblems, optionsProblems, finalProblems,
+        feedback: mergeRefactoringFeedbacks(feedbacks),
+        change: mergeChanges(changes),
+        potentialEdits: potentialEdits);
+  }
+
+  /**
+   * Return a list of source changes composed by merging the lists of source
+   * changes in the [partialResultList].
+   *
+   * The resulting list will contain all of the source changes from all of the
+   * plugins. If two or more plugins contribute the same source change the
+   * resulting list will contain duplications.
+   */
+  List<SourceChange> mergeSourceChanges(
+      List<List<SourceChange>> partialResultList) {
+    int count = partialResultList.length;
+    if (count == 0) {
+      return <SourceChange>[];
+    } else if (count == 1) {
+      return partialResultList[0];
+    }
+    List<SourceChange> mergedChanges = <SourceChange>[];
+    for (List<SourceChange> partialResults in partialResultList) {
+      mergedChanges.addAll(partialResults);
+    }
+    return mergedChanges;
+  }
+
+  /**
+   * Return `true` if a region extending from [leftStart] (inclusive) to
+   * [leftEnd] (exclusive) overlaps a region extending from [rightStart]
+   * (inclusive) to [rightEnd] (exclusive). If [allowNesting] is `true`, then
+   * the regions are allowed to overlap as long as one region is completely
+   * nested within the other region.
+   */
+  @visibleForTesting
+  bool overlaps(int leftStart, int leftEnd, int rightStart, int rightEnd,
+      {bool allowNesting: false}) {
+    if (leftEnd < rightStart || leftStart > rightEnd) {
+      return false;
+    }
+    if (!allowNesting) {
+      return true;
+    }
+    return !((leftStart <= rightStart && rightEnd <= leftEnd) ||
+        (rightStart <= leftStart && leftEnd <= rightEnd));
+  }
+}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index 3fde4ac..6274b4a 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -12,6 +12,10 @@
 
 int _computeArgIndex(AstNode containingNode, Object entity) {
   var argList = containingNode;
+  if (argList is NamedExpression) {
+    entity = argList;
+    argList = argList.parent;
+  }
   if (argList is ArgumentList) {
     NodeList<Expression> args = argList.arguments;
     for (int index = 0; index < args.length; ++index) {
@@ -137,13 +141,14 @@
   /**
    * Compute the appropriate [CompletionTarget] for the given [offset] within
    * the [compilationUnit].
-   * 
+   *
    * Optionally, start the search from within [entryPoint] instead of using
    * the [compilationUnit], which is useful for analyzing ASTs that have no
    * [compilationUnit] such as dart expressions within angular templates.
    */
   factory CompletionTarget.forOffset(
-      CompilationUnit compilationUnit, int offset, {AstNode entryPoint}) {
+      CompilationUnit compilationUnit, int offset,
+      {AstNode entryPoint}) {
     // The precise algorithm is as follows.  We perform a depth-first search of
     // all edges in the parse tree (both those that point to AST nodes and
     // those that point to tokens), visiting parents before children.  The
@@ -160,7 +165,8 @@
     // to.
     entryPoint ??= compilationUnit;
     AstNode containingNode = entryPoint;
-    outerLoop: while (true) {
+    outerLoop:
+    while (true) {
       if (containingNode is Comment) {
         // Comments are handled specially: we descend into any CommentReference
         // child node that contains the cursor offset.
@@ -284,6 +290,9 @@
       return false;
     }
     AstNode parent = containingNode.parent;
+    if (parent is ArgumentList) {
+      parent = parent.parent;
+    }
     if (parent is InstanceCreationExpression) {
       DartType instType = parent.bestType;
       if (instType != null) {
@@ -294,7 +303,8 @@
               ? intTypeElem.getNamedConstructor(constructorName.name)
               : intTypeElem.unnamedConstructor;
           return constructor != null &&
-              _isFunctionalParameter(constructor.parameters, argIndex);
+              _isFunctionalParameter(
+                  constructor.parameters, argIndex, containingNode);
         }
       }
     } else if (parent is MethodInvocation) {
@@ -302,9 +312,11 @@
       if (methodName != null) {
         Element methodElem = methodName.bestElement;
         if (methodElem is MethodElement) {
-          return _isFunctionalParameter(methodElem.parameters, argIndex);
+          return _isFunctionalParameter(
+              methodElem.parameters, argIndex, containingNode);
         } else if (methodElem is FunctionElement) {
-          return _isFunctionalParameter(methodElem.parameters, argIndex);
+          return _isFunctionalParameter(
+              methodElem.parameters, argIndex, containingNode);
         }
       }
     }
@@ -317,14 +329,17 @@
    * needs to be resolved so that [isFunctionalArgument] will work.
    */
   bool maybeFunctionalArgument() {
-    if (argIndex == null) {
-      return false;
+    if (argIndex != null) {
+      if (containingNode is ArgumentList) {
+        return true;
+      }
+      if (containingNode is NamedExpression) {
+        if (containingNode.parent is ArgumentList) {
+          return true;
+        }
+      }
     }
-    AstNode argList = containingNode;
-    if (argList is! ArgumentList) {
-      return false;
-    }
-    return true;
+    return false;
   }
 
   /**
@@ -420,18 +435,25 @@
   /**
    * Return `true` if the parameter is a functional parameter.
    */
-  static bool _isFunctionalParameter(
-      List<ParameterElement> parameters, int paramIndex) {
+  static bool _isFunctionalParameter(List<ParameterElement> parameters,
+      int paramIndex, AstNode containingNode) {
+    DartType paramType;
     if (paramIndex < parameters.length) {
       ParameterElement param = parameters[paramIndex];
-      DartType paramType = param.type;
       if (param.parameterKind == ParameterKind.NAMED) {
-        // TODO(danrubel) handle named parameters
-        return false;
+        if (containingNode is NamedExpression) {
+          String name = containingNode.name?.label?.name;
+          param = parameters.firstWhere(
+              (ParameterElement param) =>
+                  param.parameterKind == ParameterKind.NAMED &&
+                  param.name == name,
+              orElse: () => null);
+          paramType = param?.type;
+        }
       } else {
-        return paramType is FunctionType || paramType is FunctionTypeAlias;
+        paramType = param.type;
       }
     }
-    return false;
+    return paramType is FunctionType || paramType is FunctionTypeAlias;
   }
 }
diff --git a/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
index 8c35743..8fbcbdf 100644
--- a/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
@@ -2,11 +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.
 
-library analysis_server.plugin.edit.utilities.change_builder_core;
+import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/utilities/change_builder_core.dart';
-import 'package:analyzer/src/generated/source.dart';
 
 /**
  * A builder used to build a [SourceChange].
@@ -20,18 +19,20 @@
   factory ChangeBuilder() = ChangeBuilderImpl;
 
   /**
-   * Return the source change that was built.
+   * Return the source change that was built. The source change will not be
+   * complete until all of the futures returned by [addFileEdit] have completed.
    */
   SourceChange get sourceChange;
 
   /**
    * Use the [buildFileEdit] function to create a collection of edits to the
-   * given [source]. The edits will be added to the source change that is being
-   * built. The [timeStamp] is the time at which the [source] was last modified
-   * and is used by clients to ensure that it is safe to apply the edits.
+   * file with the given [path]. The edits will be added to the source change
+   * that is being built. The [timeStamp] is the time at which the file was last
+   * modified and is used by clients to ensure that it is safe to apply the
+   * edits.
    */
-  void addFileEdit(Source source, int timeStamp,
-      void buildFileEdit(FileEditBuilder builder));
+  Future<Null> addFileEdit(
+      String path, int timeStamp, void buildFileEdit(FileEditBuilder builder));
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
index 2ab9d6c..557b150 100644
--- a/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
@@ -2,14 +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.
 
-library analysis_server.plugin.edit.utilities.change_builder_dart;
-
 import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
 import 'package:analysis_server/src/utilities/change_builder_dart.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 
 /**
  * A [ChangeBuilder] used to build changes in Dart files.
@@ -20,7 +18,7 @@
   /**
    * Initialize a newly created change builder.
    */
-  factory DartChangeBuilder(AnalysisContext context) = DartChangeBuilderImpl;
+  factory DartChangeBuilder(AnalysisDriver driver) = DartChangeBuilderImpl;
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 072fa75..ea6074e 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -242,9 +242,10 @@
       "incremental-resolution-validation";
 
   /**
-   * The name of the option used to enable using the new analysis driver.
+   * The name of the option used to disable using the new analysis driver.
    */
-  static const String ENABLE_NEW_ANALYSIS_DRIVER = 'enable-new-analysis-driver';
+  static const String DISABLE_NEW_ANALYSIS_DRIVER =
+      'disable-new-analysis-driver';
 
   /**
    * The name of the option used to enable using pub summary manager.
@@ -393,7 +394,7 @@
     analysisServerOptions.enableIncrementalResolutionValidation =
         results[INCREMENTAL_RESOLUTION_VALIDATION];
     analysisServerOptions.enableNewAnalysisDriver =
-        results[ENABLE_NEW_ANALYSIS_DRIVER];
+        !results[DISABLE_NEW_ANALYSIS_DRIVER];
     analysisServerOptions.enablePubSummaryManager =
         results[ENABLE_PUB_SUMMARY_MANAGER];
     analysisServerOptions.finerGrainedInvalidation =
@@ -543,8 +544,8 @@
         help: "enable validation of incremental resolution results (slow)",
         defaultsTo: false,
         negatable: false);
-    parser.addFlag(ENABLE_NEW_ANALYSIS_DRIVER,
-        help: "enable using new analysis driver",
+    parser.addFlag(DISABLE_NEW_ANALYSIS_DRIVER,
+        help: "disable using new analysis driver",
         defaultsTo: false,
         negatable: false);
     parser.addFlag(ENABLE_PUB_SUMMARY_MANAGER,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index 3b26f60..0e92c36 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/protocol_server.dart'
     hide Element, ElementKind;
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/utilities/documentation.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -143,7 +144,7 @@
       // parameter list, guard first against end of list
       if (node.arguments.length == argIndex + 1 ||
           node.arguments.getRange(argIndex + 1, argIndex + 2).first
-          is NamedExpression) {
+              is NamedExpression) {
         return true;
       }
     }
@@ -204,12 +205,8 @@
 
     // Generate argument list suggestion based upon the type of element
     if (elem is ClassElement) {
-      for (ConstructorElement constructor in elem.constructors) {
-        if (!constructor.isFactory) {
-          _addSuggestions(constructor.parameters);
-          return suggestions;
-        }
-      }
+      _addSuggestions(elem.unnamedConstructor?.parameters);
+      return suggestions;
     }
     if (elem is ConstructorElement) {
       _addSuggestions(elem.parameters);
@@ -230,10 +227,10 @@
       [bool appendComma = false]) {
     bool appendColon = !_isInNamedExpression(request);
     Iterable<String> namedArgs = _namedArgs(request);
-    for (ParameterElement param in parameters) {
-      if (param.parameterKind == ParameterKind.NAMED) {
-        _addNamedParameterSuggestion(request, namedArgs, param.name,
-            param.type?.displayName, appendColon, appendComma);
+    for (ParameterElement parameter in parameters) {
+      if (parameter.parameterKind == ParameterKind.NAMED) {
+        _addNamedParameterSuggestion(
+            request, namedArgs, parameter, appendColon, appendComma);
       }
     }
   }
@@ -241,10 +238,11 @@
   void _addNamedParameterSuggestion(
       DartCompletionRequest request,
       List<String> namedArgs,
-      String name,
-      String paramType,
+      ParameterElement parameter,
       bool appendColon,
       bool appendComma) {
+    String name = parameter.name;
+    String type = parameter.type?.displayName;
     if (name != null && name.length > 0 && !namedArgs.contains(name)) {
       String completion = name;
       if (appendColon) {
@@ -253,7 +251,7 @@
       if (appendComma) {
         completion += ',';
       }
-      suggestions.add(new CompletionSuggestion(
+      CompletionSuggestion suggestion = new CompletionSuggestion(
           CompletionSuggestionKind.NAMED_ARGUMENT,
           DART_RELEVANCE_NAMED_PARAMETER,
           completion,
@@ -262,7 +260,12 @@
           false,
           false,
           parameterName: name,
-          parameterType: paramType));
+          parameterType: type);
+      if (parameter is FieldFormalParameterElement) {
+        _setDocumentation(suggestion, parameter.field?.documentationComment);
+        suggestion.element = convertElement(parameter);
+      }
+      suggestions.add(suggestion);
     }
   }
 
@@ -288,4 +291,17 @@
       _addDefaultParamSuggestions(parameters);
     }
   }
+
+  /**
+   * If the given [comment] is not `null`, fill the [suggestion] documentation
+   * fields.
+   */
+  static void _setDocumentation(
+      CompletionSuggestion suggestion, String comment) {
+    if (comment != null) {
+      String doc = removeDartDocDelimiters(comment);
+      suggestion.docComplete = doc;
+      suggestion.docSummary = getDartDocSummary(doc);
+    }
+  }
 }
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 5a8d8cb..ee485ff 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
@@ -88,6 +88,20 @@
 
   @override
   visitBlock(Block node) {
+    Statement prevStmt = OpType.getPreviousStatement(node, entity);
+    if (prevStmt is TryStatement) {
+      if (prevStmt.finallyBlock == null) {
+        _addSuggestion2('on');
+        _addSuggestion(Keyword.CATCH);
+        _addSuggestion(Keyword.FINALLY);
+        if (prevStmt.catchClauses.isEmpty) {
+          // If try statement with no catch, on, or finally
+          // then only suggest these keywords
+          return;
+        }
+      }
+    }
+
     if (entity is ExpressionStatement) {
       Expression expression = (entity as ExpressionStatement).expression;
       if (expression is SimpleIdentifier) {
@@ -411,6 +425,18 @@
   }
 
   @override
+  visitTryStatement(TryStatement node) {
+    var obj = entity;
+    if (obj is CatchClause ||
+        (obj is KeywordToken && obj.value() == Keyword.FINALLY)) {
+      _addSuggestion2('on');
+      _addSuggestion(Keyword.CATCH);
+      return null;
+    }
+    return visitStatement(node);
+  }
+
+  @override
   visitVariableDeclaration(VariableDeclaration node) {
     if (entity == node.initializer) {
       _addExpressionKeywords(node);
@@ -467,7 +493,7 @@
       Keyword.TRUE,
     ]);
     if (_inClassMemberBody(node)) {
-      _addSuggestions([Keyword.SUPER, Keyword.THIS,]);
+      _addSuggestions([Keyword.SUPER, Keyword.THIS]);
     }
     if (_inAsyncMethodOrFunction(node)) {
       _addSuggestion2(AWAIT);
@@ -497,7 +523,7 @@
 
   void _addStatementKeywords(AstNode node) {
     if (_inClassMemberBody(node)) {
-      _addSuggestions([Keyword.SUPER, Keyword.THIS,]);
+      _addSuggestions([Keyword.SUPER, Keyword.THIS]);
     }
     if (_inAsyncMethodOrFunction(node)) {
       _addSuggestion2(AWAIT);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
index c9954d5..975e910 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
@@ -153,6 +153,22 @@
       !includeNamedArgumentSuggestions &&
       !includeReturnValueSuggestions &&
       !includeVoidReturnSuggestions;
+
+  /// Return the statement before [entity]
+  /// where [entity] can be a statement or the `}` closing the given block.
+  static Statement getPreviousStatement(Block node, Object entity) {
+    if (entity == node.rightBracket) {
+      return node.statements.isNotEmpty ? node.statements.last : null;
+    }
+    if (entity is Statement) {
+      int index = node.statements.indexOf(entity);
+      if (index > 0) {
+        return node.statements[index - 1];
+      }
+      return null;
+    }
+    return null;
+  }
 }
 
 class _OpTypeAstVisitor extends GeneralizingAstVisitor {
@@ -189,38 +205,57 @@
   @override
   void visitArgumentList(ArgumentList node) {
     AstNode parent = node.parent;
-    if (parent is InvocationExpression) {
+    List<ParameterElement> parameters;
+    if (parent is InstanceCreationExpression) {
+      Element constructor;
+      SimpleIdentifier name = parent.constructorName?.name;
+      if (name != null) {
+        constructor = name.bestElement;
+      } else {
+        var classElem = parent.constructorName?.type?.name?.bestElement;
+        if (classElem is ClassElement) {
+          constructor = classElem.unnamedConstructor;
+        }
+      }
+      if (constructor is ConstructorElement) {
+        parameters = constructor.parameters;
+      } else if (constructor == null) {
+        // If unresolved, then include named arguments
+        optype.includeNamedArgumentSuggestions = true;
+      }
+    } else if (parent is InvocationExpression) {
       Expression function = parent.function;
       if (function is SimpleIdentifier) {
         var elem = function.bestElement;
         if (elem is FunctionTypedElement) {
-          List<ParameterElement> parameters = elem.parameters;
-          if (parameters != null) {
-            int index;
-            if (node.arguments.isEmpty) {
-              index = 0;
-            } else if (entity == node.rightParenthesis) {
-              // Parser ignores trailing commas
-              if (node.rightParenthesis.previous?.lexeme == ',') {
-                index = node.arguments.length;
-              } else {
-                index = node.arguments.length - 1;
-              }
-            } else {
-              index = node.arguments.indexOf(entity);
-            }
-            if (0 <= index && index < parameters.length) {
-              ParameterElement param = parameters[index];
-              if (param?.parameterKind == ParameterKind.NAMED) {
-                optype.includeNamedArgumentSuggestions = true;
-                return;
-              }
-            }
-          }
+          parameters = elem.parameters;
         } else if (elem == null) {
           // If unresolved, then include named arguments
           optype.includeNamedArgumentSuggestions = true;
-          // fall through to include others as well
+        }
+      }
+    }
+    // Based upon the insertion location and declared parameters
+    // determine whether only named arguments should be suggested
+    if (parameters != null) {
+      int index;
+      if (node.arguments.isEmpty) {
+        index = 0;
+      } else if (entity == node.rightParenthesis) {
+        // Parser ignores trailing commas
+        if (node.rightParenthesis.previous?.lexeme == ',') {
+          index = node.arguments.length;
+        } else {
+          index = node.arguments.length - 1;
+        }
+      } else {
+        index = node.arguments.indexOf(entity);
+      }
+      if (0 <= index && index < parameters.length) {
+        ParameterElement param = parameters[index];
+        if (param?.parameterKind == ParameterKind.NAMED) {
+          optype.includeNamedArgumentSuggestions = true;
+          return;
         }
       }
     }
@@ -278,6 +313,12 @@
 
   @override
   void visitBlock(Block node) {
+    Statement prevStmt = OpType.getPreviousStatement(node, entity);
+    if (prevStmt is TryStatement) {
+      if (prevStmt.catchClauses.isEmpty && prevStmt.finallyBlock == null) {
+        return;
+      }
+    }
     optype.includeReturnValueSuggestions = true;
     optype.includeTypeNameSuggestions = true;
     optype.includeVoidReturnSuggestions = true;
@@ -906,6 +947,11 @@
     }
   }
 
+  @override
+  void visitWithClause(WithClause node) {
+    optype.includeTypeNameSuggestions = true;
+  }
+
   bool _isEntityPrevTokenSynthetic() {
     Object entity = this.entity;
     if (entity is AstNode && entity.beginToken.previous?.isSynthetic ?? false) {
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 c92920d..28d6f8f 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -876,7 +876,7 @@
     }
     // strip !()
     if (getExpressionParentPrecedence(prefExpression) >=
-        TokenType.IS.precedence) {
+        TokenClass.RELATIONAL_OPERATOR.precedence) {
       _addRemoveEdit(rangeToken(prefExpression.operator));
     } else {
       _addRemoveEdit(
@@ -925,7 +925,7 @@
     }
     // strip !()
     if (getExpressionParentPrecedence(prefExpression) >=
-        TokenType.IS.precedence) {
+        TokenClass.RELATIONAL_OPERATOR.precedence) {
       _addRemoveEdit(rangeToken(prefExpression.operator));
     } else {
       _addRemoveEdit(
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 dc59c71..c823e4e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -34,6 +34,7 @@
 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -61,10 +62,11 @@
  */
 class DartFixContextImpl extends FixContextImpl implements DartFixContext {
   final GetTopLevelDeclarations getTopLevelDeclarations;
+  final AstProvider astProvider;
   final CompilationUnit unit;
 
-  DartFixContextImpl(
-      FixContext fixContext, this.getTopLevelDeclarations, this.unit)
+  DartFixContextImpl(FixContext fixContext, this.getTopLevelDeclarations,
+      this.astProvider, this.unit)
       : super.from(fixContext);
 }
 
@@ -90,6 +92,7 @@
   static const int MAX_LEVENSHTEIN_DISTANCE = 3;
 
   ResourceProvider resourceProvider;
+  AstProvider astProvider;
   GetTopLevelDeclarations getTopLevelDeclarations;
   CompilationUnit unit;
   AnalysisError error;
@@ -120,6 +123,7 @@
 
   FixProcessor(DartFixContext dartContext) {
     resourceProvider = dartContext.resourceProvider;
+    astProvider = dartContext.astProvider;
     getTopLevelDeclarations = dartContext.getTopLevelDeclarations;
     context = dartContext.analysisContext;
     // unit
@@ -254,14 +258,14 @@
       _addFix_replaceVarWithDynamic();
     }
     if (errorCode == StaticWarningCode.ASSIGNMENT_TO_FINAL) {
-      _addFix_makeFieldNotFinal();
+      await _addFix_makeFieldNotFinal();
     }
     if (errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER) {
       _addFix_makeEnclosingClassAbstract();
     }
     if (errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) {
       _addFix_createConstructor_insteadOfSyntheticDefault();
-      _addFix_addMissingParameter();
+      await _addFix_addMissingParameter();
     }
     if (errorCode == StaticWarningCode.FUNCTION_WITHOUT_CALL) {
       _addFix_addMissingMethodCall();
@@ -458,7 +462,7 @@
     _addFix(DartFixKind.CREATE_MISSING_METHOD_CALL, []);
   }
 
-  void _addFix_addMissingParameter() {
+  Future<Null> _addFix_addMissingParameter() async {
     if (node is ArgumentList && node.parent is MethodInvocation) {
       ArgumentList argumentList = node;
       MethodInvocation invocation = node.parent;
@@ -481,19 +485,26 @@
         // prepare target
         int targetOffset;
         if (numRequired != 0) {
-          AstNode parameterNode = requiredParameters.last.computeNode();
-          targetOffset = parameterNode.end;
+          SimpleIdentifier lastName = await astProvider
+              .getParsedNameForElement(requiredParameters.last);
+          if (lastName != null) {
+            targetOffset = lastName.end;
+          } else {
+            return;
+          }
         } else {
-          AstNode targetNode = targetElement.computeNode();
-          if (targetNode is FunctionDeclaration) {
-            FunctionExpression function = targetNode.functionExpression;
-            Token paren = function.parameters.leftParenthesis;
+          SimpleIdentifier targetName =
+              await astProvider.getParsedNameForElement(targetElement);
+          AstNode targetDeclaration = targetName?.parent;
+          if (targetDeclaration is FunctionDeclaration) {
+            FunctionExpression function = targetDeclaration.functionExpression;
+            Token paren = function.parameters?.leftParenthesis;
             if (paren == null) {
               return;
             }
             targetOffset = paren.end;
-          } else if (targetNode is MethodDeclaration) {
-            Token paren = targetNode.parameters.leftParenthesis;
+          } else if (targetDeclaration is MethodDeclaration) {
+            Token paren = targetDeclaration.parameters?.leftParenthesis;
             if (paren == null) {
               return;
             }
@@ -1649,7 +1660,7 @@
     _addFix(DartFixKind.MAKE_CLASS_ABSTRACT, [className]);
   }
 
-  void _addFix_makeFieldNotFinal() {
+  Future<Null> _addFix_makeFieldNotFinal() async {
     AstNode node = this.node;
     if (node is SimpleIdentifier &&
         node.bestElement is PropertyAccessorElement) {
@@ -1659,7 +1670,9 @@
           !getter.variable.isSynthetic &&
           getter.variable.setter == null &&
           getter.enclosingElement is ClassElement) {
-        AstNode variable = getter.variable.computeNode();
+        AstNode name =
+            await astProvider.getParsedNameForElement(getter.variable);
+        AstNode variable = name?.parent;
         if (variable is VariableDeclaration &&
             variable.parent is VariableDeclarationList &&
             variable.parent.parent is FieldDeclaration) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
index de6e761..0dac920 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
@@ -24,11 +25,13 @@
 class ConvertGetterToMethodRefactoringImpl extends RefactoringImpl
     implements ConvertGetterToMethodRefactoring {
   final SearchEngine searchEngine;
+  final AstProvider astProvider;
   final PropertyAccessorElement element;
 
   SourceChange change;
 
-  ConvertGetterToMethodRefactoringImpl(this.searchEngine, this.element);
+  ConvertGetterToMethodRefactoringImpl(
+      this.searchEngine, this.astProvider, this.element);
 
   @override
   String get refactoringName => 'Convert Getter To Method';
@@ -50,7 +53,7 @@
     change = new SourceChange(refactoringName);
     // function
     if (element.enclosingElement is CompilationUnitElement) {
-      _updateElementDeclaration(element);
+      await _updateElementDeclaration(element);
       await _updateElementReferences(element);
     }
     // method
@@ -58,11 +61,13 @@
       FieldElement field = element.variable;
       Set<ClassMemberElement> elements =
           await getHierarchyMembers(searchEngine, field);
-      await Future.forEach(elements, (FieldElement field) {
-        PropertyAccessorElement getter = field.getter;
-        if (!getter.isSynthetic) {
-          _updateElementDeclaration(getter);
-          return _updateElementReferences(getter);
+      await Future.forEach(elements, (ClassMemberElement member) async {
+        if (member is FieldElement) {
+          PropertyAccessorElement getter = member.getter;
+          if (!getter.isSynthetic) {
+            await _updateElementDeclaration(getter);
+            return _updateElementReferences(getter);
+          }
         }
       });
     }
@@ -81,15 +86,19 @@
     return new RefactoringStatus();
   }
 
-  void _updateElementDeclaration(PropertyAccessorElement element) {
+  Future<Null> _updateElementDeclaration(
+      PropertyAccessorElement element) async {
     // prepare "get" keyword
     Token getKeyword = null;
     {
-      AstNode node = element.computeNode();
-      if (node is MethodDeclaration) {
-        getKeyword = node.propertyKeyword;
-      } else if (node is FunctionDeclaration) {
-        getKeyword = node.propertyKeyword;
+      AstNode name = await astProvider.getParsedNameForElement(element);
+      AstNode declaration = name?.parent;
+      if (declaration is MethodDeclaration) {
+        getKeyword = declaration.propertyKeyword;
+      } else if (declaration is FunctionDeclaration) {
+        getKeyword = declaration.propertyKeyword;
+      } else {
+        return;
       }
     }
     // remove "get "
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
index e8ef23c..5ba028e 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
@@ -24,13 +25,13 @@
 class ConvertMethodToGetterRefactoringImpl extends RefactoringImpl
     implements ConvertMethodToGetterRefactoring {
   final SearchEngine searchEngine;
-  final GetResolvedUnit getResolvedUnit;
+  final AstProvider astProvider;
   final ExecutableElement element;
 
   SourceChange change;
 
   ConvertMethodToGetterRefactoringImpl(
-      this.searchEngine, this.getResolvedUnit, this.element);
+      this.searchEngine, this.astProvider, this.element);
 
   @override
   String get refactoringName => 'Convert Method To Getter';
@@ -72,7 +73,7 @@
     change = new SourceChange(refactoringName);
     // FunctionElement
     if (element is FunctionElement) {
-      _updateElementDeclaration(element);
+      await _updateElementDeclaration(element);
       await _updateElementReferences(element);
     }
     // MethodElement
@@ -80,8 +81,8 @@
       MethodElement method = element;
       Set<ClassMemberElement> elements =
           await getHierarchyMembers(searchEngine, method);
-      await Future.forEach(elements, (Element element) {
-        _updateElementDeclaration(element);
+      await Future.forEach(elements, (Element element) async {
+        await _updateElementDeclaration(element);
         return _updateElementReferences(element);
       });
     }
@@ -92,16 +93,18 @@
   @override
   bool requiresPreview() => false;
 
-  void _updateElementDeclaration(Element element) {
+  Future<Null> _updateElementDeclaration(Element element) async {
     // prepare parameters
     FormalParameterList parameters;
     {
-      AstNode node = element.computeNode();
-      if (node is MethodDeclaration) {
-        parameters = node.parameters;
-      }
-      if (node is FunctionDeclaration) {
-        parameters = node.functionExpression.parameters;
+      AstNode name = await astProvider.getParsedNameForElement(element);
+      AstNode declaration = name?.parent;
+      if (declaration is MethodDeclaration) {
+        parameters = declaration.parameters;
+      } else if (declaration is FunctionDeclaration) {
+        parameters = declaration.functionExpression.parameters;
+      } else {
+        return;
       }
     }
     // insert "get "
@@ -125,7 +128,8 @@
       // prepare invocation
       MethodInvocation invocation;
       {
-        CompilationUnit refUnit = await getResolvedUnit(refElement);
+        CompilationUnit refUnit =
+            await astProvider.getParsedUnitForElement(refElement);
         AstNode refNode =
             new NodeLocator(refRange.offset).searchWithin(refUnit);
         invocation = refNode.getAncestor((node) => node is MethodInvocation);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
index 141eb8a..74e1add 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source.dart';
 
@@ -26,6 +27,7 @@
 class InlineLocalRefactoringImpl extends RefactoringImpl
     implements InlineLocalRefactoring {
   final SearchEngine searchEngine;
+  final AstProvider astProvider;
   final CompilationUnit unit;
   final int offset;
   CompilationUnitElement unitElement;
@@ -35,7 +37,8 @@
   VariableDeclaration _variableNode;
   List<SearchMatch> _references;
 
-  InlineLocalRefactoringImpl(this.searchEngine, this.unit, this.offset) {
+  InlineLocalRefactoringImpl(
+      this.searchEngine, this.astProvider, this.unit, this.offset) {
     unitElement = unit.element;
     utils = new CorrectionUtils(unit);
   }
@@ -75,7 +78,8 @@
         Element element = offsetNode.staticElement;
         if (element is LocalVariableElement) {
           _variableElement = element;
-          _variableNode = element.computeNode();
+          AstNode name = await astProvider.getResolvedNameForElement(element);
+          _variableNode = name.parent as VariableDeclaration;
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index 68acb96..0fbbaaf 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -20,6 +20,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -196,10 +197,10 @@
 class InlineMethodRefactoringImpl extends RefactoringImpl
     implements InlineMethodRefactoring {
   final SearchEngine searchEngine;
-  final GetResolvedUnit getResolvedUnit;
+  final AstProvider astProvider;
   final CompilationUnit unit;
   final int offset;
-  _UnitCache _unitCache;
+  ResolvedUnitCache _unitCache;
   CorrectionUtils utils;
   SourceChange change;
 
@@ -221,8 +222,8 @@
   Set<FunctionBody> _alreadyMadeAsync = new Set<FunctionBody>();
 
   InlineMethodRefactoringImpl(
-      this.searchEngine, this.getResolvedUnit, this.unit, this.offset) {
-    _unitCache = new _UnitCache(getResolvedUnit, unit);
+      this.searchEngine, this.astProvider, this.unit, this.offset) {
+    _unitCache = new ResolvedUnitCache(astProvider, unit);
     utils = new CorrectionUtils(unit);
   }
 
@@ -788,26 +789,6 @@
   }
 }
 
-class _UnitCache {
-  final GetResolvedUnit getResolvedUnit;
-  final Map<CompilationUnitElement, CompilationUnit> map = {};
-
-  _UnitCache(this.getResolvedUnit, CompilationUnit unit) {
-    map[unit.element] = unit;
-  }
-
-  Future<CompilationUnit> getUnit(Element element) async {
-    Element unitElement =
-        element.getAncestor((e) => e is CompilationUnitElement);
-    CompilationUnit unit = map[unitElement];
-    if (unit == null) {
-      unit = unitElement.unit;
-      map[unitElement] = unit;
-    }
-    return unit;
-  }
-}
-
 /**
  * A visitor that fills [_SourcePart] with fields, parameters and variables.
  */
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 9c2da5d..480d1c9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -27,15 +27,11 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
- * Completes with the resolved [CompilationUnit] that contains the [element].
- */
-typedef Future<CompilationUnit> GetResolvedUnit(Element element);
-
-/**
  * [Refactoring] to convert getters into normal [MethodDeclaration]s.
  */
 abstract class ConvertGetterToMethodRefactoring implements Refactoring {
@@ -43,9 +39,10 @@
    * Returns a new [ConvertMethodToGetterRefactoring] instance for converting
    * [element] and all the corresponding hierarchy elements.
    */
-  factory ConvertGetterToMethodRefactoring(
-      SearchEngine searchEngine, PropertyAccessorElement element) {
-    return new ConvertGetterToMethodRefactoringImpl(searchEngine, element);
+  factory ConvertGetterToMethodRefactoring(SearchEngine searchEngine,
+      AstProvider astProvider, PropertyAccessorElement element) {
+    return new ConvertGetterToMethodRefactoringImpl(
+        searchEngine, astProvider, element);
   }
 }
 
@@ -58,9 +55,9 @@
    * [element] and all the corresponding hierarchy elements.
    */
   factory ConvertMethodToGetterRefactoring(SearchEngine searchEngine,
-      GetResolvedUnit getResolvedUnit, ExecutableElement element) {
+      AstProvider astProvider, ExecutableElement element) {
     return new ConvertMethodToGetterRefactoringImpl(
-        searchEngine, getResolvedUnit, element);
+        searchEngine, astProvider, element);
   }
 }
 
@@ -231,9 +228,10 @@
   /**
    * Returns a new [InlineLocalRefactoring] instance.
    */
-  factory InlineLocalRefactoring(
-      SearchEngine searchEngine, CompilationUnit unit, int offset) {
-    return new InlineLocalRefactoringImpl(searchEngine, unit, offset);
+  factory InlineLocalRefactoring(SearchEngine searchEngine,
+      AstProvider astProvider, CompilationUnit unit, int offset) {
+    return new InlineLocalRefactoringImpl(
+        searchEngine, astProvider, unit, offset);
   }
 
   /**
@@ -255,9 +253,9 @@
    * Returns a new [InlineMethodRefactoring] instance.
    */
   factory InlineMethodRefactoring(SearchEngine searchEngine,
-      GetResolvedUnit getResolvedUnit, CompilationUnit unit, int offset) {
+      AstProvider astProvider, CompilationUnit unit, int offset) {
     return new InlineMethodRefactoringImpl(
-        searchEngine, getResolvedUnit, unit, offset);
+        searchEngine, astProvider, unit, offset);
   }
 
   /**
@@ -374,7 +372,8 @@
    * maybe `null` if there is no support for renaming [Element]s of the given
    * type.
    */
-  factory RenameRefactoring(SearchEngine searchEngine, Element element) {
+  factory RenameRefactoring(
+      SearchEngine searchEngine, AstProvider astProvider, Element element) {
     if (element == null) {
       return null;
     }
@@ -385,7 +384,8 @@
       return new RenameUnitMemberRefactoringImpl(searchEngine, element);
     }
     if (element is ConstructorElement) {
-      return new RenameConstructorRefactoringImpl(searchEngine, element);
+      return new RenameConstructorRefactoringImpl(
+          searchEngine, astProvider, element);
     }
     if (element is ImportElement) {
       return new RenameImportRefactoringImpl(searchEngine, element);
@@ -397,7 +397,7 @@
       return new RenameLibraryRefactoringImpl(searchEngine, element);
     }
     if (element is LocalElement) {
-      return new RenameLocalRefactoringImpl(searchEngine, element);
+      return new RenameLocalRefactoringImpl(searchEngine, astProvider, element);
     }
     if (element.enclosingElement is ClassElement) {
       return new RenameClassMemberRefactoringImpl(searchEngine, element);
@@ -432,3 +432,33 @@
    */
   RefactoringStatus checkNewName();
 }
+
+/**
+ * Cache for accessing resolved [CompilationUnit]s by [Element]s.
+ *
+ * Must by short-lived.
+ *
+ * TODO(scheglov) consider moving to request-bound object.
+ */
+class ResolvedUnitCache {
+  final AstProvider _astProvider;
+  final Map<CompilationUnitElement, CompilationUnit> _map = {};
+
+  ResolvedUnitCache(this._astProvider, [CompilationUnit unit]) {
+    if (unit != null) {
+      _map[unit.element] = unit;
+    }
+  }
+
+  Future<CompilationUnit> getUnit(Element element) async {
+    CompilationUnitElement unitElement =
+        element.getAncestor((e) => e is CompilationUnitElement)
+            as CompilationUnitElement;
+    CompilationUnit unit = _map[unitElement];
+    if (unit == null) {
+      unit = await _astProvider.getResolvedUnitForElement(element);
+      _map[unitElement] = unit;
+    }
+    return unit;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index cb9d88d..e23c60c 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -19,6 +19,7 @@
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source.dart';
 
@@ -26,8 +27,10 @@
  * A [Refactoring] for renaming [ConstructorElement]s.
  */
 class RenameConstructorRefactoringImpl extends RenameRefactoringImpl {
+  final AstProvider astProvider;
+
   RenameConstructorRefactoringImpl(
-      SearchEngine searchEngine, ConstructorElement element)
+      SearchEngine searchEngine, this.astProvider, ConstructorElement element)
       : super(searchEngine, element);
 
   @override
@@ -61,7 +64,7 @@
     List<SourceReference> references = getSourceReferences(matches);
     // append declaration
     if (element.isSynthetic) {
-      _replaceSynthetic();
+      await _replaceSynthetic();
     } else {
       references.add(_createDeclarationReference());
     }
@@ -107,9 +110,10 @@
         true));
   }
 
-  void _replaceSynthetic() {
+  Future<Null> _replaceSynthetic() async {
     ClassElement classElement = element.enclosingElement;
-    ClassDeclaration classNode = classElement.computeNode();
+    AstNode name = await astProvider.getResolvedNameForElement(classElement);
+    ClassDeclaration classNode = name.parent as ClassDeclaration;
     CorrectionUtils utils = new CorrectionUtils(classNode.parent);
     ClassMemberLocation location =
         utils.prepareNewConstructorLocation(classNode);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
index 5d8597f..2b165a7 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -24,10 +25,15 @@
  * A [Refactoring] for renaming [LocalElement]s.
  */
 class RenameLocalRefactoringImpl extends RenameRefactoringImpl {
+  final AstProvider astProvider;
+  final ResolvedUnitCache unitCache;
+
   Set<LocalElement> elements = new Set<LocalElement>();
 
-  RenameLocalRefactoringImpl(SearchEngine searchEngine, LocalElement element)
-      : super(searchEngine, element);
+  RenameLocalRefactoringImpl(
+      SearchEngine searchEngine, this.astProvider, LocalElement element)
+      : unitCache = new ResolvedUnitCache(astProvider),
+        super(searchEngine, element);
 
   @override
   LocalElement get element => super.element as LocalElement;
@@ -46,18 +52,14 @@
   @override
   Future<RefactoringStatus> checkFinalConditions() async {
     RefactoringStatus result = new RefactoringStatus();
-    // prepare all elements (usually one)
     await _prepareElements();
-    // checks the resolved CompilationUnit(s)
     for (LocalElement element in elements) {
-      Source unitSource = element.source;
-      List<Source> librarySources = context.getLibrariesContaining(unitSource);
-      for (Source librarySource in librarySources) {
-        _analyzePossibleConflicts_inLibrary(
-            result, unitSource, librarySource, element);
+      CompilationUnit unit = await unitCache.getUnit(element);
+      if (unit != null) {
+        SourceRange elementRange = element.visibleRange;
+        unit.accept(new _ConflictValidatorVisitor(this, result, elementRange));
       }
     }
-    // done
     return result;
   }
 
@@ -82,21 +84,6 @@
     }
   }
 
-  void _analyzePossibleConflicts_inLibrary(RefactoringStatus result,
-      Source unitSource, Source librarySource, LocalElement element) {
-    // prepare resolved unit
-    CompilationUnit unit = null;
-    try {
-      unit = context.resolveCompilationUnit2(unitSource, librarySource);
-    } catch (e) {}
-    if (unit == null) {
-      return;
-    }
-    // check for conflicts in the unit
-    SourceRange elementRange = element.visibleRange;
-    unit.accept(new _ConflictValidatorVisitor(this, result, elementRange));
-  }
-
   /**
    * Fills [elements] with [Element]s to rename.
    */
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 63a6996..83d968f 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
@@ -22,12 +23,18 @@
 import 'package:analyzer/src/summary/idl.dart';
 
 /**
+ * The type of a function that returns the [AstProvider] managing the [file].
+ */
+typedef AstProvider GetAstProvider(String file);
+
+/**
  * A [SearchEngine] implementation.
  */
 class SearchEngineImpl implements SearchEngine {
   final Index _index;
+  final GetAstProvider _getAstProvider;
 
-  SearchEngineImpl(this._index);
+  SearchEngineImpl(this._index, this._getAstProvider);
 
   @override
   Future<Set<ClassElement>> searchAllSubtypes(ClassElement type) async {
@@ -254,8 +261,9 @@
   Future<List<SearchMatch>> _searchReferences_Local(
       Element element, bool isRootNode(AstNode n)) async {
     _LocalReferencesVisitor visitor = new _LocalReferencesVisitor(element);
-    AstNode node = element.computeNode();
-    AstNode enclosingNode = node?.getAncestor(isRootNode);
+    AstProvider astProvider = _getAstProvider(element.source.fullName);
+    AstNode name = await astProvider.getResolvedNameForElement(element);
+    AstNode enclosingNode = name?.getAncestor(isRootNode);
     enclosingNode?.accept(visitor);
     return visitor.matches;
   }
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal2.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal2.dart
index e14a6ac..d9088a9 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal2.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal2.dart
@@ -39,9 +39,8 @@
   @override
   Future<List<SearchMatch>> searchMemberDeclarations(String name) async {
     List<SearchMatch> allDeclarations = [];
-    RegExp regExp = new RegExp('^$name\$');
     for (AnalysisDriver driver in _drivers) {
-      List<Element> elements = await driver.search.classMembers(regExp);
+      List<Element> elements = await driver.search.classMembers(name);
       allDeclarations.addAll(elements.map(_SearchMatch.forElement));
     }
     return allDeclarations;
@@ -153,6 +152,19 @@
     return buffer.toString();
   }
 
+  static _SearchMatch forElement(Element element) {
+    return new _SearchMatch(
+        element.source.fullName,
+        element.librarySource,
+        element.source,
+        element.library,
+        element,
+        true,
+        true,
+        MatchKind.DECLARATION,
+        new SourceRange(element.nameOffset, element.nameLength));
+  }
+
   static _SearchMatch forSearchResult(SearchResult result) {
     Element enclosingElement = result.enclosingElement;
     return new _SearchMatch(
@@ -167,19 +179,6 @@
         new SourceRange(result.offset, result.length));
   }
 
-  static _SearchMatch forElement(Element element) {
-    return new _SearchMatch(
-        element.source.fullName,
-        element.librarySource,
-        element.source,
-        element.library,
-        element,
-        true,
-        true,
-        MatchKind.DECLARATION,
-        new SourceRange(element.nameOffset, element.nameLength));
-  }
-
   static MatchKind toMatchKind(SearchResultKind kind) {
     if (kind == SearchResultKind.READ) {
       return MatchKind.READ;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 087b658..7243ef2 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -2527,9 +2527,12 @@
         buffer.write('Inactive');
       }
       buffer.write('<br>');
-      buffer.write('Version: ');
+      buffer.write('Server version: ');
       buffer.write(AnalysisServer.VERSION);
       buffer.write('<br>');
+      buffer.write('SDK: ');
+      buffer.write(Platform.version);
+      buffer.write('<br>');
       buffer.write('Process ID: ');
       buffer.write(pid);
       buffer.write('</p>');
diff --git a/pkg/analysis_server/lib/src/status/get_handler2.dart b/pkg/analysis_server/lib/src/status/get_handler2.dart
index 2541deb..fc181055 100644
--- a/pkg/analysis_server/lib/src/status/get_handler2.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler2.dart
@@ -1105,9 +1105,12 @@
         buffer.write('Inactive');
       }
       buffer.write('<br>');
-      buffer.write('Version: ');
+      buffer.write('Server version: ');
       buffer.write(AnalysisServer.VERSION);
       buffer.write('<br>');
+      buffer.write('SDK: ');
+      buffer.write(Platform.version);
+      buffer.write('<br>');
       buffer.write('Process ID: ');
       buffer.write(pid);
       buffer.write('</p>');
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_core.dart b/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
index 199fa90..c91a832 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
@@ -2,11 +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.
 
-library analysis_server.src.utilities.change_builder_core;
+import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
-import 'package:analyzer/src/generated/source.dart';
 
 /**
  * A builder used to build a [SourceChange].
@@ -44,9 +43,9 @@
   }
 
   @override
-  void addFileEdit(Source source, int fileStamp,
-      void buildFileEdit(FileEditBuilder builder)) {
-    FileEditBuilderImpl builder = createFileEditBuilder(source, fileStamp);
+  Future<Null> addFileEdit(String path, int fileStamp,
+      void buildFileEdit(FileEditBuilder builder)) async {
+    FileEditBuilderImpl builder = await createFileEditBuilder(path, fileStamp);
     try {
       buildFileEdit(builder);
     } finally {
@@ -56,10 +55,11 @@
 
   /**
    * Create and return a [FileEditBuilder] that can be used to build edits to
-   * the given [source].
+   * the file with the given [path] and [timeStamp].
    */
-  FileEditBuilderImpl createFileEditBuilder(Source source, int fileStamp) {
-    return new FileEditBuilderImpl(this, source, fileStamp);
+  Future<FileEditBuilderImpl> createFileEditBuilder(
+      String path, int timeStamp) async {
+    return new FileEditBuilderImpl(this, path, timeStamp);
   }
 
   /**
@@ -181,10 +181,10 @@
   /**
    * Initialize a newly created builder to build a source file edit within the
    * change being built by the given [changeBuilder]. The file being edited has
-   * the given [timeStamp] and [timeStamp].
+   * the given absolute [path] and [timeStamp].
    */
-  FileEditBuilderImpl(this.changeBuilder, Source source, int timeStamp)
-      : fileEdit = new SourceFileEdit(source.fullName, timeStamp);
+  FileEditBuilderImpl(this.changeBuilder, String path, int timeStamp)
+      : fileEdit = new SourceFileEdit(path, timeStamp);
 
   @override
   void addInsertion(int offset, void buildEdit(EditBuilder builder)) {
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
index f438d257..422549f 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analysis_server.src.utilities.change_builder_dart;
+import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart' hide ElementKind;
 import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
@@ -14,7 +14,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -24,18 +24,20 @@
 class DartChangeBuilderImpl extends ChangeBuilderImpl
     implements DartChangeBuilder {
   /**
-   * The analysis context in which the files being edited were analyzed.
+   * The analysis driver in which the files being edited were analyzed.
    */
-  final AnalysisContext context;
+  final AnalysisDriver driver;
 
   /**
    * Initialize a newly created change builder.
    */
-  DartChangeBuilderImpl(this.context);
+  DartChangeBuilderImpl(this.driver);
 
   @override
-  DartFileEditBuilderImpl createFileEditBuilder(Source source, int fileStamp) {
-    return new DartFileEditBuilderImpl(this, source, fileStamp);
+  Future<DartFileEditBuilderImpl> createFileEditBuilder(
+      String path, int fileStamp) async {
+    AnalysisResult result = await driver.getResult(path);
+    return new DartFileEditBuilderImpl(this, path, fileStamp, result.unit);
   }
 }
 
@@ -466,17 +468,11 @@
   /**
    * Initialize a newly created builder to build a source file edit within the
    * change being built by the given [changeBuilder]. The file being edited has
-   * the given [source] and [timeStamp].
+   * the given [source] and [timeStamp], and the given fully resolved [unit].
    */
-  DartFileEditBuilderImpl(
-      DartChangeBuilderImpl changeBuilder, Source source, int timeStamp)
-      : super(changeBuilder, source, timeStamp) {
-    AnalysisContext context = changeBuilder.context;
-    List<Source> librariesContaining = context.getLibrariesContaining(source);
-    if (librariesContaining.length < 1) {
-      throw new StateError('Cannot build edits for ${source.fullName}');
-    }
-    unit = context.resolveCompilationUnit2(source, librariesContaining[0]);
+  DartFileEditBuilderImpl(DartChangeBuilderImpl changeBuilder, String path,
+      int timeStamp, this.unit)
+      : super(changeBuilder, path, timeStamp) {
     utils = new CorrectionUtils(unit);
   }
 
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index cb366f9..0387ddd 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -9,7 +9,7 @@
   analyzer: ^0.28.0
   args: '>=0.13.0 <0.14.0'
   dart_style: '>=0.2.0 <0.3.0'
-  isolate: ^0.2.2
+  isolate: '>=0.2.2 <2.0.0'
   linter: ^0.1.16
   logging: any
   package_config: '>=0.1.5 <2.0.0'
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index d243352..e3c4b93 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -86,6 +86,7 @@
     File file = newFile(path, content);
     if (enableNewAnalysisDriver) {
       driver.addFile(path);
+      driver.changeFile(path);
       _fileContentOverlay[path] = content;
       return null;
     } else {
@@ -168,6 +169,7 @@
   void tearDown() {
     _context = null;
     provider = null;
+    AnalysisEngine.instance.clearCaches();
     AnalysisEngine.instance.logger = null;
   }
 }
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index 7f48ae2..66db6aa 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -308,6 +308,48 @@
     expect(hover.parameter, isNull);
   }
 
+  test_expression_parameter_fieldFormal_declaration() async {
+    addTestFile('''
+class A {
+  /// The field documentation.
+  final int fff;
+  A({this.fff});
+}
+main() {
+  new A(fff: 42);
+}
+''');
+    HoverInformation hover = await prepareHover('fff});');
+    expect(hover.containingLibraryName, isNull);
+    expect(hover.containingLibraryPath, isNull);
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.dartdoc, 'The field documentation.');
+    expect(hover.elementDescription, '{int fff}');
+    expect(hover.elementKind, 'parameter');
+    expect(hover.staticType, 'int');
+  }
+
+  test_expression_parameter_fieldFormal_use() async {
+    addTestFile('''
+class A {
+  /// The field documentation.
+  final int fff;
+  A({this.fff});
+}
+main() {
+  new A(fff: 42);
+}
+''');
+    HoverInformation hover = await prepareHover('fff: 42');
+    expect(hover.containingLibraryName, isNull);
+    expect(hover.containingLibraryPath, isNull);
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.dartdoc, 'The field documentation.');
+    expect(hover.elementDescription, '{int fff}');
+    expect(hover.elementKind, 'parameter');
+    expect(hover.staticType, 'int');
+  }
+
   test_expression_syntheticGetter_invocation() async {
     addTestFile('''
 library my.library;
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index 154f29b..ceabdba 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -869,8 +869,7 @@
         'testCommentSnippets085',
         '''
 class List{}class Map{}class Z extends List with !1Ma!2p {}''',
-        <String>["1+List", "1+Map", "2+Map", "2-List"],
-        failingTests: '12');
+        <String>["1+List", "1+Map", "2+Map", "2-List"]);
 
     buildTests(
         'testCommentSnippets086',
@@ -883,8 +882,7 @@
         'testCommentSnippets087',
         '''
 class Map{}class Q extends Object with !1Map {}''',
-        <String>["1+Map", "1-HashMap"],
-        failingTests: '1');
+        <String>["1+Map", "1-HashMap"]);
 
     buildTests(
         'testCommentSnippets088',
@@ -2445,7 +2443,7 @@
           "7-Dclass",
           "7-Ctype",
         ],
-        failingTests: '23467');
+        failingTests: '2346');
 
     // keywords
     buildTests(
@@ -2600,7 +2598,7 @@
           "K+else",
           "L+return"
         ],
-        failingTests: '3BCK');
+        failingTests: '3CK');
 
     // operators in function
     buildTests('test015', '''f(a,b,c) => a + b * c !1;''', <String>["1+=="],
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 4f51e86..ee33a76 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -2088,6 +2088,19 @@
     // No error means success.
   }
 
+  test_deleteRoot_hasAnalysisOptions() async {
+    newFile([projPath, optionsFileName], '');
+
+    // Add the root.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Remove the root, with the analysis options file.
+    // No exceptions.
+    resourceProvider.deleteFolder(projPath);
+    await pumpEventQueue();
+  }
+
   test_embedder_options() async {
     // Create files.
     String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index b3d85f2..31d853b 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -28,6 +28,28 @@
 
 @reflectiveTest
 class CompletionDomainHandlerTest extends AbstractCompletionDomainTest {
+  test_ArgumentList_constructor_named_param_label() async {
+    addTestFile('main() { new A(^);}'
+        'class A { A({one, two}) {} }');
+    await getSuggestions();
+    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ',
+        relevance: DART_RELEVANCE_NAMED_PARAMETER);
+    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ',
+        relevance: DART_RELEVANCE_NAMED_PARAMETER);
+    expect(suggestions, hasLength(2));
+  }
+
+  test_ArgumentList_factory_named_param_label() async {
+    addTestFile('main() { new A(^);}'
+        'class A { factory A({one, two}) => null; }');
+    await getSuggestions();
+    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ',
+        relevance: DART_RELEVANCE_NAMED_PARAMETER);
+    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ',
+        relevance: DART_RELEVANCE_NAMED_PARAMETER);
+    expect(suggestions, hasLength(2));
+  }
+
   test_ArgumentList_imported_function_named_param() async {
     addTestFile('main() { int.parse("16", ^);}');
     await getSuggestions();
@@ -77,6 +99,76 @@
     expect(suggestions, hasLength(2));
   }
 
+  test_catch() async {
+    addTestFile('main() {try {} ^}');
+    await getSuggestions();
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'on',
+        relevance: DART_RELEVANCE_KEYWORD);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch',
+        relevance: DART_RELEVANCE_KEYWORD);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'finally',
+        relevance: DART_RELEVANCE_KEYWORD);
+    expect(suggestions, hasLength(3));
+  }
+
+  test_catch2() async {
+    addTestFile('main() {try {} on Foo {} ^}');
+    await getSuggestions();
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'on',
+        relevance: DART_RELEVANCE_KEYWORD);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch',
+        relevance: DART_RELEVANCE_KEYWORD);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'finally',
+        relevance: DART_RELEVANCE_KEYWORD);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'for',
+        relevance: DART_RELEVANCE_KEYWORD);
+    suggestions.firstWhere(
+        (CompletionSuggestion suggestion) =>
+            suggestion.kind != CompletionSuggestionKind.KEYWORD, orElse: () {
+      fail('Expected suggestions other than keyword suggestions');
+    });
+  }
+
+  test_catch3() async {
+    addTestFile('main() {try {} catch (e) {} finally {} ^}');
+    await getSuggestions();
+    assertNoResult('on');
+    assertNoResult('catch');
+    assertNoResult('finally');
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'for',
+        relevance: DART_RELEVANCE_KEYWORD);
+    suggestions.firstWhere(
+        (CompletionSuggestion suggestion) =>
+            suggestion.kind != CompletionSuggestionKind.KEYWORD, orElse: () {
+      fail('Expected suggestions other than keyword suggestions');
+    });
+  }
+
+  test_catch4() async {
+    addTestFile('main() {try {} finally {} ^}');
+    await getSuggestions();
+    assertNoResult('on');
+    assertNoResult('catch');
+    assertNoResult('finally');
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'for',
+        relevance: DART_RELEVANCE_KEYWORD);
+    suggestions.firstWhere(
+        (CompletionSuggestion suggestion) =>
+            suggestion.kind != CompletionSuggestionKind.KEYWORD, orElse: () {
+      fail('Expected suggestions other than keyword suggestions');
+    });
+  }
+
+  test_catch5() async {
+    addTestFile('main() {try {} ^ finally {}}');
+    await getSuggestions();
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'on',
+        relevance: DART_RELEVANCE_KEYWORD);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch',
+        relevance: DART_RELEVANCE_KEYWORD);
+    expect(suggestions, hasLength(2));
+  }
+
   test_html() {
     testFile = '/project/web/test.html';
     addTestFile('''
diff --git a/pkg/analysis_server/test/integration/analysis/error_test.dart b/pkg/analysis_server/test/integration/analysis/error_test.dart
index 5c4bea4..3d11f4e 100644
--- a/pkg/analysis_server/test/integration/analysis/error_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/error_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -11,6 +13,8 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnalysisErrorIntegrationTest);
+    defineReflectiveTests(NoAnalysisErrorsIntegrationTest);
+    defineReflectiveTests(NoAnalysisErrorsIntegrationTest_Driver);
   });
 }
 
@@ -97,3 +101,44 @@
 @reflectiveTest
 class AnalysisErrorIntegrationTest
     extends AbstractAnalysisErrorIntegrationTest {}
+
+@reflectiveTest
+class NoAnalysisErrorsIntegrationTest
+    extends AbstractAnalysisServerIntegrationTest {
+  @override
+  Future startServer(
+          {bool checked: true, int diagnosticPort, int servicesPort}) =>
+      server.start(
+          checked: checked,
+          diagnosticPort: diagnosticPort,
+          enableNewAnalysisDriver: enableNewAnalysisDriver,
+          noErrorNotification: true,
+          servicesPort: servicesPort);
+
+  test_detect_simple_error() {
+    String pathname = sourcePath('test.dart');
+    writeFile(
+        pathname,
+        '''
+main() {
+  print(null) // parse error: missing ';'
+}''');
+    standardAnalysisSetup();
+    return analysisFinished.then((_) {
+      expect(currentAnalysisErrors[pathname], isNull);
+    });
+  }
+}
+
+@reflectiveTest
+class NoAnalysisErrorsIntegrationTest_Driver
+    extends NoAnalysisErrorsIntegrationTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+
+  @failingTest
+  @override
+  test_detect_simple_error() {
+    return super.test_detect_simple_error();
+  }
+}
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors.dart b/pkg/analysis_server/test/integration/analysis/get_errors.dart
deleted file mode 100644
index d7aee3c..0000000
--- a/pkg/analysis_server/test/integration/analysis/get_errors.dart
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.integration.analysis.get.errors;
-
-import 'dart:async';
-
-import 'package:test/test.dart';
-
-import '../integration_tests.dart';
-
-/**
- * Base class for testing the "analysis.getErrors" request.
- */
-class AnalysisDomainGetErrorsTest
-    extends AbstractAnalysisServerIntegrationTest {
-  /**
-   * True if the "analysis.getErrors" request should be made after analysis is
-   * complete.
-   */
-  final bool afterAnalysis;
-
-  AnalysisDomainGetErrorsTest(this.afterAnalysis);
-
-  test_getErrors() {
-    String pathname = sourcePath('test.dart');
-    String text = r'''
-main() {
-  var x // parse error: missing ';'
-}''';
-    writeFile(pathname, text);
-    standardAnalysisSetup();
-    Future finishTest() {
-      return sendAnalysisGetErrors(pathname).then((result) {
-        expect(result.errors, equals(currentAnalysisErrors[pathname]));
-      });
-    }
-    if (afterAnalysis) {
-      return analysisFinished.then((_) => finishTest());
-    } else {
-      return finishTest();
-    }
-  }
-}
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_after_analysis_test.dart b/pkg/analysis_server/test/integration/analysis/get_errors_after_analysis_test.dart
deleted file mode 100644
index 81ab905..0000000
--- a/pkg/analysis_server/test/integration/analysis/get_errors_after_analysis_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import 'get_errors.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(GetErrorsAfterTest);
-    defineReflectiveTests(GetErrorsAfterTest_Driver);
-  });
-}
-
-class AbstractGetErrorsAfterTest extends AnalysisDomainGetErrorsTest {
-  AbstractGetErrorsAfterTest() : super(true);
-}
-
-@reflectiveTest
-class GetErrorsAfterTest extends AbstractGetErrorsAfterTest {}
-
-@reflectiveTest
-class GetErrorsAfterTest_Driver extends AbstractGetErrorsAfterTest {
-  @override
-  bool get enableNewAnalysisDriver => true;
-}
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_before_analysis_test.dart b/pkg/analysis_server/test/integration/analysis/get_errors_before_analysis_test.dart
deleted file mode 100644
index 2c5d5b8..0000000
--- a/pkg/analysis_server/test/integration/analysis/get_errors_before_analysis_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import 'get_errors.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(GetErrorsBeforeTest);
-    defineReflectiveTests(GetErrorsBeforeTest_Driver);
-  });
-}
-
-class AbstractGetErrorsBeforeTest extends AnalysisDomainGetErrorsTest {
-  AbstractGetErrorsBeforeTest() : super(false);
-}
-
-@reflectiveTest
-class GetErrorsBeforeTest extends AbstractGetErrorsBeforeTest {}
-
-@reflectiveTest
-class GetErrorsBeforeTest_Driver extends AbstractGetErrorsBeforeTest {
-  @override
-  bool get enableNewAnalysisDriver => true;
-}
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_test.dart b/pkg/analysis_server/test/integration/analysis/get_errors_test.dart
new file mode 100644
index 0000000..ce66f05
--- /dev/null
+++ b/pkg/analysis_server/test/integration/analysis/get_errors_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.integration.analysis.get.errors;
+
+import 'dart:async';
+
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../integration_tests.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(GetErrorsTest);
+    defineReflectiveTests(GetErrorsTest_Driver);
+  });
+}
+
+/**
+ * Base class for testing the "analysis.getErrors" request.
+ */
+class AnalysisDomainGetErrorsTest
+    extends AbstractAnalysisServerIntegrationTest {
+  AnalysisDomainGetErrorsTest();
+
+  test_getErrors() {
+    String pathname = sourcePath('test.dart');
+    String text = r'''
+main() {
+  var x // parse error: missing ';'
+}''';
+    writeFile(pathname, text);
+    standardAnalysisSetup();
+    Future finishTest() {
+      return sendAnalysisGetErrors(pathname).then((result) {
+        expect(result.errors, equals(currentAnalysisErrors[pathname]));
+      });
+    }
+
+    return analysisFinished.then((_) => finishTest());
+  }
+}
+
+@reflectiveTest
+class GetErrorsTest extends AnalysisDomainGetErrorsTest {}
+
+@reflectiveTest
+class GetErrorsTest_Driver extends AnalysisDomainGetErrorsTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analysis_server/test/integration/analysis/test_all.dart b/pkg/analysis_server/test/integration/analysis/test_all.dart
index 9937146..a7eb871 100644
--- a/pkg/analysis_server/test/integration/analysis/test_all.dart
+++ b/pkg/analysis_server/test/integration/analysis/test_all.dart
@@ -9,10 +9,8 @@
 import 'analysis_options_test.dart' as analysis_options_test;
 import 'error_driver_test.dart' as error_driver_test;
 import 'error_test.dart' as error_test;
-import 'get_errors_after_analysis_test.dart' as get_errors_after_analysis_test;
-import 'get_errors_before_analysis_test.dart'
-    as get_errors_before_analysis_test;
 import 'get_errors_nonStandard_sdk.dart' as get_errors_nonStandard_sdk;
+import 'get_errors_test.dart' as get_errors_test;
 import 'get_hover_test.dart' as get_hover_test;
 import 'highlights_test.dart' as highlights_test;
 import 'highlights_test2.dart' as highlights_test2;
@@ -37,8 +35,7 @@
     analysis_options_test.main();
     error_driver_test.main();
     error_test.main();
-    get_errors_after_analysis_test.main();
-    get_errors_before_analysis_test.main();
+    get_errors_test.main();
     get_errors_nonStandard_sdk.main();
     get_hover_test.main();
     highlights_test.main();
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
new file mode 100644
index 0000000..0bf74f6
--- /dev/null
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -0,0 +1,51 @@
+Checklist to ensure that we have integration test coverage of all analysis
+server calls.
+
+This file is validated by `coverage_test.dart`.
+
+## server domain
+- [x] server.getVersion
+- [x] server.shutdown
+- [x] server.setSubscriptions
+
+## analysis domain
+- [x] analysis.getErrors
+- [x] analysis.getHover
+- [ ] analysis.getReachableSources
+- [ ] analysis.getLibraryDependencies
+- [ ] analysis.getNavigation
+- [x] analysis.reanalyze
+- [ ] analysis.setAnalysisRoots
+- [ ] analysis.setGeneralSubscriptions
+- [ ] analysis.setPriorityFiles
+- [ ] analysis.setSubscriptions
+- [x] analysis.updateContent
+- [ ] analysis.updateOptions
+
+## completion domain
+- [x] completion.getSuggestions
+
+## search domain
+- [ ] search.findElementReferences
+- [ ] search.findMemberDeclarations
+- [ ] search.findMemberReferences
+- [ ] search.findTopLevelDeclarations
+- [x] search.getTypeHierarchy
+
+## edit domain
+- [ ] edit.format
+- [ ] edit.getAssists
+- [ ] edit.getAvailableRefactorings
+- [ ] edit.getFixes
+- [ ] edit.getRefactoring
+- [ ] edit.sortMembers
+- [ ] edit.organizeDirectives
+
+## execution domain
+- [x] execution.createContext
+- [x] execution.deleteContext
+- [x] execution.mapUri
+- [ ] execution.setSubscriptions
+
+## diagnostic domain
+- [ ] diagnostic.getDiagnostics
diff --git a/pkg/analysis_server/test/integration/coverage_test.dart b/pkg/analysis_server/test/integration/coverage_test.dart
new file mode 100644
index 0000000..48acfba
--- /dev/null
+++ b/pkg/analysis_server/test/integration/coverage_test.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+import '../../tool/spec/api.dart';
+import '../../tool/spec/from_html.dart';
+
+// TODO(devoncarew): Several of the analysis domain methods are covered, but
+// they aren't using the below file name pattern.
+
+/// Define tests to fail if there's no mention in the coverage file.
+main() {
+  Api api;
+  File coverageFile;
+  String pathPrefix;
+
+  // parse the API file
+  if (FileSystemEntity
+      .isFileSync(path.join('tool', 'spec', 'spec_input.html'))) {
+    api = readApi('.');
+    pathPrefix = '.';
+  } else {
+    api = readApi(path.join('pkg', 'analysis_server'));
+    pathPrefix = path.join('pkg', 'analysis_server');
+  }
+
+  coverageFile =
+      new File(path.join(pathPrefix, 'test', 'integration', 'coverage.md'));
+  List<String> lines = coverageFile.readAsLinesSync();
+
+  // ## server domain
+  Set<String> coveredDomains = lines
+      .where((line) => line.startsWith('## ') && line.endsWith(' domain'))
+      .map((line) =>
+          line.substring('##'.length, line.length - 'domain'.length).trim())
+      .toSet();
+
+  // - [ ] server.getVersion
+  Set<String> allMembers = lines
+      .where((line) => line.startsWith('- '))
+      .map((line) => line.substring('- [ ]'.length).trim())
+      .toSet();
+  Set<String> coveredMembers = lines
+      .where((line) => line.startsWith('- [x]'))
+      .map((line) => line.substring('- [x]'.length).trim())
+      .toSet();
+
+  // generate domain tests
+  for (Domain domain in api.domains) {
+    group('integration coverage of ${domain.name}', () {
+      // domain
+      test('domain', () {
+        if (!coveredDomains.contains(domain.name)) {
+          fail('${domain.name} domain not found in ${coverageFile.path}');
+        }
+      });
+
+      // requests
+      for (Request request in domain.requests) {
+        String fullName = '${domain.name}.${request.method}';
+        test(fullName, () {
+          if (!allMembers.contains(fullName)) {
+            fail('$fullName not found in ${coverageFile.path}');
+          }
+
+          final String fileName = getCamelWords(request.method)
+              .map((s) => s.toLowerCase())
+              .join('_');
+          final String testName =
+              path.join(domain.name, '${fileName}_test.dart');
+          final String testPath =
+              path.join(pathPrefix, 'test', 'integration', testName);
+
+          // Test that if checked, a test file exists; if not checked, no such
+          // file exists.
+          expect(FileSystemEntity.isFileSync(testPath),
+              coveredMembers.contains(fullName),
+              reason: '$testName state incorrect');
+        });
+      }
+    });
+  }
+
+  // validate no unexpected domains
+  group('integration coverage', () {
+    test('no unexpected domains', () {
+      for (String domain in coveredDomains) {
+        expect(api.domains.map((d) => d.name), contains(domain));
+      }
+    });
+  });
+}
diff --git a/pkg/analysis_server/test/integration/execution/create_context_test.dart b/pkg/analysis_server/test/integration/execution/create_context_test.dart
new file mode 100644
index 0000000..66e6b21
--- /dev/null
+++ b/pkg/analysis_server/test/integration/execution/create_context_test.dart
@@ -0,0 +1,27 @@
+// 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:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../integration_tests.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CreateContextTest);
+  });
+}
+
+@reflectiveTest
+class CreateContextTest extends AbstractAnalysisServerIntegrationTest {
+  test_create() async {
+    standardAnalysisSetup();
+    String contextId =
+        (await sendExecutionCreateContext(sourceDirectory.path)).id;
+    expect(contextId, isNotNull);
+  }
+
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analysis_server/test/integration/execution/delete_context_test.dart b/pkg/analysis_server/test/integration/execution/delete_context_test.dart
new file mode 100644
index 0000000..2f16dc1
--- /dev/null
+++ b/pkg/analysis_server/test/integration/execution/delete_context_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../integration_tests.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(DeleteContextTest);
+  });
+}
+
+@reflectiveTest
+class DeleteContextTest extends AbstractAnalysisServerIntegrationTest {
+  test_delete() async {
+    String pathname = sourcePath('lib/main.dart');
+    writeFile(pathname, '// dummy');
+    writeFile(sourcePath('.packages'), 'foo:lib/');
+    standardAnalysisSetup();
+
+    String contextId =
+        (await sendExecutionCreateContext(sourceDirectory.path)).id;
+
+    ExecutionMapUriResult result =
+        await sendExecutionMapUri(contextId, uri: 'package:foo/main.dart');
+    expect(result.file, pathname);
+
+    expect(await sendExecutionDeleteContext(contextId), isNull);
+
+    // After the delete, expect this to fail.
+    try {
+      result =
+          await sendExecutionMapUri(contextId, uri: 'package:foo/main.dart');
+      fail('expected exception after context delete');
+    } on ServerErrorMessage catch (message) {
+      expect(message.error['code'], 'INVALID_PARAMETER');
+    }
+  }
+
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analysis_server/test/integration/execution/map_uri_test.dart b/pkg/analysis_server/test/integration/execution/map_uri_test.dart
new file mode 100644
index 0000000..dcece47
--- /dev/null
+++ b/pkg/analysis_server/test/integration/execution/map_uri_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../integration_tests.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MapUriTest);
+    defineReflectiveTests(MapUriTest_Driver);
+  });
+}
+
+abstract class AbstractMapUriTest extends AbstractAnalysisServerIntegrationTest {
+  test_mapUri() async {
+    String pathname = sourcePath('lib/main.dart');
+    writeFile(pathname, '// dummy');
+    writeFile(sourcePath('.packages'), 'foo:lib/');
+    standardAnalysisSetup();
+
+    String contextId =
+        (await sendExecutionCreateContext(sourceDirectory.path))?.id;
+
+    {
+      ExecutionMapUriResult result =
+          await sendExecutionMapUri(contextId, uri: 'package:foo/main.dart');
+      expect(result.file, pathname);
+    }
+
+    {
+      ExecutionMapUriResult result =
+          await sendExecutionMapUri(contextId, file: pathname);
+      expect(result.uri, 'package:foo/main.dart');
+    }
+  }
+}
+
+@reflectiveTest
+class MapUriTest extends AbstractMapUriTest {}
+
+@reflectiveTest
+class MapUriTest_Driver extends AbstractMapUriTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analysis_server/test/integration/execution/test_all.dart b/pkg/analysis_server/test/integration/execution/test_all.dart
new file mode 100644
index 0000000..f24942d
--- /dev/null
+++ b/pkg/analysis_server/test/integration/execution/test_all.dart
@@ -0,0 +1,17 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'create_context_test.dart' as create_context_test;
+import 'delete_context_test.dart' as delete_context_test;
+import 'map_uri_test.dart' as map_uri_test;
+
+main() {
+  defineReflectiveSuite(() {
+    create_context_test.main();
+    delete_context_test.main();
+    map_uri_test.main();
+  }, name: 'execution');
+}
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index b278c96..59cbe57 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -177,7 +177,9 @@
    * [sourceDirectory] is created.
    */
   Future setUp() {
-    sourceDirectory = Directory.systemTemp.createTempSync('analysisServer');
+    sourceDirectory = new Directory(Directory.systemTemp
+        .createTempSync('analysisServer')
+        .resolveSymbolicLinksSync());
 
     onAnalysisErrors.listen((AnalysisErrorsParams params) {
       currentAnalysisErrors[params.file] = params.errors;
@@ -278,6 +280,17 @@
 }
 
 /**
+ * An error result from a server request.
+ */
+class ServerErrorMessage {
+  final Map message;
+
+  ServerErrorMessage(this.message);
+
+  dynamic get error => message['error'];
+}
+
+/**
  * Wrapper class for Matcher which doesn't create the underlying Matcher object
  * until it is needed.  This is necessary in order to create matchers that can
  * refer to themselves (so that recursive data structures can be represented).
@@ -575,9 +588,7 @@
           _pendingCommands.remove(id);
         }
         if (messageAsMap.containsKey('error')) {
-          // TODO(paulberry): propagate the error info to the completer.
-          completer.completeError(new UnimplementedError(
-              'Server responded with an error: ${JSON.encode(message)}'));
+          completer.completeError(new ServerErrorMessage(messageAsMap));
         } else {
           completer.complete(messageAsMap['result']);
         }
@@ -643,6 +654,7 @@
       bool debugServer: false,
       int diagnosticPort,
       bool enableNewAnalysisDriver: false,
+      bool noErrorNotification: false,
       bool profileServer: false,
       String sdkPath,
       int servicesPort,
@@ -698,8 +710,11 @@
     if (useAnalysisHighlight2) {
       arguments.add('--useAnalysisHighlight2');
     }
-    if (enableNewAnalysisDriver) {
-      arguments.add('--enable-new-analysis-driver');
+    if (!enableNewAnalysisDriver) {
+      arguments.add('--disable-new-analysis-driver');
+    }
+    if (noErrorNotification) {
+      arguments.add('--no-error-notification');
     }
 //    print('Launching $serverPath');
 //    print('$dartBinary ${arguments.join(' ')}');
diff --git a/pkg/analysis_server/test/integration/test_all.dart b/pkg/analysis_server/test/integration/test_all.dart
index 3eda5bdf..8e0c603 100644
--- a/pkg/analysis_server/test/integration/test_all.dart
+++ b/pkg/analysis_server/test/integration/test_all.dart
@@ -8,6 +8,8 @@
 
 import 'analysis/test_all.dart' as analysis_test_all;
 import 'completion/test_all.dart' as completion_test_all;
+import 'coverage_test.dart' as coverage_test;
+import 'execution/test_all.dart' as execution_test_all;
 import 'search/test_all.dart' as search_test_all;
 import 'server/test_all.dart' as server_test_all;
 
@@ -18,7 +20,10 @@
   defineReflectiveSuite(() {
     analysis_test_all.main();
     completion_test_all.main();
+    execution_test_all.main();
     search_test_all.main();
     server_test_all.main();
+
+    coverage_test.main();
   }, name: 'analysis_server_integration');
 }
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index e796abb..c553188 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -74,6 +74,12 @@
     assertTarget(')', '()', argIndex: 0, isFunctionalArgument: true);
   }
 
+  test_ArgumentList_InstanceCreationExpression_functionArg3() {
+    // ArgumentList  InstanceCreationExpression  Block
+    addTestSource('main() {new B(1, f: ^)} class B{B(int i, {f()}){}}');
+    assertTarget('', 'f: ', argIndex: 1, isFunctionalArgument: true);
+  }
+
   test_ArgumentList_MethodInvocation() {
     // ArgumentList  MethodInvocation  Block
     addTestSource('main() {foo(^)}');
@@ -116,6 +122,18 @@
     assertTarget(')', '()', argIndex: 0, isFunctionalArgument: true);
   }
 
+  test_ArgumentList_MethodInvocation_functionArg3() {
+    // ArgumentList  MethodInvocation  Block
+    addTestSource('main() {foo(f: ^)} foo({f()}) {}');
+    assertTarget('', 'f: ', argIndex: 0, isFunctionalArgument: true);
+  }
+
+  test_ArgumentList_MethodInvocation_functionArg4() {
+    // ArgumentList  MethodInvocation  Block
+    addTestSource('main() {new B().boo(f: ^)} class B{boo({f()}){}}');
+    assertTarget('', 'f: ', argIndex: 0, isFunctionalArgument: true);
+  }
+
   test_AsExpression_identifier() {
     // SimpleIdentifier  TypeName  AsExpression
     addTestSource('class A {var b; X _c; foo() {var a; (a^ as String).foo();}');
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index 5d7c085..3ac9fd8 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -229,7 +229,7 @@
   }
 
   test_ArgumentList_imported_constructor_named_param() async {
-    //
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement
     addSource('/libA.dart', 'library libA; class A{A({int one}); }');
     addTestSource('import "/libA.dart"; main() { new A(^);}');
     await computeSuggestions();
@@ -237,7 +237,7 @@
   }
 
   test_ArgumentList_imported_constructor_named_param2() async {
-    //
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement
     addSource('/libA.dart', 'library libA; class A{A.foo({int one}); }');
     addTestSource('import "/libA.dart"; main() { new A.foo(^);}');
     await computeSuggestions();
@@ -245,7 +245,7 @@
   }
 
   test_ArgumentList_imported_constructor_named_typed_param() async {
-    //
+    // ArgumentList  InstanceCreationExpression  VariableDeclaration
     addSource(
         '/libA.dart', 'library libA; class A { A({int i, String s, d}) {} }}');
     addTestSource('import "/libA.dart"; main() { var a = new A(^);}');
@@ -254,6 +254,34 @@
         namedArgumentsWithTypes: {'i': 'int', 's': 'String', 'd': 'dynamic'});
   }
 
+  test_ArgumentList_imported_factory_named_param() async {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement
+    addSource(
+        '/libA.dart', 'library libA; class A{factory A({int one}) => null;}');
+    addTestSource('import "/libA.dart"; main() { new A(^);}');
+    await computeSuggestions();
+    assertSuggestArgumentsAndTypes(namedArgumentsWithTypes: {'one': 'int'});
+  }
+
+  test_ArgumentList_imported_factory_named_param2() async {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement
+    addSource('/libA.dart',
+        'library libA; abstract class A{factory A.foo({int one});}');
+    addTestSource('import "/libA.dart"; main() { new A.foo(^);}');
+    await computeSuggestions();
+    assertSuggestArgumentsAndTypes(namedArgumentsWithTypes: {'one': 'int'});
+  }
+
+  test_ArgumentList_imported_factory_named_typed_param() async {
+    // ArgumentList  InstanceCreationExpression  VariableDeclaration
+    addSource('/libA.dart',
+        'library libA; class A {factory A({int i, String s, d}) {} }}');
+    addTestSource('import "/libA.dart"; main() { var a = new A(^);}');
+    await computeSuggestions();
+    assertSuggestArgumentsAndTypes(
+        namedArgumentsWithTypes: {'i': 'int', 's': 'String', 'd': 'dynamic'});
+  }
+
   test_ArgumentList_imported_function_0() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
@@ -453,6 +481,60 @@
         namedArgumentsWithTypes: {'radix': 'int', 'onError': '(String) → int'});
   }
 
+  test_ArgumentList_local_constructor_named_fieldFormal_documentation() async {
+    String content = '''
+class A {
+  /// aaa
+  ///
+  /// bbb
+  /// ccc
+  int fff;
+  A({this.fff});
+}
+main() {
+  new A(^);
+}
+''';
+    addTestSource(content);
+    await computeSuggestions();
+    expect(suggestions, hasLength(1));
+
+    CompletionSuggestion suggestion = suggestions[0];
+    expect(suggestion.docSummary, 'aaa');
+    expect(suggestion.docComplete, 'aaa\n\nbbb\nccc');
+
+    Element element = suggestion.element;
+    expect(element, isNotNull);
+    expect(element.kind, ElementKind.PARAMETER);
+    expect(element.name, 'fff');
+    expect(element.location.offset, content.indexOf('fff})'));
+  }
+
+  test_ArgumentList_local_constructor_named_fieldFormal_noDocumentation() async {
+    String content = '''
+class A {
+  int fff;
+  A({this.fff});
+}
+main() {
+  new A(^);
+}
+''';
+    addTestSource(content);
+    await computeSuggestions();
+    expect(suggestions, hasLength(1));
+
+    CompletionSuggestion suggestion = suggestions[0];
+    expect(suggestion.docSummary, isNull);
+    expect(suggestion.docComplete, isNull);
+
+    Element element = suggestion.element;
+    expect(element, isNotNull);
+    expect(element.kind, ElementKind.PARAMETER);
+    expect(element.name, 'fff');
+    expect(element.location.offset, content.indexOf('fff})'));
+  }
+
   test_ArgumentList_local_constructor_named_param() async {
     //
     addTestSource('''
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 6d85584..2a0bd25 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -18,6 +18,7 @@
     show DartCompletionRequestImpl, ReplacementRange;
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_context.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/task/dart.dart';
@@ -465,7 +466,7 @@
     }
     CompletionRequestImpl baseRequest = new CompletionRequestImpl(
         analysisResult,
-        enableNewAnalysisDriver ? null: context,
+        enableNewAnalysisDriver ? null : context,
         provider,
         searchEngine,
         testSource,
@@ -547,7 +548,8 @@
     return cs;
   }
 
-  Future/*<E>*/ performAnalysis/*<E>*/(int times, Completer/*<E>*/ completer) async {
+  Future/*<E>*/ performAnalysis/*<E>*/(
+      int times, Completer/*<E>*/ completer) async {
     if (completer.isCompleted) {
       return completer.future;
     }
@@ -579,7 +581,8 @@
   void setUp() {
     super.setUp();
     index = createMemoryIndex();
-    searchEngine = new SearchEngineImpl(index);
+    searchEngine =
+        new SearchEngineImpl(index, (_) => new AstProviderForContext(context));
     contributor = createContributor();
   }
 }
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 4f05941..c9462d3 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
@@ -470,13 +470,202 @@
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_catch() async {
+  test_catch_1a() async {
+    // '}'  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} ^}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_1b() async {
+    // [ExpressionStatement 'c']  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} c^}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_1c() async {
+    // [EmptyStatement] Block BlockFunction FunctionExpression
+    addTestSource('main() {try {} ^;}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_1d() async {
+    // [EmptyStatement] Block BlockFunction FunctionExpression
+    addTestSource('main() {try {} ^ Foo foo;}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_2a() async {
+    // '}'  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} on SomeException {} ^}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_2b() async {
+    // [ExpressionStatement 'c']  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} on SomeException {} c^}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_2c() async {
+    // [EmptyStatement] Block BlockFunction FunctionExpression
+    addTestSource('main() {try {} on SomeException {} ^;}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_2d() async {
+    // [EmptyStatement] Block BlockFunction FunctionExpression
+    addTestSource('main() {try {} on SomeException {} ^ Foo foo;}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_3a() async {
+    // '}'  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} catch (e) {} ^}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_3b() async {
+    // [ExpressionStatement 'c']  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} catch (e) {} c^}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_3c() async {
+    // [EmptyStatement] Block BlockFunction FunctionExpression
+    addTestSource('main() {try {} catch (e) {} ^;}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_3d() async {
+    // [EmptyStatement] Block BlockFunction FunctionExpression
+    addTestSource('main() {try {} catch (e) {} ^ Foo foo;}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    keywords.add(Keyword.FINALLY);
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_4a1() async {
+    // [CatchClause]  TryStatement  Block
+    addTestSource('main() {try {} ^ on SomeException {}}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_4a2() async {
+    // ['c' VariableDeclarationStatement]  Block  BlockFunctionBody
+    addTestSource('main() {try {} c^ on SomeException {}}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    // TODO(danrubel) finally should not be suggested here
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_4b1() async {
+    // [CatchClause]  TryStatement  Block
+    addTestSource('main() {try {} ^ catch (e) {}}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_4b2() async {
+    // ['c' ExpressionStatement]  Block  BlockFunctionBody
+    addTestSource('main() {try {} c^ catch (e) {}}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    // TODO(danrubel) finally should not be suggested here
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_4c1() async {
+    // ['finally']  TryStatement  Block
+    addTestSource('main() {try {} ^ finally {}}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_4c2() async {
+    // ['c' ExpressionStatement]  Block  BlockFunctionBody
+    addTestSource('main() {try {} c^ finally {}}');
+    await computeSuggestions();
+    var keywords = <Keyword>[];
+    keywords.add(Keyword.CATCH);
+    // TODO(danrubel) finally should not be suggested here
+    keywords.add(Keyword.FINALLY);
+    assertSuggestKeywords(keywords, pseudoKeywords: ['on']);
+  }
+
+  test_catch_block() async {
+    // '}'  Block  CatchClause  TryStatement  Block
     addTestSource('main() {try {} catch (e) {^}}}');
     await computeSuggestions();
     var keywords = <Keyword>[];
     keywords.addAll(STMT_START_OUTSIDE_CLASS);
     keywords.add(Keyword.RETHROW);
-    assertSuggestKeywords(keywords, relevance: DART_RELEVANCE_KEYWORD);
+    assertSuggestKeywords(keywords);
   }
 
   test_class() async {
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index 20cf6ef..45624f2 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -262,7 +262,7 @@
 import '/libA.dart';
 class B { }
 String bar(f()) => true;
-void main() {bar(^);}''');
+void main() {boo(){} bar(^);}''');
     await computeSuggestions();
 
     expect(replacementOffset, completionOffset);
@@ -271,6 +271,45 @@
     assertSuggestFunction('bar', 'String',
         kind: CompletionSuggestionKind.IDENTIFIER,
         relevance: DART_RELEVANCE_LOCAL_FUNCTION);
+    assertSuggestFunction('boo', 'dynamic',
+        kind: CompletionSuggestionKind.IDENTIFIER,
+        relevance: DART_RELEVANCE_LOCAL_FUNCTION);
+    assertNotSuggested('hasLength');
+    assertNotSuggested('identical');
+    assertSuggestClass('B', kind: CompletionSuggestionKind.IDENTIFIER);
+    assertNotSuggested('A');
+    assertNotSuggested('Object');
+    assertNotSuggested('main');
+    assertNotSuggested('baz');
+    assertNotSuggested('print');
+  }
+
+  test_ArgumentList_MethodInvocation_functionalArg2() async {
+    // ArgumentList  MethodInvocation  ExpressionStatement  Block
+    addSource(
+        '/libA.dart',
+        '''
+library A;
+class A { A(f()) { } }
+bool hasLength(int expected) { }
+void baz() { }''');
+    addTestSource('''
+import 'dart:async';
+import '/libA.dart';
+class B { }
+String bar({inc()}) => true;
+void main() {boo(){} bar(inc: ^);}''');
+    await computeSuggestions();
+
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
+    assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+    assertSuggestFunction('bar', 'String',
+        kind: CompletionSuggestionKind.IDENTIFIER,
+        relevance: DART_RELEVANCE_LOCAL_FUNCTION + DART_RELEVANCE_INCREMENT);
+    assertSuggestFunction('boo', 'dynamic',
+        kind: CompletionSuggestionKind.IDENTIFIER,
+        relevance: DART_RELEVANCE_LOCAL_FUNCTION + DART_RELEVANCE_INCREMENT);
     assertNotSuggested('hasLength');
     assertNotSuggested('identical');
     assertSuggestClass('B', kind: CompletionSuggestionKind.IDENTIFIER);
diff --git a/pkg/analysis_server/test/services/completion/dart/optype_test.dart b/pkg/analysis_server/test/services/completion/dart/optype_test.dart
index 17cf6c4..15fcb87 100644
--- a/pkg/analysis_server/test/services/completion/dart/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/optype_test.dart
@@ -103,6 +103,90 @@
     assertOpType(namedArgs: true, returnValue: true, typeNames: true);
   }
 
+  test_ArgumentList_constructor_named_resolved_1_0() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement Block
+    addTestSource(
+        'main() { new A.b(^); }'
+        'class A{ A.b({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_constructor_named_resolved_1_1() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement  Block
+    addTestSource(
+        'main() { new A.b(o^); }'
+        'class A { A.b({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_constructor_resolved_1_0() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement Block
+    addTestSource(
+        'main() { new A(^); }'
+        'class A{ A({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_constructor_resolved_1_1() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement  Block
+    addTestSource(
+        'main() { new A(o^); }'
+        'class A { A({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_factory_named_resolved_1_0() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement Block
+    addTestSource(
+        'main() { new A.b(^); }'
+        'class A{ factory A.b({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_factory_named_resolved_1_1() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement  Block
+    addTestSource(
+        'main() { new A.b(o^); }'
+        'class A { factory A.b({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_factory_resolved_1_0() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement Block
+    addTestSource(
+        'main() { new A(^); }'
+        'class A{ factory A({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_factory_resolved_1_1() {
+    // ArgumentList  InstanceCreationExpression  ExpressionStatement  Block
+    addTestSource(
+        'main() { new A(o^); }'
+        'class A { factory A({one, two}) {} }',
+        resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_method_resolved_1_0() {
+    // ArgumentList  MethodInvocation  ExpressionStatement  Block
+    addTestSource('main() { foo(^);} foo({one, two}) {}', resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
+  test_ArgumentList_method_resolved_1_1() {
+    // ArgumentList  MethodInvocation  ExpressionStatement  Block
+    addTestSource('main() { foo(o^);} foo({one, two}) {}', resolved: true);
+    assertOpType(namedArgs: true);
+  }
+
   test_ArgumentList_namedParam() {
     // SimpleIdentifier  NamedExpression  ArgumentList  MethodInvocation
     // ExpressionStatement
@@ -122,18 +206,6 @@
     assertOpType(returnValue: true, typeNames: true);
   }
 
-  test_ArgumentList_resolved_1_0() {
-    // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addTestSource('main() { foo(^);} foo({one, two}) {}', resolved: true);
-    assertOpType(namedArgs: true);
-  }
-
-  test_ArgumentList_resolved_1_1() {
-    // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addTestSource('main() { foo(o^);} foo({one, two}) {}', resolved: true);
-    assertOpType(namedArgs: true);
-  }
-
   test_ArgumentList_resolved_2_0() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('void main() {int.parse("16", ^)}', resolved: true);
@@ -303,6 +375,122 @@
     assertOpType(returnValue: true, typeNames: true, voidReturn: true);
   }
 
+  test_Block_catch_1a() async {
+    // '}'  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} ^}');
+    // Only return 'on', 'catch', and 'finally' keywords
+    assertOpType();
+  }
+
+  test_Block_catch_1b() async {
+    // [ExpressionStatement 'c']  Block  BlockFunctionBody
+    addTestSource('main() {try {} c^}');
+    // Only return 'on', 'catch', and 'finally' keywords
+    assertOpType();
+  }
+
+  test_Block_catch_1c() async {
+    // [EmptyStatement]  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} ^;}');
+    // Only return 'on', 'catch', and 'finally' keywords
+    assertOpType();
+  }
+
+  test_Block_catch_1d() async {
+    // [VariableDeclarationStatement 'Foo foo']  Block  BlockFunctionBody
+    addTestSource('main() {try {} ^ Foo foo;}');
+    // Only return 'on', 'catch', and 'finally' keywords
+    assertOpType();
+  }
+
+  test_Block_catch_2a() async {
+    // '}'  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} catch () {} ^}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_2b() async {
+    // [ExpressionStatement 'c']  Block  BlockFunctionBody
+    addTestSource('main() {try {} catch () {} c^}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_2c() async {
+    // [EmptyStatement]  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} catch () {} ^;}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_2d() async {
+    // [VariableDeclarationStatement 'Foo foo']  Block  BlockFunctionBody
+    addTestSource('main() {try {} catch () {} ^ Foo foo;}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_3a() async {
+    // '}'  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} finally {} ^}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_3b() async {
+    // [ExpressionStatement 'c']  Block  BlockFunctionBody
+    addTestSource('main() {try {} finally {} c^}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_3c() async {
+    // [EmptyStatement]  Block  BlockFunctionBody  FunctionExpression
+    addTestSource('main() {try {} finally {} ^;}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_Block_catch_3d() async {
+    // [VariableDeclarationStatement 'Foo foo']  Block  BlockFunctionBody
+    addTestSource('main() {try {} finally {} ^ Foo foo;}');
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+  }
+
+  test_catch_4a1() async {
+    addTestSource('main() {try {} ^ on SomeException {}}');
+    assertOpType();
+  }
+
+  test_catch_4a2() async {
+    addTestSource('main() {try {} c^ on SomeException {}}');
+    assertOpType();
+  }
+
+  test_catch_4b1() async {
+    addTestSource('main() {try {} ^ catch (e) {}}');
+    assertOpType();
+  }
+
+  test_catch_4b2() async {
+    addTestSource('main() {try {} c^ catch (e) {}}');
+    assertOpType();
+  }
+
+  test_catch_4c1() async {
+    addTestSource('main() {try {} ^ finally {}}');
+    assertOpType();
+  }
+
+  test_catch_4c2() async {
+    addTestSource('main() {try {} c^ finally {}}');
+    assertOpType();
+  }
+
+  test_catch_5a() async {
+    addTestSource('main() {try {} on ^ finally {}}');
+    assertOpType(typeNames: true);
+  }
+
+  test_catch_5b() async {
+    addTestSource('main() {try {} on E^ finally {}}');
+    assertOpType(typeNames: true);
+  }
+
   test_Block_empty() {
     // Block  BlockFunctionBody  MethodDeclaration  ClassDeclaration
     addTestSource('class A extends E implements I with M {a() {^}}');
@@ -1558,6 +1746,12 @@
     addTestSource('mth() { while (b^) {} }}');
     assertOpType(returnValue: true, typeNames: true);
   }
+
+  test_WithClause() {
+    // WithClause  ClassDeclaration
+    addTestSource('class x extends Object with ^\n{}');
+    assertOpType(typeNames: true);
+  }
 }
 
 class _TestSource implements Source {
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 2f0e0bc..d6bd2db 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -17,6 +17,8 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/parser.dart';
@@ -161,6 +163,7 @@
           provider,
           driver.getTopLevelNameDeclarations,
           resolutionMap.elementDeclaredByCompilationUnit(testUnit).context,
+          new AstProviderForDriver(driver),
           testUnit,
           error);
       return await new DefaultFixContributor().internalComputeFixes(fixContext);
@@ -472,7 +475,7 @@
     // Has fix for "await".
     {
       AnalysisError error = errors[1];
-      expect(error.message, startsWith("Undefined name 'await'."));
+      expect(error.message, startsWith("Undefined name 'await' in function"));
       List<Fix> fixes = await _computeFixes(error);
       // has exactly one fix
       expect(fixes, hasLength(1));
@@ -5647,11 +5650,14 @@
   final AnalysisContext analysisContext;
 
   @override
+  final AstProvider astProvider;
+
+  @override
   final CompilationUnit unit;
 
   @override
   final AnalysisError error;
 
   _DartFixContextImpl(this.resourceProvider, this.getTopLevelDeclarations,
-      this.analysisContext, this.unit, this.error);
+      this.analysisContext, this.astProvider, this.unit, this.error);
 }
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index a57c988..8ea2d8d 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -22,6 +22,9 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart' show Element;
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_context.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:test/test.dart';
 
@@ -47,6 +50,7 @@
 abstract class RefactoringTest extends AbstractSingleUnitTest {
   Index index;
   SearchEngine searchEngine;
+  AstProvider astProvider;
 
   SourceChange refactoringChange;
 
@@ -180,9 +184,12 @@
     super.setUp();
     if (enableNewAnalysisDriver) {
       searchEngine = new SearchEngineImpl2([driver]);
+      astProvider = new AstProviderForDriver(driver);
     } else {
       index = createMemoryIndex();
-      searchEngine = new SearchEngineImpl(index);
+      searchEngine = new SearchEngineImpl(
+          index, (_) => new AstProviderForContext(context));
+      astProvider = new AstProviderForContext(context);
     }
   }
 }
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
index 0c89003..4498fe7 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
@@ -57,7 +57,7 @@
    * Fails if no [RenameRefactoring] can be created.
    */
   void createRenameRefactoringForElement(Element element) {
-    refactoring = new RenameRefactoring(searchEngine, element);
+    refactoring = new RenameRefactoring(searchEngine, astProvider, element);
     expect(refactoring, isNotNull, reason: "No refactoring for '$element'.");
   }
 
diff --git a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
index 9fb67da..d4fd186 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
@@ -157,7 +157,8 @@
   }
 
   void _createRefactoringForElement(ExecutableElement element) {
-    refactoring = new ConvertGetterToMethodRefactoring(searchEngine, element);
+    refactoring = new ConvertGetterToMethodRefactoring(
+        searchEngine, astProvider, element);
   }
 
   void _createRefactoringForString(String search) {
diff --git a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
index 313fe30..9629164 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
@@ -208,7 +208,7 @@
 
   void _createRefactoringForElement(ExecutableElement element) {
     refactoring = new ConvertMethodToGetterRefactoring(
-        searchEngine, getResolvedUnitWithElement, element);
+        searchEngine, astProvider, element);
   }
 
   void _createRefactoringForString(String search) {
diff --git a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
index 674b5a7..5bd5cf9 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
@@ -636,7 +636,8 @@
 
   void _createRefactoring(String search) {
     int offset = findOffset(search);
-    refactoring = new InlineLocalRefactoring(searchEngine, testUnit, offset);
+    refactoring =
+        new InlineLocalRefactoring(searchEngine, astProvider, testUnit, offset);
   }
 }
 
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 19fead0..9258b6c 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -1714,7 +1714,7 @@
   void _createRefactoring(String search) {
     int offset = findOffset(search);
     refactoring = new InlineMethodRefactoring(
-        searchEngine, getResolvedUnitWithElement, testUnit, offset);
+        searchEngine, astProvider, testUnit, offset);
   }
 }
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index b018389..205dc8a 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -235,7 +235,8 @@
   }
 
   test_newInstance_nullElement() async {
-    RenameRefactoring refactoring = new RenameRefactoring(searchEngine, null);
+    RenameRefactoring refactoring =
+        new RenameRefactoring(searchEngine, null, null);
     expect(refactoring, isNull);
   }
 
diff --git a/pkg/analysis_server/test/services/search/hierarchy_test.dart b/pkg/analysis_server/test/services/search/hierarchy_test.dart
index e8638dc..9f23cf7 100644
--- a/pkg/analysis_server/test/services/search/hierarchy_test.dart
+++ b/pkg/analysis_server/test/services/search/hierarchy_test.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal2.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_context.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -368,7 +369,8 @@
   void setUp() {
     super.setUp();
     index = createMemoryIndex();
-    searchEngine = new SearchEngineImpl(index);
+    searchEngine =
+        new SearchEngineImpl(index, (_) => new AstProviderForContext(context));
   }
 
   Future<Null> _indexTestUnit(String code) async {
diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart
index 152364d..b4832bb 100644
--- a/pkg/analysis_server/test/services/search/search_engine_test.dart
+++ b/pkg/analysis_server/test/services/search/search_engine_test.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_context.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -71,7 +72,8 @@
   void setUp() {
     super.setUp();
     index = createMemoryIndex();
-    searchEngine = new SearchEngineImpl(index);
+    searchEngine =
+        new SearchEngineImpl(index, (_) => new AstProviderForContext(context));
   }
 
   test_searchAllSubtypes() async {
@@ -508,8 +510,8 @@
   test_searchReferences_LibraryElement() async {
     var codeA = 'part of lib; // A';
     var codeB = 'part of lib; // B';
-    addSource('/unitA.dart', codeA);
-    addSource('/unitB.dart', codeB);
+    var sourceA = addSource('/unitA.dart', codeA);
+    var sourceB = addSource('/unitB.dart', codeB);
     await _indexTestUnit('''
 library lib;
 part 'unitA.dart';
@@ -518,8 +520,10 @@
     LibraryElement element = testLibraryElement;
     CompilationUnitElement unitElementA = element.parts[0];
     CompilationUnitElement unitElementB = element.parts[1];
-    index.indexUnit(unitElementA.computeNode());
-    index.indexUnit(unitElementB.computeNode());
+    index.indexUnit(
+        context.resolveCompilationUnit2(sourceA, testLibraryElement.source));
+    index.indexUnit(
+        context.resolveCompilationUnit2(sourceB, testLibraryElement.source));
     var expected = [
       new ExpectedMatch(unitElementA, MatchKind.REFERENCE,
           codeA.indexOf('lib; // A'), 'lib'.length),
diff --git a/pkg/analysis_server/test/src/plugin/plugin_locator_test.dart b/pkg/analysis_server/test/src/plugin/plugin_locator_test.dart
new file mode 100644
index 0000000..956987c
--- /dev/null
+++ b/pkg/analysis_server/test/src/plugin/plugin_locator_test.dart
@@ -0,0 +1,90 @@
+// 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:analysis_server/src/plugin/plugin_locator.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(PluginLocatorTest);
+  });
+}
+
+@reflectiveTest
+class PluginLocatorTest {
+  MemoryResourceProvider resourceProvider;
+  String packageRoot;
+  String pubspecPath;
+  String defaultDirPath;
+  PluginLocator locator;
+
+  void setUp() {
+    resourceProvider = new MemoryResourceProvider();
+    packageRoot = resourceProvider.convertPath('/package');
+    resourceProvider.newFolder(packageRoot);
+    locator = new PluginLocator(resourceProvider);
+  }
+
+  void test_findPlugin_inPubspec_defaultDir() {
+    String dirPath = _createPubspecWithKey();
+    _createDefaultDir();
+    expect(locator.findPlugin(packageRoot), dirPath);
+  }
+
+  void test_findPlugin_inPubspec_noDefaultDir() {
+    String dirPath = _createPubspecWithKey();
+    expect(locator.findPlugin(packageRoot), dirPath);
+  }
+
+  void test_findPlugin_noPubspec_defaultDir() {
+    _createDefaultDir();
+    expect(locator.findPlugin(packageRoot), defaultDirPath);
+  }
+
+  void test_findPlugin_noPubspec_noDefaultDir() {
+    expect(locator.findPlugin(packageRoot), isNull);
+  }
+
+  void test_findPlugin_notInPubspec_defaultDir() {
+    _createPubspecWithoutKey();
+    _createDefaultDir();
+    expect(locator.findPlugin(packageRoot), defaultDirPath);
+  }
+
+  void test_findPlugin_notInPubspec_noDefaultDir() {
+    _createPubspecWithoutKey();
+    expect(locator.findPlugin(packageRoot), isNull);
+  }
+
+  void _createDefaultDir() {
+    defaultDirPath = resourceProvider.pathContext.join(packageRoot,
+        PluginLocator.toolsFolderName, PluginLocator.defaultPluginFolderName);
+    resourceProvider.newFolder(defaultDirPath);
+  }
+
+  void _createPubspec(String content) {
+    pubspecPath = resourceProvider.pathContext
+        .join(packageRoot, PluginLocator.pubspecFileName);
+    resourceProvider.newFile(pubspecPath, content);
+  }
+
+  String _createPubspecWithKey() {
+    String nonDefaultPath =
+        resourceProvider.pathContext.join(packageRoot, 'pluginDir');
+    _createPubspec('''
+name: test_project
+${PluginLocator.analysisPluginKey}: $nonDefaultPath
+''');
+    resourceProvider.newFolder(nonDefaultPath);
+    return nonDefaultPath;
+  }
+
+  void _createPubspecWithoutKey() {
+    _createPubspec('''
+name: test_project
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart b/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart
new file mode 100644
index 0000000..37a3f01
--- /dev/null
+++ b/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart
@@ -0,0 +1,304 @@
+// 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:analysis_server/plugin/protocol/protocol.dart' as server;
+import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
+import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
+import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+
+class ProtocolTestUtilities {
+  static const List<String> strings = const <String>[
+    'aa',
+    'ab',
+    'ac',
+    'ad',
+    'ae',
+    'af',
+    'ag',
+    'ah',
+    'ai',
+    'aj',
+    'ak',
+    'al',
+    'am',
+    'an',
+    'ao',
+    'ap',
+    'aq',
+    'ar',
+    'as',
+    'at',
+    'au',
+    'av',
+    'aw',
+    'ax',
+    'ay',
+    'az',
+    'ba',
+    'bb',
+    'bc',
+    'bd',
+    'be',
+    'bf',
+    'bg',
+    'bh',
+    'bi',
+    'bj',
+    'bk',
+    'bl',
+    'bm',
+    'bn',
+    'bo',
+    'bp',
+    'bq',
+    'br',
+    'bs',
+    'bt',
+    'bu',
+    'bv',
+    'bw',
+    'bx',
+    'by',
+    'bz',
+  ];
+
+  String fileName(int stringIndex) => '${strings[stringIndex]}.dart';
+
+  /**
+   * On return, increment [stringIndex] by 3 (or 4 if no [file] name is
+   * provided) and [intIndex] by 4.
+   */
+  plugin.AnalysisError pluginAnalysisError(int stringIndex, int intIndex,
+      {String file}) {
+    return new plugin.AnalysisError(
+        plugin.AnalysisErrorSeverity.ERROR,
+        plugin.AnalysisErrorType.COMPILE_TIME_ERROR,
+        pluginLocation(stringIndex, intIndex, file: file),
+        strings[stringIndex++],
+        strings[stringIndex++],
+        correction: strings[stringIndex++],
+        hasFix: true);
+  }
+
+  /**
+   * On return, increment [stringIndex] by 5 and [intIndex] by 5.
+   */
+  plugin.Element pluginElement(int stringIndex, int intIndex,
+          {plugin.ElementKind kind}) =>
+      new plugin.Element(
+          kind ?? plugin.ElementKind.CLASS, strings[stringIndex++], intIndex++,
+          location: new plugin.Location(fileName(stringIndex++), intIndex++,
+              intIndex++, intIndex++, intIndex++),
+          parameters: strings[stringIndex++],
+          returnType: strings[stringIndex++],
+          typeParameters: strings[stringIndex++]);
+
+  plugin.FoldingRegion pluginFoldingRegion(int offset, int length) =>
+      new plugin.FoldingRegion(plugin.FoldingKind.COMMENT, offset, length);
+
+  plugin.HighlightRegion pluginHighlightRegion(int offset, int length) =>
+      new plugin.HighlightRegion(
+          plugin.HighlightRegionType.FIELD, offset, length);
+
+  /**
+   * On return, increment [stringIndex] by 1 and [intIndex] by 4.
+   */
+  plugin.Location pluginLocation(int stringIndex, int intIndex,
+          {String file}) =>
+      new plugin.Location(file ?? fileName(stringIndex), intIndex++, intIndex++,
+          intIndex++, intIndex++);
+
+  /**
+   * On return, increment [stringIndex] by 2 (or 3 if no [file] name is
+   * provided) and [intIndex] by 6.
+   */
+  plugin.AnalysisNavigationParams pluginNavigationParams(
+          int stringIndex, int intIndex, {String file}) =>
+      new plugin.AnalysisNavigationParams(
+          file ?? fileName(stringIndex++), <plugin.NavigationRegion>[
+        new plugin.NavigationRegion(intIndex++, intIndex++, <int>[0])
+      ], <plugin.NavigationTarget>[
+        new plugin.NavigationTarget(plugin.ElementKind.FIELD, 0, intIndex++,
+            intIndex++, intIndex++, intIndex++)
+      ], <String>[
+        strings[stringIndex++],
+        strings[stringIndex++]
+      ]);
+
+  /**
+   * On return, increment [stringIndex] by 5 and [intIndex] by 7.
+   */
+  plugin.Occurrences pluginOccurrences(int stringIndex, int intIndex) {
+    plugin.Element element = pluginElement(stringIndex, intIndex);
+    return new plugin.Occurrences(
+        element, <int>[intIndex + 5, intIndex + 6], element.name.length);
+  }
+
+  /**
+   * On return, increment [stringIndex] by 10 and [intIndex] by 14.
+   */
+  plugin.Outline pluginOutline(int stringIndex, int intIndex) =>
+      new plugin.Outline(
+          pluginElement(stringIndex, intIndex), intIndex + 5, intIndex + 6,
+          children: <plugin.Outline>[
+            new plugin.Outline(
+                pluginElement(stringIndex + 5, intIndex + 7,
+                    kind: plugin.ElementKind.METHOD),
+                intIndex + 12,
+                intIndex + 13)
+          ]);
+
+  /**
+   * On return, increment [stringIndex] by 2 and [intIndex] by 4.
+   */
+  plugin.RefactoringProblem pluginRefactoringProblem(
+      int stringIndex, int intIndex) {
+    return new plugin.RefactoringProblem(
+        plugin.RefactoringProblemSeverity.FATAL, strings[stringIndex++],
+        location: pluginLocation(stringIndex, intIndex));
+  }
+
+  /**
+   * On return, increment [stringIndex] by 6 and [intIndex] by 6.
+   */
+  plugin.SourceChange pluginSourceChange(int stringIndex, int intIndex) =>
+      new plugin.SourceChange(strings[stringIndex++],
+          edits: <plugin.SourceFileEdit>[
+            new plugin.SourceFileEdit(fileName(stringIndex), intIndex++,
+                edits: <plugin.SourceEdit>[
+                  new plugin.SourceEdit(
+                      intIndex++, intIndex++, strings[stringIndex++])
+                ])
+          ],
+          linkedEditGroups: <plugin.LinkedEditGroup>[
+            new plugin.LinkedEditGroup(
+                <plugin.Position>[
+                  new plugin.Position(fileName(stringIndex), intIndex++)
+                ],
+                intIndex++,
+                <plugin.LinkedEditSuggestion>[
+                  new plugin.LinkedEditSuggestion(strings[stringIndex++],
+                      plugin.LinkedEditSuggestionKind.METHOD)
+                ])
+          ],
+          selection: new plugin.Position(fileName(stringIndex), intIndex++));
+
+  /**
+   * On return, increment [stringIndex] by 3 (or 4 if no [file] name is
+   * provided) and [intIndex] by 4.
+   */
+  server.AnalysisError serverAnalysisError(int stringIndex, int intIndex,
+      {String file}) {
+    return new server.AnalysisError(
+        server.AnalysisErrorSeverity.ERROR,
+        server.AnalysisErrorType.COMPILE_TIME_ERROR,
+        serverLocation(stringIndex, intIndex, file: file),
+        strings[stringIndex++],
+        strings[stringIndex++],
+        correction: strings[stringIndex++],
+        hasFix: true);
+  }
+
+  /**
+   * On return, increment [stringIndex] by 5 and [intIndex] by 5.
+   */
+  server.Element serverElement(int stringIndex, int intIndex,
+          {server.ElementKind kind}) =>
+      new server.Element(
+          kind ?? server.ElementKind.CLASS, strings[stringIndex++], intIndex++,
+          location: new server.Location(fileName(stringIndex++), intIndex++,
+              intIndex++, intIndex++, intIndex++),
+          parameters: strings[stringIndex++],
+          returnType: strings[stringIndex++],
+          typeParameters: strings[stringIndex++]);
+
+  server.FoldingRegion serverFoldingRegion(int offset, int length) =>
+      new server.FoldingRegion(server.FoldingKind.COMMENT, offset, length);
+
+  server.HighlightRegion serverHighlightRegion(int offset, int length) =>
+      new server.HighlightRegion(
+          server.HighlightRegionType.FIELD, offset, length);
+
+  /**
+   * On return, increment [stringIndex] by 1 and [intIndex] by 4.
+   */
+  server.Location serverLocation(int stringIndex, int intIndex,
+          {String file}) =>
+      new server.Location(file ?? fileName(stringIndex), intIndex++, intIndex++,
+          intIndex++, intIndex++);
+
+  /**
+   * On return, increment [stringIndex] by 2 (or 3 if no [file] name is
+   * provided) and [intIndex] by 6.
+   */
+  server.AnalysisNavigationParams serverNavigationParams(
+          int stringIndex, int intIndex, {String file}) =>
+      new server.AnalysisNavigationParams(
+          file ?? fileName(stringIndex++), <server.NavigationRegion>[
+        new server.NavigationRegion(intIndex++, intIndex++, <int>[0])
+      ], <server.NavigationTarget>[
+        new server.NavigationTarget(server.ElementKind.FIELD, 0, intIndex++,
+            intIndex++, intIndex++, intIndex++)
+      ], <String>[
+        strings[stringIndex++],
+        strings[stringIndex++]
+      ]);
+
+  /**
+   * On return, increment [stringIndex] by 5 and [intIndex] by 7.
+   */
+  server.Occurrences serverOccurrences(int stringIndex, int intIndex) {
+    server.Element element = serverElement(stringIndex, intIndex);
+    return new server.Occurrences(
+        element, <int>[intIndex + 5, intIndex + 6], element.name.length);
+  }
+
+  /**
+   * On return, increment [stringIndex] by 10 and [intIndex] by 14.
+   */
+  server.Outline serverOutline(int stringIndex, int intIndex) =>
+      new server.Outline(
+          serverElement(stringIndex, intIndex), intIndex + 5, intIndex + 6,
+          children: <server.Outline>[
+            new server.Outline(
+                serverElement(stringIndex + 5, intIndex + 7,
+                    kind: server.ElementKind.METHOD),
+                intIndex + 12,
+                intIndex + 13)
+          ]);
+
+  /**
+   * On return, increment [stringIndex] by 2 and [intIndex] by 4.
+   */
+  server.RefactoringProblem serverRefactoringProblem(
+          int stringIndex, int intIndex) =>
+      new server.RefactoringProblem(
+          server.RefactoringProblemSeverity.FATAL, strings[stringIndex++],
+          location: serverLocation(stringIndex, intIndex));
+
+  /**
+   * On return, increment [stringIndex] by 6 and [intIndex] by 6.
+   */
+  server.SourceChange serverSourceChange(int stringIndex, int intIndex) =>
+      new server.SourceChange(strings[stringIndex++],
+          edits: <server.SourceFileEdit>[
+            new server.SourceFileEdit(fileName(stringIndex), intIndex++,
+                edits: <server.SourceEdit>[
+                  new server.SourceEdit(
+                      intIndex++, intIndex++, strings[stringIndex++])
+                ])
+          ],
+          linkedEditGroups: <server.LinkedEditGroup>[
+            new server.LinkedEditGroup(
+                <server.Position>[
+                  new server.Position(fileName(stringIndex), intIndex++)
+                ],
+                intIndex++,
+                <server.LinkedEditSuggestion>[
+                  new server.LinkedEditSuggestion(strings[stringIndex++],
+                      server.LinkedEditSuggestionKind.METHOD)
+                ])
+          ],
+          selection: new server.Position(fileName(stringIndex), intIndex++));
+}
diff --git a/pkg/analysis_server/test/src/plugin/result_collector_test.dart b/pkg/analysis_server/test/src/plugin/result_collector_test.dart
new file mode 100644
index 0000000..e6372c6
--- /dev/null
+++ b/pkg/analysis_server/test/src/plugin/result_collector_test.dart
@@ -0,0 +1,110 @@
+// 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:analysis_server/src/plugin/result_collector.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ResultCollectorTest);
+  });
+}
+
+@reflectiveTest
+class ResultCollectorTest {
+  static const String serverId = 'server';
+
+  ResultCollector<String> collector = new ResultCollector<String>(serverId);
+
+  void test_clearResultsForFile() {
+    String filePath1 = 'test1.dart';
+    String filePath2 = 'test2.dart';
+    String value1 = 'r1';
+    String value2 = 'r2';
+    collector.startCollectingFor(filePath1);
+    collector.startCollectingFor(filePath2);
+    collector.putResults(filePath1, 'p', value1);
+    collector.putResults(filePath2, 'p', value2);
+    expect(collector.getResults(filePath1), contains(value1));
+    expect(collector.getResults(filePath2), contains(value2));
+
+    collector.clearResultsForFile(filePath2);
+    expect(collector.getResults(filePath1), contains(value1));
+    expect(collector.getResults(filePath2), isEmpty);
+  }
+
+  void test_clearResultsFromPlugin() {
+    String filePath = 'test.dart';
+    String p1Name = 'p1';
+    String p2Name = 'p2';
+    String p1Value = 'r1';
+    String p2Value = 'r2';
+
+    collector.startCollectingFor(filePath);
+    collector.putResults(filePath, p1Name, p1Value);
+    collector.putResults(filePath, p2Name, p2Value);
+    expect(collector.getResults(filePath), contains(p1Value));
+    expect(collector.getResults(filePath), contains(p2Value));
+
+    collector.clearResultsFromPlugin(p1Name);
+    expect(collector.getResults(filePath), isNot(contains(p1Value)));
+    expect(collector.getResults(filePath), contains(p2Value));
+  }
+
+  void test_getResults_emptyCollector() {
+    expect(collector.getResults('test.dart'), isEmpty);
+  }
+
+  void test_getResults_serverFirst() {
+    // This is a flaky test in that it is possible for the test to pass even
+    // when the code is broken.
+    String filePath = 'test.dart';
+    String value1 = 'r1';
+    String value2 = 'r2';
+    collector.startCollectingFor(filePath);
+    collector.putResults(filePath, 'p', value1);
+    collector.putResults(filePath, serverId, value2);
+    expect(collector.getResults(filePath), <String>[value2, value1]);
+  }
+
+  void test_putResults_collecting() {
+    String filePath1 = 'test1.dart';
+    String filePath2 = 'test2.dart';
+    String value1 = 'r1';
+    String value2 = 'r2';
+    expect(collector.getResults(filePath1), isEmpty);
+    expect(collector.getResults(filePath2), isEmpty);
+
+    collector.startCollectingFor(filePath1);
+    collector.startCollectingFor(filePath2);
+    collector.putResults(filePath1, 'p', value1);
+    collector.putResults(filePath2, 'p', value2);
+    expect(collector.getResults(filePath1), contains(value1));
+    expect(collector.getResults(filePath1), isNot(contains(value2)));
+    expect(collector.getResults(filePath2), contains(value2));
+    expect(collector.getResults(filePath2), isNot(contains(value1)));
+  }
+
+  void test_putResults_notCollecting() {
+    String filePath = 'test.dart';
+    expect(collector.getResults(filePath), isEmpty);
+
+    collector.putResults(filePath, 'p', 'r');
+    expect(collector.getResults(filePath), isEmpty);
+  }
+
+  void test_stopCollectingFor() {
+    String filePath = 'test.dart';
+    String value = 'r';
+    collector.startCollectingFor(filePath);
+    collector.putResults(filePath, 'p', value);
+    expect(collector.getResults(filePath), contains(value));
+
+    collector.stopCollectingFor(filePath);
+    expect(collector.getResults(filePath), isEmpty);
+    collector.putResults(filePath, 'p', value);
+    expect(collector.getResults(filePath), isEmpty);
+  }
+}
diff --git a/pkg/analysis_server/test/src/plugin/result_converter_test.dart b/pkg/analysis_server/test/src/plugin/result_converter_test.dart
new file mode 100644
index 0000000..d882319
--- /dev/null
+++ b/pkg/analysis_server/test/src/plugin/result_converter_test.dart
@@ -0,0 +1,334 @@
+// 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:analysis_server/plugin/protocol/protocol.dart' as server;
+import 'package:analysis_server/src/plugin/result_converter.dart';
+import 'package:analysis_server/src/protocol/protocol_internal.dart' as server;
+import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'protocol_test_utilities.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ResultConverterTest);
+  });
+}
+
+@reflectiveTest
+class ResultConverterTest extends ProtocolTestUtilities {
+  static const List<String> strings = const <String>[
+    'a',
+    'b',
+    'c',
+    'd',
+    'e',
+    'f',
+    'g',
+    'h',
+    'i',
+    'j',
+    'k',
+    'l',
+    'm',
+    'n'
+  ];
+
+  ResultConverter converter = new ResultConverter();
+
+  void test_convertAnalysisError() {
+    plugin.AnalysisError initial = pluginAnalysisError(0, 0);
+    server.AnalysisError expected = serverAnalysisError(0, 0);
+    expect(converter.convertAnalysisError(initial), expected);
+  }
+
+  void test_convertAnalysisErrorFixes() {
+    plugin.AnalysisErrorFixes initial = new plugin.AnalysisErrorFixes(
+        pluginAnalysisError(0, 0),
+        fixes: <plugin.PrioritizedSourceChange>[
+          new plugin.PrioritizedSourceChange(100, pluginSourceChange(4, 4))
+        ]);
+    server.AnalysisErrorFixes expected = new server.AnalysisErrorFixes(
+        serverAnalysisError(0, 0),
+        fixes: <server.SourceChange>[serverSourceChange(4, 4)]);
+    expect(converter.convertAnalysisErrorFixes(initial), expected);
+  }
+
+  void test_convertAnalysisNavigationParams() {
+    plugin.AnalysisNavigationParams initial =
+        new plugin.AnalysisNavigationParams('a.dart', <plugin.NavigationRegion>[
+      new plugin.NavigationRegion(1, 2, <int>[3, 4])
+    ], <plugin.NavigationTarget>[
+      new plugin.NavigationTarget(plugin.ElementKind.FIELD, 5, 6, 7, 8, 9)
+    ], <String>[
+      'a',
+      'b'
+    ]);
+    server.AnalysisNavigationParams expected =
+        new server.AnalysisNavigationParams('a.dart', <server.NavigationRegion>[
+      new server.NavigationRegion(1, 2, <int>[3, 4])
+    ], <server.NavigationTarget>[
+      new server.NavigationTarget(server.ElementKind.FIELD, 5, 6, 7, 8, 9)
+    ], <String>[
+      'a',
+      'b'
+    ]);
+    expect(converter.convertAnalysisNavigationParams(initial), expected);
+  }
+
+  void test_convertCompletionSuggestion() {
+    plugin.CompletionSuggestion initial = new plugin.CompletionSuggestion(
+        plugin.CompletionSuggestionKind.IMPORT, 1, 'a', 2, 3, true, false,
+        docSummary: 'b',
+        docComplete: 'c',
+        declaringType: 'd',
+        element: pluginElement(4, 4),
+        returnType: 'i',
+        parameterNames: <String>['j', 'k'],
+        parameterTypes: <String>[],
+        requiredParameterCount: 9,
+        hasNamedParameters: true,
+        parameterName: 'l',
+        parameterType: 'm',
+        importUri: 'n');
+    server.CompletionSuggestion expected = new server.CompletionSuggestion(
+        server.CompletionSuggestionKind.IMPORT, 1, 'a', 2, 3, true, false,
+        docSummary: 'b',
+        docComplete: 'c',
+        declaringType: 'd',
+        element: serverElement(4, 4),
+        returnType: 'i',
+        parameterNames: <String>['j', 'k'],
+        parameterTypes: <String>[],
+        requiredParameterCount: 9,
+        hasNamedParameters: true,
+        parameterName: 'l',
+        parameterType: 'm',
+        importUri: 'n');
+    expect(converter.convertCompletionSuggestion(initial), expected);
+  }
+
+  void test_convertEditGetRefactoringResult_inlineMethod() {
+    plugin.EditGetRefactoringResult initial =
+        new plugin.EditGetRefactoringResult(
+            <plugin.RefactoringProblem>[pluginRefactoringProblem(0, 0)],
+            <plugin.RefactoringProblem>[pluginRefactoringProblem(2, 4)],
+            <plugin.RefactoringProblem>[pluginRefactoringProblem(4, 8)],
+            feedback:
+                new plugin.InlineMethodFeedback('a', true, className: 'b'),
+            change: pluginSourceChange(6, 12),
+            potentialEdits: <String>['f']);
+    server.EditGetRefactoringResult expected =
+        new server.EditGetRefactoringResult(
+            <server.RefactoringProblem>[serverRefactoringProblem(0, 0)],
+            <server.RefactoringProblem>[serverRefactoringProblem(2, 4)],
+            <server.RefactoringProblem>[serverRefactoringProblem(4, 8)],
+            feedback:
+                new server.InlineMethodFeedback('a', true, className: 'b'),
+            change: serverSourceChange(6, 12),
+            potentialEdits: <String>['f']);
+    expect(
+        converter.convertEditGetRefactoringResult(
+            plugin.RefactoringKind.INLINE_METHOD, initial),
+        expected);
+  }
+
+  void test_convertEditGetRefactoringResult_moveFile() {
+    plugin.EditGetRefactoringResult initial =
+        new plugin.EditGetRefactoringResult(
+            <plugin.RefactoringProblem>[pluginRefactoringProblem(0, 0)],
+            <plugin.RefactoringProblem>[pluginRefactoringProblem(2, 4)],
+            <plugin.RefactoringProblem>[pluginRefactoringProblem(4, 8)],
+            feedback: new plugin.MoveFileFeedback(),
+            change: pluginSourceChange(6, 12),
+            potentialEdits: <String>['f']);
+    server.EditGetRefactoringResult expected =
+        new server.EditGetRefactoringResult(
+            <server.RefactoringProblem>[serverRefactoringProblem(0, 0)],
+            <server.RefactoringProblem>[serverRefactoringProblem(2, 4)],
+            <server.RefactoringProblem>[serverRefactoringProblem(4, 8)],
+            change: serverSourceChange(6, 12),
+            potentialEdits: <String>['f']);
+    expect(
+        converter.convertEditGetRefactoringResult(
+            plugin.RefactoringKind.MOVE_FILE, initial),
+        expected);
+  }
+
+  void test_convertFoldingRegion() {
+    plugin.FoldingRegion initial = pluginFoldingRegion(1, 2);
+    server.FoldingRegion expected = serverFoldingRegion(1, 2);
+    expect(converter.convertFoldingRegion(initial), expected);
+  }
+
+  void test_convertHighlightRegion() {
+    plugin.HighlightRegion initial = pluginHighlightRegion(1, 2);
+    server.HighlightRegion expected = serverHighlightRegion(1, 2);
+    expect(converter.convertHighlightRegion(initial), expected);
+  }
+
+  void test_convertOccurrences() {
+    plugin.Occurrences initial = pluginOccurrences(1, 1);
+    server.Occurrences expected = serverOccurrences(1, 1);
+    expect(converter.convertOccurrences(initial), expected);
+  }
+
+  void test_convertOutline() {
+    plugin.Outline initial = new plugin.Outline(pluginElement(1, 1), 6, 7,
+        children: <plugin.Outline>[
+          new plugin.Outline(pluginElement(6, 8), 14, 15)
+        ]);
+    server.Outline expected = new server.Outline(serverElement(1, 1), 6, 7,
+        children: <server.Outline>[
+          new server.Outline(serverElement(6, 8), 14, 15)
+        ]);
+    expect(converter.convertOutline(initial), expected);
+  }
+
+  void test_convertPrioritizedSourceChange() {
+    plugin.PrioritizedSourceChange initial =
+        new plugin.PrioritizedSourceChange(100, pluginSourceChange(0, 0));
+    server.SourceChange expected = serverSourceChange(0, 0);
+    expect(converter.convertPrioritizedSourceChange(initial), expected);
+  }
+
+  void test_convertRefactoringFeedback_convertGetterToMethod() {
+    plugin.ConvertGetterToMethodFeedback initial =
+        new plugin.ConvertGetterToMethodFeedback();
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.CONVERT_GETTER_TO_METHOD, initial),
+        isNull);
+  }
+
+  void test_convertRefactoringFeedback_convertMethodToGetter() {
+    plugin.ConvertMethodToGetterFeedback initial =
+        new plugin.ConvertMethodToGetterFeedback();
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.CONVERT_METHOD_TO_GETTER, initial),
+        isNull);
+  }
+
+  void test_convertRefactoringFeedback_extractLocalVariable() {
+    plugin.ExtractLocalVariableFeedback initial =
+        new plugin.ExtractLocalVariableFeedback(
+            <String>['a', 'b'], <int>[1, 2], <int>[3],
+            coveringExpressionOffsets: <int>[4, 5],
+            coveringExpressionLengths: <int>[6]);
+    server.ExtractLocalVariableFeedback expected =
+        new server.ExtractLocalVariableFeedback(
+            <String>['a', 'b'], <int>[1, 2], <int>[3],
+            coveringExpressionOffsets: <int>[4, 5],
+            coveringExpressionLengths: <int>[6]);
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.EXTRACT_LOCAL_VARIABLE, initial),
+        expected);
+  }
+
+  void test_convertRefactoringFeedback_extractMethod() {
+    plugin.ExtractMethodFeedback initial = new plugin.ExtractMethodFeedback(
+        1,
+        2,
+        'a',
+        <String>['b', 'c'],
+        true,
+        <plugin.RefactoringMethodParameter>[
+          new plugin.RefactoringMethodParameter(
+              plugin.RefactoringMethodParameterKind.NAMED, 'd', 'e',
+              id: 'f', parameters: 'g')
+        ],
+        <int>[3, 4],
+        <int>[5, 6]);
+    server.ExtractMethodFeedback expected = new server.ExtractMethodFeedback(
+        1,
+        2,
+        'a',
+        <String>['b', 'c'],
+        true,
+        <server.RefactoringMethodParameter>[
+          new server.RefactoringMethodParameter(
+              server.RefactoringMethodParameterKind.NAMED, 'd', 'e',
+              id: 'f', parameters: 'g')
+        ],
+        <int>[3, 4],
+        <int>[5, 6]);
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.EXTRACT_METHOD, initial),
+        expected);
+  }
+
+  void test_convertRefactoringFeedback_inlineLocalVariable() {
+    plugin.InlineLocalVariableFeedback initial =
+        new plugin.InlineLocalVariableFeedback('a', 1);
+    server.InlineLocalVariableFeedback expected =
+        new server.InlineLocalVariableFeedback('a', 1);
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.INLINE_LOCAL_VARIABLE, initial),
+        expected);
+  }
+
+  void test_convertRefactoringFeedback_inlineMethod() {
+    plugin.InlineMethodFeedback initial =
+        new plugin.InlineMethodFeedback('a', true, className: 'b');
+    server.InlineMethodFeedback expected =
+        new server.InlineMethodFeedback('a', true, className: 'b');
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.INLINE_METHOD, initial),
+        expected);
+  }
+
+  void test_convertRefactoringFeedback_moveFile() {
+    plugin.MoveFileFeedback initial = new plugin.MoveFileFeedback();
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.MOVE_FILE, initial),
+        isNull);
+  }
+
+  void test_convertRefactoringFeedback_rename() {
+    plugin.RenameFeedback initial = new plugin.RenameFeedback(1, 2, 'a', 'b');
+    server.RenameFeedback expected = new server.RenameFeedback(1, 2, 'a', 'b');
+    expect(
+        converter.convertRefactoringFeedback(
+            plugin.RefactoringKind.RENAME, initial),
+        expected);
+  }
+
+  void test_convertRefactoringKind() {
+    Map<plugin.RefactoringKind, server.RefactoringKind> kindMap =
+        <plugin.RefactoringKind, server.RefactoringKind>{
+      plugin.RefactoringKind.CONVERT_GETTER_TO_METHOD:
+          server.RefactoringKind.CONVERT_GETTER_TO_METHOD,
+      plugin.RefactoringKind.CONVERT_METHOD_TO_GETTER:
+          server.RefactoringKind.CONVERT_METHOD_TO_GETTER,
+      plugin.RefactoringKind.EXTRACT_LOCAL_VARIABLE:
+          server.RefactoringKind.EXTRACT_LOCAL_VARIABLE,
+      plugin.RefactoringKind.EXTRACT_METHOD:
+          server.RefactoringKind.EXTRACT_METHOD,
+      plugin.RefactoringKind.INLINE_LOCAL_VARIABLE:
+          server.RefactoringKind.INLINE_LOCAL_VARIABLE,
+      plugin.RefactoringKind.INLINE_METHOD:
+          server.RefactoringKind.INLINE_METHOD,
+      plugin.RefactoringKind.MOVE_FILE: server.RefactoringKind.MOVE_FILE,
+      plugin.RefactoringKind.RENAME: server.RefactoringKind.RENAME,
+      plugin.RefactoringKind.SORT_MEMBERS: server.RefactoringKind.SORT_MEMBERS,
+    };
+    kindMap.forEach(
+        (plugin.RefactoringKind pluginKind, server.RefactoringKind serverKind) {
+      expect(converter.convertRefactoringKind(pluginKind), serverKind);
+    });
+  }
+
+  void test_convertSourceChange() {
+    plugin.SourceChange initial = pluginSourceChange(0, 0);
+    server.SourceChange expected = serverSourceChange(0, 0);
+    expect(converter.convertSourceChange(initial), expected);
+  }
+}
diff --git a/pkg/analysis_server/test/src/plugin/result_merger_test.dart b/pkg/analysis_server/test/src/plugin/result_merger_test.dart
new file mode 100644
index 0000000..aa4213f
--- /dev/null
+++ b/pkg/analysis_server/test/src/plugin/result_merger_test.dart
@@ -0,0 +1,739 @@
+// 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:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/plugin/result_merger.dart';
+import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ResultMergerTest);
+  });
+}
+
+@reflectiveTest
+class ResultMergerTest {
+  //
+  // The tests in this class should always perform the merge operation twice
+  // using the same input values in order to ensure that the input values are
+  // not modified by the merge operation.
+  //
+
+  ResultMerger merger = new ResultMerger();
+
+  void test_mergeAnalysisErrorFixes() {
+    plugin.AnalysisError createError(int offset) {
+      plugin.AnalysisErrorSeverity severity =
+          plugin.AnalysisErrorSeverity.ERROR;
+      plugin.AnalysisErrorType type = plugin.AnalysisErrorType.HINT;
+      plugin.Location location =
+          new plugin.Location('test.dart', offset, 2, 3, 4);
+      return new plugin.AnalysisError(severity, type, location, '', '');
+    }
+
+    plugin.AnalysisError error1 = createError(10);
+    plugin.AnalysisError error2 = createError(20);
+    plugin.AnalysisError error3 = createError(30);
+    plugin.AnalysisError error4 = createError(40);
+    plugin.PrioritizedSourceChange change1 =
+        new plugin.PrioritizedSourceChange(1, new plugin.SourceChange('a'));
+    plugin.PrioritizedSourceChange change2 =
+        new plugin.PrioritizedSourceChange(2, new plugin.SourceChange('b'));
+    plugin.PrioritizedSourceChange change3 =
+        new plugin.PrioritizedSourceChange(3, new plugin.SourceChange('c'));
+    plugin.PrioritizedSourceChange change4 =
+        new plugin.PrioritizedSourceChange(4, new plugin.SourceChange('d'));
+    plugin.PrioritizedSourceChange change5 =
+        new plugin.PrioritizedSourceChange(5, new plugin.SourceChange('e'));
+    plugin.AnalysisErrorFixes fix1 =
+        new plugin.AnalysisErrorFixes(error1, fixes: [change1]);
+    plugin.AnalysisErrorFixes fix2 =
+        new plugin.AnalysisErrorFixes(error2, fixes: [change2]);
+    plugin.AnalysisErrorFixes fix3 =
+        new plugin.AnalysisErrorFixes(error2, fixes: [change3]);
+    plugin.AnalysisErrorFixes fix4 =
+        new plugin.AnalysisErrorFixes(error3, fixes: [change4]);
+    plugin.AnalysisErrorFixes fix5 =
+        new plugin.AnalysisErrorFixes(error4, fixes: [change5]);
+    plugin.AnalysisErrorFixes fix2and3 =
+        new plugin.AnalysisErrorFixes(error2, fixes: [change2, change3]);
+
+    void runTest() {
+      expect(
+          merger.mergeAnalysisErrorFixes([
+            [fix1, fix2],
+            [fix3, fix4],
+            [fix5],
+            []
+          ]),
+          unorderedEquals([fix1, fix2and3, fix4, fix5]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeAnalysisErrors() {
+    AnalysisError createError(int offset) {
+      AnalysisErrorSeverity severity = AnalysisErrorSeverity.ERROR;
+      AnalysisErrorType type = AnalysisErrorType.HINT;
+      Location location = new Location('test.dart', offset, 2, 3, 4);
+      return new AnalysisError(severity, type, location, '', '');
+    }
+
+    AnalysisError error1 = createError(10);
+    AnalysisError error2 = createError(20);
+    AnalysisError error3 = createError(30);
+    AnalysisError error4 = createError(40);
+
+    void runTest() {
+      expect(
+          merger.mergeAnalysisErrors([
+            [error1, error2],
+            [error3],
+            [],
+            [error4]
+          ]),
+          unorderedEquals([error1, error2, error3, error4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeCompletionSuggestions() {
+    CompletionSuggestion createSuggestion(String completion) =>
+        new CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER, 50,
+            completion, 0, 3, false, false);
+
+    CompletionSuggestion suggestion1 = createSuggestion('a');
+    CompletionSuggestion suggestion2 = createSuggestion('b');
+    CompletionSuggestion suggestion3 = createSuggestion('c');
+    CompletionSuggestion suggestion4 = createSuggestion('d');
+
+    void runTest() {
+      expect(
+          merger.mergeCompletionSuggestions([
+            [suggestion1],
+            [suggestion2, suggestion3, suggestion4],
+            []
+          ]),
+          unorderedEquals(
+              [suggestion1, suggestion2, suggestion3, suggestion4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeFoldingRegion() {
+    FoldingKind kind = FoldingKind.COMMENT;
+    FoldingRegion region1 = new FoldingRegion(kind, 30, 5);
+    FoldingRegion region2 = new FoldingRegion(kind, 0, 4);
+    FoldingRegion region3 = new FoldingRegion(kind, 20, 6);
+    FoldingRegion region4 = new FoldingRegion(kind, 10, 3);
+    FoldingRegion region5 = new FoldingRegion(kind, 2, 6); // overlaps
+
+    void runTest() {
+      expect(
+          merger.mergeFoldingRegions([
+            [region1, region2],
+            [],
+            [region3],
+            [region4, region5]
+          ]),
+          unorderedEquals([region1, region2, region3, region4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeHighlightRegions() {
+    HighlightRegionType type = HighlightRegionType.COMMENT_BLOCK;
+    HighlightRegion region1 = new HighlightRegion(type, 30, 5);
+    HighlightRegion region2 = new HighlightRegion(type, 0, 4);
+    HighlightRegion region3 = new HighlightRegion(type, 20, 6);
+    HighlightRegion region4 = new HighlightRegion(type, 10, 3);
+
+    void runTest() {
+      expect(
+          merger.mergeHighlightRegions([
+            [region1, region2],
+            [],
+            [region3],
+            [region4]
+          ]),
+          unorderedEquals([region1, region2, region3, region4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeNavigation() {
+    NavigationTarget target(int fileIndex, int offset) {
+      return new NavigationTarget(
+          ElementKind.CLASS, fileIndex, offset, 1, 0, 0);
+    }
+
+    //
+    // Create the parameters from the server.
+    //
+    NavigationTarget target1_1 = target(0, 1);
+    NavigationTarget target1_2 = target(0, 2);
+    NavigationTarget target2_1 = target(1, 3);
+    NavigationTarget target2_2 = target(1, 4);
+    NavigationRegion region1_1 = new NavigationRegion(10, 4, [0]);
+    NavigationRegion region1_2 = new NavigationRegion(20, 4, [1]);
+    NavigationRegion region2_1 = new NavigationRegion(30, 4, [2]);
+    NavigationRegion region2_2 = new NavigationRegion(40, 4, [3]);
+    AnalysisNavigationParams params1 = new AnalysisNavigationParams(
+        'a.dart',
+        [region1_1, region1_2, region2_1, region2_2],
+        [target1_1, target1_2, target2_1, target2_2],
+        ['one.dart', 'two.dart']);
+    //
+    // Create the parameters from the second plugin.
+    //
+    // same file and offset as target 2_2
+    NavigationTarget target2_3 = target(0, 4);
+    NavigationTarget target2_4 = target(0, 5);
+    NavigationTarget target3_1 = target(1, 6);
+    NavigationTarget target3_2 = target(1, 7);
+    // same region and target as region2_2
+    NavigationRegion region2_3 = new NavigationRegion(40, 4, [0]);
+    // same region as region2_2, but a different target
+    NavigationRegion region2_4 = new NavigationRegion(40, 4, [2]);
+    NavigationRegion region2_5 = new NavigationRegion(50, 4, [1]);
+    NavigationRegion region3_1 = new NavigationRegion(60, 4, [2]);
+    NavigationRegion region3_2 = new NavigationRegion(70, 4, [3]);
+    AnalysisNavigationParams params2 = new AnalysisNavigationParams(
+        'a.dart',
+        [region2_3, region2_4, region2_5, region3_1, region3_2],
+        [target2_3, target2_4, target3_1, target3_2],
+        ['two.dart', 'three.dart']);
+    AnalysisNavigationParams expected = new AnalysisNavigationParams('a.dart', [
+      region1_1,
+      region1_2,
+      region2_1,
+      new NavigationRegion(40, 4, [3, 5]), // union of region2_2 and region2_4
+      new NavigationRegion(50, 4, [4]), // region2_5
+      new NavigationRegion(60, 4, [5]), // region3_1
+      new NavigationRegion(70, 4, [6]), // region3_2
+    ], [
+      target1_1,
+      target1_2,
+      target2_1,
+      target2_2,
+      target(1, 5), // target2_4
+      target(2, 6), // target3_1
+      target(2, 7), // target3_2
+    ], [
+      'one.dart',
+      'two.dart',
+      'three.dart'
+    ]);
+
+    void runTest() {
+      expect(merger.mergeNavigation([params1, params2]), expected);
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeOccurrences() {
+    Element element1 = new Element(ElementKind.CLASS, 'e1', 0);
+    Element element2 = new Element(ElementKind.CLASS, 'e2', 0);
+    Element element3 = new Element(ElementKind.CLASS, 'e3', 0);
+    Occurrences occurrence1 = new Occurrences(element1, [1, 2, 4], 2);
+    Occurrences occurrence2 = new Occurrences(element2, [5], 2);
+    Occurrences occurrence3 = new Occurrences(element1, [2, 3], 2);
+    Occurrences occurrence4 = new Occurrences(element3, [8], 2);
+    Occurrences occurrence5 = new Occurrences(element2, [6], 2);
+    Occurrences occurrence6 = new Occurrences(element3, [7, 9], 2);
+    Occurrences result1 = new Occurrences(element1, [1, 2, 3, 4], 2);
+    Occurrences result2 = new Occurrences(element2, [5, 6], 2);
+    Occurrences result3 = new Occurrences(element3, [7, 8, 9], 2);
+
+    void runTest() {
+      expect(
+          merger.mergeOccurrences([
+            [occurrence1, occurrence2],
+            [],
+            [occurrence3, occurrence4],
+            [occurrence5, occurrence6]
+          ]),
+          unorderedEquals([result1, result2, result3]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeOutline() {
+    Element element(ElementKind kind, int offset) {
+      Location location = new Location('', offset, 0, 0, 0);
+      return new Element(kind, '', 0, location: location);
+    }
+
+    Element element1 = element(ElementKind.CLASS, 100);
+    Element element1_1 = element(ElementKind.METHOD, 110);
+    Element element1_2 = element(ElementKind.METHOD, 120);
+    Element element2 = element(ElementKind.CLASS, 200);
+    Element element2_1 = element(ElementKind.METHOD, 210);
+    Element element2_2 = element(ElementKind.METHOD, 220);
+    Element element3_1 = element(ElementKind.METHOD, 220); // same as 2_2
+    Element element3_2 = element(ElementKind.METHOD, 230);
+    Element element4 = element(ElementKind.CLASS, 300);
+    Element element4_1 = element(ElementKind.METHOD, 310);
+    //
+    // Unique, contributed from first plugin.
+    //
+    // element1
+    // - element1_1
+    // - element1_2
+    //
+    Outline outline1_1 = new Outline(element1_1, 0, 0, children: []);
+    Outline outline1_2 = new Outline(element1_2, 0, 0, children: []);
+    Outline outline1 =
+        new Outline(element1, 0, 0, children: [outline1_1, outline1_2]);
+    //
+    // Same top level element, common child.
+    //
+    // element2
+    // - element2_1
+    // - element2_2
+    // element2
+    // - element3_1
+    // - element3_2
+    //
+    Outline outline2_1 = new Outline(element2_1, 0, 0, children: []);
+    Outline outline2_2 = new Outline(element2_2, 0, 0, children: []);
+    Outline outline3_1 = new Outline(element3_1, 0, 0, children: []);
+    Outline outline3_2 = new Outline(element3_2, 0, 0, children: []);
+    Outline outline2 =
+        new Outline(element2, 0, 0, children: [outline2_1, outline2_2]);
+    Outline outline3 =
+        new Outline(element2, 0, 0, children: [outline3_1, outline3_2]);
+    Outline outline2and3 = new Outline(element2, 0, 0,
+        children: [outline2_1, outline2_2, outline3_2]);
+    //
+    // Unique, contributed from second plugin.
+    //
+    // element4
+    // - element4_1
+    //
+    Outline outline4_1 = new Outline(element4_1, 0, 0, children: []);
+    Outline outline4 = new Outline(element4, 0, 0, children: [outline4_1]);
+
+    void runTest() {
+      expect(
+          merger.mergeOutline([
+            [outline1, outline2],
+            [],
+            [outline3, outline4]
+          ]),
+          unorderedEquals([outline1, outline2and3, outline4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergePrioritizedSourceChanges() {
+    plugin.PrioritizedSourceChange kind1 =
+        new plugin.PrioritizedSourceChange(1, new plugin.SourceChange(''));
+    plugin.PrioritizedSourceChange kind2 =
+        new plugin.PrioritizedSourceChange(1, new plugin.SourceChange(''));
+    plugin.PrioritizedSourceChange kind3 =
+        new plugin.PrioritizedSourceChange(1, new plugin.SourceChange(''));
+    plugin.PrioritizedSourceChange kind4 =
+        new plugin.PrioritizedSourceChange(1, new plugin.SourceChange(''));
+
+    void runTest() {
+      expect(
+          merger.mergePrioritizedSourceChanges([
+            [kind3, kind2],
+            [],
+            [kind4],
+            [kind1]
+          ]),
+          unorderedEquals([kind1, kind2, kind3, kind4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_convertGetterToMethodFeedback() {
+    RefactoringFeedback feedback1 = new ConvertGetterToMethodFeedback();
+    RefactoringFeedback feedback2 = new ConvertGetterToMethodFeedback();
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(feedback1));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_convertMethodToGetterFeedback() {
+    RefactoringFeedback feedback1 = new ConvertMethodToGetterFeedback();
+    RefactoringFeedback feedback2 = new ConvertMethodToGetterFeedback();
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(feedback1));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void
+      test_mergeRefactoringFeedbacks_extractLocalVariableFeedback_addEverything() {
+    List<String> names1 = <String>['a', 'b', 'c'];
+    List<int> offsets1 = <int>[10, 20];
+    List<int> lengths1 = <int>[4, 5];
+    List<int> coveringOffsets1 = <int>[100, 150, 200];
+    List<int> coveringLengths1 = <int>[200, 100, 20];
+    RefactoringFeedback feedback1 = new ExtractLocalVariableFeedback(
+        names1, offsets1, lengths1,
+        coveringExpressionOffsets: coveringOffsets1,
+        coveringExpressionLengths: coveringLengths1);
+    List<String> names2 = <String>['c', 'd'];
+    List<int> offsets2 = <int>[30];
+    List<int> lengths2 = <int>[6];
+    List<int> coveringOffsets2 = <int>[210];
+    List<int> coveringLengths2 = <int>[5];
+    RefactoringFeedback feedback2 = new ExtractLocalVariableFeedback(
+        names2, offsets2, lengths2,
+        coveringExpressionOffsets: coveringOffsets2,
+        coveringExpressionLengths: coveringLengths2);
+    List<String> resultNames = <String>['a', 'b', 'c', 'd'];
+    List<int> resultOffsets = new List<int>.from(offsets1)..addAll(offsets2);
+    List<int> resultLengths = new List<int>.from(lengths1)..addAll(lengths2);
+    List<int> resultCoveringOffsets = new List<int>.from(coveringOffsets1)
+      ..addAll(coveringOffsets2);
+    List<int> resultCoveringLengths = new List<int>.from(coveringLengths1)
+      ..addAll(coveringLengths2);
+    RefactoringFeedback result = new ExtractLocalVariableFeedback(
+        resultNames, resultOffsets, resultLengths,
+        coveringExpressionOffsets: resultCoveringOffsets,
+        coveringExpressionLengths: resultCoveringLengths);
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(result));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void
+      test_mergeRefactoringFeedbacks_extractLocalVariableFeedback_addOffsetsAndLengths() {
+    List<String> names1 = <String>['a', 'b', 'c'];
+    List<int> offsets1 = <int>[10, 20];
+    List<int> lengths1 = <int>[4, 5];
+    List<int> coveringOffsets1 = <int>[100, 150, 200];
+    List<int> coveringLengths1 = <int>[200, 100, 20];
+    RefactoringFeedback feedback1 = new ExtractLocalVariableFeedback(
+        names1, offsets1, lengths1,
+        coveringExpressionOffsets: coveringOffsets1,
+        coveringExpressionLengths: coveringLengths1);
+    List<String> names2 = <String>[];
+    List<int> offsets2 = <int>[30];
+    List<int> lengths2 = <int>[6];
+    RefactoringFeedback feedback2 =
+        new ExtractLocalVariableFeedback(names2, offsets2, lengths2);
+    List<int> resultOffsets = new List<int>.from(offsets1)..addAll(offsets2);
+    List<int> resultLengths = new List<int>.from(lengths1)..addAll(lengths2);
+    RefactoringFeedback result = new ExtractLocalVariableFeedback(
+        names1, resultOffsets, resultLengths,
+        coveringExpressionOffsets: coveringOffsets1,
+        coveringExpressionLengths: coveringLengths1);
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(result));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void
+      test_mergeRefactoringFeedbacks_extractLocalVariableFeedback_noCoverings() {
+    List<String> names1 = <String>['a', 'b', 'c'];
+    List<int> offsets1 = <int>[10, 20];
+    List<int> lengths1 = <int>[4, 5];
+    RefactoringFeedback feedback1 =
+        new ExtractLocalVariableFeedback(names1, offsets1, lengths1);
+    List<String> names2 = <String>[];
+    List<int> offsets2 = <int>[30];
+    List<int> lengths2 = <int>[6];
+    RefactoringFeedback feedback2 =
+        new ExtractLocalVariableFeedback(names2, offsets2, lengths2);
+    List<int> resultOffsets = new List<int>.from(offsets1)..addAll(offsets2);
+    List<int> resultLengths = new List<int>.from(lengths1)..addAll(lengths2);
+    RefactoringFeedback result =
+        new ExtractLocalVariableFeedback(names1, resultOffsets, resultLengths);
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(result));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_extractMethodFeedback() {
+    int offset1 = 20;
+    int length1 = 5;
+    String returnType1 = 'int';
+    List<String> names1 = <String>['a', 'b', 'c'];
+    bool canCreateGetter1 = false;
+    List<RefactoringMethodParameter> parameters1 =
+        <RefactoringMethodParameter>[];
+    List<int> offsets1 = <int>[10, 20];
+    List<int> lengths1 = <int>[4, 5];
+    RefactoringFeedback feedback1 = new ExtractMethodFeedback(offset1, length1,
+        returnType1, names1, canCreateGetter1, parameters1, offsets1, lengths1);
+    List<String> names2 = <String>['c', 'd'];
+    bool canCreateGetter2 = true;
+    List<RefactoringMethodParameter> parameters2 =
+        <RefactoringMethodParameter>[];
+    List<int> offsets2 = <int>[30];
+    List<int> lengths2 = <int>[6];
+    RefactoringFeedback feedback2 = new ExtractMethodFeedback(
+        0, 0, '', names2, canCreateGetter2, parameters2, offsets2, lengths2);
+    List<String> resultNames = <String>['a', 'b', 'c', 'd'];
+    List<int> resultOffsets = new List<int>.from(offsets1)..addAll(offsets2);
+    List<int> resultLengths = new List<int>.from(lengths1)..addAll(lengths2);
+    RefactoringFeedback result = new ExtractMethodFeedback(
+        offset1,
+        length1,
+        returnType1,
+        resultNames,
+        false,
+        parameters1,
+        resultOffsets,
+        resultLengths);
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(result));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_inlineLocalVariableFeedback() {
+    RefactoringFeedback feedback1 = new InlineLocalVariableFeedback('a', 2);
+    RefactoringFeedback feedback2 = new InlineLocalVariableFeedback('a', 3);
+    RefactoringFeedback result = new InlineLocalVariableFeedback('a', 5);
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(result));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_inlineMethodFeedback() {
+    RefactoringFeedback feedback1 = new InlineMethodFeedback('a', false);
+    RefactoringFeedback feedback2 = new InlineMethodFeedback('a', false);
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(feedback1));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_moveFileFeedback() {
+    RefactoringFeedback feedback1 = new MoveFileFeedback();
+    RefactoringFeedback feedback2 = new MoveFileFeedback();
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(feedback1));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringFeedbacks_renameFeedback() {
+    RefactoringFeedback feedback1 = new RenameFeedback(10, 0, '', '');
+    RefactoringFeedback feedback2 = new RenameFeedback(20, 0, '', '');
+
+    void runTest() {
+      expect(merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+          equals(feedback1));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactoringKinds() {
+    RefactoringKind kind1 = RefactoringKind.CONVERT_GETTER_TO_METHOD;
+    RefactoringKind kind2 = RefactoringKind.EXTRACT_LOCAL_VARIABLE;
+    RefactoringKind kind3 = RefactoringKind.INLINE_LOCAL_VARIABLE;
+    RefactoringKind kind4 = RefactoringKind.MOVE_FILE;
+    RefactoringKind kind5 = RefactoringKind.EXTRACT_LOCAL_VARIABLE;
+
+    void runTest() {
+      expect(
+          merger.mergeRefactoringKinds([
+            [kind1, kind2],
+            [kind3],
+            [],
+            [kind4, kind5]
+          ]),
+          unorderedEquals([kind1, kind2, kind3, kind4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeRefactorings() {
+    RefactoringProblem problem(String message) =>
+        new RefactoringProblem(RefactoringProblemSeverity.ERROR, message);
+    RefactoringProblem problem1 = problem('1');
+    RefactoringProblem problem2 = problem('2');
+    RefactoringProblem problem3 = problem('3');
+    RefactoringProblem problem4 = problem('4');
+    RefactoringProblem problem5 = problem('5');
+    RefactoringProblem problem6 = problem('6');
+
+    List<RefactoringProblem> initialProblems1 = <RefactoringProblem>[
+      problem1,
+      problem2
+    ];
+    List<RefactoringProblem> optionsProblems1 = <RefactoringProblem>[problem3];
+    List<RefactoringProblem> finalProblems1 = <RefactoringProblem>[problem4];
+    RefactoringFeedback feedback1 = new RenameFeedback(10, 0, '', '');
+    SourceFileEdit edit1 =
+        new SourceFileEdit('file1.dart', 11, edits: <SourceEdit>[
+      new SourceEdit(12, 2, 'w', id: 'e1'),
+      new SourceEdit(13, 3, 'x'),
+    ]);
+    SourceChange change1 =
+        new SourceChange('c1', edits: <SourceFileEdit>[edit1]);
+    List<String> potentialEdits1 = <String>['e1'];
+    EditGetRefactoringResult result1 = new EditGetRefactoringResult(
+        initialProblems1, optionsProblems1, finalProblems1,
+        feedback: feedback1, change: change1, potentialEdits: potentialEdits1);
+    List<RefactoringProblem> initialProblems2 = <RefactoringProblem>[problem5];
+    List<RefactoringProblem> optionsProblems2 = <RefactoringProblem>[];
+    List<RefactoringProblem> finalProblems2 = <RefactoringProblem>[problem6];
+    RefactoringFeedback feedback2 = new RenameFeedback(20, 0, '', '');
+    SourceFileEdit edit2 =
+        new SourceFileEdit('file2.dart', 21, edits: <SourceEdit>[
+      new SourceEdit(12, 2, 'y', id: 'e2'),
+      new SourceEdit(13, 3, 'z'),
+    ]);
+    SourceChange change2 =
+        new SourceChange('c2', edits: <SourceFileEdit>[edit2]);
+    List<String> potentialEdits2 = <String>['e2'];
+    EditGetRefactoringResult result2 = new EditGetRefactoringResult(
+        initialProblems2, optionsProblems2, finalProblems2,
+        feedback: feedback2, change: change2, potentialEdits: potentialEdits2);
+    List<RefactoringProblem> mergedInitialProblems = <RefactoringProblem>[
+      problem1,
+      problem2,
+      problem5
+    ];
+    List<RefactoringProblem> mergedOptionsProblems = <RefactoringProblem>[
+      problem3
+    ];
+    List<RefactoringProblem> mergedFinalProblems = <RefactoringProblem>[
+      problem4,
+      problem6
+    ];
+    SourceChange mergedChange =
+        new SourceChange('c1', edits: <SourceFileEdit>[edit1, edit2]);
+    List<String> mergedPotentialEdits = <String>['e1', 'e2'];
+    EditGetRefactoringResult mergedResult = new EditGetRefactoringResult(
+        mergedInitialProblems, mergedOptionsProblems, mergedFinalProblems,
+        feedback: merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
+        change: mergedChange,
+        potentialEdits: mergedPotentialEdits);
+
+    void runTest() {
+      expect(merger.mergeRefactorings([result1, result2]), mergedResult);
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_mergeSourceChanges() {
+    SourceChange kind1 = new SourceChange('');
+    SourceChange kind2 = new SourceChange('');
+    SourceChange kind3 = new SourceChange('');
+    SourceChange kind4 = new SourceChange('');
+
+    void runTest() {
+      expect(
+          merger.mergeSourceChanges([
+            [kind1, kind2],
+            [],
+            [kind3],
+            [kind4]
+          ]),
+          unorderedEquals([kind1, kind2, kind3, kind4]));
+    }
+
+    runTest();
+    runTest();
+  }
+
+  void test_overlaps_false_nested_left() {
+    expect(merger.overlaps(3, 5, 1, 7, allowNesting: true), isFalse);
+  }
+
+  void test_overlaps_false_nested_right() {
+    expect(merger.overlaps(1, 7, 3, 5, allowNesting: true), isFalse);
+  }
+
+  void test_overlaps_false_onLeft() {
+    expect(merger.overlaps(1, 3, 5, 7), isFalse);
+  }
+
+  void test_overlaps_false_onRight() {
+    expect(merger.overlaps(5, 7, 1, 3), isFalse);
+  }
+
+  void test_overlaps_true_nested_left() {
+    expect(merger.overlaps(3, 5, 1, 7), isTrue);
+  }
+
+  void test_overlaps_true_nested_right() {
+    expect(merger.overlaps(1, 7, 3, 5), isTrue);
+  }
+
+  void test_overlaps_true_onLeft() {
+    expect(merger.overlaps(1, 5, 3, 7), isTrue);
+  }
+
+  void test_overlaps_true_onRight() {
+    expect(merger.overlaps(3, 7, 1, 5), isTrue);
+  }
+}
diff --git a/pkg/analysis_server/test/src/plugin/test_all.dart b/pkg/analysis_server/test/src/plugin/test_all.dart
new file mode 100644
index 0000000..8037322
--- /dev/null
+++ b/pkg/analysis_server/test/src/plugin/test_all.dart
@@ -0,0 +1,19 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'plugin_locator_test.dart' as plugin_locator_test;
+import 'result_collector_test.dart' as result_collector_test;
+import 'result_converter_test.dart' as result_converter_test;
+import 'result_merger_test.dart' as result_merger_test;
+
+main() {
+  defineReflectiveSuite(() {
+    plugin_locator_test.main();
+    result_collector_test.main();
+    result_converter_test.main();
+    result_merger_test.main();
+  });
+}
diff --git a/pkg/analysis_server/test/src/test_all.dart b/pkg/analysis_server/test/src/test_all.dart
index e7df8d3..63a5bcf 100644
--- a/pkg/analysis_server/test/src/test_all.dart
+++ b/pkg/analysis_server/test/src/test_all.dart
@@ -6,6 +6,7 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'plugin/test_all.dart' as plugin_all;
 import 'utilities/test_all.dart' as utilities_all;
 
 /**
@@ -13,6 +14,7 @@
  */
 main() {
   defineReflectiveSuite(() {
+    plugin_all.main();
     utilities_all.main();
   }, name: 'analysis_server');
 }
diff --git a/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart b/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
index 118bdb8..f2fbf7d 100644
--- a/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
+++ b/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
@@ -2,16 +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.
 
-library analysis_server.test.src.utilities.change_builder_core_test;
-
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
 import 'package:analysis_server/src/utilities/change_builder_core.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../domain_execution_test.dart';
-
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ChangeBuilderImplTest);
@@ -23,15 +19,15 @@
 
 @reflectiveTest
 class ChangeBuilderImplTest {
-  void test_createFileEditBuilder() {
+  test_createFileEditBuilder() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    TestSource source = new TestSource('/test.dart');
+    String path = '/test.dart';
     int timeStamp = 54;
     FileEditBuilderImpl fileEditBuilder =
-        builder.createFileEditBuilder(source, timeStamp);
+        await builder.createFileEditBuilder(path, timeStamp);
     expect(fileEditBuilder, new isInstanceOf<FileEditBuilder>());
     SourceFileEdit fileEdit = fileEditBuilder.fileEdit;
-    expect(fileEdit.file, source.fullName);
+    expect(fileEdit.file, path);
     expect(fileEdit.fileStamp, timeStamp);
   }
 
@@ -52,10 +48,10 @@
     expect(sourceChange.selection, isNull);
   }
 
-  void test_sourceChange_oneChange() {
+  test_sourceChange_oneChange() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    TestSource source = new TestSource('/test.dart');
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {});
+    String path = '/test.dart';
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {});
     builder.getLinkedEditGroup('a');
     SourceChange sourceChange = builder.sourceChange;
     expect(sourceChange, isNotNull);
@@ -68,13 +64,13 @@
 
 @reflectiveTest
 class EditBuilderImplTest {
-  TestSource source = new TestSource('/test.dart');
+  String path = '/test.dart';
 
-  void test_addLinkedEdit() {
+  test_addLinkedEdit() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
     int offset = 10;
     String text = 'content';
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addInsertion(10, (EditBuilder builder) {
         builder.addLinkedEdit('a', (LinkedEditBuilder builder) {
           builder.write(text);
@@ -95,9 +91,9 @@
     expect(positions[0].offset, offset);
   }
 
-  void test_createLinkedEditBuilder() {
+  test_createLinkedEditBuilder() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addInsertion(10, (EditBuilder builder) {
         LinkedEditBuilderImpl linkBuilder =
             (builder as EditBuilderImpl).createLinkedEditBuilder();
@@ -106,12 +102,12 @@
     });
   }
 
-  void test_write() {
+  test_write() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
     int timeStamp = 93;
     int offset = 10;
     String text = 'write';
-    builder.addFileEdit(source, timeStamp, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, timeStamp, (FileEditBuilder builder) {
       builder.addInsertion(offset, (EditBuilder builder) {
         builder.write(text);
       });
@@ -124,7 +120,7 @@
     expect(fileEdits, hasLength(1));
     SourceFileEdit fileEdit = fileEdits[0];
     expect(fileEdit, isNotNull);
-    expect(fileEdit.file, source.fullName);
+    expect(fileEdit.file, path);
     expect(fileEdit.fileStamp, timeStamp);
 
     List<SourceEdit> edits = fileEdit.edits;
@@ -136,12 +132,12 @@
     expect(edit.replacement, text);
   }
 
-  void test_writeln_withoutText() {
+  test_writeln_withoutText() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
     int timeStamp = 39;
     int offset = 52;
     int length = 12;
-    builder.addFileEdit(source, timeStamp, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, timeStamp, (FileEditBuilder builder) {
       builder.addReplacement(offset, length, (EditBuilder builder) {
         builder.writeln();
       });
@@ -154,7 +150,7 @@
     expect(fileEdits, hasLength(1));
     SourceFileEdit fileEdit = fileEdits[0];
     expect(fileEdit, isNotNull);
-    expect(fileEdit.file, source.fullName);
+    expect(fileEdit.file, path);
     expect(fileEdit.fileStamp, timeStamp);
 
     List<SourceEdit> edits = fileEdit.edits;
@@ -166,13 +162,13 @@
     expect(edit.replacement == '\n' || edit.replacement == '\r\n', isTrue);
   }
 
-  void test_writeln_withText() {
+  test_writeln_withText() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
     int timeStamp = 39;
     int offset = 52;
     int length = 12;
     String text = 'writeln';
-    builder.addFileEdit(source, timeStamp, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, timeStamp, (FileEditBuilder builder) {
       builder.addReplacement(offset, length, (EditBuilder builder) {
         builder.writeln(text);
       });
@@ -185,7 +181,7 @@
     expect(fileEdits, hasLength(1));
     SourceFileEdit fileEdit = fileEdits[0];
     expect(fileEdit, isNotNull);
-    expect(fileEdit.file, source.fullName);
+    expect(fileEdit.file, path);
     expect(fileEdit.fileStamp, timeStamp);
 
     List<SourceEdit> edits = fileEdit.edits;
@@ -201,45 +197,45 @@
 
 @reflectiveTest
 class FileEditBuilderImplTest {
-  TestSource source = new TestSource('/test.dart');
+  String path = '/test.dart';
 
-  void test_addInsertion() {
+  test_addInsertion() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addInsertion(10, (EditBuilder builder) {
         expect(builder, isNotNull);
       });
     });
   }
 
-  void test_addLinkedPosition() {
-    ChangeBuilderImpl changeBuilder = new ChangeBuilderImpl();
+  test_addLinkedPosition() async {
+    ChangeBuilderImpl builder = new ChangeBuilderImpl();
     String groupName = 'a';
-    changeBuilder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addLinkedPosition(3, 6, groupName);
     });
 
-    LinkedEditGroup group = changeBuilder.getLinkedEditGroup(groupName);
+    LinkedEditGroup group = builder.getLinkedEditGroup(groupName);
     List<Position> positions = group.positions;
     expect(positions, hasLength(1));
     Position position = positions[0];
-    expect(position.file, source.fullName);
+    expect(position.file, path);
     expect(position.offset, 3);
     expect(group.length, 6);
   }
 
-  void test_addReplacement() {
+  test_addReplacement() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addReplacement(4, 5, (EditBuilder builder) {
         expect(builder, isNotNull);
       });
     });
   }
 
-  void test_createEditBuilder() {
+  test_createEditBuilder() async {
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       int offset = 4;
       int length = 5;
       EditBuilderImpl editBuilder =
@@ -255,12 +251,12 @@
 
 @reflectiveTest
 class LinkedEditBuilderImplTest {
-  TestSource source = new TestSource('/test.dart');
+  String path = '/test.dart';
 
-  void test_addSuggestion() {
+  test_addSuggestion() async {
     String groupName = 'a';
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addInsertion(10, (EditBuilder builder) {
         builder.addLinkedEdit(groupName, (LinkedEditBuilder builder) {
           builder.addSuggestion(LinkedEditSuggestionKind.TYPE, 'A');
@@ -272,10 +268,10 @@
     expect(group.suggestions, hasLength(1));
   }
 
-  void test_addSuggestions() {
+  test_addSuggestions() async {
     String groupName = 'a';
     ChangeBuilderImpl builder = new ChangeBuilderImpl();
-    builder.addFileEdit(source, 0, (FileEditBuilder builder) {
+    await builder.addFileEdit(path, 0, (FileEditBuilder builder) {
       builder.addInsertion(10, (EditBuilder builder) {
         builder.addLinkedEdit(groupName, (LinkedEditBuilder builder) {
           builder.addSuggestions(LinkedEditSuggestionKind.TYPE, ['A', 'B']);
diff --git a/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart b/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
index 4e88aec..8ff8eb5 100644
--- a/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
+++ b/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analysis_server.test.src.utilities.change_builder_dart_test;
+import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
@@ -11,7 +11,8 @@
 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/generated/source.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -27,22 +28,28 @@
 
 @reflectiveTest
 class DartChangeBuilderImplTest extends AbstractContextTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+
   test_createFileEditBuilder() async {
-    Source source = addSource('/test.dart', 'library test;');
-    await resolveLibraryUnit(source);
+    String path = '/test.dart';
+    addSource(path, 'library test;');
     int timeStamp = 54;
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
     DartFileEditBuilderImpl fileEditBuilder =
-        builder.createFileEditBuilder(source, timeStamp);
+        await builder.createFileEditBuilder(path, timeStamp);
     expect(fileEditBuilder, new isInstanceOf<DartFileEditBuilder>());
     SourceFileEdit fileEdit = fileEditBuilder.fileEdit;
-    expect(fileEdit.file, source.fullName);
+    expect(fileEdit.file, path);
     expect(fileEdit.fileStamp, timeStamp);
   }
 }
 
 @reflectiveTest
 class DartEditBuilderImplTest extends AbstractContextTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+
   SourceEdit getEdit(DartChangeBuilderImpl builder) {
     SourceChange sourceChange = builder.sourceChange;
     expect(sourceChange, isNotNull);
@@ -56,16 +63,15 @@
   }
 
   test_writeClassDeclaration_interfaces() async {
-    Source source = addSource('/test.dart', 'class A {}');
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration declaration = unit.declarations[0];
+    String path = '/test.dart';
+    addSource(path, 'class A {}');
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeClassDeclaration('C', interfaces: [
-          resolutionMap.elementDeclaredByClassDeclaration(declaration).type
-        ]);
+        (builder as DartEditBuilder)
+            .writeClassDeclaration('C', interfaces: [typeA]);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -74,11 +80,11 @@
   }
 
   test_writeClassDeclaration_isAbstract() async {
-    Source source = addSource('/test.dart', '');
-    await resolveLibraryUnit(source);
+    String path = '/test.dart';
+    addSource(path, '');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeClassDeclaration('C', isAbstract: true);
@@ -89,11 +95,11 @@
   }
 
   test_writeClassDeclaration_memberWriter() async {
-    Source source = addSource('/test.dart', '');
-    await resolveLibraryUnit(source);
+    String path = '/test.dart';
+    addSource(path, '');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
         (builder as DartEditBuilder).writeClassDeclaration('C',
             memberWriter: () {
@@ -106,16 +112,15 @@
   }
 
   test_writeClassDeclaration_mixins_noSuperclass() async {
-    Source source = addSource('/test.dart', 'class A {}');
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
+    String path = '/test.dart';
+    addSource(path, 'class A {}');
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeClassDeclaration('C', mixins: [
-          resolutionMap.elementDeclaredByClassDeclaration(classA).type
-        ]);
+        (builder as DartEditBuilder)
+            .writeClassDeclaration('C', mixins: [typeA]);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -124,20 +129,16 @@
   }
 
   test_writeClassDeclaration_mixins_superclass() async {
-    Source source = addSource('/test.dart', 'class A {} class B {}');
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
-    ClassDeclaration classB = unit.declarations[1];
+    String path = '/test.dart';
+    addSource(path, 'class A {} class B {}');
+    DartType typeA = await _getType(path, 'A');
+    DartType typeB = await _getType(path, 'B');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeClassDeclaration('C',
-            mixins: [
-              resolutionMap.elementDeclaredByClassDeclaration(classB).type
-            ],
-            superclass:
-                resolutionMap.elementDeclaredByClassDeclaration(classA).type);
+        (builder as DartEditBuilder)
+            .writeClassDeclaration('C', mixins: [typeB], superclass: typeA);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -146,11 +147,11 @@
   }
 
   test_writeClassDeclaration_nameGroupName() async {
-    Source source = addSource('/test.dart', '');
-    await resolveLibraryUnit(source);
+    String path = '/test.dart';
+    addSource(path, '');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeClassDeclaration('C', nameGroupName: 'name');
@@ -168,17 +169,15 @@
   }
 
   test_writeClassDeclaration_superclass() async {
-    Source source = addSource('/test.dart', 'class B {}');
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration declaration = unit.declarations[0];
+    String path = '/test.dart';
+    addSource(path, 'class B {}');
+    DartType typeB = await _getType(path, 'B');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(0, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeClassDeclaration('C',
-            superclass: resolutionMap
-                .elementDeclaredByClassDeclaration(declaration)
-                .type);
+        (builder as DartEditBuilder)
+            .writeClassDeclaration('C', superclass: typeB);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -186,12 +185,12 @@
   }
 
   test_writeFieldDeclaration_initializerWriter() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeFieldDeclaration('f',
             initializerWriter: () {
@@ -204,12 +203,12 @@
   }
 
   test_writeFieldDeclaration_isConst() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeFieldDeclaration('f', isConst: true);
       });
@@ -219,12 +218,12 @@
   }
 
   test_writeFieldDeclaration_isConst_isFinal() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeFieldDeclaration('f', isConst: true, isFinal: true);
@@ -235,12 +234,12 @@
   }
 
   test_writeFieldDeclaration_isFinal() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeFieldDeclaration('f', isFinal: true);
       });
@@ -250,12 +249,12 @@
   }
 
   test_writeFieldDeclaration_isStatic() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeFieldDeclaration('f', isStatic: true);
       });
@@ -265,12 +264,12 @@
   }
 
   test_writeFieldDeclaration_nameGroupName() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeFieldDeclaration('f', nameGroupName: 'name');
@@ -290,19 +289,16 @@
   }
 
   test_writeFieldDeclaration_type_typeGroupName() async {
+    String path = '/test.dart';
     String content = 'class A {} class B {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration declaration = unit.declarations[0];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeFieldDeclaration('f',
-            type: resolutionMap
-                .elementDeclaredByClassDeclaration(declaration)
-                .type,
-            typeGroupName: 'type');
+        (builder as DartEditBuilder)
+            .writeFieldDeclaration('f', type: typeA, typeGroupName: 'type');
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -319,12 +315,12 @@
   }
 
   test_writeGetterDeclaration_bodyWriter() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeGetterDeclaration('g',
             bodyWriter: () {
@@ -337,12 +333,12 @@
   }
 
   test_writeGetterDeclaration_isStatic() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeGetterDeclaration('g', isStatic: true);
@@ -353,12 +349,12 @@
   }
 
   test_writeGetterDeclaration_nameGroupName() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeGetterDeclaration('g', nameGroupName: 'name');
@@ -378,18 +374,16 @@
   }
 
   test_writeGetterDeclaration_returnType() async {
+    String path = '/test.dart';
     String content = 'class A {} class B {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeGetterDeclaration('g',
-            returnType:
-                resolutionMap.elementDeclaredByClassDeclaration(classA).type,
-            returnTypeGroupName: 'returnType');
+            returnType: typeA, returnTypeGroupName: 'returnType');
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -406,23 +400,21 @@
   }
 
   test_writeOverrideOfInheritedMember() async {
+    String path = '/test.dart';
     String content = '''
 class A {
   A add(A a) => null;
 }
 class B extends A {
 }''';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration declaration = unit.declarations[0];
+    addSource(path, content);
+    ClassElement classA = await _getClassElement(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeOverrideOfInheritedMember(
-            resolutionMap
-                .elementDeclaredByClassDeclaration(declaration)
-                .methods[0]);
+        (builder as DartEditBuilder)
+            .writeOverrideOfInheritedMember(classA.methods[0]);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -435,16 +427,17 @@
   }
 
   test_writeParameters_named() async {
+    String path = '/test.dart';
     String content = 'f(int i, {String s}) {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0];
     FormalParameterList parameters = f.functionExpression.parameters;
     Iterable<ParameterElement> elements = parameters.parameters
         .map(resolutionMap.elementDeclaredByFormalParameter);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeParameters(elements);
       });
@@ -454,16 +447,17 @@
   }
 
   test_writeParameters_positional() async {
+    String path = '/test.dart';
     String content = 'f(int i, [String s]) {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0];
     FormalParameterList parameters = f.functionExpression.parameters;
     Iterable<ParameterElement> elements = parameters.parameters
         .map(resolutionMap.elementDeclaredByFormalParameter);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeParameters(elements);
       });
@@ -473,16 +467,17 @@
   }
 
   test_writeParameters_required() async {
+    String path = '/test.dart';
     String content = 'f(int i, String s) {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0];
     FormalParameterList parameters = f.functionExpression.parameters;
     Iterable<ParameterElement> elements = parameters.parameters
         .map(resolutionMap.elementDeclaredByFormalParameter);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeParameters(elements);
       });
@@ -492,19 +487,20 @@
   }
 
   test_writeParametersMatchingArguments_named() async {
+    String path = '/test.dart';
     String content = '''
 f(int i, String s) {
   g(s, index: i);
 }''';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0];
     BlockFunctionBody body = f.functionExpression.body;
     ExpressionStatement statement = body.block.statements[0];
     MethodInvocation invocation = statement.expression;
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeParametersMatchingArguments(invocation.argumentList);
@@ -516,19 +512,20 @@
   }
 
   test_writeParametersMatchingArguments_required() async {
+    String path = '/test.dart';
     String content = '''
 f(int i, String s) {
   g(s, i);
 }''';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0];
     BlockFunctionBody body = f.functionExpression.body;
     ExpressionStatement statement = body.block.statements[0];
     MethodInvocation invocation = statement.expression;
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder)
             .writeParametersMatchingArguments(invocation.argumentList);
@@ -539,16 +536,15 @@
   }
 
   test_writeParameterSource() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeParameterSource(
-            resolutionMap.elementDeclaredByClassDeclaration(classA).type, 'a');
+        (builder as DartEditBuilder).writeParameterSource(typeA, 'a');
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -556,12 +552,13 @@
   }
 
   test_writeType_dynamic() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeType(resolutionMap
             .elementDeclaredByCompilationUnit(unit)
@@ -575,21 +572,16 @@
   }
 
   test_writeType_genericType() async {
+    String path = '/test.dart';
     String content = 'class A {} class B<E> {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
-    ClassDeclaration classB = unit.declarations[1];
+    addSource(path, content);
+    InterfaceType typeA = await _getType(path, 'A');
+    InterfaceType typeB = await _getType(path, 'B');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(resolutionMap
-            .elementDeclaredByClassDeclaration(classB)
-            .type
-            .instantiate([
-          resolutionMap.elementDeclaredByClassDeclaration(classA).type
-        ]));
+        (builder as DartEditBuilder).writeType(typeB.instantiate([typeA]));
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -597,17 +589,15 @@
   }
 
   test_writeType_groupName() async {
+    String path = '/test.dart';
     String content = 'class A {} class B extends A {} class C extends B {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classC = unit.declarations[2];
+    addSource(path, content);
+    DartType typeC = await _getType(path, 'C');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(
-            resolutionMap.elementDeclaredByClassDeclaration(classC).type,
-            groupName: 'type');
+        (builder as DartEditBuilder).writeType(typeC, groupName: 'type');
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -621,18 +611,16 @@
   }
 
   test_writeType_groupName_addSupertypeProposals() async {
+    String path = '/test.dart';
     String content = 'class A {} class B extends A {} class C extends B {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classC = unit.declarations[2];
+    addSource(path, content);
+    DartType typeC = await _getType(path, 'C');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(
-            resolutionMap.elementDeclaredByClassDeclaration(classC).type,
-            addSupertypeProposals: true,
-            groupName: 'type');
+        (builder as DartEditBuilder)
+            .writeType(typeC, addSupertypeProposals: true, groupName: 'type');
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -656,12 +644,12 @@
   }
 
   test_writeType_null() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeType(null);
       });
@@ -671,12 +659,13 @@
   }
 
   test_writeType_required_dynamic() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
+    addSource(path, content);
+    CompilationUnit unit = (await driver.getResult(path))?.unit;
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeType(
             resolutionMap
@@ -692,17 +681,15 @@
   }
 
   test_writeType_required_notNull() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(
-            resolutionMap.elementDeclaredByClassDeclaration(classA).type,
-            required: true);
+        (builder as DartEditBuilder).writeType(typeA, required: true);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -710,12 +697,12 @@
   }
 
   test_writeType_required_null() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilder).writeType(null, required: true);
       });
@@ -725,16 +712,15 @@
   }
 
   test_writeType_simpleType() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(
-            resolutionMap.elementDeclaredByClassDeclaration(classA).type);
+        (builder as DartEditBuilder).writeType(typeA);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -742,12 +728,12 @@
   }
 
   test_writeTypes_empty() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilderImpl).writeTypes([]);
       });
@@ -757,19 +743,16 @@
   }
 
   test_writeTypes_noPrefix() async {
+    String path = '/test.dart';
     String content = 'class A {} class B {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
-    ClassDeclaration classB = unit.declarations[1];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
+    DartType typeB = await _getType(path, 'B');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilderImpl).writeTypes([
-          resolutionMap.elementDeclaredByClassDeclaration(classA).type,
-          resolutionMap.elementDeclaredByClassDeclaration(classB).type
-        ]);
+        (builder as DartEditBuilderImpl).writeTypes([typeA, typeB]);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -777,12 +760,12 @@
   }
 
   test_writeTypes_null() async {
+    String path = '/test.dart';
     String content = 'class A {}';
-    Source source = addSource('/test.dart', content);
-    await resolveLibraryUnit(source);
+    addSource(path, content);
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
         (builder as DartEditBuilderImpl).writeTypes(null);
       });
@@ -792,34 +775,45 @@
   }
 
   test_writeTypes_prefix() async {
+    String path = '/test.dart';
     String content = 'class A {} class B {}';
-    Source source = addSource('/test.dart', content);
-    CompilationUnit unit = await resolveLibraryUnit(source);
-    ClassDeclaration classA = unit.declarations[0];
-    ClassDeclaration classB = unit.declarations[1];
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
+    DartType typeB = await _getType(path, 'B');
 
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, 1, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, 1, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilderImpl).writeTypes([
-          resolutionMap.elementDeclaredByClassDeclaration(classA).type,
-          resolutionMap.elementDeclaredByClassDeclaration(classB).type
-        ], prefix: 'implements ');
+        (builder as DartEditBuilderImpl)
+            .writeTypes([typeA, typeB], prefix: 'implements ');
       });
     });
     SourceEdit edit = getEdit(builder);
     expect(edit.replacement, equalsIgnoringWhitespace('implements A, B'));
   }
+
+  Future<ClassElement> _getClassElement(String path, String name) async {
+    UnitElementResult result = await driver.getUnitElement(path);
+    return result.element.getType(name);
+  }
+
+  Future<DartType> _getType(String path, String name) async {
+    ClassElement classElement = await _getClassElement(path, name);
+    return classElement.type;
+  }
 }
 
 @reflectiveTest
 class DartFileEditBuilderImplTest extends AbstractContextTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+
   test_createEditBuilder() async {
-    Source source = addSource('/test.dart', 'library test;');
-    await resolveLibraryUnit(source);
+    String path = '/test.dart';
+    addSource(path, 'library test;');
     int timeStamp = 65;
-    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
-    builder.addFileEdit(source, timeStamp, (FileEditBuilder builder) {
+    DartChangeBuilderImpl builder = new DartChangeBuilderImpl(driver);
+    await builder.addFileEdit(path, timeStamp, (FileEditBuilder builder) {
       int offset = 4;
       int length = 5;
       DartEditBuilderImpl editBuilder = (builder as DartFileEditBuilderImpl)
diff --git a/pkg/analysis_server/test/stress/utilities/server.dart b/pkg/analysis_server/test/stress/utilities/server.dart
index cc96aca..08beaa0 100644
--- a/pkg/analysis_server/test/stress/utilities/server.dart
+++ b/pkg/analysis_server/test/stress/utilities/server.dart
@@ -190,11 +190,6 @@
   List<String> _analysisRootIncludes = <String>[];
 
   /**
-   * The analysis roots that are excluded.
-   */
-  List<String> _analysisRootExcludes = <String>[];
-
-  /**
    * A list containing the paths of files for which an overlay has been created.
    */
   List<String> filesWithOverlays = <String>[];
@@ -448,7 +443,6 @@
       List<String> included, List<String> excluded,
       {Map<String, String> packageRoots}) {
     _analysisRootIncludes = included;
-    _analysisRootExcludes = excluded;
     var params = new AnalysisSetAnalysisRootsParams(included, excluded,
             packageRoots: packageRoots)
         .toJson();
@@ -689,8 +683,8 @@
     if (useAnalysisHighlight2) {
       arguments.add('--useAnalysisHighlight2');
     }
-    if (enableNewAnalysisDriver) {
-      arguments.add('--enable-new-analysis-driver');
+    if (!enableNewAnalysisDriver) {
+      arguments.add('--disable-new-analysis-driver');
     }
 //    stdout.writeln('Launching $serverPath');
 //    stdout.writeln('$dartBinary ${arguments.join(' ')}');
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index bdde0bc..8ba3d32 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -216,7 +216,14 @@
         toHtmlVisitor.write(disclaimer);
       });
     }));
-    writeln('class $className {');
+    write('class $className');
+    if (impliedType.kind == 'refactoringFeedback') {
+      writeln(' extends RefactoringFeedback {');
+    } else if (impliedType.kind == 'refactoringOptions') {
+      writeln(' extends RefactoringOptions {');
+    } else {
+      writeln(' {');
+    }
     indent(() {
       if (emitToRequestMember(impliedType)) {
         writeln();
@@ -378,12 +385,12 @@
     }));
     write('class $className');
     if (impliedType.kind == 'refactoringFeedback') {
-      write(' extends RefactoringFeedback');
+      writeln(' extends RefactoringFeedback {');
+    } else if (impliedType.kind == 'refactoringOptions') {
+      writeln(' extends RefactoringOptions {');
+    } else {
+      writeln(' implements HasToJson {');
     }
-    if (impliedType.kind == 'refactoringOptions') {
-      write(' extends RefactoringOptions');
-    }
-    writeln(' implements HasToJson {');
     indent(() {
       if (emitSpecialStaticMembers(className)) {
         writeln();
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/NavigationTarget.java b/pkg/analysis_server/tool/spec/generated/java/types/NavigationTarget.java
index 001a7a0..d1ef09f 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/NavigationTarget.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/NavigationTarget.java
@@ -54,12 +54,12 @@
   private final int fileIndex;
 
   /**
-   * The offset of the region from which the user can navigate.
+   * The offset of the region to which the user can navigate.
    */
   private final int offset;
 
   /**
-   * The length of the region from which the user can navigate.
+   * The length of the region to which the user can navigate.
    */
   private final int length;
 
@@ -143,14 +143,14 @@
   }
 
   /**
-   * The length of the region from which the user can navigate.
+   * The length of the region to which the user can navigate.
    */
   public int getLength() {
     return length;
   }
 
   /**
-   * The offset of the region from which the user can navigate.
+   * The offset of the region to which the user can navigate.
    */
   public int getOffset() {
     return offset;
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 44e480f..d9213e2 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -3345,13 +3345,13 @@
           <field name="offset">
             <ref>int</ref>
             <p>
-              The offset of the region from which the user can navigate.
+              The offset of the region to which the user can navigate.
             </p>
           </field>
           <field name="length">
             <ref>int</ref>
             <p>
-              The length of the region from which the user can navigate.
+              The length of the region to which the user can navigate.
             </p>
           </field>
           <field name="startLine">
diff --git a/pkg/analyzer/analyzer.iml b/pkg/analyzer/analyzer.iml
new file mode 100644
index 0000000..5b8978b
--- /dev/null
+++ b/pkg/analyzer/analyzer.iml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.pub" />
+      <excludeFolder url="file://$MODULE_DIR$/benchmark/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/example/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/context/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/dart/ast/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/dart/element/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/dart/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/file_system/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/generated/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/instrumentation/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/source/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/command_line/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/context/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/dart/analysis/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/dart/ast/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/dart/constant/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/dart/element/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/dart/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/dart/sdk/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/lint/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/source/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/summary/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/task/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/task/strong/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/util/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/stress/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/summary/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/task_dependency_graph/packages" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Dart SDK" level="application" />
+    <orderEntry type="library" name="Dart SDK" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 1cabe11..28f9429 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -118,6 +118,7 @@
   CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
   CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
   CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
+  CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED,
   CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
   CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS,
   CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index 411d0d1..b190c1b 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -226,7 +226,9 @@
   _PhysicalFolder(io.Directory directory) : super(directory);
 
   @override
-  Stream<WatchEvent> get changes => new DirectoryWatcher(_entry.path).events;
+  Stream<WatchEvent> get changes => new DirectoryWatcher(_entry.path)
+      .events
+      .handleError(() {}, test: (error) => error is io.FileSystemException);
 
   /**
    * Return the underlying file being represented by this wrapper.
diff --git a/pkg/analyzer/lib/src/cancelable_future.dart b/pkg/analyzer/lib/src/cancelable_future.dart
index 43eb00c..50b1fa2 100644
--- a/pkg/analyzer/lib/src/cancelable_future.dart
+++ b/pkg/analyzer/lib/src/cancelable_future.dart
@@ -252,7 +252,8 @@
       _completer._outerCompleter.future.catchError(onError, test: test);
 
   @override
-  Future/*<S>*/ then/*<S>*/(onValue(T value), {Function onError}) =>
+  Future/*<S>*/ then/*<S>*/(FutureOr/*<S>*/ onValue(T value),
+          {Function onError}) =>
       _completer._outerCompleter.future.then(onValue, onError: onError);
 
   @override
@@ -288,7 +289,8 @@
       _future.catchError(onError, test: test);
 
   @override
-  Future/*<S>*/ then/*<S>*/(onValue(T value), {Function onError}) =>
+  Future/*<S>*/ then/*<S>*/(FutureOr/*<S>*/ onValue(T value),
+          {Function onError}) =>
       _future.then(onValue, onError: onError);
 
   @override
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 58301b7..fe6f5c3 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -24,6 +24,7 @@
 import 'package:analyzer/src/generated/gn.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/workspace.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary/pub_summary.dart';
 import 'package:analyzer/src/summary/summary_sdk.dart';
@@ -245,36 +246,20 @@
   }
 
   SourceFactory createSourceFactory(String rootPath, AnalysisOptions options) {
-    BazelWorkspace bazelWorkspace =
-        BazelWorkspace.find(resourceProvider, rootPath);
-    if (bazelWorkspace != null) {
-      List<UriResolver> resolvers = <UriResolver>[
-        new DartUriResolver(findSdk(null, options)),
-        new BazelPackageUriResolver(bazelWorkspace),
-        new BazelFileUriResolver(bazelWorkspace)
-      ];
-      return new SourceFactory(resolvers, null, resourceProvider);
-    }
+    Workspace workspace = createWorkspace(rootPath);
+    DartSdk sdk = findSdk(workspace.packageMap, options);
+    return workspace.createSourceFactory(sdk);
+  }
 
-    GnWorkspace gnWorkspace = GnWorkspace.find(resourceProvider, rootPath);
-    if (gnWorkspace != null) {
-      DartSdk sdk = findSdk(gnWorkspace.packageMap, options);
-      List<UriResolver> resolvers = <UriResolver>[
-        new DartUriResolver(sdk),
-        new GnPackageUriResolver(gnWorkspace),
-        new GnFileUriResolver(gnWorkspace)
-      ];
-      return new SourceFactory(resolvers, null, resourceProvider);
+  Workspace createWorkspace(String rootPath) {
+    if (_hasPackageFileInPath(rootPath)) {
+      // Bazel workspaces that include package files are treated like normal
+      // (non-Bazel) directories.
+      return _BasicWorkspace.find(resourceProvider, rootPath, this);
     }
-
-    Packages packages = createPackageMap(rootPath);
-    Map<String, List<Folder>> packageMap = convertPackagesToMap(packages);
-    List<UriResolver> resolvers = <UriResolver>[
-      new DartUriResolver(findSdk(packageMap, options)),
-      new PackageMapUriResolver(resourceProvider, packageMap),
-      new ResourceUriResolver(resourceProvider)
-    ];
-    return new SourceFactory(resolvers, packages, resourceProvider);
+    Workspace workspace = BazelWorkspace.find(resourceProvider, rootPath);
+    workspace ??= GnWorkspace.find(resourceProvider, rootPath);
+    return workspace ?? _BasicWorkspace.find(resourceProvider, rootPath, this);
   }
 
   /**
@@ -404,27 +389,46 @@
    * directory with the given [path].
    */
   AnalysisOptions getAnalysisOptions(String path) {
+    // TODO(danrubel) restructure so that we don't create a workspace
+    // both here and in createSourceFactory
+    Workspace workspace = createWorkspace(path);
+    SourceFactory sourceFactory = workspace.createSourceFactory(null);
+    AnalysisOptionsProvider optionsProvider =
+        new AnalysisOptionsProvider(sourceFactory);
+
     AnalysisOptionsImpl options = createDefaultOptions();
     File optionsFile = getOptionsFile(path);
+    Map<String, YamlNode> optionMap;
+
     if (optionsFile != null) {
-      // TODO(danrubel) restructure so that we don't recalculate the package map
-      // more than once per path.
-      Packages packages = createPackageMap(path);
-      Map<String, List<Folder>> packageMap = convertPackagesToMap(packages);
-      List<UriResolver> resolvers = <UriResolver>[
-        new ResourceUriResolver(resourceProvider),
-        new PackageMapUriResolver(resourceProvider, packageMap),
-      ];
-      SourceFactory sourceFactory =
-          new SourceFactory(resolvers, packages, resourceProvider);
       try {
-        Map<String, YamlNode> optionMap =
-            new AnalysisOptionsProvider(sourceFactory)
-                .getOptionsFromFile(optionsFile);
-        applyToAnalysisOptions(options, optionMap);
+        optionMap = optionsProvider.getOptionsFromFile(optionsFile);
       } catch (_) {
         // Ignore exceptions thrown while trying to load the options file.
       }
+    } else {
+      // Search for the default analysis options
+      Source source;
+      // TODO(danrubel) determine if bazel or gn project depends upon flutter
+      if (workspace.hasFlutterDependency) {
+        source =
+            sourceFactory.forUri('package:flutter/analysis_options_user.yaml');
+      }
+      if (source == null || !source.exists()) {
+        source =
+            sourceFactory.forUri('package:dart.analysis_options/default.yaml');
+      }
+      if (source.exists()) {
+        try {
+          optionMap = optionsProvider.getOptionsFromSource(source);
+        } catch (_) {
+          // Ignore exceptions thrown while trying to load the options file.
+        }
+      }
+    }
+
+    if (optionMap != null) {
+      applyToAnalysisOptions(options, optionMap);
       if (builderOptions.argResults != null) {
         applyAnalysisOptionFlags(options, builderOptions.argResults);
       }
@@ -522,8 +526,9 @@
   Resource _findPackagesLocation(String path) {
     Folder folder = resourceProvider.getFolder(path);
     if (!folder.exists) {
-      throw new ArgumentError.value(path, "path", "Directory does not exist.");
+      return null;
     }
+
     File checkForConfigFile(Folder folder) {
       File file = folder.getChildAssumingFile('.packages');
       if (file.exists) {
@@ -553,6 +558,22 @@
     }
     return null;
   }
+
+  /**
+   * Return `true` if either the directory at [rootPath] or a parent of that
+   * directory contains a `.packages` file.
+   */
+  bool _hasPackageFileInPath(String rootPath) {
+    Folder folder = resourceProvider.getFolder(rootPath);
+    while (folder != null) {
+      File file = folder.getChildAssumingFile('.packages');
+      if (file.exists) {
+        return true;
+      }
+      folder = folder.parent;
+    }
+    return false;
+  }
 }
 
 /**
@@ -711,3 +732,65 @@
     }
   }
 }
+
+/**
+ * Information about a default Dart workspace.
+ */
+class _BasicWorkspace extends Workspace {
+  /**
+   * The [ResourceProvider] by which paths are converted into [Resource]s.
+   */
+  final ResourceProvider provider;
+
+  /**
+   * The absolute workspace root path (the directory containing the `.jiri_root`
+   * directory).
+   */
+  final String root;
+
+  final ContextBuilder _builder;
+
+  Map<String, List<Folder>> _packageMap;
+
+  Packages _packages;
+
+  _BasicWorkspace._(this.provider, this.root, this._builder);
+
+  @override
+  // Alternately, we could check the pubspec for "sdk: flutter"
+  bool get hasFlutterDependency => packageMap.containsKey('flutter');
+
+  @override
+  Map<String, List<Folder>> get packageMap {
+    _packageMap ??= _builder.convertPackagesToMap(packages);
+    return _packageMap;
+  }
+
+  Packages get packages {
+    _packages ??= _builder.createPackageMap(root);
+    return _packages;
+  }
+
+  @override
+  UriResolver get packageUriResolver =>
+      new PackageMapUriResolver(provider, packageMap);
+
+  @override
+  SourceFactory createSourceFactory(DartSdk sdk) {
+    List<UriResolver> resolvers = <UriResolver>[];
+    if (sdk != null) {
+      resolvers.add(new DartUriResolver(sdk));
+    }
+    resolvers.add(packageUriResolver);
+    resolvers.add(new ResourceUriResolver(provider));
+    return new SourceFactory(resolvers, packages, provider);
+  }
+
+  /**
+   * Find the basic workspace that contains the given [path].
+   */
+  static _BasicWorkspace find(
+      ResourceProvider resourceProvider, String path, ContextBuilder builder) {
+    return new _BasicWorkspace._(resourceProvider, path, builder);
+  }
+}
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index 1f7c3b5..9ea1d7d 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -5,6 +5,7 @@
 library analyzer.src.context.source;
 
 import 'dart:collection';
+import 'dart:math' show min;
 
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -14,7 +15,6 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:package_config/packages.dart';
 
 /**
@@ -112,7 +112,7 @@
   @override
   Source forUri(String absoluteUri) {
     try {
-      Uri uri = FastUri.parse(absoluteUri);
+      Uri uri = Uri.parse(absoluteUri);
       if (uri.isAbsolute) {
         return _internalResolveUri(null, uri);
       }
@@ -157,7 +157,7 @@
     }
     try {
       // Force the creation of an escaped URI to deal with spaces, etc.
-      return _internalResolveUri(containingSource, FastUri.parse(containedUri));
+      return _internalResolveUri(containingSource, Uri.parse(containedUri));
     } on FormatException {
       return null;
     } catch (exception, stackTrace) {
@@ -203,8 +203,9 @@
     _packages.asMap().forEach((String name, Uri uri) {
       if (packageUri == null) {
         if (utils.startsWith(sourceUri, uri)) {
-          packageUri = Uri.parse(
-              'package:$name/${sourceUri.path.substring(uri.path.length)}');
+          String relativePath = sourceUri.path
+              .substring(min(uri.path.length, sourceUri.path.length));
+          packageUri = Uri.parse('package:$name/$relativePath');
         }
       }
     });
@@ -255,7 +256,7 @@
       }
     }
 
-    return _absoluteUriToSourceCache.putIfAbsent(containedUri, () {
+    return _absoluteUriToSourceCache.putIfAbsent(actualUri, () {
       for (UriResolver resolver in resolvers) {
         Source result = resolver.resolveAbsolute(containedUri, actualUri);
         if (result != null) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/ast_provider_context.dart b/pkg/analyzer/lib/src/dart/analysis/ast_provider_context.dart
new file mode 100644
index 0000000..b53334e
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/ast_provider_context.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
+
+/**
+ * [AstProvider] implementation for [AnalysisContext].
+ */
+class AstProviderForContext extends AbstractAstProvider {
+  final AnalysisContext context;
+
+  AstProviderForContext(this.context);
+
+  @override
+  Future<CompilationUnit> getParsedUnitForElement(Element element) async {
+    return context.parseCompilationUnit(element.source);
+  }
+
+  @override
+  Future<CompilationUnit> getResolvedUnitForElement(Element element) async {
+    return context.getResolvedCompilationUnit2(
+        element.source, element.librarySource);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/ast_provider_driver.dart b/pkg/analyzer/lib/src/dart/analysis/ast_provider_driver.dart
new file mode 100644
index 0000000..ef2aa51
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/ast_provider_driver.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/ast_provider.dart';
+
+abstract class AbstractAstProvider implements AstProvider {
+  @override
+  Future<SimpleIdentifier> getParsedNameForElement(Element element) async {
+    CompilationUnit unit = await getParsedUnitForElement(element);
+    return _getNameNode(unit, element);
+  }
+
+  @override
+  Future<SimpleIdentifier> getResolvedNameForElement(Element element) async {
+    CompilationUnit unit = await getResolvedUnitForElement(element);
+    return _getNameNode(unit, element);
+  }
+
+  SimpleIdentifier _getNameNode(CompilationUnit unit, Element element) {
+    int nameOffset = element.nameOffset;
+    if (nameOffset == -1) {
+      return null;
+    }
+    AstNode nameNode = new NodeLocator(nameOffset).searchWithin(unit);
+    if (nameNode is SimpleIdentifier) {
+      return nameNode;
+    }
+    return null;
+  }
+}
+
+/**
+ * [AstProvider] implementation for [AnalysisDriver].
+ */
+class AstProviderForDriver extends AbstractAstProvider {
+  final AnalysisDriver driver;
+
+  AstProviderForDriver(this.driver);
+
+  @override
+  Future<CompilationUnit> getParsedUnitForElement(Element element) async {
+    String path = element.source.fullName;
+    ParseResult parseResult = await driver.parseFile(path);
+    return parseResult.unit;
+  }
+
+  @override
+  Future<CompilationUnit> getResolvedUnitForElement(Element element) async {
+    String path = element.source.fullName;
+    AnalysisResult analysisResult = await driver.getResult(path);
+    return analysisResult?.unit;
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/defined_names.dart b/pkg/analyzer/lib/src/dart/analysis/defined_names.dart
new file mode 100644
index 0000000..58d0a65
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/defined_names.dart
@@ -0,0 +1,53 @@
+// 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:analyzer/dart/ast/ast.dart';
+
+/**
+ * Compute the [DefinedNames] for the given [unit].
+ */
+DefinedNames computeDefinedNames(CompilationUnit unit) {
+  DefinedNames names = new DefinedNames();
+
+  void appendName(Set<String> names, SimpleIdentifier node) {
+    String name = node?.name;
+    if (name != null && name.length != 0) {
+      names.add(name);
+    }
+  }
+
+  void appendClassMemberName(ClassMember member) {
+    if (member is MethodDeclaration) {
+      appendName(names.classMemberNames, member.name);
+    } else if (member is FieldDeclaration) {
+      for (VariableDeclaration field in member.fields.variables) {
+        appendName(names.classMemberNames, field.name);
+      }
+    }
+  }
+
+  void appendTopLevelName(CompilationUnitMember member) {
+    if (member is NamedCompilationUnitMember) {
+      appendName(names.topLevelNames, member.name);
+      if (member is ClassDeclaration) {
+        member.members.forEach(appendClassMemberName);
+      }
+    } else if (member is TopLevelVariableDeclaration) {
+      for (VariableDeclaration variable in member.variables.variables) {
+        appendName(names.topLevelNames, variable.name);
+      }
+    }
+  }
+
+  unit.declarations.forEach(appendTopLevelName);
+  return names;
+}
+
+/**
+ * Defined top-level and class member names.
+ */
+class DefinedNames {
+  final Set<String> topLevelNames = new Set<String>();
+  final Set<String> classMemberNames = new Set<String>();
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 18c8124..334a7ea 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -13,10 +13,12 @@
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/file_tracker.dart';
 import 'package:analyzer/src/dart/analysis/index.dart';
+import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
+import 'package:analyzer/src/dart/analysis/library_context.dart';
 import 'package:analyzer/src/dart/analysis/search.dart';
 import 'package:analyzer/src/dart/analysis/status.dart';
 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
@@ -27,10 +29,6 @@
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/link.dart';
-import 'package:analyzer/src/summary/package_bundle_reader.dart';
-import 'package:analyzer/src/task/dart.dart' show COMPILATION_UNIT_ELEMENT;
-import 'package:analyzer/task/dart.dart' show LibrarySpecificUnit;
 import 'package:meta/meta.dart';
 
 /**
@@ -74,7 +72,13 @@
   /**
    * The version of data format, should be incremented on every format change.
    */
-  static const int DATA_VERSION = 13;
+  static const int DATA_VERSION = 20;
+
+  /**
+   * The number of exception contexts allowed to write. Once this field is
+   * zero, we stop writing any new exception contexts in this process.
+   */
+  static int allowedNumberOfContextsToWrite = 10;
 
   /**
    * The name of the driver, e.g. the name of the folder.
@@ -132,21 +136,16 @@
   final DeclaredVariables declaredVariables = new DeclaredVariables();
 
   /**
+   * If `true`, then analysis should be done without using tasks model.
+   */
+  final bool analyzeWithoutTasks;
+
+  /**
    * The salt to mix into all hashes used as keys for serialized data.
    */
   final Uint32List _salt = new Uint32List(1 + AnalysisOptions.signatureLength);
 
   /**
-   * The current file system state.
-   */
-  FileSystemState _fsState;
-
-  /**
-   * The set of added files.
-   */
-  final _addedFiles = new LinkedHashSet<String>();
-
-  /**
    * The set of priority files, that should be analyzed sooner.
    */
   final _priorityFiles = new LinkedHashSet<String>();
@@ -158,6 +157,11 @@
   final _requestedFiles = <String, List<Completer<AnalysisResult>>>{};
 
   /**
+   * The list of tasks to compute files defining a class member name.
+   */
+  final _definingClassMemberNameTasks = <_FilesDefiningClassMemberNameTask>[];
+
+  /**
    * The list of tasks to compute files referencing a name.
    */
   final _referencingNameTasks = <_FilesReferencingNameTask>[];
@@ -175,22 +179,17 @@
       <String, List<Completer<AnalysisDriverUnitIndex>>>{};
 
   /**
-   * The mapping from the files for which the index was requested using
-   * [getIndex] to the [Completer]s to report the result.
+   * The mapping from the files for which the unit element key was requested
+   * using [getUnitElementSignature] to the [Completer]s to report the result.
+   */
+  final _unitElementSignatureRequests = <String, List<Completer<String>>>{};
+
+  /**
+   * The mapping from the files for which the unit element was requested using
+   * [getUnitElement] to the [Completer]s to report the result.
    */
   final _unitElementRequestedFiles =
-      <String, List<Completer<CompilationUnitElement>>>{};
-
-  /**
-   * The set of files were reported as changed through [changeFile] and not
-   * checked for actual changes yet.
-   */
-  final _changedFiles = new LinkedHashSet<String>();
-
-  /**
-   * The set of files that are currently scheduled for analysis.
-   */
-  final _filesToAnalyze = new LinkedHashSet<String>();
+      <String, List<Completer<UnitElementResult>>>{};
 
   /**
    * The mapping from the files for which analysis was requested using
@@ -215,11 +214,6 @@
   final Map<String, AnalysisResult> _priorityResults = {};
 
   /**
-   * The instance of the status helper.
-   */
-  final StatusSupport _statusSupport = new StatusSupport();
-
-  /**
    * The controller for the [exceptions] stream.
    */
   final StreamController<ExceptionResult> _exceptionController =
@@ -233,6 +227,11 @@
   AnalysisDriverTestView _testView;
 
   /**
+   * The [FileTracker] used by this driver.
+   */
+  FileTracker _fileTracker;
+
+  /**
    * Create a new instance of [AnalysisDriver].
    *
    * The given [SourceFactory] is cloned to ensure that it does not contain a
@@ -240,20 +239,20 @@
    */
   AnalysisDriver(
       this._scheduler,
-      this._logger,
+      PerformanceLog logger,
       this._resourceProvider,
       this._byteStore,
       this._contentOverlay,
       this.name,
       SourceFactory sourceFactory,
       this._analysisOptions,
-      {PackageBundle sdkBundle})
-      : _sourceFactory = sourceFactory.clone(),
+      {PackageBundle sdkBundle,
+      this.analyzeWithoutTasks: false})
+      : _logger = logger,
+        _sourceFactory = sourceFactory.clone(),
         _sdkBundle = sdkBundle {
     _testView = new AnalysisDriverTestView(this);
-    _fillSalt();
-    _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
-        _resourceProvider, sourceFactory, _analysisOptions, _salt);
+    _createFileTracker(logger);
     _scheduler._add(this);
     _search = new Search(this);
   }
@@ -261,7 +260,7 @@
   /**
    * Return the set of files explicitly added to analysis using [addFile].
    */
-  Set<String> get addedFiles => _addedFiles;
+  Set<String> get addedFiles => _fileTracker.addedFiles;
 
   /**
    * Return the analysis options used to control analysis.
@@ -276,16 +275,16 @@
   /**
    * The current file system state.
    */
-  FileSystemState get fsState => _fsState;
+  FileSystemState get fsState => _fileTracker.fsState;
 
   /**
    * Return `true` if the driver has a file to analyze.
    */
   bool get hasFilesToAnalyze {
-    return _changedFiles.isNotEmpty ||
+    return _fileTracker.hasChangedFiles ||
         _requestedFiles.isNotEmpty ||
         _requestedParts.isNotEmpty ||
-        _filesToAnalyze.isNotEmpty ||
+        _fileTracker.hasPendingFiles ||
         _partsToAnalyze.isNotEmpty;
   }
 
@@ -294,12 +293,12 @@
    * always include all added files or all implicitly used file. If a file has
    * not been processed yet, it might be missing.
    */
-  Set<String> get knownFiles => _fsState.knownFilePaths;
+  Set<String> get knownFiles => _fileTracker.fsState.knownFilePaths;
 
   /**
    * Return the number of files scheduled for analysis.
    */
-  int get numberOfFilesToAnalyze => _filesToAnalyze.length;
+  int get numberOfFilesToAnalyze => _fileTracker.numberOfPendingFiles;
 
   /**
    * Return the list of files that the driver should try to analyze sooner.
@@ -322,8 +321,7 @@
         .forEach(_priorityResults.remove);
     _priorityFiles.clear();
     _priorityFiles.addAll(priorityPaths);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    _scheduler.notify(this);
   }
 
   /**
@@ -361,11 +359,6 @@
    */
   SourceFactory get sourceFactory => _sourceFactory;
 
-  /**
-   * Return the stream that produces [AnalysisStatus] events.
-   */
-  Stream<AnalysisStatus> get status => _statusSupport.stream;
-
   @visibleForTesting
   AnalysisDriverTestView get test => _testView;
 
@@ -376,12 +369,16 @@
     if (_requestedFiles.isNotEmpty) {
       return AnalysisDriverPriority.interactive;
     }
-    if (_referencingNameTasks.isNotEmpty) {
+    if (_definingClassMemberNameTasks.isNotEmpty ||
+        _referencingNameTasks.isNotEmpty) {
       return AnalysisDriverPriority.interactive;
     }
     if (_indexRequestedFiles.isNotEmpty) {
       return AnalysisDriverPriority.interactive;
     }
+    if (_unitElementSignatureRequests.isNotEmpty) {
+      return AnalysisDriverPriority.interactive;
+    }
     if (_unitElementRequestedFiles.isNotEmpty) {
       return AnalysisDriverPriority.interactive;
     }
@@ -390,21 +387,20 @@
     }
     if (_priorityFiles.isNotEmpty) {
       for (String path in _priorityFiles) {
-        if (_filesToAnalyze.contains(path)) {
+        if (_fileTracker.isFilePending(path)) {
           return AnalysisDriverPriority.priority;
         }
       }
     }
-    if (_filesToAnalyze.isNotEmpty) {
+    if (_fileTracker.hasPendingFiles) {
       return AnalysisDriverPriority.general;
     }
-    if (_changedFiles.isNotEmpty) {
+    if (_fileTracker.hasChangedFiles) {
       return AnalysisDriverPriority.general;
     }
     if (_requestedParts.isNotEmpty || _partsToAnalyze.isNotEmpty) {
       return AnalysisDriverPriority.general;
     }
-    _statusSupport.transitionToIdle();
     return AnalysisDriverPriority.nothing;
   }
 
@@ -416,13 +412,12 @@
    * The results of analysis are eventually produced by the [results] stream.
    */
   void addFile(String path) {
-    if (AnalysisEngine.isDartFileName(path)) {
-      _addedFiles.add(path);
-      _filesToAnalyze.add(path);
-      _priorityResults.clear();
+    if (!_fileTracker.fsState.hasUri(path)) {
+      return;
     }
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    if (AnalysisEngine.isDartFileName(path)) {
+      _fileTracker.addFile(path);
+    }
   }
 
   /**
@@ -444,13 +439,8 @@
    * [changeFile] invocation.
    */
   void changeFile(String path) {
-    _changedFiles.add(path);
-    if (_addedFiles.contains(path)) {
-      _filesToAnalyze.add(path);
-    }
+    _fileTracker.changeFile(path);
     _priorityResults.clear();
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
   }
 
   /**
@@ -468,12 +458,9 @@
     if (sourceFactory != null) {
       _sourceFactory = sourceFactory;
     }
-    _fillSalt();
-    _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
-        _resourceProvider, _sourceFactory, _analysisOptions, _salt);
-    _filesToAnalyze.addAll(_addedFiles);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    Iterable<String> addedFiles = _fileTracker.addedFiles;
+    _createFileTracker(_logger);
+    _fileTracker.addFiles(addedFiles);
   }
 
   /**
@@ -484,35 +471,78 @@
   }
 
   /**
+   * Return a [Future] that completes with the [ErrorsResult] for the Dart
+   * file with the given [path]. If the file is not a Dart file or cannot
+   * be analyzed, the [Future] completes with `null`.
+   *
+   * The [path] must be absolute and normalized.
+   *
+   * This method does not use analysis priorities, and must not be used in
+   * interactive analysis, such as Analysis Server or its plugins.
+   */
+  Future<ErrorsResult> getErrors(String path) async {
+    // Ask the analysis result without unit, so return cached errors.
+    // If no cached analysis result, it will be computed.
+    AnalysisResult analysisResult = _computeAnalysisResult(path);
+
+    // If not computed yet, because a part file without a known library,
+    // we have to compute the full analysis result, with the unit.
+    analysisResult ??= await getResult(path);
+    if (analysisResult == null) {
+      return null;
+    }
+
+    return new ErrorsResult(
+        path,
+        analysisResult.uri,
+        analysisResult.contentHash,
+        analysisResult.lineInfo,
+        analysisResult.errors);
+  }
+
+  /**
+   * Return a [Future] that completes with the list of added files that
+   * define a class member with the given [name].
+   */
+  Future<List<String>> getFilesDefiningClassMemberName(String name) {
+    var task = new _FilesDefiningClassMemberNameTask(this, name);
+    _definingClassMemberNameTasks.add(task);
+    _scheduler.notify(this);
+    return task.completer.future;
+  }
+
+  /**
    * Return a [Future] that completes with the list of added files that
    * reference the given external [name].
    */
   Future<List<String>> getFilesReferencingName(String name) {
     var task = new _FilesReferencingNameTask(this, name);
     _referencingNameTasks.add(task);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    _scheduler.notify(this);
     return task.completer.future;
   }
 
   /**
    * Return a [Future] that completes with the [AnalysisDriverUnitIndex] for
-   * the file with the given [path].
+   * the file with the given [path], or with `null` if the file cannot be
+   * analyzed.
    */
   Future<AnalysisDriverUnitIndex> getIndex(String path) {
+    if (!_fileTracker.fsState.hasUri(path)) {
+      return new Future.value();
+    }
     var completer = new Completer<AnalysisDriverUnitIndex>();
     _indexRequestedFiles
         .putIfAbsent(path, () => <Completer<AnalysisDriverUnitIndex>>[])
         .add(completer);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    _scheduler.notify(this);
     return completer.future;
   }
 
   /**
    * Return a [Future] that completes with a [AnalysisResult] for the Dart
-   * file with the given [path]. If the file is not a Dart file, the [Future]
-   * completes with `null`.
+   * file with the given [path]. If the file is not a Dart file or cannot
+   * be analyzed, the [Future] completes with `null`.
    *
    * The [path] must be absolute and normalized.
    *
@@ -521,12 +551,16 @@
    * If the driver has the cached analysis result for the file, it is returned.
    *
    * Otherwise causes the analysis state to transition to "analyzing" (if it is
-   * not in that state already), the driver will read the file and produce the
-   * analysis result for it, which is consistent with the current file state
-   * (including the new state of the file), prior to the next time the analysis
-   * state transitions to "idle".
+   * not in that state already), the driver will produce the analysis result for
+   * it, which is consistent with the current file state (including new states
+   * of the files previously reported using [changeFile]), prior to the next
+   * time the analysis state transitions to "idle".
    */
   Future<AnalysisResult> getResult(String path) {
+    if (!_fileTracker.fsState.hasUri(path)) {
+      return new Future.value();
+    }
+
     // Return the cached result.
     {
       AnalysisResult result = _priorityResults[path];
@@ -540,12 +574,26 @@
     _requestedFiles
         .putIfAbsent(path, () => <Completer<AnalysisResult>>[])
         .add(completer);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    _scheduler.notify(this);
     return completer.future;
   }
 
   /**
+   * Return a [Future] that completes with the [SourceKind] for the Dart
+   * file with the given [path]. If the file is not a Dart file or cannot
+   * be analyzed, the [Future] completes with `null`.
+   *
+   * The [path] must be absolute and normalized.
+   */
+  Future<SourceKind> getSourceKind(String path) async {
+    if (AnalysisEngine.isDartFileName(path)) {
+      FileState file = _fileTracker.fsState.getFileForPath(path);
+      return file.isPart ? SourceKind.PART : SourceKind.LIBRARY;
+    }
+    return null;
+  }
+
+  /**
    * Return a [Future] that completes with top-level declarations with the
    * given [name] in all known libraries.
    */
@@ -553,22 +601,44 @@
       String name) {
     var task = new _TopLevelNameDeclarationsTask(this, name);
     _topLevelNameDeclarationsTasks.add(task);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    _scheduler.notify(this);
     return task.completer.future;
   }
 
   /**
-   * Return a [Future] that completes with the [CompilationUnitElement] for the
-   * file with the given [path].
+   * Return a [Future] that completes with the [UnitElementResult] for the
+   * file with the given [path], or with `null` if the file cannot be analyzed.
    */
-  Future<CompilationUnitElement> getUnitElement(String path) {
-    var completer = new Completer<CompilationUnitElement>();
+  Future<UnitElementResult> getUnitElement(String path) {
+    if (!_fileTracker.fsState.hasUri(path)) {
+      return new Future.value();
+    }
+    var completer = new Completer<UnitElementResult>();
     _unitElementRequestedFiles
-        .putIfAbsent(path, () => <Completer<CompilationUnitElement>>[])
+        .putIfAbsent(path, () => <Completer<UnitElementResult>>[])
         .add(completer);
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
+    _scheduler.notify(this);
+    return completer.future;
+  }
+
+  /**
+   * Return a [Future] that completes with the signature for the
+   * [UnitElementResult] for the file with the given [path], or with `null` if
+   * the file cannot be analyzed.
+   *
+   * The signature is based on the content of the file, and the transitive
+   * closure of files imported and exported by the the library of the requested
+   * file.
+   */
+  Future<String> getUnitElementSignature(String path) {
+    if (!_fileTracker.fsState.hasUri(path)) {
+      return new Future.value();
+    }
+    var completer = new Completer<String>();
+    _unitElementSignatureRequests
+        .putIfAbsent(path, () => <Completer<String>>[])
+        .add(completer);
+    _scheduler.notify(this);
     return completer.future;
   }
 
@@ -585,7 +655,7 @@
    * resolved unit).
    */
   Future<ParseResult> parseFile(String path) async {
-    FileState file = _verifyApiSignature(path);
+    FileState file = _fileTracker.verifyApiSignature(path);
     RecordingErrorListener listener = new RecordingErrorListener();
     CompilationUnit unit = file.parse(listener);
     return new ParseResult(file.path, file.uri, file.content, file.contentHash,
@@ -602,22 +672,18 @@
    * but does not guarantee this.
    */
   void removeFile(String path) {
-    _addedFiles.remove(path);
-    _filesToAnalyze.remove(path);
-    _fsState.removeFile(path);
-    _filesToAnalyze.addAll(_addedFiles);
+    _fileTracker.removeFile(path);
     _priorityResults.clear();
-    _statusSupport.transitionToAnalyzing();
-    _scheduler._notify(this);
   }
 
   /**
-   * Return a future that will be completed the next time the status is idle.
-   *
-   * If the status is currently idle, the returned future will be signaled
-   * immediately.
+   * Handles a notification from the [FileTracker] that there has been a change
+   * of state.
    */
-  Future<Null> waitForIdle() => _statusSupport.waitForIdle();
+  void _changeHook() {
+    _priorityResults.clear();
+    _scheduler.notify(this);
+  }
 
   /**
    * Return the cached or newly computed analysis result of the file with the
@@ -632,31 +698,21 @@
    */
   AnalysisResult _computeAnalysisResult(String path,
       {bool withUnit: false, bool asIsIfPartWithoutLibrary: false}) {
-    /**
-     * If the [file] is a library, return the [file] itself.
-     * If the [file] is a part, return a library it is known to be a part of.
-     * If there is no such library, return `null`.
-     */
-    FileState getLibraryFile(FileState file) {
-      FileState libraryFile = file.isPart ? file.library : file;
-      if (libraryFile == null && asIsIfPartWithoutLibrary) {
-        libraryFile = file;
+    FileState file = _fileTracker.fsState.getFileForPath(path);
+
+    // Prepare the library - the file itself, or the known library.
+    FileState library = file.isPart ? file.library : file;
+    if (library == null) {
+      if (asIsIfPartWithoutLibrary) {
+        library = file;
+      } else {
+        return null;
       }
-      return libraryFile;
     }
 
     // If we don't need the fully resolved unit, check for the cached result.
     if (!withUnit) {
-      FileState file = _fsState.getFileForPath(path);
-
-      // Prepare the library file - the file itself, or the known library.
-      FileState libraryFile = getLibraryFile(file);
-      if (libraryFile == null) {
-        return null;
-      }
-
-      // Check for the cached result.
-      String key = _getResolvedUnitKey(libraryFile, file);
+      String key = _getResolvedUnitKey(library, file);
       List<int> bytes = _byteStore.get(key);
       if (bytes != null) {
         return _getAnalysisResultFromBytes(file, bytes);
@@ -665,52 +721,53 @@
 
     // We need the fully resolved unit, or the result is not cached.
     return _logger.run('Compute analysis result for $path', () {
-      FileState file = _verifyApiSignature(path);
-
-      // Prepare the library file - the file itself, or the known library.
-      FileState libraryFile = getLibraryFile(file);
-      if (libraryFile == null) {
-        return null;
-      }
-
-      _LibraryContext libraryContext = _createLibraryContext(libraryFile);
-      AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
       try {
-        CompilationUnit resolvedUnit = analysisContext.resolveCompilationUnit2(
-            file.source, libraryFile.source);
-        List<AnalysisError> errors = analysisContext.computeErrors(file.source);
-        AnalysisDriverUnitIndexBuilder index = indexUnit(resolvedUnit);
+        LibraryContext libraryContext = _createLibraryContext(library);
+        try {
+          CompilationUnit resolvedUnit;
+          List<int> bytes;
+          if (analyzeWithoutTasks) {
+            LibraryAnalyzer analyzer = new LibraryAnalyzer(
+                analysisOptions,
+                declaredVariables,
+                sourceFactory,
+                _fileTracker.fsState,
+                libraryContext.store,
+                library);
+            Map<FileState, UnitAnalysisResult> results = analyzer.analyze();
+            UnitAnalysisResult fileResult = results[file];
+            resolvedUnit = fileResult.unit;
 
-        // Store the result into the cache.
-        List<int> bytes;
-        {
-          bytes = new AnalysisDriverResolvedUnitBuilder(
-                  errors: errors
-                      .map((error) => new AnalysisDriverUnitErrorBuilder(
-                          offset: error.offset,
-                          length: error.length,
-                          uniqueName: error.errorCode.uniqueName,
-                          message: error.message,
-                          correction: error.correction))
-                      .toList(),
-                  index: index)
-              .toBuffer();
-          String key = _getResolvedUnitKey(libraryFile, file);
-          _byteStore.put(key, bytes);
-        }
+            // Store the result into the cache.
+            bytes = _storeResolvedUnit(
+                library, file, resolvedUnit, fileResult.errors);
+          } else {
+            ResolutionResult resolutionResult =
+                libraryContext.resolveUnit(library.source, file.source);
+            resolvedUnit = resolutionResult.resolvedUnit;
+            List<AnalysisError> errors = resolutionResult.errors;
 
-        // Return the result, full or partial.
-        _logger.writeln('Computed new analysis result.');
-        AnalysisResult result = _getAnalysisResultFromBytes(file, bytes,
-            content: withUnit ? file.content : null,
-            withErrors: _addedFiles.contains(path),
-            resolvedUnit: withUnit ? resolvedUnit : null);
-        if (withUnit && _priorityFiles.contains(path)) {
-          _priorityResults[path] = result;
+            // Store the result into the cache.
+            bytes = _storeResolvedUnit(library, file, resolvedUnit, errors);
+          }
+
+          // Return the result, full or partial.
+          _logger.writeln('Computed new analysis result.');
+          AnalysisResult result = _getAnalysisResultFromBytes(file, bytes,
+              content: withUnit ? file.content : null,
+              withErrors: _fileTracker.addedFiles.contains(path),
+              resolvedUnit: withUnit ? resolvedUnit : null);
+          if (withUnit && _priorityFiles.contains(path)) {
+            _priorityResults[path] = result;
+          }
+          return result;
+        } finally {
+          libraryContext.dispose();
         }
-        return result;
-      } finally {
-        analysisContext.dispose();
+      } catch (exception, stackTrace) {
+        String contextKey =
+            _storeExceptionContext(path, library, exception, stackTrace);
+        throw new _ExceptionState(exception, stackTrace, contextKey);
       }
     });
   }
@@ -721,120 +778,57 @@
     return analysisResult._index;
   }
 
-  CompilationUnitElement _computeUnitElement(String path) {
-    FileState file = _fsState.getFileForPath(path);
-    FileState libraryFile = file.library ?? file;
+  UnitElementResult _computeUnitElement(String path) {
+    FileState file = _fileTracker.fsState.getFileForPath(path);
+    FileState library = file.library ?? file;
 
     // Create the AnalysisContext to resynthesize elements in.
-    _LibraryContext libraryContext = _createLibraryContext(libraryFile);
-    AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
+    LibraryContext libraryContext = _createLibraryContext(library);
 
     // Resynthesize the CompilationUnitElement in the context.
     try {
-      return analysisContext.computeResult(
-          new LibrarySpecificUnit(libraryFile.source, file.source),
-          COMPILATION_UNIT_ELEMENT);
+      CompilationUnitElement element =
+          libraryContext.computeUnitElement(library.source, file.source);
+      String signature = _getResolvedUnitSignature(library, file);
+      return new UnitElementResult(path, file.contentHash, signature, element);
     } finally {
-      analysisContext.dispose();
+      libraryContext.dispose();
     }
   }
 
-  AnalysisContext _createAnalysisContext(_LibraryContext libraryContext) {
-    AnalysisContextImpl analysisContext =
-        AnalysisEngine.instance.createAnalysisContext();
-    analysisContext.useSdkCachePartition = false;
-    analysisContext.analysisOptions = _analysisOptions;
-    analysisContext.declaredVariables.addAll(declaredVariables);
-    analysisContext.sourceFactory = _sourceFactory.clone();
-    analysisContext.contentCache = new _ContentCacheWrapper(_fsState);
-    analysisContext.resultProvider =
-        new InputPackagesResultProvider(analysisContext, libraryContext.store);
-    return analysisContext;
+  String _computeUnitElementSignature(String path) {
+    FileState file = _fileTracker.fsState.getFileForPath(path);
+    FileState library = file.library ?? file;
+    return _getResolvedUnitSignature(library, file);
   }
 
   /**
-   * Return the context in which the [library] should be analyzed it.
+   * Creates a new [FileTracker] object and stores it in [_fileTracker].
+   *
+   * This is used both on initial construction and whenever the configuration
+   * changes.
    */
-  _LibraryContext _createLibraryContext(FileState library) {
-    return _logger.run('Create library context', () {
-      Map<String, FileState> libraries = <String, FileState>{};
-      SummaryDataStore store = new SummaryDataStore(const <String>[]);
-
-      if (_sdkBundle != null) {
-        store.addBundle(null, _sdkBundle);
-      }
-
-      void appendLibraryFiles(FileState library) {
-        if (!libraries.containsKey(library.uriStr)) {
-          // Serve 'dart:' URIs from the SDK bundle.
-          if (_sdkBundle != null && library.uri.scheme == 'dart') {
-            return;
-          }
-
-          libraries[library.uriStr] = library;
-
-          // Append the defining unit.
-          store.addUnlinkedUnit(library.uriStr, library.unlinked);
-
-          // Append parts.
-          for (FileState part in library.partedFiles) {
-            store.addUnlinkedUnit(part.uriStr, part.unlinked);
-          }
-
-          // Append referenced libraries.
-          library.importedFiles.forEach(appendLibraryFiles);
-          library.exportedFiles.forEach(appendLibraryFiles);
-        }
-      }
-
-      _logger.run('Append library files', () {
-        return appendLibraryFiles(library);
-      });
-
-      Set<String> libraryUrisToLink = new Set<String>();
-      _logger.run('Load linked bundles', () {
-        for (FileState library in libraries.values) {
-          if (library.exists) {
-            String key = '${library.transitiveSignature}.linked';
-            List<int> bytes = _byteStore.get(key);
-            if (bytes != null) {
-              LinkedLibrary linked = new LinkedLibrary.fromBuffer(bytes);
-              store.addLinkedLibrary(library.uriStr, linked);
-            } else {
-              libraryUrisToLink.add(library.uriStr);
-            }
-          }
-        }
-        int numOfLoaded = libraries.length - libraryUrisToLink.length;
-        _logger.writeln('Loaded $numOfLoaded linked bundles.');
-      });
-
-      Map<String, LinkedLibraryBuilder> linkedLibraries = {};
-      _logger.run('Link bundles', () {
-        linkedLibraries = link(libraryUrisToLink, (String uri) {
-          LinkedLibrary linkedLibrary = store.linkedMap[uri];
-          return linkedLibrary;
-        }, (String uri) {
-          UnlinkedUnit unlinkedUnit = store.unlinkedMap[uri];
-          return unlinkedUnit;
-        }, (_) => null, _analysisOptions.strongMode);
-        _logger.writeln('Linked ${linkedLibraries.length} bundles.');
-      });
-
-      linkedLibraries.forEach((uri, linkedBuilder) {
-        FileState library = libraries[uri];
-        String key = '${library.transitiveSignature}.linked';
-        List<int> bytes = linkedBuilder.toBuffer();
-        LinkedLibrary linked = new LinkedLibrary.fromBuffer(bytes);
-        store.addLinkedLibrary(uri, linked);
-        _byteStore.put(key, bytes);
-      });
-
-      return new _LibraryContext(library, store);
-    });
+  void _createFileTracker(PerformanceLog logger) {
+    _fillSalt();
+    _fileTracker = new FileTracker(logger, _byteStore, _contentOverlay,
+        _resourceProvider, sourceFactory, _analysisOptions, _salt, _changeHook);
   }
 
   /**
+   * Return the context in which the [library] should be analyzed.
+   */
+  LibraryContext _createLibraryContext(FileState library) =>
+      new LibraryContext.forSingleLibrary(
+          library,
+          _logger,
+          _sdkBundle,
+          _byteStore,
+          _analysisOptions,
+          declaredVariables,
+          _sourceFactory,
+          _fileTracker);
+
+  /**
    * Fill [_salt] with data.
    */
   void _fillSalt() {
@@ -892,15 +886,23 @@
 
   /**
    * Return the key to store fully resolved results for the [file] in the
-   * [library] into the cache. Return `null` if the dependency signature is
-   * not known yet.
+   * [library] into the cache.
    */
   String _getResolvedUnitKey(FileState library, FileState file) {
+    String signature = _getResolvedUnitSignature(library, file);
+    return '$signature.resolved';
+  }
+
+  /**
+   * Return the signature that identifies fully resolved results for the [file]
+   * in the [library], e.g. element model, errors, index, etc.
+   */
+  String _getResolvedUnitSignature(FileState library, FileState file) {
     ApiSignature signature = new ApiSignature();
     signature.addUint32List(_salt);
     signature.addString(library.transitiveSignature);
     signature.addString(file.contentHash);
-    return '${signature.toHex()}.resolved';
+    return signature.toHex();
   }
 
   /**
@@ -925,14 +927,7 @@
    * Perform a single chunk of work and produce [results].
    */
   Future<Null> _performWork() async {
-    // Verify all changed files one at a time.
-    if (_changedFiles.isNotEmpty) {
-      String path = _removeFirst(_changedFiles);
-      // If the file has not been accessed yet, we either will eventually read
-      // it later while analyzing one of the added files, or don't need it.
-      if (_fsState.knownFilePaths.contains(path)) {
-        _verifyApiSignature(path);
-      }
+    if (_fileTracker.verifyChangedFilesIfNeeded()) {
       return;
     }
 
@@ -953,10 +948,10 @@
           completer.complete(result);
         });
         // Remove from to be analyzed and produce it now.
-        _filesToAnalyze.remove(path);
+        _fileTracker.fileWasAnalyzed(path);
         _resultController.add(result);
       } catch (exception, stackTrace) {
-        _filesToAnalyze.remove(path);
+        _fileTracker.fileWasAnalyzed(path);
         _requestedFiles.remove(path).forEach((completer) {
           completer.completeError(exception, stackTrace);
         });
@@ -974,16 +969,37 @@
       return;
     }
 
-    // Process a unit request.
+    // Process a unit element key request.
+    if (_unitElementSignatureRequests.isNotEmpty) {
+      String path = _unitElementSignatureRequests.keys.first;
+      String signature = _computeUnitElementSignature(path);
+      _unitElementSignatureRequests.remove(path).forEach((completer) {
+        completer.complete(signature);
+      });
+      return;
+    }
+
+    // Process a unit element request.
     if (_unitElementRequestedFiles.isNotEmpty) {
       String path = _unitElementRequestedFiles.keys.first;
-      CompilationUnitElement unitElement = _computeUnitElement(path);
+      UnitElementResult result = _computeUnitElement(path);
       _unitElementRequestedFiles.remove(path).forEach((completer) {
-        completer.complete(unitElement);
+        completer.complete(result);
       });
       return;
     }
 
+    // Compute files defining a name.
+    if (_definingClassMemberNameTasks.isNotEmpty) {
+      _FilesDefiningClassMemberNameTask task =
+          _definingClassMemberNameTasks.first;
+      bool isDone = await task.perform();
+      if (isDone) {
+        _definingClassMemberNameTasks.remove(task);
+      }
+      return;
+    }
+
     // Compute files referencing a name.
     if (_referencingNameTasks.isNotEmpty) {
       _FilesReferencingNameTask task = _referencingNameTasks.first;
@@ -1007,7 +1023,7 @@
     // Analyze a priority file.
     if (_priorityFiles.isNotEmpty) {
       for (String path in _priorityFiles) {
-        if (_filesToAnalyze.remove(path)) {
+        if (_fileTracker.isFilePending(path)) {
           try {
             AnalysisResult result =
                 _computeAnalysisResult(path, withUnit: true);
@@ -1017,16 +1033,18 @@
               _resultController.add(result);
             }
           } catch (exception, stackTrace) {
-            _reportError(path, exception, stackTrace);
+            _reportException(path, exception, stackTrace);
+          } finally {
+            _fileTracker.fileWasAnalyzed(path);
           }
           return;
         }
       }
     }
 
-    // Analyze a general file.
-    if (_filesToAnalyze.isNotEmpty) {
-      String path = _removeFirst(_filesToAnalyze);
+    if (_fileTracker.hasPendingFiles) {
+      // Analyze a general file.
+      String path = _fileTracker.anyPendingFile;
       try {
         AnalysisResult result = _computeAnalysisResult(path, withUnit: false);
         if (result == null) {
@@ -1035,7 +1053,9 @@
           _resultController.add(result);
         }
       } catch (exception, stackTrace) {
-        _reportError(path, exception, stackTrace);
+        _reportException(path, exception, stackTrace);
+      } finally {
+        _fileTracker.fileWasAnalyzed(path);
       }
       return;
     }
@@ -1064,54 +1084,103 @@
 
     // Analyze a general part.
     if (_partsToAnalyze.isNotEmpty) {
-      String path = _removeFirst(_partsToAnalyze);
+      String path = _partsToAnalyze.first;
+      _partsToAnalyze.remove(path);
       try {
         AnalysisResult result = _computeAnalysisResult(path,
             withUnit: _priorityFiles.contains(path),
             asIsIfPartWithoutLibrary: true);
         _resultController.add(result);
       } catch (exception, stackTrace) {
-        _reportError(path, exception, stackTrace);
+        _reportException(path, exception, stackTrace);
       }
       return;
     }
   }
 
-  void _reportError(String path, exception, StackTrace stackTrace) {
+  void _reportException(String path, exception, StackTrace stackTrace) {
+    String contextKey = null;
+    if (exception is _ExceptionState) {
+      var state = exception as _ExceptionState;
+      exception = state.exception;
+      stackTrace = state.stackTrace;
+      contextKey = state.contextKey;
+    }
     CaughtException caught = new CaughtException(exception, stackTrace);
-    _exceptionController.add(new ExceptionResult(path, caught));
+    _exceptionController.add(new ExceptionResult(path, caught, contextKey));
+  }
+
+  String _storeExceptionContext(
+      String path, FileState libraryFile, exception, StackTrace stackTrace) {
+    if (allowedNumberOfContextsToWrite <= 0) {
+      return null;
+    } else {
+      allowedNumberOfContextsToWrite--;
+    }
+    try {
+      List<AnalysisDriverExceptionFileBuilder> contextFiles = libraryFile
+          .transitiveFiles
+          .map((file) => new AnalysisDriverExceptionFileBuilder(
+              path: file.path, content: file.content))
+          .toList();
+      contextFiles.sort((a, b) => a.path.compareTo(b.path));
+      AnalysisDriverExceptionContextBuilder contextBuilder =
+          new AnalysisDriverExceptionContextBuilder(
+              path: path,
+              exception: exception.toString(),
+              stackTrace: stackTrace.toString(),
+              files: contextFiles);
+      List<int> bytes = contextBuilder.toBuffer();
+
+      String _twoDigits(int n) {
+        if (n >= 10) return '$n';
+        return '0$n';
+      }
+
+      String _threeDigits(int n) {
+        if (n >= 100) return '$n';
+        if (n >= 10) return '0$n';
+        return '00$n';
+      }
+
+      DateTime time = new DateTime.now();
+      String m = _twoDigits(time.month);
+      String d = _twoDigits(time.day);
+      String h = _twoDigits(time.hour);
+      String min = _twoDigits(time.minute);
+      String sec = _twoDigits(time.second);
+      String ms = _threeDigits(time.millisecond);
+      String key = 'exception_${time.year}$m$d' '_$h$min$sec' + '_$ms';
+
+      _byteStore.put(key, bytes);
+      return key;
+    } catch (_) {
+      return null;
+    }
   }
 
   /**
-   * Verify the API signature for the file with the given [path], and decide
-   * which linked libraries should be invalidated, and files reanalyzed.
+   * Store the fully resolved results for the [file] in the [library] into the
+   * cache and return the stored bytes.
    */
-  FileState _verifyApiSignature(String path) {
-    return _logger.run('Verify API signature of $path', () {
-      bool anyApiChanged = false;
-      List<FileState> files = _fsState.getFilesForPath(path);
-      for (FileState file in files) {
-        bool apiChanged = file.refresh();
-        if (apiChanged) {
-          anyApiChanged = true;
-        }
-      }
-      if (anyApiChanged) {
-        _logger.writeln('API signatures mismatch found for $path');
-        // TODO(scheglov) schedule analysis of only affected files
-        _filesToAnalyze.addAll(_addedFiles);
-      }
-      return files[0];
-    });
-  }
+  List<int> _storeResolvedUnit(FileState library, FileState file,
+      CompilationUnit resolvedUnit, List<AnalysisError> errors) {
+    AnalysisDriverUnitIndexBuilder index = indexUnit(resolvedUnit);
 
-  /**
-   * Remove and return the first item in the given [set].
-   */
-  static Object/*=T*/ _removeFirst/*<T>*/(LinkedHashSet<Object/*=T*/ > set) {
-    Object/*=T*/ element = set.first;
-    set.remove(element);
-    return element;
+    String key = _getResolvedUnitKey(library, file);
+    List<int> bytes = new AnalysisDriverResolvedUnitBuilder(
+            errors: errors
+                .map((error) => new AnalysisDriverUnitErrorBuilder(
+                    offset: error.offset,
+                    length: error.length,
+                    uniqueName: error.errorCode.uniqueName,
+                    message: error.message,
+                    correction: error.correction))
+                .toList(),
+            index: index)
+        .toBuffer();
+    _byteStore.put(key, bytes);
+    return bytes;
   }
 }
 
@@ -1180,6 +1249,15 @@
   }
 
   /**
+   * Notify that there is a change to the [driver], it it might need to
+   * perform some work.
+   */
+  void notify(AnalysisDriver driver) {
+    _hasWork.notify();
+    _statusSupport.preTransitionToAnalyzing();
+  }
+
+  /**
    * Start the scheduler, so that any [AnalysisDriver] created before or
    * after will be asked to perform work.
    */
@@ -1192,6 +1270,14 @@
   }
 
   /**
+   * Return a future that will be completed the next time the status is idle.
+   *
+   * If the status is currently idle, the returned future will be signaled
+   * immediately.
+   */
+  Future<Null> waitForIdle() => _statusSupport.waitForIdle();
+
+  /**
    * Add the given [driver] and schedule it to perform its work.
    */
   void _add(AnalysisDriver driver) {
@@ -1200,14 +1286,6 @@
   }
 
   /**
-   * Notify that there is a change to the [driver], it it might need to
-   * perform some work.
-   */
-  void _notify(AnalysisDriver driver) {
-    _hasWork.notify();
-  }
-
-  /**
    * Remove the given [driver] from the scheduler, so that it will not be
    * asked to perform any new work.
    */
@@ -1243,7 +1321,7 @@
       AnalysisDriverPriority bestPriority = AnalysisDriverPriority.nothing;
       for (AnalysisDriver driver in _drivers) {
         AnalysisDriverPriority priority = driver._workPriority;
-        if (bestPriority == null || priority.index > bestPriority.index) {
+        if (priority.index > bestPriority.index) {
           bestDriver = driver;
           bestPriority = priority;
         }
@@ -1287,7 +1365,7 @@
 
   AnalysisDriverTestView(this.driver);
 
-  Set<String> get filesToAnalyze => driver._filesToAnalyze;
+  FileTracker get fileTracker => driver._fileTracker;
 
   Map<String, AnalysisResult> get priorityResults => driver._priorityResults;
 }
@@ -1376,6 +1454,43 @@
 }
 
 /**
+ * The errors in a single file.
+ *
+ * These results are self-consistent, i.e. [content], [contentHash], [errors]
+ * correspond to each other. But none of the results is guaranteed to be
+ * consistent with the state of the files.
+ */
+class ErrorsResult {
+  /**
+   * The path of the parsed file, absolute and normalized.
+   */
+  final String path;
+
+  /**
+   * The URI of the file that corresponded to the [path].
+   */
+  final Uri uri;
+
+  /**
+   * The MD5 hash of the [content].
+   */
+  final String contentHash;
+
+  /**
+   * Information about lines in the [content].
+   */
+  final LineInfo lineInfo;
+
+  /**
+   * The full list of computed analysis errors, both syntactic and semantic.
+   */
+  final List<AnalysisError> errors;
+
+  ErrorsResult(
+      this.path, this.uri, this.contentHash, this.lineInfo, this.errors);
+}
+
+/**
  * Exception that happened during analysis.
  */
 class ExceptionResult {
@@ -1391,7 +1506,15 @@
    */
   final CaughtException exception;
 
-  ExceptionResult(this.path, this.exception);
+  /**
+   * If the exception happened during a file analysis, and the context in which
+   * the exception happened was stored, this field is the key of the context
+   * in the byte store. May be `null` if the context is unknown, the maximum
+   * number of context to store was reached, etc.
+   */
+  final String contextKey;
+
+  ExceptionResult(this.path, this.exception, this.contextKey);
 }
 
 /**
@@ -1518,47 +1641,114 @@
 }
 
 /**
- * [ContentCache] wrapper around [FileContentOverlay].
+ * The result with the [CompilationUnitElement] of a single file.
+ *
+ * These results are self-consistent, i.e. all elements and types accessible
+ * through [element], including defined in other files, correspond to each
+ * other. But none of the results is guaranteed to be consistent with the state
+ * of the files.
+ *
+ * Every result is independent, and is not guaranteed to be consistent with
+ * any previously returned result, even inside of the same library.
  */
-class _ContentCacheWrapper implements ContentCache {
-  final FileSystemState fsState;
+class UnitElementResult {
+  /**
+   * The path of the file, absolute and normalized.
+   */
+  final String path;
 
-  _ContentCacheWrapper(this.fsState);
+  /**
+   * The MD5 hash of the file content.
+   */
+  final String contentHash;
+
+  /**
+   * The signature of the [element] based on the content of the file, and the
+   * transitive closure of files imported and exported by the the library of
+   * the requested file.
+   */
+  final String signature;
+
+  /**
+   * The element of the file.
+   */
+  final CompilationUnitElement element;
+
+  UnitElementResult(this.path, this.contentHash, this.signature, this.element);
+}
+
+/**
+ * Information about an exception and its context.
+ */
+class _ExceptionState {
+  final exception;
+  final StackTrace stackTrace;
+
+  /**
+   * The key under which the context of the exception was stored, or `null`
+   * if unknown, the maximum number of context to store was reached, etc.
+   */
+  final String contextKey;
+
+  _ExceptionState(this.exception, this.stackTrace, this.contextKey);
 
   @override
-  void accept(ContentCacheVisitor visitor) {
-    throw new UnimplementedError();
-  }
+  String toString() => '$exception\n$stackTrace';
+}
 
-  @override
-  String getContents(Source source) {
-    return _getFileForSource(source).content;
-  }
+/**
+ * Task that computes the list of files that were added to the driver and
+ * declare a class member with the given [name].
+ */
+class _FilesDefiningClassMemberNameTask {
+  static const int _MS_WORK_INTERVAL = 5;
 
-  @override
-  bool getExists(Source source) {
-    if (source.isInSystemLibrary) {
-      return true;
+  final AnalysisDriver driver;
+  final String name;
+  final Completer<List<String>> completer = new Completer<List<String>>();
+
+  final List<String> definingFiles = <String>[];
+  final Set<String> checkedFiles = new Set<String>();
+  final List<String> filesToCheck = <String>[];
+
+  _FilesDefiningClassMemberNameTask(this.driver, this.name);
+
+  /**
+   * Perform work for a fixed length of time, and complete the [completer] to
+   * either return `true` to indicate that the task is done, or return `false`
+   * to indicate that the task should continue to be run.
+   *
+   * Each invocation of an asynchronous method has overhead, which looks as
+   * `_SyncCompleter.complete` invocation, we see as much as 62% in some
+   * scenarios. Instead we use a fixed length of time, so we can spend less time
+   * overall and keep quick enough response time.
+   */
+  Future<bool> perform() async {
+    Stopwatch timer = new Stopwatch()..start();
+    while (timer.elapsedMilliseconds < _MS_WORK_INTERVAL) {
+      // Prepare files to check.
+      if (filesToCheck.isEmpty) {
+        Set<String> newFiles = driver.addedFiles.difference(checkedFiles);
+        filesToCheck.addAll(newFiles);
+      }
+
+      // If no more files to check, complete and done.
+      if (filesToCheck.isEmpty) {
+        completer.complete(definingFiles);
+        return true;
+      }
+
+      // Check the next file.
+      String path = filesToCheck.removeLast();
+      FileState file = driver._fileTracker.fsState.getFileForPath(path);
+      if (file.definedClassMemberNames.contains(name)) {
+        definingFiles.add(path);
+      }
+      checkedFiles.add(path);
     }
-    return _getFileForSource(source).exists;
-  }
 
-  @override
-  int getModificationStamp(Source source) {
-    if (source.isInSystemLibrary) {
-      return 0;
-    }
-    return _getFileForSource(source).exists ? 0 : -1;
-  }
-
-  @override
-  String setContents(Source source, String contents) {
-    throw new UnimplementedError();
-  }
-
-  FileState _getFileForSource(Source source) {
-    String path = source.fullName;
-    return fsState.getFileForPath(path);
+    // We're not done yet.
+    return false;
   }
 }
 
@@ -1607,7 +1797,7 @@
 
       // Check the next file.
       String path = filesToCheck.removeLast();
-      FileState file = driver._fsState.getFileForPath(path);
+      FileState file = driver._fileTracker.fsState.getFileForPath(path);
       if (file.referencedNames.contains(name)) {
         referencingFiles.add(path);
       }
@@ -1620,15 +1810,6 @@
 }
 
 /**
- * TODO(scheglov) document
- */
-class _LibraryContext {
-  final FileState file;
-  final SummaryDataStore store;
-  _LibraryContext(this.file, this.store);
-}
-
-/**
  * Task that computes top-level declarations for a certain name in all
  * known libraries.
  */
@@ -1666,7 +1847,7 @@
     // Check the next file.
     String path = filesToCheck.removeLast();
     if (checkedFiles.add(path)) {
-      FileState file = driver._fsState.getFileForPath(path);
+      FileState file = driver._fileTracker.fsState.getFileForPath(path);
       if (!file.isPart) {
         bool isExported = false;
         TopLevelDeclaration declaration = file.topLevelDeclarations[name];
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
index 3e18290..fba6fbf 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
@@ -21,49 +21,41 @@
 }
 
 /**
- * [ByteStore] that stores values as files.
+ * [ByteStore] that stores values as files and performs cache eviction.
+ *
+ * Only the process that manages the cache, e.g. Analysis Server, should use
+ * this class. Other processes, e.g. Analysis Server plugins, should use
+ * [FileByteStore] instead and let the main process to perform eviction.
  */
-class FileByteStore implements ByteStore {
+class EvictingFileByteStore implements ByteStore {
   static bool _cleanUpSendPortShouldBePrepared = true;
   static SendPort _cleanUpSendPort;
 
   final String _cachePath;
-  final String _tempName = 'temp_$pid';
   final int _maxSizeBytes;
+  final FileByteStore _fileByteStore;
 
   int _bytesWrittenSinceCleanup = 0;
   bool _evictionIsolateIsRunning = false;
 
-  FileByteStore(this._cachePath, this._maxSizeBytes) {
+  EvictingFileByteStore(this._cachePath, this._maxSizeBytes)
+      : _fileByteStore = new FileByteStore(_cachePath) {
     _requestCacheCleanUp();
   }
 
   @override
   List<int> get(String key) {
-    try {
-      return _getFileForKey(key).readAsBytesSync();
-    } catch (_) {
-      return null;
-    }
+    return _fileByteStore.get(key);
   }
 
   @override
   void put(String key, List<int> bytes) {
-    try {
-      File tempFile = _getFileForKey(_tempName);
-      tempFile.writeAsBytesSync(bytes);
-      File file = _getFileForKey(key);
-      tempFile.renameSync(file.path);
-      // Update the current size.
-      _bytesWrittenSinceCleanup += bytes.length;
-      if (_bytesWrittenSinceCleanup > _maxSizeBytes ~/ 8) {
-        _requestCacheCleanUp();
-      }
-    } catch (_) {}
-  }
-
-  File _getFileForKey(String key) {
-    return new File(join(_cachePath, key));
+    _fileByteStore.put(key, bytes);
+    // Update the current size.
+    _bytesWrittenSinceCleanup += bytes.length;
+    if (_bytesWrittenSinceCleanup > _maxSizeBytes ~/ 8) {
+      _requestCacheCleanUp();
+    }
   }
 
   /**
@@ -144,3 +136,36 @@
     }
   }
 }
+
+/**
+ * [ByteStore] that stores values as files.
+ */
+class FileByteStore implements ByteStore {
+  final String _cachePath;
+  final String _tempName = 'temp_$pid';
+
+  FileByteStore(this._cachePath);
+
+  @override
+  List<int> get(String key) {
+    try {
+      return _getFileForKey(key).readAsBytesSync();
+    } catch (_) {
+      return null;
+    }
+  }
+
+  @override
+  void put(String key, List<int> bytes) {
+    try {
+      File tempFile = _getFileForKey(_tempName);
+      tempFile.writeAsBytesSync(bytes);
+      File file = _getFileForKey(key);
+      tempFile.renameSync(file.path);
+    } catch (_) {}
+  }
+
+  File _getFileForKey(String key) {
+    return new File(join(_cachePath, key));
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index eeb734a..a8c8670 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/defined_names.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/referenced_names.dart';
 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
@@ -25,7 +26,6 @@
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/name_filter.dart';
 import 'package:analyzer/src/summary/summarize_ast.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
 import 'package:meta/meta.dart';
@@ -89,6 +89,8 @@
   String _content;
   String _contentHash;
   LineInfo _lineInfo;
+  Set<String> _definedTopLevelNames;
+  Set<String> _definedClassMemberNames;
   Set<String> _referencedNames;
   UnlinkedUnit _unlinked;
   List<int> _apiSignature;
@@ -123,6 +125,16 @@
   String get contentHash => _contentHash;
 
   /**
+   * The class member names defined by the file.
+   */
+  Set<String> get definedClassMemberNames => _definedClassMemberNames;
+
+  /**
+   * The top-level names defined by the file.
+   */
+  Set<String> get definedTopLevelNames => _definedTopLevelNames;
+
+  /**
    * Return the set of all directly referenced files - imported, exported or
    * parted.
    */
@@ -192,9 +204,10 @@
   List<FileState> get importedFiles => _importedFiles;
 
   /**
-   * Return `true` if the file has a `part of` directive, so is probably a part.
+   * Return `true` if the file does not have a `library` directive, and has a
+   * `part of` directive, so is probably a part.
    */
-  bool get isPart => _unlinked.isPartOf;
+  bool get isPart => _unlinked.libraryNameOffset == 0 && _unlinked.isPartOf;
 
   /**
    * If the file [isPart], return a currently know library the file is a part
@@ -375,7 +388,8 @@
     {
       ApiSignature signature = new ApiSignature();
       signature.addUint32List(_fsState._salt);
-      signature.addBytes(contentBytes);
+      signature.addInt(contentBytes.length);
+      signature.addString(_contentHash);
       unlinkedKey = '${signature.toHex()}.unlinked';
     }
 
@@ -388,8 +402,13 @@
         _fsState._logger.run('Create unlinked for $path', () {
           UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
           List<String> referencedNames = computeReferencedNames(unit).toList();
+          DefinedNames definedNames = computeDefinedNames(unit);
           bytes = new AnalysisDriverUnlinkedUnitBuilder(
-                  unit: unlinkedUnit, referencedNames: referencedNames)
+                  unit: unlinkedUnit,
+                  definedTopLevelNames: definedNames.topLevelNames.toList(),
+                  definedClassMemberNames:
+                      definedNames.classMemberNames.toList(),
+                  referencedNames: referencedNames)
               .toBuffer();
           _fsState._byteStore.put(unlinkedKey, bytes);
         });
@@ -398,13 +417,16 @@
 
     // Read the unlinked bundle.
     var driverUnlinkedUnit = new AnalysisDriverUnlinkedUnit.fromBuffer(bytes);
-    _referencedNames = new Set<String>.from(driverUnlinkedUnit.referencedNames);
+    _definedTopLevelNames = driverUnlinkedUnit.definedTopLevelNames.toSet();
+    _definedClassMemberNames =
+        driverUnlinkedUnit.definedClassMemberNames.toSet();
+    _referencedNames = driverUnlinkedUnit.referencedNames.toSet();
     _unlinked = driverUnlinkedUnit.unit;
     _lineInfo = new LineInfo(_unlinked.lineStarts);
     _topLevelDeclarations = null;
 
     // Prepare API signature.
-    List<int> newApiSignature = _unlinked.apiSignature;
+    List<int> newApiSignature = new Uint8List.fromList(_unlinked.apiSignature);
     bool apiSignatureChanged = _apiSignature != null &&
         !_equalByteLists(_apiSignature, newApiSignature);
     _apiSignature = newApiSignature;
@@ -489,10 +511,16 @@
   String toString() => path;
 
   /**
-   * Return the [FileState] for the given [relativeUri].
+   * Return the [FileState] for the given [relativeUri], or `null` if the URI
+   * cannot be parsed, cannot correspond any file, etc.
    */
   FileState _fileForRelativeUri(String relativeUri) {
-    Uri absoluteUri = resolveRelativeUri(uri, FastUri.parse(relativeUri));
+    Uri absoluteUri;
+    try {
+      absoluteUri = resolveRelativeUri(uri, Uri.parse(relativeUri));
+    } on FormatException {
+      return null;
+    }
     return _fsState.getFileForUri(absoluteUri);
   }
 
@@ -540,6 +568,11 @@
   final Set<String> knownFilePaths = new Set<String>();
 
   /**
+   * Mapping from a path to the flag whether there is a URI for the path.
+   */
+  final Map<String, bool> _hasUriForPath = {};
+
+  /**
    * Mapping from a path to the corresponding [FileState]s, canonical or not.
    */
   final Map<String, List<FileState>> _pathToFiles = {};
@@ -570,8 +603,8 @@
   /**
    * Return the known files.
    */
-  Iterable<FileState> get knownFiles =>
-      _pathToFiles.values.map((files) => files.first);
+  List<FileState> get knownFiles =>
+      _pathToFiles.values.map((files) => files.first).toList();
 
   @visibleForTesting
   FileSystemStateTestView get test => _testView;
@@ -592,7 +625,7 @@
       // Try to get the existing instance.
       file = _uriToFile[uri];
       // If we have a file, call it the canonical one and return it.
-      if (file != null && file.path == path) {
+      if (file != null) {
         _pathToCanonicalFile[path] = file;
         return file;
       }
@@ -648,6 +681,26 @@
   }
 
   /**
+   * Return `true` if there is a URI that can be resolved to the [path].
+   *
+   * When a file exists, but for the URI that corresponds to the file is
+   * resolved to another file, e.g. a generated one in Bazel, Gn, etc, we
+   * cannot analyze the original file.
+   */
+  bool hasUri(String path) {
+    bool flag = _hasUriForPath[path];
+    if (flag == null) {
+      File resource = _resourceProvider.getFile(path);
+      Source fileSource = resource.createSource();
+      Uri uri = _sourceFactory.restoreUri(fileSource);
+      Source uriSource = _sourceFactory.forUri2(uri);
+      flag = uriSource.fullName == path;
+      _hasUriForPath[path] = flag;
+    }
+    return flag;
+  }
+
+  /**
    * Remove the file with the given [path].
    */
   void removeFile(String path) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
new file mode 100644
index 0000000..aa34c33
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
@@ -0,0 +1,201 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:typed_data';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * Callback used by [FileTracker] to report to its client that files have been
+ * added, changed, or removed, and therefore more analysis may be necessary.
+ */
+typedef void FileTrackerChangeHook();
+
+/**
+ * Maintains the file system state needed by the analysis driver, as well as
+ * information about files that have changed and the impact of those changes.
+ *
+ * Three related sets of files are tracked: "added files" is the set of files
+ * for which the client would like analysis.  "changed files" is the set of
+ * files which is known to have changed, but for which we have not yet measured
+ * the impact of the change.  "pending files" is the subset of "added files"
+ * which might have been impacted by a change, and thus need analysis.
+ *
+ * Provides methods for updating the file system state in response to changes.
+ */
+class FileTracker {
+  /**
+   * Callback invoked whenever a change occurs that may require the client to
+   * perform analysis.
+   */
+  final FileTrackerChangeHook _changeHook;
+
+  /**
+   * The logger to write performed operations and performance to.
+   */
+  final PerformanceLog logger;
+
+  /**
+   * The current file system state.
+   */
+  final FileSystemState fsState;
+
+  /**
+   * The set of added files.
+   */
+  final addedFiles = new LinkedHashSet<String>();
+
+  /**
+   * The set of files were reported as changed through [changeFile] and not
+   * checked for actual changes yet.
+   */
+  final _changedFiles = new LinkedHashSet<String>();
+
+  /**
+   * The set of files that are currently scheduled for analysis.
+   */
+  final _pendingFiles = new LinkedHashSet<String>();
+
+  FileTracker(
+      this.logger,
+      ByteStore byteStore,
+      FileContentOverlay contentOverlay,
+      ResourceProvider resourceProvider,
+      SourceFactory sourceFactory,
+      AnalysisOptions analysisOptions,
+      Uint32List salt,
+      this._changeHook)
+      : fsState = new FileSystemState(logger, byteStore, contentOverlay,
+            resourceProvider, sourceFactory, analysisOptions, salt);
+
+  /**
+   * Returns the path to exactly one that needs analysis.  Throws a [StateError]
+   * if no files need analysis.
+   */
+  String get anyPendingFile => _pendingFiles.first;
+
+  /**
+   * Returns a boolean indicating whether there are any files that have changed,
+   * but for which the impact of the changes hasn't been measured.
+   */
+  bool get hasChangedFiles => _changedFiles.isNotEmpty;
+
+  /**
+   * Returns a boolean indicating whether there are any files that need
+   * analysis.
+   */
+  bool get hasPendingFiles => _pendingFiles.isNotEmpty;
+
+  /**
+   * Returns a count of how many files need analysis.
+   */
+  int get numberOfPendingFiles => _pendingFiles.length;
+
+  /**
+   * Adds the given [path] to the set of "added files".
+   */
+  void addFile(String path) {
+    addedFiles.add(path);
+    _pendingFiles.add(path);
+    _changeHook();
+  }
+
+  /**
+   * Adds the given [paths] to the set of "added files".
+   */
+  void addFiles(Iterable<String> paths) {
+    addedFiles.addAll(paths);
+    _pendingFiles.addAll(paths);
+    _changeHook();
+  }
+
+  /**
+   * Adds the given [path] to the set of "changed files".
+   */
+  void changeFile(String path) {
+    _changedFiles.add(path);
+    if (addedFiles.contains(path)) {
+      _pendingFiles.add(path);
+    }
+    _changeHook();
+  }
+
+  /**
+   * Removes the given [path] from the set of "pending files".
+   *
+   * Should be called after the client has analyzed a file.
+   */
+  void fileWasAnalyzed(String path) {
+    _pendingFiles.remove(path);
+  }
+
+  /**
+   * Returns a boolean indicating whether the given [path] points to a file that
+   * requires analysis.
+   */
+  bool isFilePending(String path) => _pendingFiles.contains(path);
+
+  /**
+   * Removes the given [path] from the set of "added files".
+   */
+  void removeFile(String path) {
+    addedFiles.remove(path);
+    _pendingFiles.remove(path);
+    // TODO(paulberry): removing the path from [fsState] and re-analyzing all
+    // files seems extreme.
+    fsState.removeFile(path);
+    _pendingFiles.addAll(addedFiles);
+    _changeHook();
+  }
+
+  /**
+   * Verify the API signature for the file with the given [path], and decide
+   * which linked libraries should be invalidated, and files reanalyzed.
+   */
+  FileState verifyApiSignature(String path) {
+    return logger.run('Verify API signature of $path', () {
+      bool anyApiChanged = false;
+      List<FileState> files = fsState.getFilesForPath(path);
+      for (FileState file in files) {
+        bool apiChanged = file.refresh();
+        if (apiChanged) {
+          anyApiChanged = true;
+        }
+      }
+      if (anyApiChanged) {
+        logger.writeln('API signatures mismatch found for $path');
+        // TODO(scheglov) schedule analysis of only affected files
+        _pendingFiles.addAll(addedFiles);
+      }
+      return files[0];
+    });
+  }
+
+  /**
+   * If at least one file is in the "changed files" set, determines the impact
+   * of the change, updates the set of pending files, and returns `true`.
+   *
+   * If no files are in the "changed files" set, returns `false`.
+   */
+  bool verifyChangedFilesIfNeeded() {
+    // Verify all changed files one at a time.
+    if (_changedFiles.isNotEmpty) {
+      String path = _changedFiles.first;
+      _changedFiles.remove(path);
+      // If the file has not been accessed yet, we either will eventually read
+      // it later while analyzing one of the added files, or don't need it.
+      if (fsState.knownFilePaths.contains(path)) {
+        verifyApiSignature(path);
+      }
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
new file mode 100644
index 0000000..7ac3b30
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -0,0 +1,768 @@
+// 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:analyzer/context/declared_variables.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/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/constant/evaluation.dart';
+import 'package:analyzer/src/dart/constant/utilities.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/error/pending_error.dart';
+import 'package:analyzer/src/generated/declaration_resolver.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:front_end/src/dependency_walker.dart';
+
+/**
+ * Analyzer of a single library.
+ */
+class LibraryAnalyzer {
+  final AnalysisOptions _analysisOptions;
+  final DeclaredVariables _declaredVariables;
+  final SourceFactory _sourceFactory;
+  final FileSystemState _fsState;
+  final SummaryDataStore _store;
+  final FileState _library;
+
+  TypeProvider _typeProvider;
+  AnalysisContextImpl _context;
+  StoreBasedSummaryResynthesizer _resynthesizer;
+  LibraryElement _libraryElement;
+
+  final Map<FileState, LineInfo> _fileToLineInfo = {};
+  final Map<FileState, IgnoreInfo> _fileToIgnoreInfo = {};
+
+  final Map<FileState, RecordingErrorListener> _errorListeners = {};
+  final Map<FileState, ErrorReporter> _errorReporters = {};
+  final List<UsedImportedElements> _usedImportedElementsList = [];
+  final List<UsedLocalElements> _usedLocalElementsList = [];
+  final Map<FileState, List<PendingError>> _fileToPendingErrors = {};
+  final List<ConstantEvaluationTarget> _constants = [];
+
+  LibraryAnalyzer(this._analysisOptions, this._declaredVariables,
+      this._sourceFactory, this._fsState, this._store, this._library);
+
+  /**
+   * Compute analysis results for all units of the library.
+   */
+  Map<FileState, UnitAnalysisResult> analyze() {
+    Map<FileState, CompilationUnit> units = {};
+
+    // Parse all files.
+    units[_library] = _parse(_library);
+    for (FileState part in _library.partedFiles) {
+      units[part] = _parse(part);
+    }
+
+    // Resolve URIs in directives to corresponding sources.
+    units.forEach((file, unit) {
+      _resolveUriBasedDirectives(file, unit);
+    });
+
+    _createAnalysisContext();
+
+    try {
+      _resynthesizer = new StoreBasedSummaryResynthesizer(
+          _context, _sourceFactory, _analysisOptions.strongMode, _store);
+      _typeProvider = _resynthesizer.typeProvider;
+      _context.typeProvider = _typeProvider;
+
+      _libraryElement = _resynthesizer.getLibraryElement(_library.uriStr);
+
+      _resolveDirectives(units);
+
+      units.forEach((file, unit) {
+        _resolveFile(file, unit);
+        _computePendingMissingRequiredParameters(file, unit);
+      });
+
+      _computeConstants();
+
+      units.forEach((file, unit) {
+        _computeVerifyErrors(file, unit);
+      });
+
+      if (_analysisOptions.hint) {
+        units.forEach((file, unit) {
+          {
+            var visitor = new GatherUsedLocalElementsVisitor(_libraryElement);
+            unit.accept(visitor);
+            _usedLocalElementsList.add(visitor.usedElements);
+          }
+          {
+            var visitor =
+                new GatherUsedImportedElementsVisitor(_libraryElement);
+            unit.accept(visitor);
+            _usedImportedElementsList.add(visitor.usedElements);
+          }
+        });
+        units.forEach((file, unit) {
+          _computeHints(file, unit);
+        });
+      }
+
+      if (_analysisOptions.lint) {
+        units.forEach((file, unit) {
+          _computeLints(file, unit);
+        });
+      }
+    } finally {
+      _context.dispose();
+    }
+
+    // Return full results.
+    Map<FileState, UnitAnalysisResult> results = {};
+    units.forEach((file, unit) {
+      List<AnalysisError> errors = _getErrorListener(file).errors;
+      errors = _filterIgnoredErrors(file, errors);
+      results[file] = new UnitAnalysisResult(file, unit, errors);
+    });
+    return results;
+  }
+
+  /**
+   * Compute [_constants] in all units.
+   */
+  void _computeConstants() {
+    ConstantEvaluationEngine evaluationEngine = new ConstantEvaluationEngine(
+        _typeProvider, _declaredVariables,
+        typeSystem: _context.typeSystem);
+
+    List<_ConstantNode> nodes = [];
+    Map<ConstantEvaluationTarget, _ConstantNode> nodeMap = {};
+    for (ConstantEvaluationTarget constant in _constants) {
+      var node = new _ConstantNode(evaluationEngine, nodeMap, constant);
+      nodes.add(node);
+      nodeMap[constant] = node;
+    }
+
+    for (_ConstantNode node in nodes) {
+      if (!node.isEvaluated) {
+        new _ConstantWalker(evaluationEngine).walk(node);
+      }
+    }
+  }
+
+  void _computeHints(FileState file, CompilationUnit unit) {
+    AnalysisErrorListener errorListener = _getErrorListener(file);
+    ErrorReporter errorReporter = _getErrorReporter(file);
+
+    //
+    // Convert the pending errors into actual errors.
+    //
+    for (PendingError pendingError in _fileToPendingErrors[file]) {
+      errorListener.onError(pendingError.toAnalysisError());
+    }
+
+    unit.accept(
+        new DeadCodeVerifier(errorReporter, typeSystem: _context.typeSystem));
+
+    // Dart2js analysis.
+    if (_analysisOptions.dart2jsHint) {
+      unit.accept(new Dart2JSVerifier(errorReporter));
+    }
+
+    InheritanceManager inheritanceManager = new InheritanceManager(
+        _libraryElement,
+        includeAbstractFromSuperclasses: true);
+
+    unit.accept(new BestPracticesVerifier(
+        errorReporter, _typeProvider, _libraryElement, inheritanceManager,
+        typeSystem: _context.typeSystem));
+
+    unit.accept(new OverrideVerifier(errorReporter, inheritanceManager));
+
+    new ToDoFinder(errorReporter).findIn(unit);
+
+    // Verify imports.
+    {
+      ImportsVerifier verifier = new ImportsVerifier();
+      verifier.addImports(unit);
+      _usedImportedElementsList.forEach(verifier.removeUsedElements);
+      verifier.generateDuplicateImportHints(errorReporter);
+      verifier.generateUnusedImportHints(errorReporter);
+      verifier.generateUnusedShownNameHints(errorReporter);
+    }
+
+    // Unused local elements.
+    {
+      UsedLocalElements usedElements =
+          new UsedLocalElements.merge(_usedLocalElementsList);
+      UnusedLocalElementsVerifier visitor =
+          new UnusedLocalElementsVerifier(errorListener, usedElements);
+      unit.element.accept(visitor);
+    }
+  }
+
+  void _computeLints(FileState file, CompilationUnit unit) {
+    ErrorReporter errorReporter = _getErrorReporter(file);
+
+    List<AstVisitor> visitors = <AstVisitor>[];
+    for (Linter linter in _analysisOptions.lintRules) {
+      AstVisitor visitor = linter.getVisitor();
+      if (visitor != null) {
+        linter.reporter = errorReporter;
+        if (_analysisOptions.enableTiming) {
+          visitor = new TimedAstVisitor(visitor, lintRegistry.getTimer(linter));
+        }
+        visitors.add(visitor);
+      }
+    }
+
+    AstVisitor visitor = new ExceptionHandlingDelegatingAstVisitor(
+        visitors, ExceptionHandlingDelegatingAstVisitor.logException);
+
+    unit.accept(visitor);
+  }
+
+  void _computePendingMissingRequiredParameters(
+      FileState file, CompilationUnit unit) {
+    // TODO(scheglov) This can be done without "pending" if we resynthesize.
+    var computer = new RequiredConstantsComputer(file.source);
+    unit.accept(computer);
+    _constants.addAll(computer.requiredConstants);
+    _fileToPendingErrors[file] = computer.pendingErrors;
+  }
+
+  void _computeVerifyErrors(FileState file, CompilationUnit unit) {
+    RecordingErrorListener errorListener = _getErrorListener(file);
+
+    if (_analysisOptions.strongMode) {
+      AnalysisOptionsImpl options = _analysisOptions as AnalysisOptionsImpl;
+      CodeChecker checker = new CodeChecker(
+          _typeProvider,
+          new StrongTypeSystemImpl(_typeProvider,
+              implicitCasts: options.implicitCasts,
+              nonnullableTypes: options.nonnullableTypes),
+          errorListener,
+          options);
+      checker.visitCompilationUnit(unit);
+    }
+
+    ErrorReporter errorReporter = _getErrorReporter(file);
+
+    //
+    // Validate the directives.
+    //
+    _validateUriBasedDirectives(file, unit);
+
+    //
+    // Use the ConstantVerifier to compute errors.
+    //
+    ConstantVerifier constantVerifier = new ConstantVerifier(
+        errorReporter, _libraryElement, _typeProvider, _declaredVariables);
+    unit.accept(constantVerifier);
+
+    //
+    // Use the ErrorVerifier to compute errors.
+    //
+    ErrorVerifier errorVerifier = new ErrorVerifier(
+        errorReporter,
+        _libraryElement,
+        _typeProvider,
+        new InheritanceManager(_libraryElement),
+        _analysisOptions.enableSuperMixins);
+    unit.accept(errorVerifier);
+  }
+
+  void _createAnalysisContext() {
+    AnalysisContextImpl analysisContext =
+        AnalysisEngine.instance.createAnalysisContext();
+    analysisContext.analysisOptions = _analysisOptions;
+    analysisContext.declaredVariables.addAll(_declaredVariables);
+    analysisContext.sourceFactory = _sourceFactory.clone();
+    analysisContext.contentCache = new _ContentCacheWrapper(_fsState);
+    this._context = analysisContext;
+  }
+
+  /**
+   * Return a subset of the given [errors] that are not marked as ignored in
+   * the [file].
+   */
+  List<AnalysisError> _filterIgnoredErrors(
+      FileState file, List<AnalysisError> errors) {
+    if (errors.isEmpty) {
+      return errors;
+    }
+
+    IgnoreInfo ignoreInfo = _fileToIgnoreInfo[file];
+    if (!ignoreInfo.hasIgnores) {
+      return errors;
+    }
+
+    LineInfo lineInfo = _fileToLineInfo[file];
+
+    bool isIgnored(AnalysisError error) {
+      int errorLine = lineInfo.getLocation(error.offset).lineNumber;
+      String errorCode = error.errorCode.name.toLowerCase();
+      // Ignores can be on the line or just preceding the error.
+      return ignoreInfo.ignoredAt(errorCode, errorLine) ||
+          ignoreInfo.ignoredAt(errorCode, errorLine - 1);
+    }
+
+    return errors.where((AnalysisError e) => !isIgnored(e)).toList();
+  }
+
+  RecordingErrorListener _getErrorListener(FileState file) =>
+      _errorListeners.putIfAbsent(file, () => new RecordingErrorListener());
+
+  ErrorReporter _getErrorReporter(FileState file) {
+    return _errorReporters.putIfAbsent(file, () {
+      RecordingErrorListener listener = _getErrorListener(file);
+      return new ErrorReporter(listener, file.source);
+    });
+  }
+
+  /**
+   * Return the name of the library that the given part is declared to be a
+   * part of, or `null` if the part does not contain a part-of directive.
+   */
+  _NameOrSource _getPartLibraryNameOrUri(Source partSource,
+      CompilationUnit partUnit, List<Directive> directivesToResolve) {
+    for (Directive directive in partUnit.directives) {
+      if (directive is PartOfDirective) {
+        directivesToResolve.add(directive);
+        LibraryIdentifier libraryName = directive.libraryName;
+        if (libraryName != null) {
+          return new _NameOrSource(libraryName.name, null);
+        }
+        String uri = directive.uri?.stringValue;
+        if (uri != null) {
+          Source librarySource = _sourceFactory.resolveUri(partSource, uri);
+          if (librarySource != null) {
+            return new _NameOrSource(null, librarySource);
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Return `true` if the given [source] is a library.
+   */
+  bool _isLibrarySource(Source source) {
+    String uriStr = source.uri.toString();
+    return _store.unlinkedMap[uriStr]?.isPartOf == false;
+  }
+
+  /**
+   * Return a new parsed unresolved [CompilationUnit].
+   */
+  CompilationUnit _parse(FileState file) {
+    RecordingErrorListener errorListener = _getErrorListener(file);
+    String content = file.content;
+    CompilationUnit unit = file.parse(errorListener);
+
+    LineInfo lineInfo = unit.lineInfo;
+    _fileToLineInfo[file] = lineInfo;
+    _fileToIgnoreInfo[file] = IgnoreInfo.calculateIgnores(content, lineInfo);
+
+    return unit;
+  }
+
+  void _resolveDirectives(Map<FileState, CompilationUnit> units) {
+    CompilationUnit definingCompilationUnit = units[_library];
+
+    var uriToElement = <Uri, CompilationUnitElement>{};
+    for (CompilationUnitElement partElement in _libraryElement.units) {
+      uriToElement[partElement.source.uri] = partElement;
+    }
+
+    var sourceToUnit = <Source, CompilationUnit>{};
+    units.forEach((file, unit) {
+      Source source = file.source;
+      unit.element = uriToElement[source.uri];
+      sourceToUnit[source] = unit;
+    });
+
+    ErrorReporter libraryErrorReporter = _getErrorReporter(_library);
+    LibraryIdentifier libraryNameNode = null;
+    bool hasPartDirective = false;
+    var seenPartSources = new Set<Source>();
+    var directivesToResolve = <Directive>[];
+    for (Directive directive in definingCompilationUnit.directives) {
+      if (directive is LibraryDirective) {
+        libraryNameNode = directive.name;
+        directivesToResolve.add(directive);
+      } else if (directive is ImportDirective) {
+        for (ImportElement importElement in _libraryElement.imports) {
+          if (importElement.nameOffset == directive.offset) {
+            directive.element = importElement;
+            if (!_isLibrarySource(importElement.importedLibrary.source)) {
+              ErrorCode errorCode = importElement.isDeferred
+                  ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
+                  : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
+              libraryErrorReporter.reportErrorForNode(
+                  errorCode, directive.uri, [directive.uri]);
+            }
+          }
+        }
+      } else if (directive is ExportDirective) {
+        for (ExportElement exportElement in _libraryElement.exports) {
+          if (exportElement.nameOffset == directive.offset) {
+            directive.element = exportElement;
+            if (!_isLibrarySource(exportElement.exportedLibrary.source)) {
+              libraryErrorReporter.reportErrorForNode(
+                  CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
+                  directive.uri,
+                  [directive.uri]);
+            }
+          }
+        }
+      } else if (directive is PartDirective) {
+        hasPartDirective = true;
+        StringLiteral partUri = directive.uri;
+        Source partSource = directive.uriSource;
+        CompilationUnit partUnit = sourceToUnit[partSource];
+        if (partUnit != null) {
+          directive.element = partUnit.element;
+          //
+          // Validate that the part source is unique in the library.
+          //
+          if (!seenPartSources.add(partSource)) {
+            libraryErrorReporter.reportErrorForNode(
+                CompileTimeErrorCode.DUPLICATE_PART, partUri, [partSource.uri]);
+          }
+          //
+          // Validate that the part contains a part-of directive with the same
+          // name as the library.
+          //
+          if (_context.exists(partSource)) {
+            _NameOrSource nameOrSource = _getPartLibraryNameOrUri(
+                partSource, partUnit, directivesToResolve);
+            if (nameOrSource == null) {
+              libraryErrorReporter.reportErrorForNode(
+                  CompileTimeErrorCode.PART_OF_NON_PART,
+                  partUri,
+                  [partUri.toSource()]);
+            } else {
+              String name = nameOrSource.name;
+              if (name != null) {
+                if (libraryNameNode != null && libraryNameNode.name != name) {
+                  libraryErrorReporter.reportErrorForNode(
+                      StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
+                      partUri,
+                      [libraryNameNode.name, name]);
+                }
+              } else {
+                Source source = nameOrSource.source;
+                if (source != _library.source) {
+                  libraryErrorReporter.reportErrorForNode(
+                      StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
+                      partUri,
+                      [_library.uriStr, source.uri]);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (hasPartDirective && libraryNameNode == null) {
+      libraryErrorReporter.reportErrorForOffset(
+          ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART, 0, 0);
+    }
+
+    //
+    // Resolve the relevant directives to the library element.
+    //
+    for (Directive directive in directivesToResolve) {
+      directive.element = _libraryElement;
+    }
+
+    // TODO(scheglov) remove DirectiveResolver class
+  }
+
+  void _resolveFile(FileState file, CompilationUnit unit) {
+    RecordingErrorListener errorListener = _getErrorListener(file);
+
+    CompilationUnitElement unitElement = unit.element;
+    Source source = file.source;
+
+    // TODO(scheglov) Hack: set types for top-level variables
+    // Otherwise TypeResolverVisitor will set declared types, and because we
+    // don't run InferStaticVariableTypeTask, we will stuck with these declared
+    // types. And we don't need to run this task - resynthesized elements have
+    // inferred types.
+    for (var e in unitElement.topLevelVariables) {
+      if (!e.isSynthetic) {
+        e.type;
+      }
+    }
+
+    new DeclarationResolver().resolve(unit, unitElement);
+
+    // TODO(scheglov) remove EnumMemberBuilder class
+
+    new TypeParameterBoundsResolver(
+            _typeProvider, _libraryElement, source, errorListener)
+        .resolveTypeBounds(unit);
+
+    unit.accept(new TypeResolverVisitor(
+        _libraryElement, source, _typeProvider, errorListener));
+
+    LibraryScope libraryScope = new LibraryScope(_libraryElement);
+    unit.accept(new VariableResolverVisitor(
+        _libraryElement, source, _typeProvider, errorListener,
+        nameScope: libraryScope));
+
+    unit.accept(new PartialResolverVisitor(_libraryElement, source,
+        _typeProvider, AnalysisErrorListener.NULL_LISTENER));
+
+    // Nothing for RESOLVED_UNIT8?
+    // Nothing for RESOLVED_UNIT9?
+    // Nothing for RESOLVED_UNIT10?
+
+    unit.accept(new ResolverVisitor(
+        _libraryElement, source, _typeProvider, errorListener));
+
+    //
+    // Find constants to compute.
+    //
+    {
+      ConstantFinder constantFinder = new ConstantFinder();
+      unit.accept(constantFinder);
+      _constants.addAll(constantFinder.constantsToCompute);
+    }
+
+    //
+    // Find constant dependencies to compute.
+    //
+    {
+      var finder = new ConstantExpressionsDependenciesFinder();
+      unit.accept(finder);
+      _constants.addAll(finder.dependencies);
+    }
+  }
+
+  /**
+   * Return the result of resolve the given [uriContent], reporting errors
+   * against the [uriLiteral].
+   */
+  Source _resolveUri(FileState file, bool isImport, StringLiteral uriLiteral,
+      String uriContent) {
+    UriValidationCode code =
+        UriBasedDirectiveImpl.validateUri(isImport, uriLiteral, uriContent);
+    if (code == null) {
+      try {
+        Uri.parse(uriContent);
+      } on FormatException {
+        return null;
+      }
+      return _sourceFactory.resolveUri(file.source, uriContent);
+    } else if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) {
+      return null;
+    } else if (code == UriValidationCode.URI_WITH_INTERPOLATION) {
+      _getErrorReporter(file).reportErrorForNode(
+          CompileTimeErrorCode.URI_WITH_INTERPOLATION, uriLiteral);
+      return null;
+    } else if (code == UriValidationCode.INVALID_URI) {
+      _getErrorReporter(file).reportErrorForNode(
+          CompileTimeErrorCode.INVALID_URI, uriLiteral, [uriContent]);
+      return null;
+    }
+    return null;
+  }
+
+  void _resolveUriBasedDirectives(FileState file, CompilationUnit unit) {
+    for (Directive directive in unit.directives) {
+      if (directive is UriBasedDirective) {
+        StringLiteral uriLiteral = directive.uri;
+        String uriContent = uriLiteral.stringValue?.trim();
+        directive.uriContent = uriContent;
+        Source defaultSource = _resolveUri(
+            file, directive is ImportDirective, uriLiteral, uriContent);
+        directive.uriSource = defaultSource;
+      }
+    }
+  }
+
+  /**
+   * Check the given [directive] to see if the referenced source exists and
+   * report an error if it does not.
+   */
+  void _validateUriBasedDirective(
+      FileState file, UriBasedDirectiveImpl directive) {
+    Source source = directive.uriSource;
+    if (source != null) {
+      if (_context.exists(source)) {
+        return;
+      }
+    } else {
+      // Don't report errors already reported by ParseDartTask.resolveDirective
+      // TODO(scheglov) we don't use this task here
+      if (directive.validate() != null) {
+        return;
+      }
+    }
+    StringLiteral uriLiteral = directive.uri;
+    CompileTimeErrorCode errorCode = CompileTimeErrorCode.URI_DOES_NOT_EXIST;
+    if (_isGenerated(source)) {
+      errorCode = CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED;
+    }
+    _getErrorReporter(file)
+        .reportErrorForNode(errorCode, uriLiteral, [directive.uriContent]);
+  }
+
+  /**
+   * Check each directive in the given [unit] to see if the referenced source
+   * exists and report an error if it does not.
+   */
+  void _validateUriBasedDirectives(FileState file, CompilationUnit unit) {
+    for (Directive directive in unit.directives) {
+      if (directive is UriBasedDirective) {
+        _validateUriBasedDirective(file, directive);
+      }
+    }
+  }
+
+  /**
+   * Return `true` if the given [source] refers to a file that is assumed to be
+   * generated.
+   */
+  static bool _isGenerated(Source source) {
+    if (source == null) {
+      return false;
+    }
+    // TODO(brianwilkerson) Generalize this mechanism.
+    const List<String> suffixes = const <String>[
+      '.g.dart',
+      '.pb.dart',
+      '.pbenum.dart',
+      '.pbserver.dart',
+      '.pbjson.dart',
+      '.template.dart'
+    ];
+    String fullName = source.fullName;
+    for (String suffix in suffixes) {
+      if (fullName.endsWith(suffix)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
+/**
+ * Analysis result for single file.
+ */
+class UnitAnalysisResult {
+  final FileState file;
+  final CompilationUnit unit;
+  final List<AnalysisError> errors;
+
+  UnitAnalysisResult(this.file, this.unit, this.errors);
+}
+
+/**
+ * [Node] that is used to compute constants in dependency order.
+ */
+class _ConstantNode extends Node<_ConstantNode> {
+  final ConstantEvaluationEngine evaluationEngine;
+  final Map<ConstantEvaluationTarget, _ConstantNode> nodeMap;
+  final ConstantEvaluationTarget constant;
+
+  bool isEvaluated = false;
+
+  _ConstantNode(this.evaluationEngine, this.nodeMap, this.constant);
+
+  @override
+  List<_ConstantNode> computeDependencies() {
+    List<ConstantEvaluationTarget> targets = [];
+    evaluationEngine.computeDependencies(constant, targets.add);
+    return targets.map(_getNode).toList();
+  }
+
+  _ConstantNode _getNode(ConstantEvaluationTarget constant) {
+    return nodeMap.putIfAbsent(
+        constant, () => new _ConstantNode(evaluationEngine, nodeMap, constant));
+  }
+}
+
+/**
+ * [DependencyWalker] for computing constants and detecting cycles.
+ */
+class _ConstantWalker extends DependencyWalker<_ConstantNode> {
+  final ConstantEvaluationEngine evaluationEngine;
+
+  _ConstantWalker(this.evaluationEngine);
+
+  @override
+  void evaluate(_ConstantNode node) {
+    evaluationEngine.computeConstantValue(node.constant);
+    node.isEvaluated = true;
+  }
+
+  @override
+  void evaluateScc(List<_ConstantNode> scc) {
+    var constantsInCycle = scc.map((node) => node.constant);
+    for (_ConstantNode node in scc) {
+      evaluationEngine.generateCycleError(constantsInCycle, node.constant);
+      node.isEvaluated = true;
+    }
+  }
+}
+
+/**
+ * [ContentCache] wrapper around [FileContentOverlay].
+ */
+class _ContentCacheWrapper implements ContentCache {
+  final FileSystemState fsState;
+
+  _ContentCacheWrapper(this.fsState);
+
+  @override
+  void accept(ContentCacheVisitor visitor) {
+    throw new UnimplementedError();
+  }
+
+  @override
+  String getContents(Source source) {
+    return _getFileForSource(source).content;
+  }
+
+  @override
+  bool getExists(Source source) {
+    return _getFileForSource(source).exists;
+  }
+
+  @override
+  int getModificationStamp(Source source) {
+    return _getFileForSource(source).exists ? 0 : -1;
+  }
+
+  @override
+  String setContents(Source source, String contents) {
+    throw new UnimplementedError();
+  }
+
+  FileState _getFileForSource(Source source) {
+    String path = source.fullName;
+    return fsState.getFileForPath(path);
+  }
+}
+
+/**
+ * Either the name or the source associated with a part-of directive.
+ */
+class _NameOrSource {
+  final String name;
+  final Source source;
+  _NameOrSource(this.name, this.source);
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
new file mode 100644
index 0000000..f14cde2
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -0,0 +1,237 @@
+// 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:analyzer/context/declared_variables.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement;
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/file_tracker.dart';
+import 'package:analyzer/src/generated/engine.dart'
+    show AnalysisContext, AnalysisEngine, AnalysisOptions;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/link.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/task/dart.dart' show COMPILATION_UNIT_ELEMENT;
+import 'package:analyzer/task/dart.dart' show LibrarySpecificUnit;
+
+/**
+ * Context information necessary to analyze one or more libraries within an
+ * [AnalysisDriver].
+ *
+ * Currently this is implemented as a wrapper around [AnalysisContext].
+ * TODO(paulberry): make a front end API that this can make use of instead.
+ */
+class LibraryContext {
+  final SummaryDataStore store;
+
+  /**
+   * The [AnalysisContext] which is used to do the analysis.
+   */
+  final AnalysisContext _analysisContext;
+
+  /**
+   * Create a [LibraryContext] which is prepared to analyze [targetLibrary].
+   */
+  factory LibraryContext.forSingleLibrary(
+      FileState targetLibrary,
+      PerformanceLog logger,
+      PackageBundle sdkBundle,
+      ByteStore byteStore,
+      AnalysisOptions options,
+      DeclaredVariables declaredVariables,
+      SourceFactory sourceFactory,
+      FileTracker fileTracker) {
+    return logger.run('Create library context', () {
+      Map<String, FileState> libraries = <String, FileState>{};
+      SummaryDataStore store = new SummaryDataStore(const <String>[]);
+
+      if (sdkBundle != null) {
+        store.addBundle(null, sdkBundle);
+      }
+
+      void appendLibraryFiles(FileState library) {
+        if (!libraries.containsKey(library.uriStr)) {
+          // Serve 'dart:' URIs from the SDK bundle.
+          if (sdkBundle != null && library.uri.scheme == 'dart') {
+            return;
+          }
+
+          libraries[library.uriStr] = library;
+
+          // Append the defining unit.
+          store.addUnlinkedUnit(library.uriStr, library.unlinked);
+
+          // Append parts.
+          for (FileState part in library.partedFiles) {
+            store.addUnlinkedUnit(part.uriStr, part.unlinked);
+          }
+
+          // Append referenced libraries.
+          library.importedFiles.forEach(appendLibraryFiles);
+          library.exportedFiles.forEach(appendLibraryFiles);
+        }
+      }
+
+      logger.run('Append library files', () {
+        return appendLibraryFiles(targetLibrary);
+      });
+
+      Set<String> libraryUrisToLink = new Set<String>();
+      logger.run('Load linked bundles', () {
+        for (FileState library in libraries.values) {
+          if (library.exists || library == targetLibrary) {
+            String key = '${library.transitiveSignature}.linked';
+            List<int> bytes = byteStore.get(key);
+            if (bytes != null) {
+              LinkedLibrary linked = new LinkedLibrary.fromBuffer(bytes);
+              store.addLinkedLibrary(library.uriStr, linked);
+            } else {
+              libraryUrisToLink.add(library.uriStr);
+            }
+          }
+        }
+        int numOfLoaded = libraries.length - libraryUrisToLink.length;
+        logger.writeln('Loaded $numOfLoaded linked bundles.');
+      });
+
+      Map<String, LinkedLibraryBuilder> linkedLibraries = {};
+      logger.run('Link bundles', () {
+        linkedLibraries = link(libraryUrisToLink, (String uri) {
+          LinkedLibrary linkedLibrary = store.linkedMap[uri];
+          return linkedLibrary;
+        }, (String uri) {
+          UnlinkedUnit unlinkedUnit = store.unlinkedMap[uri];
+          return unlinkedUnit;
+        }, (_) => null, options.strongMode);
+        logger.writeln('Linked ${linkedLibraries.length} bundles.');
+      });
+
+      linkedLibraries.forEach((uri, linkedBuilder) {
+        FileState library = libraries[uri];
+        String key = '${library.transitiveSignature}.linked';
+        List<int> bytes = linkedBuilder.toBuffer();
+        LinkedLibrary linked = new LinkedLibrary.fromBuffer(bytes);
+        store.addLinkedLibrary(uri, linked);
+        byteStore.put(key, bytes);
+      });
+
+      var analysisContext = _createAnalysisContext(
+          options, declaredVariables, sourceFactory, fileTracker, store);
+
+      return new LibraryContext._(store, analysisContext);
+    });
+  }
+
+  LibraryContext._(this.store, this._analysisContext);
+
+  /**
+   * Computes a [CompilationUnitElement] for the given library/unit pair.
+   */
+  CompilationUnitElement computeUnitElement(
+      Source librarySource, Source unitSource) {
+    return _analysisContext.computeResult(
+        new LibrarySpecificUnit(librarySource, unitSource),
+        COMPILATION_UNIT_ELEMENT);
+  }
+
+  /**
+   * Cleans up any persistent resources used by this [LibraryContext].
+   *
+   * Should be called once the [LibraryContext] is no longer needed.
+   */
+  void dispose() {
+    _analysisContext.dispose();
+  }
+
+  /**
+   * Computes a resolved [CompilationUnit] and a list of [AnalysisError]s for
+   * the given library/unit pair.
+   */
+  ResolutionResult resolveUnit(Source librarySource, Source unitSource) {
+    CompilationUnit resolvedUnit =
+        _analysisContext.resolveCompilationUnit2(unitSource, librarySource);
+    List<AnalysisError> errors = _analysisContext.computeErrors(unitSource);
+    return new ResolutionResult(resolvedUnit, errors);
+  }
+
+  static AnalysisContext _createAnalysisContext(
+      AnalysisOptions _analysisOptions,
+      DeclaredVariables declaredVariables,
+      SourceFactory _sourceFactory,
+      FileTracker fileTracker,
+      SummaryDataStore store) {
+    AnalysisContextImpl analysisContext =
+        AnalysisEngine.instance.createAnalysisContext();
+    analysisContext.useSdkCachePartition = false;
+    analysisContext.analysisOptions = _analysisOptions;
+    analysisContext.declaredVariables.addAll(declaredVariables);
+    analysisContext.sourceFactory = _sourceFactory.clone();
+    analysisContext.contentCache = new _ContentCacheWrapper(fileTracker);
+    analysisContext.resultProvider =
+        new InputPackagesResultProvider(analysisContext, store);
+    return analysisContext;
+  }
+}
+
+/**
+ * Container object holding the result of a call to
+ * [LibraryContext.resolveUnit].
+ */
+class ResolutionResult {
+  final CompilationUnit resolvedUnit;
+  final List<AnalysisError> errors;
+
+  ResolutionResult(this.resolvedUnit, this.errors);
+}
+
+/**
+ * [ContentCache] wrapper around [FileContentOverlay].
+ */
+class _ContentCacheWrapper implements ContentCache {
+  final FileTracker fileTracker;
+
+  _ContentCacheWrapper(this.fileTracker);
+
+  @override
+  void accept(ContentCacheVisitor visitor) {
+    throw new UnimplementedError();
+  }
+
+  @override
+  String getContents(Source source) {
+    return _getFileForSource(source).content;
+  }
+
+  @override
+  bool getExists(Source source) {
+    if (source.isInSystemLibrary) {
+      return true;
+    }
+    return _getFileForSource(source).exists;
+  }
+
+  @override
+  int getModificationStamp(Source source) {
+    if (source.isInSystemLibrary) {
+      return 0;
+    }
+    return _getFileForSource(source).exists ? 0 : -1;
+  }
+
+  @override
+  String setContents(Source source, String contents) {
+    throw new UnimplementedError();
+  }
+
+  FileState _getFileForSource(Source source) {
+    String path = source.fullName;
+    return fileTracker.fsState.getFileForPath(path);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
index 811aa92..1d0ed18 100644
--- a/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
@@ -56,6 +56,13 @@
     return scope;
   }
 
+  factory _LocalNameScope.forConstructor(
+      _LocalNameScope enclosing, ConstructorDeclaration node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    scope.addFormalParameters(node.parameters);
+    return scope;
+  }
+
   factory _LocalNameScope.forFunction(
       _LocalNameScope enclosing, FunctionDeclaration node) {
     _LocalNameScope scope = new _LocalNameScope(enclosing);
@@ -175,6 +182,17 @@
   }
 
   @override
+  visitConstructorDeclaration(ConstructorDeclaration node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forConstructor(localScope, node);
+      super.visitConstructorDeclaration(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
   visitConstructorName(ConstructorName node) {
     if (node.parent is! ConstructorDeclaration) {
       super.visitConstructorName(node);
@@ -235,8 +253,10 @@
     }
     // Prepare name.
     String name = node.name;
-    // Ignore unqualified names shadowed by local elements.
-    if (!node.isQualified) {
+    // Ignore names shadowed by local elements.
+    if (node.isQualified || _isNameExpressionLabel(parent)) {
+      // Cannot be local.
+    } else {
       if (localScope.contains(name)) {
         return;
       }
@@ -247,4 +267,12 @@
     // Do add the name.
     names.add(name);
   }
+
+  static bool _isNameExpressionLabel(AstNode parent) {
+    if (parent is Label) {
+      AstNode parent2 = parent?.parent;
+      return parent2 is NamedExpression && parent2.name == parent;
+    }
+    return false;
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index b733e19..6bb75be 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -34,24 +34,26 @@
   Search(this._driver);
 
   /**
-   * Returns class members with names matching the given [regExp].
+   * Returns class members with the given [name].
    */
-  Future<List<Element>> classMembers(RegExp regExp) async {
+  Future<List<Element>> classMembers(String name) async {
     List<Element> elements = <Element>[];
 
     void addElement(Element element) {
-      if (!element.isSynthetic && regExp.hasMatch(element.displayName)) {
+      if (!element.isSynthetic && element.displayName == name) {
         elements.add(element);
       }
     }
 
-    for (FileState file in _driver.fsState.knownFiles) {
-      CompilationUnitElement unitElement =
-          await _driver.getUnitElement(file.path);
-      for (ClassElement clazz in unitElement.types) {
-        clazz.accessors.forEach(addElement);
-        clazz.fields.forEach(addElement);
-        clazz.methods.forEach(addElement);
+    List<String> files = await _driver.getFilesDefiningClassMemberName(name);
+    for (String file in files) {
+      UnitElementResult unitResult = await _driver.getUnitElement(file);
+      if (unitResult != null) {
+        for (ClassElement clazz in unitResult.element.types) {
+          clazz.accessors.forEach(addElement);
+          clazz.fields.forEach(addElement);
+          clazz.methods.forEach(addElement);
+        }
       }
     }
     return elements;
@@ -130,14 +132,16 @@
     }
 
     for (FileState file in _driver.fsState.knownFiles) {
-      CompilationUnitElement unitElement =
-          await _driver.getUnitElement(file.path);
-      unitElement.accessors.forEach(addElement);
-      unitElement.enums.forEach(addElement);
-      unitElement.functions.forEach(addElement);
-      unitElement.functionTypeAliases.forEach(addElement);
-      unitElement.topLevelVariables.forEach(addElement);
-      unitElement.types.forEach(addElement);
+      UnitElementResult unitResult = await _driver.getUnitElement(file.path);
+      if (unitResult != null) {
+        CompilationUnitElement unitElement = unitResult.element;
+        unitElement.accessors.forEach(addElement);
+        unitElement.enums.forEach(addElement);
+        unitElement.functions.forEach(addElement);
+        unitElement.functionTypeAliases.forEach(addElement);
+        unitElement.topLevelVariables.forEach(addElement);
+        unitElement.types.forEach(addElement);
+      }
     }
     return elements;
   }
@@ -157,17 +161,19 @@
     List<SearchResult> results = [];
     for (String file in files) {
       AnalysisDriverUnitIndex index = await _driver.getIndex(file);
-      _IndexRequest request = new _IndexRequest(index);
-      var fileResults = await request.getUnresolvedMemberReferences(
-          name,
-          const {
-            IndexRelationKind.IS_READ_BY: SearchResultKind.READ,
-            IndexRelationKind.IS_WRITTEN_BY: SearchResultKind.WRITE,
-            IndexRelationKind.IS_READ_WRITTEN_BY: SearchResultKind.READ_WRITE,
-            IndexRelationKind.IS_INVOKED_BY: SearchResultKind.INVOCATION
-          },
-          () => _driver.getUnitElement(file));
-      results.addAll(fileResults);
+      if (index != null) {
+        _IndexRequest request = new _IndexRequest(index);
+        var fileResults = await request.getUnresolvedMemberReferences(
+            name,
+            const {
+              IndexRelationKind.IS_READ_BY: SearchResultKind.READ,
+              IndexRelationKind.IS_WRITTEN_BY: SearchResultKind.WRITE,
+              IndexRelationKind.IS_READ_WRITTEN_BY: SearchResultKind.READ_WRITE,
+              IndexRelationKind.IS_INVOKED_BY: SearchResultKind.INVOCATION
+            },
+            () => _getUnitElement(file));
+        results.addAll(fileResults);
+      }
     }
 
     return results;
@@ -217,15 +223,22 @@
       Map<IndexRelationKind, SearchResultKind> relationToResultKind,
       String file) async {
     AnalysisDriverUnitIndex index = await _driver.getIndex(file);
-    _IndexRequest request = new _IndexRequest(index);
-    int elementId = request.findElementId(element);
-    if (elementId != -1) {
-      List<SearchResult> fileResults = await request.getRelations(
-          elementId, relationToResultKind, () => _driver.getUnitElement(file));
-      results.addAll(fileResults);
+    if (index != null) {
+      _IndexRequest request = new _IndexRequest(index);
+      int elementId = request.findElementId(element);
+      if (elementId != -1) {
+        List<SearchResult> fileResults = await request.getRelations(
+            elementId, relationToResultKind, () => _getUnitElement(file));
+        results.addAll(fileResults);
+      }
     }
   }
 
+  Future<CompilationUnitElement> _getUnitElement(String file) async {
+    UnitElementResult result = await _driver.getUnitElement(file);
+    return result?.element;
+  }
+
   Future<List<SearchResult>> _searchReferences(Element element) async {
     List<SearchResult> results = <SearchResult>[];
     await _addResults(results, element,
@@ -689,15 +702,17 @@
       if (resultKind != null) {
         int offset = index.usedElementOffsets[i];
         enclosingUnitElement ??= await getEnclosingUnitElement();
-        Element enclosingElement =
-            _getEnclosingElement(enclosingUnitElement, offset);
-        results.add(new SearchResult._(
-            enclosingElement,
-            resultKind,
-            offset,
-            index.usedElementLengths[i],
-            true,
-            index.usedElementIsQualifiedFlags[i]));
+        if (enclosingUnitElement != null) {
+          Element enclosingElement =
+              _getEnclosingElement(enclosingUnitElement, offset);
+          results.add(new SearchResult._(
+              enclosingElement,
+              resultKind,
+              offset,
+              index.usedElementLengths[i],
+              true,
+              index.usedElementIsQualifiedFlags[i]));
+        }
       }
     }
     return results;
@@ -763,10 +778,12 @@
       if (resultKind != null) {
         int offset = index.usedNameOffsets[i];
         enclosingUnitElement ??= await getEnclosingUnitElement();
-        Element enclosingElement =
-            _getEnclosingElement(enclosingUnitElement, offset);
-        results.add(new SearchResult._(enclosingElement, resultKind, offset,
-            name.length, false, index.usedNameIsQualifiedFlags[i]));
+        if (enclosingUnitElement != null) {
+          Element enclosingElement =
+              _getEnclosingElement(enclosingUnitElement, offset);
+          results.add(new SearchResult._(enclosingElement, resultKind, offset,
+              name.length, false, index.usedNameIsQualifiedFlags[i]));
+        }
       }
     }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/status.dart b/pkg/analyzer/lib/src/dart/analysis/status.dart
index e70de68..5759b5e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/status.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/status.dart
@@ -16,12 +16,12 @@
   const AnalysisStatus._(this._analyzing);
 
   /**
-   * Return `true` is the driver is analyzing.
+   * Return `true` if the scheduler is analyzing.
    */
   bool get isAnalyzing => _analyzing;
 
   /**
-   * Return `true` is the driver is idle.
+   * Return `true` if the scheduler is idle.
    */
   bool get isIdle => !_analyzing;
 
@@ -89,25 +89,37 @@
   Stream<AnalysisStatus> get stream => _statusController.stream;
 
   /**
-   * Send a notifications to the [stream] that the driver started analyzing.
+   * Prepare for the scheduler to start analyzing, but do not notify the
+   * [stream] yet.
+   *
+   * A call to [preTransitionToAnalyzing] has the same effect on [waitForIdle]
+   * as a call to [transitionToAnalyzing], but it has no effect on the [stream].
+   */
+  void preTransitionToAnalyzing() {
+    _idleCompleter ??= new Completer<Null>();
+  }
+
+  /**
+   * Send a notification to the [stream] that the scheduler started analyzing.
    */
   void transitionToAnalyzing() {
     if (_currentStatus != AnalysisStatus.ANALYZING) {
+      preTransitionToAnalyzing();
       _currentStatus = AnalysisStatus.ANALYZING;
       _statusController.add(AnalysisStatus.ANALYZING);
     }
   }
 
   /**
-   * Send a notifications to the [stream] stream that the driver is idle.
+   * Send a notification to the [stream] stream that the scheduler is idle.
    */
   void transitionToIdle() {
     if (_currentStatus != AnalysisStatus.IDLE) {
       _currentStatus = AnalysisStatus.IDLE;
       _statusController.add(AnalysisStatus.IDLE);
-      _idleCompleter?.complete();
-      _idleCompleter = null;
     }
+    _idleCompleter?.complete();
+    _idleCompleter = null;
   }
 
   /**
@@ -117,11 +129,6 @@
    * immediately.
    */
   Future<Null> waitForIdle() {
-    if (_currentStatus == AnalysisStatus.IDLE) {
-      return new Future.value();
-    } else {
-      _idleCompleter ??= new Completer<Null>();
-      return _idleCompleter.future;
-    }
+    return _idleCompleter?.future ?? new Future.value();
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 8722aa4..d1c684b 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -5700,6 +5700,9 @@
    */
   FormalParameterList _parameters;
 
+  @override
+  DartType type;
+
   /**
    * Initialize a newly created generic function type.
    */
@@ -5743,9 +5746,6 @@
     _returnType = _becomeParentOf(type as AstNodeImpl);
   }
 
-  @override
-  DartType get type => null;
-
   /**
    * Return the type parameters for the function type, or `null` if the function
    * type does not have any type parameters.
diff --git a/pkg/analyzer/lib/src/dart/element/ast_provider.dart b/pkg/analyzer/lib/src/dart/element/ast_provider.dart
new file mode 100644
index 0000000..312a057
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/element/ast_provider.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+
+/**
+ * Provider for resolved and unresolved [CompilationUnit]s that contain, or
+ * [AstNode]s that declare [Element]s.
+ */
+abstract class AstProvider {
+  /**
+   * Completes with the [SimpleIdentifier] that declares the [element]. The
+   * enclosing unit is only parsed, but not resolved. Completes with `null` if
+   * the [element] is synthetic, or the file where it is declared cannot be
+   * parsed, etc.
+   */
+  Future<SimpleIdentifier> getParsedNameForElement(Element element);
+
+  /**
+   * Completes with the parsed [CompilationUnit] that contains the [element].
+   */
+  Future<CompilationUnit> getParsedUnitForElement(Element element);
+
+  /**
+   * Completes with the [SimpleIdentifier] that declares the [element]. The
+   * enclosing unit is fully resolved. Completes with `null` if the [element]
+   * is synthetic, or the file where it is declared cannot be parsed and
+   * resolved, etc.
+   */
+  Future<SimpleIdentifier> getResolvedNameForElement(Element element);
+
+  /**
+   * Completes with the resolved [CompilationUnit] that contains the [element].
+   */
+  Future<CompilationUnit> getResolvedUnitForElement(Element element);
+}
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 17f98e9..3524404 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -156,6 +156,7 @@
     element.localVariables = holder.localVariables;
     element.parameters = holder.parameters;
     element.isConst = node.constKeyword != null;
+    element.isCycleFree = element.isConst;
     if (body.isAsynchronous) {
       element.asynchronous = true;
     }
@@ -230,18 +231,14 @@
   Object visitFieldFormalParameter(FieldFormalParameter node) {
     if (node.parent is! DefaultFormalParameter) {
       SimpleIdentifier parameterName = node.identifier;
-      FieldElement field =
-          _fieldMap == null ? null : _fieldMap[parameterName.name];
       FieldFormalParameterElementImpl parameter =
           new FieldFormalParameterElementImpl.forNode(parameterName);
       _setCodeRange(parameter, node);
+      _setFieldParameterField(node, parameter);
       parameter.isConst = node.isConst;
       parameter.isExplicitlyCovariant = node.covariantKeyword != null;
       parameter.isFinal = node.isFinal;
       parameter.parameterKind = node.kind;
-      if (field != null) {
-        parameter.field = field;
-      }
       _currentHolder.addParameter(parameter);
       parameterName.staticElement = parameter;
     }
@@ -733,10 +730,13 @@
   }
 
   @override
-  void _setFieldParameterField(FieldFormalParameterElementImpl parameter) {
-    FieldElement field = _fieldMap == null ? null : _fieldMap[parameter.name];
-    if (field != null) {
-      parameter.field = field;
+  void _setFieldParameterField(
+      FormalParameter node, FieldFormalParameterElementImpl element) {
+    if (node.parent?.parent is ConstructorDeclaration) {
+      FieldElement field = _fieldMap == null ? null : _fieldMap[element.name];
+      if (field != null) {
+        element.field = field;
+      }
     }
   }
 }
@@ -1388,7 +1388,7 @@
     if (normalParameter is FieldFormalParameter) {
       DefaultFieldFormalParameterElementImpl fieldParameter =
           new DefaultFieldFormalParameterElementImpl.forNode(parameterName);
-      _setFieldParameterField(fieldParameter);
+      _setFieldParameterField(node, fieldParameter);
       parameter = fieldParameter;
     } else {
       parameter = new DefaultParameterElementImpl.forNode(parameterName);
@@ -1515,7 +1515,8 @@
     element.setCodeRange(node.offset, node.length);
   }
 
-  void _setFieldParameterField(FieldFormalParameterElementImpl parameter) {}
+  void _setFieldParameterField(
+      FormalParameter node, FieldFormalParameterElementImpl element) {}
 
   /**
    * Sets the visible source range for formal parameter.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index ac89153..ecd8ec6 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -730,7 +730,7 @@
       ResynthesizerContext context = enclosingUnit.resynthesizerContext;
       _interfaces = _unlinkedClass.interfaces
           .map((EntityRef t) => context.resolveTypeRef(t, this))
-          .where((DartType type) => type is InterfaceType)
+          .where(_isClassInterfaceType)
           .toList(growable: false);
     }
     return _interfaces ?? const <InterfaceType>[];
@@ -837,7 +837,7 @@
       ResynthesizerContext context = enclosingUnit.resynthesizerContext;
       _mixins = _unlinkedClass.mixins
           .map((EntityRef t) => context.resolveTypeRef(t, this))
-          .where((DartType type) => type is InterfaceType)
+          .where(_isClassInterfaceType)
           .toList(growable: false);
     }
     return _mixins ?? const <InterfaceType>[];
@@ -871,7 +871,7 @@
       if (_unlinkedClass.supertype != null) {
         DartType type = enclosingUnit.resynthesizerContext
             .resolveTypeRef(_unlinkedClass.supertype, this);
-        if (type is InterfaceType) {
+        if (_isClassInterfaceType(type)) {
           _supertype = type;
         } else {
           _supertype = context.typeProvider.objectType;
@@ -1208,16 +1208,6 @@
         PropertyAccessorElementImpl accessor =
             new PropertyAccessorElementImpl.forSerialized(e, this);
         explicitAccessors.add(accessor);
-        // Prepare the field type.
-        DartType fieldType;
-        if (e.kind == UnlinkedExecutableKind.getter) {
-          fieldType = accessor.returnType;
-        } else {
-          List<ParameterElement> parameters = accessor.parameters;
-          fieldType = parameters.isNotEmpty
-              ? parameters[0].type
-              : DynamicTypeImpl.instance;
-        }
         // Create or update the implicit field.
         String fieldName = accessor.displayName;
         FieldElementImpl field = implicitFields[fieldName];
@@ -1227,7 +1217,6 @@
           field.enclosingElement = this;
           field.isSynthetic = true;
           field.isFinal = e.kind == UnlinkedExecutableKind.getter;
-          field.type = fieldType;
           field.isStatic = e.isStatic;
         } else {
           field.isFinal = false;
@@ -1275,6 +1264,13 @@
     }
     return false;
   }
+
+  /**
+   * Return `true` if the given [type] is a class [InterfaceType].
+   */
+  static bool _isClassInterfaceType(DartType type) {
+    return type is InterfaceType && !type.element.isEnum;
+  }
 }
 
 /**
@@ -3875,7 +3871,8 @@
           serializedExecutable.inferredReturnTypeSlot, typeParameterContext);
       _declaredReturnType = enclosingUnit.resynthesizerContext.resolveTypeRef(
           serializedExecutable.returnType, typeParameterContext,
-          defaultVoid: isSetter && context.analysisOptions.strongMode);
+          defaultVoid: isSetter && context.analysisOptions.strongMode,
+          declaredType: true);
     }
     return _returnType ?? _declaredReturnType;
   }
@@ -4317,13 +4314,14 @@
   @override
   FieldElement get field {
     if (_unlinkedParam != null && _field == null) {
-      Element enclosing = enclosingElement?.enclosingElement;
-      while (enclosing != null) {
-        if (enclosing is ClassElement) {
-          _field = enclosing.getField(_unlinkedParam.name);
-          break;
-        } else {
-          enclosing = enclosing.enclosingElement;
+      Element enclosingConstructor = enclosingElement;
+      if (enclosingConstructor is ConstructorElement) {
+        Element enclosingClass = enclosingConstructor.enclosingElement;
+        if (enclosingClass is ClassElement) {
+          FieldElement field = enclosingClass.getField(_unlinkedParam.name);
+          if (field != null && !field.isSynthetic) {
+            _field = field;
+          }
         }
       }
     }
@@ -4747,8 +4745,9 @@
   @override
   DartType get returnType {
     if (_unlinkedTypedef != null && _returnType == null) {
-      _returnType = enclosingUnit.resynthesizerContext
-          .resolveTypeRef(_unlinkedTypedef.returnType, this);
+      _returnType = enclosingUnit.resynthesizerContext.resolveTypeRef(
+          _unlinkedTypedef.returnType, this,
+          declaredType: true);
     }
     return _returnType;
   }
@@ -6894,12 +6893,14 @@
     if (_unlinkedVariable != null && _declaredType == null && _type == null) {
       _type = enclosingUnit.resynthesizerContext.resolveLinkedType(
           _unlinkedVariable.inferredTypeSlot, typeParameterContext);
-      _declaredType = enclosingUnit.resynthesizerContext
-          .resolveTypeRef(_unlinkedVariable.type, typeParameterContext);
+      _declaredType = enclosingUnit.resynthesizerContext.resolveTypeRef(
+          _unlinkedVariable.type, typeParameterContext,
+          declaredType: true);
     }
     return super.type;
   }
 
+  @override
   void set type(DartType type) {
     _assertNotResynthesized(_unlinkedVariable);
     _type = type;
@@ -7382,8 +7383,9 @@
       } else {
         _type = enclosingUnit.resynthesizerContext.resolveLinkedType(
             _unlinkedParam.inferredTypeSlot, typeParameterContext);
-        _declaredType = enclosingUnit.resynthesizerContext
-            .resolveTypeRef(_unlinkedParam.type, typeParameterContext);
+        _declaredType = enclosingUnit.resynthesizerContext.resolveTypeRef(
+            _unlinkedParam.type, typeParameterContext,
+            declaredType: true);
       }
     }
   }
@@ -7880,6 +7882,23 @@
     _assertNotResynthesized(_unlinkedVariable);
     _propagatedType = propagatedType;
   }
+
+  @override
+  DartType get type {
+    if (isSynthetic && _type == null) {
+      if (getter != null) {
+        _type = getter.returnType;
+      } else if (setter != null) {
+        List<ParameterElement> parameters = setter.parameters;
+        _type = parameters.isNotEmpty
+            ? parameters[0].type
+            : DynamicTypeImpl.instance;
+      } else {
+        _type = DynamicTypeImpl.instance;
+      }
+    }
+    return super.type;
+  }
 }
 
 /**
@@ -7941,7 +7960,9 @@
    */
   DartType resolveTypeRef(
       EntityRef type, TypeParameterizedElementMixin typeParameterContext,
-      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true});
+      {bool defaultVoid: false,
+      bool instantiateToBoundsAllowed: true,
+      bool declaredType: false});
 }
 
 /**
@@ -8141,7 +8162,7 @@
       }
       return _bound ??= enclosingUnit.resynthesizerContext.resolveTypeRef(
           _unlinkedTypeParam.bound, enclosingElement,
-          instantiateToBoundsAllowed: false);
+          instantiateToBoundsAllowed: false, declaredType: true);
     }
     return _bound;
   }
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index b950803..fb855cb 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -137,9 +137,19 @@
       TypeParameterElement.EMPTY_LIST;
 
   @override
+  List<TypeParameterElement> get _explicitTypeParameters =>
+      TypeParameterElement.EMPTY_LIST;
+
+  @override
   bool get _isInstantiated => false;
 
   @override
+  List<ParameterElement> get _parameters => ParameterElement.EMPTY_LIST;
+
+  @override
+  DartType get _returnType => DynamicTypeImpl.instance;
+
+  @override
   List<DartType> get _typeArguments => DartType.EMPTY_LIST;
 
   @override
@@ -247,7 +257,8 @@
 
   DeferredFunctionTypeImpl(this._computeElement, String name,
       List<DartType> typeArguments, bool isInstantiated)
-      : super._(null, name, null, typeArguments, isInstantiated);
+      : super._(
+            null, name, null, typeArguments, null, null, null, isInstantiated);
 
   @override
   FunctionTypedElement get element {
@@ -340,6 +351,24 @@
   List<TypeParameterElement> _typeParameters;
 
   /**
+   * The list of [typeParameters], if there is no element from which they can be
+   * computed, or `null` if they should be computed when necessary.
+   */
+  final List<TypeParameterElement> _explicitTypeParameters;
+
+  /**
+   * The return type of the function, or `null` if the return type should be
+   * accessed through the element.
+   */
+  final DartType _returnType;
+
+  /**
+   * The parameters to the function, or `null` if the parameters should be
+   * accessed through the element.
+   */
+  final List<ParameterElement> _parameters;
+
+  /**
    * True if this type is the result of instantiating type parameters (and thus
    * any type parameters bound by the typedef should be considered part of
    * [typeParameters] rather than [typeFormals]).
@@ -359,7 +388,7 @@
    */
   FunctionTypeImpl(ExecutableElement element,
       [List<FunctionTypeAliasElement> prunedTypedefs])
-      : this._(element, null, prunedTypedefs, null, false);
+      : this._(element, null, prunedTypedefs, null, null, null, null, false);
 
   /**
    * Initialize a newly created function type to be declared by the given
@@ -367,7 +396,21 @@
    */
   FunctionTypeImpl.elementWithNameAndArgs(Element element, String name,
       List<DartType> typeArguments, bool isInstantiated)
-      : this._(element, name, null, typeArguments, isInstantiated);
+      : this._(element, name, null, typeArguments, null, null, null,
+            isInstantiated);
+
+  /**
+   * Initialize a newly created function type to represent a type described by
+   * a generic function type.
+   */
+  FunctionTypeImpl.forGenericFunctionType(
+      List<TypeParameterElement> typeParameters,
+      List<DartType> typeArguments,
+      DartType returnType,
+      List<ParameterElement> parameters,
+      bool isInstantiated)
+      : this._(null, null, null, typeArguments, typeParameters, returnType,
+            parameters, isInstantiated);
 
   /**
    * Initialize a newly created function type to be declared by the given
@@ -375,24 +418,34 @@
    */
   FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element,
       [List<FunctionTypeAliasElement> prunedTypedefs])
-      : this._(element, element?.name, prunedTypedefs, null, false);
+      : this._(element, element?.name, prunedTypedefs, null, null, null, null,
+            false);
 
   /**
    * Private constructor.
    */
-  FunctionTypeImpl._(TypeParameterizedElement element, String name,
-      this.prunedTypedefs, this._typeArguments, this._isInstantiated)
-      : super(element, name);
+  FunctionTypeImpl._(
+      TypeParameterizedElement element,
+      String name,
+      this.prunedTypedefs,
+      this._typeArguments,
+      this._explicitTypeParameters,
+      this._returnType,
+      this._parameters,
+      this._isInstantiated)
+      : _typeParameters = _explicitTypeParameters,
+        super(element, name);
 
   /**
    * Return the base parameter elements of this function element.
    */
-  List<ParameterElement> get baseParameters => element.parameters;
+  List<ParameterElement> get baseParameters =>
+      _parameters ?? element.parameters;
 
   /**
    * Return the return type defined by this function's element.
    */
-  DartType get baseReturnType => element.returnType;
+  DartType get baseReturnType => _returnType ?? element.returnType;
 
   @deprecated
   @override
@@ -801,8 +854,8 @@
     newTypeArgs.addAll(typeArguments);
     newTypeArgs.addAll(argumentTypes);
 
-    return new FunctionTypeImpl._(
-        element, name, prunedTypedefs, newTypeArgs, true);
+    return new FunctionTypeImpl._(element, name, prunedTypedefs, newTypeArgs,
+        _explicitTypeParameters, _returnType, _parameters, true);
   }
 
   @override
@@ -851,8 +904,8 @@
       List<DartType> typeArgs = typeArguments
           .map((DartType t) => (t as TypeImpl).pruned(prune))
           .toList(growable: false);
-      return new FunctionTypeImpl._(
-          element, name, prune, typeArgs, _isInstantiated);
+      return new FunctionTypeImpl._(element, name, prune, typeArgs,
+          _explicitTypeParameters, _returnType, _parameters, _isInstantiated);
     }
   }
 
@@ -878,8 +931,8 @@
     }
     List<DartType> typeArgs =
         TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes);
-    return new FunctionTypeImpl._(
-        element, name, prune, typeArgs, _isInstantiated);
+    return new FunctionTypeImpl._(element, name, prune, typeArgs,
+        _explicitTypeParameters, _returnType, _parameters, _isInstantiated);
   }
 
   @override
@@ -959,6 +1012,8 @@
    * and return TArgs.
    *
    * This function must be called with type [f] that was instantiated from [g].
+   *
+   * If [g] is not generic, returns an empty list.
    */
   static Iterable<DartType> recoverTypeArguments(
       FunctionType g, FunctionType f) {
@@ -968,7 +1023,11 @@
     //
     // For now though, this is a pretty quick operation.
     assert(identical(g.element, f.element));
-    assert(g.typeFormals.isNotEmpty && f.typeFormals.isEmpty);
+    if (g.typeFormals.isEmpty) {
+      assert(g == f);
+      return DartType.EMPTY_LIST;
+    }
+    assert(f.typeFormals.isEmpty);
     assert(g.typeFormals.length + g.typeArguments.length ==
         f.typeArguments.length);
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index dcbcb04..8ceb0bc 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -859,15 +859,14 @@
   }
 
   HashMap<String, Element> _getExportMapping(LibraryElement library) {
+    if (library.exportNamespace != null) {
+      return library.exportNamespace.definedNames;
+    }
     if (library is LibraryElementImpl) {
-      if (library.exportNamespace != null) {
-        return library.exportNamespace.definedNames;
-      } else {
-        HashMap<String, Element> exportMapping =
-            _computeExportMapping(library, new HashSet<LibraryElement>());
-        library.exportNamespace = new Namespace(exportMapping);
-        return exportMapping;
-      }
+      HashMap<String, Element> exportMapping =
+          _computeExportMapping(library, new HashSet<LibraryElement>());
+      library.exportNamespace = new Namespace(exportMapping);
+      return exportMapping;
     }
     return _computeExportMapping(library, new HashSet<LibraryElement>());
   }
diff --git a/pkg/analyzer/lib/src/dart/sdk/patch.dart b/pkg/analyzer/lib/src/dart/sdk/patch.dart
index 44f6765..ee0caa2 100644
--- a/pkg/analyzer/lib/src/dart/sdk/patch.dart
+++ b/pkg/analyzer/lib/src/dart/sdk/patch.dart
@@ -51,7 +51,7 @@
       _allowNewPublicNames = libraryName == '_internal';
     }
     // Prepare the patch files to apply.
-    List<String> patchPaths = allPatchPaths[libraryUriStr];
+    List<String> patchPaths = allPatchPaths[libraryUriStr] ?? const <String> [];
 
     for (String path in patchPaths) {
       File patchFile = resourceProvider.getFile(path);
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 9b4b73d..8171fa6 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -1048,6 +1048,22 @@
           "Try using a normal parameter.");
 
   /**
+   * Temporary error to work around dartbug.com/28515.
+   *
+   * We cannot yet properly summarize function-typed parameters with generic
+   * arguments, so to prevent confusion, we produce an error for any such
+   * constructs (regardless of whether summaries are in use).
+   *
+   * TODO(paulberry): remove this once dartbug.com/28515 is fixed.
+   */
+  static const GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED =
+      const CompileTimeErrorCode(
+          'GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED',
+          "Analysis of generic function typed parameters is not yet supported.",
+          "Try using an explicit typedef, or changing type parameters to "
+          "`dynamic`.");
+
+  /**
    * 7.2 Getters: It is a compile-time error if a class has both a getter and a
    * method with the same name.
    *
@@ -4542,7 +4558,7 @@
   static const StaticWarningCode UNDEFINED_IDENTIFIER_AWAIT =
       const StaticWarningCode(
           'UNDEFINED_IDENTIFIER_AWAIT',
-          "Undefined name 'await'.",
+          "Undefined name 'await' in function body not marked with 'async'.",
           "Try correcting the name to one that is defined, "
           "defining the name, or "
           "adding 'async' to the enclosing function body.");
diff --git a/pkg/analyzer/lib/src/generated/bazel.dart b/pkg/analyzer/lib/src/generated/bazel.dart
index 8d014c7..ae3c3ec 100644
--- a/pkg/analyzer/lib/src/generated/bazel.dart
+++ b/pkg/analyzer/lib/src/generated/bazel.dart
@@ -8,9 +8,10 @@
 import 'dart:core';
 
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
+import 'package:analyzer/src/generated/workspace.dart';
 import 'package:path/path.dart';
 
 /**
@@ -103,7 +104,7 @@
               components[3] == 'lib') {
             String packageName = components[2];
             String pathInLib = components.skip(4).join('/');
-            return FastUri.parse('package:$packageName/$pathInLib');
+            return Uri.parse('package:$packageName/$pathInLib');
           }
         } else {
           for (int i = 2; i < components.length - 1; i++) {
@@ -111,7 +112,7 @@
             if (component == 'lib') {
               String packageName = components.getRange(0, i).join('.');
               String pathInLib = components.skip(i + 1).join('/');
-              return FastUri.parse('package:$packageName/$pathInLib');
+              return Uri.parse('package:$packageName/$pathInLib');
             }
           }
         }
@@ -139,7 +140,7 @@
 /**
  * Information about a Bazel workspace.
  */
-class BazelWorkspace {
+class BazelWorkspace extends Workspace {
   static const String _WORKSPACE = 'WORKSPACE';
   static const String _READONLY = 'READONLY';
 
@@ -178,6 +179,23 @@
   BazelWorkspace._(
       this.provider, this.root, this.readonly, this.bin, this.genfiles);
 
+  @override
+  Map<String, List<Folder>> get packageMap => null;
+
+  @override
+  UriResolver get packageUriResolver => new BazelPackageUriResolver(this);
+
+  @override
+  SourceFactory createSourceFactory(DartSdk sdk) {
+    List<UriResolver> resolvers = <UriResolver>[];
+    if (sdk != null) {
+      resolvers.add(new DartUriResolver(sdk));
+    }
+    resolvers.add(packageUriResolver);
+    resolvers.add(new BazelFileUriResolver(this));
+    return new SourceFactory(resolvers, null, provider);
+  }
+
   /**
    * Return the file with the given [absolutePath], looking first into
    * directories for generated files: `bazel-bin` and `bazel-genfiles`, and
diff --git a/pkg/analyzer/lib/src/generated/declaration_resolver.dart b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
index 90f3483..f87f5f6 100644
--- a/pkg/analyzer/lib/src/generated/declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/exception/exception.dart';
 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/generated/resolver.dart';
 
 /**
@@ -339,8 +340,17 @@
   @override
   Object visitPartDirective(PartDirective node) {
     super.visitPartDirective(node);
-    _resolveAnnotations(
-        node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
+    List<ElementAnnotation> annotations =
+        _enclosingUnit.getAnnotations(node.offset);
+    if (annotations.isEmpty && node.metadata.isNotEmpty) {
+      int index = (node.parent as CompilationUnit)
+          .directives
+          .where((directive) => directive is PartDirective)
+          .toList()
+          .indexOf(node);
+      annotations = _walker.element.library.parts[index].metadata;
+    }
+    _resolveAnnotations(node, node.metadata, annotations);
     return null;
   }
 
@@ -386,6 +396,14 @@
 
   @override
   Object visitTypeParameter(TypeParameter node) {
+    if (node.parent.parent is FunctionTypedFormalParameter) {
+      // Work around dartbug.com/28515.
+      // TODO(paulberry): remove this once dartbug.com/28515 is fixed.
+      var element = new TypeParameterElementImpl.forNode(node.name);
+      element.type = new TypeParameterTypeImpl(element);
+      node.name?.staticElement = element;
+      return null;
+    }
     Element element = _match(node.name, _walker.getTypeParameter());
     super.visitTypeParameter(node);
     _resolveMetadata(node, node.metadata, element);
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 800b6e3..c4ebab6 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -857,6 +857,14 @@
               [node.identifier]);
         }
       }
+
+      // TODO(paulberry): remove this once dartbug.com/28515 is fixed.
+      if (node.typeParameters != null) {
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED,
+            node);
+      }
+
       return super.visitFunctionTypedFormalParameter(node);
     } finally {
       _isInFunctionTypedFormalParameter = old;
@@ -2574,6 +2582,39 @@
   }
 
   /**
+   * Verifies that the class is not named `Function` and that it doesn't
+   * extends/implements/mixes in `Function`.
+   */
+  void _checkForBadFunctionUse(ClassDeclaration node) {
+    ExtendsClause extendsClause = node.extendsClause;
+    WithClause withClause = node.withClause;
+
+    if (node.name.name == "Function") {
+      _errorReporter.reportErrorForNode(
+          HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION, node.name);
+    }
+
+    if (extendsClause != null) {
+      InterfaceType superclassType = _enclosingClass.supertype;
+      ClassElement superclassElement = superclassType?.element;
+      if (superclassElement != null && superclassElement.name == "Function") {
+        _errorReporter.reportErrorForNode(
+            HintCode.DEPRECATED_EXTENDS_FUNCTION, extendsClause.superclass);
+      }
+    }
+
+    if (withClause != null) {
+      for (TypeName type in withClause.mixinTypes) {
+        Element mixinElement = type.name.staticElement;
+        if (mixinElement != null && mixinElement.name == "Function") {
+          _errorReporter.reportErrorForNode(
+              HintCode.DEPRECATED_MIXIN_FUNCTION, type);
+        }
+      }
+    }
+  }
+
+  /**
    * Verify that the given [identifier] is not a keyword, and generates the
    * given [errorCode] on the identifier if it is a keyword.
    *
@@ -2944,40 +2985,6 @@
   }
 
   /**
-   * Verifies that the class is not named `Function` and that it doesn't
-   * extends/implements/mixes in `Function`.
-   */
-  void _checkForBadFunctionUse(ClassDeclaration node) {
-    ExtendsClause extendsClause = node.extendsClause;
-    ImplementsClause implementsClause = node.implementsClause;
-    WithClause withClause = node.withClause;
-
-    if (node.name.name == "Function") {
-      _errorReporter.reportErrorForNode(
-          HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION, node.name);
-    }
-
-    if (extendsClause != null) {
-      InterfaceType superclassType = _enclosingClass.supertype;
-      ClassElement superclassElement = superclassType?.element;
-      if (superclassElement != null && superclassElement.name == "Function") {
-        _errorReporter.reportErrorForNode(
-            HintCode.DEPRECATED_EXTENDS_FUNCTION, extendsClause.superclass);
-      }
-    }
-
-    if (withClause != null) {
-      for (TypeName type in withClause.mixinTypes) {
-        Element mixinElement = type.name.staticElement;
-        if (mixinElement != null && mixinElement.name == "Function") {
-          _errorReporter.reportErrorForNode(
-              HintCode.DEPRECATED_MIXIN_FUNCTION, type);
-        }
-      }
-    }
-  }
-
-  /**
    * Verify that the enclosing class does not have an instance member with the
    * same name as the given static [method] declaration.
    *
@@ -4000,7 +4007,9 @@
     }
     DartType invokeType = node.staticInvokeType;
     DartType declaredType = node.function.staticType;
-    if (invokeType is FunctionType && declaredType is FunctionType) {
+    if (invokeType is FunctionType &&
+        declaredType is FunctionType &&
+        declaredType.typeFormals.isNotEmpty) {
       Iterable<DartType> typeArgs =
           FunctionTypeImpl.recoverTypeArguments(declaredType, invokeType);
       if (typeArgs.any((t) => t.isDynamic)) {
@@ -5895,6 +5904,11 @@
   }
 
   void _checkForValidField(FieldFormalParameter parameter) {
+    AstNode parent2 = parameter.parent?.parent;
+    if (parent2 is! ConstructorDeclaration &&
+        parent2?.parent is! ConstructorDeclaration) {
+      return;
+    }
     ParameterElement element = parameter.element;
     if (element is FieldFormalParameterElement) {
       FieldElement fieldElement = element.field;
diff --git a/pkg/analyzer/lib/src/generated/gn.dart b/pkg/analyzer/lib/src/generated/gn.dart
index ea19833..0e0b7fc 100644
--- a/pkg/analyzer/lib/src/generated/gn.dart
+++ b/pkg/analyzer/lib/src/generated/gn.dart
@@ -8,9 +8,10 @@
 import 'dart:core';
 
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
+import 'package:analyzer/src/generated/workspace.dart';
 import 'package:path/path.dart';
 
 /**
@@ -125,14 +126,14 @@
 
     String sourcePath = context.relative(path, from: _packages[package]);
 
-    return FastUri.parse('package:$package/$sourcePath');
+    return Uri.parse('package:$package/$sourcePath');
   }
 }
 
 /**
  * Information about a Gn workspace.
  */
-class GnWorkspace {
+class GnWorkspace extends Workspace {
   /**
    * The name of the directory that identifies the root of the workspace.
    */
@@ -156,9 +157,7 @@
 
   GnWorkspace._(this.provider, this.root, this.packages);
 
-  /**
-   * Return a map of package sources.
-   */
+  @override
   Map<String, List<Folder>> get packageMap {
     Map<String, List<Folder>> result = new HashMap<String, List<Folder>>();
     packages.forEach((package, sourceDir) {
@@ -167,6 +166,20 @@
     return result;
   }
 
+  @override
+  UriResolver get packageUriResolver => new GnPackageUriResolver(this);
+
+  @override
+  SourceFactory createSourceFactory(DartSdk sdk) {
+    List<UriResolver> resolvers = <UriResolver>[];
+    if (sdk != null) {
+      resolvers.add(new DartUriResolver(sdk));
+    }
+    resolvers.add(packageUriResolver);
+    resolvers.add(new GnFileUriResolver(this));
+    return new SourceFactory(resolvers, null, provider);
+  }
+
   /**
    * Return the file with the given [absolutePath].
    *
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 56e59c5..291f075 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -29,6 +29,7 @@
 import 'package:analyzer/src/generated/error_verifier.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_system.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -4168,6 +4169,24 @@
   }
 
   /**
+   * Like [getContext] but expands a union type into a list of types.
+   */
+  Iterable<DartType> getTypes(AstNode node) {
+    DartType t = getContext(node);
+    if (t == null) {
+      return DartType.EMPTY_LIST;
+    }
+    if (t is InterfaceType && t.isDartAsyncFutureOr) {
+      var tArg = t.typeArguments[0]; // The T in FutureOr<T>
+      return [
+        _typeProvider.futureType.instantiate([tArg]),
+        tArg
+      ];
+    }
+    return [t];
+  }
+
+  /**
    * Match type [t1] against type [t2] as follows.
    * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
    * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
@@ -4369,24 +4388,6 @@
   }
 
   /**
-   * Like [getContext] but expands a union type into a list of types.
-   */
-  Iterable<DartType> getTypes(AstNode node) {
-    DartType t = getContext(node);
-    if (t == null) {
-      return DartType.EMPTY_LIST;
-    }
-    if (t is InterfaceType && t.isDartAsyncFutureOr) {
-      var tArg = t.typeArguments[0]; // The T in FutureOr<T>
-      return [
-        _typeProvider.futureType.instantiate([tArg]),
-        tArg
-      ];
-    }
-    return [t];
-  }
-
-  /**
    * Attach contextual type information [type] to [node] for use during
    * inference.
    */
@@ -9508,9 +9509,26 @@
     _undefinedType = UndefinedTypeImpl.instance;
     _futureDynamicType = _futureType.instantiate(<DartType>[_dynamicType]);
     _futureNullType = _futureType.instantiate(<DartType>[_nullType]);
-    _futureOrNullType = _futureOrType.instantiate(<DartType>[_nullType]);
     _iterableDynamicType = _iterableType.instantiate(<DartType>[_dynamicType]);
     _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) {
+    var compilationUnit =
+        futureType.element.getAncestor((e) => e is CompilationUnitElement);
+    var element = ElementFactory.classElement('FutureOr', objectType, ['T']);
+    element.enclosingElement = compilationUnit;
+    return element.type;
   }
 }
 
@@ -9875,6 +9893,23 @@
   }
 
   @override
+  Object visitGenericFunctionType(GenericFunctionType node) {
+    DartType returnType = node.returnType?.type ?? DynamicTypeImpl.instance;
+    List<TypeParameterElement> typeParameters = node
+        .typeParameters.typeParameters
+        .map((TypeParameter parameter) =>
+            parameter.element as TypeParameterElement)
+        .toList();
+    List<ParameterElement> parameters = node.parameters.parameters
+        .map((FormalParameter parameter) => parameter.element)
+        .toList();
+    (node as GenericFunctionTypeImpl).type =
+        new FunctionTypeImpl.forGenericFunctionType(
+            typeParameters, DartType.EMPTY_LIST, returnType, parameters, false);
+    return null;
+  }
+
+  @override
   Object visitMethodDeclaration(MethodDeclaration node) {
     super.visitMethodDeclaration(node);
     ExecutableElementImpl element = node.element as ExecutableElementImpl;
diff --git a/pkg/analyzer/lib/src/generated/utilities_collection.dart b/pkg/analyzer/lib/src/generated/utilities_collection.dart
index b1c5e88..ee84315 100644
--- a/pkg/analyzer/lib/src/generated/utilities_collection.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_collection.dart
@@ -50,7 +50,8 @@
    * Return the value of the element at the given index.
    */
   @deprecated
-  static bool getEnum(int array, Enum index) => get(array, index.ordinal);
+  static bool getEnum<E extends Enum<E>>(int array, Enum<E> index) => get(
+      array, index.ordinal);
 
   /**
    * Set the value of the element of the given [array] at the given [index] to
@@ -69,7 +70,7 @@
    * Set the value of the element at the given index to the given value.
    */
   @deprecated
-  static int setEnum(int array, Enum index, bool value) =>
+  static int setEnum<E extends Enum<E>>(int array, Enum<E> index, bool value) =>
       set(array, index.ordinal, value);
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/utilities_dart.dart b/pkg/analyzer/lib/src/generated/utilities_dart.dart
index b3f688a..3bdb6e9 100644
--- a/pkg/analyzer/lib/src/generated/utilities_dart.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_dart.dart
@@ -6,51 +6,10 @@
 
 import 'package:analyzer/dart/ast/ast.dart' show AnnotatedNode, Comment;
 import 'package:analyzer/dart/ast/token.dart' show Token;
-import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/src/dart/element/element.dart' show ElementImpl;
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
 
-/**
- * Resolve the [containedUri] against [baseUri] using Dart rules.
- *
- * This function behaves similarly to [Uri.resolveUri], except that it properly
- * handles situations like the following:
- *
- *     resolveRelativeUri(dart:core, bool.dart) -> dart:core/bool.dart
- *     resolveRelativeUri(package:a/b.dart, ../c.dart) -> package:a/c.dart
- */
-Uri resolveRelativeUri(Uri baseUri, Uri containedUri) {
-  if (containedUri.isAbsolute) {
-    return containedUri;
-  }
-  Uri origBaseUri = baseUri;
-  try {
-    String scheme = baseUri.scheme;
-    // dart:core => dart:core/core.dart
-    if (scheme == DartUriResolver.DART_SCHEME) {
-      String part = baseUri.path;
-      if (part.indexOf('/') < 0) {
-        baseUri = FastUri.parse('$scheme:$part/$part.dart');
-      }
-    }
-    // foo.dart + ../bar.dart = ../bar.dart
-    // TODO(scheglov) Remove this temporary workaround.
-    // Should be fixed as https://github.com/dart-lang/sdk/issues/27447
-    List<String> baseSegments = baseUri.pathSegments;
-    List<String> containedSegments = containedUri.pathSegments;
-    if (baseSegments.length == 1 &&
-        containedSegments.length > 0 &&
-        containedSegments[0] == '..') {
-      return containedUri;
-    }
-    return baseUri.resolveUri(containedUri);
-  } catch (exception, stackTrace) {
-    throw new AnalysisException(
-        "Could not resolve URI ($containedUri) relative to source ($origBaseUri)",
-        new CaughtException(exception, stackTrace));
-  }
-}
+export 'package:front_end/src/base/resolve_relative_uri.dart'
+    show resolveRelativeUri;
 
 /**
  * If the given [node] has a documentation comment, remember its content
diff --git a/pkg/analyzer/lib/src/generated/workspace.dart b/pkg/analyzer/lib/src/generated/workspace.dart
new file mode 100644
index 0000000..503472b
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/workspace.dart
@@ -0,0 +1,38 @@
+// 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 analyzer.src.generated.workspace;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * Abstract superclass of classes that provide information about the workspace
+ * in which analysis is being performed.
+ */
+abstract class Workspace {
+
+  /**
+   * Return a map of package sources.
+   */
+  Map<String, List<Folder>> get packageMap;
+
+  /**
+   * The [UriResolver] that can resolve `package` URIs.
+   */
+  UriResolver get packageUriResolver;
+
+  /**
+   * Return `true` if this workspace defines a single "project"
+   * and that "project" depends upon flutter,
+   */
+  bool get hasFlutterDependency => false;
+
+  /**
+   * Create the [SourceFactory] for resolving Uris to [Source]s.
+   * The [sdk] may be `null`.
+   */
+  SourceFactory createSourceFactory(DartSdk sdk);
+}
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 95f7186..9ad6c5c 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -129,6 +129,302 @@
   }
 }
 
+class AnalysisDriverExceptionContextBuilder extends Object with _AnalysisDriverExceptionContextMixin implements idl.AnalysisDriverExceptionContext {
+  String _exception;
+  List<AnalysisDriverExceptionFileBuilder> _files;
+  String _path;
+  String _stackTrace;
+
+  @override
+  String get exception => _exception ??= '';
+
+  /**
+   * The exception string.
+   */
+  void set exception(String value) {
+    this._exception = value;
+  }
+
+  @override
+  List<AnalysisDriverExceptionFileBuilder> get files => _files ??= <AnalysisDriverExceptionFileBuilder>[];
+
+  /**
+   * The state of files when the exception happened.
+   */
+  void set files(List<AnalysisDriverExceptionFileBuilder> value) {
+    this._files = value;
+  }
+
+  @override
+  String get path => _path ??= '';
+
+  /**
+   * The path of the file being analyzed when the exception happened.
+   */
+  void set path(String value) {
+    this._path = value;
+  }
+
+  @override
+  String get stackTrace => _stackTrace ??= '';
+
+  /**
+   * The exception stack trace string.
+   */
+  void set stackTrace(String value) {
+    this._stackTrace = value;
+  }
+
+  AnalysisDriverExceptionContextBuilder({String exception, List<AnalysisDriverExceptionFileBuilder> files, String path, String stackTrace})
+    : _exception = exception,
+      _files = files,
+      _path = path,
+      _stackTrace = stackTrace;
+
+  /**
+   * Flush [informative] data recursively.
+   */
+  void flushInformative() {
+    _files?.forEach((b) => b.flushInformative());
+  }
+
+  /**
+   * Accumulate non-[informative] data into [signature].
+   */
+  void collectApiSignature(api_sig.ApiSignature signature) {
+    signature.addString(this._path ?? '');
+    signature.addString(this._exception ?? '');
+    signature.addString(this._stackTrace ?? '');
+    if (this._files == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._files.length);
+      for (var x in this._files) {
+        x?.collectApiSignature(signature);
+      }
+    }
+  }
+
+  List<int> toBuffer() {
+    fb.Builder fbBuilder = new fb.Builder();
+    return fbBuilder.finish(finish(fbBuilder), "ADEC");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_exception;
+    fb.Offset offset_files;
+    fb.Offset offset_path;
+    fb.Offset offset_stackTrace;
+    if (_exception != null) {
+      offset_exception = fbBuilder.writeString(_exception);
+    }
+    if (!(_files == null || _files.isEmpty)) {
+      offset_files = fbBuilder.writeList(_files.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_path != null) {
+      offset_path = fbBuilder.writeString(_path);
+    }
+    if (_stackTrace != null) {
+      offset_stackTrace = fbBuilder.writeString(_stackTrace);
+    }
+    fbBuilder.startTable();
+    if (offset_exception != null) {
+      fbBuilder.addOffset(1, offset_exception);
+    }
+    if (offset_files != null) {
+      fbBuilder.addOffset(3, offset_files);
+    }
+    if (offset_path != null) {
+      fbBuilder.addOffset(0, offset_path);
+    }
+    if (offset_stackTrace != null) {
+      fbBuilder.addOffset(2, offset_stackTrace);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.AnalysisDriverExceptionContext readAnalysisDriverExceptionContext(List<int> buffer) {
+  fb.BufferContext rootRef = new fb.BufferContext.fromBytes(buffer);
+  return const _AnalysisDriverExceptionContextReader().read(rootRef, 0);
+}
+
+class _AnalysisDriverExceptionContextReader extends fb.TableReader<_AnalysisDriverExceptionContextImpl> {
+  const _AnalysisDriverExceptionContextReader();
+
+  @override
+  _AnalysisDriverExceptionContextImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverExceptionContextImpl(bc, offset);
+}
+
+class _AnalysisDriverExceptionContextImpl extends Object with _AnalysisDriverExceptionContextMixin implements idl.AnalysisDriverExceptionContext {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _AnalysisDriverExceptionContextImpl(this._bc, this._bcOffset);
+
+  String _exception;
+  List<idl.AnalysisDriverExceptionFile> _files;
+  String _path;
+  String _stackTrace;
+
+  @override
+  String get exception {
+    _exception ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 1, '');
+    return _exception;
+  }
+
+  @override
+  List<idl.AnalysisDriverExceptionFile> get files {
+    _files ??= const fb.ListReader<idl.AnalysisDriverExceptionFile>(const _AnalysisDriverExceptionFileReader()).vTableGet(_bc, _bcOffset, 3, const <idl.AnalysisDriverExceptionFile>[]);
+    return _files;
+  }
+
+  @override
+  String get path {
+    _path ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 0, '');
+    return _path;
+  }
+
+  @override
+  String get stackTrace {
+    _stackTrace ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 2, '');
+    return _stackTrace;
+  }
+}
+
+abstract class _AnalysisDriverExceptionContextMixin implements idl.AnalysisDriverExceptionContext {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (exception != '') _result["exception"] = exception;
+    if (files.isNotEmpty) _result["files"] = files.map((_value) => _value.toJson()).toList();
+    if (path != '') _result["path"] = path;
+    if (stackTrace != '') _result["stackTrace"] = stackTrace;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "exception": exception,
+    "files": files,
+    "path": path,
+    "stackTrace": stackTrace,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class AnalysisDriverExceptionFileBuilder extends Object with _AnalysisDriverExceptionFileMixin implements idl.AnalysisDriverExceptionFile {
+  String _content;
+  String _path;
+
+  @override
+  String get content => _content ??= '';
+
+  /**
+   * The content of the file.
+   */
+  void set content(String value) {
+    this._content = value;
+  }
+
+  @override
+  String get path => _path ??= '';
+
+  /**
+   * The path of the file.
+   */
+  void set path(String value) {
+    this._path = value;
+  }
+
+  AnalysisDriverExceptionFileBuilder({String content, String path})
+    : _content = content,
+      _path = path;
+
+  /**
+   * Flush [informative] data recursively.
+   */
+  void flushInformative() {
+  }
+
+  /**
+   * Accumulate non-[informative] data into [signature].
+   */
+  void collectApiSignature(api_sig.ApiSignature signature) {
+    signature.addString(this._path ?? '');
+    signature.addString(this._content ?? '');
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_content;
+    fb.Offset offset_path;
+    if (_content != null) {
+      offset_content = fbBuilder.writeString(_content);
+    }
+    if (_path != null) {
+      offset_path = fbBuilder.writeString(_path);
+    }
+    fbBuilder.startTable();
+    if (offset_content != null) {
+      fbBuilder.addOffset(1, offset_content);
+    }
+    if (offset_path != null) {
+      fbBuilder.addOffset(0, offset_path);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _AnalysisDriverExceptionFileReader extends fb.TableReader<_AnalysisDriverExceptionFileImpl> {
+  const _AnalysisDriverExceptionFileReader();
+
+  @override
+  _AnalysisDriverExceptionFileImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverExceptionFileImpl(bc, offset);
+}
+
+class _AnalysisDriverExceptionFileImpl extends Object with _AnalysisDriverExceptionFileMixin implements idl.AnalysisDriverExceptionFile {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _AnalysisDriverExceptionFileImpl(this._bc, this._bcOffset);
+
+  String _content;
+  String _path;
+
+  @override
+  String get content {
+    _content ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 1, '');
+    return _content;
+  }
+
+  @override
+  String get path {
+    _path ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 0, '');
+    return _path;
+  }
+}
+
+abstract class _AnalysisDriverExceptionFileMixin implements idl.AnalysisDriverExceptionFile {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (content != '') _result["content"] = content;
+    if (path != '') _result["path"] = path;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "content": content,
+    "path": path,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
 class AnalysisDriverResolvedUnitBuilder extends Object with _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
   List<AnalysisDriverUnitErrorBuilder> _errors;
   AnalysisDriverUnitIndexBuilder _index;
@@ -1187,10 +1483,32 @@
 }
 
 class AnalysisDriverUnlinkedUnitBuilder extends Object with _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+  List<String> _definedClassMemberNames;
+  List<String> _definedTopLevelNames;
   List<String> _referencedNames;
   UnlinkedUnitBuilder _unit;
 
   @override
+  List<String> get definedClassMemberNames => _definedClassMemberNames ??= <String>[];
+
+  /**
+   * List of class member names defined by the unit.
+   */
+  void set definedClassMemberNames(List<String> value) {
+    this._definedClassMemberNames = value;
+  }
+
+  @override
+  List<String> get definedTopLevelNames => _definedTopLevelNames ??= <String>[];
+
+  /**
+   * List of top-level names defined by the unit.
+   */
+  void set definedTopLevelNames(List<String> value) {
+    this._definedTopLevelNames = value;
+  }
+
+  @override
   List<String> get referencedNames => _referencedNames ??= <String>[];
 
   /**
@@ -1210,8 +1528,10 @@
     this._unit = value;
   }
 
-  AnalysisDriverUnlinkedUnitBuilder({List<String> referencedNames, UnlinkedUnitBuilder unit})
-    : _referencedNames = referencedNames,
+  AnalysisDriverUnlinkedUnitBuilder({List<String> definedClassMemberNames, List<String> definedTopLevelNames, List<String> referencedNames, UnlinkedUnitBuilder unit})
+    : _definedClassMemberNames = definedClassMemberNames,
+      _definedTopLevelNames = definedTopLevelNames,
+      _referencedNames = referencedNames,
       _unit = unit;
 
   /**
@@ -1235,6 +1555,22 @@
     }
     signature.addBool(this._unit != null);
     this._unit?.collectApiSignature(signature);
+    if (this._definedTopLevelNames == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._definedTopLevelNames.length);
+      for (var x in this._definedTopLevelNames) {
+        signature.addString(x);
+      }
+    }
+    if (this._definedClassMemberNames == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._definedClassMemberNames.length);
+      for (var x in this._definedClassMemberNames) {
+        signature.addString(x);
+      }
+    }
   }
 
   List<int> toBuffer() {
@@ -1243,8 +1579,16 @@
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_definedClassMemberNames;
+    fb.Offset offset_definedTopLevelNames;
     fb.Offset offset_referencedNames;
     fb.Offset offset_unit;
+    if (!(_definedClassMemberNames == null || _definedClassMemberNames.isEmpty)) {
+      offset_definedClassMemberNames = fbBuilder.writeList(_definedClassMemberNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (!(_definedTopLevelNames == null || _definedTopLevelNames.isEmpty)) {
+      offset_definedTopLevelNames = fbBuilder.writeList(_definedTopLevelNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
     if (!(_referencedNames == null || _referencedNames.isEmpty)) {
       offset_referencedNames = fbBuilder.writeList(_referencedNames.map((b) => fbBuilder.writeString(b)).toList());
     }
@@ -1252,6 +1596,12 @@
       offset_unit = _unit.finish(fbBuilder);
     }
     fbBuilder.startTable();
+    if (offset_definedClassMemberNames != null) {
+      fbBuilder.addOffset(3, offset_definedClassMemberNames);
+    }
+    if (offset_definedTopLevelNames != null) {
+      fbBuilder.addOffset(2, offset_definedTopLevelNames);
+    }
     if (offset_referencedNames != null) {
       fbBuilder.addOffset(0, offset_referencedNames);
     }
@@ -1280,10 +1630,24 @@
 
   _AnalysisDriverUnlinkedUnitImpl(this._bc, this._bcOffset);
 
+  List<String> _definedClassMemberNames;
+  List<String> _definedTopLevelNames;
   List<String> _referencedNames;
   idl.UnlinkedUnit _unit;
 
   @override
+  List<String> get definedClassMemberNames {
+    _definedClassMemberNames ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 3, const <String>[]);
+    return _definedClassMemberNames;
+  }
+
+  @override
+  List<String> get definedTopLevelNames {
+    _definedTopLevelNames ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 2, const <String>[]);
+    return _definedTopLevelNames;
+  }
+
+  @override
   List<String> get referencedNames {
     _referencedNames ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 0, const <String>[]);
     return _referencedNames;
@@ -1300,6 +1664,8 @@
   @override
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
+    if (definedClassMemberNames.isNotEmpty) _result["definedClassMemberNames"] = definedClassMemberNames;
+    if (definedTopLevelNames.isNotEmpty) _result["definedTopLevelNames"] = definedTopLevelNames;
     if (referencedNames.isNotEmpty) _result["referencedNames"] = referencedNames;
     if (unit != null) _result["unit"] = unit.toJson();
     return _result;
@@ -1307,6 +1673,8 @@
 
   @override
   Map<String, Object> toMap() => {
+    "definedClassMemberNames": definedClassMemberNames,
+    "definedTopLevelNames": definedTopLevelNames,
     "referencedNames": referencedNames,
     "unit": unit,
   };
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 6a75528..84e37ff 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -812,7 +812,12 @@
   /**
    * Push `this` expression onto the stack.
    */
-  pushThis
+  pushThis,
+
+  /**
+   * Push `super` expression onto the stack.
+   */
+  pushSuper
 }
 
 /**
@@ -836,6 +841,46 @@
 }
 
 /**
+ * Information about the context of an exception in analysis driver.
+ */
+table AnalysisDriverExceptionContext {
+  /**
+   * The exception string.
+   */
+  exception:string (id: 1);
+
+  /**
+   * The state of files when the exception happened.
+   */
+  files:[AnalysisDriverExceptionFile] (id: 3);
+
+  /**
+   * The path of the file being analyzed when the exception happened.
+   */
+  path:string (id: 0);
+
+  /**
+   * The exception stack trace string.
+   */
+  stackTrace:string (id: 2);
+}
+
+/**
+ * Information about a single file in [AnalysisDriverExceptionContext].
+ */
+table AnalysisDriverExceptionFile {
+  /**
+   * The content of the file.
+   */
+  content:string (id: 1);
+
+  /**
+   * The path of the file.
+   */
+  path:string (id: 0);
+}
+
+/**
  * Information about a resolved unit.
  */
 table AnalysisDriverResolvedUnit {
@@ -1005,6 +1050,16 @@
  */
 table AnalysisDriverUnlinkedUnit {
   /**
+   * List of class member names defined by the unit.
+   */
+  definedClassMemberNames:[string] (id: 3);
+
+  /**
+   * List of top-level names defined by the unit.
+   */
+  definedTopLevelNames:[string] (id: 2);
+
+  /**
    * List of external names referenced by the unit.
    */
   referencedNames:[string] (id: 0);
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 0d8ce5e..e6f142d 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -58,6 +58,56 @@
 const informative = null;
 
 /**
+ * Information about the context of an exception in analysis driver.
+ */
+@TopLevel('ADEC')
+abstract class AnalysisDriverExceptionContext extends base.SummaryClass {
+  factory AnalysisDriverExceptionContext.fromBuffer(List<int> buffer) =>
+      generated.readAnalysisDriverExceptionContext(buffer);
+
+  /**
+   * The exception string.
+   */
+  @Id(1)
+  String get exception;
+
+  /**
+   * The state of files when the exception happened.
+   */
+  @Id(3)
+  List<AnalysisDriverExceptionFile> get files;
+
+  /**
+   * The path of the file being analyzed when the exception happened.
+   */
+  @Id(0)
+  String get path;
+
+  /**
+   * The exception stack trace string.
+   */
+  @Id(2)
+  String get stackTrace;
+}
+
+/**
+ * Information about a single file in [AnalysisDriverExceptionContext].
+ */
+abstract class AnalysisDriverExceptionFile extends base.SummaryClass {
+  /**
+   * The content of the file.
+   */
+  @Id(1)
+  String get content;
+
+  /**
+   * The path of the file.
+   */
+  @Id(0)
+  String get path;
+}
+
+/**
  * Information about a resolved unit.
  */
 @TopLevel('ADRU')
@@ -264,6 +314,18 @@
       generated.readAnalysisDriverUnlinkedUnit(buffer);
 
   /**
+   * List of class member names defined by the unit.
+   */
+  @Id(3)
+  List<String> get definedClassMemberNames;
+
+  /**
+   * List of top-level names defined by the unit.
+   */
+  @Id(2)
+  List<String> get definedTopLevelNames;
+
+  /**
    * List of external names referenced by the unit.
    */
   @Id(0)
@@ -2388,6 +2450,11 @@
    * Push `this` expression onto the stack.
    */
   pushThis,
+
+  /**
+   * Push `super` expression onto the stack.
+   */
+  pushSuper,
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 22725aa..a97a11b 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -146,8 +146,17 @@
       <String, LinkedLibraryBuilder>{};
   for (String absoluteUri in libraryUris) {
     Uri uri = Uri.parse(absoluteUri);
-    UnlinkedUnit getRelativeUnit(String relativeUri) =>
-        getUnit(resolveRelativeUri(uri, Uri.parse(relativeUri)).toString());
+
+    UnlinkedUnit getRelativeUnit(String relativeUriStr) {
+      Uri relativeUri;
+      try {
+        relativeUri = Uri.parse(relativeUriStr);
+      } on FormatException {
+        return new UnlinkedUnitBuilder();
+      }
+      return getUnit(resolveRelativeUri(uri, relativeUri).toString());
+    }
+
     linkedLibraries[absoluteUri] = prelink(
         getUnit(absoluteUri),
         getRelativeUnit,
@@ -539,6 +548,9 @@
       _unlinkedClass.interfaces.map(_computeInterfaceType).toList();
 
   @override
+  bool get isEnum => false;
+
+  @override
   bool get isMixinApplication => _unlinkedClass.isMixinApplication;
 
   @override
@@ -668,7 +680,7 @@
   InterfaceType _computeInterfaceType(EntityRef typeRef) {
     if (typeRef != null) {
       DartType type = enclosingElement.resolveTypeRef(typeRef, this);
-      if (type is InterfaceType) {
+      if (type is InterfaceType && !type.element.isEnum) {
         return type;
       }
       // In the event that the `typeRef` isn't an interface type (which may
@@ -732,6 +744,9 @@
   List<InterfaceType> get interfaces => const [];
 
   @override
+  bool get isEnum => true;
+
+  @override
   bool get isObject => false;
 
   @override
@@ -1055,7 +1070,9 @@
   @override
   DartType resolveTypeRef(
       EntityRef type, TypeParameterizedElementMixin typeParameterContext,
-      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+      {bool defaultVoid: false,
+      bool instantiateToBoundsAllowed: true,
+      bool declaredType: false}) {
     if (type == null) {
       if (defaultVoid) {
         return VoidTypeImpl.instance;
@@ -1974,6 +1991,10 @@
       // return type.  Assume `dynamic`.
       return DynamicTypeImpl.instance;
     }
+    // If no operations, we cannot compute the type.  Assume `dynamic`.
+    if (unlinkedConst.operations.isEmpty) {
+      return DynamicTypeImpl.instance;
+    }
     // Perform RPN evaluation of the constant, using a stack of inferred types.
     for (UnlinkedExprOperation operation in unlinkedConst.operations) {
       switch (operation) {
@@ -2008,6 +2029,12 @@
         case UnlinkedExprOperation.pushNull:
           stack.add(typeProvider.nullType);
           break;
+        case UnlinkedExprOperation.pushSuper:
+          stack.add(DynamicTypeImpl.instance);
+          break;
+        case UnlinkedExprOperation.pushThis:
+          stack.add(DynamicTypeImpl.instance);
+          break;
         case UnlinkedExprOperation.pushReference:
           _doPushReference();
           break;
@@ -3294,8 +3321,11 @@
   Element get enclosingElement => null;
 
   @override
-  List<LibraryElementForLink> get exportedLibraries => _exportedLibraries ??=
-      _linkedLibrary.exportDependencies.map(_getDependency).toList();
+  List<LibraryElementForLink> get exportedLibraries =>
+      _exportedLibraries ??= _linkedLibrary.exportDependencies
+          .map(_getDependency)
+          .where((library) => library != null)
+          .toList();
 
   @override
   String get identifier => _absoluteUri.toString();
@@ -3330,11 +3360,19 @@
       ];
       int numParts = definingUnit.parts.length;
       for (int i = 0; i < numParts; i++) {
-        // TODO(paulberry): make sure we handle the case where Uri.parse fails.
         // TODO(paulberry): make sure we handle the case where
         // resolveRelativeUri fails.
+        String partRelativeUriStr = definingUnit.publicNamespace.parts[i];
+
+        Uri partRelativeUri;
+        try {
+          partRelativeUri = Uri.parse(partRelativeUriStr);
+        } on FormatException {
+          continue;
+        }
+
         String partAbsoluteUri = resolveRelativeUri(
-                _absoluteUri, Uri.parse(definingUnit.publicNamespace.parts[i]))
+                _absoluteUri, partRelativeUri)
             .toString();
         UnlinkedUnit partUnit = _linker.getUnit(partAbsoluteUri);
         _units.add(_makeUnitElement(
@@ -3377,10 +3415,18 @@
   LibraryElementForLink _getDependency(int index) {
     LibraryElementForLink result = _dependencies[index];
     if (result == null) {
-      String relativeUri = _linkedLibrary.dependencies[index].uri;
-      Uri absoluteUri = relativeUri.isEmpty
+      String relativeUriStr = _linkedLibrary.dependencies[index].uri;
+
+      Uri relativeUri;
+      try {
+        relativeUri = Uri.parse(relativeUriStr);
+      } on FormatException {
+        return null;
+      }
+
+      Uri absoluteUri = relativeUriStr.isEmpty
           ? _absoluteUri
-          : resolveRelativeUri(_absoluteUri, Uri.parse(relativeUri));
+          : resolveRelativeUri(_absoluteUri, relativeUri);
       result = _linker.getLibrary(absoluteUri);
       _dependencies[index] = result;
     }
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
index ff5ab7f..31c392b 100644
--- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -14,7 +14,6 @@
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/resynthesize.dart';
 import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/general.dart';
 import 'package:analyzer/task/model.dart';
@@ -120,7 +119,7 @@
   final InternalAnalysisContext context;
   final SummaryDataStore _dataStore;
 
-  _FileBasedSummaryResynthesizer _resynthesizer;
+  StoreBasedSummaryResynthesizer _resynthesizer;
 
   ResynthesizerResultProvider(this.context, this._dataStore);
 
@@ -267,7 +266,7 @@
    * Subclasses must call this method in their constructors.
    */
   void createResynthesizer() {
-    _resynthesizer = new _FileBasedSummaryResynthesizer(context,
+    _resynthesizer = new StoreBasedSummaryResynthesizer(context,
         context.sourceFactory, context.analysisOptions.strongMode, _dataStore);
   }
 
@@ -280,6 +279,33 @@
 }
 
 /**
+ * A concrete resynthesizer that serves summaries from [SummaryDataStore].
+ */
+class StoreBasedSummaryResynthesizer extends SummaryResynthesizer {
+  final SummaryDataStore _dataStore;
+
+  StoreBasedSummaryResynthesizer(AnalysisContext context,
+      SourceFactory sourceFactory, bool strongMode, this._dataStore)
+      : super(context, sourceFactory, strongMode);
+
+  @override
+  LinkedLibrary getLinkedSummary(String uri) {
+    return _dataStore.linkedMap[uri];
+  }
+
+  @override
+  UnlinkedUnit getUnlinkedSummary(String uri) {
+    return _dataStore.unlinkedMap[uri];
+  }
+
+  @override
+  bool hasLibrarySummary(String uri) {
+    LinkedLibrary linkedLibrary = _dataStore.linkedMap[uri];
+    return linkedLibrary != null;
+  }
+}
+
+/**
  * A [SummaryDataStore] is a container for the data extracted from a set of
  * summary package bundles.  It contains maps which can be used to find linked
  * and unlinked summaries by URI.
@@ -338,7 +364,7 @@
       bool includesDartUris = false;
       bool includesFileUris = false;
       for (String uriString in bundle.unlinkedUnitUris) {
-        Uri uri = FastUri.parse(uriString);
+        Uri uri = Uri.parse(uriString);
         String scheme = uri.scheme;
         if (scheme == 'package') {
           List<String> pathSegments = uri.pathSegments;
@@ -393,9 +419,9 @@
     // Check every unlinked unit whether it uses [unitUri] as a part.
     List<String> libraryUriStrings = <String>[];
     unlinkedMap.forEach((unlinkedUnitUriString, unlinkedUnit) {
-      Uri libraryUri = FastUri.parse(unlinkedUnitUriString);
+      Uri libraryUri = Uri.parse(unlinkedUnitUriString);
       for (String partUriString in unlinkedUnit.publicNamespace.parts) {
-        Uri partUri = FastUri.parse(partUriString);
+        Uri partUri = Uri.parse(partUriString);
         String partAbsoluteUriString =
             resolveRelativeUri(libraryUri, partUri).toString();
         if (partAbsoluteUriString == unitUriString) {
@@ -413,30 +439,3 @@
     addBundle(path, bundle);
   }
 }
-
-/**
- * A concrete resynthesizer that serves summaries from given file paths.
- */
-class _FileBasedSummaryResynthesizer extends SummaryResynthesizer {
-  final SummaryDataStore _dataStore;
-
-  _FileBasedSummaryResynthesizer(AnalysisContext context,
-      SourceFactory sourceFactory, bool strongMode, this._dataStore)
-      : super(context, sourceFactory, strongMode);
-
-  @override
-  LinkedLibrary getLinkedSummary(String uri) {
-    return _dataStore.linkedMap[uri];
-  }
-
-  @override
-  UnlinkedUnit getUnlinkedSummary(String uri) {
-    return _dataStore.unlinkedMap[uri];
-  }
-
-  @override
-  bool hasLibrarySummary(String uri) {
-    LinkedLibrary linkedLibrary = _dataStore.linkedMap[uri];
-    return linkedLibrary != null;
-  }
-}
diff --git a/pkg/analyzer/lib/src/summary/prelink.dart b/pkg/analyzer/lib/src/summary/prelink.dart
index 489bd35..33ce0f9 100644
--- a/pkg/analyzer/lib/src/summary/prelink.dart
+++ b/pkg/analyzer/lib/src/summary/prelink.dart
@@ -53,7 +53,7 @@
  * A [_Meaning] representing a class.
  */
 class _ClassMeaning extends _Meaning {
-  final Map<String, _Meaning> namespace;
+  final _Namespace namespace;
 
   _ClassMeaning(int unit, int dependency, int numTypeParameters, this.namespace)
       : super(unit, ReferenceKind.classOrEnum, dependency, numTypeParameters);
@@ -109,10 +109,74 @@
 }
 
 /**
+ * Mapping from names to corresponding unique [_Meaning]s.
+ */
+class _Namespace {
+  final Set<String> namesWithConflictingDefinitions = new Set<String>();
+  final Set<String> libraryNames = new Set<String>();
+  final Map<String, _Meaning> map = <String, _Meaning>{};
+
+  /**
+   * Return the [_Meaning] of the name, or `null` is not defined.
+   */
+  _Meaning operator [](String name) {
+    return map[name];
+  }
+
+  /**
+   * Define that the [name] has the given [value].  If the [name] already been
+   * defined with a different value, then it becomes undefined.
+   */
+  void add(String name, _Meaning value) {
+    // Already determined to be a conflict.
+    if (namesWithConflictingDefinitions.contains(name)) {
+      return;
+    }
+
+    _Meaning currentValue = map[name];
+    if (currentValue == null) {
+      map[name] = value;
+    } else if (currentValue == value) {
+      // The same value, ignore.
+    } else {
+      // A conflict, remember it, and un-define the name.
+      namesWithConflictingDefinitions.add(name);
+      map.remove(name);
+    }
+  }
+
+  /**
+   * Return `true` if the [name] was defined before [rememberLibraryNames]
+   * invocation.
+   */
+  bool definesLibraryName(String name) => libraryNames.contains(name);
+
+  /**
+   * Return `true` if the [name] is already defined.
+   */
+  bool definesName(String name) => map.containsKey(name);
+
+  /**
+   * Apply [f] to each name-meaning pair.
+   */
+  void forEach(void f(String key, _Meaning value)) {
+    map.forEach(f);
+  }
+
+  /**
+   * This method should be invoked after defining all names that are defined
+   * in a library, before defining imported names.
+   */
+  void rememberLibraryNames() {
+    libraryNames.addAll(map.keys);
+  }
+}
+
+/**
  * A [_Meaning] representing a prefix introduced by an import directive.
  */
 class _PrefixMeaning extends _Meaning {
-  final Map<String, _Meaning> namespace = <String, _Meaning>{};
+  final _Namespace namespace = new _Namespace();
 
   _PrefixMeaning() : super(0, ReferenceKind.prefix, 0, 0);
 }
@@ -144,10 +208,9 @@
   /**
    * Names defined inside the library being prelinked.
    */
-  final Map<String, _Meaning> privateNamespace = <String, _Meaning>{
-    'dynamic': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0),
-    'void': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0)
-  };
+  final _Namespace privateNamespace = new _Namespace()
+    ..add('dynamic', new _Meaning(0, ReferenceKind.classOrEnum, 0, 0))
+    ..add('void', new _Meaning(0, ReferenceKind.classOrEnum, 0, 0));
 
   /**
    * List of dependencies of the library being prelinked.  This will be output
@@ -166,8 +229,7 @@
   /**
    * List of public namespaces corresponding to each entry in [dependencies].
    */
-  final List<Map<String, _Meaning>> dependencyToPublicNamespace =
-      <Map<String, _Meaning>>[null];
+  final List<_Namespace> dependencyToPublicNamespace = <_Namespace>[null];
 
   _Prelinker(this.definingUnit, this.getPart, this.getImport,
       this.getDeclaredVariable) {
@@ -180,7 +242,7 @@
    * [definingUnit] via [relativeUri], by aggregating together public namespace
    * information from all of its parts.
    */
-  Map<String, _Meaning> aggregatePublicNamespace(String relativeUri) {
+  _Namespace aggregatePublicNamespace(String relativeUri) {
     if (uriToDependency.containsKey(relativeUri)) {
       return dependencyToPublicNamespace[uriToDependency[relativeUri]];
     }
@@ -192,7 +254,7 @@
         uri: relativeUri, parts: unitUris.sublist(1));
     dependencies.add(linkedDependency);
 
-    Map<String, _Meaning> aggregated = <String, _Meaning>{};
+    _Namespace aggregated = new _Namespace();
 
     for (int unitNum = 0; unitNum < unitUris.length; unitNum++) {
       String unitUri = unitUris[unitNum];
@@ -201,22 +263,29 @@
         continue;
       }
       for (UnlinkedPublicName name in importedNamespace.names) {
-        aggregated.putIfAbsent(name.name, () {
-          if (name.kind == ReferenceKind.classOrEnum) {
-            Map<String, _Meaning> namespace = <String, _Meaning>{};
-            name.members.forEach((executable) {
-              namespace[executable.name] = new _Meaning(
-                  unitNum, executable.kind, 0, executable.numTypeParameters);
-            });
-            return new _ClassMeaning(
-                unitNum, dependency, name.numTypeParameters, namespace);
-          }
-          return new _Meaning(
-              unitNum, name.kind, dependency, name.numTypeParameters);
-        });
+        if (name.kind == ReferenceKind.classOrEnum) {
+          _Namespace namespace = new _Namespace();
+          name.members.forEach((executable) {
+            namespace.add(
+                executable.name,
+                new _Meaning(
+                    unitNum, executable.kind, 0, executable.numTypeParameters));
+          });
+          aggregated.add(
+              name.name,
+              new _ClassMeaning(
+                  unitNum, dependency, name.numTypeParameters, namespace));
+        } else {
+          aggregated.add(
+              name.name,
+              new _Meaning(
+                  unitNum, name.kind, dependency, name.numTypeParameters));
+        }
       }
     }
 
+    aggregated.rememberLibraryNames();
+
     dependencyToPublicNamespace.add(aggregated);
     return aggregated;
   }
@@ -229,38 +298,36 @@
    * If [relativeUri] is `null` (meaning the export namespace of [definingUnit]
    * should be computed), then names defined in [definingUnit] are ignored.
    */
-  Map<String, _Meaning> computeExportNamespace(String relativeUri) {
-    Map<String, _Meaning> exportNamespace = relativeUri == null
-        ? <String, _Meaning>{}
-        : aggregatePublicNamespace(relativeUri);
-    void chaseExports(
-        NameFilter filter, String relativeUri, Set<String> seenUris) {
+  _Namespace computeExportNamespace(String relativeUri) {
+    Set<String> seenUris = new Set<String>();
+    _Namespace chaseExports(String relativeUri, NameFilter filter) {
+      _Namespace exportedNamespace = relativeUri == null
+          ? new _Namespace()
+          : aggregatePublicNamespace(relativeUri);
       if (seenUris.add(relativeUri)) {
-        UnlinkedPublicNamespace exportedNamespace =
-            getImportCached(relativeUri);
-        if (exportedNamespace != null) {
-          for (UnlinkedExportPublic export in exportedNamespace.exports) {
+        UnlinkedPublicNamespace publicNamespace = getImportCached(relativeUri);
+        if (publicNamespace != null) {
+          for (UnlinkedExportPublic export in publicNamespace.exports) {
             String relativeExportUri =
                 _selectUri(export.uri, export.configurations);
             String exportUri = resolveUri(relativeUri, relativeExportUri);
             NameFilter newFilter = filter.merge(
                 new NameFilter.forUnlinkedCombinators(export.combinators));
-            aggregatePublicNamespace(exportUri)
-                .forEach((String name, _Meaning meaning) {
+            _Namespace exportNamespace = chaseExports(exportUri, newFilter);
+            exportNamespace.forEach((String name, _Meaning meaning) {
               if (newFilter.accepts(name) &&
-                  !exportNamespace.containsKey(name)) {
-                exportNamespace[name] = meaning;
+                  !exportedNamespace.definesLibraryName(name)) {
+                exportedNamespace.add(name, meaning);
               }
             });
-            chaseExports(newFilter, exportUri, seenUris);
           }
         }
         seenUris.remove(relativeUri);
       }
+      return exportedNamespace;
     }
 
-    chaseExports(NameFilter.identity, relativeUri, new Set<String>());
-    return exportNamespace;
+    return chaseExports(relativeUri, NameFilter.identity);
   }
 
   /**
@@ -270,51 +337,47 @@
    */
   void extractPrivateNames(UnlinkedUnit unit, int unitNum) {
     for (UnlinkedClass cls in unit.classes) {
-      privateNamespace.putIfAbsent(cls.name, () {
-        Map<String, _Meaning> namespace = <String, _Meaning>{};
-        cls.fields.forEach((field) {
-          if (field.isStatic && field.isConst) {
-            namespace[field.name] =
-                new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
-          }
-        });
-        cls.executables.forEach((executable) {
-          ReferenceKind kind = null;
-          if (executable.kind == UnlinkedExecutableKind.constructor) {
-            kind = ReferenceKind.constructor;
-          } else if (executable.kind ==
-                  UnlinkedExecutableKind.functionOrMethod &&
-              executable.isStatic) {
-            kind = ReferenceKind.method;
-          } else if (executable.kind == UnlinkedExecutableKind.getter &&
-              executable.isStatic) {
-            kind = ReferenceKind.propertyAccessor;
-          }
-          if (kind != null && executable.name.isNotEmpty) {
-            namespace[executable.name] = new _Meaning(
-                unitNum, kind, 0, executable.typeParameters.length);
-          }
-        });
-        return new _ClassMeaning(
-            unitNum, 0, cls.typeParameters.length, namespace);
+      _Namespace namespace = new _Namespace();
+      cls.fields.forEach((field) {
+        if (field.isStatic && field.isConst) {
+          namespace.add(field.name,
+              new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0));
+        }
       });
+      cls.executables.forEach((executable) {
+        ReferenceKind kind = null;
+        if (executable.kind == UnlinkedExecutableKind.constructor) {
+          kind = ReferenceKind.constructor;
+        } else if (executable.kind == UnlinkedExecutableKind.functionOrMethod &&
+            executable.isStatic) {
+          kind = ReferenceKind.method;
+        } else if (executable.kind == UnlinkedExecutableKind.getter &&
+            executable.isStatic) {
+          kind = ReferenceKind.propertyAccessor;
+        }
+        if (kind != null && executable.name.isNotEmpty) {
+          namespace.add(executable.name,
+              new _Meaning(unitNum, kind, 0, executable.typeParameters.length));
+        }
+      });
+      privateNamespace.add(cls.name,
+          new _ClassMeaning(unitNum, 0, cls.typeParameters.length, namespace));
     }
     for (UnlinkedEnum enm in unit.enums) {
-      privateNamespace.putIfAbsent(enm.name, () {
-        Map<String, _Meaning> namespace = <String, _Meaning>{};
-        enm.values.forEach((UnlinkedEnumValue value) {
-          namespace[value.name] =
-              new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
-        });
-        namespace['values'] =
-            new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
-        return new _ClassMeaning(unitNum, 0, 0, namespace);
+      _Namespace namespace = new _Namespace();
+      enm.values.forEach((UnlinkedEnumValue value) {
+        namespace.add(value.name,
+            new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0));
       });
+      namespace.add('values',
+          new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0));
+      privateNamespace.add(
+          enm.name, new _ClassMeaning(unitNum, 0, 0, namespace));
     }
     for (UnlinkedExecutable executable in unit.executables) {
-      privateNamespace.putIfAbsent(
+      privateNamespace.add(
           executable.name,
-          () => new _Meaning(
+          new _Meaning(
               unitNum,
               executable.kind == UnlinkedExecutableKind.functionOrMethod
                   ? ReferenceKind.topLevelFunction
@@ -323,20 +386,18 @@
               executable.typeParameters.length));
     }
     for (UnlinkedTypedef typedef in unit.typedefs) {
-      privateNamespace.putIfAbsent(
+      privateNamespace.add(
           typedef.name,
-          () => new _Meaning(unitNum, ReferenceKind.typedef, 0,
+          new _Meaning(unitNum, ReferenceKind.typedef, 0,
               typedef.typeParameters.length));
     }
     for (UnlinkedVariable variable in unit.variables) {
-      privateNamespace.putIfAbsent(
-          variable.name,
-          () => new _Meaning(
-              unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+      privateNamespace.add(variable.name,
+          new _Meaning(unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
       if (!(variable.isConst || variable.isFinal)) {
-        privateNamespace.putIfAbsent(
+        privateNamespace.add(
             variable.name + '=',
-            () => new _Meaning(
+            new _Meaning(
                 unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
       }
     }
@@ -349,8 +410,8 @@
    * already exist in [result] are not overwritten.
    */
   void filterExportNamespace(String relativeUri,
-      List<UnlinkedCombinator> combinators, Map<String, _Meaning> result) {
-    Map<String, _Meaning> exportNamespace = computeExportNamespace(relativeUri);
+      List<UnlinkedCombinator> combinators, _Namespace result) {
+    _Namespace exportNamespace = computeExportNamespace(relativeUri);
     if (result == null) {
       // This can happen if the import prefix was shadowed by a local name, so
       // the imported symbols are inaccessible.
@@ -358,8 +419,8 @@
     }
     NameFilter filter = new NameFilter.forUnlinkedCombinators(combinators);
     exportNamespace.forEach((String name, _Meaning meaning) {
-      if (filter.accepts(name) && !result.containsKey(name)) {
-        result[name] = meaning;
+      if (filter.accepts(name) && !result.definesLibraryName(name)) {
+        result.add(name, meaning);
       }
     });
   }
@@ -405,7 +466,7 @@
     String uri = import.isImplicit
         ? 'dart:core'
         : _selectUri(import.uri, import.configurations);
-    Map<String, _Meaning> targetNamespace = null;
+    _Namespace targetNamespace = null;
     if (import.prefixReference != 0) {
       // The name introduced by an import declaration can't have a prefix of
       // its own.
@@ -431,12 +492,11 @@
     if (unit == null) {
       return new LinkedUnitBuilder();
     }
-    Map<int, Map<String, _Meaning>> prefixNamespaces =
-        <int, Map<String, _Meaning>>{};
+    Map<int, _Namespace> prefixNamespaces = <int, _Namespace>{};
     List<LinkedReferenceBuilder> references = <LinkedReferenceBuilder>[];
     for (int i = 0; i < unit.references.length; i++) {
       UnlinkedReference reference = unit.references[i];
-      Map<String, _Meaning> namespace;
+      _Namespace namespace;
       if (reference.prefixReference == 0) {
         namespace = privateNamespace;
       } else {
@@ -444,7 +504,7 @@
         assert(reference.prefixReference < i);
         namespace = prefixNamespaces[reference.prefixReference];
         // Expressions like 'a.b.c.d' cannot be prelinked.
-        namespace ??= const <String, _Meaning>{};
+        namespace ??= new _Namespace();
       }
       _Meaning meaning = namespace[reference.name];
       if (meaning != null) {
@@ -485,7 +545,7 @@
     // exports.
     List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
     computeExportNamespace(null).forEach((String name, _Meaning meaning) {
-      if (!privateNamespace.containsKey(name)) {
+      if (!privateNamespace.definesName(name)) {
         exportNames.add(meaning.encodeExportName(name));
       }
     });
@@ -493,12 +553,17 @@
     // Fill in prefixes defined in import declarations.
     for (UnlinkedImport import in units[0].imports) {
       if (import.prefixReference != 0) {
-        privateNamespace.putIfAbsent(
-            units[0].references[import.prefixReference].name,
-            () => new _PrefixMeaning());
+        String name = units[0].references[import.prefixReference].name;
+        if (!privateNamespace.definesName(name)) {
+          privateNamespace.add(name, new _PrefixMeaning());
+        }
       }
     }
 
+    // All the names defined so far are library local, they take precedence
+    // over anything imported from other libraries.
+    privateNamespace.rememberLibraryNames();
+
     // Fill in imported and exported names.
     List<int> importDependencies =
         definingUnit.imports.map(handleImport).toList();
diff --git a/pkg/analyzer/lib/src/summary/pub_summary.dart b/pkg/analyzer/lib/src/summary/pub_summary.dart
index 171c2ff..821b4fc 100644
--- a/pkg/analyzer/lib/src/summary/pub_summary.dart
+++ b/pkg/analyzer/lib/src/summary/pub_summary.dart
@@ -26,7 +26,6 @@
     show serializeAstUnlinked;
 import 'package:analyzer/src/summary/summarize_elements.dart'
     show PackageBundleAssembler;
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
 import 'package:meta/meta.dart';
@@ -241,7 +240,7 @@
       String pathInLib = path.substring(libPath.length);
       String uriPath = pathos.posix.joinAll(pathContext.split(pathInLib));
       String uriStr = 'package:${package.name}/$uriPath';
-      return FastUri.parse(uriStr);
+      return Uri.parse(uriStr);
     }
 
     /**
@@ -689,7 +688,7 @@
       Set<_LinkNode> dependencies = new Set<_LinkNode>();
 
       void appendDependency(String uriStr) {
-        Uri uri = FastUri.parse(uriStr);
+        Uri uri = Uri.parse(uriStr);
         if (!uri.hasScheme) {
           // A relative path in this package, skip it.
         } else if (uri.scheme == 'dart') {
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 8fe29d9..68c3017 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -476,6 +476,9 @@
           Expression expression = _pop();
           _push(AstTestFactory.awaitExpression(expression));
           break;
+        case UnlinkedExprOperation.pushSuper:
+          _push(AstTestFactory.superExpression());
+          break;
         case UnlinkedExprOperation.pushThis:
           _push(AstTestFactory.thisExpression());
           break;
@@ -1191,6 +1194,11 @@
   final String name;
 
   /**
+   * Is `true` if the [element] can be used as a declared type.
+   */
+  final bool isDeclarableType;
+
+  /**
    * The element referred to by this reference, or `null` if there is no
    * associated element (e.g. because it is a reference to an undefined
    * entity).
@@ -1218,8 +1226,14 @@
    * the type itself.  Otherwise, pass `null` and the type will be computed
    * when appropriate.
    */
-  _ReferenceInfo(this.libraryResynthesizer, this.enclosing, this.name,
-      this.element, DartType specialType, this.numTypeParameters) {
+  _ReferenceInfo(
+      this.libraryResynthesizer,
+      this.enclosing,
+      this.name,
+      this.isDeclarableType,
+      this.element,
+      DartType specialType,
+      this.numTypeParameters) {
     if (specialType != null) {
       type = specialType;
     } else {
@@ -1248,9 +1262,7 @@
             : _buildType(instantiateToBoundsAllowed, numTypeArguments,
                 getTypeArgument, implicitFunctionTypeIndices);
     if (result == null) {
-      // TODO(paulberry): figure out how to handle this case (which should
-      // only occur in the event of erroneous code).
-      throw new UnimplementedError();
+      return DynamicTypeImpl.instance;
     }
     return result;
   }
@@ -1277,22 +1289,20 @@
       if (numTypeParameters == 0) {
         return element.type;
       } else if (numTypeArguments == numTypeParameters) {
-        typeArguments = new List<DartType>(numTypeParameters);
-        for (int i = 0; i < numTypeParameters; i++) {
-          typeArguments[i] = getTypeArgument(i);
-        }
+        typeArguments = _buildTypeArguments(numTypeArguments, getTypeArgument);
       }
       InterfaceTypeImpl type =
           new InterfaceTypeImpl.elementWithNameAndArgs(element, name, () {
         if (typeArguments == null) {
-          typeArguments = new List<DartType>.filled(
-              element.typeParameters.length, DynamicTypeImpl.instance);
           if (libraryResynthesizer.summaryResynthesizer.strongMode &&
               instantiateToBoundsAllowed) {
             InterfaceType instantiatedToBounds = libraryResynthesizer
                 .summaryResynthesizer.context.typeSystem
                 .instantiateToBounds(element.type) as InterfaceType;
             return instantiatedToBounds.typeArguments;
+          } else {
+            return new List<DartType>.filled(
+                numTypeParameters, DynamicTypeImpl.instance);
           }
         }
         return typeArguments;
@@ -1305,33 +1315,45 @@
       // Done.
       return type;
     } else if (element is FunctionTypedElement) {
-      int numTypeArguments;
-      FunctionTypedElementComputer computer;
-      if (implicitFunctionTypeIndices.isNotEmpty) {
-        numTypeArguments = numTypeParameters;
-        computer = () {
-          FunctionTypedElement element = this.element;
-          for (int index in implicitFunctionTypeIndices) {
-            element = element.parameters[index].type.element;
-          }
-          return element;
-        };
-      } else if (element is FunctionTypeAliasElementHandle) {
+      if (element is FunctionTypeAliasElementHandle) {
+        List<DartType> typeArguments;
+        if (numTypeArguments == numTypeParameters) {
+          typeArguments =
+              _buildTypeArguments(numTypeArguments, getTypeArgument);
+        } else if (libraryResynthesizer.summaryResynthesizer.strongMode &&
+            instantiateToBoundsAllowed) {
+          FunctionType instantiatedToBounds = libraryResynthesizer
+              .summaryResynthesizer.context.typeSystem
+              .instantiateToBounds(element.type) as FunctionType;
+          typeArguments = instantiatedToBounds.typeArguments;
+        } else {
+          typeArguments = new List<DartType>.filled(
+              numTypeParameters, DynamicTypeImpl.instance);
+        }
         return new FunctionTypeImpl.elementWithNameAndArgs(
-            element,
-            name,
-            _buildTypeArguments(numTypeParameters, getTypeArgument),
-            numTypeParameters != 0);
+            element, name, typeArguments, numTypeParameters != 0);
       } else {
-        // For a type that refers to a generic executable, the type arguments are
-        // not supposed to include the arguments to the executable itself.
-        numTypeArguments = enclosing == null ? 0 : enclosing.numTypeParameters;
-        computer = () => this.element as FunctionTypedElement;
+        FunctionTypedElementComputer computer;
+        if (implicitFunctionTypeIndices.isNotEmpty) {
+          numTypeArguments = numTypeParameters;
+          computer = () {
+            FunctionTypedElement element = this.element;
+            for (int index in implicitFunctionTypeIndices) {
+              element = element.parameters[index].type.element;
+            }
+            return element;
+          };
+        } else {
+          // For a type that refers to a generic executable, the type arguments are
+          // not supposed to include the arguments to the executable itself.
+          numTypeArguments = enclosing?.numTypeParameters ?? 0;
+          computer = () => this.element as FunctionTypedElement;
+        }
+        // TODO(paulberry): Is it a bug that we have to pass `false` for
+        // isInstantiated?
+        return new DeferredFunctionTypeImpl(computer, null,
+            _buildTypeArguments(numTypeArguments, getTypeArgument), false);
       }
-      // TODO(paulberry): Is it a bug that we have to pass `false` for
-      // isInstantiated?
-      return new DeferredFunctionTypeImpl(computer, null,
-          _buildTypeArguments(numTypeArguments, getTypeArgument), false);
     } else {
       return null;
     }
@@ -1345,9 +1367,9 @@
       int numTypeArguments, DartType getTypeArgument(int i)) {
     List<DartType> typeArguments = const <DartType>[];
     if (numTypeArguments != 0) {
-      typeArguments = <DartType>[];
+      typeArguments = new List<DartType>(numTypeArguments);
       for (int i = 0; i < numTypeArguments; i++) {
-        typeArguments.add(getTypeArgument(i));
+        typeArguments[i] = getTypeArgument(i);
       }
     }
     return typeArguments;
@@ -1408,10 +1430,13 @@
   @override
   DartType resolveTypeRef(
       EntityRef type, TypeParameterizedElementMixin typeParameterContext,
-      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+      {bool defaultVoid: false,
+      bool instantiateToBoundsAllowed: true,
+      bool declaredType: false}) {
     return _unitResynthesizer.buildType(type, typeParameterContext,
         defaultVoid: defaultVoid,
-        instantiateToBoundsAllowed: instantiateToBoundsAllowed);
+        instantiateToBoundsAllowed: instantiateToBoundsAllowed,
+        declaredType: declaredType);
   }
 }
 
@@ -1591,7 +1616,9 @@
    */
   DartType buildType(
       EntityRef type, TypeParameterizedElementMixin typeParameterContext,
-      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+      {bool defaultVoid: false,
+      bool instantiateToBoundsAllowed: true,
+      bool declaredType: false}) {
     if (type == null) {
       if (defaultVoid) {
         return VoidTypeImpl.instance;
@@ -1608,13 +1635,17 @@
     } else {
       DartType getTypeArgument(int i) {
         if (i < type.typeArguments.length) {
-          return buildType(type.typeArguments[i], typeParameterContext);
+          return buildType(type.typeArguments[i], typeParameterContext,
+              declaredType: declaredType);
         } else {
           return DynamicTypeImpl.instance;
         }
       }
 
       _ReferenceInfo referenceInfo = getReferenceInfo(type.reference);
+      if (declaredType && !referenceInfo.isDeclarableType) {
+        return DynamicTypeImpl.instance;
+      }
       return referenceInfo.buildType(
           instantiateToBoundsAllowed,
           type.typeArguments.length,
@@ -1714,19 +1745,24 @@
           : null;
       Element element;
       DartType type;
+      bool isDeclarableType = false;
       int numTypeParameters = linkedReference.numTypeParameters;
       if (linkedReference.kind == ReferenceKind.unresolved) {
         type = UndefinedTypeImpl.instance;
         element = null;
+        isDeclarableType = true;
       } else if (name == 'dynamic') {
         type = DynamicTypeImpl.instance;
         element = type.element;
+        isDeclarableType = true;
       } else if (name == 'void') {
         type = VoidTypeImpl.instance;
         element = type.element;
+        isDeclarableType = true;
       } else if (name == '*bottom*') {
         type = BottomTypeImpl.instance;
         element = null;
+        isDeclarableType = true;
       } else {
         List<String> locationComponents;
         if (enclosingInfo != null && enclosingInfo.element is ClassElement) {
@@ -1755,6 +1791,7 @@
         switch (linkedReference.kind) {
           case ReferenceKind.classOrEnum:
             element = new ClassElementHandle(summaryResynthesizer, location);
+            isDeclarableType = true;
             break;
           case ReferenceKind.constructor:
             assert(location.components.length == 4);
@@ -1781,6 +1818,7 @@
           case ReferenceKind.typedef:
             element = new FunctionTypeAliasElementHandle(
                 summaryResynthesizer, location);
+            isDeclarableType = true;
             break;
           case ReferenceKind.variable:
             Element enclosingElement = enclosingInfo.element;
@@ -1810,7 +1848,7 @@
         }
       }
       result = new _ReferenceInfo(libraryResynthesizer, enclosingInfo, name,
-          element, type, numTypeParameters);
+          isDeclarableType, element, type, numTypeParameters);
       referenceInfos[index] = result;
     }
     return result;
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index 35b5029..240fa80 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -99,8 +99,7 @@
   EntityRefBuilder serializeIdentifier(Identifier identifier) {
     EntityRefBuilder b = new EntityRefBuilder();
     if (identifier is SimpleIdentifier) {
-      int index = visitor.serializeSimpleReference(identifier.name,
-          allowTypeParameter: true);
+      int index = visitor.serializeSimpleReference(identifier.name);
       if (index < 0) {
         b.paramReference = -index;
       } else {
@@ -108,6 +107,9 @@
       }
     } else if (identifier is PrefixedIdentifier) {
       int prefix = visitor.serializeSimpleReference(identifier.prefix.name);
+      if (prefix < 0) {
+        throw new StateError('Invalid type parameter usage: $identifier}');
+      }
       b.reference =
           visitor.serializeReference(prefix, identifier.identifier.name);
     } else {
@@ -267,12 +269,6 @@
       <UnlinkedReferenceBuilder>[new UnlinkedReferenceBuilder()];
 
   /**
-   * Map associating names used as prefixes in this compilation unit with their
-   * associated indices into [UnlinkedUnit.references].
-   */
-  final Map<String, int> prefixIndices = <String, int>{};
-
-  /**
    * List of [_Scope]s currently in effect.  This is used to resolve type names
    * to type parameters within classes, typedefs, and executables, as well as
    * references to class members.
@@ -714,8 +710,10 @@
       bool serializeBody) {
     if (body is BlockFunctionBody || body is ExpressionFunctionBody) {
       for (UnlinkedParamBuilder parameter in b.parameters) {
-        parameter.visibleOffset = body.offset;
-        parameter.visibleLength = body.length;
+        if (!parameter.isInitializingFormal) {
+          parameter.visibleOffset = body.offset;
+          parameter.visibleLength = body.length;
+        }
       }
     }
     List<UnlinkedExecutableBuilder> oldExecutables = executables;
@@ -847,10 +845,9 @@
    * Serialize a reference to a name declared either at top level or in a
    * nested scope.
    *
-   * If [allowTypeParameter] is `true`, then references to type
-   * parameters are allowed, and are returned as negative numbers.
+   * References to type parameters are returned as negative numbers.
    */
-  int serializeSimpleReference(String name, {bool allowTypeParameter: false}) {
+  int serializeSimpleReference(String name) {
     int indexOffset = 0;
     for (int i = scopes.length - 1; i >= 0; i--) {
       _Scope scope = scopes[i];
@@ -859,15 +856,9 @@
         if (entity is _ScopedClassMember) {
           return serializeReference(
               serializeReference(null, entity.className), name);
-        } else if (allowTypeParameter && entity is _ScopedTypeParameter) {
+        } else if (entity is _ScopedTypeParameter) {
           int paramReference = indexOffset + entity.index;
           return -paramReference;
-        } else {
-          // Invalid reference to a type parameter.  Should never happen in
-          // legal Dart code.
-          // TODO(paulberry): could this exception ever be uncaught in illegal
-          // code?
-          throw new StateError('Invalid identifier reference');
         }
       }
       if (scope is _TypeParameterScope) {
@@ -913,10 +904,16 @@
         }
         b.reference = serializeReference(null, name);
       } else if (identifier is PrefixedIdentifier) {
-        int prefixIndex = prefixIndices.putIfAbsent(identifier.prefix.name,
-            () => serializeSimpleReference(identifier.prefix.name));
-        b.reference =
-            serializeReference(prefixIndex, identifier.identifier.name);
+        int prefixIndex = serializeSimpleReference(identifier.prefix.name);
+        if (prefixIndex < 0) {
+          // Type parameters are not expected here, so this is an error and the
+          // type should be treated as a reference to `dynamic`.
+          b.reference = serializeReference(null, 'dynamic');
+          return b;
+        } else {
+          b.reference =
+              serializeReference(prefixIndex, identifier.identifier.name);
+        }
       } else {
         throw new StateError(
             'Unexpected identifier type: ${identifier.runtimeType}');
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
index 52ad3bc..46b6958 100644
--- a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -127,6 +127,12 @@
       _serialize(expr);
     } on StateError {
       isValidConst = false;
+      operations.clear();
+      assignmentOperators.clear();
+      ints.clear();
+      doubles.clear();
+      strings.clear();
+      references.clear();
     }
   }
 
@@ -388,6 +394,8 @@
       _serialize(expr.expression);
       references.add(serializeTypeName(expr.type));
       operations.add(UnlinkedExprOperation.typeCheck);
+    } else if (expr is SuperExpression) {
+      operations.add(UnlinkedExprOperation.pushSuper);
     } else if (expr is ThisExpression) {
       operations.add(UnlinkedExprOperation.pushThis);
     } else if (expr is ThrowExpression) {
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index fcdc232..5ac11b7 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -200,7 +200,14 @@
   @override
   InterfaceType get futureOrType {
     assert(_asyncLibrary != null);
-    _futureOrType ??= _getType(_asyncLibrary, "FutureOr");
+    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;
   }
 
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 05528d7..32a8bf4 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -4258,8 +4258,12 @@
     UriValidationCode code =
         UriBasedDirectiveImpl.validateUri(isImport, uriLiteral, uriContent);
     if (code == null) {
-      String encodedUriContent = Uri.encodeFull(uriContent);
-      return context.sourceFactory.resolveUri(_source, encodedUriContent);
+      try {
+        Uri.parse(uriContent);
+      } on FormatException {
+        return null;
+      }
+      return context.sourceFactory.resolveUri(_source, uriContent);
     } else if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) {
       return null;
     } else if (code == UriValidationCode.URI_WITH_INTERPOLATION) {
diff --git a/pkg/analyzer/lib/src/util/fast_uri.dart b/pkg/analyzer/lib/src/util/fast_uri.dart
deleted file mode 100644
index 691a51d..0000000
--- a/pkg/analyzer/lib/src/util/fast_uri.dart
+++ /dev/null
@@ -1,325 +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';
-
-/**
- * Implementation of [Uri] that understands only a limited set of valid
- * URI formats, but works fast. In practice Dart code almost always uses such
- * limited URI format, so almost always can be processed fast.
- */
-class FastUri implements Uri {
-  /***
-   * The maximum [_cache] length before we flush it and start a new generation.
-   */
-  static const int _MAX_CACHE_LENGTH_BEFORE_FLUSH = 50000;
-
-  static HashMap<String, Uri> _cache = new HashMap<String, Uri>();
-  static int _currentCacheLength = 0;
-  static int _currentCacheGeneration = 0;
-
-  static bool _hashUsingText = _shouldComputeHashCodeUsingText();
-
-  final int _cacheGeneration;
-  final String _text;
-  final String _scheme;
-  final bool _hasEmptyAuthority;
-  final String _path;
-
-  /**
-   * The offset of the last `/` in [_text], or `null` if there isn't any.
-   */
-  final int _lastSlashIndex;
-
-  /**
-   * The cached hash code.
-   */
-  int _hashCode;
-
-  Uri _cachedFallbackUri;
-
-  FastUri._(this._cacheGeneration, this._text, this._scheme,
-      this._hasEmptyAuthority, this._path, this._lastSlashIndex);
-
-  @override
-  String get authority => '';
-
-  @override
-  UriData get data => null;
-
-  @override
-  String get fragment => '';
-
-  @override
-  bool get hasAbsolutePath => path.startsWith('/');
-
-  @override
-  bool get hasAuthority => _hasEmptyAuthority;
-
-  @override
-  bool get hasEmptyPath => _path.isEmpty;
-
-  @override
-  bool get hasFragment => false;
-
-  @override
-  int get hashCode {
-    return _hashCode ??= _hashUsingText
-        ? _computeHashUsingText(this)
-        : _computeHashUsingCombine(this);
-  }
-
-  @override
-  bool get hasPort => false;
-
-  @override
-  bool get hasQuery => false;
-
-  @override
-  bool get hasScheme => _scheme.isNotEmpty;
-
-  @override
-  String get host => '';
-
-  @override
-  bool get isAbsolute => hasScheme;
-
-  @override
-  String get origin => _fallbackUri.origin;
-
-  @override
-  String get path => _path;
-
-  @override
-  List<String> get pathSegments => _fallbackUri.pathSegments;
-
-  @override
-  int get port => 0;
-
-  @override
-  String get query => '';
-
-  @override
-  Map<String, String> get queryParameters => const <String, String>{};
-
-  @override
-  Map<String, List<String>> get queryParametersAll =>
-      const <String, List<String>>{};
-
-  @override
-  String get scheme => _scheme;
-
-  @override
-  String get userInfo => '';
-
-  /**
-   * Full [Uri] object computed on demand; we fall back to this for some of the
-   * more complex methods of [Uri] that are less in need of a fast
-   * implementation.
-   */
-  Uri get _fallbackUri => _cachedFallbackUri ??= Uri.parse(_text);
-
-  @override
-  bool operator ==(other) {
-    if (other is FastUri) {
-      if (other._cacheGeneration == _cacheGeneration) {
-        return identical(other, this);
-      }
-      return _text == other._text;
-    } else if (other is Uri) {
-      return _fallbackUri == other;
-    }
-    return false;
-  }
-
-  @override
-  Uri normalizePath() {
-    return this;
-  }
-
-  @override
-  Uri removeFragment() {
-    return this;
-  }
-
-  @override
-  Uri replace(
-      {String scheme,
-      String userInfo,
-      String host,
-      int port,
-      String path,
-      Iterable<String> pathSegments,
-      String query,
-      Map<String, dynamic> queryParameters,
-      String fragment}) {
-    return _fallbackUri.replace(
-        scheme: scheme,
-        userInfo: userInfo,
-        host: host,
-        port: port,
-        path: path,
-        pathSegments: pathSegments,
-        query: query,
-        queryParameters: queryParameters,
-        fragment: fragment);
-  }
-
-  @override
-  Uri resolve(String reference) {
-    // TODO: maybe implement faster
-    return _fallbackUri.resolve(reference);
-  }
-
-  @override
-  Uri resolveUri(Uri reference) {
-    if (reference.hasScheme) {
-      return reference;
-    }
-    String refPath = reference.path;
-    if (refPath.startsWith('./')) {
-      refPath = refPath.substring(2);
-    }
-    if (refPath.startsWith('../') ||
-        refPath.contains('/../') ||
-        refPath.contains('/./') ||
-        refPath.startsWith('/')) {
-      Uri slowResult = _fallbackUri.resolveUri(reference);
-      return FastUri.parse(slowResult.toString());
-    }
-    String newText;
-    if (_lastSlashIndex != null) {
-      newText = _text.substring(0, _lastSlashIndex + 1) + refPath;
-    } else {
-      newText = _text + '/' + refPath;
-    }
-    return FastUri.parse(newText);
-  }
-
-  @override
-  String toFilePath({bool windows}) {
-    return _fallbackUri.toFilePath(windows: windows);
-  }
-
-  @override
-  String toString() => _text;
-
-  /**
-   * Parse the given URI [text] and return the corresponding [Uri] instance.  If
-   * the [text] can be represented as a [FastUri], then it is returned.  If the
-   * [text] is more complex, then `dart:core` [Uri] is created and returned.
-   * This method also performs memoization, so that usually the same instance
-   * of [FastUri] or [Uri] is returned for the same [text].
-   */
-  static Uri parse(String text) {
-    Uri uri = _cache[text];
-    if (uri == null) {
-      uri = _parse(text);
-      uri ??= Uri.parse(text);
-      _cache[text] = uri;
-      _currentCacheLength++;
-      // If the cache is too big, start a new generation.
-      if (_currentCacheLength > _MAX_CACHE_LENGTH_BEFORE_FLUSH) {
-        _cache.clear();
-        _currentCacheLength = 0;
-        _currentCacheGeneration++;
-      }
-    }
-    return uri;
-  }
-
-  /**
-   * This implementation was used before 'fast-URI' in Dart VM.
-   */
-  static int _computeHashUsingCombine(FastUri uri) {
-    // This code is copied from the standard Uri implementation.
-    // It is important that Uri and FastUri generate compatible hashCodes
-    // because Uri and FastUri may be used as keys in the same map.
-    int combine(part, current) {
-      // The sum is truncated to 30 bits to make sure it fits into a Smi.
-      return (current * 31 + part.hashCode) & 0x3FFFFFFF;
-    }
-
-    return combine(
-        uri.scheme,
-        combine(
-            uri.userInfo,
-            combine(
-                uri.host,
-                combine(
-                    uri.port,
-                    combine(uri.path,
-                        combine(uri.query, combine(uri.fragment, 1)))))));
-  }
-
-  /**
-   * This implementation should be used with 'fast-URI' in Dart VM.
-   * https://github.com/dart-lang/sdk/commit/afbbbb97cfcd86a64d0ba5dcfe1ab758954adaf4
-   */
-  static int _computeHashUsingText(FastUri uri) {
-    return uri._text.hashCode;
-  }
-
-  static bool _isAlphabetic(int char) {
-    return char >= 'A'.codeUnitAt(0) && char <= 'Z'.codeUnitAt(0) ||
-        char >= 'a'.codeUnitAt(0) && char <= 'z'.codeUnitAt(0);
-  }
-
-  static bool _isDigit(int char) {
-    return char >= '0'.codeUnitAt(0) && char <= '9'.codeUnitAt(0);
-  }
-
-  /**
-   * Parse the given [text] into a new [FastUri].  If the [text] uses URI
-   * features that are not supported by [FastUri], return `null`.
-   */
-  static FastUri _parse(String text) {
-    int schemeEnd = null;
-    int pathStart = 0;
-    int lastSlashIndex = null;
-    for (int i = 0; i < text.length; i++) {
-      int char = text.codeUnitAt(i);
-      if (_isAlphabetic(char) ||
-          _isDigit(char) ||
-          char == '.'.codeUnitAt(0) ||
-          char == '-'.codeUnitAt(0) ||
-          char == '_'.codeUnitAt(0)) {
-        // Valid characters.
-      } else if (char == '/'.codeUnitAt(0)) {
-        lastSlashIndex = i;
-      } else if (char == ':'.codeUnitAt(0)) {
-        if (schemeEnd != null) {
-          return null;
-        }
-        schemeEnd = i;
-        pathStart = i + 1;
-      } else {
-        return null;
-      }
-    }
-    String scheme = schemeEnd != null ? text.substring(0, schemeEnd) : '';
-    bool hasEmptyAuthority = false;
-    String path = text.substring(pathStart);
-    if (path.startsWith('//')) {
-      hasEmptyAuthority = true;
-      path = path.substring(2);
-      if (!path.startsWith('/')) {
-        return null;
-      }
-    }
-    return new FastUri._(_currentCacheGeneration, text, scheme,
-        hasEmptyAuthority, path, lastSlashIndex);
-  }
-
-  /**
-   * Determine whether VM has the text based hash code computation in [Uri],
-   * or the old combine style.
-   *
-   * See https://github.com/dart-lang/sdk/issues/27159 for details.
-   */
-  static bool _shouldComputeHashCodeUsingText() {
-    String text = 'package:foo/foo.dart';
-    return Uri.parse(text).hashCode == text.hashCode;
-  }
-}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 5232709..55cb642 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,19 +1,19 @@
 name: analyzer
-version: 0.30.0-alpha.0
+version: 0.30.0-alpha.1
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
 environment:
-  sdk: '>=1.12.0 <2.0.0'
+  sdk: '>=1.20.0 <2.0.0'
 dependencies:
   args: '>=0.12.1 <0.14.0'
   charcode: ^1.1.0
   collection: ^1.10.1
   crypto: '>=1.1.1 <3.0.0'
-  front_end: 0.1.0-alpha.0
+  front_end: 0.1.0-alpha.1
   glob: ^1.0.3
   html: '>=0.12.0 <1.14.0'
-  isolate: ^0.2.2
+  isolate: '>=0.2.2 <2.0.0'
   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/visitor_test.dart b/pkg/analyzer/test/dart/ast/visitor_test.dart
index 5c7d14f..0753c10 100644
--- a/pkg/analyzer/test/dart/ast/visitor_test.dart
+++ b/pkg/analyzer/test/dart/ast/visitor_test.dart
@@ -40,7 +40,7 @@
     return null;
   }
 }''';
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(source);
+    CompilationUnit unit = parseCompilationUnit(source);
     List<AstNode> nodes = new List<AstNode>();
     BreadthFirstVisitor<Object> visitor =
         new _BreadthFirstVisitorTestHelper(nodes);
diff --git a/pkg/analyzer/test/dart/element/builder_test.dart b/pkg/analyzer/test/dart/element/builder_test.dart
index b441823..ecbb202 100644
--- a/pkg/analyzer/test/dart/element/builder_test.dart
+++ b/pkg/analyzer/test/dart/element/builder_test.dart
@@ -1030,7 +1030,7 @@
   }
 
   void test_buildLocalElements() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(r'''
+    CompilationUnit unit = parseCompilationUnit(r'''
 main() {
   int v1;
   f1() {
@@ -1074,7 +1074,7 @@
   }
 
   void test_buildParameterInitializer() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit('f({p: 42}) {}');
+    CompilationUnit unit = parseCompilationUnit('f({p: 42}) {}');
     var function = unit.declarations.single as FunctionDeclaration;
     var parameter = function.functionExpression.parameters.parameters.single
         as DefaultFormalParameter;
@@ -1094,7 +1094,7 @@
   }
 
   void test_buildVariableInitializer() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit('var V = 42;');
+    CompilationUnit unit = parseCompilationUnit('var V = 42;');
     TopLevelVariableDeclaration topLevelDecl =
         unit.declarations[0] as TopLevelVariableDeclaration;
     VariableDeclaration variable = topLevelDecl.variables.variables.single;
@@ -1114,7 +1114,7 @@
   }
 
   void test_visitDefaultFormalParameter_local() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit('''
+    CompilationUnit unit = parseCompilationUnit('''
 main() {
   f({bool b: false}) {}
 }
@@ -2538,7 +2538,7 @@
   }
 }
 
-abstract class _BaseTest {
+abstract class _BaseTest extends ParserTestCase {
   CompilationUnitElement compilationUnitElement;
   CompilationUnit _compilationUnit;
 
@@ -2619,7 +2619,7 @@
     TestLogger logger = new TestLogger();
     AnalysisEngine.instance.logger = logger;
     try {
-      _compilationUnit = ParserTestCase.parseCompilationUnit(code);
+      _compilationUnit = parseCompilationUnit(code);
       compilationUnit.accept(visitor);
     } finally {
       expect(logger.log, hasLength(0));
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 5f11129..6356fee 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -1742,8 +1742,8 @@
   }
 
   void _assertHasReturn(bool expectedResult, String source) {
-    Statement statement = ParserTestCase.parseStatement(
-        source, [], enableLazyAssignmentOperators);
+    Statement statement =
+        parseStatement(source, [], enableLazyAssignmentOperators);
     expect(ExitDetector.exits(statement), expectedResult);
   }
 
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index aabfe67..3c95c9d 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -2441,6 +2441,51 @@
     verify([source]);
   }
 
+  test_genericFunctionTypedParameter() async {
+    // Once dartbug.com/28515 is fixed, this syntax should no longer generate an
+    // error.
+    // TODO(paulberry): When dartbug.com/28515 is fixed, convert this into a
+    // NonErrorResolverTest.
+    Source source = addSource('void g(T f<T>(T x)) {}');
+    await computeAnalysisResult(source);
+    var expectedErrorCodes = <ErrorCode>[
+      CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED
+    ];
+    if (enableNewAnalysisDriver) {
+      // Due to dartbug.com/28515, some additional errors appear when using the
+      // new analysis driver.
+      expectedErrorCodes.addAll([
+        StaticWarningCode.UNDEFINED_CLASS,
+        StaticWarningCode.UNDEFINED_CLASS
+      ]);
+    }
+    assertErrors(source, expectedErrorCodes);
+    verify([source]);
+  }
+
+  test_genericFunctionTypedParameter_commentSyntax() async {
+    // Once dartbug.com/28515 is fixed, this syntax should no longer generate an
+    // error.
+    // TODO(paulberry): When dartbug.com/28515 is fixed, convert this into a
+    // NonErrorResolverTest.
+    resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
+    Source source = addSource('void g(/*=T*/ f/*<T>*/(/*=T*/ x)) {}');
+    await computeAnalysisResult(source);
+    var expectedErrorCodes = <ErrorCode>[
+      CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED
+    ];
+    if (enableNewAnalysisDriver) {
+      // Due to dartbug.com/28515, some additional errors appear when using the
+      // new analysis driver.
+      expectedErrorCodes.addAll([
+        StaticWarningCode.UNDEFINED_CLASS,
+        StaticWarningCode.UNDEFINED_CLASS
+      ]);
+    }
+    assertErrors(source, expectedErrorCodes);
+    verify([source]);
+  }
+
   test_getterAndMethodWithSameName() async {
     Source source = addSource(r'''
 class A {
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 9ecac6a..a78bc31 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -225,8 +225,7 @@
   }
 
   test_metadata_libraryDirective_resynthesized() async {
-    CompilationUnit unit =
-        await resolveSource('@a library L; const a = null;');
+    CompilationUnit unit = await resolveSource('@a library L; const a = null;');
     expect(unit.directives.single.metadata.single.name.name, 'a');
     var unitElement = unit.element as CompilationUnitElementImpl;
     // Damage the unit element - as if "setAnnotations" were not called.
@@ -274,6 +273,38 @@
     checkMetadata('part');
   }
 
+  test_metadata_partDirective_resynthesized() async {
+    addNamedSource('/part_a.dart', 'part of L;');
+    addNamedSource('/part_b.dart', 'part of L;');
+
+    CompilationUnit unit = await resolveSource(r'''
+library L;
+
+@a
+part "part_a.dart";
+
+@b
+part "part_b.dart";
+
+const a = null;
+const b = null;
+''');
+    expect(unit.directives[1].metadata.single.name.name, 'a');
+    expect(unit.directives[2].metadata.single.name.name, 'b');
+    var unitElement = unit.element as CompilationUnitElementImpl;
+    // Damage the unit element - as if "setAnnotations" were not called.
+    // The ImportElement(s) still have the metadata, we should use it.
+    unitElement.setAnnotations(unit.directives[1].offset, []);
+    unitElement.setAnnotations(unit.directives[2].offset, []);
+    expect(unitElement.library.parts[0].metadata, hasLength(1));
+    expect(unitElement.library.parts[1].metadata, hasLength(1));
+    // DeclarationResolver on the clone should succeed.
+    CompilationUnit clonedUnit = AstCloner.clone(unit);
+    new DeclarationResolver().resolve(clonedUnit, unit.element);
+    expect(unit.directives[1].metadata.single.name.name, 'a');
+    expect(unit.directives[2].metadata.single.name.name, 'b');
+  }
+
   test_metadata_simpleFormalParameter() async {
     await setupCode('f(@a x) {}) {}');
     checkMetadata('x');
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 52faa6d..21568cc 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -6264,8 +6264,4 @@
   Future<Null> _check_wrongNumberOfParametersForOperator1(String name) async {
     await _check_wrongNumberOfParametersForOperator(name, "a");
   }
-
-  Future<CompilationUnit> _getResolvedLibraryUnit(Source source) async {
-    return analysisContext.getResolvedCompilationUnit2(source, source);
-  }
 }
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
new file mode 100644
index 0000000..9f2a03e
--- /dev/null
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -0,0 +1,356 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:front_end/src/fasta/analyzer/ast_builder.dart';
+import 'package:front_end/src/fasta/analyzer/element_store.dart';
+import 'package:front_end/src/fasta/builder/scope.dart';
+import 'package:front_end/src/fasta/kernel/kernel_builder.dart';
+import 'package:front_end/src/fasta/kernel/kernel_library_builder.dart';
+import 'package:front_end/src/fasta/parser/parser.dart';
+import 'package:front_end/src/fasta/scanner/string_scanner.dart';
+import 'package:front_end/src/fasta/scanner/token.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'parser_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ComplexParserTest_Fasta);
+  });
+}
+
+/**
+ * Type of the "parse..." methods defined in the Fasta parser.
+ */
+typedef Token ParseFunction(Token token);
+
+/**
+ * Proxy implementation of [Builder] used by Fasta parser tests.
+ *
+ * All undeclared identifiers are presumed to resolve via an instance of this
+ * class.
+ */
+class BuilderProxy implements Builder {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Tests of the fasta parser based on [ComplexParserTestMixin].
+ */
+@reflectiveTest
+class ComplexParserTest_Fasta extends FastaParserTestCase
+    with ComplexParserTestMixin {
+  @override
+  @failingTest
+  void test_additiveExpression_precedence_multiplicative_left_withSuper() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_additiveExpression_precedence_multiplicative_left_withSuper();
+  }
+
+  @override
+  @failingTest
+  void test_additiveExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_additiveExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_assignableExpression_arguments_normal_chain() {
+    // TODO(paulberry,ahe): AstBuilder.doInvocation doesn't handle receiver
+    // other than SimpleIdentifier.
+    super.test_assignableExpression_arguments_normal_chain();
+  }
+
+  @override
+  @failingTest
+  void test_assignableExpression_arguments_normal_chain_typeArgumentComments() {
+    // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax.
+    super
+        .test_assignableExpression_arguments_normal_chain_typeArgumentComments();
+  }
+
+  @override
+  @failingTest
+  void test_assignableExpression_arguments_normal_chain_typeArguments() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // endTypeArguments().
+    super.test_assignableExpression_arguments_normal_chain_typeArguments();
+  }
+
+  @override
+  @failingTest
+  void test_assignmentExpression_prefixedIdentifier() {
+    // TODO(paulberry,ahe): Analyzer expects "x.y" to be parsed as a
+    // PrefixedIdentifier, even if x is not a prefix.
+    super.test_assignmentExpression_prefixedIdentifier();
+  }
+
+  @override
+  @failingTest
+  void test_assignmentExpression_propertyAccess() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_assignmentExpression_propertyAccess();
+  }
+
+  @override
+  @failingTest
+  void test_bitwiseAndExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_bitwiseAndExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_bitwiseOrExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_bitwiseOrExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_bitwiseXorExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_bitwiseXorExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_cascade_withAssignment() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // endConstructorReference().
+    super.test_cascade_withAssignment();
+  }
+
+  @override
+  @failingTest
+  void test_conditionalExpression_precedence_nullableType_as() {
+    // TODO(paulberry,ahe): Fasta doesn't support NNBD syntax yet.
+    super.test_conditionalExpression_precedence_nullableType_as();
+  }
+
+  @override
+  @failingTest
+  void test_conditionalExpression_precedence_nullableType_is() {
+    // TODO(paulberry,ahe): Fasta doesn't support NNBD syntax yet.
+    super.test_conditionalExpression_precedence_nullableType_is();
+  }
+
+  @override
+  @failingTest
+  void test_constructor_initializer_withParenthesizedExpression() {
+    // TODO(paulberry): Implement parseCompilationUnitWithOptions
+    super.test_constructor_initializer_withParenthesizedExpression();
+  }
+
+  @override
+  @failingTest
+  void test_equalityExpression_normal() {
+    // TODO(paulberry,ahe): bad error recovery
+    super.test_equalityExpression_normal();
+  }
+
+  @override
+  @failingTest
+  void test_equalityExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_equalityExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_logicalAndExpression_precedence_nullableType() {
+    // TODO(paulberry,ahe): Fasta doesn't support NNBD syntax yet.
+    super.test_logicalAndExpression_precedence_nullableType();
+  }
+
+  @override
+  @failingTest
+  void test_logicalOrExpression_precedence_nullableType() {
+    // TODO(paulberry,ahe): Fasta doesn't support NNBD syntax yet.
+    super.test_logicalOrExpression_precedence_nullableType();
+  }
+
+  @override
+  @failingTest
+  void test_multipleLabels_statement() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement handleLabel().
+    super.test_multipleLabels_statement();
+  }
+
+  @override
+  @failingTest
+  void test_multiplicativeExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_multiplicativeExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_shiftExpression_super() {
+    // TODO(paulberry,ahe): AstBuilder doesn't implement
+    // handleSuperExpression().
+    super.test_shiftExpression_super();
+  }
+
+  @override
+  @failingTest
+  void test_topLevelFunction_nestedGenericFunction() {
+    // TODO(paulberry): Implement parseCompilationUnitWithOptions
+    super.test_topLevelFunction_nestedGenericFunction();
+  }
+}
+
+/**
+ * Proxy implementation of [KernelClassElement] used by Fasta parser tests.
+ *
+ * All undeclared identifiers are presumed to resolve to an instance of this
+ * class.
+ */
+class ElementProxy implements KernelClassElement {
+  @override
+  final KernelInterfaceType rawType = new InterfaceTypeProxy();
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Proxy implementation of [KernelClassElement] used by Fasta parser tests.
+ *
+ * Any request for an element is satisfied by creating an instance of
+ * [ElementProxy].
+ */
+class ElementStoreProxy implements ElementStore {
+  final _elements = <Builder, Element>{};
+
+  @override
+  Element operator [](Builder builder) =>
+      _elements.putIfAbsent(builder, () => new ElementProxy());
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Implementation of [AbstractParserTestCase] specialized for testing the
+ * Fasta parser.
+ */
+class FastaParserTestCase implements AbstractParserTestCase {
+  @override
+  set enableGenericMethodComments(bool value) {
+    if (value == true) {
+      // TODO(paulberry,ahe): generic method comment syntax is not supported by
+      // Fasta.
+      throw new UnimplementedError();
+    }
+  }
+
+  @override
+  set enableNnbd(bool value) {
+    if (value == true) {
+      // TODO(paulberry,ahe): non-null-by-default syntax is not supported by
+      // Fasta.
+      throw new UnimplementedError();
+    }
+  }
+
+  @override
+  CompilationUnit parseCompilationUnit(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
+    // TODO(paulberry): implement parseCompilationUnit
+    throw new UnimplementedError();
+  }
+
+  @override
+  CompilationUnit parseCompilationUnitWithOptions(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
+    // TODO(paulberry): implement parseCompilationUnitWithOptions
+    throw new UnimplementedError();
+  }
+
+  @override
+  Expression parseExpression(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
+    return _runParser(source, (parser) => parser.parseExpression, errorCodes);
+  }
+
+  @override
+  Statement parseStatement(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[],
+      bool enableLazyAssignmentOperators]) {
+    return _runParser(source, (parser) => parser.parseStatement, errorCodes);
+  }
+
+  Object _runParser(String source, ParseFunction getParseFuction(Parser parser),
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
+    if (errorCodes.isNotEmpty) {
+      // TODO(paulberry): Check that the parser generates the proper errors.
+      throw new UnimplementedError();
+    }
+    var scanner = new StringScanner(source);
+    var token = scanner.tokenize();
+    var library = new KernelLibraryBuilderProxy();
+    var member = new BuilderProxy();
+    var elementStore = new ElementStoreProxy();
+    var scope = new ScopeProxy();
+    var astBuilder = new AstBuilder(library, member, elementStore, scope);
+    var parser = new Parser(astBuilder);
+    var parseFunction = getParseFuction(parser);
+    var endToken = parseFunction(token);
+    expect(endToken.isEof, isTrue);
+    expect(astBuilder.stack, hasLength(1));
+    return astBuilder.pop();
+  }
+}
+
+/**
+ * Proxy implementation of [KernelClassElement] used by Fasta parser tests.
+ *
+ * Any element used as a type name is presumed to refer to an instance of this
+ * class.
+ */
+class InterfaceTypeProxy implements KernelInterfaceType {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Proxy implementation of [KernelLibraryBuilderProxy] used by Fasta parser
+ * tests.
+ */
+class KernelLibraryBuilderProxy implements KernelLibraryBuilder {
+  @override
+  final uri = Uri.parse('file:///test.dart');
+
+  @override
+  Uri get fileUri => uri;
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Proxy implementation of [Scope] used by Fasta parser tests.
+ *
+ * Any name lookup request is satisfied by creating an instance of
+ * [BuilderProxy].
+ */
+class ScopeProxy implements Scope {
+  final _locals = <String, Builder>{};
+
+  @override
+  Builder lookup(String name, int charOffset, Uri fileUri) =>
+      _locals.putIfAbsent(name, () => new BuilderProxy());
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 77f83b2..914abd0 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -34,6 +34,30 @@
 }
 
 /**
+ * Abstract base class for parser tests, which does not make assumptions about
+ * which parser is used.
+ */
+abstract class AbstractParserTestCase {
+  void set enableGenericMethodComments(bool value);
+
+  void set enableNnbd(bool value);
+
+  CompilationUnit parseCompilationUnit(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]);
+
+  /// TODO(paulberry): merge with [parseCompilationUnit]
+  CompilationUnit parseCompilationUnitWithOptions(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]);
+
+  Expression parseExpression(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]);
+
+  Statement parseStatement(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[],
+      bool enableLazyAssignmentOperators]);
+}
+
+/**
  * Instances of the class `AstValidator` are used to validate the correct construction of an
  * AST structure.
  */
@@ -109,14 +133,19 @@
 }
 
 /**
+ * Tests of the analyzer parser based on [ComplexParserTestMixin].
+ */
+@reflectiveTest
+class ComplexParserTest extends ParserTestCase with ComplexParserTestMixin {}
+
+/**
  * The class `ComplexParserTest` defines parser tests that test the parsing of more complex
  * code fragments or the interactions between multiple parsing methods. For example, tests to ensure
  * that the precedence of operations is being handled correctly should be defined in this class.
  *
  * Simpler tests should be defined in the class [SimpleParserTest].
  */
-@reflectiveTest
-class ComplexParserTest extends ParserTestCase {
+abstract class ComplexParserTestMixin implements AbstractParserTestCase {
   void test_additiveExpression_normal() {
     BinaryExpression expression = parseExpression("x + y - z");
     EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
@@ -367,7 +396,7 @@
   }
 
   void test_constructor_initializer_withParenthesizedExpression() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(r'''
+    CompilationUnit unit = parseCompilationUnit(r'''
 class C {
   C() :
     this.a = (b == null ? c : d) {
@@ -470,8 +499,7 @@
   }
 
   void test_multipleLabels_statement() {
-    LabeledStatement statement =
-        ParserTestCase.parseStatement("a: b: c: return x;");
+    LabeledStatement statement = parseStatement("a: b: c: return x;");
     expect(statement.labels, hasLength(3));
     EngineTestCase.assertInstanceOf(
         (obj) => obj is ReturnStatement, ReturnStatement, statement.statement);
@@ -624,42 +652,42 @@
   }
 
   void test_abstractEnum() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "abstract enum E {ONE}", [ParserErrorCode.ABSTRACT_ENUM]);
   }
 
   void test_abstractTopLevelFunction_function() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "abstract f(v) {}", [ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION]);
   }
 
   void test_abstractTopLevelFunction_getter() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "abstract get m {}", [ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION]);
   }
 
   void test_abstractTopLevelFunction_setter() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "abstract set m(v) {}", [ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION]);
   }
 
   void test_abstractTopLevelVariable() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "abstract C f;", [ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE]);
   }
 
   void test_abstractTypeDef() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "abstract typedef F();", [ParserErrorCode.ABSTRACT_TYPEDEF]);
   }
 
   void test_annotationOnEnumConstant_first() {
-    ParserTestCase.parseCompilationUnit("enum E { @override C }",
+    parseCompilationUnit("enum E { @override C }",
         [ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT]);
   }
 
   void test_annotationOnEnumConstant_middle() {
-    ParserTestCase.parseCompilationUnit("enum E { C, @override D, E }",
+    parseCompilationUnit("enum E { C, @override D, E }",
         [ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT]);
   }
 
@@ -699,21 +727,21 @@
   }
 
   void test_breakOutsideOfLoop_functionExpression_inALoop() {
-    ParserTestCase.parseStatement(
+    parseStatement(
         "for(; x;) {() {break;};}", [ParserErrorCode.BREAK_OUTSIDE_OF_LOOP]);
   }
 
   void test_breakOutsideOfLoop_functionExpression_withALoop() {
-    ParserTestCase.parseStatement("() {for (; x;) {break;}};");
+    parseStatement("() {for (; x;) {break;}};");
   }
 
   void test_classInClass_abstract() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "class C { abstract class B {} }", [ParserErrorCode.CLASS_IN_CLASS]);
   }
 
   void test_classInClass_nonAbstract() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "class C { class B {} }", [ParserErrorCode.CLASS_IN_CLASS]);
   }
 
@@ -721,15 +749,14 @@
     // This syntax has been removed from the language in favor of
     // "abstract class A = B with C;" (issue 18098).
     createParser('class A = abstract B with C;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes(
         [ParserErrorCode.EXPECTED_TOKEN, ParserErrorCode.EXPECTED_TOKEN]);
   }
 
   void test_colonInPlaceOfIn() {
-    ParserTestCase.parseStatement(
+    parseStatement(
         "for (var x : list) {}", [ParserErrorCode.COLON_IN_PLACE_OF_IN]);
   }
 
@@ -755,8 +782,7 @@
   }
 
   void test_constClass() {
-    ParserTestCase.parseCompilationUnit(
-        "const class C {}", [ParserErrorCode.CONST_CLASS]);
+    parseCompilationUnit("const class C {}", [ParserErrorCode.CONST_CLASS]);
   }
 
   void test_constConstructorWithBody() {
@@ -768,8 +794,7 @@
   }
 
   void test_constEnum() {
-    ParserTestCase.parseCompilationUnit(
-        "const enum E {ONE}", [ParserErrorCode.CONST_ENUM]);
+    parseCompilationUnit("const enum E {ONE}", [ParserErrorCode.CONST_ENUM]);
   }
 
   void test_constFactory() {
@@ -803,8 +828,7 @@
   }
 
   void test_constTypedef() {
-    ParserTestCase.parseCompilationUnit(
-        "const typedef F();", [ParserErrorCode.CONST_TYPEDEF]);
+    parseCompilationUnit("const typedef F();", [ParserErrorCode.CONST_TYPEDEF]);
   }
 
   void test_continueOutsideOfLoop_continueInDoStatement() {
@@ -843,12 +867,12 @@
   }
 
   void test_continueOutsideOfLoop_functionExpression_inALoop() {
-    ParserTestCase.parseStatement("for(; x;) {() {continue;};}",
+    parseStatement("for(; x;) {() {continue;};}",
         [ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP]);
   }
 
   void test_continueOutsideOfLoop_functionExpression_withALoop() {
-    ParserTestCase.parseStatement("() {for (; x;) {continue;}};");
+    parseStatement("() {for (; x;) {continue;}};");
   }
 
   void test_continueWithoutLabelInCase_error() {
@@ -889,8 +913,7 @@
 
   void test_covariantConstructor() {
     createParser('class C { covariant C(); }');
-    ClassDeclaration member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    ClassDeclaration member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.COVARIANT_CONSTRUCTOR]);
   }
@@ -918,8 +941,7 @@
 
   void test_covariantTopLevelDeclaration_class() {
     createParser('covariant class C {}');
-    ClassDeclaration member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    ClassDeclaration member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes(
         [ParserErrorCode.COVARIANT_TOP_LEVEL_DECLARATION]);
@@ -927,15 +949,14 @@
 
   void test_covariantTopLevelDeclaration_enum() {
     createParser('covariant enum E { v }');
-    EnumDeclaration member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    EnumDeclaration member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes(
         [ParserErrorCode.COVARIANT_TOP_LEVEL_DECLARATION]);
   }
 
   void test_covariantTopLevelDeclaration_typedef() {
-    ParserTestCase.parseCompilationUnit("covariant typedef F();",
+    parseCompilationUnit("covariant typedef F();",
         [ParserErrorCode.COVARIANT_TOP_LEVEL_DECLARATION]);
   }
 
@@ -967,14 +988,13 @@
   }
 
   void test_directiveAfterDeclaration_classBeforeDirective() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
-        "class Foo{} library l;",
+    CompilationUnit unit = parseCompilationUnit("class Foo{} library l;",
         [ParserErrorCode.DIRECTIVE_AFTER_DECLARATION]);
     expect(unit, isNotNull);
   }
 
   void test_directiveAfterDeclaration_classBetweenDirectives() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "library l;\nclass Foo{}\npart 'a.dart';",
         [ParserErrorCode.DIRECTIVE_AFTER_DECLARATION]);
     expect(unit, isNotNull);
@@ -1032,14 +1052,13 @@
 
   void test_emptyEnumBody() {
     createParser('enum E {}');
-    EnumDeclaration declaration =
-        parser.parseEnumDeclaration(emptyCommentAndMetadata());
+    EnumDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertErrorsWithCodes([ParserErrorCode.EMPTY_ENUM_BODY]);
   }
 
   void test_enumInClass() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 class Foo {
   enum Bar {
@@ -1095,32 +1114,28 @@
 
   void test_expectedExecutable_topLevel_afterType() {
     createParser('heart 2 heart');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.EXPECTED_EXECUTABLE]);
   }
 
   void test_expectedExecutable_topLevel_afterVoid() {
     createParser('void 2 void');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.EXPECTED_EXECUTABLE]);
   }
 
   void test_expectedExecutable_topLevel_beforeType() {
     createParser('4 score');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.EXPECTED_EXECUTABLE]);
   }
 
   void test_expectedExecutable_topLevel_eof() {
     createParser('x');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrors(
         [new AnalysisError(null, 0, 1, ParserErrorCode.EXPECTED_EXECUTABLE)]);
@@ -1176,12 +1191,12 @@
   }
 
   void test_expectedToken_parseStatement_afterVoid() {
-    ParserTestCase.parseStatement("void}",
+    parseStatement("void}",
         [ParserErrorCode.EXPECTED_TOKEN, ParserErrorCode.MISSING_IDENTIFIER]);
   }
 
   void test_expectedToken_semicolonMissingAfterExport() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "export '' class A {}", [ParserErrorCode.EXPECTED_TOKEN]);
     ExportDirective directive = unit.directives[0] as ExportDirective;
     Token semicolon = directive.semicolon;
@@ -1190,11 +1205,11 @@
   }
 
   void test_expectedToken_semicolonMissingAfterExpression() {
-    ParserTestCase.parseStatement("x", [ParserErrorCode.EXPECTED_TOKEN]);
+    parseStatement("x", [ParserErrorCode.EXPECTED_TOKEN]);
   }
 
   void test_expectedToken_semicolonMissingAfterImport() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "import '' class A {}", [ParserErrorCode.EXPECTED_TOKEN]);
     ImportDirective directive = unit.directives[0] as ImportDirective;
     Token semicolon = directive.semicolon;
@@ -1203,8 +1218,7 @@
   }
 
   void test_expectedToken_whileMissingInDoStatement() {
-    ParserTestCase
-        .parseStatement("do {} (x);", [ParserErrorCode.EXPECTED_TOKEN]);
+    parseStatement("do {} (x);", [ParserErrorCode.EXPECTED_TOKEN]);
   }
 
   void test_expectedTypeName_as() {
@@ -1224,7 +1238,7 @@
   }
 
   void test_exportDirectiveAfterPartDirective() {
-    ParserTestCase.parseCompilationUnit("part 'a.dart'; export 'b.dart';",
+    parseCompilationUnit("part 'a.dart'; export 'b.dart';",
         [ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE]);
   }
 
@@ -1250,7 +1264,7 @@
   }
 
   void test_externalClass() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "external class C {}", [ParserErrorCode.EXTERNAL_CLASS]);
   }
 
@@ -1271,7 +1285,7 @@
   }
 
   void test_externalEnum() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "external enum E {ONE}", [ParserErrorCode.EXTERNAL_ENUM]);
   }
 
@@ -1340,7 +1354,7 @@
   }
 
   void test_externalTypedef() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "external typedef F();", [ParserErrorCode.EXTERNAL_TYPEDEF]);
   }
 
@@ -1380,17 +1394,17 @@
   }
 
   void test_factoryTopLevelDeclaration_class() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "factory class C {}", [ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION]);
   }
 
   void test_factoryTopLevelDeclaration_enum() {
-    ParserTestCase.parseCompilationUnit("factory enum E { v }",
+    parseCompilationUnit("factory enum E { v }",
         [ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION]);
   }
 
   void test_factoryTopLevelDeclaration_typedef() {
-    ParserTestCase.parseCompilationUnit("factory typedef F();",
+    parseCompilationUnit("factory typedef F();",
         [ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION]);
   }
 
@@ -1431,8 +1445,7 @@
   }
 
   void test_finalClass() {
-    ParserTestCase.parseCompilationUnit(
-        "final class C {}", [ParserErrorCode.FINAL_CLASS]);
+    parseCompilationUnit("final class C {}", [ParserErrorCode.FINAL_CLASS]);
   }
 
   void test_finalConstructor() {
@@ -1443,8 +1456,7 @@
   }
 
   void test_finalEnum() {
-    ParserTestCase.parseCompilationUnit(
-        "final enum E {ONE}", [ParserErrorCode.FINAL_ENUM]);
+    parseCompilationUnit("final enum E {ONE}", [ParserErrorCode.FINAL_ENUM]);
   }
 
   void test_finalMethod() {
@@ -1455,44 +1467,41 @@
   }
 
   void test_finalTypedef() {
-    ParserTestCase.parseCompilationUnit(
-        "final typedef F();", [ParserErrorCode.FINAL_TYPEDEF]);
+    parseCompilationUnit("final typedef F();", [ParserErrorCode.FINAL_TYPEDEF]);
   }
 
   void test_functionTypedParameter_const() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "void f(const x()) {}", [ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR]);
   }
 
   void test_functionTypedParameter_final() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "void f(final x()) {}", [ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR]);
   }
 
   void test_functionTypedParameter_var() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "void f(var x()) {}", [ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR]);
   }
 
   void test_getterInFunction_block_noReturnType() {
-    FunctionDeclarationStatement statement = ParserTestCase.parseStatement(
+    FunctionDeclarationStatement statement = parseStatement(
         "get x { return _x; }", [ParserErrorCode.GETTER_IN_FUNCTION]);
     expect(statement.functionDeclaration.functionExpression.parameters, isNull);
   }
 
   void test_getterInFunction_block_returnType() {
-    ParserTestCase.parseStatement(
+    parseStatement(
         "int get x { return _x; }", [ParserErrorCode.GETTER_IN_FUNCTION]);
   }
 
   void test_getterInFunction_expression_noReturnType() {
-    ParserTestCase
-        .parseStatement("get x => _x;", [ParserErrorCode.GETTER_IN_FUNCTION]);
+    parseStatement("get x => _x;", [ParserErrorCode.GETTER_IN_FUNCTION]);
   }
 
   void test_getterInFunction_expression_returnType() {
-    ParserTestCase.parseStatement(
-        "int get x => _x;", [ParserErrorCode.GETTER_IN_FUNCTION]);
+    parseStatement("int get x => _x;", [ParserErrorCode.GETTER_IN_FUNCTION]);
   }
 
   void test_getterWithParameters() {
@@ -1543,18 +1552,17 @@
   }
 
   void test_implementsBeforeExtends() {
-    ParserTestCase.parseCompilationUnit("class A implements B extends C {}",
+    parseCompilationUnit("class A implements B extends C {}",
         [ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS]);
   }
 
   void test_implementsBeforeWith() {
-    ParserTestCase.parseCompilationUnit(
-        "class A extends B implements C with D {}",
+    parseCompilationUnit("class A extends B implements C with D {}",
         [ParserErrorCode.IMPLEMENTS_BEFORE_WITH]);
   }
 
   void test_importDirectiveAfterPartDirective() {
-    ParserTestCase.parseCompilationUnit("part 'a.dart'; import 'b.dart';",
+    parseCompilationUnit("part 'a.dart'; import 'b.dart';",
         [ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE]);
   }
 
@@ -1734,34 +1742,33 @@
   }
 
   void test_libraryDirectiveNotFirst() {
-    ParserTestCase.parseCompilationUnit("import 'x.dart'; library l;",
+    parseCompilationUnit("import 'x.dart'; library l;",
         [ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST]);
   }
 
   void test_libraryDirectiveNotFirst_afterPart() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
-        "part 'a.dart';\nlibrary l;",
+    CompilationUnit unit = parseCompilationUnit("part 'a.dart';\nlibrary l;",
         [ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST]);
     expect(unit, isNotNull);
   }
 
   void test_localFunctionDeclarationModifier_abstract() {
-    ParserTestCase.parseStatement("abstract f() {}",
+    parseStatement("abstract f() {}",
         [ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER]);
   }
 
   void test_localFunctionDeclarationModifier_external() {
-    ParserTestCase.parseStatement("external f() {}",
+    parseStatement("external f() {}",
         [ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER]);
   }
 
   void test_localFunctionDeclarationModifier_factory() {
-    ParserTestCase.parseStatement("factory f() {}",
+    parseStatement("factory f() {}",
         [ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER]);
   }
 
   void test_localFunctionDeclarationModifier_static() {
-    ParserTestCase.parseStatement(
+    parseStatement(
         "static f() {}", [ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER]);
   }
 
@@ -1888,7 +1895,7 @@
   }
 
   void test_missingClassBody() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "class A class B {}", [ParserErrorCode.MISSING_CLASS_BODY]);
   }
 
@@ -1905,7 +1912,7 @@
   }
 
   void test_missingConstFinalVarOrType_static() {
-    ParserTestCase.parseCompilationUnit("class A { static f; }",
+    parseCompilationUnit("class A { static f; }",
         [ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE]);
   }
 
@@ -1919,8 +1926,7 @@
 
   void test_missingEnumBody() {
     createParser('enum E;');
-    EnumDeclaration declaration =
-        parser.parseEnumDeclaration(emptyCommentAndMetadata());
+    EnumDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertErrorsWithCodes([ParserErrorCode.MISSING_ENUM_BODY]);
   }
@@ -1962,7 +1968,7 @@
     // The parser does not recognize this as a function declaration, so it tries
     // to parse it as an expression statement. It isn't clear what the best
     // error message is in this case.
-    ParserTestCase.parseStatement(
+    parseStatement(
         "int f { return x;}", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
   }
 
@@ -1971,39 +1977,39 @@
     // The parser does not recognize this as a function declaration, so it tries
     // to parse it as an expression statement. It isn't clear what the best
     // error message is in this case.
-    ParserTestCase.parseStatement(
+    parseStatement(
         "int f => x;", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
   }
 
   void test_missingFunctionParameters_local_void_block() {
-    ParserTestCase.parseStatement(
+    parseStatement(
         "void f { return x;}", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
   }
 
   void test_missingFunctionParameters_local_void_expression() {
-    ParserTestCase.parseStatement(
+    parseStatement(
         "void f => x;", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
   }
 
   void test_missingFunctionParameters_topLevel_nonVoid_block() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "int f { return x;}", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
   }
 
   void test_missingFunctionParameters_topLevel_nonVoid_expression() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "int f => x;", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
   }
 
   void test_missingFunctionParameters_topLevel_void_block() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "void f { return x;}", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
     FunctionDeclaration funct = unit.declarations[0];
     expect(funct.functionExpression.parameters, hasLength(0));
   }
 
   void test_missingFunctionParameters_topLevel_void_expression() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "void f => x;", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
     FunctionDeclaration funct = unit.declarations[0];
     expect(funct.functionExpression.parameters, hasLength(0));
@@ -2026,8 +2032,7 @@
 
   void test_missingIdentifier_inEnum() {
     createParser('enum E {, TWO}');
-    EnumDeclaration declaration =
-        parser.parseEnumDeclaration(emptyCommentAndMetadata());
+    EnumDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertErrorsWithCodes([ParserErrorCode.MISSING_IDENTIFIER]);
   }
@@ -2063,8 +2068,7 @@
 
   void test_missingKeywordOperator() {
     createParser('+(x) {}');
-    MethodDeclaration method =
-        parser.parseOperator(emptyCommentAndMetadata(), null, null);
+    MethodDeclaration method = parser.parseClassMember('C');
     expectNotNullIfNoErrors(method);
     listener.assertErrorsWithCodes([ParserErrorCode.MISSING_KEYWORD_OPERATOR]);
   }
@@ -2139,19 +2143,19 @@
   }
 
   void test_missingNameInLibraryDirective() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "library;", [ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE]);
     expect(unit, isNotNull);
   }
 
   void test_missingNameInPartOfDirective() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "part of;", [ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE]);
     expect(unit, isNotNull);
   }
 
   void test_missingPrefixInDeferredImport() {
-    ParserTestCase.parseCompilationUnit("import 'foo.dart' deferred;",
+    parseCompilationUnit("import 'foo.dart' deferred;",
         [ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT]);
   }
 
@@ -2163,11 +2167,11 @@
   }
 
   void test_missingStatement() {
-    ParserTestCase.parseStatement("is", [ParserErrorCode.MISSING_STATEMENT]);
+    parseStatement("is", [ParserErrorCode.MISSING_STATEMENT]);
   }
 
   void test_missingStatement_afterVoid() {
-    ParserTestCase.parseStatement("void;", [ParserErrorCode.MISSING_STATEMENT]);
+    parseStatement("void;", [ParserErrorCode.MISSING_STATEMENT]);
   }
 
   void test_missingTerminatorForParameterGroup_named() {
@@ -2187,17 +2191,17 @@
   }
 
   void test_missingTypedefParameters_nonVoid() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "typedef int F;", [ParserErrorCode.MISSING_TYPEDEF_PARAMETERS]);
   }
 
   void test_missingTypedefParameters_typeParameters() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "typedef F<E>;", [ParserErrorCode.MISSING_TYPEDEF_PARAMETERS]);
   }
 
   void test_missingTypedefParameters_void() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "typedef void F;", [ParserErrorCode.MISSING_TYPEDEF_PARAMETERS]);
   }
 
@@ -2224,22 +2228,21 @@
   }
 
   void test_mixin_application_lacks_with_clause() {
-    ParserTestCase.parseCompilationUnit(
-        "class Foo = Bar;", [ParserErrorCode.EXPECTED_TOKEN]);
+    parseCompilationUnit("class Foo = Bar;", [ParserErrorCode.EXPECTED_TOKEN]);
   }
 
   void test_multipleExtendsClauses() {
-    ParserTestCase.parseCompilationUnit("class A extends B extends C {}",
+    parseCompilationUnit("class A extends B extends C {}",
         [ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES]);
   }
 
   void test_multipleImplementsClauses() {
-    ParserTestCase.parseCompilationUnit("class A implements B implements C {}",
+    parseCompilationUnit("class A implements B implements C {}",
         [ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES]);
   }
 
   void test_multipleLibraryDirectives() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "library l; library m;", [ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES]);
   }
 
@@ -2252,7 +2255,7 @@
   }
 
   void test_multiplePartOfDirectives() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "part of l; part of m;", [ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES]);
   }
 
@@ -2273,7 +2276,7 @@
   }
 
   void test_multipleWithClauses() {
-    ParserTestCase.parseCompilationUnit("class A extends B with C with D {}",
+    parseCompilationUnit("class A extends B with C with D {}",
         [ParserErrorCode.MULTIPLE_WITH_CLAUSES]);
   }
 
@@ -2311,24 +2314,24 @@
   }
 
   void test_nonIdentifierLibraryName_library() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "library 'lib';", [ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME]);
     expect(unit, isNotNull);
   }
 
   void test_nonIdentifierLibraryName_partOf() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "part of 'lib';", [ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME]);
     expect(unit, isNotNull);
   }
 
   void test_nonPartOfDirectiveInPart_after() {
-    ParserTestCase.parseCompilationUnit("part of l; part 'f.dart';",
+    parseCompilationUnit("part of l; part 'f.dart';",
         [ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART]);
   }
 
   void test_nonPartOfDirectiveInPart_before() {
-    ParserTestCase.parseCompilationUnit("part 'f.dart'; part of m;",
+    parseCompilationUnit("part 'f.dart'; part of m;",
         [ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART]);
   }
 
@@ -2374,12 +2377,12 @@
   }
 
   void test_optionalAfterNormalParameters_named() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "f({a}, b) {}", [ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS]);
   }
 
   void test_optionalAfterNormalParameters_positional() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "f([a], b) {}", [ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS]);
   }
 
@@ -2448,13 +2451,11 @@
   }
 
   void test_setterInFunction_block() {
-    ParserTestCase.parseStatement(
-        "set x(v) {_x = v;}", [ParserErrorCode.SETTER_IN_FUNCTION]);
+    parseStatement("set x(v) {_x = v;}", [ParserErrorCode.SETTER_IN_FUNCTION]);
   }
 
   void test_setterInFunction_expression() {
-    ParserTestCase.parseStatement(
-        "set x(v) => _x = v;", [ParserErrorCode.SETTER_IN_FUNCTION]);
+    parseStatement("set x(v) => _x = v;", [ParserErrorCode.SETTER_IN_FUNCTION]);
   }
 
   void test_staticAfterConst() {
@@ -2516,32 +2517,32 @@
   }
 
   void test_staticTopLevelDeclaration_class() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "static class C {}", [ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION]);
   }
 
   void test_staticTopLevelDeclaration_enum() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "static enum E { v }", [ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION]);
   }
 
   void test_staticTopLevelDeclaration_function() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "static f() {}", [ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION]);
   }
 
   void test_staticTopLevelDeclaration_typedef() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "static typedef F();", [ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION]);
   }
 
   void test_staticTopLevelDeclaration_variable() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "static var x;", [ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION]);
   }
 
   void test_string_unterminated_interpolation_block() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 m() {
  {
@@ -2598,8 +2599,7 @@
 
   void test_topLevel_getter() {
     createParser('get x => 7;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -2609,30 +2609,27 @@
 
   void test_topLevelOperator_withoutType() {
     createParser('operator +(bool x, bool y) => x | y;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.TOP_LEVEL_OPERATOR]);
   }
 
   void test_topLevelOperator_withType() {
     createParser('bool operator +(bool x, bool y) => x | y;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.TOP_LEVEL_OPERATOR]);
   }
 
   void test_topLevelOperator_withVoid() {
     createParser('void operator +(bool x, bool y) => x | y;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.TOP_LEVEL_OPERATOR]);
   }
 
   void test_topLevelVariable_withMetadata() {
-    ParserTestCase.parseCompilationUnit("String @A string;", [
+    parseCompilationUnit("String @A string;", [
       ParserErrorCode.MISSING_IDENTIFIER,
       ParserErrorCode.EXPECTED_TOKEN,
       ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
@@ -2640,12 +2637,12 @@
   }
 
   void test_typedefInClass_withoutReturnType() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "class C { typedef F(x); }", [ParserErrorCode.TYPEDEF_IN_CLASS]);
   }
 
   void test_typedefInClass_withReturnType() {
-    ParserTestCase.parseCompilationUnit("class C { typedef int F(int x); }",
+    parseCompilationUnit("class C { typedef int F(int x); }",
         [ParserErrorCode.TYPEDEF_IN_CLASS]);
   }
 
@@ -2666,8 +2663,7 @@
   }
 
   void test_unexpectedToken_endOfFieldDeclarationStatement() {
-    ParserTestCase.parseStatement(
-        "String s = (null));", [ParserErrorCode.UNEXPECTED_TOKEN]);
+    parseStatement("String s = (null));", [ParserErrorCode.UNEXPECTED_TOKEN]);
   }
 
   @failingTest
@@ -2678,28 +2674,26 @@
   }
 
   void test_unexpectedToken_returnInExpressionFuntionBody() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "f() => return null;", [ParserErrorCode.UNEXPECTED_TOKEN]);
   }
 
   void test_unexpectedToken_semicolonBetweenClassMembers() {
     createParser('class C { int x; ; int y;}');
-    ClassDeclaration declaration =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    ClassDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertErrorsWithCodes([ParserErrorCode.UNEXPECTED_TOKEN]);
   }
 
   void test_unexpectedToken_semicolonBetweenCompilationUnitMembers() {
-    ParserTestCase.parseCompilationUnit(
-        "int x; ; int y;", [ParserErrorCode.UNEXPECTED_TOKEN]);
+    parseCompilationUnit("int x; ; int y;", [ParserErrorCode.UNEXPECTED_TOKEN]);
   }
 
   void test_unterminatedString_at_eof() {
     // Although the "unterminated string" error message is produced by the
     // scanner, we need to verify that the parser can handle the tokens
     // produced by the scanner when an unterminated string is encountered.
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 void main() {
   var x = "''',
@@ -2714,7 +2708,7 @@
     // Although the "unterminated string" error message is produced by the
     // scanner, we need to verify that the parser can handle the tokens
     // produced by the scanner when an unterminated string is encountered.
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 void main() {
   var x = "
@@ -2728,7 +2722,7 @@
     // Although the "unterminated string" error message is produced by the
     // scanner, we need to verify that the parser can handle the tokens
     // produced by the scanner when an unterminated string is encountered.
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 void main() {
   var x = """''',
@@ -2743,7 +2737,7 @@
     // Although the "unterminated string" error message is produced by the
     // scanner, we need to verify that the parser can handle the tokens
     // produced by the scanner when an unterminated string is encountered.
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 void main() {
   var x = """"''',
@@ -2758,7 +2752,7 @@
     // Although the "unterminated string" error message is produced by the
     // scanner, we need to verify that the parser can handle the tokens
     // produced by the scanner when an unterminated string is encountered.
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 void main() {
   var x = """""''',
@@ -2780,7 +2774,7 @@
   }
 
   void test_varAndType_field() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "class C { var int x; }", [ParserErrorCode.VAR_AND_TYPE]);
   }
 
@@ -2788,7 +2782,7 @@
   void test_varAndType_local() {
     // This is currently reporting EXPECTED_TOKEN for a missing semicolon, but
     // this would be a better error message.
-    ParserTestCase.parseStatement("var int x;", [ParserErrorCode.VAR_AND_TYPE]);
+    parseStatement("var int x;", [ParserErrorCode.VAR_AND_TYPE]);
   }
 
   @failingTest
@@ -2802,8 +2796,7 @@
   }
 
   void test_varAndType_topLevelVariable() {
-    ParserTestCase
-        .parseCompilationUnit("var int x;", [ParserErrorCode.VAR_AND_TYPE]);
+    parseCompilationUnit("var int x;", [ParserErrorCode.VAR_AND_TYPE]);
   }
 
   void test_varAsTypeName_as() {
@@ -2811,13 +2804,11 @@
   }
 
   void test_varClass() {
-    ParserTestCase
-        .parseCompilationUnit("var class C {}", [ParserErrorCode.VAR_CLASS]);
+    parseCompilationUnit("var class C {}", [ParserErrorCode.VAR_CLASS]);
   }
 
   void test_varEnum() {
-    ParserTestCase
-        .parseCompilationUnit("var enum E {ONE}", [ParserErrorCode.VAR_ENUM]);
+    parseCompilationUnit("var enum E {ONE}", [ParserErrorCode.VAR_ENUM]);
   }
 
   void test_varReturnType() {
@@ -2828,8 +2819,7 @@
   }
 
   void test_varTypedef() {
-    ParserTestCase.parseCompilationUnit(
-        "var typedef F();", [ParserErrorCode.VAR_TYPEDEF]);
+    parseCompilationUnit("var typedef F();", [ParserErrorCode.VAR_TYPEDEF]);
   }
 
   void test_voidParameter() {
@@ -2854,54 +2844,49 @@
   }
 
   void test_voidVariable_parseCompilationUnit_initializer() {
-    ParserTestCase
-        .parseCompilationUnit("void x = 0;", [ParserErrorCode.VOID_VARIABLE]);
+    parseCompilationUnit("void x = 0;", [ParserErrorCode.VOID_VARIABLE]);
   }
 
   void test_voidVariable_parseCompilationUnit_noInitializer() {
-    ParserTestCase
-        .parseCompilationUnit("void x;", [ParserErrorCode.VOID_VARIABLE]);
+    parseCompilationUnit("void x;", [ParserErrorCode.VOID_VARIABLE]);
   }
 
   void test_voidVariable_parseCompilationUnitMember_initializer() {
     createParser('void a = 0;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.VOID_VARIABLE]);
   }
 
   void test_voidVariable_parseCompilationUnitMember_noInitializer() {
     createParser('void a;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertErrorsWithCodes([ParserErrorCode.VOID_VARIABLE]);
   }
 
   void test_voidVariable_statement_initializer() {
-    ParserTestCase.parseStatement("void x = 0;", [
+    parseStatement("void x = 0;", [
       ParserErrorCode.VOID_VARIABLE,
       ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
     ]);
   }
 
   void test_voidVariable_statement_noInitializer() {
-    ParserTestCase.parseStatement("void x;", [
+    parseStatement("void x;", [
       ParserErrorCode.VOID_VARIABLE,
       ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
     ]);
   }
 
   void test_withBeforeExtends() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "class A with B extends C {}", [ParserErrorCode.WITH_BEFORE_EXTENDS]);
   }
 
   void test_withWithoutExtends() {
     createParser('class A with B, C {}');
-    ClassDeclaration declaration =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    ClassDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertErrorsWithCodes([ParserErrorCode.WITH_WITHOUT_EXTENDS]);
   }
@@ -2953,7 +2938,11 @@
   }
 }
 
-class ParserTestCase extends EngineTestCase {
+/**
+ * Implementation of [AbstractParserTestCase] specialized for testing the
+ * analyzer parser.
+ */
+class ParserTestCase extends EngineTestCase implements AbstractParserTestCase {
   /**
    * A flag indicating whether parser is to parse function bodies.
    */
@@ -3008,18 +2997,6 @@
   Parser parser;
 
   /**
-   * Return a CommentAndMetadata object with the given values that can be used for testing.
-   *
-   * @param comment the comment to be wrapped in the object
-   * @param annotations the annotations to be wrapped in the object
-   * @return a CommentAndMetadata object that can be used for testing
-   */
-  CommentAndMetadata commentAndMetadata(Comment comment,
-      [List<Annotation> annotations]) {
-    return new CommentAndMetadata(comment, annotations);
-  }
-
-  /**
    * Create the [parser] and [listener] used by a test. The [parser] will be
    * prepared to parse the tokens scanned from the given [content].
    */
@@ -3047,14 +3024,6 @@
     parser.currentToken = tokenStream;
   }
 
-  /**
-   * Return an empty CommentAndMetadata object that can be used for testing.
-   *
-   * @return an empty CommentAndMetadata object that can be used for testing
-   */
-  CommentAndMetadata emptyCommentAndMetadata() =>
-      new CommentAndMetadata(null, null);
-
   void expectNotNullIfNoErrors(Object result) {
     if (!listener.hasErrors) {
       expect(result, isNotNull);
@@ -3062,6 +3031,43 @@
   }
 
   /**
+   * Parse the given source as a compilation unit.
+   *
+   * @param source the source to be parsed
+   * @param errorCodes the error codes of the errors that are expected to be found
+   * @return the compilation unit that was parsed
+   * @throws Exception if the source could not be parsed, if the compilation errors in the source do
+   *           not match those that are expected, or if the result would have been `null`
+   */
+  CompilationUnit parseCompilationUnit(String source,
+      [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
+    GatheringErrorListener listener = new GatheringErrorListener();
+    Scanner scanner =
+        new Scanner(null, new CharSequenceReader(source), listener);
+    listener.setLineInfo(new TestSource(), scanner.lineStarts);
+    Token token = scanner.tokenize();
+    Parser parser = new Parser(null, listener);
+    CompilationUnit unit = parser.parseCompilationUnit(token);
+    expect(unit, isNotNull);
+    listener.assertErrorsWithCodes(errorCodes);
+    return unit;
+  }
+
+  /**
+   * Parse the given [code] as a compilation unit.
+   */
+  CompilationUnit parseCompilationUnit2(String code,
+      {AnalysisErrorListener listener}) {
+    listener ??= AnalysisErrorListener.NULL_LISTENER;
+    Scanner scanner = new Scanner(null, new CharSequenceReader(code), listener);
+    Token token = scanner.tokenize();
+    Parser parser = new Parser(null, listener);
+    CompilationUnit unit = parser.parseCompilationUnit(token);
+    unit.lineInfo = new LineInfo(scanner.lineStarts);
+    return unit;
+  }
+
+  /**
    * Parse the given [source] as a compilation unit. Throw an exception if the
    * source could not be parsed, if the compilation errors in the source do not
    * match those that are expected, or if the result would have been `null`.
@@ -3093,48 +3099,27 @@
     return expression;
   }
 
-  @override
-  void setUp() {
-    super.setUp();
-    parseFunctionBodies = true;
-  }
+  /**
+   * Parses a single top level member of a compilation unit (other than a
+   * directive), including any comment and/or metadata that precedes it.
+   */
+  CompilationUnitMember parseFullCompilationUnitMember() =>
+      parser.parseCompilationUnitMember(parser.parseCommentAndMetadata());
 
   /**
-   * Parse the given source as a compilation unit.
-   *
-   * @param source the source to be parsed
-   * @param errorCodes the error codes of the errors that are expected to be found
-   * @return the compilation unit that was parsed
-   * @throws Exception if the source could not be parsed, if the compilation errors in the source do
-   *           not match those that are expected, or if the result would have been `null`
+   * Parses a single top level directive, including any comment and/or metadata
+   * that precedes it.
    */
-  static CompilationUnit parseCompilationUnit(String source,
-      [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
-    GatheringErrorListener listener = new GatheringErrorListener();
-    Scanner scanner =
-        new Scanner(null, new CharSequenceReader(source), listener);
-    listener.setLineInfo(new TestSource(), scanner.lineStarts);
-    Token token = scanner.tokenize();
-    Parser parser = new Parser(null, listener);
-    CompilationUnit unit = parser.parseCompilationUnit(token);
-    expect(unit, isNotNull);
-    listener.assertErrorsWithCodes(errorCodes);
-    return unit;
-  }
+  Directive parseFullDirective() =>
+      parser.parseDirective(parser.parseCommentAndMetadata());
 
   /**
-   * Parse the given [code] as a compilation unit.
+   * Parses a variable declaration list (equivalent to a variable declaration
+   * statement, but without the final comma).
    */
-  static CompilationUnit parseCompilationUnit2(String code,
-      {AnalysisErrorListener listener}) {
-    listener ??= AnalysisErrorListener.NULL_LISTENER;
-    Scanner scanner = new Scanner(null, new CharSequenceReader(code), listener);
-    Token token = scanner.tokenize();
-    Parser parser = new Parser(null, listener);
-    CompilationUnit unit = parser.parseCompilationUnit(token);
-    unit.lineInfo = new LineInfo(scanner.lineStarts);
-    return unit;
-  }
+  VariableDeclarationList parseFullVariableDeclarationList() =>
+      parser.parseVariableDeclarationListAfterMetadata(
+          parser.parseCommentAndMetadata());
 
   /**
    * Parse the given [source] as a statement. The [errorCodes] are the error
@@ -3142,7 +3127,7 @@
    * [enableLazyAssignmentOperators] is `true`, then lazy assignment operators
    * should be enabled.
    */
-  static Statement parseStatement(String source,
+  Statement parseStatement(String source,
       [List<ErrorCode> errorCodes = const <ErrorCode>[],
       bool enableLazyAssignmentOperators]) {
     GatheringErrorListener listener = new GatheringErrorListener();
@@ -3169,7 +3154,7 @@
    *           the expected count, if the compilation errors in the source do not match those that
    *           are expected, or if the result would have been `null`
    */
-  static List<Statement> parseStatements(String source, int expectedCount,
+  List<Statement> parseStatements(String source, int expectedCount,
       [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
     GatheringErrorListener listener = new GatheringErrorListener();
     Scanner scanner =
@@ -3182,6 +3167,12 @@
     listener.assertErrorsWithCodes(errorCodes);
     return statements;
   }
+
+  @override
+  void setUp() {
+    super.setUp();
+    parseFunctionBodies = true;
+  }
 }
 
 /**
@@ -3508,7 +3499,7 @@
   }
 
   void test_classTypeAlias_withBody() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         r'''
 class A {}
 class B = Object with A {}''',
@@ -3540,7 +3531,7 @@
   }
 
   void test_declarationBeforeDirective() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "class foo { } import 'bar.dart';",
         [ParserErrorCode.DIRECTIVE_AFTER_DECLARATION]);
     expect(unit.directives, hasLength(1));
@@ -3654,7 +3645,7 @@
   }
 
   void test_functionExpression_in_ConstructorFieldInitializer() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "class A { A() : a = (){}; var v; }",
         [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.UNEXPECTED_TOKEN]);
     // Make sure we recovered and parsed "var v" correctly
@@ -3674,7 +3665,7 @@
   }
 
   void test_importDirectivePartial_as() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "import 'b.dart' d as b;", [ParserErrorCode.UNEXPECTED_TOKEN]);
     ImportDirective importDirective = unit.childEntities.first;
     expect(importDirective.asKeyword, isNotNull);
@@ -3683,7 +3674,7 @@
   }
 
   void test_importDirectivePartial_hide() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "import 'b.dart' d hide foo;", [ParserErrorCode.UNEXPECTED_TOKEN]);
     ImportDirective importDirective = unit.childEntities.first;
     expect(importDirective.combinators, hasLength(1));
@@ -3692,7 +3683,7 @@
   }
 
   void test_importDirectivePartial_show() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "import 'b.dart' d show foo;", [ParserErrorCode.UNEXPECTED_TOKEN]);
     ImportDirective importDirective = unit.childEntities.first;
     expect(importDirective.combinators, hasLength(1));
@@ -3740,7 +3731,7 @@
 
   @failingTest
   void test_incomplete_returnType() {
-    ParserTestCase.parseCompilationUnit(r'''
+    parseCompilationUnit(r'''
 Map<Symbol, convertStringToSymbolMap(Map<String, dynamic> map) {
   if (map == null) return null;
   Map<Symbol, dynamic> result = new Map<Symbol, dynamic>();
@@ -3752,13 +3743,12 @@
   }
 
   void test_incomplete_topLevelFunction() {
-    ParserTestCase.parseCompilationUnit(
-        "foo();", [ParserErrorCode.MISSING_FUNCTION_BODY]);
+    parseCompilationUnit("foo();", [ParserErrorCode.MISSING_FUNCTION_BODY]);
   }
 
   void test_incomplete_topLevelVariable() {
-    CompilationUnit unit = ParserTestCase
-        .parseCompilationUnit("String", [ParserErrorCode.EXPECTED_EXECUTABLE]);
+    CompilationUnit unit =
+        parseCompilationUnit("String", [ParserErrorCode.EXPECTED_EXECUTABLE]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
     CompilationUnitMember member = declarations[0];
@@ -3772,7 +3762,7 @@
   }
 
   void test_incomplete_topLevelVariable_const() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit("const ",
+    CompilationUnit unit = parseCompilationUnit("const ",
         [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
@@ -3787,7 +3777,7 @@
   }
 
   void test_incomplete_topLevelVariable_final() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit("final ",
+    CompilationUnit unit = parseCompilationUnit("final ",
         [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
@@ -3802,7 +3792,7 @@
   }
 
   void test_incomplete_topLevelVariable_var() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit("var ",
+    CompilationUnit unit = parseCompilationUnit("var ",
         [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
@@ -3817,7 +3807,7 @@
   }
 
   void test_incompleteField_const() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         r'''
 class C {
   const
@@ -3843,7 +3833,7 @@
   }
 
   void test_incompleteField_final() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         r'''
 class C {
   final
@@ -3869,7 +3859,7 @@
   }
 
   void test_incompleteField_var() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         r'''
 class C {
   var
@@ -3895,8 +3885,7 @@
   }
 
   void test_incompleteForEach() {
-    ForStatement statement = ParserTestCase.parseStatement(
-        'for (String item i) {}',
+    ForStatement statement = parseStatement('for (String item i) {}',
         [ParserErrorCode.EXPECTED_TOKEN, ParserErrorCode.EXPECTED_TOKEN]);
     expect(statement, new isInstanceOf<ForStatement>());
     expect(statement.toSource(), 'for (String item; i;) {}');
@@ -3907,42 +3896,42 @@
   }
 
   void test_incompleteLocalVariable_atTheEndOfBlock() {
-    Statement statement = ParserTestCase
-        .parseStatement('String v }', [ParserErrorCode.EXPECTED_TOKEN]);
+    Statement statement =
+        parseStatement('String v }', [ParserErrorCode.EXPECTED_TOKEN]);
     expect(statement, new isInstanceOf<VariableDeclarationStatement>());
     expect(statement.toSource(), 'String v;');
   }
 
   void test_incompleteLocalVariable_beforeIdentifier() {
-    Statement statement = ParserTestCase.parseStatement(
-        'String v String v2;', [ParserErrorCode.EXPECTED_TOKEN]);
+    Statement statement =
+        parseStatement('String v String v2;', [ParserErrorCode.EXPECTED_TOKEN]);
     expect(statement, new isInstanceOf<VariableDeclarationStatement>());
     expect(statement.toSource(), 'String v;');
   }
 
   void test_incompleteLocalVariable_beforeKeyword() {
-    Statement statement = ParserTestCase.parseStatement(
+    Statement statement = parseStatement(
         'String v if (true) {}', [ParserErrorCode.EXPECTED_TOKEN]);
     expect(statement, new isInstanceOf<VariableDeclarationStatement>());
     expect(statement.toSource(), 'String v;');
   }
 
   void test_incompleteLocalVariable_beforeNextBlock() {
-    Statement statement = ParserTestCase
-        .parseStatement('String v {}', [ParserErrorCode.EXPECTED_TOKEN]);
+    Statement statement =
+        parseStatement('String v {}', [ParserErrorCode.EXPECTED_TOKEN]);
     expect(statement, new isInstanceOf<VariableDeclarationStatement>());
     expect(statement.toSource(), 'String v;');
   }
 
   void test_incompleteLocalVariable_parameterizedType() {
-    Statement statement = ParserTestCase
-        .parseStatement('List<String> v {}', [ParserErrorCode.EXPECTED_TOKEN]);
+    Statement statement =
+        parseStatement('List<String> v {}', [ParserErrorCode.EXPECTED_TOKEN]);
     expect(statement, new isInstanceOf<VariableDeclarationStatement>());
     expect(statement.toSource(), 'List<String> v;');
   }
 
   void test_incompleteTypeArguments_field() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         r'''
 class C {
   final List<int f;
@@ -3972,7 +3961,7 @@
   }
 
   void test_incompleteTypeParameters() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         r'''
 class C<K {
 }''',
@@ -3991,12 +3980,12 @@
   }
 
   void test_invalidFunctionBodyModifier() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "f() sync {}", [ParserErrorCode.MISSING_STAR_AFTER_SYNC]);
   }
 
   void test_isExpression_noType() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         "class Bar<T extends Foo> {m(x){if (x is ) return;if (x is !)}}", [
       ParserErrorCode.EXPECTED_TYPE_NAME,
       ParserErrorCode.EXPECTED_TYPE_NAME,
@@ -4019,7 +4008,7 @@
 
   void test_keywordInPlaceOfIdentifier() {
     // TODO(brianwilkerson) We could do better with this.
-    ParserTestCase.parseCompilationUnit("do() {}", [
+    parseCompilationUnit("do() {}", [
       ParserErrorCode.EXPECTED_EXECUTABLE,
       ParserErrorCode.UNEXPECTED_TOKEN
     ]);
@@ -4128,7 +4117,7 @@
   }
 
   void test_missingGet() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+    CompilationUnit unit = parseCompilationUnit(
         r'''
 class C {
   int length {}
@@ -4176,8 +4165,7 @@
       expect(declaration.semicolon.lexeme, expectedSemicolon);
     }
 
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
-        'String n x = "";', [
+    CompilationUnit unit = parseCompilationUnit('String n x = "";', [
       ParserErrorCode.EXPECTED_TOKEN,
       ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
     ]);
@@ -4250,7 +4238,7 @@
   }
 
   void test_nonStringLiteralUri_import() {
-    ParserTestCase.parseCompilationUnit("import dart:io; class C {}",
+    parseCompilationUnit("import dart:io; class C {}",
         [ParserErrorCode.NON_STRING_LITERAL_AS_URI]);
   }
 
@@ -4377,7 +4365,7 @@
   }
 
   void test_typedef_eof() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit("typedef n", [
+    CompilationUnit unit = parseCompilationUnit("typedef n", [
       ParserErrorCode.EXPECTED_TOKEN,
       ParserErrorCode.MISSING_TYPEDEF_PARAMETERS
     ]);
@@ -4504,46 +4492,45 @@
   }
 
   void test_function_literal_allowed_at_toplevel() {
-    ParserTestCase.parseCompilationUnit("var x = () {};");
+    parseCompilationUnit("var x = () {};");
   }
 
   void
       test_function_literal_allowed_in_ArgumentList_in_ConstructorFieldInitializer() {
-    ParserTestCase.parseCompilationUnit("class C { C() : a = f(() {}); }");
+    parseCompilationUnit("class C { C() : a = f(() {}); }");
   }
 
   void
       test_function_literal_allowed_in_IndexExpression_in_ConstructorFieldInitializer() {
-    ParserTestCase.parseCompilationUnit("class C { C() : a = x[() {}]; }");
+    parseCompilationUnit("class C { C() : a = x[() {}]; }");
   }
 
   void
       test_function_literal_allowed_in_ListLiteral_in_ConstructorFieldInitializer() {
-    ParserTestCase.parseCompilationUnit("class C { C() : a = [() {}]; }");
+    parseCompilationUnit("class C { C() : a = [() {}]; }");
   }
 
   void
       test_function_literal_allowed_in_MapLiteral_in_ConstructorFieldInitializer() {
-    ParserTestCase
-        .parseCompilationUnit("class C { C() : a = {'key': () {}}; }");
+    parseCompilationUnit("class C { C() : a = {'key': () {}}; }");
   }
 
   void
       test_function_literal_allowed_in_ParenthesizedExpression_in_ConstructorFieldInitializer() {
-    ParserTestCase.parseCompilationUnit("class C { C() : a = (() {}); }");
+    parseCompilationUnit("class C { C() : a = (() {}); }");
   }
 
   void
       test_function_literal_allowed_in_StringInterpolation_in_ConstructorFieldInitializer() {
-    ParserTestCase.parseCompilationUnit("class C { C() : a = \"\${(){}}\"; }");
+    parseCompilationUnit("class C { C() : a = \"\${(){}}\"; }");
   }
 
   void test_import_as_show() {
-    ParserTestCase.parseCompilationUnit("import 'dart:math' as M show E;");
+    parseCompilationUnit("import 'dart:math' as M show E;");
   }
 
   void test_import_show_hide() {
-    ParserTestCase.parseCompilationUnit(
+    parseCompilationUnit(
         "import 'import1_lib.dart' show hide, show hide ugly;");
   }
 
@@ -5748,10 +5735,8 @@
   }
 
   void test_parseClassDeclaration_abstract() {
-    createParser('class A {}');
-    CompilationUnitMember member = parser.parseClassDeclaration(
-        emptyCommentAndMetadata(),
-        TokenFactory.tokenFromKeyword(Keyword.ABSTRACT));
+    createParser('abstract class A {}');
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5770,8 +5755,7 @@
 
   void test_parseClassDeclaration_empty() {
     createParser('class A {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5790,8 +5774,7 @@
 
   void test_parseClassDeclaration_extends() {
     createParser('class A extends B {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5810,8 +5793,7 @@
 
   void test_parseClassDeclaration_extendsAndImplements() {
     createParser('class A extends B implements C {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5830,8 +5812,7 @@
 
   void test_parseClassDeclaration_extendsAndWith() {
     createParser('class A extends B with C {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5851,8 +5832,7 @@
 
   void test_parseClassDeclaration_extendsAndWithAndImplements() {
     createParser('class A extends B with C implements D {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5872,8 +5852,7 @@
 
   void test_parseClassDeclaration_implements() {
     createParser('class A implements C {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5892,8 +5871,7 @@
 
   void test_parseClassDeclaration_native() {
     createParser('class A native "nativeValue" {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5908,8 +5886,7 @@
 
   void test_parseClassDeclaration_nonEmpty() {
     createParser('class A {var f;}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -5928,8 +5905,7 @@
 
   void test_parseClassDeclaration_typeAlias_implementsC() {
     createParser('class A = Object with B implements C;');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -5946,8 +5922,7 @@
 
   void test_parseClassDeclaration_typeAlias_withB() {
     createParser('class A = Object with B;');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -5964,8 +5939,7 @@
 
   void test_parseClassDeclaration_typeParameters() {
     createParser('class A<B> {}');
-    CompilationUnitMember member =
-        parser.parseClassDeclaration(emptyCommentAndMetadata(), null);
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -7297,21 +7271,21 @@
   }
 
   void test_parseCompilationUnit_builtIn_asFunctionName() {
-    ParserTestCase.parseCompilationUnit('abstract(x) => 0;');
-    ParserTestCase.parseCompilationUnit('as(x) => 0;');
-    ParserTestCase.parseCompilationUnit('dynamic(x) => 0;');
-    ParserTestCase.parseCompilationUnit('export(x) => 0;');
-    ParserTestCase.parseCompilationUnit('external(x) => 0;');
-    ParserTestCase.parseCompilationUnit('factory(x) => 0;');
-    ParserTestCase.parseCompilationUnit('get(x) => 0;');
-    ParserTestCase.parseCompilationUnit('implements(x) => 0;');
-    ParserTestCase.parseCompilationUnit('import(x) => 0;');
-    ParserTestCase.parseCompilationUnit('library(x) => 0;');
-    ParserTestCase.parseCompilationUnit('operator(x) => 0;');
-    ParserTestCase.parseCompilationUnit('part(x) => 0;');
-    ParserTestCase.parseCompilationUnit('set(x) => 0;');
-    ParserTestCase.parseCompilationUnit('static(x) => 0;');
-    ParserTestCase.parseCompilationUnit('typedef(x) => 0;');
+    parseCompilationUnit('abstract(x) => 0;');
+    parseCompilationUnit('as(x) => 0;');
+    parseCompilationUnit('dynamic(x) => 0;');
+    parseCompilationUnit('export(x) => 0;');
+    parseCompilationUnit('external(x) => 0;');
+    parseCompilationUnit('factory(x) => 0;');
+    parseCompilationUnit('get(x) => 0;');
+    parseCompilationUnit('implements(x) => 0;');
+    parseCompilationUnit('import(x) => 0;');
+    parseCompilationUnit('library(x) => 0;');
+    parseCompilationUnit('operator(x) => 0;');
+    parseCompilationUnit('part(x) => 0;');
+    parseCompilationUnit('set(x) => 0;');
+    parseCompilationUnit('static(x) => 0;');
+    parseCompilationUnit('typedef(x) => 0;');
   }
 
   void test_parseCompilationUnit_directives_multiple() {
@@ -7416,8 +7390,7 @@
 
   void test_parseCompilationUnitMember_abstractAsPrefix() {
     createParser('abstract.A _abstract = new abstract.A();');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
@@ -7428,8 +7401,7 @@
 
   void test_parseCompilationUnitMember_class() {
     createParser('class A {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassDeclaration>());
@@ -7440,8 +7412,7 @@
 
   void test_parseCompilationUnitMember_classTypeAlias() {
     createParser('abstract class A = B with C;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -7452,8 +7423,7 @@
 
   void test_parseCompilationUnitMember_constVariable() {
     createParser('const int x = 0;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
@@ -7464,8 +7434,7 @@
 
   void test_parseCompilationUnitMember_finalVariable() {
     createParser('final x = 0;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
@@ -7476,8 +7445,7 @@
 
   void test_parseCompilationUnitMember_function_external_noType() {
     createParser('external f();');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7489,8 +7457,7 @@
 
   void test_parseCompilationUnitMember_function_external_type() {
     createParser('external int f();');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7502,8 +7469,7 @@
 
   void test_parseCompilationUnitMember_function_generic_noReturnType() {
     createParser('f<E>() {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7515,8 +7481,7 @@
   void
       test_parseCompilationUnitMember_function_generic_noReturnType_annotated() {
     createParser('f<@a E>() {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7527,8 +7492,7 @@
 
   void test_parseCompilationUnitMember_function_generic_returnType() {
     createParser('E f<E>() {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7539,8 +7503,7 @@
 
   void test_parseCompilationUnitMember_function_generic_void() {
     createParser('void f<T>(T t) {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7551,8 +7514,7 @@
 
   void test_parseCompilationUnitMember_function_noType() {
     createParser('f() {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7563,8 +7525,7 @@
 
   void test_parseCompilationUnitMember_function_type() {
     createParser('int f() {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7575,8 +7536,7 @@
 
   void test_parseCompilationUnitMember_function_void() {
     createParser('void f() {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7586,8 +7546,7 @@
 
   void test_parseCompilationUnitMember_getter_external_noType() {
     createParser('external get p;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7599,8 +7558,7 @@
 
   void test_parseCompilationUnitMember_getter_external_type() {
     createParser('external int get p;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7612,8 +7570,7 @@
 
   void test_parseCompilationUnitMember_getter_noType() {
     createParser('get p => 0;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7624,8 +7581,7 @@
 
   void test_parseCompilationUnitMember_getter_type() {
     createParser('int get p => 0;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7636,8 +7592,7 @@
 
   void test_parseCompilationUnitMember_setter_external_noType() {
     createParser('external set p(v);');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7649,8 +7604,7 @@
 
   void test_parseCompilationUnitMember_setter_external_type() {
     createParser('external void set p(int v);');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7662,8 +7616,7 @@
 
   void test_parseCompilationUnitMember_setter_noType() {
     createParser('set p(v) {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7674,8 +7627,7 @@
 
   void test_parseCompilationUnitMember_setter_type() {
     createParser('void set p(int v) {}');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionDeclaration>());
@@ -7687,8 +7639,7 @@
 
   void test_parseCompilationUnitMember_typeAlias_abstract() {
     createParser('abstract class C = S with M;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -7706,8 +7657,7 @@
 
   void test_parseCompilationUnitMember_typeAlias_generic() {
     createParser('class C<E> = S<E> with M<E> implements I<E>;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -7725,8 +7675,7 @@
 
   void test_parseCompilationUnitMember_typeAlias_implements() {
     createParser('class C = S with M implements I;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -7744,8 +7693,7 @@
 
   void test_parseCompilationUnitMember_typeAlias_noImplements() {
     createParser('class C = S with M;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<ClassTypeAlias>());
@@ -7763,8 +7711,7 @@
 
   void test_parseCompilationUnitMember_typedef() {
     createParser('typedef F();');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<FunctionTypeAlias>());
@@ -7775,8 +7722,7 @@
 
   void test_parseCompilationUnitMember_variable() {
     createParser('var x = 0;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
@@ -7787,8 +7733,7 @@
 
   void test_parseCompilationUnitMember_variableGet() {
     createParser('String get = null;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
@@ -7799,8 +7744,7 @@
 
   void test_parseCompilationUnitMember_variableSet() {
     createParser('String set = null;');
-    CompilationUnitMember member =
-        parser.parseCompilationUnitMember(emptyCommentAndMetadata());
+    CompilationUnitMember member = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(member);
     listener.assertNoErrors();
     expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
@@ -8107,7 +8051,7 @@
 
   void test_parseDirective_export() {
     createParser("export 'lib/lib.dart';");
-    Directive directive = parser.parseDirective(emptyCommentAndMetadata());
+    Directive directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive, new isInstanceOf<ExportDirective>());
@@ -8120,7 +8064,7 @@
 
   void test_parseDirective_import() {
     createParser("import 'lib/lib.dart';");
-    Directive directive = parser.parseDirective(emptyCommentAndMetadata());
+    Directive directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive, new isInstanceOf<ImportDirective>());
@@ -8135,7 +8079,7 @@
 
   void test_parseDirective_library() {
     createParser("library l;");
-    Directive directive = parser.parseDirective(emptyCommentAndMetadata());
+    Directive directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive, new isInstanceOf<LibraryDirective>());
@@ -8147,7 +8091,7 @@
 
   void test_parseDirective_part() {
     createParser("part 'lib/lib.dart';");
-    Directive directive = parser.parseDirective(emptyCommentAndMetadata());
+    Directive directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive, new isInstanceOf<PartDirective>());
@@ -8159,7 +8103,7 @@
 
   void test_parseDirective_partOf() {
     createParser("part of l;");
-    Directive directive = parser.parseDirective(emptyCommentAndMetadata());
+    Directive directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive, new isInstanceOf<PartOfDirective>());
@@ -8292,8 +8236,7 @@
 
   void test_parseEnumDeclaration_one() {
     createParser("enum E {ONE}");
-    EnumDeclaration declaration =
-        parser.parseEnumDeclaration(emptyCommentAndMetadata());
+    EnumDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
     expect(declaration.documentationComment, isNull);
@@ -8306,8 +8249,7 @@
 
   void test_parseEnumDeclaration_trailingComma() {
     createParser("enum E {ONE,}");
-    EnumDeclaration declaration =
-        parser.parseEnumDeclaration(emptyCommentAndMetadata());
+    EnumDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
     expect(declaration.documentationComment, isNull);
@@ -8320,8 +8262,7 @@
 
   void test_parseEnumDeclaration_two() {
     createParser("enum E {ONE, TWO}");
-    EnumDeclaration declaration =
-        parser.parseEnumDeclaration(emptyCommentAndMetadata());
+    EnumDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
     expect(declaration.documentationComment, isNull);
@@ -8356,8 +8297,7 @@
 
   void test_parseExportDirective_configuration_multiple() {
     createParser("export 'lib/lib.dart' if (a) 'b.dart' if (c) 'd.dart';");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -8371,8 +8311,7 @@
 
   void test_parseExportDirective_configuration_single() {
     createParser("export 'lib/lib.dart' if (a.b == 'c.dart') '';");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -8385,8 +8324,7 @@
 
   void test_parseExportDirective_hide() {
     createParser("export 'lib/lib.dart' hide A, B;");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -8397,8 +8335,7 @@
 
   void test_parseExportDirective_hide_show() {
     createParser("export 'lib/lib.dart' hide A show B;");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -8409,8 +8346,7 @@
 
   void test_parseExportDirective_noCombinator() {
     createParser("export 'lib/lib.dart';");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -8421,8 +8357,7 @@
 
   void test_parseExportDirective_show() {
     createParser("export 'lib/lib.dart' show A, B;");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -8433,8 +8368,7 @@
 
   void test_parseExportDirective_show_hide() {
     createParser("export 'lib/lib.dart' show B hide A;");
-    ExportDirective directive =
-        parser.parseExportDirective(emptyCommentAndMetadata());
+    ExportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -9995,16 +9929,12 @@
   }
 
   void test_parseFunctionDeclaration_function() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('f() {}');
-    FunctionDeclaration declaration = parser.parseFunctionDeclaration(
-        commentAndMetadata(comment), null, returnType);
+    createParser('/// Doc\nT f() {}');
+    FunctionDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
-    expect(declaration.returnType, returnType);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
+    expect((declaration.returnType as TypeName).name.name, 'T');
     expect(declaration.name, isNotNull);
     FunctionExpression expression = declaration.functionExpression;
     expect(expression, isNotNull);
@@ -10015,16 +9945,12 @@
   }
 
   void test_parseFunctionDeclaration_functionWithTypeParameters() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('f<E>() {}');
-    FunctionDeclaration declaration = parser.parseFunctionDeclaration(
-        commentAndMetadata(comment), null, returnType);
+    createParser('/// Doc\nT f<E>() {}');
+    FunctionDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
-    expect(declaration.returnType, returnType);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
+    expect((declaration.returnType as TypeName).name.name, 'T');
     expect(declaration.name, isNotNull);
     FunctionExpression expression = declaration.functionExpression;
     expect(expression, isNotNull);
@@ -10036,16 +9962,12 @@
 
   void test_parseFunctionDeclaration_functionWithTypeParameters_comment() {
     enableGenericMethodComments = true;
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('f/*<E>*/() {}');
-    FunctionDeclaration declaration = parser.parseFunctionDeclaration(
-        commentAndMetadata(comment), null, returnType);
+    createParser('/// Doc\nT f/*<E>*/() {}');
+    FunctionDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
-    expect(declaration.returnType, returnType);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
+    expect((declaration.returnType as TypeName).name.name, 'T');
     expect(declaration.name, isNotNull);
     FunctionExpression expression = declaration.functionExpression;
     expect(expression, isNotNull);
@@ -10056,16 +9978,12 @@
   }
 
   void test_parseFunctionDeclaration_getter() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('get p => 0;');
-    FunctionDeclaration declaration = parser.parseFunctionDeclaration(
-        commentAndMetadata(comment), null, returnType);
+    createParser('/// Doc\nT get p => 0;');
+    FunctionDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
-    expect(declaration.returnType, returnType);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
+    expect((declaration.returnType as TypeName).name.name, 'T');
     expect(declaration.name, isNotNull);
     FunctionExpression expression = declaration.functionExpression;
     expect(expression, isNotNull);
@@ -10076,16 +9994,12 @@
   }
 
   void test_parseFunctionDeclaration_setter() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('set p(v) {}');
-    FunctionDeclaration declaration = parser.parseFunctionDeclaration(
-        commentAndMetadata(comment), null, returnType);
+    createParser('/// Doc\nT set p(v) {}');
+    FunctionDeclaration declaration = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
-    expect(declaration.returnType, returnType);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
+    expect((declaration.returnType as TypeName).name.name, 'T');
     expect(declaration.name, isNotNull);
     FunctionExpression expression = declaration.functionExpression;
     expect(expression, isNotNull);
@@ -10180,8 +10094,7 @@
   @failingTest
   void test_parseGenericTypeAlias_noTypeParameters() {
     createParser('F = int Function(int);');
-    GenericTypeAlias alias =
-        parser.parseGenericTypeAlias(emptyCommentAndMetadata(), null);
+    GenericTypeAlias alias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(alias);
     listener.assertNoErrors();
     expect(alias.name, isNotNull);
@@ -10195,8 +10108,7 @@
   @failingTest
   void test_parseGenericTypeAlias_typeParameters() {
     createParser('F<T> = T Function(T);');
-    GenericTypeAlias alias =
-        parser.parseGenericTypeAlias(emptyCommentAndMetadata(), null);
+    GenericTypeAlias alias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(alias);
     listener.assertNoErrors();
     expect(alias.name, isNotNull);
@@ -10208,45 +10120,36 @@
   }
 
   void test_parseGetter_nonStatic() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('get a;');
-    MethodDeclaration method =
-        parser.parseGetter(commentAndMetadata(comment), null, null, returnType);
+    createParser('/// Doc\nT get a;');
+    MethodDeclaration method = parser.parseClassMember('C');
     expectNotNullIfNoErrors(method);
     listener.assertNoErrors();
     expect(method.body, isNotNull);
-    expect(method.documentationComment, comment);
+    _expectCommentText(method.documentationComment, '/// Doc');
     expect(method.externalKeyword, isNull);
     expect(method.modifierKeyword, isNull);
     expect(method.name, isNotNull);
     expect(method.operatorKeyword, isNull);
     expect(method.parameters, isNull);
     expect(method.propertyKeyword, isNotNull);
-    expect(method.returnType, returnType);
+    expect((method.returnType as TypeName).name.name, 'T');
   }
 
   void test_parseGetter_static() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    Token staticKeyword = TokenFactory.tokenFromKeyword(Keyword.STATIC);
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('get a => 42;');
-    MethodDeclaration method = parser.parseGetter(
-        commentAndMetadata(comment), null, staticKeyword, returnType);
+    createParser('/// Doc\nstatic T get a => 42;');
+    MethodDeclaration method = parser.parseClassMember('C');
     expectNotNullIfNoErrors(method);
     listener.assertNoErrors();
     expect(method.body, isNotNull);
-    expect(method.documentationComment, comment);
+    _expectCommentText(method.documentationComment, '/// Doc');
     expect(method.externalKeyword, isNull);
-    expect(method.modifierKeyword, staticKeyword);
+    expect(method.modifierKeyword.lexeme, 'static');
     expect(method.name, isNotNull);
     expect(method.operatorKeyword, isNull);
     expect(method.typeParameters, isNull);
     expect(method.parameters, isNull);
     expect(method.propertyKeyword, isNotNull);
-    expect(method.returnType, returnType);
+    expect((method.returnType as TypeName).name.name, 'T');
   }
 
   void test_parseIdentifierList_multiple() {
@@ -10341,8 +10244,7 @@
 
   void test_parseImportDirective_configuration_multiple() {
     createParser("import 'lib/lib.dart' if (a) 'b.dart' if (c) 'd.dart';");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10359,8 +10261,7 @@
 
   void test_parseImportDirective_configuration_single() {
     createParser("import 'lib/lib.dart' if (a.b == 'c.dart') '';");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10376,8 +10277,7 @@
 
   void test_parseImportDirective_deferred() {
     createParser("import 'lib/lib.dart' deferred as a;");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10391,8 +10291,7 @@
 
   void test_parseImportDirective_hide() {
     createParser("import 'lib/lib.dart' hide A, B;");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10406,8 +10305,7 @@
 
   void test_parseImportDirective_noCombinator() {
     createParser("import 'lib/lib.dart';");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10421,8 +10319,7 @@
 
   void test_parseImportDirective_prefix() {
     createParser("import 'lib/lib.dart' as a;");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10436,8 +10333,7 @@
 
   void test_parseImportDirective_prefix_hide_show() {
     createParser("import 'lib/lib.dart' as a hide A show B;");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10451,8 +10347,7 @@
 
   void test_parseImportDirective_prefix_show_hide() {
     createParser("import 'lib/lib.dart' as a show B hide A;");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10466,8 +10361,7 @@
 
   void test_parseImportDirective_show() {
     createParser("import 'lib/lib.dart' show A, B;");
-    ImportDirective directive =
-        parser.parseImportDirective(emptyCommentAndMetadata());
+    ImportDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.keyword, isNotNull);
@@ -10480,41 +10374,32 @@
   }
 
   void test_parseInitializedIdentifierList_type() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    Token staticKeyword = TokenFactory.tokenFromKeyword(Keyword.STATIC);
-    TypeName type =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser("a = 1, b, c = 3;");
-    FieldDeclaration declaration = parser.parseInitializedIdentifierList(
-        commentAndMetadata(comment), staticKeyword, null, null, type);
+    createParser("/// Doc\nstatic T a = 1, b, c = 3;");
+    FieldDeclaration declaration = parser.parseClassMember('C');
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
     VariableDeclarationList fields = declaration.fields;
     expect(fields, isNotNull);
     expect(fields.keyword, isNull);
-    expect(fields.type, type);
+    expect((fields.type as TypeName).name.name, 'T');
     expect(fields.variables, hasLength(3));
-    expect(declaration.staticKeyword, staticKeyword);
+    expect(declaration.staticKeyword.lexeme, 'static');
     expect(declaration.semicolon, isNotNull);
   }
 
   void test_parseInitializedIdentifierList_var() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    Token staticKeyword = TokenFactory.tokenFromKeyword(Keyword.STATIC);
-    Token varKeyword = TokenFactory.tokenFromKeyword(Keyword.VAR);
-    createParser('a = 1, b, c = 3;');
-    FieldDeclaration declaration = parser.parseInitializedIdentifierList(
-        commentAndMetadata(comment), staticKeyword, null, varKeyword, null);
+    createParser('/// Doc\nstatic var a = 1, b, c = 3;');
+    FieldDeclaration declaration = parser.parseClassMember('C');
     expectNotNullIfNoErrors(declaration);
     listener.assertNoErrors();
-    expect(declaration.documentationComment, comment);
+    _expectCommentText(declaration.documentationComment, '/// Doc');
     VariableDeclarationList fields = declaration.fields;
     expect(fields, isNotNull);
-    expect(fields.keyword, varKeyword);
+    expect(fields.keyword.lexeme, 'var');
     expect(fields.type, isNull);
     expect(fields.variables, hasLength(3));
-    expect(declaration.staticKeyword, staticKeyword);
+    expect(declaration.staticKeyword.lexeme, 'static');
     expect(declaration.semicolon, isNotNull);
   }
 
@@ -10765,8 +10650,7 @@
 
   void test_parseLibraryDirective() {
     createParser('library l;');
-    LibraryDirective directive =
-        parser.parseLibraryDirective(emptyCommentAndMetadata());
+    LibraryDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.libraryKeyword, isNotNull);
@@ -11726,16 +11610,12 @@
   }
 
   void test_parseOperator() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('operator +(A a);');
-    MethodDeclaration method =
-        parser.parseOperator(commentAndMetadata(comment), null, returnType);
+    createParser('/// Doc\nT operator +(A a);');
+    MethodDeclaration method = parser.parseClassMember('C');
     expectNotNullIfNoErrors(method);
     listener.assertNoErrors();
     expect(method.body, isNotNull);
-    expect(method.documentationComment, comment);
+    _expectCommentText(method.documentationComment, '/// Doc');
     expect(method.externalKeyword, isNull);
     expect(method.modifierKeyword, isNull);
     expect(method.name, isNotNull);
@@ -11743,7 +11623,7 @@
     expect(method.typeParameters, isNull);
     expect(method.parameters, isNotNull);
     expect(method.propertyKeyword, isNull);
-    expect(method.returnType, returnType);
+    expect((method.returnType as TypeName).name.name, 'T');
   }
 
   void test_parseOptionalReturnType() {
@@ -11752,8 +11632,7 @@
 
   void test_parsePartDirective() {
     createParser("part 'lib/lib.dart';");
-    PartDirective directive =
-        parser.parsePartOrPartOfDirective(emptyCommentAndMetadata());
+    PartDirective directive = parseFullDirective();
     expectNotNullIfNoErrors(directive);
     listener.assertNoErrors();
     expect(directive.partKeyword, isNotNull);
@@ -11764,8 +11643,7 @@
   void test_parsePartOfDirective_name() {
     enableUriInPartOf = true;
     createParser("part of l;");
-    PartOfDirective directive =
-        parser.parsePartOrPartOfDirective(emptyCommentAndMetadata());
+    PartOfDirective directive = parseFullDirective();
     expect(directive.partKeyword, isNotNull);
     expect(directive.ofKeyword, isNotNull);
     expect(directive.libraryName, isNotNull);
@@ -11776,8 +11654,7 @@
   void test_parsePartOfDirective_uri() {
     enableUriInPartOf = true;
     createParser("part of 'lib.dart';");
-    PartOfDirective directive =
-        parser.parsePartOrPartOfDirective(emptyCommentAndMetadata());
+    PartOfDirective directive = parseFullDirective();
     expect(directive.partKeyword, isNotNull);
     expect(directive.ofKeyword, isNotNull);
     expect(directive.libraryName, isNull);
@@ -12446,16 +12323,12 @@
   }
 
   void test_parseSetter_nonStatic() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('set a(var x);');
-    MethodDeclaration method =
-        parser.parseSetter(commentAndMetadata(comment), null, null, returnType);
+    createParser('/// Doc\nT set a(var x);');
+    MethodDeclaration method = parser.parseClassMember('C');
     expectNotNullIfNoErrors(method);
     listener.assertNoErrors();
     expect(method.body, isNotNull);
-    expect(method.documentationComment, comment);
+    _expectCommentText(method.documentationComment, '/// Doc');
     expect(method.externalKeyword, isNull);
     expect(method.modifierKeyword, isNull);
     expect(method.name, isNotNull);
@@ -12463,29 +12336,24 @@
     expect(method.typeParameters, isNull);
     expect(method.parameters, isNotNull);
     expect(method.propertyKeyword, isNotNull);
-    expect(method.returnType, returnType);
+    expect((method.returnType as TypeName).name.name, 'T');
   }
 
   void test_parseSetter_static() {
-    Comment comment = astFactory.documentationComment(new List<Token>(0));
-    Token staticKeyword = TokenFactory.tokenFromKeyword(Keyword.STATIC);
-    TypeName returnType =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('set a(var x) {}');
-    MethodDeclaration method = parser.parseSetter(
-        commentAndMetadata(comment), null, staticKeyword, returnType);
+    createParser('/// Doc\nstatic T set a(var x) {}');
+    MethodDeclaration method = parser.parseClassMember('C');
     expectNotNullIfNoErrors(method);
     listener.assertNoErrors();
     expect(method.body, isNotNull);
-    expect(method.documentationComment, comment);
+    _expectCommentText(method.documentationComment, '/// Doc');
     expect(method.externalKeyword, isNull);
-    expect(method.modifierKeyword, staticKeyword);
+    expect(method.modifierKeyword.lexeme, 'static');
     expect(method.name, isNotNull);
     expect(method.operatorKeyword, isNull);
     expect(method.typeParameters, isNull);
     expect(method.parameters, isNotNull);
     expect(method.propertyKeyword, isNotNull);
-    expect(method.returnType, returnType);
+    expect((method.returnType as TypeName).name.name, 'T');
   }
 
   void test_parseShiftExpression_normal() {
@@ -12636,13 +12504,12 @@
   }
 
   void test_parseStatements_multiple() {
-    List<Statement> statements =
-        ParserTestCase.parseStatements("return; return;", 2);
+    List<Statement> statements = parseStatements("return; return;", 2);
     expect(statements, hasLength(2));
   }
 
   void test_parseStatements_single() {
-    List<Statement> statements = ParserTestCase.parseStatements("return;", 1);
+    List<Statement> statements = parseStatements("return;", 1);
     expect(statements, hasLength(1));
   }
 
@@ -13261,8 +13128,7 @@
 
   void test_parseTypeAlias_function_noParameters() {
     createParser('typedef bool F();');
-    FunctionTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    FunctionTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13275,8 +13141,7 @@
 
   void test_parseTypeAlias_function_noReturnType() {
     createParser('typedef F();');
-    FunctionTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    FunctionTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13289,8 +13154,7 @@
 
   void test_parseTypeAlias_function_parameterizedReturnType() {
     createParser('typedef A<B> F();');
-    FunctionTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    FunctionTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13303,8 +13167,7 @@
 
   void test_parseTypeAlias_function_parameters() {
     createParser('typedef bool F(Object value);');
-    FunctionTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    FunctionTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13317,8 +13180,7 @@
 
   void test_parseTypeAlias_function_typeParameters() {
     createParser('typedef bool F<E>();');
-    FunctionTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    FunctionTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13331,8 +13193,7 @@
 
   void test_parseTypeAlias_function_voidReturnType() {
     createParser('typedef void F();');
-    FunctionTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    FunctionTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13346,8 +13207,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_noParameters() {
     createParser('typedef F = bool Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13364,8 +13224,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_noReturnType() {
     createParser('typedef F = Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13382,8 +13241,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_parameterizedReturnType() {
     createParser('typedef F = A<B> Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13400,8 +13258,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_parameters() {
     createParser('typedef F = bool Function(Object value);');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13418,8 +13275,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_typeParameters() {
     createParser('typedef F = bool Function<E>();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13436,8 +13292,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_typeParameters_noParameters() {
     createParser('typedef F<T> = bool Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13454,8 +13309,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_typeParameters_noReturnType() {
     createParser('typedef F<T> = Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13473,8 +13327,7 @@
   void
       test_parseTypeAlias_genericFunction_typeParameters_parameterizedReturnType() {
     createParser('typedef F<T> = A<B> Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13491,8 +13344,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_typeParameters_parameters() {
     createParser('typedef F<T> = bool Function(Object value);');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13509,8 +13361,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_typeParameters_typeParameters() {
     createParser('typedef F<T> = bool Function<E>();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13527,8 +13378,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_typeParameters_voidReturnType() {
     createParser('typedef F<T> = void Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -13545,8 +13395,7 @@
   @failingTest
   void test_parseTypeAlias_genericFunction_voidReturnType() {
     createParser('typedef F = void Function();');
-    GenericTypeAlias typeAlias =
-        parser.parseTypeAlias(emptyCommentAndMetadata());
+    GenericTypeAlias typeAlias = parseFullCompilationUnitMember();
     expectNotNullIfNoErrors(typeAlias);
     listener.assertNoErrors();
     expect(typeAlias.typedefKeyword, isNotNull);
@@ -14167,8 +14016,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_const_noType() {
     createParser('const a');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNotNull);
@@ -14178,8 +14027,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_const_type() {
     createParser('const A a');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNotNull);
@@ -14189,8 +14038,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_final_noType() {
     createParser('final a');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNotNull);
@@ -14200,8 +14049,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_final_type() {
     createParser('final A a');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNotNull);
@@ -14212,8 +14061,8 @@
   void test_parseVariableDeclarationListAfterMetadata_final_typeComment() {
     enableGenericMethodComments = true;
     createParser('final/*=T*/ x');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect((declarationList.type as TypeName).name.name, 'T');
@@ -14222,8 +14071,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_type_multiple() {
     createParser('A a, b, c');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNull);
@@ -14233,8 +14082,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_type_single() {
     createParser('A a');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNull);
@@ -14244,8 +14093,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_var_multiple() {
     createParser('var a, b, c');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNotNull);
@@ -14255,8 +14104,8 @@
 
   void test_parseVariableDeclarationListAfterMetadata_var_single() {
     createParser('var a');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNotNull);
@@ -14267,8 +14116,8 @@
   void test_parseVariableDeclarationListAfterMetadata_var_typeComment() {
     enableGenericMethodComments = true;
     createParser('var/*=T*/ x');
-    VariableDeclarationList declarationList = parser
-        .parseVariableDeclarationListAfterMetadata(emptyCommentAndMetadata());
+    VariableDeclarationList declarationList =
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect((declarationList.type as TypeName).name.name, 'T');
@@ -14276,37 +14125,30 @@
   }
 
   void test_parseVariableDeclarationListAfterType_type() {
-    TypeName type =
-        astFactory.typeName(astFactory.simpleIdentifier(null), null);
-    createParser('a');
+    createParser('T a');
     VariableDeclarationList declarationList =
-        parser.parseVariableDeclarationListAfterType(
-            emptyCommentAndMetadata(), null, type);
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
     expect(declarationList.keyword, isNull);
-    expect(declarationList.type, type);
+    expect((declarationList.type as TypeName).name.name, 'T');
     expect(declarationList.variables, hasLength(1));
   }
 
   void test_parseVariableDeclarationListAfterType_var() {
-    Token keyword = TokenFactory.tokenFromKeyword(Keyword.VAR);
-    createParser('a, b, c');
+    createParser('var a, b, c');
     VariableDeclarationList declarationList =
-        parser.parseVariableDeclarationListAfterType(
-            emptyCommentAndMetadata(), keyword, null);
+        parseFullVariableDeclarationList();
     expectNotNullIfNoErrors(declarationList);
     listener.assertNoErrors();
-    expect(declarationList.keyword, keyword);
+    expect(declarationList.keyword.lexeme, 'var');
     expect(declarationList.type, isNull);
     expect(declarationList.variables, hasLength(3));
   }
 
   void test_parseVariableDeclarationStatementAfterMetadata_multiple() {
     createParser('var x, y, z;');
-    VariableDeclarationStatement statement =
-        parser.parseVariableDeclarationStatementAfterMetadata(
-            emptyCommentAndMetadata());
+    VariableDeclarationStatement statement = parser.parseStatement2();
     expectNotNullIfNoErrors(statement);
     listener.assertNoErrors();
     expect(statement.semicolon, isNotNull);
@@ -14317,9 +14159,7 @@
 
   void test_parseVariableDeclarationStatementAfterMetadata_single() {
     createParser('var x;');
-    VariableDeclarationStatement statement =
-        parser.parseVariableDeclarationStatementAfterMetadata(
-            emptyCommentAndMetadata());
+    VariableDeclarationStatement statement = parser.parseStatement2();
     expectNotNullIfNoErrors(statement);
     listener.assertNoErrors();
     expect(statement.semicolon, isNotNull);
@@ -14523,6 +14363,11 @@
     return value;
   }
 
+  void _expectCommentText(Comment comment, String expectedText) {
+    expect(comment.beginToken, same(comment.endToken));
+    expect(comment.beginToken.lexeme, expectedText);
+  }
+
   void _expectDottedName(DottedName name, List<String> expectedComponents) {
     int count = expectedComponents.length;
     NodeList<SimpleIdentifier> components = name.components;
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 957d94c..8d21db67 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -1040,8 +1040,7 @@
   }
 }''';
     CompilationUnit unit = await resolveSource(code);
-    DartType t =
-        findMarkedIdentifier(code, unit, "; // marker").propagatedType;
+    DartType t = findMarkedIdentifier(code, unit, "; // marker").propagatedType;
     expect(typeProvider.intType.isSubtypeOf(t), isTrue);
     expect(typeProvider.stringType.isSubtypeOf(t), isTrue);
   }
@@ -1074,8 +1073,7 @@
   }
 }''';
     CompilationUnit unit = await resolveSource(code);
-    DartType t =
-        findMarkedIdentifier(code, unit, "; // marker").propagatedType;
+    DartType t = findMarkedIdentifier(code, unit, "; // marker").propagatedType;
     expect(typeProvider.intType.isSubtypeOf(t), isTrue);
     expect(typeProvider.stringType.isSubtypeOf(t), isTrue);
   }
@@ -2083,8 +2081,7 @@
       expect(identifier.propagatedType, null);
     }
     {
-      SimpleIdentifier identifier =
-          findMarkedIdentifier(code, unit, "v = '';");
+      SimpleIdentifier identifier = findMarkedIdentifier(code, unit, "v = '';");
       expect(identifier.propagatedType, typeProvider.stringType);
     }
   }
@@ -2425,7 +2422,8 @@
     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 futureOrType =
+        _classElement("FutureOr", objectType, ["T"]).type;
     InterfaceType intType = _classElement("int", numType).type;
     InterfaceType iterableType =
         _classElement("Iterable", objectType, ["T"]).type;
@@ -2454,7 +2452,11 @@
     ];
     CompilationUnitElementImpl asyncUnit =
         new CompilationUnitElementImpl("async.dart");
-    asyncUnit.types = <ClassElement>[futureType.element, futureOrType.element, streamType.element];
+    asyncUnit.types = <ClassElement>[
+      futureType.element,
+      futureOrType.element,
+      streamType.element
+    ];
     AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
     LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
         context, AstTestFactory.libraryIdentifier2(["dart.core"]));
@@ -2512,7 +2514,7 @@
 }
 
 @reflectiveTest
-class TypeResolverVisitorTest {
+class TypeResolverVisitorTest extends ParserTestCase {
   /**
    * The error listener to which errors will be reported.
    */
@@ -2573,7 +2575,7 @@
   }
 
   test_modeApi() async {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(r'''
+    CompilationUnit unit = parseCompilationUnit(r'''
 class C extends A with A implements A {
   A f = new A();
   A m() {
@@ -3567,7 +3569,7 @@
    */
   void _resolveTypeModeLocal(
       String code, AstNode getNodeToResolve(CompilationUnit unit)) {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit2(code);
+    CompilationUnit unit = parseCompilationUnit2(code);
     var unitElement = new CompilationUnitElementImpl('/test.dart');
 
     // Build API elements.
diff --git a/pkg/analyzer/test/generated/simple_resolver_test.dart b/pkg/analyzer/test/generated/simple_resolver_test.dart
index f8ce31e..cf3cc2e 100644
--- a/pkg/analyzer/test/generated/simple_resolver_test.dart
+++ b/pkg/analyzer/test/generated/simple_resolver_test.dart
@@ -16,6 +16,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../utils.dart';
 import 'resolver_test_case.dart';
 import 'test_support.dart';
 
@@ -127,7 +128,7 @@
   }
 
   test_argumentResolution_setter_propagated() async {
-    Source source = addSource(r'''
+    CompilationUnit unit = await resolveSource(r'''
 main() {
   var a = new A();
   a.sss = 0;
@@ -135,17 +136,12 @@
 class A {
   set sss(x) {}
 }''');
-    LibraryElement library = resolve2(source);
-    CompilationUnitElement unit = library.definingCompilationUnit;
     // find "a.sss = 0"
     AssignmentExpression assignment;
     {
-      FunctionElement mainElement = unit.functions[0];
-      FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
-      Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
-      ExpressionStatement expressionStatement =
-          statement as ExpressionStatement;
-      assignment = expressionStatement.expression as AssignmentExpression;
+      var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
+      var statement = statements[1] as ExpressionStatement;
+      assignment = statement.expression as AssignmentExpression;
     }
     // get parameter
     Expression rhs = assignment.rightHandSide;
@@ -154,13 +150,13 @@
     expect(parameter, isNotNull);
     expect(parameter.displayName, "x");
     // validate
-    ClassElement classA = unit.types[0];
+    ClassElement classA = unit.element.types[0];
     PropertyAccessorElement setter = classA.accessors[0];
     expect(setter.parameters[0], same(parameter));
   }
 
   test_argumentResolution_setter_propagated_propertyAccess() async {
-    Source source = addSource(r'''
+    CompilationUnit unit = await resolveSource(r'''
 main() {
   var a = new A();
   a.b.sss = 0;
@@ -171,17 +167,12 @@
 class B {
   set sss(x) {}
 }''');
-    LibraryElement library = resolve2(source);
-    CompilationUnitElement unit = library.definingCompilationUnit;
     // find "a.b.sss = 0"
     AssignmentExpression assignment;
     {
-      FunctionElement mainElement = unit.functions[0];
-      FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
-      Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
-      ExpressionStatement expressionStatement =
-          statement as ExpressionStatement;
-      assignment = expressionStatement.expression as AssignmentExpression;
+      var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
+      var statement = statements[1] as ExpressionStatement;
+      assignment = statement.expression as AssignmentExpression;
     }
     // get parameter
     Expression rhs = assignment.rightHandSide;
@@ -190,13 +181,13 @@
     expect(parameter, isNotNull);
     expect(parameter.displayName, "x");
     // validate
-    ClassElement classB = unit.types[1];
+    ClassElement classB = unit.element.types[1];
     PropertyAccessorElement setter = classB.accessors[0];
     expect(setter.parameters[0], same(parameter));
   }
 
   test_argumentResolution_setter_static() async {
-    Source source = addSource(r'''
+    CompilationUnit unit = await resolveSource(r'''
 main() {
   A a = new A();
   a.sss = 0;
@@ -204,17 +195,12 @@
 class A {
   set sss(x) {}
 }''');
-    LibraryElement library = resolve2(source);
-    CompilationUnitElement unit = library.definingCompilationUnit;
     // find "a.sss = 0"
     AssignmentExpression assignment;
     {
-      FunctionElement mainElement = unit.functions[0];
-      FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
-      Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
-      ExpressionStatement expressionStatement =
-          statement as ExpressionStatement;
-      assignment = expressionStatement.expression as AssignmentExpression;
+      var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
+      var statement = statements[1] as ExpressionStatement;
+      assignment = statement.expression as AssignmentExpression;
     }
     // get parameter
     Expression rhs = assignment.rightHandSide;
@@ -222,13 +208,13 @@
     expect(parameter, isNotNull);
     expect(parameter.displayName, "x");
     // validate
-    ClassElement classA = unit.types[0];
+    ClassElement classA = unit.element.types[0];
     PropertyAccessorElement setter = classA.accessors[0];
     expect(setter.parameters[0], same(parameter));
   }
 
   test_argumentResolution_setter_static_propertyAccess() async {
-    Source source = addSource(r'''
+    CompilationUnit unit = await resolveSource(r'''
 main() {
   A a = new A();
   a.b.sss = 0;
@@ -239,17 +225,12 @@
 class B {
   set sss(x) {}
 }''');
-    LibraryElement library = resolve2(source);
-    CompilationUnitElement unit = library.definingCompilationUnit;
     // find "a.b.sss = 0"
     AssignmentExpression assignment;
     {
-      FunctionElement mainElement = unit.functions[0];
-      FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
-      Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
-      ExpressionStatement expressionStatement =
-          statement as ExpressionStatement;
-      assignment = expressionStatement.expression as AssignmentExpression;
+      var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
+      var statement = statements[1] as ExpressionStatement;
+      assignment = statement.expression as AssignmentExpression;
     }
     // get parameter
     Expression rhs = assignment.rightHandSide;
@@ -257,7 +238,7 @@
     expect(parameter, isNotNull);
     expect(parameter.displayName, "x");
     // validate
-    ClassElement classB = unit.types[1];
+    ClassElement classB = unit.element.types[1];
     PropertyAccessorElement setter = classB.accessors[0];
     expect(setter.parameters[0], same(parameter));
   }
@@ -741,17 +722,15 @@
   }
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that both the getter and setter for "x" in C.f() refer to the
     // accessors defined in M2.
-    ClassElement classC = library.definingCompilationUnit.types[3];
-    MethodDeclaration f = classC.getMethod('f').computeNode();
-    BlockFunctionBody body = f.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    AssignmentExpression assignment = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInMethod(analysisResult.unit, 'C', 'f');
+    var statement = statements[0] as ExpressionStatement;
+    AssignmentExpression assignment = statement.expression;
     SimpleIdentifier leftHandSide = assignment.leftHandSide;
     expect(
         resolutionMap
@@ -768,7 +747,7 @@
     // TODO(paulberry): it appears that auxiliaryElements isn't properly set on
     // a SimpleIdentifier that's inside a property access.  This bug should be
     // fixed.
-    Source source = addSource('''
+    Source source = addSource(r'''
 class B {}
 class M1 {
   get x => null;
@@ -783,17 +762,15 @@
   new C().x += 1;
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that both the getter and setter for "x" in "new C().x" refer to
     // the accessors defined in M2.
-    FunctionDeclaration main =
-        library.definingCompilationUnit.functions[0].computeNode();
-    BlockFunctionBody body = main.functionExpression.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    AssignmentExpression assignment = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(analysisResult.unit, 'main');
+    var statement = statements[0] as ExpressionStatement;
+    AssignmentExpression assignment = statement.expression;
     PropertyAccess propertyAccess = assignment.leftHandSide;
     expect(
         resolutionMap
@@ -822,17 +799,15 @@
   }
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the getter for "x" in C.f() refers to the getter defined in
     // M2.
-    ClassElement classC = library.definingCompilationUnit.types[3];
-    MethodDeclaration f = classC.getMethod('f').computeNode();
-    BlockFunctionBody body = f.body;
-    ReturnStatement stmt = body.block.statements[0];
-    SimpleIdentifier x = stmt.expression;
+    var statements =
+        AstFinder.getStatementsInMethod(analysisResult.unit, 'C', 'f');
+    var statement = statements[0] as ReturnStatement;
+    SimpleIdentifier x = statement.expression;
     expect(resolutionMap.staticElementForIdentifier(x).enclosingElement.name,
         'M2');
   }
@@ -851,17 +826,16 @@
   var y = new C().x;
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the getter for "x" in "new C().x" refers to the getter
     // defined in M2.
-    FunctionDeclaration main =
-        library.definingCompilationUnit.functions[0].computeNode();
-    BlockFunctionBody body = main.functionExpression.body;
-    VariableDeclarationStatement stmt = body.block.statements[0];
-    PropertyAccess propertyAccess = stmt.variables.variables[0].initializer;
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(analysisResult.unit, 'main');
+    var statement = statements[0] as VariableDeclarationStatement;
+    PropertyAccess propertyAccess =
+        statement.variables.variables[0].initializer;
     expect(
         resolutionMap
             .staticElementForIdentifier(propertyAccess.propertyName)
@@ -1571,16 +1545,14 @@
   new C().f();
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the "f" in "new C().f()" refers to the "f" defined in M2.
-    FunctionDeclaration main =
-        library.definingCompilationUnit.functions[0].computeNode();
-    BlockFunctionBody body = main.functionExpression.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    MethodInvocation expr = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(analysisResult.unit, 'main');
+    var statement = statements[0] as ExpressionStatement;
+    MethodInvocation expr = statement.expression;
     expect(
         resolutionMap
             .staticElementForIdentifier(expr.methodName)
@@ -1604,16 +1576,14 @@
   }
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the call to f() in C.g() refers to the method defined in M2.
-    ClassElement classC = library.definingCompilationUnit.types[3];
-    MethodDeclaration g = classC.getMethod('g').computeNode();
-    BlockFunctionBody body = g.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    MethodInvocation invocation = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInMethod(analysisResult.unit, 'C', 'g');
+    var statement = statements[0] as ExpressionStatement;
+    MethodInvocation invocation = statement.expression;
     SimpleIdentifier methodName = invocation.methodName;
     expect(
         resolutionMap
@@ -1623,7 +1593,7 @@
         'M2');
   }
 
-  test_method_fromMixins_invked_from_outside_class() async {
+  test_method_fromMixins_invoked_from_outside_class() async {
     Source source = addSource('''
 class B {}
 class M1 {
@@ -1637,17 +1607,15 @@
   new C().f();
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the call to f() in "new C().f()" refers to the method
     // defined in M2.
-    FunctionDeclaration main =
-        library.definingCompilationUnit.functions[0].computeNode();
-    BlockFunctionBody body = main.functionExpression.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    MethodInvocation invocation = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(analysisResult.unit, 'main');
+    var statement = statements[0] as ExpressionStatement;
+    MethodInvocation invocation = statement.expression;
     expect(
         resolutionMap
             .staticElementForIdentifier(invocation.methodName)
@@ -1732,17 +1700,15 @@
   }
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the setter for "x" in C.f() refers to the setter defined in
     // M2.
-    ClassElement classC = library.definingCompilationUnit.types[3];
-    MethodDeclaration f = classC.getMethod('f').computeNode();
-    BlockFunctionBody body = f.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    AssignmentExpression assignment = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInMethod(analysisResult.unit, 'C', 'f');
+    var statement = statements[0] as ExpressionStatement;
+    AssignmentExpression assignment = statement.expression;
     SimpleIdentifier leftHandSide = assignment.leftHandSide;
     expect(
         resolutionMap
@@ -1766,17 +1732,15 @@
   new C().x = 1;
 }
 ''');
-    LibraryElement library = resolve2(source);
-    await computeAnalysisResult(source);
+    var analysisResult = await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
     // Verify that the setter for "x" in "new C().x" refers to the setter
     // defined in M2.
-    FunctionDeclaration main =
-        library.definingCompilationUnit.functions[0].computeNode();
-    BlockFunctionBody body = main.functionExpression.body;
-    ExpressionStatement stmt = body.block.statements[0];
-    AssignmentExpression assignment = stmt.expression;
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(analysisResult.unit, 'main');
+    var statement = statements[0] as ExpressionStatement;
+    AssignmentExpression assignment = statement.expression;
     PropertyAccess propertyAccess = assignment.leftHandSide;
     expect(
         resolutionMap
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 838f146..68b7170 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -2224,9 +2224,12 @@
   }
 
   test_genericFunction_parameter() async {
-    await resolveTestUnit(r'''
+    await resolveTestUnit(
+        r'''
 void g(/*=T*/ f/*<T>*/(/*=T*/ x)) {}
-''');
+''',
+        noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
     expectFunctionType('f', '<T>(T) → T',
         elementTypeParams: '[T]', typeFormals: '[T]');
     SimpleIdentifier f = findIdentifier('f');
@@ -2346,7 +2349,8 @@
   }
 
   test_genericMethod_functionExpressionInvocation_explicit() async {
-    await resolveTestUnit(r'''
+    await resolveTestUnit(
+        r'''
 class C<E> {
   /*=T*/ f/*<T>*/(/*=T*/ e) => null;
   static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
@@ -2368,7 +2372,9 @@
   var localCall = (lf)/*<int>*/(3);
   var paramCall = (pf)/*<int>*/(3);
 }
-''');
+''',
+        noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -2380,7 +2386,8 @@
   }
 
   test_genericMethod_functionExpressionInvocation_inferred() async {
-    await resolveTestUnit(r'''
+    await resolveTestUnit(
+        r'''
 class C<E> {
   /*=T*/ f/*<T>*/(/*=T*/ e) => null;
   static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
@@ -2402,7 +2409,9 @@
   var localCall = (lf)(3);
   var paramCall = (pf)(3);
 }
-''');
+''',
+        noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -2414,7 +2423,8 @@
   }
 
   test_genericMethod_functionInvocation_explicit() async {
-    await resolveTestUnit(r'''
+    await resolveTestUnit(
+        r'''
 class C<E> {
   /*=T*/ f/*<T>*/(/*=T*/ e) => null;
   static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
@@ -2434,7 +2444,9 @@
   var localCall = lf/*<int>*/(3);
   var paramCall = pf/*<int>*/(3);
 }
-''');
+''',
+        noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -2445,7 +2457,8 @@
   }
 
   test_genericMethod_functionInvocation_inferred() async {
-    await resolveTestUnit(r'''
+    await resolveTestUnit(
+        r'''
 class C<E> {
   /*=T*/ f/*<T>*/(/*=T*/ e) => null;
   static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
@@ -2465,7 +2478,9 @@
   var localCall = lf(3);
   var paramCall = pf(3);
 }
-''');
+''',
+        noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -2710,7 +2725,8 @@
   }
 
   test_genericMethod_tearoff() async {
-    await resolveTestUnit(r'''
+    await resolveTestUnit(
+        r'''
 class C<E> {
   /*=T*/ f/*<T>*/(E e) => null;
   static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
@@ -2730,7 +2746,9 @@
   var localTearOff = lf;
   var paramTearOff = pf;
 }
-''');
+''',
+        noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
     expectIdentifierType('methodTearOff', "<T>(int) → T");
     expectIdentifierType('staticTearOff', "<T>(T) → T");
     expectIdentifierType('staticFieldTearOff', "<T>(T) → T");
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index 4ad2c63..d46f666 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -32,6 +32,7 @@
 import 'non_error_resolver_test.dart' as non_error_resolver_test;
 import 'non_hint_code_driver_test.dart' as non_hint_code_driver_test;
 import 'non_hint_code_test.dart' as non_hint_code_test;
+import 'parser_fasta_test.dart' as parser_fasta_test;
 import 'parser_test.dart' as parser_test;
 import 'resolver_driver_test.dart' as resolver_driver_test;
 import 'resolver_test.dart' as resolver_test;
@@ -80,6 +81,7 @@
     non_error_resolver_test.main();
     non_hint_code_driver_test.main();
     non_hint_code_test.main();
+    parser_fasta_test.main();
     parser_test.main();
     resolver_driver_test.main();
     resolver_test.main();
diff --git a/pkg/analyzer/test/generated/utilities_dart_test.dart b/pkg/analyzer/test/generated/utilities_dart_test.dart
index 1917b16..f616027 100644
--- a/pkg/analyzer/test/generated/utilities_dart_test.dart
+++ b/pkg/analyzer/test/generated/utilities_dart_test.dart
@@ -38,9 +38,7 @@
     _validate('a/b.dart', '../c.dart', 'c.dart');
     _validate('a.dart', '../b.dart', '../b.dart');
     _validate('a.dart', '../../b.dart', '../../b.dart');
-    // TODO(scheglov) After https://github.com/dart-lang/sdk/issues/27447
-    // TODO(scheglov) include also this, currently failing test.
-//    _validate('a/b.dart', '../../c.dart', '../c.dart');
+    _validate('a/b.dart', '../../c.dart', '../c.dart');
   }
 
   void _validate(String base, String contained, String expected) {
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 4569f8e..fab9f18 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -6,6 +6,7 @@
 
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/command_line/arguments.dart';
 import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/context/source.dart';
@@ -13,6 +14,9 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/lint/linter.dart';
+import 'package:analyzer/src/lint/registry.dart';
+import 'package:analyzer/src/services/lint.dart';
 import 'package:args/args.dart';
 import 'package:package_config/packages.dart';
 import 'package:package_config/src/packages_impl.dart';
@@ -125,7 +129,7 @@
 
     String path = resourceProvider.convertPath('/some/directory/path');
     String filePath =
-    pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+        pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
     resourceProvider.newFile(
         filePath,
         '''
@@ -304,6 +308,12 @@
     expect(packages, same(Packages.noPackages));
   }
 
+  void test_createPackageMap_rootDoesNotExist() {
+    String rootPath = resourceProvider.convertPath('/root');
+    Packages packages = builder.createPackageMap(rootPath);
+    expect(packages, same(Packages.noPackages));
+  }
+
   void test_createSourceFactory_bazelWorkspace_fileProvider() {
     String _p(String path) => resourceProvider.convertPath(path);
 
@@ -322,6 +332,25 @@
         contains(predicate((r) => r is BazelPackageUriResolver)));
   }
 
+  void test_createSourceFactory_bazelWorkspace_withPackagesFile() {
+    String _p(String path) => resourceProvider.convertPath(path);
+
+    String projectPath = _p('/workspace/my/module');
+    resourceProvider.newFile(_p('/workspace/WORKSPACE'), '');
+    resourceProvider.newFolder(_p('/workspace/bazel-bin'));
+    resourceProvider.newFolder(_p('/workspace/bazel-genfiles'));
+    resourceProvider.newFolder(projectPath);
+    resourceProvider.newFile(_p(path.join(projectPath, '.packages')), '');
+
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    SourceFactoryImpl factory =
+        builder.createSourceFactory(projectPath, options);
+    expect(factory.resolvers,
+        contains(predicate((r) => r is ResourceUriResolver)));
+    expect(factory.resolvers,
+        contains(predicate((r) => r is PackageMapUriResolver)));
+  }
+
   void test_createSourceFactory_noProvider_packages_embedder_extensions() {
     String rootPath = resourceProvider.convertPath('/root');
     Folder rootFolder = resourceProvider.getFolder(rootPath);
@@ -521,6 +550,67 @@
     expect(htmlSource.exists(), isTrue);
   }
 
+  void test_getAnalysisOptions_default_bazel() {
+    MockLintRule mockLintRule = new MockLintRule('mock_lint_rule');
+    Registry.ruleRegistry.register(mockLintRule);
+    MockLintRule mockLintRule2 = new MockLintRule('mock_lint_rule2');
+    Registry.ruleRegistry.register(mockLintRule2);
+    AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+    builderOptions.defaultOptions = defaultOptions;
+    AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
+    expected.lint = true;
+    expected.lintRules = <Linter>[mockLintRule];
+    createFile(resourceProvider.convertPath('/root/WORKSPACE'), '');
+    createFile(
+        resourceProvider
+            .convertPath('/root/dart/analysis_options/lib/default.yaml'),
+        '''
+linter:
+  rules:
+    - mock_lint_rule
+''');
+    createFile(
+        resourceProvider
+            .convertPath('/root/dart/analysis_options/lib/flutter.yaml'),
+        '''
+linter:
+  rules:
+    - mock_lint_rule2
+''');
+    AnalysisOptions options = builder
+        .getAnalysisOptions(resourceProvider.convertPath('/root/some/path'));
+    _expectEqualOptions(options, expected);
+  }
+
+  void test_getAnalysisOptions_default_flutter() {
+    MockLintRule mockLintRule = new MockLintRule('mock_lint_rule');
+    Registry.ruleRegistry.register(mockLintRule);
+    AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+    builderOptions.defaultOptions = defaultOptions;
+    AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
+    expected.lint = true;
+    expected.lintRules = <Linter>[mockLintRule];
+    createFile(
+        resourceProvider.convertPath('/some/directory/path/.packages'),
+        '''
+flutter:/pkg/flutter/lib/
+''');
+    createFile(
+        resourceProvider
+            .convertPath('/pkg/flutter/lib/analysis_options_user.yaml'),
+        '''
+linter:
+  rules:
+    - mock_lint_rule
+''');
+    AnalysisOptions options = builder.getAnalysisOptions(
+        resourceProvider.convertPath('/some/directory/path'));
+    // TODO(danrubel) fix on Windows
+    if (resourceProvider.absolutePathContext.separator != r'\') {
+      _expectEqualOptions(options, expected);
+    }
+  }
+
   void test_getAnalysisOptions_default_noOverrides() {
     AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
     defaultOptions.enableLazyAssignmentOperators = true;
@@ -544,6 +634,7 @@
 
   void test_getAnalysisOptions_default_overrides() {
     AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+    defaultOptions.enableSuperMixins = false;
     defaultOptions.enableLazyAssignmentOperators = true;
     builderOptions.defaultOptions = defaultOptions;
     AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
@@ -565,14 +656,26 @@
   }
 
   void test_getAnalysisOptions_includes() {
+    MockLintRule mockLintRule = new MockLintRule('mock_lint_rule');
+    Registry.ruleRegistry.register(mockLintRule);
+    MockLintRule mockLintRule2 = new MockLintRule('mock_lint_rule2');
+    Registry.ruleRegistry.register(mockLintRule2);
+    MockLintRule mockLintRule3 = new MockLintRule('mock_lint_rule3');
+    Registry.ruleRegistry.register(mockLintRule3);
+
     AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+    defaultOptions.enableSuperMixins = false;
     builderOptions.defaultOptions = defaultOptions;
     AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
     expected.enableSuperMixins = true;
+    expected.lint = true;
+    expected.lintRules = <Linter>[mockLintRule, mockLintRule2, mockLintRule3];
     resourceProvider.newFile(
         resourceProvider.convertPath('/mypkgs/somepkg/lib/here.yaml'),
         '''
-two: {boo: newt}
+linter:
+  rules:
+    - mock_lint_rule3
 ''');
     String path = resourceProvider.convertPath('/some/directory/path');
     resourceProvider.newFile(
@@ -584,7 +687,12 @@
         pathContext.join(path, 'bar.yaml'),
         '''
 include: package:somepkg/here.yaml
-foo: {bar: baz}
+analyzer:
+  language:
+    enableSuperMixins : true
+linter:
+  rules:
+    - mock_lint_rule2
 ''');
     String filePath =
         pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
@@ -592,9 +700,9 @@
         filePath,
         '''
 include: bar.yaml
-analyzer:
-  language:
-    enableSuperMixins : true
+linter:
+  rules:
+    - mock_lint_rule
 ''');
 
     AnalysisOptions options = builder.getAnalysisOptions(path);
@@ -720,6 +828,10 @@
     expect(actual.incrementalApi, expected.incrementalApi);
     expect(actual.incrementalValidation, expected.incrementalValidation);
     expect(actual.lint, expected.lint);
+    expect(
+      actual.lintRules.map((l) => l.name),
+      unorderedEquals(expected.lintRules.map((l) => l.name)),
+    );
     expect(actual.preserveComments, expected.preserveComments);
     expect(actual.strongMode, expected.strongMode);
     expect(actual.strongModeHints, expected.strongModeHints);
@@ -758,3 +870,14 @@
     expect(locator.embedderYamls, hasLength(1));
   }
 }
+
+class MockLintRule implements LintRule {
+  final String _name;
+
+  MockLintRule(this._name);
+
+  @override
+  String get name => _name;
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 1f612b9..6595387 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -2534,6 +2534,7 @@
     _assertNoExceptions();
   }
 
+  @failingTest // TODO(paulberry): Remove the annotation when dartbug.com/28515 is fixed.
   void test_resolveCompilationUnit_existingElementModel() {
     prepareAnalysisContext(new AnalysisOptionsImpl()..strongMode = true);
     Source source = addSource(
diff --git a/pkg/analyzer/test/src/context/source_test.dart b/pkg/analyzer/test/src/context/source_test.dart
new file mode 100644
index 0000000..dcb81ac
--- /dev/null
+++ b/pkg/analyzer/test/src/context/source_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.context.source_test;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/source.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:package_config/packages.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'abstract_context.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(SourceFactoryImplTest);
+  });
+}
+
+@reflectiveTest
+class SourceFactoryImplTest extends AbstractContextTest {
+  void test_restoreUri() {
+    Map<String, Uri> packageUriMap = <String, Uri>{
+      'foo': Uri.parse('file:///pkgs/somepkg/lib/')
+    };
+    SourceFactoryImpl sourceFactory = new SourceFactoryImpl(
+      <UriResolver>[new ResourceUriResolver(resourceProvider)],
+      new _MockPackages(packageUriMap),
+    );
+    Uri uri = sourceFactory.restoreUri(newSource('/pkgs/somepkg/lib'));
+    // TODO(danrubel) fix on Windows
+    if (resourceProvider.absolutePathContext.separator != r'\') {
+      expect(uri, Uri.parse('package:foo/'));
+    }
+  }
+}
+
+/**
+ * An implementation of [Packages] used for testing.
+ */
+class _MockPackages implements Packages {
+  final Map<String, Uri> map;
+
+  _MockPackages(this.map);
+
+  @override
+  Iterable<String> get packages => map.keys;
+
+  @override
+  Map<String, Uri> asMap() => map;
+
+  @override
+  Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) {
+    fail('Unexpected invocation of resolve');
+    return null;
+  }
+}
diff --git a/pkg/analyzer/test/src/context/test_all.dart b/pkg/analyzer/test/src/context/test_all.dart
index ec38b52..886098f 100644
--- a/pkg/analyzer/test/src/context/test_all.dart
+++ b/pkg/analyzer/test/src/context/test_all.dart
@@ -9,6 +9,7 @@
 import 'builder_test.dart' as builder_test;
 import 'cache_test.dart' as cache_test;
 import 'context_test.dart' as context_test;
+import 'source_test.dart' as source_test;
 
 /// Utility for manually running all tests.
 main() {
@@ -16,5 +17,6 @@
     builder_test.main();
     cache_test.main();
     context_test.main();
+    source_test.main();
   }, name: 'context');
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
index 11452bc..558e232 100644
--- a/pkg/analyzer/test/src/dart/analysis/base.dart
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:test/test.dart';
+import 'package:typed_mock/typed_mock.dart';
 
 import '../../context/mock_sdk.dart';
 
@@ -51,10 +52,12 @@
   final StringBuffer logBuffer = new StringBuffer();
   PerformanceLog logger;
 
+  final UriResolver generatedUriResolver = new _GeneratedUriResolverMock();
   AnalysisDriverScheduler scheduler;
   AnalysisDriver driver;
   final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
   final List<AnalysisResult> allResults = <AnalysisResult>[];
+  final List<ExceptionResult> allExceptions = <ExceptionResult>[];
 
   String testProject;
   String testFile;
@@ -113,15 +116,19 @@
         'test',
         new SourceFactory([
           new DartUriResolver(sdk),
+          generatedUriResolver,
           new PackageMapUriResolver(provider, <String, List<Folder>>{
             'test': [provider.getFolder(testProject)]
           }),
           new ResourceUriResolver(provider)
         ], null, provider),
-        new AnalysisOptionsImpl()..strongMode = true);
+        new AnalysisOptionsImpl()
+          ..strongMode = true
+          ..enableUriInPartOf = true);
     scheduler.start();
-    driver.status.listen(allStatuses.add);
+    scheduler.status.listen(allStatuses.add);
     driver.results.listen(allResults.add);
+    driver.exceptions.listen(allExceptions.add);
   }
 
   String _p(String path) => provider.convertPath(path);
@@ -140,3 +147,5 @@
     super.visitElement(element);
   }
 }
+
+class _GeneratedUriResolverMock extends TypedMock implements UriResolver {}
diff --git a/pkg/analyzer/test/src/dart/analysis/defined_names_test.dart b/pkg/analyzer/test/src/dart/analysis/defined_names_test.dart
new file mode 100644
index 0000000..6b5131c
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/defined_names_test.dart
@@ -0,0 +1,58 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/analysis/defined_names.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../generated/parser_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(DefinedNamesTest);
+  });
+}
+
+@reflectiveTest
+class DefinedNamesTest extends ParserTestCase {
+  test_classMemberNames() {
+    DefinedNames names = _computeDefinedNames('''
+class A {
+  int a, b;
+  A();
+  A.c();
+  d() {}
+  get e => null;
+  set f(_) {}
+}
+class B {
+  g() {}
+}
+''');
+    expect(names.topLevelNames, unorderedEquals(['A', 'B']));
+    expect(names.classMemberNames,
+        unorderedEquals(['a', 'b', 'd', 'e', 'f', 'g']));
+  }
+
+  test_topLevelNames() {
+    DefinedNames names = _computeDefinedNames('''
+class A {}
+class B = Object with A;
+typedef C {}
+D() {}
+get E => null;
+set F(_) {}
+var G, H;
+''');
+    expect(names.topLevelNames,
+        unorderedEquals(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']));
+    expect(names.classMemberNames, isEmpty);
+  }
+
+  DefinedNames _computeDefinedNames(String code) {
+    CompilationUnit unit = parseCompilationUnit2(code);
+    return computeDefinedNames(unit);
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 30fc32e..7fcf61d 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -19,8 +19,11 @@
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/status.dart';
 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
+import 'package:analyzer/src/dart/constant/evaluation.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/resolver.dart' show ResolverErrorCode;
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -28,7 +31,9 @@
 import 'package:crypto/crypto.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:typed_mock/typed_mock.dart';
 
+import '../../../utils.dart';
 import '../../context/mock_sdk.dart';
 import 'base.dart';
 
@@ -111,8 +116,7 @@
     AnalysisResult result = await driver2.getResult(b);
     expect(result.path, b);
 
-    await driver1.status.firstWhere((status) => status.isIdle);
-    await driver2.status.firstWhere((status) => status.isIdle);
+    await scheduler.status.firstWhere((status) => status.isIdle);
 
     expect(allResults, hasLength(3));
     expect(allResults[0].path, b);
@@ -133,8 +137,7 @@
     driver1.priorityFiles = [a];
     driver2.priorityFiles = [a];
 
-    await driver1.status.firstWhere((status) => status.isIdle);
-    await driver2.status.firstWhere((status) => status.isIdle);
+    await scheduler.status.firstWhere((status) => status.isIdle);
 
     expect(allResults, hasLength(2));
     expect(allResults[0].path, a);
@@ -154,8 +157,7 @@
     driver1.priorityFiles = [b];
     driver2.priorityFiles = [b];
 
-    await driver1.status.firstWhere((status) => status.isIdle);
-    await driver2.status.firstWhere((status) => status.isIdle);
+    await scheduler.status.firstWhere((status) => status.isIdle);
 
     expect(allResults, hasLength(2));
     expect(allResults[0].path, b);
@@ -178,8 +180,7 @@
     driver1.priorityFiles = [a, c];
     driver2.priorityFiles = [a, c];
 
-    await driver1.status.firstWhere((status) => status.isIdle);
-    await driver2.status.firstWhere((status) => status.isIdle);
+    await scheduler.status.firstWhere((status) => status.isIdle);
 
     expect(allResults, hasLength(3));
     expect(allResults[0].path, a);
@@ -290,7 +291,7 @@
     }
 
     // Initial analysis, 'b' does not use 'a', so there is a hint.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     assertNumberOfErrorsInB(1);
 
     // Update 'b' to use 'a', no more hints.
@@ -303,7 +304,7 @@
 }
 ''');
     driver.changeFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     assertNumberOfErrorsInB(0);
 
     // Change 'b' content so that it has a hint.
@@ -316,7 +317,7 @@
 ''');
     driver.removeFile(b);
     driver.addFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     assertNumberOfErrorsInB(1);
   }
 
@@ -331,13 +332,162 @@
     // Now remove 'a'.
     driver.removeFile(a);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     // Only 'b' has been analyzed, because 'a' was removed before we started.
     expect(allResults, hasLength(1));
     expect(allResults[0].path, b);
   }
 
+  test_analyze_resolveDirectives() async {
+    var lib = _p('/test/lib.dart');
+    var part1 = _p('/test/part1.dart');
+    var part2 = _p('/test/part2.dart');
+    provider.newFile(
+        lib,
+        '''
+library lib;
+part 'part1.dart';
+part 'part2.dart';
+''');
+    provider.newFile(
+        part1,
+        '''
+part of lib;
+''');
+    provider.newFile(
+        part2,
+        '''
+part of 'lib.dart';
+''');
+
+    AnalysisResult libResult = await driver.getResult(lib);
+    AnalysisResult partResult1 = await driver.getResult(part1);
+    AnalysisResult partResult2 = await driver.getResult(part2);
+
+    CompilationUnit libUnit = libResult.unit;
+    CompilationUnit partUnit1 = partResult1.unit;
+    CompilationUnit partUnit2 = partResult2.unit;
+
+    CompilationUnitElement unitElement = libUnit.element;
+    CompilationUnitElement partElement1 = partUnit1.element;
+    CompilationUnitElement partElement2 = partUnit2.element;
+
+    LibraryElement libraryElement = unitElement.library;
+    {
+      expect(libraryElement.entryPoint, isNull);
+      expect(libraryElement.source, unitElement.source);
+      expect(libraryElement.definingCompilationUnit, unitElement);
+      expect(libraryElement.parts, hasLength(2));
+    }
+
+    expect((libUnit.directives[0] as LibraryDirective).element, libraryElement);
+    expect((libUnit.directives[1] as PartDirective).element, partElement1);
+    expect((libUnit.directives[2] as PartDirective).element, partElement2);
+
+    {
+      var partOf = partUnit1.directives.single as PartOfDirective;
+      expect(partOf.element, libraryElement);
+    }
+
+    {
+      var partOf = partUnit2.directives.single as PartOfDirective;
+      expect(partOf.element, libraryElement);
+    }
+  }
+
+  test_analyze_resolveDirectives_error_missingLibraryDirective() async {
+    var lib = _p('/test/lib.dart');
+    var part = _p('/test/part.dart');
+    provider.newFile(
+        lib,
+        '''
+part 'part.dart';
+''');
+    provider.newFile(
+        part,
+        '''
+part of lib;
+''');
+
+    driver.addFile(lib);
+
+    AnalysisResult libResult = await driver.getResult(lib);
+    List<AnalysisError> errors = libResult.errors;
+    expect(errors, hasLength(1));
+    expect(errors[0].errorCode,
+        ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART);
+  }
+
+  test_analyze_resolveDirectives_error_partOfDifferentLibrary_byName() async {
+    var lib = _p('/test/lib.dart');
+    var part = _p('/test/part.dart');
+    provider.newFile(
+        lib,
+        '''
+library lib;
+part 'part.dart';
+''');
+    provider.newFile(
+        part,
+        '''
+part of someOtherLib;
+''');
+
+    driver.addFile(lib);
+
+    AnalysisResult libResult = await driver.getResult(lib);
+    List<AnalysisError> errors = libResult.errors;
+    expect(errors, hasLength(1));
+    expect(errors[0].errorCode, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY);
+  }
+
+  test_analyze_resolveDirectives_error_partOfDifferentLibrary_byUri() async {
+    var lib = _p('/test/lib.dart');
+    var part = _p('/test/part.dart');
+    provider.newFile(
+        lib,
+        '''
+library lib;
+part 'part.dart';
+''');
+    provider.newFile(
+        part,
+        '''
+part of 'other_lib.dart';
+''');
+
+    driver.addFile(lib);
+
+    AnalysisResult libResult = await driver.getResult(lib);
+    List<AnalysisError> errors = libResult.errors;
+    expect(errors, hasLength(1));
+    expect(errors[0].errorCode, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY);
+  }
+
+  test_analyze_resolveDirectives_error_partOfNonPart() async {
+    var lib = _p('/test/lib.dart');
+    var part = _p('/test/part.dart');
+    provider.newFile(
+        lib,
+        '''
+library lib;
+part 'part.dart';
+''');
+    provider.newFile(
+        part,
+        '''
+// no part of directive
+''');
+
+    driver.addFile(lib);
+
+    AnalysisResult libResult = await driver.getResult(lib);
+    List<AnalysisError> errors = libResult.errors;
+    expect(errors, hasLength(1));
+    expect(errors[0].errorCode, CompileTimeErrorCode.PART_OF_NON_PART);
+  }
+
   test_cachedPriorityResults() async {
     var a = _p('/test/bin/a.dart');
     provider.newFile(a, 'var a = 1;');
@@ -386,7 +536,7 @@
     var a = _p('/test/bin/a.dart');
     var b = _p('/test/bin/b.dart');
     provider.newFile(a, 'var a = 1;');
-    provider.newFile(a, 'var b = 2;');
+    provider.newFile(b, 'var b = 2;');
 
     driver.priorityFiles = [a];
 
@@ -440,7 +590,7 @@
     driver.addFile(a);
 
     // We have a result only for "a".
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(1));
     {
       AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
@@ -453,11 +603,11 @@
     driver.changeFile(b);
 
     // "b" is not an added file, so it is not scheduled for analysis.
-    expect(driver.test.filesToAnalyze, isEmpty);
+    expect(driver.test.fileTracker.hasPendingFiles, isFalse);
 
     // While "b" is not analyzed explicitly, it is analyzed implicitly.
     // The change causes "a" to be reanalyzed.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(1));
     {
       AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
@@ -473,14 +623,14 @@
 
     driver.addFile(a);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     allResults.clear();
 
     // Change "b" and notify.
     // Nothing depends on "b", so nothing is analyzed.
     provider.updateFile(b, 'class B2 {}');
     driver.changeFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, isEmpty);
 
     // This should not add "b" to the file state.
@@ -507,7 +657,7 @@
     driver.priorityFiles = [a, b];
     driver.addFile(a);
     driver.addFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     // We have results for both "a" and "b".
     expect(allResults, hasLength(2));
@@ -534,7 +684,7 @@
 
     // We again get results for both "a" and "b".
     // The results are consistent.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(2));
     {
       AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
@@ -552,7 +702,7 @@
 
     // Initial analysis.
     {
-      await driver.waitForIdle();
+      await scheduler.waitForIdle();
       expect(allResults, hasLength(1));
       AnalysisResult result = allResults[0];
       expect(result.path, testFile);
@@ -571,11 +721,11 @@
     driver.changeFile(testFile);
 
     // The file was added, so it is scheduled for analysis.
-    expect(driver.test.filesToAnalyze, contains(testFile));
+    expect(driver.test.fileTracker.isFilePending(testFile), isTrue);
 
     // We get a new result.
     {
-      await driver.waitForIdle();
+      await scheduler.waitForIdle();
       expect(allResults, hasLength(1));
       AnalysisResult result = allResults[0];
       expect(result.path, testFile);
@@ -583,6 +733,115 @@
     }
   }
 
+  test_const_annotation_notConstConstructor() async {
+    addTestFile('''
+class A {
+  final int i;
+  A(this.i);
+}
+
+@A(5)
+class C {}
+''');
+    var result = await driver.getResult(testFile);
+    var atD = AstFinder.getClass(result.unit, 'C').metadata[0];
+    var atDI = atD.elementAnnotation as ElementAnnotationImpl;
+    var value = atDI.evaluationResult.value;
+    // That is illegal.
+    expect(value, isNull);
+  }
+
+  test_const_annotation_withArgs() async {
+    addTestFile('''
+const x = 1;
+@D(x) class C {}
+class D {
+  const D(this.value);
+  final value;
+}
+''');
+    var result = await driver.getResult(testFile);
+    var atD = AstFinder.getClass(result.unit, 'C').metadata[0];
+    var atDI = atD.elementAnnotation as ElementAnnotationImpl;
+    var value = atDI.evaluationResult.value;
+    expect(value, isNotNull);
+    expect(value.type, isNotNull);
+    expect(value.type.name, 'D');
+    expect(value.fields.keys, ['value']);
+    expect(value.getField('value').toIntValue(), 1);
+    expect(atDI.evaluationResult.errors, isEmpty);
+  }
+
+  test_const_annotation_withoutArgs() async {
+    addTestFile('''
+const x = 1;
+@x class C {}
+''');
+    var result = await driver.getResult(testFile);
+    Annotation at_x = AstFinder.getClass(result.unit, 'C').metadata[0];
+    expect(at_x.elementAnnotation.constantValue.toIntValue(), 1);
+  }
+
+  test_const_circular_reference() async {
+    addTestFile('''
+const x = y + 1;
+const y = x + 1;
+''');
+    var result = await driver.getResult(testFile);
+    var x = AstFinder.getTopLevelVariableElement(result.unit, 'x')
+        as TopLevelVariableElementImpl;
+    _expectCircularityError(x.evaluationResult);
+  }
+
+  test_const_dependency_sameUnit() async {
+    addTestFile('''
+const x = y + 1;
+const y = 1;
+''');
+    var result = await driver.getResult(testFile);
+    var x = AstFinder.getTopLevelVariableElement(result.unit, 'x');
+    var y = AstFinder.getTopLevelVariableElement(result.unit, 'y');
+    expect(x.constantValue.toIntValue(), 2);
+    expect(y.constantValue.toIntValue(), 1);
+  }
+
+  test_const_externalConstFactory() async {
+    addTestFile('''
+const x = const C.foo();
+
+class C extends B {
+  external const factory C.foo();
+}
+
+class B {}
+''');
+    var result = await driver.getResult(testFile);
+    var x = AstFinder.getTopLevelVariableElement(result.unit, 'x');
+    expect(x.constantValue, isNotNull);
+  }
+
+  test_const_implicitSuperConstructorInvocation() async {
+    addTestFile('''
+class Base {}
+class Derived extends Base {
+  const Derived();
+}
+const x = const Derived();
+''');
+    var result = await driver.getResult(testFile);
+    var x = AstFinder.getTopLevelVariableElement(result.unit, 'x');
+    expect(x.constantValue, isNotNull);
+  }
+
+  test_const_simple_topLevelVariable() async {
+    addTestFile('''
+const x = 1;
+''');
+    var result = await driver.getResult(testFile);
+    var x = AstFinder.getTopLevelVariableElement(result.unit, 'x');
+    expect(x.constantValue.toIntValue(), 1);
+  }
+
   test_errors_uriDoesNotExist_export() async {
     addTestFile(r'''
 export 'foo.dart';
@@ -633,6 +892,103 @@
     expect(errors[0].errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST);
   }
 
+  test_generatedFile() async {
+    Uri uri = Uri.parse('package:aaa/foo.dart');
+    String templatePath = _p('/aaa/lib/foo.dart');
+    String generatedPath = _p('/generated/aaa/lib/foo.dart');
+
+    provider.newFile(
+        templatePath,
+        r'''
+a() {}
+b() {}
+''');
+
+    provider.newFile(
+        generatedPath,
+        r'''
+aaa() {}
+bbb() {}
+''');
+
+    Source generatedSource = new _SourceMock();
+    when(generatedSource.uri).thenReturn(uri);
+    when(generatedSource.fullName).thenReturn(generatedPath);
+
+    when(generatedUriResolver.resolveAbsolute(uri, uri))
+        .thenReturn(generatedSource);
+    when(generatedUriResolver.restoreAbsolute(anyObject))
+        .thenInvoke((Source source) {
+      String path = source.fullName;
+      if (path == templatePath || path == generatedPath) {
+        return uri;
+      } else {
+        return null;
+      }
+    });
+
+    driver.addFile(templatePath);
+
+    await scheduler.waitForIdle();
+    expect(allExceptions, isEmpty);
+    expect(allResults, isEmpty);
+
+    var result = await driver.getResult(templatePath);
+    expect(result, isNull);
+    expect(allExceptions, isEmpty);
+    expect(allResults, isEmpty);
+
+    var element = await driver.getUnitElement(templatePath);
+    expect(element, isNull);
+    expect(allExceptions, isEmpty);
+    expect(allResults, isEmpty);
+
+    driver.priorityFiles = [templatePath];
+    driver.changeFile(templatePath);
+    await scheduler.waitForIdle();
+    expect(allExceptions, isEmpty);
+    expect(allResults, isEmpty);
+
+    expect(driver.knownFiles, isNot(contains(templatePath)));
+  }
+
+  test_getErrors() async {
+    String content = 'int f() => 42 + bar();';
+    addTestFile(content, priority: true);
+
+    ErrorsResult result = await driver.getErrors(testFile);
+    expect(result.path, testFile);
+    expect(result.uri.toString(), 'package:test/test.dart');
+    expect(result.contentHash, _md5(content));
+    expect(result.errors, hasLength(1));
+  }
+
+  test_getFilesDefiningClassMemberName() async {
+    var a = _p('/test/bin/a.dart');
+    var b = _p('/test/bin/b.dart');
+    var c = _p('/test/bin/c.dart');
+    var d = _p('/test/bin/d.dart');
+
+    provider.newFile(a, 'class A { m1() {} }');
+    provider.newFile(b, 'class B { m2() {} }');
+    provider.newFile(c, 'class C { m2() {} }');
+    provider.newFile(d, 'class D { m3() {} }');
+
+    driver.addFile(a);
+    driver.addFile(b);
+    driver.addFile(c);
+    driver.addFile(d);
+
+    expect(await driver.getFilesDefiningClassMemberName('m1'),
+        unorderedEquals([a]));
+
+    expect(await driver.getFilesDefiningClassMemberName('m2'),
+        unorderedEquals([b, c]));
+
+    expect(await driver.getFilesDefiningClassMemberName('m3'),
+        unorderedEquals([d]));
+  }
+
   test_getFilesReferencingName() async {
     var a = _p('/test/bin/a.dart');
     var b = _p('/test/bin/b.dart');
@@ -699,7 +1055,7 @@
     expect(f.returnType.type.toString(), 'int');
 
     // The same result is also received through the stream.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, [result]);
   }
 
@@ -718,7 +1074,7 @@
 ''');
     driver.addFile(a);
     driver.addFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     AnalysisResult result = await driver.getResult(b);
     expect(result.errors, isEmpty);
@@ -768,6 +1124,20 @@
     expect(unitA.context.getContents(sourceB).data, 'var v = 2;');
   }
 
+  test_getResult_functionTypeFormalParameter_withTypeParameter() async {
+    // This was code crashing because of incomplete implementation.
+    // Consider (re)moving after fixing dartbug.com/28515
+    addTestFile(r'''
+class A {
+  int foo( bar<T extends B>() ) {}
+}
+class B {}
+''');
+
+    AnalysisResult result = await driver.getResult(testFile);
+    expect(result.path, testFile);
+  }
+
   test_getResult_inferTypes_finalField() async {
     addTestFile(
         r'''
@@ -776,7 +1146,7 @@
 }
 ''',
         priority: true);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     AnalysisResult result = await driver.getResult(testFile);
     expect(_getClassFieldType(result.unit, 'C', 'f'), 'int');
@@ -793,7 +1163,7 @@
 }
 ''',
         priority: true);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     AnalysisResult result = await driver.getResult(testFile);
     expect(_getClassMethodReturnType(result.unit, 'A', 'm'), 'int');
@@ -817,6 +1187,30 @@
     expect(a.name.staticElement, new isInstanceOf<FunctionElement>());
   }
 
+  test_getResult_invalidUri() async {
+    String content = r'''
+import '[invalid uri]';
+import '[invalid uri]:foo.dart';
+import 'package:aaa/a1.dart';
+import '[invalid uri]';
+import '[invalid uri]:foo.dart';
+
+export '[invalid uri]';
+export '[invalid uri]:foo.dart';
+export 'package:aaa/a2.dart';
+export '[invalid uri]';
+export '[invalid uri]:foo.dart';
+
+part '[invalid uri]';
+part 'a3.dart';
+part '[invalid uri]';
+''';
+    addTestFile(content);
+
+    AnalysisResult result = await driver.getResult(testFile);
+    expect(result.path, testFile);
+  }
+
   test_getResult_invalidUri_exports_dart() async {
     String content = r'''
 export 'dart:async';
@@ -913,6 +1307,16 @@
     }
   }
 
+  test_getResult_nameConflict_local() async {
+    String content = r'''
+foo([p = V]) {}
+V();
+var V;
+''';
+    addTestFile(content);
+    await driver.getResult(testFile);
+  }
+
   test_getResult_noErrors_ifNotAdded() async {
     var a = _p('/test/lib/a.dart');
     provider.newFile(a, 'A a = null;');
@@ -950,7 +1354,7 @@
 
     driver.addFile(a);
     driver.addFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     {
       AnalysisResult result = await driver.getResult(b);
@@ -986,7 +1390,7 @@
 
     driver.addFile(a);
     driver.addFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     {
       AnalysisResult result = await driver.getResult(a);
@@ -997,10 +1401,7 @@
     // Update "a" so that "A1" is now "double".
     // Get result for "a".
     //
-    // Even though we have not notified the driver about the change,
-    // we still get "double" for "A1", because getResult() re-read the content.
-    //
-    // We also get "double" for "A2", even though "A2" has the type from "b".
+    // We get "double" for "A2", even though "A2" has the type from "b".
     // That's because we check for "a" API signature consistency, and because
     // it has changed, we invalidated the dependency cache, relinked libraries
     // and recomputed types.
@@ -1011,6 +1412,8 @@
 var A1 = 1.2;
 var A2 = B1;
 ''');
+    driver.changeFile(a);
+
     {
       AnalysisResult result = await driver.getResult(a);
       expect(_getTopLevelVarType(result.unit, 'A1'), 'double');
@@ -1045,6 +1448,24 @@
     expect(result1.unit, isNotNull);
   }
 
+  test_getSourceKind_library() async {
+    var path = _p('/test/lib/test.dart');
+    provider.newFile(path, 'class A {}');
+    expect(await driver.getSourceKind(path), SourceKind.LIBRARY);
+  }
+
+  test_getSourceKind_notDartFile() async {
+    var path = _p('/test/lib/test.txt');
+    provider.newFile(path, 'class A {}');
+    expect(await driver.getSourceKind(path), isNull);
+  }
+
+  test_getSourceKind_part() async {
+    var path = _p('/test/lib/test.dart');
+    provider.newFile(path, 'part of lib; class A {}');
+    expect(await driver.getSourceKind(path), SourceKind.PART);
+  }
+
   test_getTopLevelNameDeclarations() async {
     var a = _p('/test/lib/a.dart');
     var b = _p('/test/lib/b.dart');
@@ -1119,8 +1540,9 @@
 ''';
     addTestFile(content);
 
-    CompilationUnitElement unitElement = await driver.getUnitElement(testFile);
-    expect(unitElement, isNotNull);
+    UnitElementResult unitResult = await driver.getUnitElement(testFile);
+    expect(unitResult, isNotNull);
+    CompilationUnitElement unitElement = unitResult.element;
     expect(unitElement.source.fullName, testFile);
     expect(unitElement.functions.map((c) => c.name),
         unorderedEquals(['foo', 'main']));
@@ -1129,9 +1551,29 @@
   test_getUnitElement_notDart() async {
     var path = _p('/test.txt');
     provider.newFile(path, 'class A {}');
-    CompilationUnitElement unit = await driver.getUnitElement(path);
-    expect(unit, isNotNull);
-    expect(unit.types.map((e) => e.name), ['A']);
+    UnitElementResult unitResult = await driver.getUnitElement(path);
+    expect(unitResult, isNotNull);
+    expect(unitResult.element.types.map((e) => e.name), ['A']);
+  }
+
+  test_getUnitElementSignature() async {
+    var a = _p('/test/lib/a.dart');
+
+    provider.newFile(a, 'foo() {}');
+
+    String signature = await driver.getUnitElementSignature(a);
+    expect(signature, isNotNull);
+
+    UnitElementResult unitResult = await driver.getUnitElement(a);
+    expect(unitResult.path, a);
+    expect(unitResult.signature, signature);
+
+    provider.updateFile(a, 'bar() {}');
+    driver.changeFile(a);
+
+    String signature2 = await driver.getUnitElementSignature(a);
+    expect(signature2, isNotNull);
+    expect(signature2, isNot(signature));
   }
 
   test_hasFilesToAnalyze() async {
@@ -1143,7 +1585,7 @@
     expect(driver.hasFilesToAnalyze, isTrue);
 
     // Wait for idle, nothing to do.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(driver.hasFilesToAnalyze, isFalse);
 
     // Ask to analyze the file, so there is a file to analyze.
@@ -1157,7 +1599,7 @@
     // Change a file, even if not added, it still might affect analysis.
     driver.changeFile(_p('/not/added.dart'));
     expect(driver.hasFilesToAnalyze, isTrue);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(driver.hasFilesToAnalyze, isFalse);
 
     // Request of referenced names is not analysis of a file.
@@ -1244,7 +1686,7 @@
 
     driver.addFile(a);
     driver.addFile(c);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     expect(driver.knownFiles, contains(a));
     expect(driver.knownFiles, contains(b));
@@ -1253,7 +1695,7 @@
     // Remove a.dart and analyze.
     // Both a.dart and b.dart are not known now.
     driver.removeFile(a);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(driver.knownFiles, isNot(contains(a)));
     expect(driver.knownFiles, isNot(contains(b)));
     expect(driver.knownFiles, contains(c));
@@ -1304,6 +1746,80 @@
     expect(clazz.name.name, 'A2');
   }
 
+  test_part_getErrors_afterLibrary() async {
+    var a = _p('/test/lib/a.dart');
+    var b = _p('/test/lib/b.dart');
+    var c = _p('/test/lib/c.dart');
+    provider.newFile(
+        a,
+        r'''
+library a;
+import 'b.dart';
+part 'c.dart';
+class A {}
+var c = new C();
+''');
+    provider.newFile(b, 'class B {}');
+    provider.newFile(
+        c,
+        r'''
+part of a;
+class C {}
+var a = new A();
+var b = new B();
+''');
+
+    driver.addFile(a);
+    driver.addFile(b);
+    driver.addFile(c);
+
+    // Process a.dart so that we know that it's a library for c.dart later.
+    {
+      ErrorsResult result = await driver.getErrors(a);
+      expect(result.errors, isEmpty);
+    }
+
+    // c.dart does not have errors in the context of a.dart
+    {
+      ErrorsResult result = await driver.getErrors(c);
+      expect(result.errors, isEmpty);
+    }
+  }
+
+  test_part_getErrors_beforeLibrary() async {
+    var a = _p('/test/lib/a.dart');
+    var b = _p('/test/lib/b.dart');
+    var c = _p('/test/lib/c.dart');
+    provider.newFile(
+        a,
+        r'''
+library a;
+import 'b.dart';
+part 'c.dart';
+class A {}
+var c = new C();
+''');
+    provider.newFile(b, 'class B {}');
+    provider.newFile(
+        c,
+        r'''
+part of a;
+class C {}
+var a = new A();
+var b = new B();
+''');
+
+    driver.addFile(a);
+    driver.addFile(b);
+    driver.addFile(c);
+
+    // c.dart is resolve in the context of a.dart, so have no errors
+    {
+      ErrorsResult result = await driver.getErrors(c);
+      expect(result.errors, isEmpty);
+    }
+  }
+
   test_part_getResult_afterLibrary() async {
     var a = _p('/test/lib/a.dart');
     var b = _p('/test/lib/b.dart');
@@ -1431,7 +1947,7 @@
     driver.addFile(c);
 
     {
-      await driver.waitForIdle();
+      await scheduler.waitForIdle();
 
       // c.dart was added after a.dart, so it is analyzed after a.dart,
       // so we know that a.dart is the library of c.dart, so no errors.
@@ -1444,7 +1960,7 @@
     {
       provider.updateFile(a, '// does not use c.dart anymore');
       driver.changeFile(a);
-      await driver.waitForIdle();
+      await scheduler.waitForIdle();
 
       // Now c.dart does not have a library context, so A and B cannot be
       // resolved, so there are errors.
@@ -1482,7 +1998,7 @@
     driver.addFile(a);
     driver.addFile(b);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     // c.dart was added before a.dart, so we attempt to analyze it before
     // a.dart, but we cannot find the library for it, so we delay analysis
@@ -1506,7 +2022,7 @@
 
     driver.addFile(c);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     // There is no library which c.dart is a part of, so it has unresolved
     // A and B references.
@@ -1544,7 +2060,7 @@
     driver.addFile(a);
     driver.addFile(b);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     // c.dart was added before a.dart, so we attempt to analyze it before
     // a.dart, but we cannot find the library for it, so we delay analysis
@@ -1571,7 +2087,7 @@
     driver.addFile(b);
 
     // We have results for both "a" and "b".
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(2));
     {
       AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
@@ -1591,7 +2107,7 @@
     // While "b" is not analyzed explicitly, it is analyzed implicitly.
     // We don't get a result for "b".
     // But the change causes "a" to be reanalyzed.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(1));
     {
       AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
@@ -1603,7 +2119,7 @@
     addTestFile('main() {}');
 
     // We have a result.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(1));
     expect(allResults[0].path, testFile);
     allResults.clear();
@@ -1614,7 +2130,7 @@
     driver.removeFile(testFile);
     driver.changeFile(testFile);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, isEmpty);
   }
 
@@ -1627,7 +2143,7 @@
 
     driver.addFile(a);
     driver.addFile(b);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     // b.dart s clean.
     expect(allResults.singleWhere((r) => r.path == b).errors, isEmpty);
@@ -1636,7 +2152,7 @@
     // Remove a.dart, now b.dart should be reanalyzed and has an error.
     provider.deleteFile(a);
     driver.removeFile(a);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults.singleWhere((r) => r.path == b).errors, hasLength(2));
     allResults.clear();
   }
@@ -1645,7 +2161,7 @@
     String content = 'int f() => 42;';
     addTestFile(content, priority: true);
 
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     expect(allResults, hasLength(1));
     AnalysisResult result = allResults.single;
@@ -1673,7 +2189,7 @@
     driver.addFile(b);
     driver.addFile(c);
     driver.priorityFiles = [b];
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     expect(allResults, hasLength(3));
     AnalysisResult result = allResults[0];
@@ -1685,7 +2201,7 @@
   test_results_regular() async {
     String content = 'int f() => 42;';
     addTestFile(content);
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     expect(allResults, hasLength(1));
     AnalysisResult result = allResults.single;
@@ -1699,7 +2215,7 @@
 
   test_results_status() async {
     addTestFile('int f() => 42;');
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
 
     expect(allStatuses, hasLength(2));
     expect(allStatuses[0].isAnalyzing, isTrue);
@@ -1709,16 +2225,16 @@
   }
 
   test_waitForIdle() async {
-    // With no analysis to do, driver.waitForIdle should complete immediately.
-    await driver.waitForIdle();
+    // With no analysis to do, scheduler.waitForIdle should complete immediately.
+    await scheduler.waitForIdle();
     // Now schedule some analysis.
     addTestFile('int f() => 42;');
     expect(allResults, isEmpty);
-    // driver.waitForIdle should wait for the analysis.
-    await driver.waitForIdle();
+    // scheduler.waitForIdle should wait for the analysis.
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(1));
     // Make sure there is no more analysis pending.
-    await driver.waitForIdle();
+    await scheduler.waitForIdle();
     expect(allResults, hasLength(1));
   }
 
@@ -1736,6 +2252,14 @@
     }
   }
 
+  void _expectCircularityError(EvaluationResultImpl evaluationResult) {
+    expect(evaluationResult, isNotNull);
+    expect(evaluationResult.value, isNull);
+    expect(evaluationResult.errors, hasLength(1));
+    expect(evaluationResult.errors[0].errorCode,
+        CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT);
+  }
+
   ClassDeclaration _getClass(CompilationUnit unit, String name) {
     for (CompilationUnitMember declaration in unit.declarations) {
       if (declaration is ClassDeclaration) {
@@ -1821,8 +2345,9 @@
   }
 
   String _getTopLevelVarType(CompilationUnit unit, String name) {
+    VariableDeclaration variable = _getTopLevelVar(unit, name);
     return resolutionMap
-        .elementDeclaredByVariableDeclaration(_getTopLevelVar(unit, name))
+        .elementDeclaredByVariableDeclaration(variable)
         .type
         .toString();
   }
@@ -1836,3 +2361,5 @@
     return hex.encode(md5.convert(UTF8.encode(content)).bytes);
   }
 }
+
+class _SourceMock extends TypedMock implements Source {}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 79323c1..79f6f3a 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisOptions, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
 import 'package:test/test.dart';
@@ -63,6 +62,46 @@
         provider, sourceFactory, analysisOptions, new Uint32List(0));
   }
 
+  test_definedClassMemberNames() {
+    String path = _p('/aaa/lib/a.dart');
+    provider.newFile(
+        path,
+        r'''
+class A {
+  int a, b;
+  A();
+  A.c();
+  d() {}
+  get e => null;
+  set f(_) {}
+}
+class B {
+  g() {}
+}
+''');
+    FileState file = fileSystemState.getFileForPath(path);
+    expect(file.definedClassMemberNames,
+        unorderedEquals(['a', 'b', 'd', 'e', 'f', 'g']));
+  }
+
+  test_definedTopLevelNames() {
+    String path = _p('/aaa/lib/a.dart');
+    provider.newFile(
+        path,
+        r'''
+class A {}
+class B = Object with A;
+typedef C {}
+D() {}
+get E => null;
+set F(_) {}
+var G, H;
+''');
+    FileState file = fileSystemState.getFileForPath(path);
+    expect(file.definedTopLevelNames,
+        unorderedEquals(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']));
+  }
+
   test_exportedTopLevelDeclarations_export() {
     String a = _p('/aaa/lib/a.dart');
     String b = _p('/aaa/lib/b.dart');
@@ -262,7 +301,7 @@
     String path = _p('/aaa/lib/a.dart');
     FileState file = fileSystemState.getFileForPath(path);
     expect(file.path, path);
-    expect(file.uri, FastUri.parse('package:aaa/a.dart'));
+    expect(file.uri, Uri.parse('package:aaa/a.dart'));
     expect(file.content, '');
     expect(file.contentHash, _md5(''));
     expect(_excludeSdk(file.importedFiles), isEmpty);
@@ -275,27 +314,51 @@
     expect(file.unlinked.classes, isEmpty);
   }
 
-  test_getFileForPath_generatedFile() {
-    Uri uri = Uri.parse('package:aaa/foo.dart');
-    String templatePath = _p('/aaa/lib/foo.dart');
-    String generatedPath = _p('/generated/aaa/lib/foo.dart');
+  test_getFileForPath_hasLibraryDirective_hasPartOfDirective() {
+    String a = _p('/test/lib/a.dart');
+    provider.newFile(
+        a,
+        r'''
+library L;
+part of L;
+''');
+    FileState file = fileSystemState.getFileForPath(a);
+    expect(file.isPart, isFalse);
+  }
 
-    Source generatedSource = new _SourceMock();
-    when(generatedSource.fullName).thenReturn(generatedPath);
-    when(generatedSource.uri).thenReturn(uri);
+  test_getFileForPath_import_invalidUri() {
+    String a = _p('/aaa/lib/a.dart');
+    String a1 = _p('/aaa/lib/a1.dart');
+    String a2 = _p('/aaa/lib/a2.dart');
+    String a3 = _p('/aaa/lib/a3.dart');
+    String content_a1 = r'''
+import 'package:aaa/a1.dart';
+import '[invalid uri]';
 
-    when(generatedUriResolver.resolveAbsolute(uri, uri))
-        .thenReturn(generatedSource);
+export '[invalid uri]';
+export 'package:aaa/a2.dart';
 
-    FileState generatedFile = fileSystemState.getFileForUri(uri);
-    expect(generatedFile.path, generatedPath);
-    expect(generatedFile.uri, uri);
+part 'a3.dart';
+part '[invalid uri]';
+''';
+    provider.newFile(a, content_a1);
 
-    FileState templateFile = fileSystemState.getFileForPath(templatePath);
-    expect(templateFile.path, templatePath);
-    expect(templateFile.uri, uri);
+    FileState file = fileSystemState.getFileForPath(a);
 
-    expect(fileSystemState.getFilesForPath(templatePath), [templateFile]);
+    expect(_excludeSdk(file.importedFiles), hasLength(1));
+    expect(file.importedFiles[0].path, a1);
+    expect(file.importedFiles[0].uri, Uri.parse('package:aaa/a1.dart'));
+    expect(file.importedFiles[0].source, isNotNull);
+
+    expect(_excludeSdk(file.exportedFiles), hasLength(1));
+    expect(file.exportedFiles[0].path, a2);
+    expect(file.exportedFiles[0].uri, Uri.parse('package:aaa/a2.dart'));
+    expect(file.exportedFiles[0].source, isNotNull);
+
+    expect(_excludeSdk(file.partedFiles), hasLength(1));
+    expect(file.partedFiles[0].path, a3);
+    expect(file.partedFiles[0].uri, Uri.parse('package:aaa/a3.dart'));
+    expect(file.partedFiles[0].source, isNotNull);
   }
 
   test_getFileForPath_library() {
@@ -329,23 +392,23 @@
 
     expect(_excludeSdk(file.importedFiles), hasLength(2));
     expect(file.importedFiles[0].path, a2);
-    expect(file.importedFiles[0].uri, FastUri.parse('package:aaa/a2.dart'));
+    expect(file.importedFiles[0].uri, Uri.parse('package:aaa/a2.dart'));
     expect(file.importedFiles[0].source, isNotNull);
     expect(file.importedFiles[1].path, b1);
-    expect(file.importedFiles[1].uri, FastUri.parse('package:bbb/b1.dart'));
+    expect(file.importedFiles[1].uri, Uri.parse('package:bbb/b1.dart'));
     expect(file.importedFiles[1].source, isNotNull);
 
     expect(file.exportedFiles, hasLength(2));
     expect(file.exportedFiles[0].path, b2);
-    expect(file.exportedFiles[0].uri, FastUri.parse('package:bbb/b2.dart'));
+    expect(file.exportedFiles[0].uri, Uri.parse('package:bbb/b2.dart'));
     expect(file.exportedFiles[0].source, isNotNull);
     expect(file.exportedFiles[1].path, a3);
-    expect(file.exportedFiles[1].uri, FastUri.parse('package:aaa/a3.dart'));
+    expect(file.exportedFiles[1].uri, Uri.parse('package:aaa/a3.dart'));
     expect(file.exportedFiles[1].source, isNotNull);
 
     expect(file.partedFiles, hasLength(1));
     expect(file.partedFiles[0].path, a4);
-    expect(file.partedFiles[0].uri, FastUri.parse('package:aaa/a4.dart'));
+    expect(file.partedFiles[0].uri, Uri.parse('package:aaa/a4.dart'));
 
     expect(_excludeSdk(file.directReferencedFiles), hasLength(5));
 
@@ -398,7 +461,7 @@
 
     FileState file_a2 = fileSystemState.getFileForPath(a2);
     expect(file_a2.path, a2);
-    expect(file_a2.uri, FastUri.parse('package:aaa/a2.dart'));
+    expect(file_a2.uri, Uri.parse('package:aaa/a2.dart'));
 
     expect(file_a2.unlinked, isNotNull);
     expect(file_a2.unlinked.classes, hasLength(1));
@@ -445,7 +508,7 @@
 
   test_getFileForUri_packageVsFileUri() {
     String path = _p('/aaa/lib/a.dart');
-    var packageUri = FastUri.parse('package:aaa/a.dart');
+    var packageUri = Uri.parse('package:aaa/a.dart');
     var fileUri = provider.pathContext.toUri(path);
 
     // The files with `package:` and `file:` URIs are different.
@@ -464,6 +527,22 @@
     expect(files, [filePackageUri, fileFileUri]);
   }
 
+  test_hasUri() {
+    Uri uri = Uri.parse('package:aaa/foo.dart');
+    String templatePath = _p('/aaa/lib/foo.dart');
+    String generatedPath = _p('/generated/aaa/lib/foo.dart');
+
+    Source generatedSource = new _SourceMock();
+    when(generatedSource.fullName).thenReturn(generatedPath);
+    when(generatedSource.uri).thenReturn(uri);
+
+    when(generatedUriResolver.resolveAbsolute(uri, uri))
+        .thenReturn(generatedSource);
+
+    expect(fileSystemState.hasUri(templatePath), isFalse);
+    expect(fileSystemState.hasUri(generatedPath), isTrue);
+  }
+
   test_referencedNames() {
     String path = _p('/aaa/lib/a.dart');
     provider.newFile(
diff --git a/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart b/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart
index 97a1bdca..2a0ea6c 100644
--- a/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart
@@ -16,7 +16,7 @@
 }
 
 @reflectiveTest
-class ReferencedNamesBuilderTest {
+class ReferencedNamesBuilderTest extends ParserTestCase {
   test_class_constructor() {
     Set<String> names = _computeReferencedNames('''
 class U {
@@ -28,6 +28,18 @@
     expect(names, unorderedEquals(['A', 'B', 'C']));
   }
 
+  test_class_constructor_parameters() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  U(A a) {
+    a;
+    b;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'b']));
+  }
+
   test_class_field() {
     Set<String> names = _computeReferencedNames('''
 class U {
@@ -120,6 +132,16 @@
     expect(names, unorderedEquals(['A', 'b']));
   }
 
+  test_class_method_parameters_dontHideNamedExpressionName() {
+    Set<String> names = _computeReferencedNames('''
+main() {
+  var p;
+  new C(p: p);
+}
+''');
+    expect(names, unorderedEquals(['C', 'p']));
+  }
+
   test_class_method_typeParameters() {
     Set<String> names = _computeReferencedNames('''
 class U {
@@ -383,7 +405,7 @@
   }
 
   Set<String> _computeReferencedNames(String code) {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit2(code);
+    CompilationUnit unit = parseCompilationUnit2(code);
     return computeReferencedNames(unit);
   }
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 93cc816..a732388 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -86,8 +86,7 @@
 ''');
     ClassElement a = _findElement('A');
     ClassElement b = _findElement('B');
-    RegExp regExp = new RegExp(r'^test$');
-    expect(await driver.search.classMembers(regExp),
+    expect(await driver.search.classMembers('test'),
         unorderedEquals([a.methods[0], b.fields[0]]));
   }
 
@@ -95,8 +94,7 @@
     await _resolveTestUnit('''
 import 'not-dart.txt';
 ''');
-    RegExp regExp = new RegExp(r'^test$');
-    expect(await driver.search.classMembers(regExp), isEmpty);
+    expect(await driver.search.classMembers('test'), isEmpty);
   }
 
   test_searchMemberReferences_qualified_resolved() async {
diff --git a/pkg/analyzer/test/src/dart/ast/utilities_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
index cb3652e..b818e5d 100644
--- a/pkg/analyzer/test/src/dart/ast/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -370,7 +370,7 @@
   void test_onlyStartOffset() {
     String code = ' int vv; ';
     //             012345678
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+    CompilationUnit unit = parseCompilationUnit(code);
     TopLevelVariableDeclaration declaration = unit.declarations[0];
     VariableDeclarationList variableList = declaration.variables;
     Identifier typeName = (variableList.type as TypeName).name;
@@ -391,7 +391,7 @@
   void test_startEndOffset() {
     String code = ' int vv; ';
     //             012345678
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+    CompilationUnit unit = parseCompilationUnit(code);
     TopLevelVariableDeclaration declaration = unit.declarations[0];
     VariableDeclarationList variableList = declaration.variables;
     Identifier typeName = (variableList.type as TypeName).name;
@@ -412,8 +412,7 @@
 @reflectiveTest
 class NodeLocatorTest extends ParserTestCase {
   void test_range() {
-    CompilationUnit unit =
-        ParserTestCase.parseCompilationUnit("library myLib;");
+    CompilationUnit unit = parseCompilationUnit("library myLib;");
     _assertLocate(
         unit, 4, 10, (node) => node is LibraryDirective, LibraryDirective);
   }
@@ -424,14 +423,13 @@
   }
 
   void test_searchWithin_offset() {
-    CompilationUnit unit =
-        ParserTestCase.parseCompilationUnit("library myLib;");
+    CompilationUnit unit = parseCompilationUnit("library myLib;");
     _assertLocate(
         unit, 10, 10, (node) => node is SimpleIdentifier, SimpleIdentifier);
   }
 
   void test_searchWithin_offsetAfterNode() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(r'''
+    CompilationUnit unit = parseCompilationUnit(r'''
 class A {}
 class B {}''');
     NodeLocator locator = new NodeLocator(1024, 1024);
@@ -440,7 +438,7 @@
   }
 
   void test_searchWithin_offsetBeforeNode() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(r'''
+    CompilationUnit unit = parseCompilationUnit(r'''
 class A {}
 class B {}''');
     NodeLocator locator = new NodeLocator(0, 0);
diff --git a/pkg/analyzer/test/src/dart/sdk/patch_test.dart b/pkg/analyzer/test/src/dart/sdk/patch_test.dart
index ec02930..9746b52 100644
--- a/pkg/analyzer/test/src/dart/sdk/patch_test.dart
+++ b/pkg/analyzer/test/src/dart/sdk/patch_test.dart
@@ -10,7 +10,6 @@
 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/util/fast_uri.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -805,7 +804,7 @@
         'dart:test': [_p('/sdk/lib/does_not_exist.dart')]
       };
       File file = provider.newFile(_p('/sdk/lib/test/test.dart'), '');
-      Source source = file.createSource(FastUri.parse('dart:test'));
+      Source source = file.createSource(Uri.parse('dart:test'));
       CompilationUnit unit = SdkPatcher.parse(source, true, listener);
       patcher.patch(provider, true, patchPaths, listener, source, unit);
     }, throwsArgumentError);
@@ -844,7 +843,7 @@
 
     _createSdk();
 
-    Source source = file.createSource(FastUri.parse('dart:_internal'));
+    Source source = file.createSource(Uri.parse('dart:_internal'));
     CompilationUnit unit = SdkPatcher.parse(source, true, listener);
     patcher.patch(provider, true, patchPaths, listener, source, unit);
     _assertUnitCode(
@@ -897,7 +896,7 @@
     _createSdk();
 
     {
-      Uri uri = FastUri.parse('dart:test');
+      Uri uri = Uri.parse('dart:test');
       Source source = fileLib.createSource(uri);
       CompilationUnit unit = SdkPatcher.parse(source, true, listener);
       patcher.patch(provider, true, patchPaths, listener, source, unit);
@@ -908,7 +907,7 @@
     }
 
     {
-      Uri uri = FastUri.parse('dart:test/test_part.dart');
+      Uri uri = Uri.parse('dart:test/test_part.dart');
       Source source = filePart.createSource(uri);
       CompilationUnit unit = SdkPatcher.parse(source, true, listener);
       patcher.patch(provider, true, patchPaths, listener, source, unit);
@@ -1196,7 +1195,7 @@
 
     _createSdk();
 
-    Source source = file.createSource(FastUri.parse('dart:test'));
+    Source source = file.createSource(Uri.parse('dart:test'));
     CompilationUnit unit = SdkPatcher.parse(source, true, listener);
     patcher.patch(provider, true, patchPaths, listener, source, unit);
     return unit;
diff --git a/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart b/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart
index 404d9af..0eb1ed1 100644
--- a/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart
+++ b/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/general.dart';
 import 'package:test/test.dart';
@@ -286,7 +285,7 @@
   final Uri uri;
   final String fullName;
 
-  _SourceMock(String uriStr, this.fullName) : uri = FastUri.parse(uriStr);
+  _SourceMock(String uriStr, this.fullName) : uri = Uri.parse(uriStr);
 
   @override
   Source get librarySource => null;
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
index 1fcc9bc..7d59560 100644
--- a/pkg/analyzer/test/src/summary/prelinker_test.dart
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -5,6 +5,7 @@
 library analyzer.test.src.summary.prelinker_test;
 
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/prelink.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -35,10 +36,16 @@
   void serializeLibraryText(String text, {bool allowErrors: false}) {
     super.serializeLibraryText(text, allowErrors: allowErrors);
 
-    UnlinkedUnit getPart(String relativeUri) {
+    UnlinkedUnit getPart(String relativeUriStr) {
+      Uri relativeUri;
+      try {
+        relativeUri = Uri.parse(relativeUriStr);
+      } on FormatException {
+        return new UnlinkedUnitBuilder();
+      }
+
       String absoluteUri =
-          resolveRelativeUri(linkerInputs.testDartUri, Uri.parse(relativeUri))
-              .toString();
+          resolveRelativeUri(linkerInputs.testDartUri, relativeUri).toString();
       return linkerInputs.getUnit(absoluteUri);
     }
 
diff --git a/pkg/analyzer/test/src/summary/pub_summary_test.dart b/pkg/analyzer/test/src/summary/pub_summary_test.dart
index 0724cef..62d9145 100644
--- a/pkg/analyzer/test/src/summary/pub_summary_test.dart
+++ b/pkg/analyzer/test/src/summary/pub_summary_test.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/pub_summary.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:path/path.dart' as pathos;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -1104,7 +1103,7 @@
 ''');
       PackageBundleAssembler assembler = new PackageBundleAssembler()
         ..addUnlinkedUnit(
-            file.createSource(FastUri.parse('package:aaa/a.dart')),
+            file.createSource(Uri.parse('package:aaa/a.dart')),
             new UnlinkedUnitBuilder());
       resourceProvider.newFileWithBytes(
           resourceProvider
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 266f772..b101aa6 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -719,7 +719,6 @@
         .test_unsafeBlockClosureInference_methodCall_implicitTypeParam_comment();
   }
 
-  @override
   LibraryElementImpl _checkSource(
       SummaryResynthesizer resynthesizer, Source source) {
     LibraryElementImpl resynthesized =
@@ -883,7 +882,7 @@
   }
 
   void _serializeLibrary(Source librarySource) {
-    if (librarySource.isInSystemLibrary) {
+    if (librarySource == null || librarySource.isInSystemLibrary) {
       return;
     }
     if (!serializedSources.add(librarySource)) {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 3d8874c..fd40ab4 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -43,6 +43,11 @@
   Set<String> variablesWithNotConstInitializers = new Set<String>();
 
   /**
+   * Names that cannot be resolved, e.g. because of duplicate declaration.
+   */
+  Set<String> namesThatCannotBeResolved = new Set<String>();
+
+  /**
    * Tests may set this to `true` to indicate that a missing file at the time of
    * summary resynthesis shouldn't trigger an error.
    */
@@ -381,7 +386,11 @@
         compareConstAsts(r, o.expression, desc);
       } else if (o is SimpleIdentifier && r is SimpleIdentifier) {
         expect(r.name, o.name, reason: desc);
-        compareElements(r.staticElement, o.staticElement, desc);
+        if (namesThatCannotBeResolved.contains(r.name)) {
+          expect(r.staticElement, isNull);
+        } else {
+          compareElements(r.staticElement, o.staticElement, desc);
+        }
       } else if (o is PrefixedIdentifier && r is SimpleIdentifier) {
         // We don't resynthesize prefixed identifiers when the prefix refers to
         // a PrefixElement or a ClassElement.  We use simple identifiers with
@@ -440,6 +449,8 @@
         checkElidablePrefix(oTarget.prefix);
         checkElidablePrefix(oTarget.identifier);
         compareConstAsts(r, o.propertyName, desc);
+      } else if (o is SuperExpression && r is SuperExpression) {
+        // Nothing to compare.
       } else if (o is ThisExpression && r is ThisExpression) {
         // Nothing to compare.
       } else if (o is NullLiteral) {
@@ -1666,6 +1677,10 @@
 ''');
   }
 
+  test_closure_generic() {
+    checkLibrary('final f = <U, V>(U x, V y) => y;');
+  }
+
   test_closure_in_variable_declaration_in_part() {
     addSource('/a.dart', 'part of lib; final f = (int i) => i.toDouble();');
     checkLibrary('''
@@ -2362,6 +2377,18 @@
 ''');
   }
 
+  test_const_topLevel_super() {
+    checkLibrary(r'''
+const vSuper = super;
+''');
+  }
+
+  test_const_topLevel_this() {
+    checkLibrary(r'''
+const vThis = this;
+''');
+  }
+
   test_const_topLevel_typedList() {
     checkLibrary(r'''
 const vNull = const <Null>[];
@@ -2922,6 +2949,28 @@
     checkLibrary('enum E1 { v1 } enum E2 { v2 }');
   }
 
+  test_error_extendsEnum() {
+    checkLibrary('''
+enum E {a, b, c}
+
+class M {}
+
+class A extends E {
+  foo() {}
+}
+
+class B implements E, M {
+  foo() {}
+}
+
+class C extends Object with E, M {
+  foo() {}
+}
+
+class D = Object with M, E;
+''');
+  }
+
   test_executable_parameter_type_typedef() {
     checkLibrary(r'''
 typedef F(int p);
@@ -3082,6 +3131,15 @@
     checkLibrary('export "a.dart"; export "b.dart";');
   }
 
+  test_expr_invalid_typeParameter_asPrefix() {
+    variablesWithNotConstInitializers.add('f');
+    checkLibrary('''
+class C<T> {
+  final f = T.k;
+}
+''');
+  }
+
   test_field_covariant() {
     checkLibrary('''
 class C {
@@ -3809,6 +3867,13 @@
 ''');
   }
 
+  test_instantiateToBounds_functionTypeAlias_simple() {
+    checkLibrary('''
+typedef F<T extends num>(T p);
+F f;
+''');
+  }
+
   test_instantiateToBounds_simple() {
     checkLibrary('''
 class C<T extends num> {}
@@ -3846,6 +3911,89 @@
 ''');
   }
 
+  test_invalid_importPrefix_asTypeArgument() {
+    checkLibrary('''
+import 'dart:async' as ppp;
+class C {
+  List<ppp> v;
+}
+''');
+  }
+
+  test_invalid_nameConflict_imported() {
+    namesThatCannotBeResolved.add('V');
+    addLibrarySource('/a.dart', 'V() {}');
+    addLibrarySource('/b.dart', 'V() {}');
+    checkLibrary('''
+import 'a.dart';
+import 'b.dart';
+foo([p = V]) {}
+''');
+  }
+
+  test_invalid_nameConflict_imported_exported() {
+    namesThatCannotBeResolved.add('V');
+    addLibrarySource('/a.dart', 'V() {}');
+    addLibrarySource('/b.dart', 'V() {}');
+    addLibrarySource(
+        '/c.dart',
+        r'''
+export 'a.dart';
+export 'b.dart';
+''');
+    checkLibrary('''
+import 'c.dart';
+foo([p = V]) {}
+''');
+  }
+
+  test_invalid_nameConflict_local() {
+    namesThatCannotBeResolved.add('V');
+    checkLibrary('''
+foo([p = V]) {}
+V() {}
+var V;
+''');
+  }
+
+  test_invalid_setterParameter_fieldFormalParameter() {
+    checkLibrary('''
+class C {
+  int foo;
+  void set bar(this.foo) {}
+}
+''');
+  }
+
+  test_invalid_setterParameter_fieldFormalParameter_self() {
+    checkLibrary('''
+class C {
+  set x(this.x) {}
+}
+''');
+  }
+
+  test_invalidUris() {
+    allowMissingFiles = true;
+    checkLibrary(r'''
+import '[invalid uri]';
+import '[invalid uri]:foo.dart';
+import 'a1.dart';
+import '[invalid uri]';
+import '[invalid uri]:foo.dart';
+
+export '[invalid uri]';
+export '[invalid uri]:foo.dart';
+export 'a2.dart';
+export '[invalid uri]';
+export '[invalid uri]:foo.dart';
+
+part '[invalid uri]';
+part 'a3.dart';
+part '[invalid uri]';
+''');
+  }
+
   test_library() {
     checkLibrary('');
   }
@@ -4255,6 +4403,59 @@
     checkLibrary('class C { void f<T, U>(T x(U u)) {} }');
   }
 
+  test_nameConflict_exportedAndLocal() {
+    namesThatCannotBeResolved.add('V');
+    addLibrarySource('/a.dart', 'class C {}');
+    addLibrarySource(
+        '/c.dart',
+        '''
+export 'a.dart';
+class C {}
+''');
+    checkLibrary('''
+import 'c.dart';
+C v = null;
+''');
+  }
+
+  test_nameConflict_exportedAndLocal_exported() {
+    namesThatCannotBeResolved.add('V');
+    addLibrarySource('/a.dart', 'class C {}');
+    addLibrarySource(
+        '/c.dart',
+        '''
+export 'a.dart';
+class C {}
+''');
+    addLibrarySource('/d.dart', 'export "c.dart";');
+    checkLibrary('''
+import 'd.dart';
+C v = null;
+''');
+  }
+
+  test_nameConflict_exportedAndParted() {
+    namesThatCannotBeResolved.add('V');
+    addLibrarySource('/a.dart', 'class C {}');
+    addLibrarySource(
+        '/b.dart',
+        '''
+part of lib;
+class C {}
+''');
+    addLibrarySource(
+        '/c.dart',
+        '''
+library lib;
+export 'a.dart';
+part 'b.dart';
+''');
+    checkLibrary('''
+import 'c.dart';
+C v = null;
+''');
+  }
+
   test_nested_generic_functions_in_generic_class_with_function_typed_params() {
     checkLibrary('''
 class C<T, U> {
@@ -4596,6 +4797,37 @@
     checkLibrary('dynamic d;');
   }
 
+  test_type_invalid_topLevelVariableElement_asType() {
+    checkLibrary(
+        '''
+class C<T extends V> {}
+typedef V F(V p);
+V f(V p) {}
+V V2 = null;
+int V = 0;
+''',
+        allowErrors: true);
+  }
+
+  test_type_invalid_topLevelVariableElement_asTypeArgument() {
+    checkLibrary(
+        '''
+var V;
+static List<V> V2;
+''',
+        allowErrors: true);
+  }
+
+  test_type_invalid_typeParameter_asPrefix() {
+    checkLibrary(
+        '''
+class C<T> {
+  m(T.K p) {}
+}
+''',
+        allowErrors: true);
+  }
+
   test_type_reference_lib_to_lib() {
     checkLibrary('class C {} enum E { v } typedef F(); C c; E e; F f;');
   }
@@ -4783,6 +5015,21 @@
     checkLibrary('f() {} g() {}');
   }
 
+  @failingTest
+  test_unresolved_annotation_instanceCreation_argument_super() {
+    // TODO(scheglov) fix https://github.com/dart-lang/sdk/issues/28553
+    checkLibrary(
+        '''
+class A {
+  const A(_);
+}
+
+@A(super)
+class C {}
+''',
+        allowErrors: true);
+  }
+
   test_unresolved_annotation_instanceCreation_argument_this() {
     checkLibrary(
         '''
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
index 932e1fc..4105d32 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
@@ -153,14 +153,21 @@
     expect(linked, isNotNull);
     validateLinkedLibrary(linked);
     unlinkedUnits = <UnlinkedUnit>[linkerInputs.unlinkedDefiningUnit];
-    for (String relativeUri
+    for (String relativeUriStr
         in linkerInputs.unlinkedDefiningUnit.publicNamespace.parts) {
+      Uri relativeUri;
+      try {
+        relativeUri = Uri.parse(relativeUriStr);
+      } on FormatException {
+        unlinkedUnits.add(new UnlinkedUnitBuilder());
+        continue;
+      }
+
       UnlinkedUnit unit = uriToUnit[
-          resolveRelativeUri(linkerInputs.testDartUri, Uri.parse(relativeUri))
-              .toString()];
+          resolveRelativeUri(linkerInputs.testDartUri, relativeUri).toString()];
       if (unit == null) {
         if (!allowMissingFiles) {
-          fail('Test referred to unknown unit $relativeUri');
+          fail('Test referred to unknown unit $relativeUriStr');
         }
       } else {
         unlinkedUnits.add(unit);
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 9e12705..5f69ff1 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -5961,6 +5961,16 @@
     ]);
   }
 
+  test_executable_param_isFinal() {
+    String text = 'f(x, final y) {}';
+    UnlinkedExecutable executable = serializeExecutableText(text);
+    expect(executable.parameters, hasLength(2));
+    expect(executable.parameters[0].name, 'x');
+    expect(executable.parameters[0].isFinal, isFalse);
+    expect(executable.parameters[1].name, 'y');
+    expect(executable.parameters[1].isFinal, isTrue);
+  }
+
   test_executable_param_kind_named() {
     UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
     UnlinkedParam param = executable.parameters[0];
@@ -6021,16 +6031,6 @@
     }
   }
 
-  test_executable_param_isFinal() {
-    String text = 'f(x, final y) {}';
-    UnlinkedExecutable executable = serializeExecutableText(text);
-    expect(executable.parameters, hasLength(2));
-    expect(executable.parameters[0].name, 'x');
-    expect(executable.parameters[0].isFinal, isFalse);
-    expect(executable.parameters[1].name, 'y');
-    expect(executable.parameters[1].isFinal, isTrue);
-  }
-
   test_executable_param_no_flags() {
     UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
     expect(executable.parameters[0].isFunctionTyped, isFalse);
@@ -6481,6 +6481,14 @@
     expect(unlinkedExports[0].configurations, isEmpty);
   }
 
+  test_export_uri_invalid() {
+    String uriString = '[invalid uri]';
+    String libraryText = 'export "$uriString";';
+    serializeLibraryText(libraryText);
+    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].uri, uriString);
+  }
+
   test_export_uri_nullStringValue() {
     String libraryText = r'''
 export "${'a'}.dart";
@@ -7500,6 +7508,19 @@
         ]);
   }
 
+  test_expr_invalid_typeParameter_asPrefix() {
+    if (skipNonConstInitializers) {
+      return;
+    }
+    var c = serializeClassText('''
+class C<T> {
+  final f = T.k;
+}
+''');
+    assertUnlinkedConst(c.fields[0].initializer.bodyExpr,
+        isValidConst: false, operators: []);
+  }
+
   test_expr_invokeMethod_instance() {
     if (skipNonConstInitializers) {
       return;
@@ -7709,6 +7730,30 @@
         ]);
   }
 
+  test_expr_super() {
+    if (skipNonConstInitializers) {
+      return;
+    }
+    UnlinkedVariable variable = serializeVariableText('''
+final v = super;
+''');
+    assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
+      UnlinkedExprOperation.pushSuper,
+    ]);
+  }
+
+  test_expr_this() {
+    if (skipNonConstInitializers) {
+      return;
+    }
+    UnlinkedVariable variable = serializeVariableText('''
+final v = this;
+''');
+    assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
+      UnlinkedExprOperation.pushThis,
+    ]);
+  }
+
   test_expr_throwException() {
     if (skipNonConstInitializers) {
       return;
@@ -8367,6 +8412,15 @@
     expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
   }
 
+  test_import_uri_invalid() {
+    String uriString = '[invalid uri]';
+    String libraryText = 'import "$uriString";';
+    serializeLibraryText(libraryText);
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].uri, uriString);
+  }
+
   test_import_uri_nullStringValue() {
     String libraryText = r'''
 import "${'a'}.dart";
@@ -9192,6 +9246,28 @@
     checkAnnotationA(unlinkedUnits[0].imports[0].annotations);
   }
 
+  test_metadata_invalid_instanceCreation_argument_super() {
+    List<UnlinkedExpr> annotations = serializeClassText('''
+class A {
+  const A(_);
+}
+
+@A(super)
+class C {}
+''').annotations;
+    expect(annotations, hasLength(1));
+    assertUnlinkedConst(annotations[0], operators: [
+      UnlinkedExprOperation.pushSuper,
+      UnlinkedExprOperation.invokeConstructor,
+    ], ints: [
+      0,
+      1
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'A',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
   test_metadata_invalid_instanceCreation_argument_this() {
     List<UnlinkedExpr> annotations = serializeClassText('''
 class A {
@@ -9495,6 +9571,17 @@
     _assertParameterZeroVisibleRange(p);
   }
 
+  test_parameter_visibleRange_invalid_fieldFormalParameter() {
+    UnlinkedExecutable m =
+        findExecutable('m', executables: serializeClassText(r'''
+class C {
+  int foo;
+  void m(this.foo) {}
+}
+''').executables);
+    _assertParameterZeroVisibleRange(m.parameters[0]);
+  }
+
   test_parameter_visibleRange_typedef() {
     UnlinkedTypedef type = serializeTypedefText('typedef F(x);');
     _assertParameterZeroVisibleRange(type.parameters[0]);
@@ -9532,6 +9619,14 @@
     expect(unlinkedUnits[1].isPartOf, isTrue);
   }
 
+  test_part_uri_invalid() {
+    String uriString = '[invalid uri]';
+    String libraryText = 'part "$uriString";';
+    serializeLibraryText(libraryText);
+    expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.parts[0], uriString);
+  }
+
   test_parts_defining_compilation_unit() {
     serializeLibraryText('');
     expect(linked.units, hasLength(1));
@@ -9842,6 +9937,17 @@
     checkDynamicTypeRef(serializeTypeText('dynamic'));
   }
 
+  test_type_invalid_typeParameter_asPrefix() {
+    UnlinkedClass c = serializeClassText('''
+class C<T> {
+  m(T.K p) {}
+}
+''');
+    UnlinkedExecutable m = c.executables[0];
+    expect(m.name, 'm');
+    checkTypeRef(m.parameters[0].type, null, null, 'dynamic');
+  }
+
   test_type_param_codeRange() {
     if (!includeInformative) return;
     UnlinkedClass cls =
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 0d95689..fcd68a9 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2424,6 +2424,21 @@
     check(implicitDynamic: false);
   }
 
+  void test_implicitDynamic_static() {
+    addFile(r'''
+class C {
+  static void test(int body()) {}
+}
+
+void main() {
+  C.test(/*info:INFERRED_TYPE_CLOSURE*/()  {
+    return 42;
+  });
+}
+''');
+    check(implicitDynamic: false);
+  }
+
   void test_implicitDynamic_type() {
     addFile(r'''
 class C<T> {}
diff --git a/pkg/analyzer/test/src/task/strong_mode_driver_test.dart b/pkg/analyzer/test/src/task/strong_mode_driver_test.dart
new file mode 100644
index 0000000..e459d9e
--- /dev/null
+++ b/pkg/analyzer/test/src/task/strong_mode_driver_test.dart
@@ -0,0 +1,19 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'strong_mode_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InstanceMemberInferrerTest_Driver);
+  });
+}
+
+@reflectiveTest
+class InstanceMemberInferrerTest_Driver extends InstanceMemberInferrerTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index fa2877c..ed3d8ca 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -4,16 +4,18 @@
 
 library analyzer.test.src.task.strong_mode_test;
 
-import 'package:analyzer/dart/ast/ast.dart';
+import 'dart:async';
+
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/strong_mode.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../context/abstract_context.dart';
+import '../../generated/resolver_test_case.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -24,8 +26,9 @@
 }
 
 @reflectiveTest
-class InstanceMemberInferrerTest extends AbstractContextTest {
+class InstanceMemberInferrerTest extends ResolverTestCase {
   InstanceMemberInferrer createInferrer(LibraryElement library) {
+    AnalysisContext context = library.context;
     return new InstanceMemberInferrer(
         context.typeProvider, new InheritanceManager(library),
         typeSystem: context.typeSystem);
@@ -35,20 +38,19 @@
    * Add a source with the given [content] and return the result of resolving
    * the source.
    */
-  CompilationUnitElement resolve(String content) {
-    Source source = addSource('/test.dart', content);
-    return context.resolveCompilationUnit2(source, source).element;
+  Future<CompilationUnitElement> resolve(String content) async {
+    Source source = addNamedSource('/test.dart', content);
+    if (enableNewAnalysisDriver) {
+      var analysisResult = await computeAnalysisResult(source);
+      return analysisResult.unit.element;
+    } else {
+      return analysisContext.resolveCompilationUnit2(source, source).element;
+    }
   }
 
-  void test_creation() {
-    InstanceMemberInferrer inferrer = createInferrer(null);
-    expect(inferrer, isNotNull);
-    expect(inferrer.typeSystem, isNotNull);
-  }
-
-  void test_inferCompilationUnit_field_multiple_different() {
+  test_inferCompilationUnit_field_multiple_different() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $fieldName;
 }
@@ -71,9 +73,9 @@
     expect(getterC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_field_multiple_different_generic() {
+  test_inferCompilationUnit_field_multiple_different_generic() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   E $fieldName;
 }
@@ -96,9 +98,9 @@
     expect(getterC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_field_multiple_dynamic() {
+  test_inferCompilationUnit_field_multiple_dynamic() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $fieldName;
 }
@@ -121,9 +123,9 @@
     expect(getterC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_field_multiple_same() {
+  test_inferCompilationUnit_field_multiple_same() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $fieldName;
 }
@@ -149,9 +151,9 @@
     expect(getterC.returnType, expectedType);
   }
 
-  void test_inferCompilationUnit_field_noOverride() {
+  test_inferCompilationUnit_field_noOverride() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   final $fieldName = 0;
 }
@@ -169,9 +171,9 @@
     expect(getterA.returnType, intType);
   }
 
-  void test_inferCompilationUnit_field_noOverride_bottom() {
+  test_inferCompilationUnit_field_noOverride_bottom() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   var $fieldName = null;
 }
@@ -188,9 +190,9 @@
     expect(getterA.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_field_single_explicitlyDynamic() {
+  test_inferCompilationUnit_field_single_explicitlyDynamic() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   dynamic $fieldName;
 }
@@ -213,9 +215,9 @@
     expect(getterB.returnType, getterA.returnType);
   }
 
-  void test_inferCompilationUnit_field_single_final() {
+  test_inferCompilationUnit_field_single_final() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   final int $fieldName;
 }
@@ -238,9 +240,9 @@
     expect(getterB.returnType, getterA.returnType);
   }
 
-  void test_inferCompilationUnit_field_single_final_narrowType() {
+  test_inferCompilationUnit_field_single_final_narrowType() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   final $fieldName;
 }
@@ -260,9 +262,9 @@
     expect(getterB.returnType, fieldB.type);
   }
 
-  void test_inferCompilationUnit_field_single_generic() {
+  test_inferCompilationUnit_field_single_generic() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   E $fieldName;
 }
@@ -283,9 +285,9 @@
     expect(getterB.returnType, typeBE);
   }
 
-  void test_inferCompilationUnit_field_single_inconsistentAccessors() {
+  test_inferCompilationUnit_field_single_inconsistentAccessors() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int get $fieldName => 0;
   set $fieldName(String value) {}
@@ -306,9 +308,9 @@
     expect(getterB.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_field_single_noModifiers() {
+  test_inferCompilationUnit_field_single_noModifiers() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $fieldName;
 }
@@ -331,9 +333,9 @@
     expect(getterB.returnType, getterA.returnType);
   }
 
-  void test_inferCompilationUnit_fieldFormal() {
+  test_inferCompilationUnit_fieldFormal() async {
     String fieldName = 'f';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   final $fieldName = 0;
   A([this.$fieldName = 'hello']);
@@ -353,9 +355,9 @@
     expect(paramA.type, intType);
   }
 
-  void test_inferCompilationUnit_getter_multiple_different() {
+  test_inferCompilationUnit_getter_multiple_different() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int get $getterName => 0;
 }
@@ -378,9 +380,9 @@
     expect(getterC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_getter_multiple_dynamic() {
+  test_inferCompilationUnit_getter_multiple_dynamic() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int get $getterName => 0;
 }
@@ -403,9 +405,9 @@
     expect(getterC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_getter_multiple_same() {
+  test_inferCompilationUnit_getter_multiple_same() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   String get $getterName => '';
 }
@@ -431,9 +433,9 @@
     expect(getterC.returnType, expectedType);
   }
 
-  void test_inferCompilationUnit_getter_single() {
+  test_inferCompilationUnit_getter_single() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int get $getterName => 0;
 }
@@ -456,9 +458,9 @@
     expect(getterB.returnType, getterA.returnType);
   }
 
-  void test_inferCompilationUnit_getter_single_generic() {
+  test_inferCompilationUnit_getter_single_generic() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   E get $getterName => 0;
 }
@@ -479,9 +481,9 @@
     expect(getterB.returnType, typeBE);
   }
 
-  void test_inferCompilationUnit_getter_single_inconsistentAccessors() {
+  test_inferCompilationUnit_getter_single_inconsistentAccessors() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int get $getterName => 0;
   set $getterName(String value) {}
@@ -507,8 +509,8 @@
     expect(getterB.returnType, getterA.returnType);
   }
 
-  void test_inferCompilationUnit_invalid_inheritanceCycle() {
-    CompilationUnitElement unit = resolve('''
+  test_inferCompilationUnit_invalid_inheritanceCycle() async {
+    CompilationUnitElement unit = await resolve('''
 class A extends C {}
 class B extends A {}
 class C extends B {}
@@ -516,9 +518,9 @@
     _runInferrer(unit);
   }
 
-  void test_inferCompilationUnit_method_parameter_multiple_different() {
+  test_inferCompilationUnit_method_parameter_multiple_different() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   $methodName(int p) => 0;
 }
@@ -539,9 +541,9 @@
     expect(parameterC.type.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_method_parameter_multiple_named_different() {
+  test_inferCompilationUnit_method_parameter_multiple_named_different() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   $methodName({int p}) => 0;
 }
@@ -562,9 +564,9 @@
     expect(parameterC.type.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_method_parameter_multiple_named_same() {
+  test_inferCompilationUnit_method_parameter_multiple_named_same() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   $methodName({int p}) => 0;
 }
@@ -589,9 +591,9 @@
     expect(parameterC.type, expectedType);
   }
 
-  void test_inferCompilationUnit_method_parameter_multiple_namedAndRequired() {
+  test_inferCompilationUnit_method_parameter_multiple_namedAndRequired() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   $methodName({int p}) => 0;
 }
@@ -612,10 +614,9 @@
     expect(parameterC.type.isDynamic, isTrue);
   }
 
-  void
-      test_inferCompilationUnit_method_parameter_multiple_optionalAndRequired() {
+  test_inferCompilationUnit_method_parameter_multiple_optionalAndRequired() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   $methodName(int p) => 0;
 }
@@ -640,9 +641,9 @@
     expect(parameterC.type, expectedType);
   }
 
-  void test_inferCompilationUnit_method_parameter_single_generic() {
+  test_inferCompilationUnit_method_parameter_single_generic() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   $methodName(E p) => 0;
 }
@@ -664,9 +665,9 @@
         reason: 'function type should still have type arguments');
   }
 
-  void test_inferCompilationUnit_method_return_multiple_different() {
+  test_inferCompilationUnit_method_return_multiple_different() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $methodName() => 0;
 }
@@ -686,9 +687,9 @@
     expect(methodC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_method_return_multiple_different_generic() {
+  test_inferCompilationUnit_method_return_multiple_different_generic() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   E $methodName() => null;
 }
@@ -708,9 +709,9 @@
     expect(methodC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_method_return_multiple_dynamic() {
+  test_inferCompilationUnit_method_return_multiple_dynamic() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $methodName() => 0;
 }
@@ -730,9 +731,9 @@
     expect(methodC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_method_return_multiple_same_generic() {
+  test_inferCompilationUnit_method_return_multiple_same_generic() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   E $methodName() => 0;
 }
@@ -752,9 +753,9 @@
     expect(methodC.returnType, classC.typeParameters[0].type);
   }
 
-  void test_inferCompilationUnit_method_return_multiple_same_nonVoid() {
+  test_inferCompilationUnit_method_return_multiple_same_nonVoid() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $methodName() => 0;
 }
@@ -777,9 +778,9 @@
     expect(methodC.returnType, expectedType);
   }
 
-  void test_inferCompilationUnit_method_return_multiple_same_void() {
+  test_inferCompilationUnit_method_return_multiple_same_void() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   void $methodName() {};
 }
@@ -802,9 +803,9 @@
     expect(methodC.returnType, expectedType);
   }
 
-  void test_inferCompilationUnit_method_return_multiple_void() {
+  test_inferCompilationUnit_method_return_multiple_void() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $methodName() => 0;
 }
@@ -824,9 +825,9 @@
     expect(methodC.returnType.isDynamic, isTrue);
   }
 
-  void test_inferCompilationUnit_method_return_single() {
+  test_inferCompilationUnit_method_return_single() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int $methodName() => 0;
 }
@@ -845,9 +846,9 @@
     expect(methodB.returnType, methodA.returnType);
   }
 
-  void test_inferCompilationUnit_method_return_single_generic() {
+  test_inferCompilationUnit_method_return_single_generic() async {
     String methodName = 'm';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   E $methodName() => 0;
 }
@@ -868,9 +869,9 @@
         reason: 'function type should still have type arguments');
   }
 
-  void test_inferCompilationUnit_setter_single() {
+  test_inferCompilationUnit_setter_single() async {
     String setterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   set $setterName(int x) {}
 }
@@ -893,9 +894,9 @@
     expect(setterB.parameters[0].type, setterA.parameters[0].type);
   }
 
-  void test_inferCompilationUnit_setter_single_generic() {
+  test_inferCompilationUnit_setter_single_generic() async {
     String setterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A<E> {
   set $setterName(E x) {}
 }
@@ -916,9 +917,9 @@
     expect(setterB.parameters[0].type, typeBE);
   }
 
-  void test_inferCompilationUnit_setter_single_inconsistentAccessors() {
+  test_inferCompilationUnit_setter_single_inconsistentAccessors() async {
     String getterName = 'g';
-    CompilationUnitElement unit = resolve('''
+    CompilationUnitElement unit = await resolve('''
 class A {
   int get $getterName => 0;
   set $getterName(String value) {}
@@ -954,39 +955,36 @@
 }
 
 @reflectiveTest
-class SetFieldTypeTest extends AbstractContextTest {
-  void test_setter_withoutParameter() {
-    CompilationUnitElement unit = _resolve('''
+class SetFieldTypeTest extends ResolverTestCase {
+  test_setter_withoutParameter() async {
+    Source source = addSource('''
 var x = 0;
 set x() {}
 ''');
+    var analysisResult = await computeAnalysisResult(source);
+    CompilationUnitElement unit = analysisResult.unit.element;
     TopLevelVariableElement variable = unit.topLevelVariables.single;
-    setFieldType(variable, context.typeProvider.intType);
-  }
-
-  CompilationUnitElement _resolve(String content) {
-    Source source = addSource('/test.dart', content);
-    return context.resolveCompilationUnit2(source, source).element;
+    setFieldType(variable, unit.context.typeProvider.intType);
   }
 }
 
 @reflectiveTest
-class VariableGathererTest extends AbstractContextTest {
-  void test_creation_withFilter() {
+class VariableGathererTest extends ResolverTestCase {
+  test_creation_withFilter() async {
     VariableFilter filter = (variable) => true;
     VariableGatherer gatherer = new VariableGatherer(filter);
     expect(gatherer, isNotNull);
     expect(gatherer.filter, filter);
   }
 
-  void test_creation_withoutFilter() {
+  test_creation_withoutFilter() async {
     VariableGatherer gatherer = new VariableGatherer();
     expect(gatherer, isNotNull);
     expect(gatherer.filter, isNull);
   }
 
-  void test_visit_noReferences() {
-    Source source = addSource(
+  test_visit_noReferences() async {
+    Source source = addNamedSource(
         '/test.dart',
         '''
 library lib;
@@ -997,23 +995,25 @@
 }
 typedef void F();
 ''');
-    CompilationUnit unit = context.resolveCompilationUnit2(source, source);
+    var analysisResult = await computeAnalysisResult(source);
     VariableGatherer gatherer = new VariableGatherer();
-    unit.accept(gatherer);
+    analysisResult.unit.accept(gatherer);
     expect(gatherer.results, hasLength(0));
   }
 
-  void test_visit_withFilter() {
+  test_visit_withFilter() async {
     VariableFilter filter = (VariableElement variable) => variable.isStatic;
-    expect(_gather(filter), hasLength(1));
+    Set<VariableElement> variables = await _gather(filter);
+    expect(variables, hasLength(1));
   }
 
-  void test_visit_withoutFilter() {
-    expect(_gather(), hasLength(4));
+  test_visit_withoutFilter() async {
+    Set<VariableElement> variables = await _gather();
+    expect(variables, hasLength(4));
   }
 
-  Set<VariableElement> _gather([VariableFilter filter = null]) {
-    Source source = addSource(
+  Future<Set<VariableElement>> _gather([VariableFilter filter = null]) async {
+    Source source = addNamedSource(
         '/test.dart',
         '''
 const int zero = 0;
@@ -1032,9 +1032,9 @@
   }
 }
 ''');
-    CompilationUnit unit = context.resolveCompilationUnit2(source, source);
+    var analysisResult = await computeAnalysisResult(source);
     VariableGatherer gatherer = new VariableGatherer(filter);
-    unit.accept(gatherer);
+    analysisResult.unit.accept(gatherer);
     return gatherer.results;
   }
 }
diff --git a/pkg/analyzer/test/src/task/test_all.dart b/pkg/analyzer/test/src/task/test_all.dart
index f34c36c..97858d8 100644
--- a/pkg/analyzer/test/src/task/test_all.dart
+++ b/pkg/analyzer/test/src/task/test_all.dart
@@ -20,6 +20,7 @@
 import 'options_test.dart' as options_test;
 import 'options_work_manager_test.dart' as options_work_manager_test;
 import 'strong/test_all.dart' as strong_mode_test_all;
+import 'strong_mode_driver_test.dart' as strong_mode_driver_test;
 import 'strong_mode_test.dart' as strong_mode_test;
 import 'yaml_test.dart' as yaml_test;
 
@@ -39,6 +40,7 @@
     options_test.main();
     options_work_manager_test.main();
     strong_mode_test_all.main();
+    strong_mode_driver_test.main();
     strong_mode_test.main();
     yaml_test.main();
   }, name: 'task');
diff --git a/pkg/analyzer/test/src/util/fast_uri_test.dart b/pkg/analyzer/test/src/util/fast_uri_test.dart
deleted file mode 100644
index f04dcb4..0000000
--- a/pkg/analyzer/test/src/util/fast_uri_test.dart
+++ /dev/null
@@ -1,179 +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 analyzer.test.src.util.fast_uri_test;
-
-import 'package:analyzer/src/util/fast_uri.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(_FastUriTest);
-  });
-}
-
-@reflectiveTest
-class _FastUriTest {
-  static final isInstanceOf<FastUri> isFastUri = new isInstanceOf<FastUri>();
-
-  void test_parse_absolute_dart() {
-    _compareTextWithCoreUri('dart:core');
-  }
-
-  void test_parse_absolute_file() {
-    _compareTextWithCoreUri('file:///Users/scheglov/util/fast_uri.dart');
-  }
-
-  void test_parse_absolute_folder_withSlashAtTheEnd() {
-    _compareTextWithCoreUri('file:///Users/scheglov/util/');
-  }
-
-  void test_parse_absolute_package() {
-    _compareTextWithCoreUri('package:analyzer/src/util/fast_uri.dart');
-  }
-
-  void test_parse_notFast_hasAuthority() {
-    Uri uri = FastUri.parse('http://www.google.com/pages/about.html');
-    expect(uri, isNot(isFastUri));
-  }
-
-  void test_parse_notFast_hasPort() {
-    Uri uri = FastUri.parse('http://www.google.com:8080/pages/about.html');
-    expect(uri, isNot(isFastUri));
-  }
-
-  void test_parse_relative_down() {
-    _compareTextWithCoreUri('util/fast_uri.dart');
-  }
-
-  void test_parse_relative_up() {
-    _compareTextWithCoreUri('../util/fast_uri.dart');
-  }
-
-  void test_resolve() {
-    Uri uri1 = FastUri.parse('package:analyzer/aaa/bbbb/c.dart');
-    Uri uri2 = uri1.resolve('dd.dart');
-    _compareUris(uri2, Uri.parse('package:analyzer/aaa/bbbb/dd.dart'));
-  }
-
-  void test_resolveUri_absolute() {
-    _checkResolveUri('package:analyzer/aaa/b.dart', 'package:path/style.dart',
-        'package:path/style.dart');
-  }
-
-  void test_resolveUri_endWithSlash_onlyName() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/', 'cc.dart',
-        'package:analyzer/aaa/bbbb/cc.dart');
-  }
-
-  void test_resolveUri_nameStartsWithOneDot() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', '.name.dart',
-        'package:analyzer/aaa/bbbb/.name.dart');
-  }
-
-  void test_resolveUri_nameStartsWithTwoDots() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', '..name.dart',
-        'package:analyzer/aaa/bbbb/..name.dart');
-  }
-
-  void test_resolveUri_noSlash_onlyName() {
-    _checkResolveUri('dart:core', 'int.dart', 'dart:core/int.dart');
-  }
-
-  void test_resolveUri_onlyName() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', 'dd.dart',
-        'package:analyzer/aaa/bbbb/dd.dart');
-  }
-
-  void test_resolveUri_pathHasOneDot() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', 'dd/./ee.dart',
-        'package:analyzer/aaa/bbbb/dd/ee.dart');
-  }
-
-  void test_resolveUri_pathHasTwoDots() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', 'dd/../ee.dart',
-        'package:analyzer/aaa/bbbb/ee.dart');
-  }
-
-  void test_resolveUri_pathStartsWithOneDot() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', './ddd.dart',
-        'package:analyzer/aaa/bbbb/ddd.dart');
-  }
-
-  void test_resolveUri_pathStartsWithTwoDots() {
-    _checkResolveUri('package:analyzer/aaa/bbbb/ccc.dart', '../ddd.dart',
-        'package:analyzer/aaa/ddd.dart');
-  }
-
-  void test_resolveUri_pathWithSubFolder() {
-    Uri uri1 = FastUri.parse('package:analyzer/aaa/bbbb/ccc.dart');
-    Uri uri2 = FastUri.parse('dd/eeee.dart');
-    expect(uri1, isFastUri);
-    expect(uri2, isFastUri);
-    Uri uri3 = uri1.resolveUri(uri2);
-    expect(uri3, isFastUri);
-    _compareUris(uri3, Uri.parse('package:analyzer/aaa/bbbb/dd/eeee.dart'));
-  }
-
-  void test_resolveUri_short_absolute() {
-    // Check the case where the URI being resolved is a "short absolute" uri
-    // (starts with a "/" but doesn't start with "file://").  Such URIs are not
-    // actually valid URIs but we still want to handle them in a way that's
-    // consistent with the behavior of Uri.
-    String containing = 'file:///foo/bar';
-    String relative = '/a.dart';
-    String expectedResult = Uri.parse(containing).resolve(relative).toString();
-    _checkResolveUri(containing, relative, expectedResult);
-  }
-
-  void _checkResolveUri(String srcText, String relText, String targetText) {
-    Uri src = FastUri.parse(srcText);
-    Uri rel = FastUri.parse(relText);
-    expect(src, isFastUri);
-    expect(rel, isFastUri);
-    Uri target = src.resolveUri(rel);
-    expect(target, isFastUri);
-    _compareUris(target, Uri.parse(targetText));
-  }
-
-  void _compareTextWithCoreUri(String text, {bool isFast: true}) {
-    Uri fastUri = FastUri.parse(text);
-    Uri coreUri = Uri.parse(text);
-    if (isFast) {
-      expect(fastUri, isFastUri);
-    }
-    _compareUris(fastUri, coreUri);
-  }
-
-  void _compareUris(Uri fastUri, Uri coreUri) {
-    expect(fastUri.authority, coreUri.authority);
-    expect(fastUri.data, coreUri.data);
-    expect(fastUri.fragment, coreUri.fragment);
-    expect(fastUri.hasAbsolutePath, coreUri.hasAbsolutePath);
-    expect(fastUri.hasAuthority, coreUri.hasAuthority);
-    expect(fastUri.hasEmptyPath, coreUri.hasEmptyPath);
-    expect(fastUri.hasFragment, coreUri.hasFragment);
-    expect(fastUri.hasPort, coreUri.hasPort);
-    expect(fastUri.hasQuery, coreUri.hasQuery);
-    expect(fastUri.hasScheme, coreUri.hasScheme);
-    expect(fastUri.host, coreUri.host);
-    expect(fastUri.isAbsolute, coreUri.isAbsolute);
-    if (coreUri.scheme == 'http' || coreUri.scheme == 'https') {
-      expect(fastUri.origin, coreUri.origin);
-    }
-    expect(fastUri.path, coreUri.path);
-    expect(fastUri.pathSegments, coreUri.pathSegments);
-    expect(fastUri.port, coreUri.port);
-    expect(fastUri.query, coreUri.query);
-    expect(fastUri.queryParameters, coreUri.queryParameters);
-    expect(fastUri.queryParametersAll, coreUri.queryParametersAll);
-    expect(fastUri.scheme, coreUri.scheme);
-    expect(fastUri.userInfo, coreUri.userInfo);
-    // Object
-    expect(fastUri.hashCode, coreUri.hashCode);
-    expect(fastUri == coreUri, isTrue);
-    expect(coreUri == fastUri, isTrue);
-  }
-}
diff --git a/pkg/analyzer/test/src/util/test_all.dart b/pkg/analyzer/test/src/util/test_all.dart
index c41d8c8..de12251 100644
--- a/pkg/analyzer/test/src/util/test_all.dart
+++ b/pkg/analyzer/test/src/util/test_all.dart
@@ -8,7 +8,6 @@
 
 import 'absolute_path_test.dart' as absolute_path_test;
 import 'asserts_test.dart' as asserts_test;
-import 'fast_uri_test.dart' as fast_uri_test;
 import 'glob_test.dart' as glob_test;
 import 'lru_map_test.dart' as lru_map_test;
 import 'yaml_test.dart' as yaml_test;
@@ -18,7 +17,6 @@
   defineReflectiveSuite(() {
     absolute_path_test.main();
     asserts_test.main();
-    fast_uri_test.main();
     glob_test.main();
     lru_map_test.main();
     yaml_test.main();
diff --git a/pkg/analyzer/tool/task_dependency_graph/generate.dart b/pkg/analyzer/tool/task_dependency_graph/generate.dart
index 26745f6..716db479 100644
--- a/pkg/analyzer/tool/task_dependency_graph/generate.dart
+++ b/pkg/analyzer/tool/task_dependency_graph/generate.dart
@@ -189,41 +189,57 @@
         .instantiate([dynamicType]);
     listOfResultDescriptorType =
         context.typeProvider.listType.instantiate([resultDescriptorType]);
-    CompilationUnitElement enginePluginUnitElement =
-        getUnit(enginePluginSource).element;
-    enginePluginClass = enginePluginUnitElement.getType('EnginePlugin');
+    CompilationUnit enginePluginUnit = getUnit(enginePluginSource);
+    enginePluginClass = enginePluginUnit.element.getType('EnginePlugin');
     extensionPointIdType =
-        enginePluginUnitElement.getType('ExtensionPointId').type;
+        enginePluginUnit.element.getType('ExtensionPointId').type;
     CompilationUnit dartDartUnit = getUnit(dartDartSource);
-    CompilationUnitElement dartDartUnitElement = dartDartUnit.element;
     CompilationUnit taskUnit = getUnit(taskSource);
     taskUnitElement = taskUnit.element;
     Set<String> results = new Set<String>();
     Set<String> resultLists = new Set<String>();
-    for (ClassElement cls in dartDartUnitElement.types) {
-      if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) {
-        String task = cls.name;
-        AstNode buildInputsAst = cls.getMethod('buildInputs').computeNode();
-        findResultDescriptors(buildInputsAst, (String input) {
-          results.add(input);
-          lines.add('  $input -> $task');
-        });
-        findResultDescriptorLists(buildInputsAst, (String input) {
-          resultLists.add(input);
-          lines.add('  $input -> $task');
-        });
-        findResultDescriptors(cls.getField('DESCRIPTOR').computeNode(),
-            (String out) {
-          results.add(out);
-          lines.add('  $task -> $out');
-        });
+    for (CompilationUnitMember dartUnitMember in dartDartUnit.declarations) {
+      if (dartUnitMember is ClassDeclaration) {
+        ClassDeclaration clazz = dartUnitMember;
+        if (!clazz.isAbstract &&
+            clazz.element.type.isSubtypeOf(analysisTaskType)) {
+          String task = clazz.name.name;
+
+          MethodDeclaration buildInputsAst;
+          VariableDeclaration descriptorField;
+          for (ClassMember classMember in clazz.members) {
+            if (classMember is MethodDeclaration &&
+                classMember.name.name == 'buildInputs') {
+              buildInputsAst = classMember;
+            }
+            if (classMember is FieldDeclaration) {
+              for (VariableDeclaration field in classMember.fields.variables) {
+                if (field.name.name == 'DESCRIPTOR') {
+                  descriptorField = field;
+                }
+              }
+            }
+          }
+
+          findResultDescriptors(buildInputsAst, (String input) {
+            results.add(input);
+            lines.add('  $input -> $task');
+          });
+          findResultDescriptorLists(buildInputsAst, (String input) {
+            resultLists.add(input);
+            lines.add('  $input -> $task');
+          });
+          findResultDescriptors(descriptorField, (String out) {
+            results.add(out);
+            lines.add('  $task -> $out');
+          });
+        }
       }
     }
-    AstNode enginePluginAst = enginePluginUnitElement.computeNode();
     for (String resultList in resultLists) {
       lines.add('  $resultList [shape=hexagon]');
       TopLevelVariableElement extensionIdVariable = _getExtensionId(resultList);
-      findExtensions(enginePluginAst, extensionIdVariable, (String extension) {
+      findExtensions(enginePluginUnit, extensionIdVariable, (String extension) {
         results.add(extension);
         lines.add('  $extension -> $resultList');
       });
diff --git a/pkg/analyzer_cli/.gitignore b/pkg/analyzer_cli/.gitignore
index 3a4106f..f6aef8f 100644
--- a/pkg/analyzer_cli/.gitignore
+++ b/pkg/analyzer_cli/.gitignore
@@ -1,11 +1,6 @@
 .buildlog
 .DS_Store
 .idea
-/.packages
 .project
-.pub/
 .settings/
-analyzer_cli.iml
 build/
-packages
-pubspec.lock
diff --git a/pkg/analyzer_cli/analyzer_cli.iml b/pkg/analyzer_cli/analyzer_cli.iml
new file mode 100644
index 0000000..4a27243
--- /dev/null
+++ b/pkg/analyzer_cli/analyzer_cli.iml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.pub" />
+      <excludeFolder url="file://$MODULE_DIR$/bin/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/embedder_client/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/library_and_parts/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/linter_project/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/no_lints_project/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/no_packages_file/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/options_include_directive_tests_project/lib/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/options_include_directive_tests_project/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/options_include_directive_tests_project/pkg/foo/lib/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/options_include_directive_tests_project/pkg/foo/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/options_include_directive_tests_project/pkg/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/options_tests_project/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_prefix/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_prefix/pkg/bar/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_prefix/pkg/foo/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_prefix/pkg/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_with_embedder_yaml/lib/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_with_embedder_yaml/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_with_sdk_extension/lib/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/package_with_sdk_extension/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/packages_file/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/data/strong_sdk/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/packages" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Dart SDK" level="application" />
+    <orderEntry type="library" name="Dart SDK" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index 186ed82..5df078a 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -132,9 +132,10 @@
       for (Source source in sources) {
         if (analysisDriver != null) {
           String path = source.fullName;
-          AnalysisResult analysisResult = await analysisDriver.getResult(path);
+          analysisDriver.addFile(path);
+          ErrorsResult errorsResult = await analysisDriver.getErrors(path);
           errorInfos.add(new AnalysisErrorInfoImpl(
-              analysisResult.errors, analysisResult.lineInfo));
+              errorsResult.errors, errorsResult.lineInfo));
         } else {
           context.computeErrors(source);
           errorInfos.add(context.getErrors(source));
@@ -164,10 +165,13 @@
 
   Future<ErrorSeverity> _analyze(int printMode) async {
     // Don't try to analyze parts.
-    if (context.computeKindOf(librarySource) == SourceKind.PART) {
+    String path = librarySource.fullName;
+    SourceKind librarySourceKind = analysisDriver != null
+        ? await analysisDriver.getSourceKind(path)
+        : context.computeKindOf(librarySource);
+    if (librarySourceKind == SourceKind.PART) {
       stderr.writeln("Only libraries can be analyzed.");
-      stderr.writeln(
-          "${librarySource.fullName} is a part and can not be analyzed.");
+      stderr.writeln("${path} is a part and can not be analyzed.");
       return ErrorSeverity.ERROR;
     }
 
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index cab1e4c..e91d07e 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -229,7 +229,10 @@
     var libUris = <Uri>[];
     var parts = <Source>[];
     for (Source source in sourcesToAnalyze) {
-      if (context.computeKindOf(source) == SourceKind.PART) {
+      SourceKind sourceKind = analysisDriver != null
+          ? await analysisDriver.getSourceKind(source.fullName)
+          : context.computeKindOf(source);
+      if (sourceKind == SourceKind.PART) {
         parts.add(source);
         continue;
       }
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
index 3b69a2a..78eb5c2 100644
--- a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
@@ -4,6 +4,8 @@
 
 library dart.async;
 
+abstract class FutureOr<T> {}
+
 abstract class Future<T> {}
 
 abstract class Stream<T> {}
diff --git a/pkg/analyzer_plugin/.analysis_options b/pkg/analyzer_plugin/.analysis_options
new file mode 100644
index 0000000..9f020a3
--- /dev/null
+++ b/pkg/analyzer_plugin/.analysis_options
@@ -0,0 +1,7 @@
+analyzer:
+  strong-mode: true
+linter:
+  rules:
+    - annotate_overrides
+    - empty_constructor_bodies
+    - unnecessary_brace_in_string_interp
diff --git a/pkg/analyzer_plugin/BUILD.gn b/pkg/analyzer_plugin/BUILD.gn
new file mode 100644
index 0000000..153af16
--- /dev/null
+++ b/pkg/analyzer_plugin/BUILD.gn
@@ -0,0 +1,17 @@
+# 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("//build/dart/dart_package.gni")
+
+dart_package("analyzer_plugin") {
+  package_name = "analyzer_plugin"
+
+  source_dir = "lib"
+
+  deps = [
+    "//dart/pkg/analyzer",
+    "//third_party/dart-pkg/pub/html",
+    "//third_party/dart-pkg/pub/path",
+  ]
+}
diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md
new file mode 100644
index 0000000..2a2d63c
--- /dev/null
+++ b/pkg/analyzer_plugin/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## 0.0.1
+
+- Initial version
diff --git a/pkg/analyzer_plugin/LICENSE b/pkg/analyzer_plugin/LICENSE
new file mode 100644
index 0000000..389ce98
--- /dev/null
+++ b/pkg/analyzer_plugin/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2017, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/analyzer_plugin/README.md b/pkg/analyzer_plugin/README.md
new file mode 100644
index 0000000..954aa0e
--- /dev/null
+++ b/pkg/analyzer_plugin/README.md
@@ -0,0 +1,21 @@
+# analyzer_plugin
+
+A framework for building plugins for the analysis server.
+
+## Usage
+
+## Support
+
+Post issues and feature requests on the [issue tracker][issues].
+
+Questions and discussions are welcome at the
+[Dart Analyzer Discussion Group][list].
+
+## License
+
+See the [LICENSE] file.
+
+[issues]: https://github.com/dart-lang/sdk/issues
+[LICENSE]: https://github.com/dart-lang/sdk/blob/master/pkg/analyzer/LICENSE
+[list]: https://groups.google.com/a/dartlang.org/forum/#!forum/analyzer-discuss
+[pluginapi]: https://htmlpreview.github.io/?https://github.com/dart-lang/sdk/blob/master/pkg/analyzer_plugin/doc/api.html
diff --git a/pkg/analyzer_plugin/analyzer_plugin.iml b/pkg/analyzer_plugin/analyzer_plugin.iml
new file mode 100644
index 0000000..b9b8eef
--- /dev/null
+++ b/pkg/analyzer_plugin/analyzer_plugin.iml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.pub" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/integration/support/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/channel/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/utilities/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/spec/packages" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Dart SDK" level="application" />
+    <orderEntry type="library" name="Dart SDK" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
new file mode 100644
index 0000000..7f92857
--- /dev/null
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -0,0 +1,2499 @@
+<!DOCTYPE html><html><head>
+  <meta charset="UTF-8">
+  <title>Analysis Server Plugin API Specification</title>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro|Roboto:500,400italic,300,400" type="text/css"><style>body {
+  font-family: 'Roboto', sans-serif;
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 0 16px;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #111;
+  background-color: #fdfdfd;
+  font-weight: 300;
+  -webkit-font-smoothing: auto;
+}
+
+h1 {
+  text-align: center;
+}
+
+h2, h3, h4, h5 {
+  margin-bottom: 0;
+}
+
+h2.domain {
+  border-bottom: 1px solid rgb(200, 200, 200);
+  margin-bottom: 0.5em;
+}
+
+h4 {
+  font-size: 18px;
+}
+
+h5 {
+  font-size: 16px;
+}
+
+p {
+  margin-top: 0;
+}
+
+pre {
+  margin: 0;
+  font-family: 'Source Code Pro', monospace;
+  font-size: 15px;
+}
+
+div.box {
+  background-color: rgb(240, 245, 240);
+  border-radius: 4px;
+  padding: 4px 12px;
+  margin: 16px 0;
+}
+
+div.hangingIndent {
+  padding-left: 3em;
+  text-indent: -3em;
+}
+
+dl dt {
+  font-weight: bold;
+}
+
+dl dd {
+  margin-left: 16px;
+}
+
+dt {
+  margin-top: 1em;
+}
+
+dt.notification {
+  font-weight: bold;
+}
+
+dt.refactoring {
+  font-weight: bold;
+}
+
+dt.request {
+  font-weight: bold;
+}
+
+dt.typeDefinition {
+  font-weight: bold;
+}
+
+a {
+  text-decoration: none;
+}
+
+a:focus, a:hover {
+  text-decoration: underline;
+}
+
+/* Styles for index */
+
+.subindex {
+}
+
+.subindex ul {
+  padding-left: 0;
+  margin-left: 0;
+
+  -webkit-margin-before: 0;
+  -webkit-margin-start: 0;
+  -webkit-padding-start: 0;
+
+  list-style-type: none;
+}
+</style></head>
+<body>
+<h1>Analysis Server Plugin API Specification</h1>
+<h1 style="color:#999999">Version
+  1.0.0-alpha.0
+</h1>
+<p>
+  This document contains a specification of the API used by the analysis
+  server to communicate with analysis server plugins. Changes to the API will be
+  accompanied by an update to the protocol version number according to the
+  principles of semantic versioning
+  (<a href="http://semver.org/">semver.org</a>).
+</p>
+<h2>Overview</h2>
+<p>
+  TBD
+</p>
+<h2 class="domain"><a name="domain_plugin">plugin domain</a></h2>
+  <p>
+    The plugin domain contains API’s related to the execution of a plugin.
+  </p>
+  <p>
+    TODO: Provide notifications by which plugins can report instrumentation
+    and/or DartSilo data.
+  </p>
+  <p>
+    TODO: Add a notification to the server protocol to inform the client of
+    problems related to the execution of plugins.
+  </p>
+  
+  
+  
+<h3>Requests</h3><dl><dt class="request"><a name="request_plugin.versionCheck">plugin.versionCheck</a> (<a href="#request_plugin.versionCheck">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "plugin.versionCheck"
+  "params": {
+    "<b>byteStorePath</b>": String
+    "<b>version</b>": String
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>isCompatible</b>": bool
+    "<b>name</b>": String
+    "<b>version</b>": String
+    "<b>contactInfo</b>": <span style="color:#999999">optional</span> String
+    "<b>interestingFiles</b>": List&lt;String&gt;
+  }
+}</pre></div>
+    <p>
+      Used to request that the plugin perform a version check to confirm that it
+      works with the version of the analysis server that is executing it.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>byteStorePath (String)</b></dt><dd>
+        
+        <p>
+          The path to the directory containing the on-disk byte store that is to
+          be used by any analysis drivers that are created.
+        </p>
+      </dd><dt class="field"><b>version (String)</b></dt><dd>
+        
+        <p>
+          The version number of the plugin spec supported by the analysis server
+          that is executing the plugin.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>isCompatible (bool)</b></dt><dd>
+        
+        <p>
+          A flag indicating whether the plugin supports the same version of the
+          plugin spec as the analysis server. If the value is <tt>false</tt>,
+          then the plugin is expected to shutdown after returning the response.
+        </p>
+      </dd><dt class="field"><b>name (String)</b></dt><dd>
+        
+        <p>
+          The name of the plugin. This value is only used when the server needs
+          to identify the plugin, either to the user or for debugging purposes.
+        </p>
+      </dd><dt class="field"><b>version (String)</b></dt><dd>
+        
+        <p>
+          The version of the plugin. This value is only used when the server
+          needs to identify the plugin, either to the user or for debugging
+          purposes.
+        </p>
+      </dd><dt class="field"><b>contactInfo (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          Information that the user can use to use to contact the maintainers of
+          the plugin when there is a problem.
+        </p>
+      </dd><dt class="field"><b>interestingFiles (List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The glob patterns of the files for which the plugin will provide
+          information. This value is ignored if the <tt>isCompatible</tt>
+          field is <tt>false</tt>. Otherwise, it will be used to identify
+          the files for which the plugin should be notified of changes.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_plugin.shutdown">plugin.shutdown</a> (<a href="#request_plugin.shutdown">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "plugin.shutdown"
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to request that the plugin exit. The server will not send any other
+      requests after this request. The plugin should not send any responses or
+      notifications after sending the response to this request.
+    </p>
+  </dd></dl><h3>Notifications</h3><dl><dt class="notification"><a name="notification_plugin.error">plugin.error</a> (<a href="#notification_plugin.error">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "plugin.error"
+  "params": {
+    "<b>isFatal</b>": bool
+    "<b>message</b>": String
+    "<b>stackTrace</b>": String
+  }
+}</pre></div>
+    <p>
+      Used to report that an unexpected error has occurred while executing the
+      plugin. This notification is not used for problems with specific requests
+      (which should be returned as part of the response) but is used for
+      exceptions that occur while performing other tasks, such as analysis or
+      preparing notifications.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>isFatal (bool)</b></dt><dd>
+        
+        <p>
+          A flag indicating whether the error is a fatal error, meaning that the
+          plugin will shutdown automatically after sending this notification. If
+          <tt>true</tt>, the server will not expect any other responses or
+          notifications from the plugin.
+        </p>
+      </dd><dt class="field"><b>message (String)</b></dt><dd>
+        
+        <p>
+          The error message indicating what kind of error was encountered.
+        </p>
+      </dd><dt class="field"><b>stackTrace (String)</b></dt><dd>
+        
+        <p>
+          The stack trace associated with the generation of the error, used for
+          debugging the plugin.
+        </p>
+      </dd></dl></dd></dl>
+<h2 class="domain"><a name="domain_analysis">analysis domain</a></h2>
+  <p>
+    The analysis domain contains API’s related to the analysis of files.
+  </p>
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+<h3>Requests</h3><dl><dt class="request"><a name="request_analysis.handleWatchEvents">analysis.handleWatchEvents</a> (<a href="#request_analysis.handleWatchEvents">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.handleWatchEvents"
+  "params": {
+    "<b>events</b>": List&lt;<a href="#type_WatchEvent">WatchEvent</a>&gt;
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to inform the plugin of changes to files in the file system. Only
+      events associated with files that match the <tt>interestingFiles</tt> glob
+      patterns will be forwarded to the plugin.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>events (List&lt;<a href="#type_WatchEvent">WatchEvent</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The watch events that the plugin should handle.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_analysis.reanalyze">analysis.reanalyze</a> (<a href="#request_analysis.reanalyze">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.reanalyze"
+  "params": {
+    "<b>roots</b>": <span style="color:#999999">optional</span> List&lt;<a href="#type_FilePath">FilePath</a>&gt;
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to force the re-analysis of everything contained in the specified
+      context roots. This should cause all previously computed analysis results
+      to be discarded and recomputed, and should cause all subscribed
+      notifications to be re-sent.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>roots (<span style="color:#999999">optional</span> List&lt;<a href="#type_FilePath">FilePath</a>&gt;)</b></dt><dd>
+        
+        <p>
+          A list of the context roots that are to be re-analyzed.
+        </p>
+        <p>
+          If no context roots are provided, then all current context roots
+          should be re-analyzed.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_analysis.setContextBuilderOptions">analysis.setContextBuilderOptions</a> (<a href="#request_analysis.setContextBuilderOptions">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.setContextBuilderOptions"
+  "params": {
+    "<b>options</b>": <a href="#type_ContextBuilderOptions">ContextBuilderOptions</a>
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to set the options used to build analysis contexts. This request will
+      be sent exactly once before any context roots have been specified.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>options (<a href="#type_ContextBuilderOptions">ContextBuilderOptions</a>)</b></dt><dd>
+        
+        <p>
+          The options used to build the analysis contexts.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_analysis.setContextRoots">analysis.setContextRoots</a> (<a href="#request_analysis.setContextRoots">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.setContextRoots"
+  "params": {
+    "<b>roots</b>": List&lt;<a href="#type_ContextRoot">ContextRoot</a>&gt;
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Set the list of context roots that should be analyzed.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>roots (List&lt;<a href="#type_ContextRoot">ContextRoot</a>&gt;)</b></dt><dd>
+        
+        <p>
+          A list of the context roots that should be analyzed.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_analysis.setPriorityFiles">analysis.setPriorityFiles</a> (<a href="#request_analysis.setPriorityFiles">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.setPriorityFiles"
+  "params": {
+    "<b>files</b>": List&lt;<a href="#type_FilePath">FilePath</a>&gt;
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to set the priority files to the files in the given list. A priority
+      file is a file that should be given priority when scheduling which
+      analysis work to do first. The list typically contains those files that
+      are visible to the user and those for which analysis results will have the
+      biggest impact on the user experience. The order of the files within the
+      list is significant: the first file will be given higher priority than
+      the second, the second higher priority than the third, and so on.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>files (List&lt;<a href="#type_FilePath">FilePath</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The files that are to be a priority for analysis.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_analysis.setSubscriptions">analysis.setSubscriptions</a> (<a href="#request_analysis.setSubscriptions">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.setSubscriptions"
+  "params": {
+    "<b>subscriptions</b>": Map&lt;<a href="#type_AnalysisService">AnalysisService</a>, List&lt;<a href="#type_FilePath">FilePath</a>&gt;&gt;
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to subscribe for services that are specific to individual files. All
+      previous subscriptions should be replaced by the current set of
+      subscriptions. If a given service is not included as a key in the map then
+      no files should be subscribed to the service, exactly as if the service
+      had been included in the map with an explicit empty list of files.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>subscriptions (Map&lt;<a href="#type_AnalysisService">AnalysisService</a>, List&lt;<a href="#type_FilePath">FilePath</a>&gt;&gt;)</b></dt><dd>
+        
+        <p>
+          A table mapping services to a list of the files being subscribed to
+          the service.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_analysis.updateContent">analysis.updateContent</a> (<a href="#request_analysis.updateContent">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.updateContent"
+  "params": {
+    "<b>files</b>": Map&lt;<a href="#type_FilePath">FilePath</a>, <a href="#type_AddContentOverlay">AddContentOverlay</a> | <a href="#type_ChangeContentOverlay">ChangeContentOverlay</a> | <a href="#type_RemoveContentOverlay">RemoveContentOverlay</a>&gt;
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+    <p>
+      Used to update the content of one or more files. Files that were
+      previously updated but not included in this update remain unchanged. This
+      effectively represents an overlay of the filesystem. The files whose
+      content is overridden are therefore seen by the plugin as being files with
+      the given content, even if the files do not exist on the filesystem or if
+      the file path represents the path to a directory on the filesystem.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>files (Map&lt;<a href="#type_FilePath">FilePath</a>, <a href="#type_AddContentOverlay">AddContentOverlay</a> | <a href="#type_ChangeContentOverlay">ChangeContentOverlay</a> | <a href="#type_RemoveContentOverlay">RemoveContentOverlay</a>&gt;)</b></dt><dd>
+        
+        <p>
+          A table mapping the files whose content has changed to a description
+          of the content change.
+        </p>
+      </dd></dl></dd></dl><h3>Notifications</h3><dl><dt class="notification"><a name="notification_analysis.errors">analysis.errors</a> (<a href="#notification_analysis.errors">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "analysis.errors"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>errors</b>": List&lt;<a href="#type_AnalysisError">AnalysisError</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to report the errors associated with a given file. The set of errors
+      included in the notification is always a complete list that supersedes any
+      previously reported errors.
+    </p>
+    <p>
+      TODO: Decide whether we need to support the '--no-error-notification'
+      option.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the errors.
+        </p>
+      </dd><dt class="field"><b>errors (List&lt;<a href="#type_AnalysisError">AnalysisError</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The errors contained in the file.
+        </p>
+      </dd></dl></dd><dt class="notification"><a name="notification_analysis.folding">analysis.folding</a> (<a href="#notification_analysis.folding">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "analysis.folding"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>regions</b>": List&lt;<a href="#type_FoldingRegion">FoldingRegion</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to report the folding regions associated with a given file. Folding
+      regions can be nested, but cannot be overlapping. Nesting occurs when a
+      foldable element, such as a method, is nested inside another foldable
+      element such as a class.
+    </p>
+    <p>
+      Folding regions that overlap a folding region computed by the server, or
+      by one of the other plugins that are currently running, might be dropped
+      by the server in order to present a consistent view to the client.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"FOLDING"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the folding regions.
+        </p>
+      </dd><dt class="field"><b>regions (List&lt;<a href="#type_FoldingRegion">FoldingRegion</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The folding regions contained in the file.
+        </p>
+      </dd></dl></dd><dt class="notification"><a name="notification_analysis.highlights">analysis.highlights</a> (<a href="#notification_analysis.highlights">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "analysis.highlights"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>regions</b>": List&lt;<a href="#type_HighlightRegion">HighlightRegion</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to report the highlight regions associated with a given file. Each
+      highlight region represents a particular syntactic or semantic meaning
+      associated with some range. Note that the highlight regions that are
+      returned can overlap other highlight regions if there is more than one
+      meaning associated with a particular region.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"HIGHLIGHTS"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the highlight regions.
+        </p>
+      </dd><dt class="field"><b>regions (List&lt;<a href="#type_HighlightRegion">HighlightRegion</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The highlight regions contained in the file.
+        </p>
+      </dd></dl></dd><dt class="notification"><a name="notification_analysis.navigation">analysis.navigation</a> (<a href="#notification_analysis.navigation">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "analysis.navigation"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>regions</b>": List&lt;<a href="#type_NavigationRegion">NavigationRegion</a>&gt;
+    "<b>targets</b>": List&lt;<a href="#type_NavigationTarget">NavigationTarget</a>&gt;
+    "<b>files</b>": List&lt;<a href="#type_FilePath">FilePath</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to report the navigation regions associated with a given file. Each
+      navigation region represents a list of targets associated with some range.
+      The lists will usually contain a single target, but can contain more in
+      the case of a part that is included in multiple libraries or in Dart code
+      that is compiled against multiple versions of a package. Note that the
+      navigation regions that are returned should not overlap other navigation
+      regions.
+    </p>
+    <p>
+      Navigation regions that overlap a navigation region computed by the
+      server, or by one of the other plugins that are currently running, might
+      be dropped or modified by the server in order to present a consistent view
+      to the client.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"NAVIGATION"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the navigation regions.
+        </p>
+      </dd><dt class="field"><b>regions (List&lt;<a href="#type_NavigationRegion">NavigationRegion</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The navigation regions contained in the file.
+        </p>
+      </dd><dt class="field"><b>targets (List&lt;<a href="#type_NavigationTarget">NavigationTarget</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The navigation targets referenced in the file. They are referenced by
+          <a href="#type_NavigationRegion">NavigationRegion</a>s by their index
+          in this array.
+        </p>
+      </dd><dt class="field"><b>files (List&lt;<a href="#type_FilePath">FilePath</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The files containing navigation targets referenced in the file. They
+          are referenced by
+          <a href="#type_NavigationTarget">NavigationTarget</a>s by their index
+          in this array.
+        </p>
+      </dd></dl></dd><dt class="notification"><a name="notification_analysis.occurrences">analysis.occurrences</a> (<a href="#notification_analysis.occurrences">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "analysis.occurrences"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>occurrences</b>": List&lt;<a href="#type_Occurrences">Occurrences</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to report the occurrences of references to elements within a single
+      file. None of the occurrence regions should overlap.
+    </p>
+    <p>
+      Occurrence regions that overlap an occurrence region computed by the
+      server, or by one of the other plugins that are currently running, might
+      be dropped or modified by the server in order to present a consistent view
+      to the client.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"OCCURRENCES"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file in which the references occur.
+        </p>
+      </dd><dt class="field"><b>occurrences (List&lt;<a href="#type_Occurrences">Occurrences</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The occurrences of references to elements within the file.
+        </p>
+      </dd></dl></dd><dt class="notification"><a name="notification_analysis.outline">analysis.outline</a> (<a href="#notification_analysis.outline">#</a>)</dt><dd><div class="box"><pre>notification: {
+  "event": "analysis.outline"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>outline</b>": List&lt;<a href="#type_Outline">Outline</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to report the outline fragments associated with a single file.
+    </p>
+    <p>
+      The outline fragments will be merged with any outline produced by the
+      server and with any fragments produced by other plugins. If the server
+      cannot create a coherent outline, some fragments might be dropped.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"OUTLINE"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file with which the outline is associated.
+        </p>
+      </dd><dt class="field"><b>outline (List&lt;<a href="#type_Outline">Outline</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The outline fragments associated with the file.
+        </p>
+      </dd></dl></dd></dl>
+<h2 class="domain"><a name="domain_completion">completion domain</a></h2>
+  <p>
+    The code completion domain contains API's related to getting code completion
+    suggestions.
+  </p>
+  
+<h3>Requests</h3><dl><dt class="request"><a name="request_completion.getSuggestions">completion.getSuggestions</a> (<a href="#request_completion.getSuggestions">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "completion.getSuggestions"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>replacementOffset</b>": int
+    "<b>replacementLength</b>": int
+    "<b>results</b>": List&lt;<a href="#type_CompletionSuggestion">CompletionSuggestion</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to request that completion suggestions for the given offset in the
+      given file be returned.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the point at which suggestions are to be made.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset within the file at which suggestions are to be made.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>replacementOffset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the start of the text to be replaced. This will be
+          different than the offset used to request the completion suggestions
+          if there was a portion of an identifier before the original offset. In
+          particular, the replacementOffset will be the offset of the beginning
+          of said identifier.
+        </p>
+      </dd><dt class="field"><b>replacementLength (int)</b></dt><dd>
+        
+        <p>
+          The length of the text to be replaced if the remainder of the
+          identifier containing the cursor is to be replaced when the suggestion
+          is applied (that is, the number of characters in the existing
+          identifier).
+        </p>
+      </dd><dt class="field"><b>results (List&lt;<a href="#type_CompletionSuggestion">CompletionSuggestion</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The completion suggestions being reported. The notification contains
+          all possible completions at the requested cursor position, even those
+          that do not match the characters the user has already typed. This
+          allows the client to respond to further keystrokes from the user
+          without having to make additional requests.
+        </p>
+      </dd></dl></dd></dl>
+<h2 class="domain"><a name="domain_edit">edit domain</a></h2>
+  <p>
+    The edit domain contains API's related to edits that can be applied to the
+    code.
+  </p>
+  
+  
+  
+  
+<h3>Requests</h3><dl><dt class="request"><a name="request_edit.getAssists">edit.getAssists</a> (<a href="#request_edit.getAssists">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "edit.getAssists"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+    "<b>length</b>": int
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>assists</b>": List&lt;<a href="#type_PrioritizedSourceChange">PrioritizedSourceChange</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to request the set of assists that are available at the given
+      location. An assist is distinguished from a refactoring primarily by the
+      fact that it affects a single file and does not require user input in
+      order to be performed.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the code for which assists are being requested.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the code for which assists are being requested.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the code for which assists are being requested.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>assists (List&lt;<a href="#type_PrioritizedSourceChange">PrioritizedSourceChange</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The assists that are available at the given location.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_edit.getAvailableRefactorings">edit.getAvailableRefactorings</a> (<a href="#request_edit.getAvailableRefactorings">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "edit.getAvailableRefactorings"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+    "<b>length</b>": int
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>kinds</b>": List&lt;<a href="#type_RefactoringKind">RefactoringKind</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to request a list of the kinds of refactorings that are valid for the
+      given selection in the given file.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the code on which the refactoring would be based.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the code on which the refactoring would be based.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the code on which the refactoring would be based.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>kinds (List&lt;<a href="#type_RefactoringKind">RefactoringKind</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The kinds of refactorings that are valid for the given selection.
+        </p>
+        <p>
+          The list of refactoring kinds is currently limited to those defined by
+          the server API, preventing plugins from adding their own refactorings.
+          However, plugins can support pre-defined refactorings, such as a
+          rename refactoring, at locations not supported by server.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_edit.getFixes">edit.getFixes</a> (<a href="#request_edit.getFixes">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "edit.getFixes"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>fixes</b>": List&lt;<a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a>&gt;
+  }
+}</pre></div>
+    <p>
+      Used to request the set of fixes that are available for the errors at a
+      given offset in a given file.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the errors for which fixes are being requested.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset used to select the errors for which fixes will be returned.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>fixes (List&lt;<a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The fixes that are available for the errors at the given offset.
+        </p>
+      </dd></dl></dd><dt class="request"><a name="request_edit.getRefactoring">edit.getRefactoring</a> (<a href="#request_edit.getRefactoring">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "edit.getRefactoring"
+  "params": {
+    "<b>kind</b>": <a href="#type_RefactoringKind">RefactoringKind</a>
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+    "<b>length</b>": int
+    "<b>validateOnly</b>": bool
+    "<b>options</b>": <span style="color:#999999">optional</span> <a href="#type_RefactoringOptions">RefactoringOptions</a>
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>initialProblems</b>": List&lt;<a href="#type_RefactoringProblem">RefactoringProblem</a>&gt;
+    "<b>optionsProblems</b>": List&lt;<a href="#type_RefactoringProblem">RefactoringProblem</a>&gt;
+    "<b>finalProblems</b>": List&lt;<a href="#type_RefactoringProblem">RefactoringProblem</a>&gt;
+    "<b>feedback</b>": <span style="color:#999999">optional</span> <a href="#type_RefactoringFeedback">RefactoringFeedback</a>
+    "<b>change</b>": <span style="color:#999999">optional</span> <a href="#type_SourceChange">SourceChange</a>
+    "<b>potentialEdits</b>": <span style="color:#999999">optional</span> List&lt;String&gt;
+  }
+}</pre></div>
+    <p>
+      Used to request the changes required to perform a refactoring.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>kind (<a href="#type_RefactoringKind">RefactoringKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of refactoring to be performed.
+        </p>
+      </dd><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the code involved in the refactoring.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the region involved in the refactoring.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the region involved in the refactoring.
+        </p>
+      </dd><dt class="field"><b>validateOnly (bool)</b></dt><dd>
+        
+        <p>
+          True if the client is only requesting that the values of the options
+          be validated and no change be generated.
+        </p>
+      </dd><dt class="field"><b>options (<span style="color:#999999">optional</span> <a href="#type_RefactoringOptions">RefactoringOptions</a>)</b></dt><dd>
+        
+        <p>
+          Data used to provide values provided by the user. The structure of the
+          data is dependent on the kind of refactoring being performed. The data
+          that is expected is documented in the section titled
+          <a href="#refactorings">Refactorings</a>, labeled as "Options". This
+          field can be omitted if the refactoring does not require any options
+          or if the values of those options are not known.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>initialProblems (List&lt;<a href="#type_RefactoringProblem">RefactoringProblem</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The initial status of the refactoring, that is, problems related to
+          the context in which the refactoring is requested. The list should be
+          empty if there are no known problems.
+        </p>
+      </dd><dt class="field"><b>optionsProblems (List&lt;<a href="#type_RefactoringProblem">RefactoringProblem</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The options validation status, that is, problems in the given options,
+          such as light-weight validation of a new name, flags compatibility,
+          etc. The list should be empty if there are no known problems.
+        </p>
+      </dd><dt class="field"><b>finalProblems (List&lt;<a href="#type_RefactoringProblem">RefactoringProblem</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The final status of the refactoring, that is, problems identified in
+          the result of a full, potentially expensive validation and / or change
+          creation. The list should be empty if there are no known problems.
+        </p>
+      </dd><dt class="field"><b>feedback (<span style="color:#999999">optional</span> <a href="#type_RefactoringFeedback">RefactoringFeedback</a>)</b></dt><dd>
+        
+        <p>
+          Data used to provide feedback to the user. The structure of the data
+          is dependent on the kind of refactoring being created. The data that
+          is returned is documented in the section titled
+          <a href="#refactorings">Refactorings</a>, labeled as "Feedback".
+        </p>
+      </dd><dt class="field"><b>change (<span style="color:#999999">optional</span> <a href="#type_SourceChange">SourceChange</a>)</b></dt><dd>
+        
+        <p>
+          The changes that are to be applied to affect the refactoring. This
+          field can be omitted if there are problems that prevent a set of
+          changes from being computed, such as having no options specified for a
+          refactoring that requires them, or if only validation was requested.
+        </p>
+      </dd><dt class="field"><b>potentialEdits (<span style="color:#999999">optional</span> List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The ids of source edits that are not known to be valid. An edit is not
+          known to be valid if there was insufficient type information for the
+          plugin to be able to determine whether or not the code needs to be
+          modified, such as when a member is being renamed and there is a
+          reference to a member from an unknown type. This field can be omitted
+          if the change field is omitted or if there are no potential edits for
+          the refactoring.
+        </p>
+      </dd></dl></dd></dl>
+
+  <h2 class="domain"><a name="types">Types</a></h2>
+  <p>
+    This section contains descriptions of the data types referenced in the API’s
+    of the various domains.
+  </p>
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+<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
+      content will be used for analysis in place of the file contents in the
+      filesystem.
+    </p>
+    <p>
+      If this directive is used on a file that already has a file content
+      overlay, the old overlay is discarded and replaced with the new one.
+    </p>
+    
+  <dl><dt class="field"><b>type = "add"</b></dt><dd></dd><dt class="field"><b>content (String)</b></dt><dd>
+        
+        <p>
+          The new content of the file.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisError">AnalysisError: object</a></dt><dd>
+    <p>
+      An indication of an error, warning, or hint that was produced by the
+      analysis.
+    </p>
+    
+  <dl><dt class="field"><b>severity (<a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a>)</b></dt><dd>
+        
+        <p>
+          The severity of the error.
+        </p>
+      </dd><dt class="field"><b>type (<a href="#type_AnalysisErrorType">AnalysisErrorType</a>)</b></dt><dd>
+        
+        <p>
+          The type of the error.
+        </p>
+      </dd><dt class="field"><b>location (<a href="#type_Location">Location</a>)</b></dt><dd>
+        
+        <p>
+          The location associated with the error.
+        </p>
+      </dd><dt class="field"><b>message (String)</b></dt><dd>
+        
+        <p>
+          The message to be displayed for this error. The message should
+          indicate what is wrong with the code and why it is wrong.
+        </p>
+      </dd><dt class="field"><b>correction (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The correction message to be displayed for this error. The correction
+          message should indicate how the user can fix the error. The field is
+          omitted if there is no correction message associated with the error
+          code.
+        </p>
+      </dd><dt class="field"><b>code (String)</b></dt><dd>
+        
+        <p>
+          The name, as a string, of the error code associated with this error.
+        </p>
+      </dd><dt class="field"><b>hasFix (<span style="color:#999999">optional</span> bool)</b></dt><dd>
+        
+        <p>
+          A hint to indicate to interested clients that this error has an
+          associated fix (or fixes). The absence of this field implies there
+          are not known to be fixes. Note that since the operation to calculate
+          whether fixes apply needs to be performant it is possible that
+          complicated tests will be skipped and a false negative returned. For
+          this reason, this attribute should be treated as a "hint". Despite the
+          possibility of false negatives, no false positives should be returned.
+          If a client sees this flag set they can proceed with the confidence
+          that there are in fact associated fixes.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorFixes">AnalysisErrorFixes: object</a></dt><dd>
+    <p>
+      A list of fixes associated with a specific error
+    </p>
+    
+  <dl><dt class="field"><b>error (<a href="#type_AnalysisError">AnalysisError</a>)</b></dt><dd>
+        
+        <p>
+          The error with which the fixes are associated.
+        </p>
+      </dd><dt class="field"><b>fixes (List&lt;<a href="#type_PrioritizedSourceChange">PrioritizedSourceChange</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The fixes associated with the error.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorSeverity">AnalysisErrorSeverity: String</a></dt><dd>
+    <p>
+      An enumeration of the possible severities of analysis errors.
+    </p>
+    
+  <dl><dt class="value">INFO</dt><dt class="value">WARNING</dt><dt class="value">ERROR</dt></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorType">AnalysisErrorType: String</a></dt><dd>
+    <p>
+      An enumeration of the possible types of analysis errors.
+    </p>
+    
+  <dl><dt class="value">CHECKED_MODE_COMPILE_TIME_ERROR</dt><dt class="value">COMPILE_TIME_ERROR</dt><dt class="value">HINT</dt><dt class="value">LINT</dt><dt class="value">STATIC_TYPE_WARNING</dt><dt class="value">STATIC_WARNING</dt><dt class="value">SYNTACTIC_ERROR</dt><dt class="value">TODO</dt></dl></dd><dt class="typeDefinition"><a name="type_AnalysisService">AnalysisService: String</a></dt><dd>
+    <p>
+      An enumeration of the services provided by the analysis domain that are
+      related to a specific list of files.
+    </p>
+    
+  <dl><dt class="value">FOLDING</dt><dt class="value">HIGHLIGHTS</dt><dt class="value">NAVIGATION</dt><dt class="value">OCCURRENCES</dt><dt class="value">OUTLINE</dt></dl></dd><dt class="typeDefinition"><a name="type_ChangeContentOverlay">ChangeContentOverlay: object</a></dt><dd>
+    <p>
+      A directive to modify an existing file content overlay. One or more ranges
+      of text are deleted from the old file content overlay and replaced with
+      new text.
+    </p>
+    <p>
+      The edits are applied in the order in which they occur in the list. This
+      means that the offset of each edit must be correct under the assumption
+      that all previous edits have been applied.
+    </p>
+    <p>
+      It is an error to use this overlay on a file that does not yet have a file
+      content overlay or that has had its overlay removed via
+      <a href="#type_RemoveContentOverlay">RemoveContentOverlay</a>.
+    </p>
+    <p>
+      If any of the edits cannot be applied due to its offset or length being
+      out of range, an <tt>INVALID_OVERLAY_CHANGE</tt> error will be reported.
+    </p>
+    
+  <dl><dt class="field"><b>type = "change"</b></dt><dd></dd><dt class="field"><b>edits (List&lt;<a href="#type_SourceEdit">SourceEdit</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The edits to be applied to the file.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_CompletionSuggestion">CompletionSuggestion: object</a></dt><dd>
+    <p>
+      A suggestion for how to complete partially entered text. Many of the
+      fields are optional, depending on the kind of element being suggested.
+    </p>
+    
+  <dl><dt class="field"><b>kind (<a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of element being suggested.
+        </p>
+      </dd><dt class="field"><b>relevance (int)</b></dt><dd>
+        
+        <p>
+          The relevance of this completion suggestion where a higher number
+          indicates a higher relevance.
+        </p>
+      </dd><dt class="field"><b>completion (String)</b></dt><dd>
+        
+        <p>
+          The identifier to be inserted if the suggestion is selected. If the
+          suggestion is for a method or function, the client might want to
+          additionally insert a template for the parameters. The information
+          required in order to do so is contained in other fields.
+        </p>
+      </dd><dt class="field"><b>selectionOffset (int)</b></dt><dd>
+        
+        <p>
+          The offset, relative to the beginning of the completion, of where the
+          selection should be placed after insertion.
+        </p>
+      </dd><dt class="field"><b>selectionLength (int)</b></dt><dd>
+        
+        <p>
+          The number of characters that should be selected after insertion.
+        </p>
+      </dd><dt class="field"><b>isDeprecated (bool)</b></dt><dd>
+        
+        <p>
+          True if the suggested element is deprecated.
+        </p>
+      </dd><dt class="field"><b>isPotential (bool)</b></dt><dd>
+        
+        <p>
+          True if the element is not known to be valid for the target. This
+          happens if the type of the target is dynamic.
+        </p>
+      </dd><dt class="field"><b>docSummary (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          An abbreviated version of the Dartdoc associated with the element
+          being suggested, This field is omitted if there is no Dartdoc
+          associated with the element.
+        </p>
+      </dd><dt class="field"><b>docComplete (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The Dartdoc associated with the element being suggested. This field is
+          omitted if there is no Dartdoc associated with the element.
+        </p>
+      </dd><dt class="field"><b>declaringType (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The class that declares the element being suggested. This field is
+          omitted if the suggested element is not a member of a class.
+        </p>
+      </dd><dt class="field"><b>element (<span style="color:#999999">optional</span> <a href="#type_Element">Element</a>)</b></dt><dd>
+        
+        <p>
+          Information about the element reference being suggested.
+        </p>
+      </dd><dt class="field"><b>returnType (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The return type of the getter, function or method or the type of the
+          field being suggested. This field is omitted if the suggested element
+          is not a getter, function or method.
+        </p>
+      </dd><dt class="field"><b>parameterNames (<span style="color:#999999">optional</span> List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The names of the parameters of the function or method being suggested.
+          This field is omitted if the suggested element is not a setter,
+          function or method.
+        </p>
+      </dd><dt class="field"><b>parameterTypes (<span style="color:#999999">optional</span> List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The types of the parameters of the function or method being suggested.
+          This field is omitted if the parameterNames field is omitted.
+        </p>
+      </dd><dt class="field"><b>requiredParameterCount (<span style="color:#999999">optional</span> int)</b></dt><dd>
+        
+        <p>
+          The number of required parameters for the function or method being
+          suggested. This field is omitted if the parameterNames field is
+          omitted.
+        </p>
+      </dd><dt class="field"><b>hasNamedParameters (<span style="color:#999999">optional</span> bool)</b></dt><dd>
+        
+        <p>
+          True if the function or method being suggested has at least one named
+          parameter. This field is omitted if the parameterNames field is
+          omitted.
+        </p>
+      </dd><dt class="field"><b>parameterName (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The name of the optional parameter being suggested. This field is
+          omitted if the suggestion is not the addition of an optional argument
+          within an argument list.
+        </p>
+      </dd><dt class="field"><b>parameterType (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The type of the options parameter being suggested. This field is
+          omitted if the parameterName field is omitted.
+        </p>
+      </dd><dt class="field"><b>importUri (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The import to be added if the suggestion is out of scope and needs
+          an import to be added to be in scope.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_CompletionSuggestionKind">CompletionSuggestionKind: String</a></dt><dd>
+    <p>
+      An enumeration of the kinds of elements that can be included in a
+      completion suggestion.
+    </p>
+    
+  <dl><dt class="value">ARGUMENT_LIST</dt><dd>
+        
+        <p>
+          A list of arguments for the method or function that is being
+          invoked. For this suggestion kind, the completion field is a
+          textual representation of the invocation and the parameterNames,
+          parameterTypes, and requiredParameterCount attributes are defined.
+        </p>
+      </dd><dt class="value">IMPORT</dt><dt class="value">IDENTIFIER</dt><dd>
+        
+        <p>
+          The element identifier should be inserted at the completion
+          location. For example "someMethod" in <tt>import 'myLib.dart' show
+          someMethod;</tt>. For suggestions of this kind, the element
+          attribute is defined and the completion field is the element's
+          identifier.
+        </p>
+      </dd><dt class="value">INVOCATION</dt><dd>
+        
+        <p>
+          The element is being invoked at the completion location. For
+          example, 'someMethod' in <tt>x.someMethod();</tt>. For suggestions
+          of this kind, the element attribute is defined and the completion
+          field is the element's identifier.
+        </p>
+      </dd><dt class="value">KEYWORD</dt><dd>
+        
+        <p>
+          A keyword is being suggested. For suggestions of this kind, the
+          completion is the keyword.
+        </p>
+      </dd><dt class="value">NAMED_ARGUMENT</dt><dd>
+        
+        <p>
+          A named argument for the current call site is being suggested. For
+          suggestions of this kind, the completion is the named argument
+          identifier including a trailing ':' and a space.
+        </p>
+      </dd><dt class="value">OPTIONAL_ARGUMENT</dt><dt class="value">PARAMETER</dt></dl></dd><dt class="typeDefinition"><a name="type_ContextBuilderOptions">ContextBuilderOptions: object</a></dt><dd>
+    <p>
+      The options used to build an analysis context.
+    </p>
+    
+  <dl><dt class="field"><b>dartSdkSummaryPath (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The file path of the file containing the summary of the SDK that
+          should be used to "analyze" the SDK. The field will be omitted if the
+          summary should be found in the SDK.
+        </p>
+      </dd><dt class="field"><b>defaultAnalysisOptionsFilePath (<span style="color:#999999">optional</span> List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The file path of the analysis options file that should be used in
+          place of any file in the root directory or a parent of the root
+          directory. The field will be omitted if the normal lookup mechanism
+          should be used.
+        </p>
+      </dd><dt class="field"><b>declaredVariables (<span style="color:#999999">optional</span> Map&lt;String, String&gt;)</b></dt><dd>
+        
+        <p>
+          A table mapping variable names to values for the declared variables.
+          The field will be omitted if no additional variables need to be
+          declared.
+        </p>
+      </dd><dt class="field"><b>defaultPackageFilePath (<span style="color:#999999">optional</span> List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The file path of the .packages file that should be used in place of
+          any file found using the normal (Package Specification DEP) lookup
+          mechanism. The field will be omitted if the normal lookup mechanism
+          should be used.
+        </p>
+      </dd><dt class="field"><b>defaultPackagesDirectoryPath (<span style="color:#999999">optional</span> List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The file path of the packages directory that should be used in place
+          of any file found using the normal (Package Specification DEP) lookup
+          mechanism. The field will be omitted if the normal lookup mechanism
+          should be used.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_ContextRoot">ContextRoot: object</a></dt><dd>
+    <p>
+      A description of an analysis context.
+    </p>
+    
+  <dl><dt class="field"><b>root (String)</b></dt><dd>
+        
+        <p>
+          The absolute path of the root directory containing the files to be
+          analyzed.
+        </p>
+      </dd><dt class="field"><b>exclude (List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          A list of the absolute paths of files and directories within the root
+          directory that should not be analyzed.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_Element">Element: object</a></dt><dd>
+    <p>
+      Information about an element (something that can be declared in code).
+    </p>
+    
+  <dl><dt class="field"><b>kind (<a href="#type_ElementKind">ElementKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of the element.
+        </p>
+      </dd><dt class="field"><b>name (String)</b></dt><dd>
+        
+        <p>
+          The name of the element. This is typically used as the label in the outline.
+        </p>
+      </dd><dt class="field"><b>location (<span style="color:#999999">optional</span> <a href="#type_Location">Location</a>)</b></dt><dd>
+        
+        <p>
+          The location of the name in the declaration of the element.
+        </p>
+      </dd><dt class="field"><b>flags (int)</b></dt><dd>
+        
+        <p>
+          A bit-map containing the following flags:
+        </p>
+        <ul>
+          <li>
+            0x01 - set if the element is explicitly or implicitly abstract
+          </li>
+          <li>
+            0x02 - set if the element was declared to be ‘const’
+          </li>
+          <li>
+            0x04 - set if the element was declared to be ‘final’
+          </li>
+          <li>
+            0x08 - set if the element is a static member of a class or is a
+            top-level function or field
+          </li>
+          <li>
+            0x10 - set if the element is private
+          </li>
+          <li>
+            0x20 - set if the element is deprecated
+          </li>
+        </ul>
+      </dd><dt class="field"><b>parameters (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The parameter list for the element. If the element is not a method or
+          function this field will not be defined. If the element doesn't have
+          parameters (e.g. getter), this field will not be defined. If the
+          element has zero parameters, this field will have a value of "()".
+        </p>
+      </dd><dt class="field"><b>returnType (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The return type of the element. If the element is not a method or
+          function this field will not be defined. If the element does not have
+          a declared return type, this field will contain an empty string.
+        </p>
+      </dd><dt class="field"><b>typeParameters (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The type parameter list for the element. If the element doesn't have
+          type parameters, this field will not be defined.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_ElementKind">ElementKind: String</a></dt><dd>
+    <p>
+      An enumeration of the kinds of elements.
+    </p>
+    
+  <dl><dt class="value">CLASS</dt><dt class="value">CLASS_TYPE_ALIAS</dt><dt class="value">COMPILATION_UNIT</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">FIELD</dt><dt class="value">FILE</dt><dt class="value">FUNCTION</dt><dt class="value">FUNCTION_TYPE_ALIAS</dt><dt class="value">GETTER</dt><dt class="value">LABEL</dt><dt class="value">LIBRARY</dt><dt class="value">LOCAL_VARIABLE</dt><dt class="value">METHOD</dt><dt class="value">PARAMETER</dt><dt class="value">PREFIX</dt><dt class="value">SETTER</dt><dt class="value">TOP_LEVEL_VARIABLE</dt><dt class="value">TYPE_PARAMETER</dt><dt class="value">UNKNOWN</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
+    
+    <p>
+      The absolute, normalized path of a file.
+    </p>
+    <p>
+      If the format of a file path in a request is not valid, e.g. the path is
+      not absolute or is not normalized, then an error of type
+      <tt>INVALID_FILE_PATH_FORMAT</tt> will be generated.
+    </p>
+  </dd><dt class="typeDefinition"><a name="type_FoldingKind">FoldingKind: String</a></dt><dd>
+    <p>
+      An enumeration of the kinds of folding regions.
+    </p>
+    
+  <dl><dt class="value">COMMENT</dt><dt class="value">CLASS_MEMBER</dt><dt class="value">DIRECTIVES</dt><dt class="value">DOCUMENTATION_COMMENT</dt><dt class="value">TOP_LEVEL_DECLARATION</dt></dl></dd><dt class="typeDefinition"><a name="type_FoldingRegion">FoldingRegion: object</a></dt><dd>
+    <p>
+      A description of a region that can be folded.
+    </p>
+    
+  <dl><dt class="field"><b>kind (<a href="#type_FoldingKind">FoldingKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of the region.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the region to be folded.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the region to be folded.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_HighlightRegion">HighlightRegion: object</a></dt><dd>
+    <p>
+      A description of a region that could have special highlighting associated
+      with it.
+    </p>
+    
+  <dl><dt class="field"><b>type (<a href="#type_HighlightRegionType">HighlightRegionType</a>)</b></dt><dd>
+        
+        <p>
+          The type of highlight associated with the region.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the region to be highlighted.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the region to be highlighted.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_HighlightRegionType">HighlightRegionType: String</a></dt><dd>
+    <p>
+      An enumeration of the kinds of highlighting that can be applied to files.
+    </p>
+    
+  <dl><dt class="value">ANNOTATION</dt><dt class="value">BUILT_IN</dt><dt class="value">CLASS</dt><dt class="value">COMMENT_BLOCK</dt><dt class="value">COMMENT_DOCUMENTATION</dt><dt class="value">COMMENT_END_OF_LINE</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">DIRECTIVE</dt><dt class="value">DYNAMIC_TYPE</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">DYNAMIC_LOCAL_VARIABLE_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">DYNAMIC_LOCAL_VARIABLE_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">DYNAMIC_PARAMETER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">DYNAMIC_PARAMETER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">FIELD</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">FIELD_STATIC</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">FUNCTION</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">FUNCTION_DECLARATION</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">FUNCTION_TYPE_ALIAS</dt><dt class="value">GETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">IDENTIFIER_DEFAULT</dt><dt class="value">IMPORT_PREFIX</dt><dt class="value">INSTANCE_FIELD_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_FIELD_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_GETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_GETTER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_METHOD_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_METHOD_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_SETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INSTANCE_SETTER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">INVALID_STRING_ESCAPE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">KEYWORD</dt><dt class="value">LABEL</dt><dt class="value">LIBRARY_NAME</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">LITERAL_BOOLEAN</dt><dt class="value">LITERAL_DOUBLE</dt><dt class="value">LITERAL_INTEGER</dt><dt class="value">LITERAL_LIST</dt><dt class="value">LITERAL_MAP</dt><dt class="value">LITERAL_STRING</dt><dt class="value">LOCAL_FUNCTION_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">LOCAL_FUNCTION_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">LOCAL_VARIABLE</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">LOCAL_VARIABLE_DECLARATION</dt><dt class="value">LOCAL_VARIABLE_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">METHOD</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">METHOD_DECLARATION</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">METHOD_DECLARATION_STATIC</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">METHOD_STATIC</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">PARAMETER</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">SETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_VARIABLE</dt><dd>
+        
+        <p>Only for version 1 of highlight.</p>
+      </dd><dt class="value">PARAMETER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">PARAMETER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_FIELD_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_GETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_GETTER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_METHOD_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_METHOD_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_SETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">STATIC_SETTER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_FUNCTION_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_FUNCTION_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_GETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_GETTER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_SETTER_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_SETTER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TOP_LEVEL_VARIABLE_DECLARATION</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">TYPE_NAME_DYNAMIC</dt><dt class="value">TYPE_PARAMETER</dt><dt class="value">UNRESOLVED_INSTANCE_MEMBER_REFERENCE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd><dt class="value">VALID_STRING_ESCAPE</dt><dd>
+        
+        <p>Only for version 2 of highlight.</p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_LinkedEditGroup">LinkedEditGroup: object</a></dt><dd>
+    <p>
+      A collection of positions that should be linked (edited simultaneously)
+      for the purposes of updating code after a source change. For example, if a
+      set of edits introduced a new variable name, the group would contain all
+      of the positions of the variable name so that if the client wanted to let
+      the user edit the variable name after the operation, all occurrences of
+      the name could be edited simultaneously.
+    </p>
+    
+  <dl><dt class="field"><b>positions (List&lt;<a href="#type_Position">Position</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The positions of the regions that should be edited simultaneously.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the regions that should be edited simultaneously.
+        </p>
+      </dd><dt class="field"><b>suggestions (List&lt;<a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a>&gt;)</b></dt><dd>
+        
+        <p>
+          Pre-computed suggestions for what every region might want to be
+          changed to.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_LinkedEditSuggestion">LinkedEditSuggestion: object</a></dt><dd>
+    <p>
+      A suggestion of a value that could be used to replace all of the linked
+      edit regions in a <a href="#type_LinkedEditGroup">LinkedEditGroup</a>.
+    </p>
+    
+  <dl><dt class="field"><b>value (String)</b></dt><dd>
+        
+        <p>
+          The value that could be used to replace all of the linked edit
+          regions.
+        </p>
+      </dd><dt class="field"><b>kind (<a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of value being proposed.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_LinkedEditSuggestionKind">LinkedEditSuggestionKind: String</a></dt><dd>
+    <p>
+      An enumeration of the kind of values that can be suggested for a linked
+      edit.
+    </p>
+    
+  <dl><dt class="value">METHOD</dt><dt class="value">PARAMETER</dt><dt class="value">TYPE</dt><dt class="value">VARIABLE</dt></dl></dd><dt class="typeDefinition"><a name="type_Location">Location: object</a></dt><dd>
+    <p>
+      A location (character range) within a file.
+    </p>
+    
+  <dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the range.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the range.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the range.
+        </p>
+      </dd><dt class="field"><b>startLine (int)</b></dt><dd>
+        
+        <p>
+          The one-based index of the line containing the first character of the
+          range.
+        </p>
+      </dd><dt class="field"><b>startColumn (int)</b></dt><dd>
+        
+        <p>
+          The one-based index of the column containing the first character of
+          the range.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_NavigationRegion">NavigationRegion: object</a></dt><dd>
+    <p>
+      A description of a region from which the user can navigate to the
+      declaration of an element.
+    </p>
+    
+  <dl><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the region from which the user can navigate.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the region from which the user can navigate.
+        </p>
+      </dd><dt class="field"><b>targets (List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The indexes of the targets (in the enclosing navigation response) to
+          which the given region is bound. By opening the target, clients can
+          implement one form of navigation. This list cannot be empty.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_NavigationTarget">NavigationTarget: object</a></dt><dd>
+    <p>
+      A description of a target to which the user can navigate.
+    </p>
+    
+  <dl><dt class="field"><b>kind (<a href="#type_ElementKind">ElementKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of the element.
+        </p>
+      </dd><dt class="field"><b>fileIndex (int)</b></dt><dd>
+        
+        <p>
+          The index of the file (in the enclosing navigation response) to
+          navigate to.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the region to which the user can navigate.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the region to which the user can navigate.
+        </p>
+      </dd><dt class="field"><b>startLine (int)</b></dt><dd>
+        
+        <p>
+          The one-based index of the line containing the first character of the
+          region.
+        </p>
+      </dd><dt class="field"><b>startColumn (int)</b></dt><dd>
+        
+        <p>
+          The one-based index of the column containing the first character of
+          the region.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_Occurrences">Occurrences: object</a></dt><dd>
+    <p>
+      A description of the references to a single element within a single file.
+    </p>
+    
+  <dl><dt class="field"><b>element (<a href="#type_Element">Element</a>)</b></dt><dd>
+        
+        <p>
+          The element that was referenced.
+        </p>
+      </dd><dt class="field"><b>offsets (List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The offsets of the name of the referenced element within the file.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the name of the referenced element.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_Outline">Outline: object</a></dt><dd>
+    <p>
+      An node in the outline structure of a file.
+    </p>
+    
+  <dl><dt class="field"><b>element (<a href="#type_Element">Element</a>)</b></dt><dd>
+        
+        <p>
+          A description of the element represented by this node.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the first character of the element. This is different
+          than the offset in the Element, which is the offset of the name of the
+          element. It can be used, for example, to map locations in the file
+          back to an outline.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the element.
+        </p>
+      </dd><dt class="field"><b>children (<span style="color:#999999">optional</span> List&lt;<a href="#type_Outline">Outline</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The children of the node. The field will be omitted if the node has no
+          children.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_Position">Position: object</a></dt><dd>
+    <p>
+      A position within a file.
+    </p>
+    
+  <dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the position.
+        </p>
+      </dd><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the position.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_PrioritizedSourceChange">PrioritizedSourceChange: object</a></dt><dd>
+    <p>
+      A source change that has a priority associated with it.
+    </p>
+    
+  <dl><dt class="field"><b>priority (int)</b></dt><dd>
+        
+        <p>
+          The priority of the change. The value is expected to be non-negative,
+          and zero (0) is the lowest priority.
+        </p>
+      </dd><dt class="field"><b>change (<a href="#type_SourceChange">SourceChange</a>)</b></dt><dd>
+        
+        <p>
+          The change with which the relevance is associated.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_RefactoringFeedback">RefactoringFeedback: object</a></dt><dd>
+    <p>
+      An abstract superclass of all refactoring feedbacks.
+    </p>
+    
+  <dl></dl></dd><dt class="typeDefinition"><a name="type_RefactoringKind">RefactoringKind: String</a></dt><dd>
+    <p>
+      An enumeration of the kinds of refactorings that can be created.
+    </p>
+    
+  <dl><dt class="value">CONVERT_GETTER_TO_METHOD</dt><dt class="value">CONVERT_METHOD_TO_GETTER</dt><dt class="value">EXTRACT_LOCAL_VARIABLE</dt><dt class="value">EXTRACT_METHOD</dt><dt class="value">INLINE_LOCAL_VARIABLE</dt><dt class="value">INLINE_METHOD</dt><dt class="value">MOVE_FILE</dt><dt class="value">RENAME</dt><dt class="value">SORT_MEMBERS</dt></dl></dd><dt class="typeDefinition"><a name="type_RefactoringMethodParameter">RefactoringMethodParameter: object</a></dt><dd>
+    
+    <p>
+      A description of a parameter in a method refactoring.
+    </p>
+    
+  <dl><dt class="field"><b>id (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The unique identifier of the parameter. Clients may omit this field
+          for the parameters they want to add.
+        </p>
+      </dd><dt class="field"><b>kind (<a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a>)</b></dt><dd>
+        
+        <p>
+          The kind of the parameter.
+        </p>
+      </dd><dt class="field"><b>type (String)</b></dt><dd>
+        
+        <p>
+          The type that should be given to the parameter, or the return type of
+          the parameter's function type.
+        </p>
+      </dd><dt class="field"><b>name (String)</b></dt><dd>
+        
+        <p>
+          The name that should be given to the parameter.
+        </p>
+      </dd><dt class="field"><b>parameters (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The parameter list of the parameter's function type. If the parameter
+          is not of a function type, this field will not be defined. If the
+          function type has zero parameters, this field will have a value of
+          '()'.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_RefactoringOptions">RefactoringOptions: object</a></dt><dd>
+    <p>
+      An abstract superclass of all refactoring options.
+    </p>
+    
+  <dl></dl></dd><dt class="typeDefinition"><a name="type_RefactoringMethodParameterKind">RefactoringMethodParameterKind: String</a></dt><dd>
+    <p>
+      An enumeration of the kinds of parameters.
+    </p>
+    
+  <dl><dt class="value">REQUIRED</dt><dt class="value">POSITIONAL</dt><dt class="value">NAMED</dt></dl></dd><dt class="typeDefinition"><a name="type_RefactoringProblem">RefactoringProblem: object</a></dt><dd>
+    <p>
+      A description of a problem related to a refactoring.
+    </p>
+    
+  <dl><dt class="field"><b>severity (<a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a>)</b></dt><dd>
+        
+        <p>
+          The severity of the problem being represented.
+        </p>
+      </dd><dt class="field"><b>message (String)</b></dt><dd>
+        
+        <p>
+          A human-readable description of the problem being represented.
+        </p>
+      </dd><dt class="field"><b>location (<span style="color:#999999">optional</span> <a href="#type_Location">Location</a>)</b></dt><dd>
+        
+        <p>
+          The location of the problem being represented. This field is omitted
+          unless there is a specific location associated with the problem (such
+          as a location where an element being renamed will be shadowed).
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_RefactoringProblemSeverity">RefactoringProblemSeverity: String</a></dt><dd>
+    <p>
+      An enumeration of the severities of problems that can be returned by the
+      refactoring requests.
+    </p>
+    
+  <dl><dt class="value">INFO</dt><dd>
+        
+        <p>
+          A minor code problem. No example, because it is not used yet.
+        </p>
+      </dd><dt class="value">WARNING</dt><dd>
+        
+        <p>
+          A minor code problem. For example names of local variables should be
+          camel case and start with a lower case letter. Staring the name of a
+          variable with an upper case is OK from the language point of view, but
+          it is nice to warn the user.
+        </p>
+      </dd><dt class="value">ERROR</dt><dd>
+        
+        <p>
+          The refactoring technically can be performed, but there is a logical
+          problem. For example the name of a local variable being extracted
+          conflicts with another name in the scope, or duplicate parameter names
+          in the method being extracted, or a conflict between a parameter name
+          and a local variable, etc. In some cases the location of the problem
+          is also provided, so the IDE can show user the location and the
+          problem, and let the user decide whether they want to perform the
+          refactoring. For example the name conflict might be expected, and the
+          user wants to fix it afterwards.
+        </p>
+      </dd><dt class="value">FATAL</dt><dd>
+        
+        <p>
+          A fatal error, which prevents performing the refactoring. For example
+          the name of a local variable being extracted is not a valid
+          identifier, or selection is not a valid expression.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_RemoveContentOverlay">RemoveContentOverlay: object</a></dt><dd>
+    <p>
+      A directive to remove an existing file content overlay. After processing
+      this directive, the file contents will once again be read from the file
+      system.
+    </p>
+    <p>
+      If this directive is used on a file that doesn't currently have a content
+      overlay, it has no effect.
+    </p>
+    
+  <dl><dt class="field"><b>type = "remove"</b></dt><dd></dd></dl></dd><dt class="typeDefinition"><a name="type_RequestError">RequestError: object</a></dt><dd>
+    <p>
+      An indication of a problem with the execution of the server,
+      typically in response to a request.
+    </p>
+    
+  <dl><dt class="field"><b>code (<a href="#type_RequestErrorCode">RequestErrorCode</a>)</b></dt><dd>
+        
+        <p>
+          A code that uniquely identifies the error that occurred.
+        </p>
+      </dd><dt class="field"><b>message (String)</b></dt><dd>
+        
+        <p>
+          A short description of the error.
+        </p>
+      </dd><dt class="field"><b>stackTrace (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The stack trace associated with processing the request, used for
+          debugging the plugin.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_RequestErrorCode">RequestErrorCode: String</a></dt><dd>
+    <p>
+      An enumeration of the types of errors that can occur in the execution of
+      the plugin.
+    </p>
+    
+  <dl><dt class="value">INVALID_OVERLAY_CHANGE</dt><dd>
+        
+        <p>
+          An "analysis.updateContent" request contained a
+          <a href="#type_ChangeContentOverlay">ChangeContentOverlay</a> object
+          that can't be applied. This can happen for two reasons:
+        </p>
+        <ul>
+          <li>
+            there was no preceding
+            <a href="#type_AddContentOverlay">AddContentOverlay</a> and hence no
+            content to which the edits could be applied, or
+          </li>
+          <li>
+            one or more of the specified edits have an offset or length that is
+            out of range.
+          </li>
+        </ul>
+      </dd><dt class="value">INVALID_PARAMETER</dt><dd>
+        
+        <p>
+          One of the method parameters was invalid.
+        </p>
+      </dd><dt class="value">PLUGIN_ERROR</dt><dd>
+        
+        <p>
+          An internal error occurred in the plugin while attempting to respond
+          to a request. Also see the plugin.error notification for errors that
+          occur outside of handling a request.
+        </p>
+      </dd><dt class="value">UNKNOWN_REQUEST</dt><dd>
+        
+        <p>
+          A request was received that the plugin does not recognize, or cannot
+          handle in its current configuration.
+        </p>
+      </dd></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>
+    
+  <dl><dt class="field"><b>message (String)</b></dt><dd>
+        
+        <p>
+          A human-readable description of the change to be applied.
+        </p>
+      </dd><dt class="field"><b>edits (List&lt;<a href="#type_SourceFileEdit">SourceFileEdit</a>&gt;)</b></dt><dd>
+        
+        <p>
+          A list of the edits used to effect the change, grouped by file.
+        </p>
+      </dd><dt class="field"><b>linkedEditGroups (List&lt;<a href="#type_LinkedEditGroup">LinkedEditGroup</a>&gt;)</b></dt><dd>
+        
+        <p>
+          A list of the linked editing groups used to customize the changes that
+          were made.
+        </p>
+      </dd><dt class="field"><b>selection (<span style="color:#999999">optional</span> <a href="#type_Position">Position</a>)</b></dt><dd>
+        
+        <p>
+          The position that should be selected after the edits have been
+          applied.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_SourceEdit">SourceEdit: object</a></dt><dd>
+    <p>
+      A description of a single change to a single file.
+    </p>
+    
+  <dl><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset of the region to be modified.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the region to be modified.
+        </p>
+      </dd><dt class="field"><b>replacement (String)</b></dt><dd>
+        
+        <p>
+          The code that is to replace the specified region in the original code.
+        </p>
+      </dd><dt class="field"><b>id (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          An identifier that uniquely identifies this source edit from other
+          edits in the same response. This field is omitted unless a containing
+          structure needs to be able to identify the edit for some reason.
+        </p>
+        <p>
+          For example, some refactoring operations can produce edits that might
+          not be appropriate (referred to as potential edits). Such edits will
+          have an id so that they can be referenced. Edits in the same response
+          that do not need to be referenced will not have an id.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_SourceFileEdit">SourceFileEdit: object</a></dt><dd>
+    <p>
+      A description of a set of changes to a single file.
+    </p>
+    
+  <dl><dt class="field"><b>file (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The file containing the code to be modified.
+        </p>
+      </dd><dt class="field"><b>fileStamp (long)</b></dt><dd>
+        
+        <p>
+          The modification stamp of the file at the moment when the change was
+          created, in milliseconds since the "Unix epoch". Will be -1 if the
+          file did not exist and should be created. The client may use this
+          field to make sure that the file was not changed since then, so it is
+          safe to apply the change.
+        </p>
+      </dd><dt class="field"><b>edits (List&lt;<a href="#type_SourceEdit">SourceEdit</a>&gt;)</b></dt><dd>
+        
+        <p>
+          A list of the edits used to effect the change.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_WatchEvent">WatchEvent: object</a></dt><dd>
+    <p>
+      A watch event sent by the server when the file system has been modified.
+    </p>
+    
+  <dl><dt class="field"><b>type (<a href="#type_WatchEventType">WatchEventType</a>)</b></dt><dd>
+        
+        <p>
+          The type of change represented by this event.
+        </p>
+      </dd><dt class="field"><b>path (String)</b></dt><dd>
+        
+        <p>
+          The absolute path of the file or directory that changed.
+        </p>
+      </dd></dl></dd><dt class="typeDefinition"><a name="type_WatchEventType">WatchEventType: String</a></dt><dd>
+    <p>
+      An indication of the type of change associated with a watch event.
+    </p>
+    
+  <dl><dt class="value">ADD</dt><dd>
+        
+        <p>
+          An indication that the file or directory was added.
+        </p>
+      </dd><dt class="value">MODIFY</dt><dd>
+        
+        <p>
+          An indication that the file was modified.
+        </p>
+      </dd><dt class="value">REMOVE</dt><dd>
+        
+        <p>
+          An indication that the file or directory was removed.
+        </p>
+      </dd></dl></dd></dl>
+
+  <h2><a name="refactorings">Refactorings</a></h2>
+  <p>
+    This section contains additional information for each kind of refactoring.
+    In addition to a brief description of the refactoring, there is a
+    specification of the feedback that is provided when a refactoring is
+    requested using the
+    <a href="request_edit.getRefactoring">edit.getRefactoring</a> request
+    (designed to improve the UX) and the options that may be provided to
+    <a href="request_edit.getRefactoring">edit.getRefactoring</a>.
+  </p>
+  
+  
+  
+  
+  
+  
+  
+  
+<dl><dt class="refactoring">CONVERT_GETTER_TO_METHOD</dt><dd>
+    <p>
+      Convert a getter into a method by removing the keyword get and adding an
+      empty parameter list.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single getter.
+    </p>
+  <h4>Feedback:</h4><p>none</p><h4>Options:</h4><p>none</p></dd><dt class="refactoring">CONVERT_METHOD_TO_GETTER</dt><dd>
+    <p>
+      Convert a method into a getter by adding the keyword get and removing the
+      parameter list.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single method or if the method has a non-empty parameter
+      list.
+    </p>
+  <h4>Feedback:</h4><p>none</p><h4>Options:</h4><p>none</p></dd><dt class="refactoring">EXTRACT_LOCAL_VARIABLE</dt><dd>
+    <p>
+      Create a local variable initialized by the expression that covers the
+      specified selection.
+    </p>
+    <p>
+      It is an error if the selection range is not covered by a complete
+      expression.
+    </p>
+    
+    
+  <h4>Feedback:</h4><dl><dt class="field"><b>coveringExpressionOffsets (<span style="color:#999999">optional</span> List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The offsets of the expressions that cover the specified selection,
+          from the down most to the up most.
+        </p>
+      </dd><dt class="field"><b>coveringExpressionLengths (<span style="color:#999999">optional</span> List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The lengths of the expressions that cover the specified selection,
+          from the down most to the up most.
+        </p>
+      </dd><dt class="field"><b>names (List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The proposed names for the local variable.
+        </p>
+      </dd><dt class="field"><b>offsets (List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The offsets of the expressions that would be replaced by a reference
+          to the variable.
+        </p>
+      </dd><dt class="field"><b>lengths (List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The lengths of the expressions that would be replaced by a reference
+          to the variable. The lengths correspond to the offsets. In other
+          words, for a given expression, if the offset of that expression is
+          offsets[i], then the length of that expression is lengths[i].
+        </p>
+      </dd></dl><h4>Options:</h4><dl><dt class="field"><b>name (String)</b></dt><dd>
+        
+        <p>
+          The name that the local variable should be given.
+        </p>
+      </dd><dt class="field"><b>extractAll (bool)</b></dt><dd>
+        
+        <p>
+          True if all occurrences of the expression within the scope in which
+          the variable will be defined should be replaced by a reference to the
+          local variable. The expression used to initiate the refactoring will
+          always be replaced.
+        </p>
+      </dd></dl></dd><dt class="refactoring">EXTRACT_METHOD</dt><dd>
+    <p>
+      Create a method whose body is the specified expression or list of
+      statements, possibly augmented with a return statement.
+    </p>
+    <p>
+      It is an error if the range contains anything other than a complete
+      expression (no partial expressions are allowed) or a complete sequence of
+      statements.
+    </p>
+    
+    
+  <h4>Feedback:</h4><dl><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset to the beginning of the expression or statements that will
+          be extracted.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the expression or statements that will be extracted.
+        </p>
+      </dd><dt class="field"><b>returnType (String)</b></dt><dd>
+        
+        <p>
+          The proposed return type for the method. If the returned element does
+          not have a declared return type, this field will contain an empty
+          string.
+        </p>
+      </dd><dt class="field"><b>names (List&lt;String&gt;)</b></dt><dd>
+        
+        <p>
+          The proposed names for the method.
+        </p>
+      </dd><dt class="field"><b>canCreateGetter (bool)</b></dt><dd>
+        
+        <p>
+          True if a getter could be created rather than a method.
+        </p>
+      </dd><dt class="field"><b>parameters (List&lt;<a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The proposed parameters for the method.
+        </p>
+      </dd><dt class="field"><b>offsets (List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The offsets of the expressions or statements that would be replaced by
+          an invocation of the method.
+        </p>
+      </dd><dt class="field"><b>lengths (List&lt;int&gt;)</b></dt><dd>
+        
+        <p>
+          The lengths of the expressions or statements that would be replaced by
+          an invocation of the method. The lengths correspond to the offsets. In
+          other words, for a given expression (or block of statements), if the
+          offset of that expression is offsets[i], then the length of that
+          expression is lengths[i].
+        </p>
+      </dd></dl><h4>Options:</h4><dl><dt class="field"><b>returnType (String)</b></dt><dd>
+        
+        <p>
+          The return type that should be defined for the method.
+        </p>
+      </dd><dt class="field"><b>createGetter (bool)</b></dt><dd>
+        
+        <p>
+          True if a getter should be created rather than a method. It is an
+          error if this field is true and the list of parameters is non-empty.
+        </p>
+      </dd><dt class="field"><b>name (String)</b></dt><dd>
+        
+        <p>
+          The name that the method should be given.
+        </p>
+      </dd><dt class="field"><b>parameters (List&lt;<a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a>&gt;)</b></dt><dd>
+        
+        <p>
+          The parameters that should be defined for the method.
+        </p>
+        <p>
+          It is an error if a REQUIRED or NAMED parameter follows a POSITIONAL
+          parameter. It is an error if a REQUIRED or POSITIONAL parameter
+          follows a NAMED parameter.
+        </p>
+        <ul>
+          <li>
+            To change the order and/or update proposed parameters, add
+            parameters with the same identifiers as proposed.
+          </li>
+          <li>
+            To add new parameters, omit their identifier.
+          </li>
+          <li>
+            To remove some parameters, omit them in this list.
+          </li>
+        </ul>
+      </dd><dt class="field"><b>extractAll (bool)</b></dt><dd>
+        
+        <p>
+          True if all occurrences of the expression or statements should be
+          replaced by an invocation of the method. The expression or statements
+          used to initiate the refactoring will always be replaced.
+        </p>
+      </dd></dl></dd><dt class="refactoring">INLINE_LOCAL_VARIABLE</dt><dd>
+    <p>
+      Inline the initializer expression of a local variable in place of any
+      references to that variable.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single local variable.
+    </p>
+    
+  <h4>Feedback:</h4><dl><dt class="field"><b>name (String)</b></dt><dd>
+        
+        <p>
+          The name of the variable being inlined.
+        </p>
+      </dd><dt class="field"><b>occurrences (int)</b></dt><dd>
+        
+        <p>
+          The number of times the variable occurs.
+        </p>
+      </dd></dl><h4>Options:</h4><p>none</p></dd><dt class="refactoring">INLINE_METHOD</dt><dd>
+    <p>
+      Inline a method in place of one or all references to that method.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single method.
+    </p>
+    
+    
+  <h4>Feedback:</h4><dl><dt class="field"><b>className (<span style="color:#999999">optional</span> String)</b></dt><dd>
+        
+        <p>
+          The name of the class enclosing the method being inlined. If not a
+          class member is being inlined, this field will be absent.
+        </p>
+      </dd><dt class="field"><b>methodName (String)</b></dt><dd>
+        
+        <p>
+          The name of the method (or function) being inlined.
+        </p>
+      </dd><dt class="field"><b>isDeclaration (bool)</b></dt><dd>
+        
+        <p>
+          True if the declaration of the method is selected and all references
+          should be inlined.
+        </p>
+      </dd></dl><h4>Options:</h4><dl><dt class="field"><b>deleteSource (bool)</b></dt><dd>
+        
+        <p>
+          True if the method being inlined should be removed. It is an error if
+          this field is true and inlineAll is false.
+        </p>
+      </dd><dt class="field"><b>inlineAll (bool)</b></dt><dd>
+        
+        <p>
+          True if all invocations of the method should be inlined, or false if
+          only the invocation site used to create this refactoring should be
+          inlined.
+        </p>
+      </dd></dl></dd><dt class="refactoring">MOVE_FILE</dt><dd>
+    <p>
+      Move the given file and update all of the references to that file and from
+      it. The move operation is supported in general case - for renaming a file
+      in the same folder, moving it to a different folder or both.
+    </p>
+    <p>
+      The refactoring must be activated before an actual file moving operation
+      is performed.
+    </p>
+    <p>
+      The "offset" and "length" fields from the request are ignored, but the
+      file specified in the request specifies the file to be moved.
+    </p>
+    
+  <h4>Feedback:</h4><p>none</p><h4>Options:</h4><dl><dt class="field"><b>newFile (<a href="#type_FilePath">FilePath</a>)</b></dt><dd>
+        
+        <p>
+          The new file path to which the given file is being moved.
+        </p>
+      </dd></dl></dd><dt class="refactoring">RENAME</dt><dd>
+    <p>
+      Rename a given element and all of the references to that element.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single function (including methods, getters and setters),
+      variable (including fields, parameters and local variables), class or
+      function type.
+    </p>
+    
+    
+  <h4>Feedback:</h4><dl><dt class="field"><b>offset (int)</b></dt><dd>
+        
+        <p>
+          The offset to the beginning of the name selected to be renamed.
+        </p>
+      </dd><dt class="field"><b>length (int)</b></dt><dd>
+        
+        <p>
+          The length of the name selected to be renamed.
+        </p>
+      </dd><dt class="field"><b>elementKindName (String)</b></dt><dd>
+        
+        <p>
+          The human-readable description of the kind of element being renamed
+          (such as “class” or “function type alias”).
+        </p>
+      </dd><dt class="field"><b>oldName (String)</b></dt><dd>
+        
+        <p>
+          The old name of the element before the refactoring.
+        </p>
+      </dd></dl><h4>Options:</h4><dl><dt class="field"><b>newName (String)</b></dt><dd>
+        
+        <p>
+          The name that the element should have after the refactoring.
+        </p>
+      </dd></dl></dd></dl>
+<h2 class="domain"><a name="index">Index</a></h2>
+<h3>Domains</h3><h4>plugin (<a href="#domain_plugin">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_plugin.versionCheck">versionCheck</a></li><li><a href="#request_plugin.shutdown">shutdown</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_plugin.error">error</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.handleWatchEvents">handleWatchEvents</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setContextBuilderOptions">setContextBuilderOptions</a></li><li><a href="#request_analysis.setContextRoots">setContextRoots</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></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.errors">errors</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.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</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></ul></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><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.getRefactoring">getRefactoring</a></li></ul></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_AnalysisService">AnalysisService</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextBuilderOptions">ContextBuilderOptions</a></li><li><a href="#type_ContextRoot">ContextRoot</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</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_Position">Position</a></li><li><a href="#type_PrioritizedSourceChange">PrioritizedSourceChange</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_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</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_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_WatchEvent">WatchEvent</a></li><li><a href="#type_WatchEventType">WatchEventType</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_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/analyzer_plugin/lib/channel/channel.dart b/pkg/analyzer_plugin/lib/channel/channel.dart
new file mode 100644
index 0000000..cf4730d
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/channel/channel.dart
@@ -0,0 +1,69 @@
+// 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:analyzer_plugin/protocol/protocol.dart';
+
+/**
+ * A communication channel that allows a [ServerPlugin] to receive [Request]s
+ * from, and to return both [Response]s and [Notification]s to, an analysis
+ * server.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PluginCommunicationChannel {
+  /**
+   * Close the communication channel.
+   */
+  void close();
+
+  /**
+   * Listen to the channel for requests. If a request is received, invoke the
+   * [onRequest] function. If an error is encountered while trying to read from
+   * the socket, invoke the [onError] function. If the socket is closed by the
+   * client, invoke the [onDone] function. Only one listener is allowed per
+   * channel.
+   */
+  void listen(void onRequest(Request request),
+      {Function onError, void onDone()});
+
+  /**
+   * Send the given [notification] to the server.
+   */
+  void sendNotification(Notification notification);
+
+  /**
+   * Send the given [response] to the server.
+   */
+  void sendResponse(Response response);
+}
+
+/**
+ * A communication channel that allows an analysis server to send [Request]s
+ * to, and to receive both [Response]s and [Notification]s from, a plugin.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ServerCommunicationChannel {
+  /**
+   * Close the communication channel.
+   */
+  void close();
+
+  /**
+   * Listen to the channel for responses and notifications. If a response is
+   * received, invoke the [onResponse] function. If a notification is received,
+   * invoke the [onNotification] function. If an error is encountered while
+   * trying to read from the socket, invoke the [onError] function. If the
+   * socket is closed by the plugin, invoke the [onDone] function. Only one
+   * listener is allowed per channel.
+   */
+  void listen(void onResponse(Response response),
+      void onNotification(Notification notification),
+      {Function onError, void onDone()});
+
+  /**
+   * Send the given [request] to the plugin.
+   */
+  void sendRequest(Request request);
+}
diff --git a/pkg/analyzer_plugin/lib/plugin/plugin.dart b/pkg/analyzer_plugin/lib/plugin/plugin.dart
new file mode 100644
index 0000000..f24f6b8
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/plugin/plugin.dart
@@ -0,0 +1,405 @@
+// 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:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart'
+    show AnalysisDriverScheduler, PerformanceLog;
+import 'package:analyzer/src/dart/analysis/file_byte_store.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_plugin/channel/channel.dart';
+import 'package:analyzer_plugin/protocol/protocol.dart';
+import 'package:analyzer_plugin/protocol/protocol_constants.dart';
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+import 'package:analyzer_plugin/src/utilities/null_string_sink.dart';
+import 'package:analyzer_plugin/utilities/subscription_manager.dart';
+import 'package:pub_semver/pub_semver.dart';
+
+/**
+ * The abstract superclass of any class implementing a plugin for the analysis
+ * server.
+ *
+ * Clients may not implement or mix-in this class, but are expected to extend
+ * it.
+ */
+abstract class ServerPlugin {
+  /**
+   * A megabyte.
+   */
+  static const int M = 1024 * 1024;
+
+  /**
+   * The communication channel being used to communicate with the analysis
+   * server.
+   */
+  PluginCommunicationChannel _channel;
+
+  /**
+   * The resource provider used to access the file system.
+   */
+  final ResourceProvider resourceProvider;
+
+  /**
+   * The object used to manage analysis subscriptions.
+   */
+  final SubscriptionManager subscriptionManager = new SubscriptionManager();
+
+  /**
+   * The scheduler used by any analysis drivers that are created.
+   */
+  AnalysisDriverScheduler analysisDriverScheduler;
+
+  /**
+   * The performance log used by any analysis drivers that are created.
+   */
+  final PerformanceLog performanceLog =
+      new PerformanceLog(new NullStringSink());
+
+  /**
+   * The byte store used by any analysis drivers that are created, or `null` if
+   * the cache location isn't known because the 'plugin.version' request has not
+   * yet been received.
+   */
+  ByteStore _byteStore;
+
+  /**
+   * The file content overlay used by any analysis drivers that are created.
+   */
+  final FileContentOverlay fileContentOverlay = new FileContentOverlay();
+
+  /**
+   * Initialize a newly created analysis server plugin. If a resource [provider]
+   * is given, then it will be used to access the file system. Otherwise a
+   * resource provider that accesses the physical file system will be used.
+   */
+  ServerPlugin(this.resourceProvider) {
+    analysisDriverScheduler = new AnalysisDriverScheduler(performanceLog);
+  }
+
+  /**
+   * Return the communication channel being used to communicate with the
+   * analysis server, or `null` if the plugin has not been started.
+   */
+  PluginCommunicationChannel get channel => _channel;
+
+  /**
+   * Return the user visible information about how to contact the plugin authors
+   * with any problems that are found, or `null` if there is no contact info.
+   */
+  String get contactInfo => null;
+
+  /**
+   * Return a list of glob patterns selecting the files that this plugin is
+   * interested in analyzing.
+   */
+  List<String> get fileGlobsToAnalyze;
+
+  /**
+   * Return the user visible name of this plugin.
+   */
+  String get name;
+
+  /**
+   * Return the version number of this plugin, encoded as a string.
+   */
+  String get version;
+
+  /**
+   * Handle the fact that the file with the given [path] has been modified.
+   */
+  void contentChanged(String path) {
+    // Ignore changes to files.
+  }
+
+  /**
+   * Handle an 'analysis.handleWatchEvents' request.
+   */
+  AnalysisHandleWatchEventsResult handleAnalysisHandleWatchEvents(
+          Map<String, Object> parameters) =>
+      null;
+
+  /**
+   * Handle an 'analysis.reanalyze' request.
+   */
+  AnalysisReanalyzeResult handleAnalysisReanalyze(
+          Map<String, Object> parameters) =>
+      null;
+
+  /**
+   * Handle an 'analysis.setContextBuilderOptions' request.
+   */
+  AnalysisSetContextBuilderOptionsResult handleAnalysisSetContextBuilderOptions(
+          Map<String, Object> parameters) =>
+      null;
+
+  /**
+   * Handle an 'analysis.setContextRoots' request.
+   */
+  AnalysisSetContextRootsResult handleAnalysisSetContextRoots(
+      Map<String, Object> parameters) {
+    // TODO(brianwilkerson) Implement this so that implementors don't have to
+    // figure out how to manage contexts.
+    return null;
+  }
+
+  /**
+   * Handle an 'analysis.setPriorityFiles' request.
+   */
+  AnalysisSetPriorityFilesResult handleAnalysisSetPriorityFiles(
+          Map<String, Object> parameters) =>
+      new AnalysisSetPriorityFilesResult();
+
+  /**
+   * Handle an 'analysis.setSubscriptions' request. Most subclasses should not
+   * override this method, but should instead use the [subscriptionManager] to
+   * access the list of subscriptions for any given file.
+   */
+  AnalysisSetSubscriptionsResult handleAnalysisSetSubscriptions(
+      Map<String, Object> parameters) {
+    Map<AnalysisService, List<String>> subscriptions = validateParameter(
+        parameters,
+        ANALYSIS_REQUEST_SET_SUBSCRIPTIONS_SUBSCRIPTIONS,
+        'analysis.setSubscriptions');
+    subscriptionManager.setSubscriptions(subscriptions);
+    // TODO(brianwilkerson) Cause any newly subscribed for notifications to be sent.
+    return new AnalysisSetSubscriptionsResult();
+  }
+
+  /**
+   * Handle an 'analysis.updateContent' request. Most subclasses should not
+   * override this method, but should instead use the [contentCache] to access
+   * the current content of overlaid files.
+   */
+  AnalysisUpdateContentResult handleAnalysisUpdateContent(
+      Map<String, Object> parameters) {
+    Map<String, Object> files = validateParameter(parameters,
+        ANALYSIS_REQUEST_UPDATE_CONTENT_FILES, 'analysis.updateContent');
+    files.forEach((String filePath, Object overlay) {
+      // We don't need to get the correct URI because only the full path is
+      // used by the contentCache.
+      Source source = resourceProvider.getFile(filePath).createSource();
+      if (overlay is AddContentOverlay) {
+        fileContentOverlay[source.fullName] = overlay.content;
+      } else if (overlay is ChangeContentOverlay) {
+        String fileName = source.fullName;
+        String oldContents = fileContentOverlay[fileName];
+        String newContents;
+        if (oldContents == null) {
+          // The server should only send a ChangeContentOverlay if there is
+          // already an existing overlay for the source.
+          throw new RequestFailure(new RequestError(
+              RequestErrorCode.INVALID_OVERLAY_CHANGE,
+              'Invalid overlay change: no content to change'));
+        }
+        try {
+          newContents = SourceEdit.applySequence(oldContents, overlay.edits);
+        } on RangeError {
+          throw new RequestFailure(new RequestError(
+              RequestErrorCode.INVALID_OVERLAY_CHANGE,
+              'Invalid overlay change: invalid edit'));
+        }
+        fileContentOverlay[fileName] = newContents;
+      } else if (overlay is RemoveContentOverlay) {
+        fileContentOverlay[source.fullName] = null;
+      }
+      contentChanged(filePath);
+    });
+    return new AnalysisUpdateContentResult();
+  }
+
+  /**
+   * Handle a 'completion.getSuggestions' request.
+   */
+  CompletionGetSuggestionsResult handleCompletionGetSuggestions(
+          Map<String, Object> parameters) =>
+      new CompletionGetSuggestionsResult(
+          -1, -1, const <CompletionSuggestion>[]);
+
+  /**
+   * Handle an 'edit.getAssists' request.
+   */
+  EditGetAssistsResult handleEditGetAssists(Map<String, Object> parameters) =>
+      new EditGetAssistsResult(const <PrioritizedSourceChange>[]);
+
+  /**
+   * Handle an 'edit.getAvailableRefactorings' request. Subclasses that override
+   * this method in order to participate in refactorings must also override the
+   * method [handleEditGetRefactoring].
+   */
+  EditGetAvailableRefactoringsResult handleEditGetAvailableRefactorings(
+          Map<String, Object> parameters) =>
+      new EditGetAvailableRefactoringsResult(const <RefactoringKind>[]);
+
+  /**
+   * Handle an 'edit.getFixes' request.
+   */
+  EditGetFixesResult handleEditGetFixes(Map<String, Object> parameters) =>
+      new EditGetFixesResult(const <AnalysisErrorFixes>[]);
+
+  /**
+   * Handle an 'edit.getRefactoring' request.
+   */
+  EditGetRefactoringResult handleEditGetRefactoring(
+          Map<String, Object> parameters) =>
+      null;
+
+  /**
+   * Handle a 'plugin.shutdown' request. Subclasses can override this method to
+   * perform any required clean-up, but cannot prevent the plugin from shutting
+   * down.
+   */
+  PluginShutdownResult handlePluginShutdown(Map<String, Object> parameters) =>
+      new PluginShutdownResult();
+
+  /**
+   * Handle a 'plugin.versionCheck' request.
+   */
+  PluginVersionCheckResult handlePluginVersionCheck(
+      Map<String, Object> parameters) {
+    String byteStorePath = validateParameter(parameters,
+        PLUGIN_REQUEST_VERSION_CHECK_BYTESTOREPATH, 'plugin.versionCheck');
+    String versionString = validateParameter(parameters,
+        PLUGIN_REQUEST_VERSION_CHECK_VERSION, 'plugin.versionCheck');
+    Version serverVersion = new Version.parse(versionString);
+    _byteStore =
+        new MemoryCachingByteStore(new FileByteStore(byteStorePath), 64 * M);
+    return new PluginVersionCheckResult(
+        isCompatibleWith(serverVersion), name, version, fileGlobsToAnalyze,
+        contactInfo: contactInfo);
+  }
+
+  /**
+   * Return `true` if this plugin is compatible with an analysis server that is
+   * using the given version of the plugin API.
+   */
+  bool isCompatibleWith(Version serverVersion) =>
+      serverVersion <= new Version.parse(version);
+
+  /**
+   * The method that is called when the analysis server closes the communication
+   * channel. This method will not be invoked under normal conditions because
+   * the server will send a shutdown request and the plugin will stop listening
+   * to the channel before the server closes the channel.
+   */
+  void onDone() {}
+
+  /**
+   * The method that is called when an error has occurred in the analysis
+   * server. This method will not be invoked under normal conditions.
+   */
+  void onError(Object exception, StackTrace stackTrace) {}
+
+  /**
+   * Start this plugin by listening to the given communication [channel].
+   */
+  void start(PluginCommunicationChannel channel) {
+    this._channel = channel;
+    _channel.listen(_onRequest, onError: onError, onDone: onDone);
+  }
+
+  /**
+   * Validate that the value in the map of [parameters] at the given [key] is of
+   * the type [T]. If it is, return it. Otherwise throw a [RequestFailure] that
+   * will cause an error to be returned to the server.
+   */
+  Object/*=T*/ validateParameter/*<T>*/(
+      Map<String, Object> parameters, String key, String requestName) {
+    Object value = parameters[key];
+    // ignore: type_annotation_generic_function_parameter
+    if (value is Object/*=T*/) {
+      return value;
+    }
+    String message;
+    if (value == null) {
+      message = 'Missing parameter $key in $requestName';
+    } else {
+      message = 'Invalid value for $key in $requestName (${value.runtimeType})';
+    }
+    throw new RequestFailure(
+        new RequestError(RequestErrorCode.INVALID_PARAMETER, message));
+  }
+
+  /**
+   * Compute the response that should be returned for the given [request], or
+   * `null` if the response has already been sent.
+   */
+  Response _getResponse(Request request) {
+    ResponseResult result = null;
+    switch (request.id) {
+      case ANALYSIS_REQUEST_HANDLE_WATCH_EVENTS:
+        result = handleAnalysisHandleWatchEvents(request.params);
+        break;
+      case ANALYSIS_REQUEST_REANALYZE:
+        result = handleAnalysisReanalyze(request.params);
+        break;
+      case ANALYSIS_REQUEST_SET_CONTEXT_BUILDER_OPTIONS:
+        result = handleAnalysisSetContextBuilderOptions(request.params);
+        break;
+      case ANALYSIS_REQUEST_SET_CONTEXT_ROOTS:
+        result = handleAnalysisSetContextRoots(request.params);
+        break;
+      case ANALYSIS_REQUEST_SET_PRIORITY_FILES:
+        result = handleAnalysisSetPriorityFiles(request.params);
+        break;
+      case ANALYSIS_REQUEST_SET_SUBSCRIPTIONS:
+        result = handleAnalysisSetSubscriptions(request.params);
+        break;
+      case ANALYSIS_REQUEST_UPDATE_CONTENT:
+        result = handleAnalysisUpdateContent(request.params);
+        break;
+      case COMPLETION_REQUEST_GET_SUGGESTIONS:
+        result = handleCompletionGetSuggestions(request.params);
+        break;
+      case EDIT_REQUEST_GET_ASSISTS:
+        result = handleEditGetAssists(request.params);
+        break;
+      case EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS:
+        result = handleEditGetAvailableRefactorings(request.params);
+        break;
+      case EDIT_REQUEST_GET_FIXES:
+        result = handleEditGetFixes(request.params);
+        break;
+      case EDIT_REQUEST_GET_REFACTORING:
+        result = handleEditGetRefactoring(request.params);
+        break;
+      case PLUGIN_REQUEST_SHUTDOWN:
+        result = handlePluginShutdown(request.params);
+        _channel.sendResponse(result.toResponse(request.id));
+        _channel.close();
+        return null;
+      case PLUGIN_REQUEST_VERSION_CHECK:
+        result = handlePluginVersionCheck(request.params);
+        break;
+    }
+    if (result == null) {
+      return new Response(request.id,
+          error: RequestErrorFactory.unknownRequest(request));
+    }
+    return result.toResponse(request.id);
+  }
+
+  /**
+   * The method that is called when a [request] is received from the analysis
+   * server.
+   */
+  void _onRequest(Request request) {
+    String id = request.id;
+    Response response;
+    try {
+      response = _getResponse(request);
+    } on RequestFailure catch (exception) {
+      _channel.sendResponse(new Response(id, error: exception.error));
+    } catch (exception, stackTrace) {
+      response = new Response(id,
+          error: new RequestError(
+              RequestErrorCode.PLUGIN_ERROR, exception.toString(),
+              stackTrace: stackTrace.toString()));
+    }
+    if (response != null) {
+      _channel.sendResponse(response);
+    }
+  }
+}
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol.dart b/pkg/analyzer_plugin/lib/protocol/protocol.dart
new file mode 100644
index 0000000..3e73fb1
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/protocol/protocol.dart
@@ -0,0 +1,583 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+
+/**
+ * An interface for enumerated types in the protocol.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Enum {
+  /**
+   * The name of the enumerated value. This should match the name of the static
+   * getter which provides access to this enumerated value.
+   */
+  String get name;
+}
+
+/**
+ * A notification that can be sent to the server about an event that occurred.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Notification {
+  /**
+   * The name of the JSON attribute containing the name of the event that
+   * triggered the notification.
+   */
+  static const String EVENT = 'event';
+
+  /**
+   * The name of the JSON attribute containing the result values.
+   */
+  static const String PARAMS = 'params';
+
+  /**
+   * The name of the event that triggered the notification.
+   */
+  final String event;
+
+  /**
+   * A table mapping the names of notification parameters to their values, or
+   * `null` if there are no notification parameters.
+   */
+  Map<String, Object> params;
+
+  /**
+   * Initialize a newly created [Notification] to have the given [event] name.
+   * If [params] is provided, it will be used as the params; otherwise no
+   * params will be used.
+   */
+  Notification(this.event, [this.params]);
+
+  /**
+   * Initialize a newly created instance based on the given JSON data.
+   */
+  factory Notification.fromJson(Map json) {
+    return new Notification(json[Notification.EVENT],
+        json[Notification.PARAMS] as Map<String, Object>);
+  }
+
+  /**
+   * Return a table representing the structure of the Json object that will be
+   * sent to the client to represent this response.
+   */
+  Map<String, Object> toJson() {
+    Map<String, Object> jsonObject = {};
+    jsonObject[EVENT] = event;
+    if (params != null) {
+      jsonObject[PARAMS] = params;
+    }
+    return jsonObject;
+  }
+}
+
+/**
+ * A request that was received from the server.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Request {
+  /**
+   * The name of the JSON attribute containing the id of the request.
+   */
+  static const String ID = 'id';
+
+  /**
+   * The name of the JSON attribute containing the name of the request.
+   */
+  static const String METHOD = 'method';
+
+  /**
+   * The name of the JSON attribute containing the request parameters.
+   */
+  static const String PARAMS = 'params';
+
+  /**
+   * The name of the optional JSON attribute indicating the time (milliseconds
+   * since epoch) at which the server made the request.
+   */
+  static const String SERVER_REQUEST_TIME = 'serverRequestTime';
+
+  /**
+   * The unique identifier used to identify this request.
+   */
+  final String id;
+
+  /**
+   * The method being requested.
+   */
+  final String method;
+
+  /**
+   * A table mapping the names of request parameters to their values.
+   */
+  final Map<String, Object> params;
+
+  /**
+   * The time (milliseconds since epoch) at which the server made the request,
+   * or `null` if this information is not provided by the server.
+   */
+  final int serverRequestTime;
+
+  /**
+   * Initialize a newly created [Request] to have the given [id] and [method]
+   * name. If [params] is supplied, it is used as the "params" map for the
+   * request. Otherwise an empty "params" map is allocated.
+   */
+  Request(this.id, this.method,
+      [Map<String, Object> params, this.serverRequestTime])
+      : params = params ?? <String, Object>{};
+
+  /**
+   * Return a request parsed from the given json, or `null` if the [data] is
+   * not a valid json representation of a request. The [data] is expected to
+   * have the following format:
+   *
+   *   {
+   *     'clientRequestTime': millisecondsSinceEpoch
+   *     'id': String,
+   *     'method': methodName,
+   *     'params': {
+   *       paramter_name: value
+   *     }
+   *   }
+   *
+   * where both the parameters and clientRequestTime are optional.
+   *
+   * The parameters can contain any number of name/value pairs. The
+   * clientRequestTime must be an int representing the time at which the client
+   * issued the request (milliseconds since epoch).
+   */
+  factory Request.fromJson(Map<String, Object> result) {
+    var id = result[Request.ID];
+    var method = result[Request.METHOD];
+    if (id is! String || method is! String) {
+      return null;
+    }
+    var time = result[Request.SERVER_REQUEST_TIME];
+    if (time != null && time is! int) {
+      return null;
+    }
+    var params = result[Request.PARAMS];
+    if (params is Map || params == null) {
+      return new Request(id, method, params as Map<String, Object>, time);
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  int get hashCode {
+    return id.hashCode;
+  }
+
+  @override
+  bool operator ==(Object other) {
+    return other is Request &&
+        id == other.id &&
+        method == other.method &&
+        serverRequestTime == other.serverRequestTime &&
+        _equalMaps(params, other.params);
+  }
+
+  /**
+   * Return a table representing the structure of the Json object that will be
+   * sent to the server to represent this response.
+   */
+  Map<String, Object> toJson() {
+    Map<String, Object> jsonObject = {};
+    jsonObject[ID] = id;
+    jsonObject[METHOD] = method;
+    if (params.isNotEmpty) {
+      jsonObject[PARAMS] = params;
+    }
+    if (serverRequestTime != null) {
+      jsonObject[SERVER_REQUEST_TIME] = serverRequestTime;
+    }
+    return jsonObject;
+  }
+
+  bool _equalLists(List first, List second) {
+    if (first == null) {
+      return second == null;
+    }
+    if (second == null) {
+      return false;
+    }
+    int length = first.length;
+    if (length != second.length) {
+      return false;
+    }
+    for (int i = 0; i < length; i++) {
+      if (!_equalObjects(first[i], second[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _equalMaps(Map first, Map second) {
+    if (first == null) {
+      return second == null;
+    }
+    if (second == null) {
+      return false;
+    }
+    if (first.length != second.length) {
+      return false;
+    }
+    for (var key in first.keys) {
+      if (!second.containsKey(key)) {
+        return false;
+      }
+      if (!_equalObjects(first[key], second[key])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _equalObjects(Object first, Object second) {
+    if (first == null) {
+      return second == null;
+    }
+    if (second == null) {
+      return false;
+    }
+    if (first is Map) {
+      if (second is Map) {
+        return _equalMaps(first, second);
+      }
+      return false;
+    }
+    if (first is List) {
+      if (second is List) {
+        return _equalLists(first, second);
+      }
+      return false;
+    }
+    return first == second;
+  }
+}
+
+/**
+ * A collection of utility methods that create instances of the generated class
+ * [RequestError].
+ */
+class RequestErrorFactory {
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * GET_ERRORS_INVALID_FILE error condition.
+//   */
+//  Response.getErrorsInvalidFile(Request request)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.GET_ERRORS_INVALID_FILE,
+//          'Error during `analysis.getErrors`: invalid file.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * GET_NAVIGATION_INVALID_FILE error condition.
+//   */
+//  Response.getNavigationInvalidFile(Request request)
+//      : this(request.id,
+//      error: new RequestError(
+//          RequestErrorCode.GET_NAVIGATION_INVALID_FILE,
+//          'Error during `analysis.getNavigation`: invalid file.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * GET_REACHABLE_SOURCES_INVALID_FILE error condition.
+//   */
+//  Response.getReachableSourcesInvalidFile(Request request)
+//      : this(request.id,
+//      error: new RequestError(
+//          RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE,
+//          'Error during `analysis.getReachableSources`: invalid file.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by an analysis.reanalyze [request] that specifies an analysis root that is
+//   * not in the current list of analysis roots.
+//   */
+//  Response.invalidAnalysisRoot(Request request, String rootPath)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.INVALID_ANALYSIS_ROOT,
+//          "Invalid analysis root: $rootPath"));
+//
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by a [request] that specifies an execution context whose context root does
+//   * not exist.
+//   */
+//  Response.invalidExecutionContext(Request request, String contextId)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.INVALID_EXECUTION_CONTEXT,
+//          "Invalid execution context: $contextId"));
+//
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * INVALID_FILE_PATH_FORMAT error condition.
+//   */
+//  Response.invalidFilePathFormat(Request request, path)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.INVALID_FILE_PATH_FORMAT,
+//          'Invalid file path format: $path'));
+
+  /**
+   * Return a request error representing an error condition caused by a
+   * [request] that had invalid parameter.  [path] is the path to the
+   * invalid parameter, in Javascript notation (e.g. "foo.bar" means that the
+   * parameter "foo" contained a key "bar" whose value was the wrong type).
+   * [expectation] is a description of the type of data that was expected.
+   */
+  static RequestError invalidParameter(
+          Request request, String path, String expectation) =>
+      new RequestError(RequestErrorCode.INVALID_PARAMETER,
+          "Invalid parameter '$path'. $expectation.");
+
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by a malformed request.
+//   */
+//  Response.invalidRequestFormat()
+//      : this('',
+//      error: new RequestError(
+//          RequestErrorCode.INVALID_REQUEST, 'Invalid request'));
+//
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by a request that requires an index, but indexing is disabled.
+//   */
+//  Response.noIndexGenerated(Request request)
+//      : this(request.id,
+//      error: new RequestError(
+//          RequestErrorCode.NO_INDEX_GENERATED, 'Indexing is disabled'));
+//
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * ORGANIZE_DIRECTIVES_ERROR error condition.
+//   */
+//  Response.organizeDirectivesError(Request request, String message)
+//      : this(request.id,
+//      error: new RequestError(
+//          RequestErrorCode.ORGANIZE_DIRECTIVES_ERROR, message));
+//
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * REFACTORING_REQUEST_CANCELLED error condition.
+//   */
+//  Response.refactoringRequestCancelled(Request request)
+//      : this(request.id,
+//      error: new RequestError(
+//          RequestErrorCode.REFACTORING_REQUEST_CANCELLED,
+//          'The `edit.getRefactoring` request was cancelled.'));
+
+  /**
+   * Return a request error representing an error that occurred in the plugin.
+   */
+  static RequestError pluginError(Request request, exception, stackTrace) =>
+      new RequestError(RequestErrorCode.PLUGIN_ERROR, exception.toString(),
+          stackTrace: stackTrace);
+
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * SORT_MEMBERS_INVALID_FILE error condition.
+//   */
+//  Response.sortMembersInvalidFile(Request request)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.SORT_MEMBERS_INVALID_FILE,
+//          'Error during `edit.sortMembers`: invalid file.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent the
+//   * SORT_MEMBERS_PARSE_ERRORS error condition.
+//   */
+//  Response.sortMembersParseErrors(Request request, int numErrors)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS,
+//          'Error during `edit.sortMembers`: file has $numErrors scan/parse errors.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by a `analysis.setPriorityFiles` [request] that includes one or more files
+//   * that are not being analyzed.
+//   */
+//  Response.unanalyzedPriorityFiles(String requestId, String fileNames)
+//      : this(requestId,
+//      error: new RequestError(RequestErrorCode.UNANALYZED_PRIORITY_FILES,
+//          "Unanalyzed files cannot be a priority: '$fileNames'"));
+
+  /**
+   * Return a request error representing an error condition caused by a
+   * [request] that cannot be handled by any known handlers.
+   */
+  static RequestError unknownRequest(Request request) =>
+      new RequestError(RequestErrorCode.UNKNOWN_REQUEST, 'Unknown request');
+
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by a [request] referencing a source that does not exist.
+//   */
+//  Response.unknownSource(Request request)
+//      : this(request.id,
+//      error: new RequestError(
+//          RequestErrorCode.UNKNOWN_SOURCE, 'Unknown source'));
+//
+//  /**
+//   * Initialize a newly created instance to represent an error condition caused
+//   * by a [request] for a service that is not supported.
+//   */
+//  Response.unsupportedFeature(String requestId, String message)
+//      : this(requestId,
+//      error: new RequestError(
+//          RequestErrorCode.UNSUPPORTED_FEATURE, message));
+}
+
+/**
+ * An exception that occurred during the handling of a request that requires
+ * that an error be returned to the server.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RequestFailure implements Exception {
+  /**
+   * A description of the error that was encountered.
+   */
+  final RequestError error;
+
+  /**
+   * Initialize a newly created exception to return a response with the given
+   * [error].
+   */
+  RequestFailure(this.error);
+}
+
+/**
+ * A response to the server.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Response {
+  /**
+   * The [Response] instance that is returned when a real [Response] cannot
+   * be provided at the moment.
+   */
+  static final Response DELAYED_RESPONSE = new Response('DELAYED_RESPONSE');
+
+  /**
+   * The name of the JSON attribute containing the id of the request for which
+   * this is a response.
+   */
+  static const String ID = 'id';
+
+  /**
+   * The name of the JSON attribute containing the error message.
+   */
+  static const String ERROR = 'error';
+
+  /**
+   * The name of the JSON attribute containing the result values.
+   */
+  static const String RESULT = 'result';
+
+  /**
+   * The unique identifier used to identify the request that this response is
+   * associated with.
+   */
+  final String id;
+
+  /**
+   * The error that was caused by attempting to handle the request, or `null` if
+   * there was no error.
+   */
+  final RequestError error;
+
+  /**
+   * A table mapping the names of result fields to their values.  Should be
+   * `null` if there is no result to send.
+   */
+  Map<String, Object> result;
+
+  /**
+   * Initialize a newly created instance to represent a response to a request
+   * with the given [id].  If [_result] is provided, it will be used as the
+   * result; otherwise an empty result will be used.  If an [error] is provided
+   * then the response will represent an error condition.
+   */
+  Response(this.id, {Map<String, Object> result, this.error}) : result = result;
+
+//  /**
+//   * Initialize a newly created instance to represent the FILE_NOT_ANALYZED
+//   * error condition.
+//   */
+//  Response.fileNotAnalyzed(Request request, String file)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.FILE_NOT_ANALYZED,
+//          'File is not analyzed: $file.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent the FORMAT_INVALID_FILE
+//   * error condition.
+//   */
+//  Response.formatInvalidFile(Request request)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.FORMAT_INVALID_FILE,
+//          'Error during `edit.format`: invalid file.'));
+//
+//  /**
+//   * Initialize a newly created instance to represent the FORMAT_WITH_ERROR
+//   * error condition.
+//   */
+//  Response.formatWithErrors(Request request)
+//      : this(request.id,
+//      error: new RequestError(RequestErrorCode.FORMAT_WITH_ERRORS,
+//          'Error during `edit.format`: source contains syntax errors.'));
+
+  /**
+   * Initialize a newly created instance based on the given JSON data.
+   */
+  factory Response.fromJson(Map json) {
+    try {
+      Object id = json[Response.ID];
+      if (id is! String) {
+        return null;
+      }
+      Object error = json[Response.ERROR];
+      RequestError decodedError;
+      if (error is Map) {
+        decodedError = new RequestError.fromJson(
+            new ResponseDecoder(null), '.error', error);
+      }
+      Object result = json[Response.RESULT];
+      Map<String, Object> decodedResult;
+      if (result is Map) {
+        decodedResult = result as Map<String, Object>;
+      }
+      return new Response(id, error: decodedError, result: decodedResult);
+    } catch (exception) {
+      return null;
+    }
+  }
+
+  /**
+   * Return a table representing the structure of the Json object that will be
+   * sent to the client to represent this response.
+   */
+  Map<String, Object> toJson() {
+    Map<String, Object> jsonObject = new HashMap<String, Object>();
+    jsonObject[ID] = id;
+    if (error != null) {
+      jsonObject[ERROR] = error.toJson();
+    }
+    if (result != null) {
+      jsonObject[RESULT] = result;
+    }
+    return jsonObject;
+  }
+}
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart b/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart
new file mode 100644
index 0000000..ada6ebe
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart
@@ -0,0 +1,88 @@
+// 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 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".
+
+const String ANALYSIS_NOTIFICATION_ERRORS = 'analysis.errors';
+const String ANALYSIS_NOTIFICATION_ERRORS_ERRORS = 'errors';
+const String ANALYSIS_NOTIFICATION_ERRORS_FILE = 'file';
+const String ANALYSIS_NOTIFICATION_FOLDING = 'analysis.folding';
+const String ANALYSIS_NOTIFICATION_FOLDING_FILE = 'file';
+const String ANALYSIS_NOTIFICATION_FOLDING_REGIONS = 'regions';
+const String ANALYSIS_NOTIFICATION_HIGHLIGHTS = 'analysis.highlights';
+const String ANALYSIS_NOTIFICATION_HIGHLIGHTS_FILE = 'file';
+const String ANALYSIS_NOTIFICATION_HIGHLIGHTS_REGIONS = 'regions';
+const String ANALYSIS_NOTIFICATION_NAVIGATION = 'analysis.navigation';
+const String ANALYSIS_NOTIFICATION_NAVIGATION_FILE = 'file';
+const String ANALYSIS_NOTIFICATION_NAVIGATION_FILES = 'files';
+const String ANALYSIS_NOTIFICATION_NAVIGATION_REGIONS = 'regions';
+const String ANALYSIS_NOTIFICATION_NAVIGATION_TARGETS = 'targets';
+const String ANALYSIS_NOTIFICATION_OCCURRENCES = 'analysis.occurrences';
+const String ANALYSIS_NOTIFICATION_OCCURRENCES_FILE = 'file';
+const String ANALYSIS_NOTIFICATION_OCCURRENCES_OCCURRENCES = 'occurrences';
+const String ANALYSIS_NOTIFICATION_OUTLINE = 'analysis.outline';
+const String ANALYSIS_NOTIFICATION_OUTLINE_FILE = 'file';
+const String ANALYSIS_NOTIFICATION_OUTLINE_OUTLINE = 'outline';
+const String ANALYSIS_REQUEST_HANDLE_WATCH_EVENTS = 'analysis.handleWatchEvents';
+const String ANALYSIS_REQUEST_HANDLE_WATCH_EVENTS_EVENTS = 'events';
+const String ANALYSIS_REQUEST_REANALYZE = 'analysis.reanalyze';
+const String ANALYSIS_REQUEST_REANALYZE_ROOTS = 'roots';
+const String ANALYSIS_REQUEST_SET_CONTEXT_BUILDER_OPTIONS = 'analysis.setContextBuilderOptions';
+const String ANALYSIS_REQUEST_SET_CONTEXT_BUILDER_OPTIONS_OPTIONS = 'options';
+const String ANALYSIS_REQUEST_SET_CONTEXT_ROOTS = 'analysis.setContextRoots';
+const String ANALYSIS_REQUEST_SET_CONTEXT_ROOTS_ROOTS = 'roots';
+const String ANALYSIS_REQUEST_SET_PRIORITY_FILES = 'analysis.setPriorityFiles';
+const String ANALYSIS_REQUEST_SET_PRIORITY_FILES_FILES = 'files';
+const String ANALYSIS_REQUEST_SET_SUBSCRIPTIONS = 'analysis.setSubscriptions';
+const String ANALYSIS_REQUEST_SET_SUBSCRIPTIONS_SUBSCRIPTIONS = 'subscriptions';
+const String ANALYSIS_REQUEST_UPDATE_CONTENT = 'analysis.updateContent';
+const String ANALYSIS_REQUEST_UPDATE_CONTENT_FILES = 'files';
+const String COMPLETION_REQUEST_GET_SUGGESTIONS = 'completion.getSuggestions';
+const String COMPLETION_REQUEST_GET_SUGGESTIONS_FILE = 'file';
+const String COMPLETION_REQUEST_GET_SUGGESTIONS_OFFSET = 'offset';
+const String COMPLETION_RESPONSE_GET_SUGGESTIONS_REPLACEMENTLENGTH = 'replacementLength';
+const String COMPLETION_RESPONSE_GET_SUGGESTIONS_REPLACEMENTOFFSET = 'replacementOffset';
+const String COMPLETION_RESPONSE_GET_SUGGESTIONS_RESULTS = 'results';
+const String EDIT_REQUEST_GET_ASSISTS = 'edit.getAssists';
+const String EDIT_REQUEST_GET_ASSISTS_FILE = 'file';
+const String EDIT_REQUEST_GET_ASSISTS_LENGTH = 'length';
+const String EDIT_REQUEST_GET_ASSISTS_OFFSET = 'offset';
+const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS = 'edit.getAvailableRefactorings';
+const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_FILE = 'file';
+const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_LENGTH = 'length';
+const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_OFFSET = 'offset';
+const String EDIT_REQUEST_GET_FIXES = 'edit.getFixes';
+const String EDIT_REQUEST_GET_FIXES_FILE = 'file';
+const String EDIT_REQUEST_GET_FIXES_OFFSET = 'offset';
+const String EDIT_REQUEST_GET_REFACTORING = 'edit.getRefactoring';
+const String EDIT_REQUEST_GET_REFACTORING_FILE = 'file';
+const String EDIT_REQUEST_GET_REFACTORING_KIND = 'kind';
+const String EDIT_REQUEST_GET_REFACTORING_LENGTH = 'length';
+const String EDIT_REQUEST_GET_REFACTORING_OFFSET = 'offset';
+const String EDIT_REQUEST_GET_REFACTORING_OPTIONS = 'options';
+const String EDIT_REQUEST_GET_REFACTORING_VALIDATEONLY = 'validateOnly';
+const String EDIT_RESPONSE_GET_ASSISTS_ASSISTS = 'assists';
+const String EDIT_RESPONSE_GET_AVAILABLE_REFACTORINGS_KINDS = 'kinds';
+const String EDIT_RESPONSE_GET_FIXES_FIXES = 'fixes';
+const String EDIT_RESPONSE_GET_REFACTORING_CHANGE = 'change';
+const String EDIT_RESPONSE_GET_REFACTORING_FEEDBACK = 'feedback';
+const String EDIT_RESPONSE_GET_REFACTORING_FINALPROBLEMS = 'finalProblems';
+const String EDIT_RESPONSE_GET_REFACTORING_INITIALPROBLEMS = 'initialProblems';
+const String EDIT_RESPONSE_GET_REFACTORING_OPTIONSPROBLEMS = 'optionsProblems';
+const String EDIT_RESPONSE_GET_REFACTORING_POTENTIALEDITS = 'potentialEdits';
+const String PLUGIN_NOTIFICATION_ERROR = 'plugin.error';
+const String PLUGIN_NOTIFICATION_ERROR_ISFATAL = 'isFatal';
+const String PLUGIN_NOTIFICATION_ERROR_MESSAGE = 'message';
+const String PLUGIN_NOTIFICATION_ERROR_STACKTRACE = 'stackTrace';
+const String PLUGIN_REQUEST_SHUTDOWN = 'plugin.shutdown';
+const String PLUGIN_REQUEST_VERSION_CHECK = 'plugin.versionCheck';
+const String PLUGIN_REQUEST_VERSION_CHECK_BYTESTOREPATH = 'byteStorePath';
+const String PLUGIN_REQUEST_VERSION_CHECK_VERSION = 'version';
+const String PLUGIN_RESPONSE_VERSION_CHECK_CONTACTINFO = 'contactInfo';
+const String PLUGIN_RESPONSE_VERSION_CHECK_INTERESTINGFILES = 'interestingFiles';
+const String PLUGIN_RESPONSE_VERSION_CHECK_ISCOMPATIBLE = 'isCompatible';
+const String PLUGIN_RESPONSE_VERSION_CHECK_NAME = 'name';
+const String PLUGIN_RESPONSE_VERSION_CHECK_VERSION = 'version';
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart b/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart
new file mode 100644
index 0000000..0e063ca
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart
@@ -0,0 +1,10721 @@
+// 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 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".
+
+import 'dart:convert' hide JsonDecoder;
+
+import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer_plugin/protocol/protocol.dart';
+import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+
+/**
+ * AddContentOverlay
+ *
+ * {
+ *   "type": "add"
+ *   "content": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AddContentOverlay implements HasToJson {
+  String _content;
+
+  /**
+   * The new content of the file.
+   */
+  String get content => _content;
+
+  /**
+   * The new content of the file.
+   */
+  void set content(String value) {
+    assert(value != null);
+    this._content = value;
+  }
+
+  AddContentOverlay(String content) {
+    this.content = content;
+  }
+
+  factory AddContentOverlay.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      if (json["type"] != "add") {
+        throw jsonDecoder.mismatch(jsonPath, "equal " + "add", json);
+      }
+      String content;
+      if (json.containsKey("content")) {
+        content = jsonDecoder.decodeString(jsonPath + ".content", json["content"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "content");
+      }
+      return new AddContentOverlay(content);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "AddContentOverlay", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["type"] = "add";
+    result["content"] = content;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AddContentOverlay) {
+      return content == other.content;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, 704418402);
+    hash = JenkinsSmiHash.combine(hash, content.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * AnalysisError
+ *
+ * {
+ *   "severity": AnalysisErrorSeverity
+ *   "type": AnalysisErrorType
+ *   "location": Location
+ *   "message": String
+ *   "correction": optional String
+ *   "code": String
+ *   "hasFix": optional bool
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisError implements HasToJson {
+  AnalysisErrorSeverity _severity;
+
+  AnalysisErrorType _type;
+
+  Location _location;
+
+  String _message;
+
+  String _correction;
+
+  String _code;
+
+  bool _hasFix;
+
+  /**
+   * The severity of the error.
+   */
+  AnalysisErrorSeverity get severity => _severity;
+
+  /**
+   * The severity of the error.
+   */
+  void set severity(AnalysisErrorSeverity value) {
+    assert(value != null);
+    this._severity = value;
+  }
+
+  /**
+   * The type of the error.
+   */
+  AnalysisErrorType get type => _type;
+
+  /**
+   * The type of the error.
+   */
+  void set type(AnalysisErrorType value) {
+    assert(value != null);
+    this._type = value;
+  }
+
+  /**
+   * The location associated with the error.
+   */
+  Location get location => _location;
+
+  /**
+   * The location associated with the error.
+   */
+  void set location(Location value) {
+    assert(value != null);
+    this._location = value;
+  }
+
+  /**
+   * The message to be displayed for this error. The message should indicate
+   * what is wrong with the code and why it is wrong.
+   */
+  String get message => _message;
+
+  /**
+   * The message to be displayed for this error. The message should indicate
+   * what is wrong with the code and why it is wrong.
+   */
+  void set message(String value) {
+    assert(value != null);
+    this._message = value;
+  }
+
+  /**
+   * The correction message to be displayed for this error. The correction
+   * message should indicate how the user can fix the error. The field is
+   * omitted if there is no correction message associated with the error code.
+   */
+  String get correction => _correction;
+
+  /**
+   * The correction message to be displayed for this error. The correction
+   * message should indicate how the user can fix the error. The field is
+   * omitted if there is no correction message associated with the error code.
+   */
+  void set correction(String value) {
+    this._correction = value;
+  }
+
+  /**
+   * The name, as a string, of the error code associated with this error.
+   */
+  String get code => _code;
+
+  /**
+   * The name, as a string, of the error code associated with this error.
+   */
+  void set code(String value) {
+    assert(value != null);
+    this._code = value;
+  }
+
+  /**
+   * A hint to indicate to interested clients that this error has an associated
+   * fix (or fixes). The absence of this field implies there are not known to
+   * be fixes. Note that since the operation to calculate whether fixes apply
+   * needs to be performant it is possible that complicated tests will be
+   * skipped and a false negative returned. For this reason, this attribute
+   * should be treated as a "hint". Despite the possibility of false negatives,
+   * no false positives should be returned. If a client sees this flag set they
+   * can proceed with the confidence that there are in fact associated fixes.
+   */
+  bool get hasFix => _hasFix;
+
+  /**
+   * A hint to indicate to interested clients that this error has an associated
+   * fix (or fixes). The absence of this field implies there are not known to
+   * be fixes. Note that since the operation to calculate whether fixes apply
+   * needs to be performant it is possible that complicated tests will be
+   * skipped and a false negative returned. For this reason, this attribute
+   * should be treated as a "hint". Despite the possibility of false negatives,
+   * no false positives should be returned. If a client sees this flag set they
+   * can proceed with the confidence that there are in fact associated fixes.
+   */
+  void set hasFix(bool value) {
+    this._hasFix = value;
+  }
+
+  AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, String code, {String correction, bool hasFix}) {
+    this.severity = severity;
+    this.type = type;
+    this.location = location;
+    this.message = message;
+    this.correction = correction;
+    this.code = code;
+    this.hasFix = hasFix;
+  }
+
+  factory AnalysisError.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      AnalysisErrorSeverity severity;
+      if (json.containsKey("severity")) {
+        severity = new AnalysisErrorSeverity.fromJson(jsonDecoder, jsonPath + ".severity", json["severity"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "severity");
+      }
+      AnalysisErrorType type;
+      if (json.containsKey("type")) {
+        type = new AnalysisErrorType.fromJson(jsonDecoder, jsonPath + ".type", json["type"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "type");
+      }
+      Location location;
+      if (json.containsKey("location")) {
+        location = new Location.fromJson(jsonDecoder, jsonPath + ".location", json["location"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "location");
+      }
+      String message;
+      if (json.containsKey("message")) {
+        message = jsonDecoder.decodeString(jsonPath + ".message", json["message"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "message");
+      }
+      String correction;
+      if (json.containsKey("correction")) {
+        correction = jsonDecoder.decodeString(jsonPath + ".correction", json["correction"]);
+      }
+      String code;
+      if (json.containsKey("code")) {
+        code = jsonDecoder.decodeString(jsonPath + ".code", json["code"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "code");
+      }
+      bool hasFix;
+      if (json.containsKey("hasFix")) {
+        hasFix = jsonDecoder.decodeBool(jsonPath + ".hasFix", json["hasFix"]);
+      }
+      return new AnalysisError(severity, type, location, message, code, correction: correction, hasFix: hasFix);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "AnalysisError", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["severity"] = severity.toJson();
+    result["type"] = type.toJson();
+    result["location"] = location.toJson();
+    result["message"] = message;
+    if (correction != null) {
+      result["correction"] = correction;
+    }
+    result["code"] = code;
+    if (hasFix != null) {
+      result["hasFix"] = hasFix;
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisError) {
+      return severity == other.severity &&
+          type == other.type &&
+          location == other.location &&
+          message == other.message &&
+          correction == other.correction &&
+          code == other.code &&
+          hasFix == other.hasFix;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, severity.hashCode);
+    hash = JenkinsSmiHash.combine(hash, type.hashCode);
+    hash = JenkinsSmiHash.combine(hash, location.hashCode);
+    hash = JenkinsSmiHash.combine(hash, message.hashCode);
+    hash = JenkinsSmiHash.combine(hash, correction.hashCode);
+    hash = JenkinsSmiHash.combine(hash, code.hashCode);
+    hash = JenkinsSmiHash.combine(hash, hasFix.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * AnalysisErrorFixes
+ *
+ * {
+ *   "error": AnalysisError
+ *   "fixes": List<PrioritizedSourceChange>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisErrorFixes implements HasToJson {
+  AnalysisError _error;
+
+  List<PrioritizedSourceChange> _fixes;
+
+  /**
+   * The error with which the fixes are associated.
+   */
+  AnalysisError get error => _error;
+
+  /**
+   * The error with which the fixes are associated.
+   */
+  void set error(AnalysisError value) {
+    assert(value != null);
+    this._error = value;
+  }
+
+  /**
+   * The fixes associated with the error.
+   */
+  List<PrioritizedSourceChange> get fixes => _fixes;
+
+  /**
+   * The fixes associated with the error.
+   */
+  void set fixes(List<PrioritizedSourceChange> value) {
+    assert(value != null);
+    this._fixes = value;
+  }
+
+  AnalysisErrorFixes(AnalysisError error, {List<PrioritizedSourceChange> fixes}) {
+    this.error = error;
+    if (fixes == null) {
+      this.fixes = <PrioritizedSourceChange>[];
+    } else {
+      this.fixes = fixes;
+    }
+  }
+
+  factory AnalysisErrorFixes.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      AnalysisError error;
+      if (json.containsKey("error")) {
+        error = new AnalysisError.fromJson(jsonDecoder, jsonPath + ".error", json["error"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "error");
+      }
+      List<PrioritizedSourceChange> fixes;
+      if (json.containsKey("fixes")) {
+        fixes = jsonDecoder.decodeList(jsonPath + ".fixes", json["fixes"], (String jsonPath, Object json) => new PrioritizedSourceChange.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "fixes");
+      }
+      return new AnalysisErrorFixes(error, fixes: fixes);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "AnalysisErrorFixes", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["error"] = error.toJson();
+    result["fixes"] = fixes.map((PrioritizedSourceChange value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisErrorFixes) {
+      return error == other.error &&
+          listEqual(fixes, other.fixes, (PrioritizedSourceChange a, PrioritizedSourceChange b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, error.hashCode);
+    hash = JenkinsSmiHash.combine(hash, fixes.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * AnalysisErrorSeverity
+ *
+ * enum {
+ *   INFO
+ *   WARNING
+ *   ERROR
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisErrorSeverity implements Enum {
+  static const AnalysisErrorSeverity INFO = const AnalysisErrorSeverity._("INFO");
+
+  static const AnalysisErrorSeverity WARNING = const AnalysisErrorSeverity._("WARNING");
+
+  static const AnalysisErrorSeverity ERROR = const AnalysisErrorSeverity._("ERROR");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<AnalysisErrorSeverity> VALUES = const <AnalysisErrorSeverity>[INFO, WARNING, ERROR];
+
+  @override
+  final String name;
+
+  const AnalysisErrorSeverity._(this.name);
+
+  factory AnalysisErrorSeverity(String name) {
+    switch (name) {
+      case "INFO":
+        return INFO;
+      case "WARNING":
+        return WARNING;
+      case "ERROR":
+        return ERROR;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory AnalysisErrorSeverity.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new AnalysisErrorSeverity(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "AnalysisErrorSeverity", json);
+  }
+
+  @override
+  String toString() => "AnalysisErrorSeverity.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * AnalysisErrorType
+ *
+ * enum {
+ *   CHECKED_MODE_COMPILE_TIME_ERROR
+ *   COMPILE_TIME_ERROR
+ *   HINT
+ *   LINT
+ *   STATIC_TYPE_WARNING
+ *   STATIC_WARNING
+ *   SYNTACTIC_ERROR
+ *   TODO
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisErrorType implements Enum {
+  static const AnalysisErrorType CHECKED_MODE_COMPILE_TIME_ERROR = const AnalysisErrorType._("CHECKED_MODE_COMPILE_TIME_ERROR");
+
+  static const AnalysisErrorType COMPILE_TIME_ERROR = const AnalysisErrorType._("COMPILE_TIME_ERROR");
+
+  static const AnalysisErrorType HINT = const AnalysisErrorType._("HINT");
+
+  static const AnalysisErrorType LINT = const AnalysisErrorType._("LINT");
+
+  static const AnalysisErrorType STATIC_TYPE_WARNING = const AnalysisErrorType._("STATIC_TYPE_WARNING");
+
+  static const AnalysisErrorType STATIC_WARNING = const AnalysisErrorType._("STATIC_WARNING");
+
+  static const AnalysisErrorType SYNTACTIC_ERROR = const AnalysisErrorType._("SYNTACTIC_ERROR");
+
+  static const AnalysisErrorType TODO = const AnalysisErrorType._("TODO");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<AnalysisErrorType> VALUES = const <AnalysisErrorType>[CHECKED_MODE_COMPILE_TIME_ERROR, COMPILE_TIME_ERROR, HINT, LINT, STATIC_TYPE_WARNING, STATIC_WARNING, SYNTACTIC_ERROR, TODO];
+
+  @override
+  final String name;
+
+  const AnalysisErrorType._(this.name);
+
+  factory AnalysisErrorType(String name) {
+    switch (name) {
+      case "CHECKED_MODE_COMPILE_TIME_ERROR":
+        return CHECKED_MODE_COMPILE_TIME_ERROR;
+      case "COMPILE_TIME_ERROR":
+        return COMPILE_TIME_ERROR;
+      case "HINT":
+        return HINT;
+      case "LINT":
+        return LINT;
+      case "STATIC_TYPE_WARNING":
+        return STATIC_TYPE_WARNING;
+      case "STATIC_WARNING":
+        return STATIC_WARNING;
+      case "SYNTACTIC_ERROR":
+        return SYNTACTIC_ERROR;
+      case "TODO":
+        return TODO;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory AnalysisErrorType.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new AnalysisErrorType(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "AnalysisErrorType", json);
+  }
+
+  @override
+  String toString() => "AnalysisErrorType.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * analysis.errors params
+ *
+ * {
+ *   "file": FilePath
+ *   "errors": List<AnalysisError>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisErrorsParams implements HasToJson {
+  String _file;
+
+  List<AnalysisError> _errors;
+
+  /**
+   * The file containing the errors.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the errors.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The errors contained in the file.
+   */
+  List<AnalysisError> get errors => _errors;
+
+  /**
+   * The errors contained in the file.
+   */
+  void set errors(List<AnalysisError> value) {
+    assert(value != null);
+    this._errors = value;
+  }
+
+  AnalysisErrorsParams(String file, List<AnalysisError> errors) {
+    this.file = file;
+    this.errors = errors;
+  }
+
+  factory AnalysisErrorsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      List<AnalysisError> errors;
+      if (json.containsKey("errors")) {
+        errors = jsonDecoder.decodeList(jsonPath + ".errors", json["errors"], (String jsonPath, Object json) => new AnalysisError.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "errors");
+      }
+      return new AnalysisErrorsParams(file, errors);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.errors params", json);
+    }
+  }
+
+  factory AnalysisErrorsParams.fromNotification(Notification notification) {
+    return new AnalysisErrorsParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["errors"] = errors.map((AnalysisError value) => value.toJson()).toList();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("analysis.errors", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisErrorsParams) {
+      return file == other.file &&
+          listEqual(errors, other.errors, (AnalysisError a, AnalysisError b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, errors.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.folding params
+ *
+ * {
+ *   "file": FilePath
+ *   "regions": List<FoldingRegion>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisFoldingParams implements HasToJson {
+  String _file;
+
+  List<FoldingRegion> _regions;
+
+  /**
+   * The file containing the folding regions.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the folding regions.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The folding regions contained in the file.
+   */
+  List<FoldingRegion> get regions => _regions;
+
+  /**
+   * The folding regions contained in the file.
+   */
+  void set regions(List<FoldingRegion> value) {
+    assert(value != null);
+    this._regions = value;
+  }
+
+  AnalysisFoldingParams(String file, List<FoldingRegion> regions) {
+    this.file = file;
+    this.regions = regions;
+  }
+
+  factory AnalysisFoldingParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      List<FoldingRegion> regions;
+      if (json.containsKey("regions")) {
+        regions = jsonDecoder.decodeList(jsonPath + ".regions", json["regions"], (String jsonPath, Object json) => new FoldingRegion.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "regions");
+      }
+      return new AnalysisFoldingParams(file, regions);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.folding params", json);
+    }
+  }
+
+  factory AnalysisFoldingParams.fromNotification(Notification notification) {
+    return new AnalysisFoldingParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["regions"] = regions.map((FoldingRegion value) => value.toJson()).toList();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("analysis.folding", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisFoldingParams) {
+      return file == other.file &&
+          listEqual(regions, other.regions, (FoldingRegion a, FoldingRegion b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, regions.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.handleWatchEvents params
+ *
+ * {
+ *   "events": List<WatchEvent>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisHandleWatchEventsParams implements RequestParams {
+  List<WatchEvent> _events;
+
+  /**
+   * The watch events that the plugin should handle.
+   */
+  List<WatchEvent> get events => _events;
+
+  /**
+   * The watch events that the plugin should handle.
+   */
+  void set events(List<WatchEvent> value) {
+    assert(value != null);
+    this._events = value;
+  }
+
+  AnalysisHandleWatchEventsParams(List<WatchEvent> events) {
+    this.events = events;
+  }
+
+  factory AnalysisHandleWatchEventsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<WatchEvent> events;
+      if (json.containsKey("events")) {
+        events = jsonDecoder.decodeList(jsonPath + ".events", json["events"], (String jsonPath, Object json) => new WatchEvent.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "events");
+      }
+      return new AnalysisHandleWatchEventsParams(events);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.handleWatchEvents params", json);
+    }
+  }
+
+  factory AnalysisHandleWatchEventsParams.fromRequest(Request request) {
+    return new AnalysisHandleWatchEventsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["events"] = events.map((WatchEvent value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.handleWatchEvents", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisHandleWatchEventsParams) {
+      return listEqual(events, other.events, (WatchEvent a, WatchEvent b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, events.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.handleWatchEvents result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisHandleWatchEventsResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisHandleWatchEventsResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 779767607;
+  }
+}
+
+/**
+ * analysis.highlights params
+ *
+ * {
+ *   "file": FilePath
+ *   "regions": List<HighlightRegion>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisHighlightsParams implements HasToJson {
+  String _file;
+
+  List<HighlightRegion> _regions;
+
+  /**
+   * The file containing the highlight regions.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the highlight regions.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The highlight regions contained in the file.
+   */
+  List<HighlightRegion> get regions => _regions;
+
+  /**
+   * The highlight regions contained in the file.
+   */
+  void set regions(List<HighlightRegion> value) {
+    assert(value != null);
+    this._regions = value;
+  }
+
+  AnalysisHighlightsParams(String file, List<HighlightRegion> regions) {
+    this.file = file;
+    this.regions = regions;
+  }
+
+  factory AnalysisHighlightsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      List<HighlightRegion> regions;
+      if (json.containsKey("regions")) {
+        regions = jsonDecoder.decodeList(jsonPath + ".regions", json["regions"], (String jsonPath, Object json) => new HighlightRegion.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "regions");
+      }
+      return new AnalysisHighlightsParams(file, regions);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.highlights params", json);
+    }
+  }
+
+  factory AnalysisHighlightsParams.fromNotification(Notification notification) {
+    return new AnalysisHighlightsParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["regions"] = regions.map((HighlightRegion value) => value.toJson()).toList();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("analysis.highlights", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisHighlightsParams) {
+      return file == other.file &&
+          listEqual(regions, other.regions, (HighlightRegion a, HighlightRegion b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, regions.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.navigation params
+ *
+ * {
+ *   "file": FilePath
+ *   "regions": List<NavigationRegion>
+ *   "targets": List<NavigationTarget>
+ *   "files": List<FilePath>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisNavigationParams implements HasToJson {
+  String _file;
+
+  List<NavigationRegion> _regions;
+
+  List<NavigationTarget> _targets;
+
+  List<String> _files;
+
+  /**
+   * The file containing the navigation regions.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the navigation regions.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The navigation regions contained in the file.
+   */
+  List<NavigationRegion> get regions => _regions;
+
+  /**
+   * The navigation regions contained in the file.
+   */
+  void set regions(List<NavigationRegion> value) {
+    assert(value != null);
+    this._regions = value;
+  }
+
+  /**
+   * The navigation targets referenced in the file. They are referenced by
+   * NavigationRegions by their index in this array.
+   */
+  List<NavigationTarget> get targets => _targets;
+
+  /**
+   * The navigation targets referenced in the file. They are referenced by
+   * NavigationRegions by their index in this array.
+   */
+  void set targets(List<NavigationTarget> value) {
+    assert(value != null);
+    this._targets = value;
+  }
+
+  /**
+   * The files containing navigation targets referenced in the file. They are
+   * referenced by NavigationTargets by their index in this array.
+   */
+  List<String> get files => _files;
+
+  /**
+   * The files containing navigation targets referenced in the file. They are
+   * referenced by NavigationTargets by their index in this array.
+   */
+  void set files(List<String> value) {
+    assert(value != null);
+    this._files = value;
+  }
+
+  AnalysisNavigationParams(String file, List<NavigationRegion> regions, List<NavigationTarget> targets, List<String> files) {
+    this.file = file;
+    this.regions = regions;
+    this.targets = targets;
+    this.files = files;
+  }
+
+  factory AnalysisNavigationParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      List<NavigationRegion> regions;
+      if (json.containsKey("regions")) {
+        regions = jsonDecoder.decodeList(jsonPath + ".regions", json["regions"], (String jsonPath, Object json) => new NavigationRegion.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "regions");
+      }
+      List<NavigationTarget> targets;
+      if (json.containsKey("targets")) {
+        targets = jsonDecoder.decodeList(jsonPath + ".targets", json["targets"], (String jsonPath, Object json) => new NavigationTarget.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "targets");
+      }
+      List<String> files;
+      if (json.containsKey("files")) {
+        files = jsonDecoder.decodeList(jsonPath + ".files", json["files"], jsonDecoder.decodeString);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "files");
+      }
+      return new AnalysisNavigationParams(file, regions, targets, files);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.navigation params", json);
+    }
+  }
+
+  factory AnalysisNavigationParams.fromNotification(Notification notification) {
+    return new AnalysisNavigationParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["regions"] = regions.map((NavigationRegion value) => value.toJson()).toList();
+    result["targets"] = targets.map((NavigationTarget value) => value.toJson()).toList();
+    result["files"] = files;
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("analysis.navigation", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisNavigationParams) {
+      return file == other.file &&
+          listEqual(regions, other.regions, (NavigationRegion a, NavigationRegion b) => a == b) &&
+          listEqual(targets, other.targets, (NavigationTarget a, NavigationTarget b) => a == b) &&
+          listEqual(files, other.files, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, regions.hashCode);
+    hash = JenkinsSmiHash.combine(hash, targets.hashCode);
+    hash = JenkinsSmiHash.combine(hash, files.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.occurrences params
+ *
+ * {
+ *   "file": FilePath
+ *   "occurrences": List<Occurrences>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisOccurrencesParams implements HasToJson {
+  String _file;
+
+  List<Occurrences> _occurrences;
+
+  /**
+   * The file in which the references occur.
+   */
+  String get file => _file;
+
+  /**
+   * The file in which the references occur.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The occurrences of references to elements within the file.
+   */
+  List<Occurrences> get occurrences => _occurrences;
+
+  /**
+   * The occurrences of references to elements within the file.
+   */
+  void set occurrences(List<Occurrences> value) {
+    assert(value != null);
+    this._occurrences = value;
+  }
+
+  AnalysisOccurrencesParams(String file, List<Occurrences> occurrences) {
+    this.file = file;
+    this.occurrences = occurrences;
+  }
+
+  factory AnalysisOccurrencesParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      List<Occurrences> occurrences;
+      if (json.containsKey("occurrences")) {
+        occurrences = jsonDecoder.decodeList(jsonPath + ".occurrences", json["occurrences"], (String jsonPath, Object json) => new Occurrences.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "occurrences");
+      }
+      return new AnalysisOccurrencesParams(file, occurrences);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.occurrences params", json);
+    }
+  }
+
+  factory AnalysisOccurrencesParams.fromNotification(Notification notification) {
+    return new AnalysisOccurrencesParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["occurrences"] = occurrences.map((Occurrences value) => value.toJson()).toList();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("analysis.occurrences", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisOccurrencesParams) {
+      return file == other.file &&
+          listEqual(occurrences, other.occurrences, (Occurrences a, Occurrences b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, occurrences.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.outline params
+ *
+ * {
+ *   "file": FilePath
+ *   "outline": List<Outline>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisOutlineParams implements HasToJson {
+  String _file;
+
+  List<Outline> _outline;
+
+  /**
+   * The file with which the outline is associated.
+   */
+  String get file => _file;
+
+  /**
+   * The file with which the outline is associated.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The outline fragments associated with the file.
+   */
+  List<Outline> get outline => _outline;
+
+  /**
+   * The outline fragments associated with the file.
+   */
+  void set outline(List<Outline> value) {
+    assert(value != null);
+    this._outline = value;
+  }
+
+  AnalysisOutlineParams(String file, List<Outline> outline) {
+    this.file = file;
+    this.outline = outline;
+  }
+
+  factory AnalysisOutlineParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      List<Outline> outline;
+      if (json.containsKey("outline")) {
+        outline = jsonDecoder.decodeList(jsonPath + ".outline", json["outline"], (String jsonPath, Object json) => new Outline.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "outline");
+      }
+      return new AnalysisOutlineParams(file, outline);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.outline params", json);
+    }
+  }
+
+  factory AnalysisOutlineParams.fromNotification(Notification notification) {
+    return new AnalysisOutlineParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["outline"] = outline.map((Outline value) => value.toJson()).toList();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("analysis.outline", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisOutlineParams) {
+      return file == other.file &&
+          listEqual(outline, other.outline, (Outline a, Outline b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, outline.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.reanalyze params
+ *
+ * {
+ *   "roots": optional List<FilePath>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisReanalyzeParams implements RequestParams {
+  List<String> _roots;
+
+  /**
+   * A list of the context roots that are to be re-analyzed.
+   *
+   * If no context roots are provided, then all current context roots should be
+   * re-analyzed.
+   */
+  List<String> get roots => _roots;
+
+  /**
+   * A list of the context roots that are to be re-analyzed.
+   *
+   * If no context roots are provided, then all current context roots should be
+   * re-analyzed.
+   */
+  void set roots(List<String> value) {
+    this._roots = value;
+  }
+
+  AnalysisReanalyzeParams({List<String> roots}) {
+    this.roots = roots;
+  }
+
+  factory AnalysisReanalyzeParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<String> roots;
+      if (json.containsKey("roots")) {
+        roots = jsonDecoder.decodeList(jsonPath + ".roots", json["roots"], jsonDecoder.decodeString);
+      }
+      return new AnalysisReanalyzeParams(roots: roots);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.reanalyze params", json);
+    }
+  }
+
+  factory AnalysisReanalyzeParams.fromRequest(Request request) {
+    return new AnalysisReanalyzeParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    if (roots != null) {
+      result["roots"] = roots;
+    }
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.reanalyze", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisReanalyzeParams) {
+      return listEqual(roots, other.roots, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, roots.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.reanalyze result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisReanalyzeResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisReanalyzeResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 846803925;
+  }
+}
+
+/**
+ * AnalysisService
+ *
+ * enum {
+ *   FOLDING
+ *   HIGHLIGHTS
+ *   NAVIGATION
+ *   OCCURRENCES
+ *   OUTLINE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisService implements Enum {
+  static const AnalysisService FOLDING = const AnalysisService._("FOLDING");
+
+  static const AnalysisService HIGHLIGHTS = const AnalysisService._("HIGHLIGHTS");
+
+  static const AnalysisService NAVIGATION = const AnalysisService._("NAVIGATION");
+
+  static const AnalysisService OCCURRENCES = const AnalysisService._("OCCURRENCES");
+
+  static const AnalysisService OUTLINE = const AnalysisService._("OUTLINE");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<AnalysisService> VALUES = const <AnalysisService>[FOLDING, HIGHLIGHTS, NAVIGATION, OCCURRENCES, OUTLINE];
+
+  @override
+  final String name;
+
+  const AnalysisService._(this.name);
+
+  factory AnalysisService(String name) {
+    switch (name) {
+      case "FOLDING":
+        return FOLDING;
+      case "HIGHLIGHTS":
+        return HIGHLIGHTS;
+      case "NAVIGATION":
+        return NAVIGATION;
+      case "OCCURRENCES":
+        return OCCURRENCES;
+      case "OUTLINE":
+        return OUTLINE;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory AnalysisService.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new AnalysisService(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "AnalysisService", json);
+  }
+
+  @override
+  String toString() => "AnalysisService.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * analysis.setContextBuilderOptions params
+ *
+ * {
+ *   "options": ContextBuilderOptions
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetContextBuilderOptionsParams implements RequestParams {
+  ContextBuilderOptions _options;
+
+  /**
+   * The options used to build the analysis contexts.
+   */
+  ContextBuilderOptions get options => _options;
+
+  /**
+   * The options used to build the analysis contexts.
+   */
+  void set options(ContextBuilderOptions value) {
+    assert(value != null);
+    this._options = value;
+  }
+
+  AnalysisSetContextBuilderOptionsParams(ContextBuilderOptions options) {
+    this.options = options;
+  }
+
+  factory AnalysisSetContextBuilderOptionsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      ContextBuilderOptions options;
+      if (json.containsKey("options")) {
+        options = new ContextBuilderOptions.fromJson(jsonDecoder, jsonPath + ".options", json["options"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "options");
+      }
+      return new AnalysisSetContextBuilderOptionsParams(options);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.setContextBuilderOptions params", json);
+    }
+  }
+
+  factory AnalysisSetContextBuilderOptionsParams.fromRequest(Request request) {
+    return new AnalysisSetContextBuilderOptionsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["options"] = options.toJson();
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.setContextBuilderOptions", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetContextBuilderOptionsParams) {
+      return options == other.options;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, options.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.setContextBuilderOptions result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetContextBuilderOptionsResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetContextBuilderOptionsResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 645412314;
+  }
+}
+
+/**
+ * analysis.setContextRoots params
+ *
+ * {
+ *   "roots": List<ContextRoot>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetContextRootsParams implements RequestParams {
+  List<ContextRoot> _roots;
+
+  /**
+   * A list of the context roots that should be analyzed.
+   */
+  List<ContextRoot> get roots => _roots;
+
+  /**
+   * A list of the context roots that should be analyzed.
+   */
+  void set roots(List<ContextRoot> value) {
+    assert(value != null);
+    this._roots = value;
+  }
+
+  AnalysisSetContextRootsParams(List<ContextRoot> roots) {
+    this.roots = roots;
+  }
+
+  factory AnalysisSetContextRootsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<ContextRoot> roots;
+      if (json.containsKey("roots")) {
+        roots = jsonDecoder.decodeList(jsonPath + ".roots", json["roots"], (String jsonPath, Object json) => new ContextRoot.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "roots");
+      }
+      return new AnalysisSetContextRootsParams(roots);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.setContextRoots params", json);
+    }
+  }
+
+  factory AnalysisSetContextRootsParams.fromRequest(Request request) {
+    return new AnalysisSetContextRootsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["roots"] = roots.map((ContextRoot value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.setContextRoots", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetContextRootsParams) {
+      return listEqual(roots, other.roots, (ContextRoot a, ContextRoot b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, roots.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.setContextRoots result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetContextRootsResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetContextRootsResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 969645618;
+  }
+}
+
+/**
+ * analysis.setPriorityFiles params
+ *
+ * {
+ *   "files": List<FilePath>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetPriorityFilesParams implements RequestParams {
+  List<String> _files;
+
+  /**
+   * The files that are to be a priority for analysis.
+   */
+  List<String> get files => _files;
+
+  /**
+   * The files that are to be a priority for analysis.
+   */
+  void set files(List<String> value) {
+    assert(value != null);
+    this._files = value;
+  }
+
+  AnalysisSetPriorityFilesParams(List<String> files) {
+    this.files = files;
+  }
+
+  factory AnalysisSetPriorityFilesParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<String> files;
+      if (json.containsKey("files")) {
+        files = jsonDecoder.decodeList(jsonPath + ".files", json["files"], jsonDecoder.decodeString);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "files");
+      }
+      return new AnalysisSetPriorityFilesParams(files);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.setPriorityFiles params", json);
+    }
+  }
+
+  factory AnalysisSetPriorityFilesParams.fromRequest(Request request) {
+    return new AnalysisSetPriorityFilesParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["files"] = files;
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.setPriorityFiles", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetPriorityFilesParams) {
+      return listEqual(files, other.files, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, files.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.setPriorityFiles result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetPriorityFilesResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetPriorityFilesResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 330050055;
+  }
+}
+
+/**
+ * analysis.setSubscriptions params
+ *
+ * {
+ *   "subscriptions": Map<AnalysisService, List<FilePath>>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetSubscriptionsParams implements RequestParams {
+  Map<AnalysisService, List<String>> _subscriptions;
+
+  /**
+   * A table mapping services to a list of the files being subscribed to the
+   * service.
+   */
+  Map<AnalysisService, List<String>> get subscriptions => _subscriptions;
+
+  /**
+   * A table mapping services to a list of the files being subscribed to the
+   * service.
+   */
+  void set subscriptions(Map<AnalysisService, List<String>> value) {
+    assert(value != null);
+    this._subscriptions = value;
+  }
+
+  AnalysisSetSubscriptionsParams(Map<AnalysisService, List<String>> subscriptions) {
+    this.subscriptions = subscriptions;
+  }
+
+  factory AnalysisSetSubscriptionsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      Map<AnalysisService, List<String>> subscriptions;
+      if (json.containsKey("subscriptions")) {
+        subscriptions = jsonDecoder.decodeMap(jsonPath + ".subscriptions", json["subscriptions"], keyDecoder: (String jsonPath, Object json) => new AnalysisService.fromJson(jsonDecoder, jsonPath, json), valueDecoder: (String jsonPath, Object json) => jsonDecoder.decodeList(jsonPath, json, jsonDecoder.decodeString));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "subscriptions");
+      }
+      return new AnalysisSetSubscriptionsParams(subscriptions);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.setSubscriptions params", json);
+    }
+  }
+
+  factory AnalysisSetSubscriptionsParams.fromRequest(Request request) {
+    return new AnalysisSetSubscriptionsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["subscriptions"] = mapMap(subscriptions, keyCallback: (AnalysisService value) => value.toJson());
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.setSubscriptions", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetSubscriptionsParams) {
+      return mapEqual(subscriptions, other.subscriptions, (List<String> a, List<String> b) => listEqual(a, b, (String a, String b) => a == b));
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, subscriptions.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.setSubscriptions result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisSetSubscriptionsResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisSetSubscriptionsResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 218088493;
+  }
+}
+
+/**
+ * analysis.updateContent params
+ *
+ * {
+ *   "files": Map<FilePath, AddContentOverlay | ChangeContentOverlay | RemoveContentOverlay>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisUpdateContentParams implements RequestParams {
+  Map<String, dynamic> _files;
+
+  /**
+   * A table mapping the files whose content has changed to a description of
+   * the content change.
+   */
+  Map<String, dynamic> get files => _files;
+
+  /**
+   * A table mapping the files whose content has changed to a description of
+   * the content change.
+   */
+  void set files(Map<String, dynamic> value) {
+    assert(value != null);
+    this._files = value;
+  }
+
+  AnalysisUpdateContentParams(Map<String, dynamic> files) {
+    this.files = files;
+  }
+
+  factory AnalysisUpdateContentParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      Map<String, dynamic> files;
+      if (json.containsKey("files")) {
+        files = jsonDecoder.decodeMap(jsonPath + ".files", json["files"], valueDecoder: (String jsonPath, Object json) => jsonDecoder.decodeUnion(jsonPath, json, "type", {"add": (String jsonPath, Object json) => new AddContentOverlay.fromJson(jsonDecoder, jsonPath, json), "change": (String jsonPath, Object json) => new ChangeContentOverlay.fromJson(jsonDecoder, jsonPath, json), "remove": (String jsonPath, Object json) => new RemoveContentOverlay.fromJson(jsonDecoder, jsonPath, json)}));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "files");
+      }
+      return new AnalysisUpdateContentParams(files);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.updateContent params", json);
+    }
+  }
+
+  factory AnalysisUpdateContentParams.fromRequest(Request request) {
+    return new AnalysisUpdateContentParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["files"] = mapMap(files, valueCallback: (dynamic value) => value.toJson());
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "analysis.updateContent", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisUpdateContentParams) {
+      return mapEqual(files, other.files, (dynamic a, dynamic b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, files.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.updateContent result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisUpdateContentResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisUpdateContentResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 468798730;
+  }
+}
+
+/**
+ * ChangeContentOverlay
+ *
+ * {
+ *   "type": "change"
+ *   "edits": List<SourceEdit>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ChangeContentOverlay implements HasToJson {
+  List<SourceEdit> _edits;
+
+  /**
+   * The edits to be applied to the file.
+   */
+  List<SourceEdit> get edits => _edits;
+
+  /**
+   * The edits to be applied to the file.
+   */
+  void set edits(List<SourceEdit> value) {
+    assert(value != null);
+    this._edits = value;
+  }
+
+  ChangeContentOverlay(List<SourceEdit> edits) {
+    this.edits = edits;
+  }
+
+  factory ChangeContentOverlay.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      if (json["type"] != "change") {
+        throw jsonDecoder.mismatch(jsonPath, "equal " + "change", json);
+      }
+      List<SourceEdit> edits;
+      if (json.containsKey("edits")) {
+        edits = jsonDecoder.decodeList(jsonPath + ".edits", json["edits"], (String jsonPath, Object json) => new SourceEdit.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "edits");
+      }
+      return new ChangeContentOverlay(edits);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "ChangeContentOverlay", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["type"] = "change";
+    result["edits"] = edits.map((SourceEdit value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ChangeContentOverlay) {
+      return listEqual(edits, other.edits, (SourceEdit a, SourceEdit b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, 873118866);
+    hash = JenkinsSmiHash.combine(hash, edits.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * completion.getSuggestions params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class CompletionGetSuggestionsParams implements RequestParams {
+  String _file;
+
+  int _offset;
+
+  /**
+   * The file containing the point at which suggestions are to be made.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the point at which suggestions are to be made.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset within the file at which suggestions are to be made.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset within the file at which suggestions are to be made.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  CompletionGetSuggestionsParams(String file, int offset) {
+    this.file = file;
+    this.offset = offset;
+  }
+
+  factory CompletionGetSuggestionsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      return new CompletionGetSuggestionsParams(file, offset);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "completion.getSuggestions params", json);
+    }
+  }
+
+  factory CompletionGetSuggestionsParams.fromRequest(Request request) {
+    return new CompletionGetSuggestionsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["offset"] = offset;
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "completion.getSuggestions", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is CompletionGetSuggestionsParams) {
+      return file == other.file &&
+          offset == other.offset;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * completion.getSuggestions result
+ *
+ * {
+ *   "replacementOffset": int
+ *   "replacementLength": int
+ *   "results": List<CompletionSuggestion>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class CompletionGetSuggestionsResult implements ResponseResult {
+  int _replacementOffset;
+
+  int _replacementLength;
+
+  List<CompletionSuggestion> _results;
+
+  /**
+   * The offset of the start of the text to be replaced. This will be different
+   * than the offset used to request the completion suggestions if there was a
+   * portion of an identifier before the original offset. In particular, the
+   * replacementOffset will be the offset of the beginning of said identifier.
+   */
+  int get replacementOffset => _replacementOffset;
+
+  /**
+   * The offset of the start of the text to be replaced. This will be different
+   * than the offset used to request the completion suggestions if there was a
+   * portion of an identifier before the original offset. In particular, the
+   * replacementOffset will be the offset of the beginning of said identifier.
+   */
+  void set replacementOffset(int value) {
+    assert(value != null);
+    this._replacementOffset = value;
+  }
+
+  /**
+   * The length of the text to be replaced if the remainder of the identifier
+   * containing the cursor is to be replaced when the suggestion is applied
+   * (that is, the number of characters in the existing identifier).
+   */
+  int get replacementLength => _replacementLength;
+
+  /**
+   * The length of the text to be replaced if the remainder of the identifier
+   * containing the cursor is to be replaced when the suggestion is applied
+   * (that is, the number of characters in the existing identifier).
+   */
+  void set replacementLength(int value) {
+    assert(value != null);
+    this._replacementLength = value;
+  }
+
+  /**
+   * The completion suggestions being reported. The notification contains all
+   * possible completions at the requested cursor position, even those that do
+   * not match the characters the user has already typed. This allows the
+   * client to respond to further keystrokes from the user without having to
+   * make additional requests.
+   */
+  List<CompletionSuggestion> get results => _results;
+
+  /**
+   * The completion suggestions being reported. The notification contains all
+   * possible completions at the requested cursor position, even those that do
+   * not match the characters the user has already typed. This allows the
+   * client to respond to further keystrokes from the user without having to
+   * make additional requests.
+   */
+  void set results(List<CompletionSuggestion> value) {
+    assert(value != null);
+    this._results = value;
+  }
+
+  CompletionGetSuggestionsResult(int replacementOffset, int replacementLength, List<CompletionSuggestion> results) {
+    this.replacementOffset = replacementOffset;
+    this.replacementLength = replacementLength;
+    this.results = results;
+  }
+
+  factory CompletionGetSuggestionsResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int replacementOffset;
+      if (json.containsKey("replacementOffset")) {
+        replacementOffset = jsonDecoder.decodeInt(jsonPath + ".replacementOffset", json["replacementOffset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "replacementOffset");
+      }
+      int replacementLength;
+      if (json.containsKey("replacementLength")) {
+        replacementLength = jsonDecoder.decodeInt(jsonPath + ".replacementLength", json["replacementLength"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "replacementLength");
+      }
+      List<CompletionSuggestion> results;
+      if (json.containsKey("results")) {
+        results = jsonDecoder.decodeList(jsonPath + ".results", json["results"], (String jsonPath, Object json) => new CompletionSuggestion.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "results");
+      }
+      return new CompletionGetSuggestionsResult(replacementOffset, replacementLength, results);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "completion.getSuggestions result", json);
+    }
+  }
+
+  factory CompletionGetSuggestionsResult.fromResponse(Response response) {
+    return new CompletionGetSuggestionsResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response.result);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["replacementOffset"] = replacementOffset;
+    result["replacementLength"] = replacementLength;
+    result["results"] = results.map((CompletionSuggestion value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is CompletionGetSuggestionsResult) {
+      return replacementOffset == other.replacementOffset &&
+          replacementLength == other.replacementLength &&
+          listEqual(results, other.results, (CompletionSuggestion a, CompletionSuggestion b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, replacementOffset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, replacementLength.hashCode);
+    hash = JenkinsSmiHash.combine(hash, results.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * CompletionSuggestion
+ *
+ * {
+ *   "kind": CompletionSuggestionKind
+ *   "relevance": int
+ *   "completion": String
+ *   "selectionOffset": int
+ *   "selectionLength": int
+ *   "isDeprecated": bool
+ *   "isPotential": bool
+ *   "docSummary": optional String
+ *   "docComplete": optional String
+ *   "declaringType": optional String
+ *   "element": optional Element
+ *   "returnType": optional String
+ *   "parameterNames": optional List<String>
+ *   "parameterTypes": optional List<String>
+ *   "requiredParameterCount": optional int
+ *   "hasNamedParameters": optional bool
+ *   "parameterName": optional String
+ *   "parameterType": optional String
+ *   "importUri": optional String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class CompletionSuggestion implements HasToJson {
+  CompletionSuggestionKind _kind;
+
+  int _relevance;
+
+  String _completion;
+
+  int _selectionOffset;
+
+  int _selectionLength;
+
+  bool _isDeprecated;
+
+  bool _isPotential;
+
+  String _docSummary;
+
+  String _docComplete;
+
+  String _declaringType;
+
+  Element _element;
+
+  String _returnType;
+
+  List<String> _parameterNames;
+
+  List<String> _parameterTypes;
+
+  int _requiredParameterCount;
+
+  bool _hasNamedParameters;
+
+  String _parameterName;
+
+  String _parameterType;
+
+  String _importUri;
+
+  /**
+   * The kind of element being suggested.
+   */
+  CompletionSuggestionKind get kind => _kind;
+
+  /**
+   * The kind of element being suggested.
+   */
+  void set kind(CompletionSuggestionKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The relevance of this completion suggestion where a higher number
+   * indicates a higher relevance.
+   */
+  int get relevance => _relevance;
+
+  /**
+   * The relevance of this completion suggestion where a higher number
+   * indicates a higher relevance.
+   */
+  void set relevance(int value) {
+    assert(value != null);
+    this._relevance = value;
+  }
+
+  /**
+   * The identifier to be inserted if the suggestion is selected. If the
+   * suggestion is for a method or function, the client might want to
+   * additionally insert a template for the parameters. The information
+   * required in order to do so is contained in other fields.
+   */
+  String get completion => _completion;
+
+  /**
+   * The identifier to be inserted if the suggestion is selected. If the
+   * suggestion is for a method or function, the client might want to
+   * additionally insert a template for the parameters. The information
+   * required in order to do so is contained in other fields.
+   */
+  void set completion(String value) {
+    assert(value != null);
+    this._completion = value;
+  }
+
+  /**
+   * The offset, relative to the beginning of the completion, of where the
+   * selection should be placed after insertion.
+   */
+  int get selectionOffset => _selectionOffset;
+
+  /**
+   * The offset, relative to the beginning of the completion, of where the
+   * selection should be placed after insertion.
+   */
+  void set selectionOffset(int value) {
+    assert(value != null);
+    this._selectionOffset = value;
+  }
+
+  /**
+   * The number of characters that should be selected after insertion.
+   */
+  int get selectionLength => _selectionLength;
+
+  /**
+   * The number of characters that should be selected after insertion.
+   */
+  void set selectionLength(int value) {
+    assert(value != null);
+    this._selectionLength = value;
+  }
+
+  /**
+   * True if the suggested element is deprecated.
+   */
+  bool get isDeprecated => _isDeprecated;
+
+  /**
+   * True if the suggested element is deprecated.
+   */
+  void set isDeprecated(bool value) {
+    assert(value != null);
+    this._isDeprecated = value;
+  }
+
+  /**
+   * True if the element is not known to be valid for the target. This happens
+   * if the type of the target is dynamic.
+   */
+  bool get isPotential => _isPotential;
+
+  /**
+   * True if the element is not known to be valid for the target. This happens
+   * if the type of the target is dynamic.
+   */
+  void set isPotential(bool value) {
+    assert(value != null);
+    this._isPotential = value;
+  }
+
+  /**
+   * An abbreviated version of the Dartdoc associated with the element being
+   * suggested, This field is omitted if there is no Dartdoc associated with
+   * the element.
+   */
+  String get docSummary => _docSummary;
+
+  /**
+   * An abbreviated version of the Dartdoc associated with the element being
+   * suggested, This field is omitted if there is no Dartdoc associated with
+   * the element.
+   */
+  void set docSummary(String value) {
+    this._docSummary = value;
+  }
+
+  /**
+   * The Dartdoc associated with the element being suggested. This field is
+   * omitted if there is no Dartdoc associated with the element.
+   */
+  String get docComplete => _docComplete;
+
+  /**
+   * The Dartdoc associated with the element being suggested. This field is
+   * omitted if there is no Dartdoc associated with the element.
+   */
+  void set docComplete(String value) {
+    this._docComplete = value;
+  }
+
+  /**
+   * The class that declares the element being suggested. This field is omitted
+   * if the suggested element is not a member of a class.
+   */
+  String get declaringType => _declaringType;
+
+  /**
+   * The class that declares the element being suggested. This field is omitted
+   * if the suggested element is not a member of a class.
+   */
+  void set declaringType(String value) {
+    this._declaringType = value;
+  }
+
+  /**
+   * Information about the element reference being suggested.
+   */
+  Element get element => _element;
+
+  /**
+   * Information about the element reference being suggested.
+   */
+  void set element(Element value) {
+    this._element = value;
+  }
+
+  /**
+   * The return type of the getter, function or method or the type of the field
+   * being suggested. This field is omitted if the suggested element is not a
+   * getter, function or method.
+   */
+  String get returnType => _returnType;
+
+  /**
+   * The return type of the getter, function or method or the type of the field
+   * being suggested. This field is omitted if the suggested element is not a
+   * getter, function or method.
+   */
+  void set returnType(String value) {
+    this._returnType = value;
+  }
+
+  /**
+   * The names of the parameters of the function or method being suggested.
+   * This field is omitted if the suggested element is not a setter, function
+   * or method.
+   */
+  List<String> get parameterNames => _parameterNames;
+
+  /**
+   * The names of the parameters of the function or method being suggested.
+   * This field is omitted if the suggested element is not a setter, function
+   * or method.
+   */
+  void set parameterNames(List<String> value) {
+    this._parameterNames = value;
+  }
+
+  /**
+   * The types of the parameters of the function or method being suggested.
+   * This field is omitted if the parameterNames field is omitted.
+   */
+  List<String> get parameterTypes => _parameterTypes;
+
+  /**
+   * The types of the parameters of the function or method being suggested.
+   * This field is omitted if the parameterNames field is omitted.
+   */
+  void set parameterTypes(List<String> value) {
+    this._parameterTypes = value;
+  }
+
+  /**
+   * The number of required parameters for the function or method being
+   * suggested. This field is omitted if the parameterNames field is omitted.
+   */
+  int get requiredParameterCount => _requiredParameterCount;
+
+  /**
+   * The number of required parameters for the function or method being
+   * suggested. This field is omitted if the parameterNames field is omitted.
+   */
+  void set requiredParameterCount(int value) {
+    this._requiredParameterCount = value;
+  }
+
+  /**
+   * True if the function or method being suggested has at least one named
+   * parameter. This field is omitted if the parameterNames field is omitted.
+   */
+  bool get hasNamedParameters => _hasNamedParameters;
+
+  /**
+   * True if the function or method being suggested has at least one named
+   * parameter. This field is omitted if the parameterNames field is omitted.
+   */
+  void set hasNamedParameters(bool value) {
+    this._hasNamedParameters = value;
+  }
+
+  /**
+   * The name of the optional parameter being suggested. This field is omitted
+   * if the suggestion is not the addition of an optional argument within an
+   * argument list.
+   */
+  String get parameterName => _parameterName;
+
+  /**
+   * The name of the optional parameter being suggested. This field is omitted
+   * if the suggestion is not the addition of an optional argument within an
+   * argument list.
+   */
+  void set parameterName(String value) {
+    this._parameterName = value;
+  }
+
+  /**
+   * The type of the options parameter being suggested. This field is omitted
+   * if the parameterName field is omitted.
+   */
+  String get parameterType => _parameterType;
+
+  /**
+   * The type of the options parameter being suggested. This field is omitted
+   * if the parameterName field is omitted.
+   */
+  void set parameterType(String value) {
+    this._parameterType = value;
+  }
+
+  /**
+   * The import to be added if the suggestion is out of scope and needs an
+   * import to be added to be in scope.
+   */
+  String get importUri => _importUri;
+
+  /**
+   * The import to be added if the suggestion is out of scope and needs an
+   * import to be added to be in scope.
+   */
+  void set importUri(String value) {
+    this._importUri = value;
+  }
+
+  CompletionSuggestion(CompletionSuggestionKind kind, int relevance, String completion, int selectionOffset, int selectionLength, bool isDeprecated, bool isPotential, {String docSummary, String docComplete, String declaringType, Element element, String returnType, List<String> parameterNames, List<String> parameterTypes, int requiredParameterCount, bool hasNamedParameters, String parameterName, String parameterType, String importUri}) {
+    this.kind = kind;
+    this.relevance = relevance;
+    this.completion = completion;
+    this.selectionOffset = selectionOffset;
+    this.selectionLength = selectionLength;
+    this.isDeprecated = isDeprecated;
+    this.isPotential = isPotential;
+    this.docSummary = docSummary;
+    this.docComplete = docComplete;
+    this.declaringType = declaringType;
+    this.element = element;
+    this.returnType = returnType;
+    this.parameterNames = parameterNames;
+    this.parameterTypes = parameterTypes;
+    this.requiredParameterCount = requiredParameterCount;
+    this.hasNamedParameters = hasNamedParameters;
+    this.parameterName = parameterName;
+    this.parameterType = parameterType;
+    this.importUri = importUri;
+  }
+
+  factory CompletionSuggestion.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      CompletionSuggestionKind kind;
+      if (json.containsKey("kind")) {
+        kind = new CompletionSuggestionKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      int relevance;
+      if (json.containsKey("relevance")) {
+        relevance = jsonDecoder.decodeInt(jsonPath + ".relevance", json["relevance"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "relevance");
+      }
+      String completion;
+      if (json.containsKey("completion")) {
+        completion = jsonDecoder.decodeString(jsonPath + ".completion", json["completion"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "completion");
+      }
+      int selectionOffset;
+      if (json.containsKey("selectionOffset")) {
+        selectionOffset = jsonDecoder.decodeInt(jsonPath + ".selectionOffset", json["selectionOffset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "selectionOffset");
+      }
+      int selectionLength;
+      if (json.containsKey("selectionLength")) {
+        selectionLength = jsonDecoder.decodeInt(jsonPath + ".selectionLength", json["selectionLength"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "selectionLength");
+      }
+      bool isDeprecated;
+      if (json.containsKey("isDeprecated")) {
+        isDeprecated = jsonDecoder.decodeBool(jsonPath + ".isDeprecated", json["isDeprecated"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "isDeprecated");
+      }
+      bool isPotential;
+      if (json.containsKey("isPotential")) {
+        isPotential = jsonDecoder.decodeBool(jsonPath + ".isPotential", json["isPotential"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "isPotential");
+      }
+      String docSummary;
+      if (json.containsKey("docSummary")) {
+        docSummary = jsonDecoder.decodeString(jsonPath + ".docSummary", json["docSummary"]);
+      }
+      String docComplete;
+      if (json.containsKey("docComplete")) {
+        docComplete = jsonDecoder.decodeString(jsonPath + ".docComplete", json["docComplete"]);
+      }
+      String declaringType;
+      if (json.containsKey("declaringType")) {
+        declaringType = jsonDecoder.decodeString(jsonPath + ".declaringType", json["declaringType"]);
+      }
+      Element element;
+      if (json.containsKey("element")) {
+        element = new Element.fromJson(jsonDecoder, jsonPath + ".element", json["element"]);
+      }
+      String returnType;
+      if (json.containsKey("returnType")) {
+        returnType = jsonDecoder.decodeString(jsonPath + ".returnType", json["returnType"]);
+      }
+      List<String> parameterNames;
+      if (json.containsKey("parameterNames")) {
+        parameterNames = jsonDecoder.decodeList(jsonPath + ".parameterNames", json["parameterNames"], jsonDecoder.decodeString);
+      }
+      List<String> parameterTypes;
+      if (json.containsKey("parameterTypes")) {
+        parameterTypes = jsonDecoder.decodeList(jsonPath + ".parameterTypes", json["parameterTypes"], jsonDecoder.decodeString);
+      }
+      int requiredParameterCount;
+      if (json.containsKey("requiredParameterCount")) {
+        requiredParameterCount = jsonDecoder.decodeInt(jsonPath + ".requiredParameterCount", json["requiredParameterCount"]);
+      }
+      bool hasNamedParameters;
+      if (json.containsKey("hasNamedParameters")) {
+        hasNamedParameters = jsonDecoder.decodeBool(jsonPath + ".hasNamedParameters", json["hasNamedParameters"]);
+      }
+      String parameterName;
+      if (json.containsKey("parameterName")) {
+        parameterName = jsonDecoder.decodeString(jsonPath + ".parameterName", json["parameterName"]);
+      }
+      String parameterType;
+      if (json.containsKey("parameterType")) {
+        parameterType = jsonDecoder.decodeString(jsonPath + ".parameterType", json["parameterType"]);
+      }
+      String importUri;
+      if (json.containsKey("importUri")) {
+        importUri = jsonDecoder.decodeString(jsonPath + ".importUri", json["importUri"]);
+      }
+      return new CompletionSuggestion(kind, relevance, completion, selectionOffset, selectionLength, isDeprecated, isPotential, docSummary: docSummary, docComplete: docComplete, declaringType: declaringType, element: element, returnType: returnType, parameterNames: parameterNames, parameterTypes: parameterTypes, requiredParameterCount: requiredParameterCount, hasNamedParameters: hasNamedParameters, parameterName: parameterName, parameterType: parameterType, importUri: importUri);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "CompletionSuggestion", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["kind"] = kind.toJson();
+    result["relevance"] = relevance;
+    result["completion"] = completion;
+    result["selectionOffset"] = selectionOffset;
+    result["selectionLength"] = selectionLength;
+    result["isDeprecated"] = isDeprecated;
+    result["isPotential"] = isPotential;
+    if (docSummary != null) {
+      result["docSummary"] = docSummary;
+    }
+    if (docComplete != null) {
+      result["docComplete"] = docComplete;
+    }
+    if (declaringType != null) {
+      result["declaringType"] = declaringType;
+    }
+    if (element != null) {
+      result["element"] = element.toJson();
+    }
+    if (returnType != null) {
+      result["returnType"] = returnType;
+    }
+    if (parameterNames != null) {
+      result["parameterNames"] = parameterNames;
+    }
+    if (parameterTypes != null) {
+      result["parameterTypes"] = parameterTypes;
+    }
+    if (requiredParameterCount != null) {
+      result["requiredParameterCount"] = requiredParameterCount;
+    }
+    if (hasNamedParameters != null) {
+      result["hasNamedParameters"] = hasNamedParameters;
+    }
+    if (parameterName != null) {
+      result["parameterName"] = parameterName;
+    }
+    if (parameterType != null) {
+      result["parameterType"] = parameterType;
+    }
+    if (importUri != null) {
+      result["importUri"] = importUri;
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is CompletionSuggestion) {
+      return kind == other.kind &&
+          relevance == other.relevance &&
+          completion == other.completion &&
+          selectionOffset == other.selectionOffset &&
+          selectionLength == other.selectionLength &&
+          isDeprecated == other.isDeprecated &&
+          isPotential == other.isPotential &&
+          docSummary == other.docSummary &&
+          docComplete == other.docComplete &&
+          declaringType == other.declaringType &&
+          element == other.element &&
+          returnType == other.returnType &&
+          listEqual(parameterNames, other.parameterNames, (String a, String b) => a == b) &&
+          listEqual(parameterTypes, other.parameterTypes, (String a, String b) => a == b) &&
+          requiredParameterCount == other.requiredParameterCount &&
+          hasNamedParameters == other.hasNamedParameters &&
+          parameterName == other.parameterName &&
+          parameterType == other.parameterType &&
+          importUri == other.importUri;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, relevance.hashCode);
+    hash = JenkinsSmiHash.combine(hash, completion.hashCode);
+    hash = JenkinsSmiHash.combine(hash, selectionOffset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, selectionLength.hashCode);
+    hash = JenkinsSmiHash.combine(hash, isDeprecated.hashCode);
+    hash = JenkinsSmiHash.combine(hash, isPotential.hashCode);
+    hash = JenkinsSmiHash.combine(hash, docSummary.hashCode);
+    hash = JenkinsSmiHash.combine(hash, docComplete.hashCode);
+    hash = JenkinsSmiHash.combine(hash, declaringType.hashCode);
+    hash = JenkinsSmiHash.combine(hash, element.hashCode);
+    hash = JenkinsSmiHash.combine(hash, returnType.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameterNames.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameterTypes.hashCode);
+    hash = JenkinsSmiHash.combine(hash, requiredParameterCount.hashCode);
+    hash = JenkinsSmiHash.combine(hash, hasNamedParameters.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameterName.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameterType.hashCode);
+    hash = JenkinsSmiHash.combine(hash, importUri.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * CompletionSuggestionKind
+ *
+ * enum {
+ *   ARGUMENT_LIST
+ *   IMPORT
+ *   IDENTIFIER
+ *   INVOCATION
+ *   KEYWORD
+ *   NAMED_ARGUMENT
+ *   OPTIONAL_ARGUMENT
+ *   PARAMETER
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class CompletionSuggestionKind implements Enum {
+  /**
+   * A list of arguments for the method or function that is being invoked. For
+   * this suggestion kind, the completion field is a textual representation of
+   * the invocation and the parameterNames, parameterTypes, and
+   * requiredParameterCount attributes are defined.
+   */
+  static const CompletionSuggestionKind ARGUMENT_LIST = const CompletionSuggestionKind._("ARGUMENT_LIST");
+
+  static const CompletionSuggestionKind IMPORT = const CompletionSuggestionKind._("IMPORT");
+
+  /**
+   * The element identifier should be inserted at the completion location. For
+   * example "someMethod" in import 'myLib.dart' show someMethod;. For
+   * suggestions of this kind, the element attribute is defined and the
+   * completion field is the element's identifier.
+   */
+  static const CompletionSuggestionKind IDENTIFIER = const CompletionSuggestionKind._("IDENTIFIER");
+
+  /**
+   * The element is being invoked at the completion location. For example,
+   * 'someMethod' in x.someMethod();. For suggestions of this kind, the element
+   * attribute is defined and the completion field is the element's identifier.
+   */
+  static const CompletionSuggestionKind INVOCATION = const CompletionSuggestionKind._("INVOCATION");
+
+  /**
+   * A keyword is being suggested. For suggestions of this kind, the completion
+   * is the keyword.
+   */
+  static const CompletionSuggestionKind KEYWORD = const CompletionSuggestionKind._("KEYWORD");
+
+  /**
+   * A named argument for the current call site is being suggested. For
+   * suggestions of this kind, the completion is the named argument identifier
+   * including a trailing ':' and a space.
+   */
+  static const CompletionSuggestionKind NAMED_ARGUMENT = const CompletionSuggestionKind._("NAMED_ARGUMENT");
+
+  static const CompletionSuggestionKind OPTIONAL_ARGUMENT = const CompletionSuggestionKind._("OPTIONAL_ARGUMENT");
+
+  static const CompletionSuggestionKind PARAMETER = const CompletionSuggestionKind._("PARAMETER");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<CompletionSuggestionKind> VALUES = const <CompletionSuggestionKind>[ARGUMENT_LIST, IMPORT, IDENTIFIER, INVOCATION, KEYWORD, NAMED_ARGUMENT, OPTIONAL_ARGUMENT, PARAMETER];
+
+  @override
+  final String name;
+
+  const CompletionSuggestionKind._(this.name);
+
+  factory CompletionSuggestionKind(String name) {
+    switch (name) {
+      case "ARGUMENT_LIST":
+        return ARGUMENT_LIST;
+      case "IMPORT":
+        return IMPORT;
+      case "IDENTIFIER":
+        return IDENTIFIER;
+      case "INVOCATION":
+        return INVOCATION;
+      case "KEYWORD":
+        return KEYWORD;
+      case "NAMED_ARGUMENT":
+        return NAMED_ARGUMENT;
+      case "OPTIONAL_ARGUMENT":
+        return OPTIONAL_ARGUMENT;
+      case "PARAMETER":
+        return PARAMETER;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory CompletionSuggestionKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new CompletionSuggestionKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "CompletionSuggestionKind", json);
+  }
+
+  @override
+  String toString() => "CompletionSuggestionKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * ContextBuilderOptions
+ *
+ * {
+ *   "dartSdkSummaryPath": optional String
+ *   "defaultAnalysisOptionsFilePath": optional List<String>
+ *   "declaredVariables": optional Map<String, String>
+ *   "defaultPackageFilePath": optional List<String>
+ *   "defaultPackagesDirectoryPath": optional List<String>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ContextBuilderOptions implements HasToJson {
+  String _dartSdkSummaryPath;
+
+  List<String> _defaultAnalysisOptionsFilePath;
+
+  Map<String, String> _declaredVariables;
+
+  List<String> _defaultPackageFilePath;
+
+  List<String> _defaultPackagesDirectoryPath;
+
+  /**
+   * The file path of the file containing the summary of the SDK that should be
+   * used to "analyze" the SDK. The field will be omitted if the summary should
+   * be found in the SDK.
+   */
+  String get dartSdkSummaryPath => _dartSdkSummaryPath;
+
+  /**
+   * The file path of the file containing the summary of the SDK that should be
+   * used to "analyze" the SDK. The field will be omitted if the summary should
+   * be found in the SDK.
+   */
+  void set dartSdkSummaryPath(String value) {
+    this._dartSdkSummaryPath = value;
+  }
+
+  /**
+   * The file path of the analysis options file that should be used in place of
+   * any file in the root directory or a parent of the root directory. The
+   * field will be omitted if the normal lookup mechanism should be used.
+   */
+  List<String> get defaultAnalysisOptionsFilePath => _defaultAnalysisOptionsFilePath;
+
+  /**
+   * The file path of the analysis options file that should be used in place of
+   * any file in the root directory or a parent of the root directory. The
+   * field will be omitted if the normal lookup mechanism should be used.
+   */
+  void set defaultAnalysisOptionsFilePath(List<String> value) {
+    this._defaultAnalysisOptionsFilePath = value;
+  }
+
+  /**
+   * A table mapping variable names to values for the declared variables. The
+   * field will be omitted if no additional variables need to be declared.
+   */
+  Map<String, String> get declaredVariables => _declaredVariables;
+
+  /**
+   * A table mapping variable names to values for the declared variables. The
+   * field will be omitted if no additional variables need to be declared.
+   */
+  void set declaredVariables(Map<String, String> value) {
+    this._declaredVariables = value;
+  }
+
+  /**
+   * The file path of the .packages file that should be used in place of any
+   * file found using the normal (Package Specification DEP) lookup mechanism.
+   * The field will be omitted if the normal lookup mechanism should be used.
+   */
+  List<String> get defaultPackageFilePath => _defaultPackageFilePath;
+
+  /**
+   * The file path of the .packages file that should be used in place of any
+   * file found using the normal (Package Specification DEP) lookup mechanism.
+   * The field will be omitted if the normal lookup mechanism should be used.
+   */
+  void set defaultPackageFilePath(List<String> value) {
+    this._defaultPackageFilePath = value;
+  }
+
+  /**
+   * The file path of the packages directory that should be used in place of
+   * any file found using the normal (Package Specification DEP) lookup
+   * mechanism. The field will be omitted if the normal lookup mechanism should
+   * be used.
+   */
+  List<String> get defaultPackagesDirectoryPath => _defaultPackagesDirectoryPath;
+
+  /**
+   * The file path of the packages directory that should be used in place of
+   * any file found using the normal (Package Specification DEP) lookup
+   * mechanism. The field will be omitted if the normal lookup mechanism should
+   * be used.
+   */
+  void set defaultPackagesDirectoryPath(List<String> value) {
+    this._defaultPackagesDirectoryPath = value;
+  }
+
+  ContextBuilderOptions({String dartSdkSummaryPath, List<String> defaultAnalysisOptionsFilePath, Map<String, String> declaredVariables, List<String> defaultPackageFilePath, List<String> defaultPackagesDirectoryPath}) {
+    this.dartSdkSummaryPath = dartSdkSummaryPath;
+    this.defaultAnalysisOptionsFilePath = defaultAnalysisOptionsFilePath;
+    this.declaredVariables = declaredVariables;
+    this.defaultPackageFilePath = defaultPackageFilePath;
+    this.defaultPackagesDirectoryPath = defaultPackagesDirectoryPath;
+  }
+
+  factory ContextBuilderOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String dartSdkSummaryPath;
+      if (json.containsKey("dartSdkSummaryPath")) {
+        dartSdkSummaryPath = jsonDecoder.decodeString(jsonPath + ".dartSdkSummaryPath", json["dartSdkSummaryPath"]);
+      }
+      List<String> defaultAnalysisOptionsFilePath;
+      if (json.containsKey("defaultAnalysisOptionsFilePath")) {
+        defaultAnalysisOptionsFilePath = jsonDecoder.decodeList(jsonPath + ".defaultAnalysisOptionsFilePath", json["defaultAnalysisOptionsFilePath"], jsonDecoder.decodeString);
+      }
+      Map<String, String> declaredVariables;
+      if (json.containsKey("declaredVariables")) {
+        declaredVariables = jsonDecoder.decodeMap(jsonPath + ".declaredVariables", json["declaredVariables"], valueDecoder: jsonDecoder.decodeString);
+      }
+      List<String> defaultPackageFilePath;
+      if (json.containsKey("defaultPackageFilePath")) {
+        defaultPackageFilePath = jsonDecoder.decodeList(jsonPath + ".defaultPackageFilePath", json["defaultPackageFilePath"], jsonDecoder.decodeString);
+      }
+      List<String> defaultPackagesDirectoryPath;
+      if (json.containsKey("defaultPackagesDirectoryPath")) {
+        defaultPackagesDirectoryPath = jsonDecoder.decodeList(jsonPath + ".defaultPackagesDirectoryPath", json["defaultPackagesDirectoryPath"], jsonDecoder.decodeString);
+      }
+      return new ContextBuilderOptions(dartSdkSummaryPath: dartSdkSummaryPath, defaultAnalysisOptionsFilePath: defaultAnalysisOptionsFilePath, declaredVariables: declaredVariables, defaultPackageFilePath: defaultPackageFilePath, defaultPackagesDirectoryPath: defaultPackagesDirectoryPath);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "ContextBuilderOptions", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    if (dartSdkSummaryPath != null) {
+      result["dartSdkSummaryPath"] = dartSdkSummaryPath;
+    }
+    if (defaultAnalysisOptionsFilePath != null) {
+      result["defaultAnalysisOptionsFilePath"] = defaultAnalysisOptionsFilePath;
+    }
+    if (declaredVariables != null) {
+      result["declaredVariables"] = declaredVariables;
+    }
+    if (defaultPackageFilePath != null) {
+      result["defaultPackageFilePath"] = defaultPackageFilePath;
+    }
+    if (defaultPackagesDirectoryPath != null) {
+      result["defaultPackagesDirectoryPath"] = defaultPackagesDirectoryPath;
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ContextBuilderOptions) {
+      return dartSdkSummaryPath == other.dartSdkSummaryPath &&
+          listEqual(defaultAnalysisOptionsFilePath, other.defaultAnalysisOptionsFilePath, (String a, String b) => a == b) &&
+          mapEqual(declaredVariables, other.declaredVariables, (String a, String b) => a == b) &&
+          listEqual(defaultPackageFilePath, other.defaultPackageFilePath, (String a, String b) => a == b) &&
+          listEqual(defaultPackagesDirectoryPath, other.defaultPackagesDirectoryPath, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, dartSdkSummaryPath.hashCode);
+    hash = JenkinsSmiHash.combine(hash, defaultAnalysisOptionsFilePath.hashCode);
+    hash = JenkinsSmiHash.combine(hash, declaredVariables.hashCode);
+    hash = JenkinsSmiHash.combine(hash, defaultPackageFilePath.hashCode);
+    hash = JenkinsSmiHash.combine(hash, defaultPackagesDirectoryPath.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * ContextRoot
+ *
+ * {
+ *   "root": String
+ *   "exclude": List<String>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ContextRoot implements HasToJson {
+  String _root;
+
+  List<String> _exclude;
+
+  /**
+   * The absolute path of the root directory containing the files to be
+   * analyzed.
+   */
+  String get root => _root;
+
+  /**
+   * The absolute path of the root directory containing the files to be
+   * analyzed.
+   */
+  void set root(String value) {
+    assert(value != null);
+    this._root = value;
+  }
+
+  /**
+   * A list of the absolute paths of files and directories within the root
+   * directory that should not be analyzed.
+   */
+  List<String> get exclude => _exclude;
+
+  /**
+   * A list of the absolute paths of files and directories within the root
+   * directory that should not be analyzed.
+   */
+  void set exclude(List<String> value) {
+    assert(value != null);
+    this._exclude = value;
+  }
+
+  ContextRoot(String root, List<String> exclude) {
+    this.root = root;
+    this.exclude = exclude;
+  }
+
+  factory ContextRoot.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String root;
+      if (json.containsKey("root")) {
+        root = jsonDecoder.decodeString(jsonPath + ".root", json["root"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "root");
+      }
+      List<String> exclude;
+      if (json.containsKey("exclude")) {
+        exclude = jsonDecoder.decodeList(jsonPath + ".exclude", json["exclude"], jsonDecoder.decodeString);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "exclude");
+      }
+      return new ContextRoot(root, exclude);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "ContextRoot", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["root"] = root;
+    result["exclude"] = exclude;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ContextRoot) {
+      return root == other.root &&
+          listEqual(exclude, other.exclude, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, root.hashCode);
+    hash = JenkinsSmiHash.combine(hash, exclude.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * convertGetterToMethod feedback
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ConvertGetterToMethodFeedback extends RefactoringFeedback implements HasToJson {
+  @override
+  bool operator==(other) {
+    if (other is ConvertGetterToMethodFeedback) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 616032599;
+  }
+}
+
+/**
+ * convertGetterToMethod options
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ConvertGetterToMethodOptions extends RefactoringOptions implements HasToJson {
+  @override
+  bool operator==(other) {
+    if (other is ConvertGetterToMethodOptions) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 488848400;
+  }
+}
+
+/**
+ * convertMethodToGetter feedback
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ConvertMethodToGetterFeedback extends RefactoringFeedback implements HasToJson {
+  @override
+  bool operator==(other) {
+    if (other is ConvertMethodToGetterFeedback) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 165291526;
+  }
+}
+
+/**
+ * convertMethodToGetter options
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ConvertMethodToGetterOptions extends RefactoringOptions implements HasToJson {
+  @override
+  bool operator==(other) {
+    if (other is ConvertMethodToGetterOptions) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 27952290;
+  }
+}
+
+/**
+ * edit.getAssists params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetAssistsParams implements RequestParams {
+  String _file;
+
+  int _offset;
+
+  int _length;
+
+  /**
+   * The file containing the code for which assists are being requested.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the code for which assists are being requested.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset of the code for which assists are being requested.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the code for which assists are being requested.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the code for which assists are being requested.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the code for which assists are being requested.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  EditGetAssistsParams(String file, int offset, int length) {
+    this.file = file;
+    this.offset = offset;
+    this.length = length;
+  }
+
+  factory EditGetAssistsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      return new EditGetAssistsParams(file, offset, length);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getAssists params", json);
+    }
+  }
+
+  factory EditGetAssistsParams.fromRequest(Request request) {
+    return new EditGetAssistsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["offset"] = offset;
+    result["length"] = length;
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "edit.getAssists", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetAssistsParams) {
+      return file == other.file &&
+          offset == other.offset &&
+          length == other.length;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getAssists result
+ *
+ * {
+ *   "assists": List<PrioritizedSourceChange>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetAssistsResult implements ResponseResult {
+  List<PrioritizedSourceChange> _assists;
+
+  /**
+   * The assists that are available at the given location.
+   */
+  List<PrioritizedSourceChange> get assists => _assists;
+
+  /**
+   * The assists that are available at the given location.
+   */
+  void set assists(List<PrioritizedSourceChange> value) {
+    assert(value != null);
+    this._assists = value;
+  }
+
+  EditGetAssistsResult(List<PrioritizedSourceChange> assists) {
+    this.assists = assists;
+  }
+
+  factory EditGetAssistsResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<PrioritizedSourceChange> assists;
+      if (json.containsKey("assists")) {
+        assists = jsonDecoder.decodeList(jsonPath + ".assists", json["assists"], (String jsonPath, Object json) => new PrioritizedSourceChange.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "assists");
+      }
+      return new EditGetAssistsResult(assists);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getAssists result", json);
+    }
+  }
+
+  factory EditGetAssistsResult.fromResponse(Response response) {
+    return new EditGetAssistsResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response.result);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["assists"] = assists.map((PrioritizedSourceChange value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetAssistsResult) {
+      return listEqual(assists, other.assists, (PrioritizedSourceChange a, PrioritizedSourceChange b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, assists.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getAvailableRefactorings params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetAvailableRefactoringsParams implements RequestParams {
+  String _file;
+
+  int _offset;
+
+  int _length;
+
+  /**
+   * The file containing the code on which the refactoring would be based.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the code on which the refactoring would be based.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset of the code on which the refactoring would be based.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the code on which the refactoring would be based.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the code on which the refactoring would be based.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the code on which the refactoring would be based.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  EditGetAvailableRefactoringsParams(String file, int offset, int length) {
+    this.file = file;
+    this.offset = offset;
+    this.length = length;
+  }
+
+  factory EditGetAvailableRefactoringsParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      return new EditGetAvailableRefactoringsParams(file, offset, length);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getAvailableRefactorings params", json);
+    }
+  }
+
+  factory EditGetAvailableRefactoringsParams.fromRequest(Request request) {
+    return new EditGetAvailableRefactoringsParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["offset"] = offset;
+    result["length"] = length;
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "edit.getAvailableRefactorings", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetAvailableRefactoringsParams) {
+      return file == other.file &&
+          offset == other.offset &&
+          length == other.length;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getAvailableRefactorings result
+ *
+ * {
+ *   "kinds": List<RefactoringKind>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetAvailableRefactoringsResult implements ResponseResult {
+  List<RefactoringKind> _kinds;
+
+  /**
+   * The kinds of refactorings that are valid for the given selection.
+   *
+   * The list of refactoring kinds is currently limited to those defined by the
+   * server API, preventing plugins from adding their own refactorings.
+   * However, plugins can support pre-defined refactorings, such as a rename
+   * refactoring, at locations not supported by server.
+   */
+  List<RefactoringKind> get kinds => _kinds;
+
+  /**
+   * The kinds of refactorings that are valid for the given selection.
+   *
+   * The list of refactoring kinds is currently limited to those defined by the
+   * server API, preventing plugins from adding their own refactorings.
+   * However, plugins can support pre-defined refactorings, such as a rename
+   * refactoring, at locations not supported by server.
+   */
+  void set kinds(List<RefactoringKind> value) {
+    assert(value != null);
+    this._kinds = value;
+  }
+
+  EditGetAvailableRefactoringsResult(List<RefactoringKind> kinds) {
+    this.kinds = kinds;
+  }
+
+  factory EditGetAvailableRefactoringsResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<RefactoringKind> kinds;
+      if (json.containsKey("kinds")) {
+        kinds = jsonDecoder.decodeList(jsonPath + ".kinds", json["kinds"], (String jsonPath, Object json) => new RefactoringKind.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kinds");
+      }
+      return new EditGetAvailableRefactoringsResult(kinds);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getAvailableRefactorings result", json);
+    }
+  }
+
+  factory EditGetAvailableRefactoringsResult.fromResponse(Response response) {
+    return new EditGetAvailableRefactoringsResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response.result);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["kinds"] = kinds.map((RefactoringKind value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetAvailableRefactoringsResult) {
+      return listEqual(kinds, other.kinds, (RefactoringKind a, RefactoringKind b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, kinds.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getFixes params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetFixesParams implements RequestParams {
+  String _file;
+
+  int _offset;
+
+  /**
+   * The file containing the errors for which fixes are being requested.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the errors for which fixes are being requested.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset used to select the errors for which fixes will be returned.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset used to select the errors for which fixes will be returned.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  EditGetFixesParams(String file, int offset) {
+    this.file = file;
+    this.offset = offset;
+  }
+
+  factory EditGetFixesParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      return new EditGetFixesParams(file, offset);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getFixes params", json);
+    }
+  }
+
+  factory EditGetFixesParams.fromRequest(Request request) {
+    return new EditGetFixesParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["offset"] = offset;
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "edit.getFixes", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetFixesParams) {
+      return file == other.file &&
+          offset == other.offset;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getFixes result
+ *
+ * {
+ *   "fixes": List<AnalysisErrorFixes>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetFixesResult implements ResponseResult {
+  List<AnalysisErrorFixes> _fixes;
+
+  /**
+   * The fixes that are available for the errors at the given offset.
+   */
+  List<AnalysisErrorFixes> get fixes => _fixes;
+
+  /**
+   * The fixes that are available for the errors at the given offset.
+   */
+  void set fixes(List<AnalysisErrorFixes> value) {
+    assert(value != null);
+    this._fixes = value;
+  }
+
+  EditGetFixesResult(List<AnalysisErrorFixes> fixes) {
+    this.fixes = fixes;
+  }
+
+  factory EditGetFixesResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<AnalysisErrorFixes> fixes;
+      if (json.containsKey("fixes")) {
+        fixes = jsonDecoder.decodeList(jsonPath + ".fixes", json["fixes"], (String jsonPath, Object json) => new AnalysisErrorFixes.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "fixes");
+      }
+      return new EditGetFixesResult(fixes);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getFixes result", json);
+    }
+  }
+
+  factory EditGetFixesResult.fromResponse(Response response) {
+    return new EditGetFixesResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response.result);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["fixes"] = fixes.map((AnalysisErrorFixes value) => value.toJson()).toList();
+    return result;
+  }
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetFixesResult) {
+      return listEqual(fixes, other.fixes, (AnalysisErrorFixes a, AnalysisErrorFixes b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, fixes.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getRefactoring params
+ *
+ * {
+ *   "kind": RefactoringKind
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ *   "validateOnly": bool
+ *   "options": optional RefactoringOptions
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetRefactoringParams implements RequestParams {
+  RefactoringKind _kind;
+
+  String _file;
+
+  int _offset;
+
+  int _length;
+
+  bool _validateOnly;
+
+  RefactoringOptions _options;
+
+  /**
+   * The kind of refactoring to be performed.
+   */
+  RefactoringKind get kind => _kind;
+
+  /**
+   * The kind of refactoring to be performed.
+   */
+  void set kind(RefactoringKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The file containing the code involved in the refactoring.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the code involved in the refactoring.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset of the region involved in the refactoring.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the region involved in the refactoring.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the region involved in the refactoring.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the region involved in the refactoring.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * True if the client is only requesting that the values of the options be
+   * validated and no change be generated.
+   */
+  bool get validateOnly => _validateOnly;
+
+  /**
+   * True if the client is only requesting that the values of the options be
+   * validated and no change be generated.
+   */
+  void set validateOnly(bool value) {
+    assert(value != null);
+    this._validateOnly = value;
+  }
+
+  /**
+   * Data used to provide values provided by the user. The structure of the
+   * data is dependent on the kind of refactoring being performed. The data
+   * that is expected is documented in the section titled Refactorings, labeled
+   * as "Options". This field can be omitted if the refactoring does not
+   * require any options or if the values of those options are not known.
+   */
+  RefactoringOptions get options => _options;
+
+  /**
+   * Data used to provide values provided by the user. The structure of the
+   * data is dependent on the kind of refactoring being performed. The data
+   * that is expected is documented in the section titled Refactorings, labeled
+   * as "Options". This field can be omitted if the refactoring does not
+   * require any options or if the values of those options are not known.
+   */
+  void set options(RefactoringOptions value) {
+    this._options = value;
+  }
+
+  EditGetRefactoringParams(RefactoringKind kind, String file, int offset, int length, bool validateOnly, {RefactoringOptions options}) {
+    this.kind = kind;
+    this.file = file;
+    this.offset = offset;
+    this.length = length;
+    this.validateOnly = validateOnly;
+    this.options = options;
+  }
+
+  factory EditGetRefactoringParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      RefactoringKind kind;
+      if (json.containsKey("kind")) {
+        kind = new RefactoringKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      bool validateOnly;
+      if (json.containsKey("validateOnly")) {
+        validateOnly = jsonDecoder.decodeBool(jsonPath + ".validateOnly", json["validateOnly"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "validateOnly");
+      }
+      RefactoringOptions options;
+      if (json.containsKey("options")) {
+        options = new RefactoringOptions.fromJson(jsonDecoder, jsonPath + ".options", json["options"], kind);
+      }
+      return new EditGetRefactoringParams(kind, file, offset, length, validateOnly, options: options);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getRefactoring params", json);
+    }
+  }
+
+  factory EditGetRefactoringParams.fromRequest(Request request) {
+    var params = new EditGetRefactoringParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+    REQUEST_ID_REFACTORING_KINDS[request.id] = params.kind;
+    return params;
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["kind"] = kind.toJson();
+    result["file"] = file;
+    result["offset"] = offset;
+    result["length"] = length;
+    result["validateOnly"] = validateOnly;
+    if (options != null) {
+      result["options"] = options.toJson();
+    }
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "edit.getRefactoring", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetRefactoringParams) {
+      return kind == other.kind &&
+          file == other.file &&
+          offset == other.offset &&
+          length == other.length &&
+          validateOnly == other.validateOnly &&
+          options == other.options;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, validateOnly.hashCode);
+    hash = JenkinsSmiHash.combine(hash, options.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * edit.getRefactoring result
+ *
+ * {
+ *   "initialProblems": List<RefactoringProblem>
+ *   "optionsProblems": List<RefactoringProblem>
+ *   "finalProblems": List<RefactoringProblem>
+ *   "feedback": optional RefactoringFeedback
+ *   "change": optional SourceChange
+ *   "potentialEdits": optional List<String>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditGetRefactoringResult implements ResponseResult {
+  List<RefactoringProblem> _initialProblems;
+
+  List<RefactoringProblem> _optionsProblems;
+
+  List<RefactoringProblem> _finalProblems;
+
+  RefactoringFeedback _feedback;
+
+  SourceChange _change;
+
+  List<String> _potentialEdits;
+
+  /**
+   * The initial status of the refactoring, that is, problems related to the
+   * context in which the refactoring is requested. The list should be empty if
+   * there are no known problems.
+   */
+  List<RefactoringProblem> get initialProblems => _initialProblems;
+
+  /**
+   * The initial status of the refactoring, that is, problems related to the
+   * context in which the refactoring is requested. The list should be empty if
+   * there are no known problems.
+   */
+  void set initialProblems(List<RefactoringProblem> value) {
+    assert(value != null);
+    this._initialProblems = value;
+  }
+
+  /**
+   * The options validation status, that is, problems in the given options,
+   * such as light-weight validation of a new name, flags compatibility, etc.
+   * The list should be empty if there are no known problems.
+   */
+  List<RefactoringProblem> get optionsProblems => _optionsProblems;
+
+  /**
+   * The options validation status, that is, problems in the given options,
+   * such as light-weight validation of a new name, flags compatibility, etc.
+   * The list should be empty if there are no known problems.
+   */
+  void set optionsProblems(List<RefactoringProblem> value) {
+    assert(value != null);
+    this._optionsProblems = value;
+  }
+
+  /**
+   * The final status of the refactoring, that is, problems identified in the
+   * result of a full, potentially expensive validation and / or change
+   * creation. The list should be empty if there are no known problems.
+   */
+  List<RefactoringProblem> get finalProblems => _finalProblems;
+
+  /**
+   * The final status of the refactoring, that is, problems identified in the
+   * result of a full, potentially expensive validation and / or change
+   * creation. The list should be empty if there are no known problems.
+   */
+  void set finalProblems(List<RefactoringProblem> value) {
+    assert(value != null);
+    this._finalProblems = value;
+  }
+
+  /**
+   * Data used to provide feedback to the user. The structure of the data is
+   * dependent on the kind of refactoring being created. The data that is
+   * returned is documented in the section titled Refactorings, labeled as
+   * "Feedback".
+   */
+  RefactoringFeedback get feedback => _feedback;
+
+  /**
+   * Data used to provide feedback to the user. The structure of the data is
+   * dependent on the kind of refactoring being created. The data that is
+   * returned is documented in the section titled Refactorings, labeled as
+   * "Feedback".
+   */
+  void set feedback(RefactoringFeedback value) {
+    this._feedback = value;
+  }
+
+  /**
+   * The changes that are to be applied to affect the refactoring. This field
+   * can be omitted if there are problems that prevent a set of changes from
+   * being computed, such as having no options specified for a refactoring that
+   * requires them, or if only validation was requested.
+   */
+  SourceChange get change => _change;
+
+  /**
+   * The changes that are to be applied to affect the refactoring. This field
+   * can be omitted if there are problems that prevent a set of changes from
+   * being computed, such as having no options specified for a refactoring that
+   * requires them, or if only validation was requested.
+   */
+  void set change(SourceChange value) {
+    this._change = value;
+  }
+
+  /**
+   * The ids of source edits that are not known to be valid. An edit is not
+   * known to be valid if there was insufficient type information for the
+   * plugin to be able to determine whether or not the code needs to be
+   * modified, such as when a member is being renamed and there is a reference
+   * to a member from an unknown type. This field can be omitted if the change
+   * field is omitted or if there are no potential edits for the refactoring.
+   */
+  List<String> get potentialEdits => _potentialEdits;
+
+  /**
+   * The ids of source edits that are not known to be valid. An edit is not
+   * known to be valid if there was insufficient type information for the
+   * plugin to be able to determine whether or not the code needs to be
+   * modified, such as when a member is being renamed and there is a reference
+   * to a member from an unknown type. This field can be omitted if the change
+   * field is omitted or if there are no potential edits for the refactoring.
+   */
+  void set potentialEdits(List<String> value) {
+    this._potentialEdits = value;
+  }
+
+  EditGetRefactoringResult(List<RefactoringProblem> initialProblems, List<RefactoringProblem> optionsProblems, List<RefactoringProblem> finalProblems, {RefactoringFeedback feedback, SourceChange change, List<String> potentialEdits}) {
+    this.initialProblems = initialProblems;
+    this.optionsProblems = optionsProblems;
+    this.finalProblems = finalProblems;
+    this.feedback = feedback;
+    this.change = change;
+    this.potentialEdits = potentialEdits;
+  }
+
+  factory EditGetRefactoringResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<RefactoringProblem> initialProblems;
+      if (json.containsKey("initialProblems")) {
+        initialProblems = jsonDecoder.decodeList(jsonPath + ".initialProblems", json["initialProblems"], (String jsonPath, Object json) => new RefactoringProblem.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "initialProblems");
+      }
+      List<RefactoringProblem> optionsProblems;
+      if (json.containsKey("optionsProblems")) {
+        optionsProblems = jsonDecoder.decodeList(jsonPath + ".optionsProblems", json["optionsProblems"], (String jsonPath, Object json) => new RefactoringProblem.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "optionsProblems");
+      }
+      List<RefactoringProblem> finalProblems;
+      if (json.containsKey("finalProblems")) {
+        finalProblems = jsonDecoder.decodeList(jsonPath + ".finalProblems", json["finalProblems"], (String jsonPath, Object json) => new RefactoringProblem.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "finalProblems");
+      }
+      RefactoringFeedback feedback;
+      if (json.containsKey("feedback")) {
+        feedback = new RefactoringFeedback.fromJson(jsonDecoder, jsonPath + ".feedback", json["feedback"], json);
+      }
+      SourceChange change;
+      if (json.containsKey("change")) {
+        change = new SourceChange.fromJson(jsonDecoder, jsonPath + ".change", json["change"]);
+      }
+      List<String> potentialEdits;
+      if (json.containsKey("potentialEdits")) {
+        potentialEdits = jsonDecoder.decodeList(jsonPath + ".potentialEdits", json["potentialEdits"], jsonDecoder.decodeString);
+      }
+      return new EditGetRefactoringResult(initialProblems, optionsProblems, finalProblems, feedback: feedback, change: change, potentialEdits: potentialEdits);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "edit.getRefactoring result", json);
+    }
+  }
+
+  factory EditGetRefactoringResult.fromResponse(Response response) {
+    return new EditGetRefactoringResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response.result);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["initialProblems"] = initialProblems.map((RefactoringProblem value) => value.toJson()).toList();
+    result["optionsProblems"] = optionsProblems.map((RefactoringProblem value) => value.toJson()).toList();
+    result["finalProblems"] = finalProblems.map((RefactoringProblem value) => value.toJson()).toList();
+    if (feedback != null) {
+      result["feedback"] = feedback.toJson();
+    }
+    if (change != null) {
+      result["change"] = change.toJson();
+    }
+    if (potentialEdits != null) {
+      result["potentialEdits"] = potentialEdits;
+    }
+    return result;
+  }
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is EditGetRefactoringResult) {
+      return listEqual(initialProblems, other.initialProblems, (RefactoringProblem a, RefactoringProblem b) => a == b) &&
+          listEqual(optionsProblems, other.optionsProblems, (RefactoringProblem a, RefactoringProblem b) => a == b) &&
+          listEqual(finalProblems, other.finalProblems, (RefactoringProblem a, RefactoringProblem b) => a == b) &&
+          feedback == other.feedback &&
+          change == other.change &&
+          listEqual(potentialEdits, other.potentialEdits, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, initialProblems.hashCode);
+    hash = JenkinsSmiHash.combine(hash, optionsProblems.hashCode);
+    hash = JenkinsSmiHash.combine(hash, finalProblems.hashCode);
+    hash = JenkinsSmiHash.combine(hash, feedback.hashCode);
+    hash = JenkinsSmiHash.combine(hash, change.hashCode);
+    hash = JenkinsSmiHash.combine(hash, potentialEdits.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * Element
+ *
+ * {
+ *   "kind": ElementKind
+ *   "name": String
+ *   "location": optional Location
+ *   "flags": int
+ *   "parameters": optional String
+ *   "returnType": optional String
+ *   "typeParameters": optional String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Element implements HasToJson {
+  static const int FLAG_ABSTRACT = 0x01;
+  static const int FLAG_CONST = 0x02;
+  static const int FLAG_FINAL = 0x04;
+  static const int FLAG_STATIC = 0x08;
+  static const int FLAG_PRIVATE = 0x10;
+  static const int FLAG_DEPRECATED = 0x20;
+
+  static int makeFlags({isAbstract: false, isConst: false, isFinal: false, isStatic: false, isPrivate: false, isDeprecated: false}) {
+    int flags = 0;
+    if (isAbstract) flags |= FLAG_ABSTRACT;
+    if (isConst) flags |= FLAG_CONST;
+    if (isFinal) flags |= FLAG_FINAL;
+    if (isStatic) flags |= FLAG_STATIC;
+    if (isPrivate) flags |= FLAG_PRIVATE;
+    if (isDeprecated) flags |= FLAG_DEPRECATED;
+    return flags;
+  }
+
+  ElementKind _kind;
+
+  String _name;
+
+  Location _location;
+
+  int _flags;
+
+  String _parameters;
+
+  String _returnType;
+
+  String _typeParameters;
+
+  /**
+   * The kind of the element.
+   */
+  ElementKind get kind => _kind;
+
+  /**
+   * The kind of the element.
+   */
+  void set kind(ElementKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The name of the element. This is typically used as the label in the
+   * outline.
+   */
+  String get name => _name;
+
+  /**
+   * The name of the element. This is typically used as the label in the
+   * outline.
+   */
+  void set name(String value) {
+    assert(value != null);
+    this._name = value;
+  }
+
+  /**
+   * The location of the name in the declaration of the element.
+   */
+  Location get location => _location;
+
+  /**
+   * The location of the name in the declaration of the element.
+   */
+  void set location(Location value) {
+    this._location = value;
+  }
+
+  /**
+   * A bit-map containing the following flags:
+   *
+   * - 0x01 - set if the element is explicitly or implicitly abstract
+   * - 0x02 - set if the element was declared to be ‘const’
+   * - 0x04 - set if the element was declared to be ‘final’
+   * - 0x08 - set if the element is a static member of a class or is a
+   *   top-level function or field
+   * - 0x10 - set if the element is private
+   * - 0x20 - set if the element is deprecated
+   */
+  int get flags => _flags;
+
+  /**
+   * A bit-map containing the following flags:
+   *
+   * - 0x01 - set if the element is explicitly or implicitly abstract
+   * - 0x02 - set if the element was declared to be ‘const’
+   * - 0x04 - set if the element was declared to be ‘final’
+   * - 0x08 - set if the element is a static member of a class or is a
+   *   top-level function or field
+   * - 0x10 - set if the element is private
+   * - 0x20 - set if the element is deprecated
+   */
+  void set flags(int value) {
+    assert(value != null);
+    this._flags = value;
+  }
+
+  /**
+   * The parameter list for the element. If the element is not a method or
+   * function this field will not be defined. If the element doesn't have
+   * parameters (e.g. getter), this field will not be defined. If the element
+   * has zero parameters, this field will have a value of "()".
+   */
+  String get parameters => _parameters;
+
+  /**
+   * The parameter list for the element. If the element is not a method or
+   * function this field will not be defined. If the element doesn't have
+   * parameters (e.g. getter), this field will not be defined. If the element
+   * has zero parameters, this field will have a value of "()".
+   */
+  void set parameters(String value) {
+    this._parameters = value;
+  }
+
+  /**
+   * The return type of the element. If the element is not a method or function
+   * this field will not be defined. If the element does not have a declared
+   * return type, this field will contain an empty string.
+   */
+  String get returnType => _returnType;
+
+  /**
+   * The return type of the element. If the element is not a method or function
+   * this field will not be defined. If the element does not have a declared
+   * return type, this field will contain an empty string.
+   */
+  void set returnType(String value) {
+    this._returnType = value;
+  }
+
+  /**
+   * The type parameter list for the element. If the element doesn't have type
+   * parameters, this field will not be defined.
+   */
+  String get typeParameters => _typeParameters;
+
+  /**
+   * The type parameter list for the element. If the element doesn't have type
+   * parameters, this field will not be defined.
+   */
+  void set typeParameters(String value) {
+    this._typeParameters = value;
+  }
+
+  Element(ElementKind kind, String name, int flags, {Location location, String parameters, String returnType, String typeParameters}) {
+    this.kind = kind;
+    this.name = name;
+    this.location = location;
+    this.flags = flags;
+    this.parameters = parameters;
+    this.returnType = returnType;
+    this.typeParameters = typeParameters;
+  }
+
+  factory Element.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      ElementKind kind;
+      if (json.containsKey("kind")) {
+        kind = new ElementKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      String name;
+      if (json.containsKey("name")) {
+        name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "name");
+      }
+      Location location;
+      if (json.containsKey("location")) {
+        location = new Location.fromJson(jsonDecoder, jsonPath + ".location", json["location"]);
+      }
+      int flags;
+      if (json.containsKey("flags")) {
+        flags = jsonDecoder.decodeInt(jsonPath + ".flags", json["flags"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "flags");
+      }
+      String parameters;
+      if (json.containsKey("parameters")) {
+        parameters = jsonDecoder.decodeString(jsonPath + ".parameters", json["parameters"]);
+      }
+      String returnType;
+      if (json.containsKey("returnType")) {
+        returnType = jsonDecoder.decodeString(jsonPath + ".returnType", json["returnType"]);
+      }
+      String typeParameters;
+      if (json.containsKey("typeParameters")) {
+        typeParameters = jsonDecoder.decodeString(jsonPath + ".typeParameters", json["typeParameters"]);
+      }
+      return new Element(kind, name, flags, location: location, parameters: parameters, returnType: returnType, typeParameters: typeParameters);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "Element", json);
+    }
+  }
+
+  bool get isAbstract => (flags & FLAG_ABSTRACT) != 0;
+  bool get isConst => (flags & FLAG_CONST) != 0;
+  bool get isFinal => (flags & FLAG_FINAL) != 0;
+  bool get isStatic => (flags & FLAG_STATIC) != 0;
+  bool get isPrivate => (flags & FLAG_PRIVATE) != 0;
+  bool get isDeprecated => (flags & FLAG_DEPRECATED) != 0;
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["kind"] = kind.toJson();
+    result["name"] = name;
+    if (location != null) {
+      result["location"] = location.toJson();
+    }
+    result["flags"] = flags;
+    if (parameters != null) {
+      result["parameters"] = parameters;
+    }
+    if (returnType != null) {
+      result["returnType"] = returnType;
+    }
+    if (typeParameters != null) {
+      result["typeParameters"] = typeParameters;
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is Element) {
+      return kind == other.kind &&
+          name == other.name &&
+          location == other.location &&
+          flags == other.flags &&
+          parameters == other.parameters &&
+          returnType == other.returnType &&
+          typeParameters == other.typeParameters;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, name.hashCode);
+    hash = JenkinsSmiHash.combine(hash, location.hashCode);
+    hash = JenkinsSmiHash.combine(hash, flags.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameters.hashCode);
+    hash = JenkinsSmiHash.combine(hash, returnType.hashCode);
+    hash = JenkinsSmiHash.combine(hash, typeParameters.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * ElementKind
+ *
+ * enum {
+ *   CLASS
+ *   CLASS_TYPE_ALIAS
+ *   COMPILATION_UNIT
+ *   CONSTRUCTOR
+ *   ENUM
+ *   ENUM_CONSTANT
+ *   FIELD
+ *   FILE
+ *   FUNCTION
+ *   FUNCTION_TYPE_ALIAS
+ *   GETTER
+ *   LABEL
+ *   LIBRARY
+ *   LOCAL_VARIABLE
+ *   METHOD
+ *   PARAMETER
+ *   PREFIX
+ *   SETTER
+ *   TOP_LEVEL_VARIABLE
+ *   TYPE_PARAMETER
+ *   UNKNOWN
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ElementKind implements Enum {
+  static const ElementKind CLASS = const ElementKind._("CLASS");
+
+  static const ElementKind CLASS_TYPE_ALIAS = const ElementKind._("CLASS_TYPE_ALIAS");
+
+  static const ElementKind COMPILATION_UNIT = const ElementKind._("COMPILATION_UNIT");
+
+  static const ElementKind CONSTRUCTOR = const ElementKind._("CONSTRUCTOR");
+
+  static const ElementKind ENUM = const ElementKind._("ENUM");
+
+  static const ElementKind ENUM_CONSTANT = const ElementKind._("ENUM_CONSTANT");
+
+  static const ElementKind FIELD = const ElementKind._("FIELD");
+
+  static const ElementKind FILE = const ElementKind._("FILE");
+
+  static const ElementKind FUNCTION = const ElementKind._("FUNCTION");
+
+  static const ElementKind FUNCTION_TYPE_ALIAS = const ElementKind._("FUNCTION_TYPE_ALIAS");
+
+  static const ElementKind GETTER = const ElementKind._("GETTER");
+
+  static const ElementKind LABEL = const ElementKind._("LABEL");
+
+  static const ElementKind LIBRARY = const ElementKind._("LIBRARY");
+
+  static const ElementKind LOCAL_VARIABLE = const ElementKind._("LOCAL_VARIABLE");
+
+  static const ElementKind METHOD = const ElementKind._("METHOD");
+
+  static const ElementKind PARAMETER = const ElementKind._("PARAMETER");
+
+  static const ElementKind PREFIX = const ElementKind._("PREFIX");
+
+  static const ElementKind SETTER = const ElementKind._("SETTER");
+
+  static const ElementKind TOP_LEVEL_VARIABLE = const ElementKind._("TOP_LEVEL_VARIABLE");
+
+  static const ElementKind TYPE_PARAMETER = const ElementKind._("TYPE_PARAMETER");
+
+  static const ElementKind UNKNOWN = const ElementKind._("UNKNOWN");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<ElementKind> VALUES = const <ElementKind>[CLASS, CLASS_TYPE_ALIAS, COMPILATION_UNIT, CONSTRUCTOR, ENUM, ENUM_CONSTANT, FIELD, FILE, FUNCTION, FUNCTION_TYPE_ALIAS, GETTER, LABEL, LIBRARY, LOCAL_VARIABLE, METHOD, PARAMETER, PREFIX, SETTER, TOP_LEVEL_VARIABLE, TYPE_PARAMETER, UNKNOWN];
+
+  @override
+  final String name;
+
+  const ElementKind._(this.name);
+
+  factory ElementKind(String name) {
+    switch (name) {
+      case "CLASS":
+        return CLASS;
+      case "CLASS_TYPE_ALIAS":
+        return CLASS_TYPE_ALIAS;
+      case "COMPILATION_UNIT":
+        return COMPILATION_UNIT;
+      case "CONSTRUCTOR":
+        return CONSTRUCTOR;
+      case "ENUM":
+        return ENUM;
+      case "ENUM_CONSTANT":
+        return ENUM_CONSTANT;
+      case "FIELD":
+        return FIELD;
+      case "FILE":
+        return FILE;
+      case "FUNCTION":
+        return FUNCTION;
+      case "FUNCTION_TYPE_ALIAS":
+        return FUNCTION_TYPE_ALIAS;
+      case "GETTER":
+        return GETTER;
+      case "LABEL":
+        return LABEL;
+      case "LIBRARY":
+        return LIBRARY;
+      case "LOCAL_VARIABLE":
+        return LOCAL_VARIABLE;
+      case "METHOD":
+        return METHOD;
+      case "PARAMETER":
+        return PARAMETER;
+      case "PREFIX":
+        return PREFIX;
+      case "SETTER":
+        return SETTER;
+      case "TOP_LEVEL_VARIABLE":
+        return TOP_LEVEL_VARIABLE;
+      case "TYPE_PARAMETER":
+        return TYPE_PARAMETER;
+      case "UNKNOWN":
+        return UNKNOWN;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory ElementKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new ElementKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "ElementKind", json);
+  }
+
+  @override
+  String toString() => "ElementKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * extractLocalVariable feedback
+ *
+ * {
+ *   "coveringExpressionOffsets": optional List<int>
+ *   "coveringExpressionLengths": optional List<int>
+ *   "names": List<String>
+ *   "offsets": List<int>
+ *   "lengths": List<int>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ExtractLocalVariableFeedback extends RefactoringFeedback {
+  List<int> _coveringExpressionOffsets;
+
+  List<int> _coveringExpressionLengths;
+
+  List<String> _names;
+
+  List<int> _offsets;
+
+  List<int> _lengths;
+
+  /**
+   * The offsets of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  List<int> get coveringExpressionOffsets => _coveringExpressionOffsets;
+
+  /**
+   * The offsets of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  void set coveringExpressionOffsets(List<int> value) {
+    this._coveringExpressionOffsets = value;
+  }
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  List<int> get coveringExpressionLengths => _coveringExpressionLengths;
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  void set coveringExpressionLengths(List<int> value) {
+    this._coveringExpressionLengths = value;
+  }
+
+  /**
+   * The proposed names for the local variable.
+   */
+  List<String> get names => _names;
+
+  /**
+   * The proposed names for the local variable.
+   */
+  void set names(List<String> value) {
+    assert(value != null);
+    this._names = value;
+  }
+
+  /**
+   * The offsets of the expressions that would be replaced by a reference to
+   * the variable.
+   */
+  List<int> get offsets => _offsets;
+
+  /**
+   * The offsets of the expressions that would be replaced by a reference to
+   * the variable.
+   */
+  void set offsets(List<int> value) {
+    assert(value != null);
+    this._offsets = value;
+  }
+
+  /**
+   * The lengths of the expressions that would be replaced by a reference to
+   * the variable. The lengths correspond to the offsets. In other words, for a
+   * given expression, if the offset of that expression is offsets[i], then the
+   * length of that expression is lengths[i].
+   */
+  List<int> get lengths => _lengths;
+
+  /**
+   * The lengths of the expressions that would be replaced by a reference to
+   * the variable. The lengths correspond to the offsets. In other words, for a
+   * given expression, if the offset of that expression is offsets[i], then the
+   * length of that expression is lengths[i].
+   */
+  void set lengths(List<int> value) {
+    assert(value != null);
+    this._lengths = value;
+  }
+
+  ExtractLocalVariableFeedback(List<String> names, List<int> offsets, List<int> lengths, {List<int> coveringExpressionOffsets, List<int> coveringExpressionLengths}) {
+    this.coveringExpressionOffsets = coveringExpressionOffsets;
+    this.coveringExpressionLengths = coveringExpressionLengths;
+    this.names = names;
+    this.offsets = offsets;
+    this.lengths = lengths;
+  }
+
+  factory ExtractLocalVariableFeedback.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<int> coveringExpressionOffsets;
+      if (json.containsKey("coveringExpressionOffsets")) {
+        coveringExpressionOffsets = jsonDecoder.decodeList(jsonPath + ".coveringExpressionOffsets", json["coveringExpressionOffsets"], jsonDecoder.decodeInt);
+      }
+      List<int> coveringExpressionLengths;
+      if (json.containsKey("coveringExpressionLengths")) {
+        coveringExpressionLengths = jsonDecoder.decodeList(jsonPath + ".coveringExpressionLengths", json["coveringExpressionLengths"], jsonDecoder.decodeInt);
+      }
+      List<String> names;
+      if (json.containsKey("names")) {
+        names = jsonDecoder.decodeList(jsonPath + ".names", json["names"], jsonDecoder.decodeString);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "names");
+      }
+      List<int> offsets;
+      if (json.containsKey("offsets")) {
+        offsets = jsonDecoder.decodeList(jsonPath + ".offsets", json["offsets"], jsonDecoder.decodeInt);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offsets");
+      }
+      List<int> lengths;
+      if (json.containsKey("lengths")) {
+        lengths = jsonDecoder.decodeList(jsonPath + ".lengths", json["lengths"], jsonDecoder.decodeInt);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "lengths");
+      }
+      return new ExtractLocalVariableFeedback(names, offsets, lengths, coveringExpressionOffsets: coveringExpressionOffsets, coveringExpressionLengths: coveringExpressionLengths);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "extractLocalVariable feedback", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    if (coveringExpressionOffsets != null) {
+      result["coveringExpressionOffsets"] = coveringExpressionOffsets;
+    }
+    if (coveringExpressionLengths != null) {
+      result["coveringExpressionLengths"] = coveringExpressionLengths;
+    }
+    result["names"] = names;
+    result["offsets"] = offsets;
+    result["lengths"] = lengths;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ExtractLocalVariableFeedback) {
+      return listEqual(coveringExpressionOffsets, other.coveringExpressionOffsets, (int a, int b) => a == b) &&
+          listEqual(coveringExpressionLengths, other.coveringExpressionLengths, (int a, int b) => a == b) &&
+          listEqual(names, other.names, (String a, String b) => a == b) &&
+          listEqual(offsets, other.offsets, (int a, int b) => a == b) &&
+          listEqual(lengths, other.lengths, (int a, int b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, coveringExpressionOffsets.hashCode);
+    hash = JenkinsSmiHash.combine(hash, coveringExpressionLengths.hashCode);
+    hash = JenkinsSmiHash.combine(hash, names.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offsets.hashCode);
+    hash = JenkinsSmiHash.combine(hash, lengths.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * extractLocalVariable options
+ *
+ * {
+ *   "name": String
+ *   "extractAll": bool
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ExtractLocalVariableOptions extends RefactoringOptions {
+  String _name;
+
+  bool _extractAll;
+
+  /**
+   * The name that the local variable should be given.
+   */
+  String get name => _name;
+
+  /**
+   * The name that the local variable should be given.
+   */
+  void set name(String value) {
+    assert(value != null);
+    this._name = value;
+  }
+
+  /**
+   * True if all occurrences of the expression within the scope in which the
+   * variable will be defined should be replaced by a reference to the local
+   * variable. The expression used to initiate the refactoring will always be
+   * replaced.
+   */
+  bool get extractAll => _extractAll;
+
+  /**
+   * True if all occurrences of the expression within the scope in which the
+   * variable will be defined should be replaced by a reference to the local
+   * variable. The expression used to initiate the refactoring will always be
+   * replaced.
+   */
+  void set extractAll(bool value) {
+    assert(value != null);
+    this._extractAll = value;
+  }
+
+  ExtractLocalVariableOptions(String name, bool extractAll) {
+    this.name = name;
+    this.extractAll = extractAll;
+  }
+
+  factory ExtractLocalVariableOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String name;
+      if (json.containsKey("name")) {
+        name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "name");
+      }
+      bool extractAll;
+      if (json.containsKey("extractAll")) {
+        extractAll = jsonDecoder.decodeBool(jsonPath + ".extractAll", json["extractAll"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "extractAll");
+      }
+      return new ExtractLocalVariableOptions(name, extractAll);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "extractLocalVariable options", json);
+    }
+  }
+
+  factory ExtractLocalVariableOptions.fromRefactoringParams(EditGetRefactoringParams refactoringParams, Request request) {
+    return new ExtractLocalVariableOptions.fromJson(
+        new RequestDecoder(request), "options", refactoringParams.options);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["name"] = name;
+    result["extractAll"] = extractAll;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ExtractLocalVariableOptions) {
+      return name == other.name &&
+          extractAll == other.extractAll;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, name.hashCode);
+    hash = JenkinsSmiHash.combine(hash, extractAll.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * extractMethod feedback
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "returnType": String
+ *   "names": List<String>
+ *   "canCreateGetter": bool
+ *   "parameters": List<RefactoringMethodParameter>
+ *   "offsets": List<int>
+ *   "lengths": List<int>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ExtractMethodFeedback extends RefactoringFeedback {
+  int _offset;
+
+  int _length;
+
+  String _returnType;
+
+  List<String> _names;
+
+  bool _canCreateGetter;
+
+  List<RefactoringMethodParameter> _parameters;
+
+  List<int> _offsets;
+
+  List<int> _lengths;
+
+  /**
+   * The offset to the beginning of the expression or statements that will be
+   * extracted.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset to the beginning of the expression or statements that will be
+   * extracted.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the expression or statements that will be extracted.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the expression or statements that will be extracted.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The proposed return type for the method. If the returned element does not
+   * have a declared return type, this field will contain an empty string.
+   */
+  String get returnType => _returnType;
+
+  /**
+   * The proposed return type for the method. If the returned element does not
+   * have a declared return type, this field will contain an empty string.
+   */
+  void set returnType(String value) {
+    assert(value != null);
+    this._returnType = value;
+  }
+
+  /**
+   * The proposed names for the method.
+   */
+  List<String> get names => _names;
+
+  /**
+   * The proposed names for the method.
+   */
+  void set names(List<String> value) {
+    assert(value != null);
+    this._names = value;
+  }
+
+  /**
+   * True if a getter could be created rather than a method.
+   */
+  bool get canCreateGetter => _canCreateGetter;
+
+  /**
+   * True if a getter could be created rather than a method.
+   */
+  void set canCreateGetter(bool value) {
+    assert(value != null);
+    this._canCreateGetter = value;
+  }
+
+  /**
+   * The proposed parameters for the method.
+   */
+  List<RefactoringMethodParameter> get parameters => _parameters;
+
+  /**
+   * The proposed parameters for the method.
+   */
+  void set parameters(List<RefactoringMethodParameter> value) {
+    assert(value != null);
+    this._parameters = value;
+  }
+
+  /**
+   * The offsets of the expressions or statements that would be replaced by an
+   * invocation of the method.
+   */
+  List<int> get offsets => _offsets;
+
+  /**
+   * The offsets of the expressions or statements that would be replaced by an
+   * invocation of the method.
+   */
+  void set offsets(List<int> value) {
+    assert(value != null);
+    this._offsets = value;
+  }
+
+  /**
+   * The lengths of the expressions or statements that would be replaced by an
+   * invocation of the method. The lengths correspond to the offsets. In other
+   * words, for a given expression (or block of statements), if the offset of
+   * that expression is offsets[i], then the length of that expression is
+   * lengths[i].
+   */
+  List<int> get lengths => _lengths;
+
+  /**
+   * The lengths of the expressions or statements that would be replaced by an
+   * invocation of the method. The lengths correspond to the offsets. In other
+   * words, for a given expression (or block of statements), if the offset of
+   * that expression is offsets[i], then the length of that expression is
+   * lengths[i].
+   */
+  void set lengths(List<int> value) {
+    assert(value != null);
+    this._lengths = value;
+  }
+
+  ExtractMethodFeedback(int offset, int length, String returnType, List<String> names, bool canCreateGetter, List<RefactoringMethodParameter> parameters, List<int> offsets, List<int> lengths) {
+    this.offset = offset;
+    this.length = length;
+    this.returnType = returnType;
+    this.names = names;
+    this.canCreateGetter = canCreateGetter;
+    this.parameters = parameters;
+    this.offsets = offsets;
+    this.lengths = lengths;
+  }
+
+  factory ExtractMethodFeedback.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      String returnType;
+      if (json.containsKey("returnType")) {
+        returnType = jsonDecoder.decodeString(jsonPath + ".returnType", json["returnType"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "returnType");
+      }
+      List<String> names;
+      if (json.containsKey("names")) {
+        names = jsonDecoder.decodeList(jsonPath + ".names", json["names"], jsonDecoder.decodeString);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "names");
+      }
+      bool canCreateGetter;
+      if (json.containsKey("canCreateGetter")) {
+        canCreateGetter = jsonDecoder.decodeBool(jsonPath + ".canCreateGetter", json["canCreateGetter"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "canCreateGetter");
+      }
+      List<RefactoringMethodParameter> parameters;
+      if (json.containsKey("parameters")) {
+        parameters = jsonDecoder.decodeList(jsonPath + ".parameters", json["parameters"], (String jsonPath, Object json) => new RefactoringMethodParameter.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "parameters");
+      }
+      List<int> offsets;
+      if (json.containsKey("offsets")) {
+        offsets = jsonDecoder.decodeList(jsonPath + ".offsets", json["offsets"], jsonDecoder.decodeInt);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offsets");
+      }
+      List<int> lengths;
+      if (json.containsKey("lengths")) {
+        lengths = jsonDecoder.decodeList(jsonPath + ".lengths", json["lengths"], jsonDecoder.decodeInt);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "lengths");
+      }
+      return new ExtractMethodFeedback(offset, length, returnType, names, canCreateGetter, parameters, offsets, lengths);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "extractMethod feedback", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["offset"] = offset;
+    result["length"] = length;
+    result["returnType"] = returnType;
+    result["names"] = names;
+    result["canCreateGetter"] = canCreateGetter;
+    result["parameters"] = parameters.map((RefactoringMethodParameter value) => value.toJson()).toList();
+    result["offsets"] = offsets;
+    result["lengths"] = lengths;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ExtractMethodFeedback) {
+      return offset == other.offset &&
+          length == other.length &&
+          returnType == other.returnType &&
+          listEqual(names, other.names, (String a, String b) => a == b) &&
+          canCreateGetter == other.canCreateGetter &&
+          listEqual(parameters, other.parameters, (RefactoringMethodParameter a, RefactoringMethodParameter b) => a == b) &&
+          listEqual(offsets, other.offsets, (int a, int b) => a == b) &&
+          listEqual(lengths, other.lengths, (int a, int b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, returnType.hashCode);
+    hash = JenkinsSmiHash.combine(hash, names.hashCode);
+    hash = JenkinsSmiHash.combine(hash, canCreateGetter.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameters.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offsets.hashCode);
+    hash = JenkinsSmiHash.combine(hash, lengths.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * extractMethod options
+ *
+ * {
+ *   "returnType": String
+ *   "createGetter": bool
+ *   "name": String
+ *   "parameters": List<RefactoringMethodParameter>
+ *   "extractAll": bool
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ExtractMethodOptions extends RefactoringOptions {
+  String _returnType;
+
+  bool _createGetter;
+
+  String _name;
+
+  List<RefactoringMethodParameter> _parameters;
+
+  bool _extractAll;
+
+  /**
+   * The return type that should be defined for the method.
+   */
+  String get returnType => _returnType;
+
+  /**
+   * The return type that should be defined for the method.
+   */
+  void set returnType(String value) {
+    assert(value != null);
+    this._returnType = value;
+  }
+
+  /**
+   * True if a getter should be created rather than a method. It is an error if
+   * this field is true and the list of parameters is non-empty.
+   */
+  bool get createGetter => _createGetter;
+
+  /**
+   * True if a getter should be created rather than a method. It is an error if
+   * this field is true and the list of parameters is non-empty.
+   */
+  void set createGetter(bool value) {
+    assert(value != null);
+    this._createGetter = value;
+  }
+
+  /**
+   * The name that the method should be given.
+   */
+  String get name => _name;
+
+  /**
+   * The name that the method should be given.
+   */
+  void set name(String value) {
+    assert(value != null);
+    this._name = value;
+  }
+
+  /**
+   * The parameters that should be defined for the method.
+   *
+   * It is an error if a REQUIRED or NAMED parameter follows a POSITIONAL
+   * parameter. It is an error if a REQUIRED or POSITIONAL parameter follows a
+   * NAMED parameter.
+   *
+   * - To change the order and/or update proposed parameters, add parameters
+   *   with the same identifiers as proposed.
+   * - To add new parameters, omit their identifier.
+   * - To remove some parameters, omit them in this list.
+   */
+  List<RefactoringMethodParameter> get parameters => _parameters;
+
+  /**
+   * The parameters that should be defined for the method.
+   *
+   * It is an error if a REQUIRED or NAMED parameter follows a POSITIONAL
+   * parameter. It is an error if a REQUIRED or POSITIONAL parameter follows a
+   * NAMED parameter.
+   *
+   * - To change the order and/or update proposed parameters, add parameters
+   *   with the same identifiers as proposed.
+   * - To add new parameters, omit their identifier.
+   * - To remove some parameters, omit them in this list.
+   */
+  void set parameters(List<RefactoringMethodParameter> value) {
+    assert(value != null);
+    this._parameters = value;
+  }
+
+  /**
+   * True if all occurrences of the expression or statements should be replaced
+   * by an invocation of the method. The expression or statements used to
+   * initiate the refactoring will always be replaced.
+   */
+  bool get extractAll => _extractAll;
+
+  /**
+   * True if all occurrences of the expression or statements should be replaced
+   * by an invocation of the method. The expression or statements used to
+   * initiate the refactoring will always be replaced.
+   */
+  void set extractAll(bool value) {
+    assert(value != null);
+    this._extractAll = value;
+  }
+
+  ExtractMethodOptions(String returnType, bool createGetter, String name, List<RefactoringMethodParameter> parameters, bool extractAll) {
+    this.returnType = returnType;
+    this.createGetter = createGetter;
+    this.name = name;
+    this.parameters = parameters;
+    this.extractAll = extractAll;
+  }
+
+  factory ExtractMethodOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String returnType;
+      if (json.containsKey("returnType")) {
+        returnType = jsonDecoder.decodeString(jsonPath + ".returnType", json["returnType"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "returnType");
+      }
+      bool createGetter;
+      if (json.containsKey("createGetter")) {
+        createGetter = jsonDecoder.decodeBool(jsonPath + ".createGetter", json["createGetter"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "createGetter");
+      }
+      String name;
+      if (json.containsKey("name")) {
+        name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "name");
+      }
+      List<RefactoringMethodParameter> parameters;
+      if (json.containsKey("parameters")) {
+        parameters = jsonDecoder.decodeList(jsonPath + ".parameters", json["parameters"], (String jsonPath, Object json) => new RefactoringMethodParameter.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "parameters");
+      }
+      bool extractAll;
+      if (json.containsKey("extractAll")) {
+        extractAll = jsonDecoder.decodeBool(jsonPath + ".extractAll", json["extractAll"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "extractAll");
+      }
+      return new ExtractMethodOptions(returnType, createGetter, name, parameters, extractAll);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "extractMethod options", json);
+    }
+  }
+
+  factory ExtractMethodOptions.fromRefactoringParams(EditGetRefactoringParams refactoringParams, Request request) {
+    return new ExtractMethodOptions.fromJson(
+        new RequestDecoder(request), "options", refactoringParams.options);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["returnType"] = returnType;
+    result["createGetter"] = createGetter;
+    result["name"] = name;
+    result["parameters"] = parameters.map((RefactoringMethodParameter value) => value.toJson()).toList();
+    result["extractAll"] = extractAll;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is ExtractMethodOptions) {
+      return returnType == other.returnType &&
+          createGetter == other.createGetter &&
+          name == other.name &&
+          listEqual(parameters, other.parameters, (RefactoringMethodParameter a, RefactoringMethodParameter b) => a == b) &&
+          extractAll == other.extractAll;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, returnType.hashCode);
+    hash = JenkinsSmiHash.combine(hash, createGetter.hashCode);
+    hash = JenkinsSmiHash.combine(hash, name.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameters.hashCode);
+    hash = JenkinsSmiHash.combine(hash, extractAll.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * FoldingKind
+ *
+ * enum {
+ *   COMMENT
+ *   CLASS_MEMBER
+ *   DIRECTIVES
+ *   DOCUMENTATION_COMMENT
+ *   TOP_LEVEL_DECLARATION
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class FoldingKind implements Enum {
+  static const FoldingKind COMMENT = const FoldingKind._("COMMENT");
+
+  static const FoldingKind CLASS_MEMBER = const FoldingKind._("CLASS_MEMBER");
+
+  static const FoldingKind DIRECTIVES = const FoldingKind._("DIRECTIVES");
+
+  static const FoldingKind DOCUMENTATION_COMMENT = const FoldingKind._("DOCUMENTATION_COMMENT");
+
+  static const FoldingKind TOP_LEVEL_DECLARATION = const FoldingKind._("TOP_LEVEL_DECLARATION");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<FoldingKind> VALUES = const <FoldingKind>[COMMENT, CLASS_MEMBER, DIRECTIVES, DOCUMENTATION_COMMENT, TOP_LEVEL_DECLARATION];
+
+  @override
+  final String name;
+
+  const FoldingKind._(this.name);
+
+  factory FoldingKind(String name) {
+    switch (name) {
+      case "COMMENT":
+        return COMMENT;
+      case "CLASS_MEMBER":
+        return CLASS_MEMBER;
+      case "DIRECTIVES":
+        return DIRECTIVES;
+      case "DOCUMENTATION_COMMENT":
+        return DOCUMENTATION_COMMENT;
+      case "TOP_LEVEL_DECLARATION":
+        return TOP_LEVEL_DECLARATION;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory FoldingKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new FoldingKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "FoldingKind", json);
+  }
+
+  @override
+  String toString() => "FoldingKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * FoldingRegion
+ *
+ * {
+ *   "kind": FoldingKind
+ *   "offset": int
+ *   "length": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class FoldingRegion implements HasToJson {
+  FoldingKind _kind;
+
+  int _offset;
+
+  int _length;
+
+  /**
+   * The kind of the region.
+   */
+  FoldingKind get kind => _kind;
+
+  /**
+   * The kind of the region.
+   */
+  void set kind(FoldingKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The offset of the region to be folded.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the region to be folded.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the region to be folded.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the region to be folded.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  FoldingRegion(FoldingKind kind, int offset, int length) {
+    this.kind = kind;
+    this.offset = offset;
+    this.length = length;
+  }
+
+  factory FoldingRegion.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      FoldingKind kind;
+      if (json.containsKey("kind")) {
+        kind = new FoldingKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      return new FoldingRegion(kind, offset, length);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "FoldingRegion", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["kind"] = kind.toJson();
+    result["offset"] = offset;
+    result["length"] = length;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is FoldingRegion) {
+      return kind == other.kind &&
+          offset == other.offset &&
+          length == other.length;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * HighlightRegion
+ *
+ * {
+ *   "type": HighlightRegionType
+ *   "offset": int
+ *   "length": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class HighlightRegion implements HasToJson {
+  HighlightRegionType _type;
+
+  int _offset;
+
+  int _length;
+
+  /**
+   * The type of highlight associated with the region.
+   */
+  HighlightRegionType get type => _type;
+
+  /**
+   * The type of highlight associated with the region.
+   */
+  void set type(HighlightRegionType value) {
+    assert(value != null);
+    this._type = value;
+  }
+
+  /**
+   * The offset of the region to be highlighted.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the region to be highlighted.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the region to be highlighted.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the region to be highlighted.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  HighlightRegion(HighlightRegionType type, int offset, int length) {
+    this.type = type;
+    this.offset = offset;
+    this.length = length;
+  }
+
+  factory HighlightRegion.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      HighlightRegionType type;
+      if (json.containsKey("type")) {
+        type = new HighlightRegionType.fromJson(jsonDecoder, jsonPath + ".type", json["type"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "type");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      return new HighlightRegion(type, offset, length);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "HighlightRegion", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["type"] = type.toJson();
+    result["offset"] = offset;
+    result["length"] = length;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is HighlightRegion) {
+      return type == other.type &&
+          offset == other.offset &&
+          length == other.length;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, type.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * HighlightRegionType
+ *
+ * enum {
+ *   ANNOTATION
+ *   BUILT_IN
+ *   CLASS
+ *   COMMENT_BLOCK
+ *   COMMENT_DOCUMENTATION
+ *   COMMENT_END_OF_LINE
+ *   CONSTRUCTOR
+ *   DIRECTIVE
+ *   DYNAMIC_TYPE
+ *   DYNAMIC_LOCAL_VARIABLE_DECLARATION
+ *   DYNAMIC_LOCAL_VARIABLE_REFERENCE
+ *   DYNAMIC_PARAMETER_DECLARATION
+ *   DYNAMIC_PARAMETER_REFERENCE
+ *   ENUM
+ *   ENUM_CONSTANT
+ *   FIELD
+ *   FIELD_STATIC
+ *   FUNCTION
+ *   FUNCTION_DECLARATION
+ *   FUNCTION_TYPE_ALIAS
+ *   GETTER_DECLARATION
+ *   IDENTIFIER_DEFAULT
+ *   IMPORT_PREFIX
+ *   INSTANCE_FIELD_DECLARATION
+ *   INSTANCE_FIELD_REFERENCE
+ *   INSTANCE_GETTER_DECLARATION
+ *   INSTANCE_GETTER_REFERENCE
+ *   INSTANCE_METHOD_DECLARATION
+ *   INSTANCE_METHOD_REFERENCE
+ *   INSTANCE_SETTER_DECLARATION
+ *   INSTANCE_SETTER_REFERENCE
+ *   INVALID_STRING_ESCAPE
+ *   KEYWORD
+ *   LABEL
+ *   LIBRARY_NAME
+ *   LITERAL_BOOLEAN
+ *   LITERAL_DOUBLE
+ *   LITERAL_INTEGER
+ *   LITERAL_LIST
+ *   LITERAL_MAP
+ *   LITERAL_STRING
+ *   LOCAL_FUNCTION_DECLARATION
+ *   LOCAL_FUNCTION_REFERENCE
+ *   LOCAL_VARIABLE
+ *   LOCAL_VARIABLE_DECLARATION
+ *   LOCAL_VARIABLE_REFERENCE
+ *   METHOD
+ *   METHOD_DECLARATION
+ *   METHOD_DECLARATION_STATIC
+ *   METHOD_STATIC
+ *   PARAMETER
+ *   SETTER_DECLARATION
+ *   TOP_LEVEL_VARIABLE
+ *   PARAMETER_DECLARATION
+ *   PARAMETER_REFERENCE
+ *   STATIC_FIELD_DECLARATION
+ *   STATIC_GETTER_DECLARATION
+ *   STATIC_GETTER_REFERENCE
+ *   STATIC_METHOD_DECLARATION
+ *   STATIC_METHOD_REFERENCE
+ *   STATIC_SETTER_DECLARATION
+ *   STATIC_SETTER_REFERENCE
+ *   TOP_LEVEL_FUNCTION_DECLARATION
+ *   TOP_LEVEL_FUNCTION_REFERENCE
+ *   TOP_LEVEL_GETTER_DECLARATION
+ *   TOP_LEVEL_GETTER_REFERENCE
+ *   TOP_LEVEL_SETTER_DECLARATION
+ *   TOP_LEVEL_SETTER_REFERENCE
+ *   TOP_LEVEL_VARIABLE_DECLARATION
+ *   TYPE_NAME_DYNAMIC
+ *   TYPE_PARAMETER
+ *   UNRESOLVED_INSTANCE_MEMBER_REFERENCE
+ *   VALID_STRING_ESCAPE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class HighlightRegionType implements Enum {
+  static const HighlightRegionType ANNOTATION = const HighlightRegionType._("ANNOTATION");
+
+  static const HighlightRegionType BUILT_IN = const HighlightRegionType._("BUILT_IN");
+
+  static const HighlightRegionType CLASS = const HighlightRegionType._("CLASS");
+
+  static const HighlightRegionType COMMENT_BLOCK = const HighlightRegionType._("COMMENT_BLOCK");
+
+  static const HighlightRegionType COMMENT_DOCUMENTATION = const HighlightRegionType._("COMMENT_DOCUMENTATION");
+
+  static const HighlightRegionType COMMENT_END_OF_LINE = const HighlightRegionType._("COMMENT_END_OF_LINE");
+
+  static const HighlightRegionType CONSTRUCTOR = const HighlightRegionType._("CONSTRUCTOR");
+
+  static const HighlightRegionType DIRECTIVE = const HighlightRegionType._("DIRECTIVE");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType DYNAMIC_TYPE = const HighlightRegionType._("DYNAMIC_TYPE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType DYNAMIC_LOCAL_VARIABLE_DECLARATION = const HighlightRegionType._("DYNAMIC_LOCAL_VARIABLE_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType DYNAMIC_LOCAL_VARIABLE_REFERENCE = const HighlightRegionType._("DYNAMIC_LOCAL_VARIABLE_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType DYNAMIC_PARAMETER_DECLARATION = const HighlightRegionType._("DYNAMIC_PARAMETER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType DYNAMIC_PARAMETER_REFERENCE = const HighlightRegionType._("DYNAMIC_PARAMETER_REFERENCE");
+
+  static const HighlightRegionType ENUM = const HighlightRegionType._("ENUM");
+
+  static const HighlightRegionType ENUM_CONSTANT = const HighlightRegionType._("ENUM_CONSTANT");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType FIELD = const HighlightRegionType._("FIELD");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType FIELD_STATIC = const HighlightRegionType._("FIELD_STATIC");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType FUNCTION = const HighlightRegionType._("FUNCTION");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType FUNCTION_DECLARATION = const HighlightRegionType._("FUNCTION_DECLARATION");
+
+  static const HighlightRegionType FUNCTION_TYPE_ALIAS = const HighlightRegionType._("FUNCTION_TYPE_ALIAS");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType GETTER_DECLARATION = const HighlightRegionType._("GETTER_DECLARATION");
+
+  static const HighlightRegionType IDENTIFIER_DEFAULT = const HighlightRegionType._("IDENTIFIER_DEFAULT");
+
+  static const HighlightRegionType IMPORT_PREFIX = const HighlightRegionType._("IMPORT_PREFIX");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_FIELD_DECLARATION = const HighlightRegionType._("INSTANCE_FIELD_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_FIELD_REFERENCE = const HighlightRegionType._("INSTANCE_FIELD_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_GETTER_DECLARATION = const HighlightRegionType._("INSTANCE_GETTER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_GETTER_REFERENCE = const HighlightRegionType._("INSTANCE_GETTER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_METHOD_DECLARATION = const HighlightRegionType._("INSTANCE_METHOD_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_METHOD_REFERENCE = const HighlightRegionType._("INSTANCE_METHOD_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_SETTER_DECLARATION = const HighlightRegionType._("INSTANCE_SETTER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INSTANCE_SETTER_REFERENCE = const HighlightRegionType._("INSTANCE_SETTER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType INVALID_STRING_ESCAPE = const HighlightRegionType._("INVALID_STRING_ESCAPE");
+
+  static const HighlightRegionType KEYWORD = const HighlightRegionType._("KEYWORD");
+
+  static const HighlightRegionType LABEL = const HighlightRegionType._("LABEL");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType LIBRARY_NAME = const HighlightRegionType._("LIBRARY_NAME");
+
+  static const HighlightRegionType LITERAL_BOOLEAN = const HighlightRegionType._("LITERAL_BOOLEAN");
+
+  static const HighlightRegionType LITERAL_DOUBLE = const HighlightRegionType._("LITERAL_DOUBLE");
+
+  static const HighlightRegionType LITERAL_INTEGER = const HighlightRegionType._("LITERAL_INTEGER");
+
+  static const HighlightRegionType LITERAL_LIST = const HighlightRegionType._("LITERAL_LIST");
+
+  static const HighlightRegionType LITERAL_MAP = const HighlightRegionType._("LITERAL_MAP");
+
+  static const HighlightRegionType LITERAL_STRING = const HighlightRegionType._("LITERAL_STRING");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType LOCAL_FUNCTION_DECLARATION = const HighlightRegionType._("LOCAL_FUNCTION_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType LOCAL_FUNCTION_REFERENCE = const HighlightRegionType._("LOCAL_FUNCTION_REFERENCE");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType LOCAL_VARIABLE = const HighlightRegionType._("LOCAL_VARIABLE");
+
+  static const HighlightRegionType LOCAL_VARIABLE_DECLARATION = const HighlightRegionType._("LOCAL_VARIABLE_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType LOCAL_VARIABLE_REFERENCE = const HighlightRegionType._("LOCAL_VARIABLE_REFERENCE");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType METHOD = const HighlightRegionType._("METHOD");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType METHOD_DECLARATION = const HighlightRegionType._("METHOD_DECLARATION");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType METHOD_DECLARATION_STATIC = const HighlightRegionType._("METHOD_DECLARATION_STATIC");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType METHOD_STATIC = const HighlightRegionType._("METHOD_STATIC");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType PARAMETER = const HighlightRegionType._("PARAMETER");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType SETTER_DECLARATION = const HighlightRegionType._("SETTER_DECLARATION");
+
+  /**
+   * Only for version 1 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_VARIABLE = const HighlightRegionType._("TOP_LEVEL_VARIABLE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType PARAMETER_DECLARATION = const HighlightRegionType._("PARAMETER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType PARAMETER_REFERENCE = const HighlightRegionType._("PARAMETER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_FIELD_DECLARATION = const HighlightRegionType._("STATIC_FIELD_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_GETTER_DECLARATION = const HighlightRegionType._("STATIC_GETTER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_GETTER_REFERENCE = const HighlightRegionType._("STATIC_GETTER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_METHOD_DECLARATION = const HighlightRegionType._("STATIC_METHOD_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_METHOD_REFERENCE = const HighlightRegionType._("STATIC_METHOD_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_SETTER_DECLARATION = const HighlightRegionType._("STATIC_SETTER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType STATIC_SETTER_REFERENCE = const HighlightRegionType._("STATIC_SETTER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_FUNCTION_DECLARATION = const HighlightRegionType._("TOP_LEVEL_FUNCTION_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_FUNCTION_REFERENCE = const HighlightRegionType._("TOP_LEVEL_FUNCTION_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_GETTER_DECLARATION = const HighlightRegionType._("TOP_LEVEL_GETTER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_GETTER_REFERENCE = const HighlightRegionType._("TOP_LEVEL_GETTER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_SETTER_DECLARATION = const HighlightRegionType._("TOP_LEVEL_SETTER_DECLARATION");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_SETTER_REFERENCE = const HighlightRegionType._("TOP_LEVEL_SETTER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType TOP_LEVEL_VARIABLE_DECLARATION = const HighlightRegionType._("TOP_LEVEL_VARIABLE_DECLARATION");
+
+  static const HighlightRegionType TYPE_NAME_DYNAMIC = const HighlightRegionType._("TYPE_NAME_DYNAMIC");
+
+  static const HighlightRegionType TYPE_PARAMETER = const HighlightRegionType._("TYPE_PARAMETER");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType UNRESOLVED_INSTANCE_MEMBER_REFERENCE = const HighlightRegionType._("UNRESOLVED_INSTANCE_MEMBER_REFERENCE");
+
+  /**
+   * Only for version 2 of highlight.
+   */
+  static const HighlightRegionType VALID_STRING_ESCAPE = const HighlightRegionType._("VALID_STRING_ESCAPE");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<HighlightRegionType> VALUES = const <HighlightRegionType>[ANNOTATION, BUILT_IN, CLASS, COMMENT_BLOCK, COMMENT_DOCUMENTATION, COMMENT_END_OF_LINE, CONSTRUCTOR, DIRECTIVE, DYNAMIC_TYPE, DYNAMIC_LOCAL_VARIABLE_DECLARATION, DYNAMIC_LOCAL_VARIABLE_REFERENCE, DYNAMIC_PARAMETER_DECLARATION, DYNAMIC_PARAMETER_REFERENCE, ENUM, ENUM_CONSTANT, FIELD, FIELD_STATIC, FUNCTION, FUNCTION_DECLARATION, FUNCTION_TYPE_ALIAS, GETTER_DECLARATION, IDENTIFIER_DEFAULT, IMPORT_PREFIX, INSTANCE_FIELD_DECLARATION, INSTANCE_FIELD_REFERENCE, INSTANCE_GETTER_DECLARATION, INSTANCE_GETTER_REFERENCE, INSTANCE_METHOD_DECLARATION, INSTANCE_METHOD_REFERENCE, INSTANCE_SETTER_DECLARATION, INSTANCE_SETTER_REFERENCE, INVALID_STRING_ESCAPE, KEYWORD, LABEL, LIBRARY_NAME, LITERAL_BOOLEAN, LITERAL_DOUBLE, LITERAL_INTEGER, LITERAL_LIST, LITERAL_MAP, LITERAL_STRING, LOCAL_FUNCTION_DECLARATION, LOCAL_FUNCTION_REFERENCE, LOCAL_VARIABLE, LOCAL_VARIABLE_DECLARATION, LOCAL_VARIABLE_REFERENCE, METHOD, METHOD_DECLARATION, METHOD_DECLARATION_STATIC, METHOD_STATIC, PARAMETER, SETTER_DECLARATION, TOP_LEVEL_VARIABLE, PARAMETER_DECLARATION, PARAMETER_REFERENCE, STATIC_FIELD_DECLARATION, STATIC_GETTER_DECLARATION, STATIC_GETTER_REFERENCE, STATIC_METHOD_DECLARATION, STATIC_METHOD_REFERENCE, STATIC_SETTER_DECLARATION, STATIC_SETTER_REFERENCE, TOP_LEVEL_FUNCTION_DECLARATION, TOP_LEVEL_FUNCTION_REFERENCE, TOP_LEVEL_GETTER_DECLARATION, TOP_LEVEL_GETTER_REFERENCE, TOP_LEVEL_SETTER_DECLARATION, TOP_LEVEL_SETTER_REFERENCE, TOP_LEVEL_VARIABLE_DECLARATION, TYPE_NAME_DYNAMIC, TYPE_PARAMETER, UNRESOLVED_INSTANCE_MEMBER_REFERENCE, VALID_STRING_ESCAPE];
+
+  @override
+  final String name;
+
+  const HighlightRegionType._(this.name);
+
+  factory HighlightRegionType(String name) {
+    switch (name) {
+      case "ANNOTATION":
+        return ANNOTATION;
+      case "BUILT_IN":
+        return BUILT_IN;
+      case "CLASS":
+        return CLASS;
+      case "COMMENT_BLOCK":
+        return COMMENT_BLOCK;
+      case "COMMENT_DOCUMENTATION":
+        return COMMENT_DOCUMENTATION;
+      case "COMMENT_END_OF_LINE":
+        return COMMENT_END_OF_LINE;
+      case "CONSTRUCTOR":
+        return CONSTRUCTOR;
+      case "DIRECTIVE":
+        return DIRECTIVE;
+      case "DYNAMIC_TYPE":
+        return DYNAMIC_TYPE;
+      case "DYNAMIC_LOCAL_VARIABLE_DECLARATION":
+        return DYNAMIC_LOCAL_VARIABLE_DECLARATION;
+      case "DYNAMIC_LOCAL_VARIABLE_REFERENCE":
+        return DYNAMIC_LOCAL_VARIABLE_REFERENCE;
+      case "DYNAMIC_PARAMETER_DECLARATION":
+        return DYNAMIC_PARAMETER_DECLARATION;
+      case "DYNAMIC_PARAMETER_REFERENCE":
+        return DYNAMIC_PARAMETER_REFERENCE;
+      case "ENUM":
+        return ENUM;
+      case "ENUM_CONSTANT":
+        return ENUM_CONSTANT;
+      case "FIELD":
+        return FIELD;
+      case "FIELD_STATIC":
+        return FIELD_STATIC;
+      case "FUNCTION":
+        return FUNCTION;
+      case "FUNCTION_DECLARATION":
+        return FUNCTION_DECLARATION;
+      case "FUNCTION_TYPE_ALIAS":
+        return FUNCTION_TYPE_ALIAS;
+      case "GETTER_DECLARATION":
+        return GETTER_DECLARATION;
+      case "IDENTIFIER_DEFAULT":
+        return IDENTIFIER_DEFAULT;
+      case "IMPORT_PREFIX":
+        return IMPORT_PREFIX;
+      case "INSTANCE_FIELD_DECLARATION":
+        return INSTANCE_FIELD_DECLARATION;
+      case "INSTANCE_FIELD_REFERENCE":
+        return INSTANCE_FIELD_REFERENCE;
+      case "INSTANCE_GETTER_DECLARATION":
+        return INSTANCE_GETTER_DECLARATION;
+      case "INSTANCE_GETTER_REFERENCE":
+        return INSTANCE_GETTER_REFERENCE;
+      case "INSTANCE_METHOD_DECLARATION":
+        return INSTANCE_METHOD_DECLARATION;
+      case "INSTANCE_METHOD_REFERENCE":
+        return INSTANCE_METHOD_REFERENCE;
+      case "INSTANCE_SETTER_DECLARATION":
+        return INSTANCE_SETTER_DECLARATION;
+      case "INSTANCE_SETTER_REFERENCE":
+        return INSTANCE_SETTER_REFERENCE;
+      case "INVALID_STRING_ESCAPE":
+        return INVALID_STRING_ESCAPE;
+      case "KEYWORD":
+        return KEYWORD;
+      case "LABEL":
+        return LABEL;
+      case "LIBRARY_NAME":
+        return LIBRARY_NAME;
+      case "LITERAL_BOOLEAN":
+        return LITERAL_BOOLEAN;
+      case "LITERAL_DOUBLE":
+        return LITERAL_DOUBLE;
+      case "LITERAL_INTEGER":
+        return LITERAL_INTEGER;
+      case "LITERAL_LIST":
+        return LITERAL_LIST;
+      case "LITERAL_MAP":
+        return LITERAL_MAP;
+      case "LITERAL_STRING":
+        return LITERAL_STRING;
+      case "LOCAL_FUNCTION_DECLARATION":
+        return LOCAL_FUNCTION_DECLARATION;
+      case "LOCAL_FUNCTION_REFERENCE":
+        return LOCAL_FUNCTION_REFERENCE;
+      case "LOCAL_VARIABLE":
+        return LOCAL_VARIABLE;
+      case "LOCAL_VARIABLE_DECLARATION":
+        return LOCAL_VARIABLE_DECLARATION;
+      case "LOCAL_VARIABLE_REFERENCE":
+        return LOCAL_VARIABLE_REFERENCE;
+      case "METHOD":
+        return METHOD;
+      case "METHOD_DECLARATION":
+        return METHOD_DECLARATION;
+      case "METHOD_DECLARATION_STATIC":
+        return METHOD_DECLARATION_STATIC;
+      case "METHOD_STATIC":
+        return METHOD_STATIC;
+      case "PARAMETER":
+        return PARAMETER;
+      case "SETTER_DECLARATION":
+        return SETTER_DECLARATION;
+      case "TOP_LEVEL_VARIABLE":
+        return TOP_LEVEL_VARIABLE;
+      case "PARAMETER_DECLARATION":
+        return PARAMETER_DECLARATION;
+      case "PARAMETER_REFERENCE":
+        return PARAMETER_REFERENCE;
+      case "STATIC_FIELD_DECLARATION":
+        return STATIC_FIELD_DECLARATION;
+      case "STATIC_GETTER_DECLARATION":
+        return STATIC_GETTER_DECLARATION;
+      case "STATIC_GETTER_REFERENCE":
+        return STATIC_GETTER_REFERENCE;
+      case "STATIC_METHOD_DECLARATION":
+        return STATIC_METHOD_DECLARATION;
+      case "STATIC_METHOD_REFERENCE":
+        return STATIC_METHOD_REFERENCE;
+      case "STATIC_SETTER_DECLARATION":
+        return STATIC_SETTER_DECLARATION;
+      case "STATIC_SETTER_REFERENCE":
+        return STATIC_SETTER_REFERENCE;
+      case "TOP_LEVEL_FUNCTION_DECLARATION":
+        return TOP_LEVEL_FUNCTION_DECLARATION;
+      case "TOP_LEVEL_FUNCTION_REFERENCE":
+        return TOP_LEVEL_FUNCTION_REFERENCE;
+      case "TOP_LEVEL_GETTER_DECLARATION":
+        return TOP_LEVEL_GETTER_DECLARATION;
+      case "TOP_LEVEL_GETTER_REFERENCE":
+        return TOP_LEVEL_GETTER_REFERENCE;
+      case "TOP_LEVEL_SETTER_DECLARATION":
+        return TOP_LEVEL_SETTER_DECLARATION;
+      case "TOP_LEVEL_SETTER_REFERENCE":
+        return TOP_LEVEL_SETTER_REFERENCE;
+      case "TOP_LEVEL_VARIABLE_DECLARATION":
+        return TOP_LEVEL_VARIABLE_DECLARATION;
+      case "TYPE_NAME_DYNAMIC":
+        return TYPE_NAME_DYNAMIC;
+      case "TYPE_PARAMETER":
+        return TYPE_PARAMETER;
+      case "UNRESOLVED_INSTANCE_MEMBER_REFERENCE":
+        return UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
+      case "VALID_STRING_ESCAPE":
+        return VALID_STRING_ESCAPE;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory HighlightRegionType.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new HighlightRegionType(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "HighlightRegionType", json);
+  }
+
+  @override
+  String toString() => "HighlightRegionType.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * inlineLocalVariable feedback
+ *
+ * {
+ *   "name": String
+ *   "occurrences": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class InlineLocalVariableFeedback extends RefactoringFeedback {
+  String _name;
+
+  int _occurrences;
+
+  /**
+   * The name of the variable being inlined.
+   */
+  String get name => _name;
+
+  /**
+   * The name of the variable being inlined.
+   */
+  void set name(String value) {
+    assert(value != null);
+    this._name = value;
+  }
+
+  /**
+   * The number of times the variable occurs.
+   */
+  int get occurrences => _occurrences;
+
+  /**
+   * The number of times the variable occurs.
+   */
+  void set occurrences(int value) {
+    assert(value != null);
+    this._occurrences = value;
+  }
+
+  InlineLocalVariableFeedback(String name, int occurrences) {
+    this.name = name;
+    this.occurrences = occurrences;
+  }
+
+  factory InlineLocalVariableFeedback.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String name;
+      if (json.containsKey("name")) {
+        name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "name");
+      }
+      int occurrences;
+      if (json.containsKey("occurrences")) {
+        occurrences = jsonDecoder.decodeInt(jsonPath + ".occurrences", json["occurrences"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "occurrences");
+      }
+      return new InlineLocalVariableFeedback(name, occurrences);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "inlineLocalVariable feedback", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["name"] = name;
+    result["occurrences"] = occurrences;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is InlineLocalVariableFeedback) {
+      return name == other.name &&
+          occurrences == other.occurrences;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, name.hashCode);
+    hash = JenkinsSmiHash.combine(hash, occurrences.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * inlineLocalVariable options
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class InlineLocalVariableOptions extends RefactoringOptions implements HasToJson {
+  @override
+  bool operator==(other) {
+    if (other is InlineLocalVariableOptions) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 540364977;
+  }
+}
+
+/**
+ * inlineMethod feedback
+ *
+ * {
+ *   "className": optional String
+ *   "methodName": String
+ *   "isDeclaration": bool
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class InlineMethodFeedback extends RefactoringFeedback {
+  String _className;
+
+  String _methodName;
+
+  bool _isDeclaration;
+
+  /**
+   * The name of the class enclosing the method being inlined. If not a class
+   * member is being inlined, this field will be absent.
+   */
+  String get className => _className;
+
+  /**
+   * The name of the class enclosing the method being inlined. If not a class
+   * member is being inlined, this field will be absent.
+   */
+  void set className(String value) {
+    this._className = value;
+  }
+
+  /**
+   * The name of the method (or function) being inlined.
+   */
+  String get methodName => _methodName;
+
+  /**
+   * The name of the method (or function) being inlined.
+   */
+  void set methodName(String value) {
+    assert(value != null);
+    this._methodName = value;
+  }
+
+  /**
+   * True if the declaration of the method is selected and all references
+   * should be inlined.
+   */
+  bool get isDeclaration => _isDeclaration;
+
+  /**
+   * True if the declaration of the method is selected and all references
+   * should be inlined.
+   */
+  void set isDeclaration(bool value) {
+    assert(value != null);
+    this._isDeclaration = value;
+  }
+
+  InlineMethodFeedback(String methodName, bool isDeclaration, {String className}) {
+    this.className = className;
+    this.methodName = methodName;
+    this.isDeclaration = isDeclaration;
+  }
+
+  factory InlineMethodFeedback.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String className;
+      if (json.containsKey("className")) {
+        className = jsonDecoder.decodeString(jsonPath + ".className", json["className"]);
+      }
+      String methodName;
+      if (json.containsKey("methodName")) {
+        methodName = jsonDecoder.decodeString(jsonPath + ".methodName", json["methodName"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "methodName");
+      }
+      bool isDeclaration;
+      if (json.containsKey("isDeclaration")) {
+        isDeclaration = jsonDecoder.decodeBool(jsonPath + ".isDeclaration", json["isDeclaration"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "isDeclaration");
+      }
+      return new InlineMethodFeedback(methodName, isDeclaration, className: className);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "inlineMethod feedback", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    if (className != null) {
+      result["className"] = className;
+    }
+    result["methodName"] = methodName;
+    result["isDeclaration"] = isDeclaration;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is InlineMethodFeedback) {
+      return className == other.className &&
+          methodName == other.methodName &&
+          isDeclaration == other.isDeclaration;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, className.hashCode);
+    hash = JenkinsSmiHash.combine(hash, methodName.hashCode);
+    hash = JenkinsSmiHash.combine(hash, isDeclaration.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * inlineMethod options
+ *
+ * {
+ *   "deleteSource": bool
+ *   "inlineAll": bool
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class InlineMethodOptions extends RefactoringOptions {
+  bool _deleteSource;
+
+  bool _inlineAll;
+
+  /**
+   * True if the method being inlined should be removed. It is an error if this
+   * field is true and inlineAll is false.
+   */
+  bool get deleteSource => _deleteSource;
+
+  /**
+   * True if the method being inlined should be removed. It is an error if this
+   * field is true and inlineAll is false.
+   */
+  void set deleteSource(bool value) {
+    assert(value != null);
+    this._deleteSource = value;
+  }
+
+  /**
+   * True if all invocations of the method should be inlined, or false if only
+   * the invocation site used to create this refactoring should be inlined.
+   */
+  bool get inlineAll => _inlineAll;
+
+  /**
+   * True if all invocations of the method should be inlined, or false if only
+   * the invocation site used to create this refactoring should be inlined.
+   */
+  void set inlineAll(bool value) {
+    assert(value != null);
+    this._inlineAll = value;
+  }
+
+  InlineMethodOptions(bool deleteSource, bool inlineAll) {
+    this.deleteSource = deleteSource;
+    this.inlineAll = inlineAll;
+  }
+
+  factory InlineMethodOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      bool deleteSource;
+      if (json.containsKey("deleteSource")) {
+        deleteSource = jsonDecoder.decodeBool(jsonPath + ".deleteSource", json["deleteSource"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "deleteSource");
+      }
+      bool inlineAll;
+      if (json.containsKey("inlineAll")) {
+        inlineAll = jsonDecoder.decodeBool(jsonPath + ".inlineAll", json["inlineAll"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "inlineAll");
+      }
+      return new InlineMethodOptions(deleteSource, inlineAll);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "inlineMethod options", json);
+    }
+  }
+
+  factory InlineMethodOptions.fromRefactoringParams(EditGetRefactoringParams refactoringParams, Request request) {
+    return new InlineMethodOptions.fromJson(
+        new RequestDecoder(request), "options", refactoringParams.options);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["deleteSource"] = deleteSource;
+    result["inlineAll"] = inlineAll;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is InlineMethodOptions) {
+      return deleteSource == other.deleteSource &&
+          inlineAll == other.inlineAll;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, deleteSource.hashCode);
+    hash = JenkinsSmiHash.combine(hash, inlineAll.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * LinkedEditGroup
+ *
+ * {
+ *   "positions": List<Position>
+ *   "length": int
+ *   "suggestions": List<LinkedEditSuggestion>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class LinkedEditGroup implements HasToJson {
+  List<Position> _positions;
+
+  int _length;
+
+  List<LinkedEditSuggestion> _suggestions;
+
+  /**
+   * The positions of the regions that should be edited simultaneously.
+   */
+  List<Position> get positions => _positions;
+
+  /**
+   * The positions of the regions that should be edited simultaneously.
+   */
+  void set positions(List<Position> value) {
+    assert(value != null);
+    this._positions = value;
+  }
+
+  /**
+   * The length of the regions that should be edited simultaneously.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the regions that should be edited simultaneously.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * Pre-computed suggestions for what every region might want to be changed
+   * to.
+   */
+  List<LinkedEditSuggestion> get suggestions => _suggestions;
+
+  /**
+   * Pre-computed suggestions for what every region might want to be changed
+   * to.
+   */
+  void set suggestions(List<LinkedEditSuggestion> value) {
+    assert(value != null);
+    this._suggestions = value;
+  }
+
+  LinkedEditGroup(List<Position> positions, int length, List<LinkedEditSuggestion> suggestions) {
+    this.positions = positions;
+    this.length = length;
+    this.suggestions = suggestions;
+  }
+
+  factory LinkedEditGroup.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<Position> positions;
+      if (json.containsKey("positions")) {
+        positions = jsonDecoder.decodeList(jsonPath + ".positions", json["positions"], (String jsonPath, Object json) => new Position.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "positions");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      List<LinkedEditSuggestion> suggestions;
+      if (json.containsKey("suggestions")) {
+        suggestions = jsonDecoder.decodeList(jsonPath + ".suggestions", json["suggestions"], (String jsonPath, Object json) => new LinkedEditSuggestion.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "suggestions");
+      }
+      return new LinkedEditGroup(positions, length, suggestions);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "LinkedEditGroup", json);
+    }
+  }
+
+  /**
+   * Construct an empty LinkedEditGroup.
+   */
+  LinkedEditGroup.empty() : this(<Position>[], 0, <LinkedEditSuggestion>[]);
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["positions"] = positions.map((Position value) => value.toJson()).toList();
+    result["length"] = length;
+    result["suggestions"] = suggestions.map((LinkedEditSuggestion value) => value.toJson()).toList();
+    return result;
+  }
+
+  /**
+   * Add a new position and change the length.
+   */
+  void addPosition(Position position, int length) {
+    positions.add(position);
+    this.length = length;
+  }
+
+  /**
+   * Add a new suggestion.
+   */
+  void addSuggestion(LinkedEditSuggestion suggestion) {
+    suggestions.add(suggestion);
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is LinkedEditGroup) {
+      return listEqual(positions, other.positions, (Position a, Position b) => a == b) &&
+          length == other.length &&
+          listEqual(suggestions, other.suggestions, (LinkedEditSuggestion a, LinkedEditSuggestion b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, positions.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, suggestions.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * LinkedEditSuggestion
+ *
+ * {
+ *   "value": String
+ *   "kind": LinkedEditSuggestionKind
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class LinkedEditSuggestion implements HasToJson {
+  String _value;
+
+  LinkedEditSuggestionKind _kind;
+
+  /**
+   * The value that could be used to replace all of the linked edit regions.
+   */
+  String get value => _value;
+
+  /**
+   * The value that could be used to replace all of the linked edit regions.
+   */
+  void set value(String value) {
+    assert(value != null);
+    this._value = value;
+  }
+
+  /**
+   * The kind of value being proposed.
+   */
+  LinkedEditSuggestionKind get kind => _kind;
+
+  /**
+   * The kind of value being proposed.
+   */
+  void set kind(LinkedEditSuggestionKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  LinkedEditSuggestion(String value, LinkedEditSuggestionKind kind) {
+    this.value = value;
+    this.kind = kind;
+  }
+
+  factory LinkedEditSuggestion.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String value;
+      if (json.containsKey("value")) {
+        value = jsonDecoder.decodeString(jsonPath + ".value", json["value"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "value");
+      }
+      LinkedEditSuggestionKind kind;
+      if (json.containsKey("kind")) {
+        kind = new LinkedEditSuggestionKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      return new LinkedEditSuggestion(value, kind);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "LinkedEditSuggestion", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["value"] = value;
+    result["kind"] = kind.toJson();
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is LinkedEditSuggestion) {
+      return value == other.value &&
+          kind == other.kind;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, value.hashCode);
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * LinkedEditSuggestionKind
+ *
+ * enum {
+ *   METHOD
+ *   PARAMETER
+ *   TYPE
+ *   VARIABLE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class LinkedEditSuggestionKind implements Enum {
+  static const LinkedEditSuggestionKind METHOD = const LinkedEditSuggestionKind._("METHOD");
+
+  static const LinkedEditSuggestionKind PARAMETER = const LinkedEditSuggestionKind._("PARAMETER");
+
+  static const LinkedEditSuggestionKind TYPE = const LinkedEditSuggestionKind._("TYPE");
+
+  static const LinkedEditSuggestionKind VARIABLE = const LinkedEditSuggestionKind._("VARIABLE");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<LinkedEditSuggestionKind> VALUES = const <LinkedEditSuggestionKind>[METHOD, PARAMETER, TYPE, VARIABLE];
+
+  @override
+  final String name;
+
+  const LinkedEditSuggestionKind._(this.name);
+
+  factory LinkedEditSuggestionKind(String name) {
+    switch (name) {
+      case "METHOD":
+        return METHOD;
+      case "PARAMETER":
+        return PARAMETER;
+      case "TYPE":
+        return TYPE;
+      case "VARIABLE":
+        return VARIABLE;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory LinkedEditSuggestionKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new LinkedEditSuggestionKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "LinkedEditSuggestionKind", json);
+  }
+
+  @override
+  String toString() => "LinkedEditSuggestionKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * Location
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ *   "startLine": int
+ *   "startColumn": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Location implements HasToJson {
+  String _file;
+
+  int _offset;
+
+  int _length;
+
+  int _startLine;
+
+  int _startColumn;
+
+  /**
+   * The file containing the range.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the range.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset of the range.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the range.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the range.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the range.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The one-based index of the line containing the first character of the
+   * range.
+   */
+  int get startLine => _startLine;
+
+  /**
+   * The one-based index of the line containing the first character of the
+   * range.
+   */
+  void set startLine(int value) {
+    assert(value != null);
+    this._startLine = value;
+  }
+
+  /**
+   * The one-based index of the column containing the first character of the
+   * range.
+   */
+  int get startColumn => _startColumn;
+
+  /**
+   * The one-based index of the column containing the first character of the
+   * range.
+   */
+  void set startColumn(int value) {
+    assert(value != null);
+    this._startColumn = value;
+  }
+
+  Location(String file, int offset, int length, int startLine, int startColumn) {
+    this.file = file;
+    this.offset = offset;
+    this.length = length;
+    this.startLine = startLine;
+    this.startColumn = startColumn;
+  }
+
+  factory Location.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      int startLine;
+      if (json.containsKey("startLine")) {
+        startLine = jsonDecoder.decodeInt(jsonPath + ".startLine", json["startLine"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "startLine");
+      }
+      int startColumn;
+      if (json.containsKey("startColumn")) {
+        startColumn = jsonDecoder.decodeInt(jsonPath + ".startColumn", json["startColumn"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "startColumn");
+      }
+      return new Location(file, offset, length, startLine, startColumn);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "Location", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["offset"] = offset;
+    result["length"] = length;
+    result["startLine"] = startLine;
+    result["startColumn"] = startColumn;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is Location) {
+      return file == other.file &&
+          offset == other.offset &&
+          length == other.length &&
+          startLine == other.startLine &&
+          startColumn == other.startColumn;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, startLine.hashCode);
+    hash = JenkinsSmiHash.combine(hash, startColumn.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * moveFile feedback
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class MoveFileFeedback extends RefactoringFeedback implements HasToJson {
+  @override
+  bool operator==(other) {
+    if (other is MoveFileFeedback) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 438975893;
+  }
+}
+
+/**
+ * moveFile options
+ *
+ * {
+ *   "newFile": FilePath
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class MoveFileOptions extends RefactoringOptions {
+  String _newFile;
+
+  /**
+   * The new file path to which the given file is being moved.
+   */
+  String get newFile => _newFile;
+
+  /**
+   * The new file path to which the given file is being moved.
+   */
+  void set newFile(String value) {
+    assert(value != null);
+    this._newFile = value;
+  }
+
+  MoveFileOptions(String newFile) {
+    this.newFile = newFile;
+  }
+
+  factory MoveFileOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String newFile;
+      if (json.containsKey("newFile")) {
+        newFile = jsonDecoder.decodeString(jsonPath + ".newFile", json["newFile"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "newFile");
+      }
+      return new MoveFileOptions(newFile);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "moveFile options", json);
+    }
+  }
+
+  factory MoveFileOptions.fromRefactoringParams(EditGetRefactoringParams refactoringParams, Request request) {
+    return new MoveFileOptions.fromJson(
+        new RequestDecoder(request), "options", refactoringParams.options);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["newFile"] = newFile;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is MoveFileOptions) {
+      return newFile == other.newFile;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, newFile.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * NavigationRegion
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "targets": List<int>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class NavigationRegion implements HasToJson {
+  int _offset;
+
+  int _length;
+
+  List<int> _targets;
+
+  /**
+   * The offset of the region from which the user can navigate.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the region from which the user can navigate.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the region from which the user can navigate.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the region from which the user can navigate.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The indexes of the targets (in the enclosing navigation response) to which
+   * the given region is bound. By opening the target, clients can implement
+   * one form of navigation. This list cannot be empty.
+   */
+  List<int> get targets => _targets;
+
+  /**
+   * The indexes of the targets (in the enclosing navigation response) to which
+   * the given region is bound. By opening the target, clients can implement
+   * one form of navigation. This list cannot be empty.
+   */
+  void set targets(List<int> value) {
+    assert(value != null);
+    this._targets = value;
+  }
+
+  NavigationRegion(int offset, int length, List<int> targets) {
+    this.offset = offset;
+    this.length = length;
+    this.targets = targets;
+  }
+
+  factory NavigationRegion.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      List<int> targets;
+      if (json.containsKey("targets")) {
+        targets = jsonDecoder.decodeList(jsonPath + ".targets", json["targets"], jsonDecoder.decodeInt);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "targets");
+      }
+      return new NavigationRegion(offset, length, targets);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "NavigationRegion", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["offset"] = offset;
+    result["length"] = length;
+    result["targets"] = targets;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is NavigationRegion) {
+      return offset == other.offset &&
+          length == other.length &&
+          listEqual(targets, other.targets, (int a, int b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, targets.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * NavigationTarget
+ *
+ * {
+ *   "kind": ElementKind
+ *   "fileIndex": int
+ *   "offset": int
+ *   "length": int
+ *   "startLine": int
+ *   "startColumn": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class NavigationTarget implements HasToJson {
+  ElementKind _kind;
+
+  int _fileIndex;
+
+  int _offset;
+
+  int _length;
+
+  int _startLine;
+
+  int _startColumn;
+
+  /**
+   * The kind of the element.
+   */
+  ElementKind get kind => _kind;
+
+  /**
+   * The kind of the element.
+   */
+  void set kind(ElementKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The index of the file (in the enclosing navigation response) to navigate
+   * to.
+   */
+  int get fileIndex => _fileIndex;
+
+  /**
+   * The index of the file (in the enclosing navigation response) to navigate
+   * to.
+   */
+  void set fileIndex(int value) {
+    assert(value != null);
+    this._fileIndex = value;
+  }
+
+  /**
+   * The offset of the region to which the user can navigate.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the region to which the user can navigate.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the region to which the user can navigate.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the region to which the user can navigate.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The one-based index of the line containing the first character of the
+   * region.
+   */
+  int get startLine => _startLine;
+
+  /**
+   * The one-based index of the line containing the first character of the
+   * region.
+   */
+  void set startLine(int value) {
+    assert(value != null);
+    this._startLine = value;
+  }
+
+  /**
+   * The one-based index of the column containing the first character of the
+   * region.
+   */
+  int get startColumn => _startColumn;
+
+  /**
+   * The one-based index of the column containing the first character of the
+   * region.
+   */
+  void set startColumn(int value) {
+    assert(value != null);
+    this._startColumn = value;
+  }
+
+  NavigationTarget(ElementKind kind, int fileIndex, int offset, int length, int startLine, int startColumn) {
+    this.kind = kind;
+    this.fileIndex = fileIndex;
+    this.offset = offset;
+    this.length = length;
+    this.startLine = startLine;
+    this.startColumn = startColumn;
+  }
+
+  factory NavigationTarget.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      ElementKind kind;
+      if (json.containsKey("kind")) {
+        kind = new ElementKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      int fileIndex;
+      if (json.containsKey("fileIndex")) {
+        fileIndex = jsonDecoder.decodeInt(jsonPath + ".fileIndex", json["fileIndex"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "fileIndex");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      int startLine;
+      if (json.containsKey("startLine")) {
+        startLine = jsonDecoder.decodeInt(jsonPath + ".startLine", json["startLine"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "startLine");
+      }
+      int startColumn;
+      if (json.containsKey("startColumn")) {
+        startColumn = jsonDecoder.decodeInt(jsonPath + ".startColumn", json["startColumn"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "startColumn");
+      }
+      return new NavigationTarget(kind, fileIndex, offset, length, startLine, startColumn);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "NavigationTarget", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["kind"] = kind.toJson();
+    result["fileIndex"] = fileIndex;
+    result["offset"] = offset;
+    result["length"] = length;
+    result["startLine"] = startLine;
+    result["startColumn"] = startColumn;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is NavigationTarget) {
+      return kind == other.kind &&
+          fileIndex == other.fileIndex &&
+          offset == other.offset &&
+          length == other.length &&
+          startLine == other.startLine &&
+          startColumn == other.startColumn;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, fileIndex.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, startLine.hashCode);
+    hash = JenkinsSmiHash.combine(hash, startColumn.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * Occurrences
+ *
+ * {
+ *   "element": Element
+ *   "offsets": List<int>
+ *   "length": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Occurrences implements HasToJson {
+  Element _element;
+
+  List<int> _offsets;
+
+  int _length;
+
+  /**
+   * The element that was referenced.
+   */
+  Element get element => _element;
+
+  /**
+   * The element that was referenced.
+   */
+  void set element(Element value) {
+    assert(value != null);
+    this._element = value;
+  }
+
+  /**
+   * The offsets of the name of the referenced element within the file.
+   */
+  List<int> get offsets => _offsets;
+
+  /**
+   * The offsets of the name of the referenced element within the file.
+   */
+  void set offsets(List<int> value) {
+    assert(value != null);
+    this._offsets = value;
+  }
+
+  /**
+   * The length of the name of the referenced element.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the name of the referenced element.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  Occurrences(Element element, List<int> offsets, int length) {
+    this.element = element;
+    this.offsets = offsets;
+    this.length = length;
+  }
+
+  factory Occurrences.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      Element element;
+      if (json.containsKey("element")) {
+        element = new Element.fromJson(jsonDecoder, jsonPath + ".element", json["element"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "element");
+      }
+      List<int> offsets;
+      if (json.containsKey("offsets")) {
+        offsets = jsonDecoder.decodeList(jsonPath + ".offsets", json["offsets"], jsonDecoder.decodeInt);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offsets");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      return new Occurrences(element, offsets, length);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "Occurrences", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["element"] = element.toJson();
+    result["offsets"] = offsets;
+    result["length"] = length;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is Occurrences) {
+      return element == other.element &&
+          listEqual(offsets, other.offsets, (int a, int b) => a == b) &&
+          length == other.length;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, element.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offsets.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * Outline
+ *
+ * {
+ *   "element": Element
+ *   "offset": int
+ *   "length": int
+ *   "children": optional List<Outline>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Outline implements HasToJson {
+  Element _element;
+
+  int _offset;
+
+  int _length;
+
+  List<Outline> _children;
+
+  /**
+   * A description of the element represented by this node.
+   */
+  Element get element => _element;
+
+  /**
+   * A description of the element represented by this node.
+   */
+  void set element(Element value) {
+    assert(value != null);
+    this._element = value;
+  }
+
+  /**
+   * The offset of the first character of the element. This is different than
+   * the offset in the Element, which is the offset of the name of the element.
+   * It can be used, for example, to map locations in the file back to an
+   * outline.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the first character of the element. This is different than
+   * the offset in the Element, which is the offset of the name of the element.
+   * It can be used, for example, to map locations in the file back to an
+   * outline.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the element.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the element.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The children of the node. The field will be omitted if the node has no
+   * children.
+   */
+  List<Outline> get children => _children;
+
+  /**
+   * The children of the node. The field will be omitted if the node has no
+   * children.
+   */
+  void set children(List<Outline> value) {
+    this._children = value;
+  }
+
+  Outline(Element element, int offset, int length, {List<Outline> children}) {
+    this.element = element;
+    this.offset = offset;
+    this.length = length;
+    this.children = children;
+  }
+
+  factory Outline.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      Element element;
+      if (json.containsKey("element")) {
+        element = new Element.fromJson(jsonDecoder, jsonPath + ".element", json["element"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "element");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      List<Outline> children;
+      if (json.containsKey("children")) {
+        children = jsonDecoder.decodeList(jsonPath + ".children", json["children"], (String jsonPath, Object json) => new Outline.fromJson(jsonDecoder, jsonPath, json));
+      }
+      return new Outline(element, offset, length, children: children);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "Outline", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["element"] = element.toJson();
+    result["offset"] = offset;
+    result["length"] = length;
+    if (children != null) {
+      result["children"] = children.map((Outline value) => value.toJson()).toList();
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is Outline) {
+      return element == other.element &&
+          offset == other.offset &&
+          length == other.length &&
+          listEqual(children, other.children, (Outline a, Outline b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, element.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, children.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * plugin.error params
+ *
+ * {
+ *   "isFatal": bool
+ *   "message": String
+ *   "stackTrace": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class PluginErrorParams implements HasToJson {
+  bool _isFatal;
+
+  String _message;
+
+  String _stackTrace;
+
+  /**
+   * A flag indicating whether the error is a fatal error, meaning that the
+   * plugin will shutdown automatically after sending this notification. If
+   * true, the server will not expect any other responses or notifications from
+   * the plugin.
+   */
+  bool get isFatal => _isFatal;
+
+  /**
+   * A flag indicating whether the error is a fatal error, meaning that the
+   * plugin will shutdown automatically after sending this notification. If
+   * true, the server will not expect any other responses or notifications from
+   * the plugin.
+   */
+  void set isFatal(bool value) {
+    assert(value != null);
+    this._isFatal = value;
+  }
+
+  /**
+   * The error message indicating what kind of error was encountered.
+   */
+  String get message => _message;
+
+  /**
+   * The error message indicating what kind of error was encountered.
+   */
+  void set message(String value) {
+    assert(value != null);
+    this._message = value;
+  }
+
+  /**
+   * The stack trace associated with the generation of the error, used for
+   * debugging the plugin.
+   */
+  String get stackTrace => _stackTrace;
+
+  /**
+   * The stack trace associated with the generation of the error, used for
+   * debugging the plugin.
+   */
+  void set stackTrace(String value) {
+    assert(value != null);
+    this._stackTrace = value;
+  }
+
+  PluginErrorParams(bool isFatal, String message, String stackTrace) {
+    this.isFatal = isFatal;
+    this.message = message;
+    this.stackTrace = stackTrace;
+  }
+
+  factory PluginErrorParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      bool isFatal;
+      if (json.containsKey("isFatal")) {
+        isFatal = jsonDecoder.decodeBool(jsonPath + ".isFatal", json["isFatal"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "isFatal");
+      }
+      String message;
+      if (json.containsKey("message")) {
+        message = jsonDecoder.decodeString(jsonPath + ".message", json["message"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "message");
+      }
+      String stackTrace;
+      if (json.containsKey("stackTrace")) {
+        stackTrace = jsonDecoder.decodeString(jsonPath + ".stackTrace", json["stackTrace"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "stackTrace");
+      }
+      return new PluginErrorParams(isFatal, message, stackTrace);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "plugin.error params", json);
+    }
+  }
+
+  factory PluginErrorParams.fromNotification(Notification notification) {
+    return new PluginErrorParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["isFatal"] = isFatal;
+    result["message"] = message;
+    result["stackTrace"] = stackTrace;
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("plugin.error", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is PluginErrorParams) {
+      return isFatal == other.isFatal &&
+          message == other.message &&
+          stackTrace == other.stackTrace;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, isFatal.hashCode);
+    hash = JenkinsSmiHash.combine(hash, message.hashCode);
+    hash = JenkinsSmiHash.combine(hash, stackTrace.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * plugin.shutdown params
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class PluginShutdownParams implements RequestParams {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "plugin.shutdown", null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is PluginShutdownParams) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 478064585;
+  }
+}
+
+/**
+ * plugin.shutdown result
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class PluginShutdownResult implements ResponseResult {
+  @override
+  Map<String, dynamic> toJson() => <String, dynamic>{};
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is PluginShutdownResult) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 9389109;
+  }
+}
+
+/**
+ * plugin.versionCheck params
+ *
+ * {
+ *   "byteStorePath": String
+ *   "version": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class PluginVersionCheckParams implements RequestParams {
+  String _byteStorePath;
+
+  String _version;
+
+  /**
+   * The path to the directory containing the on-disk byte store that is to be
+   * used by any analysis drivers that are created.
+   */
+  String get byteStorePath => _byteStorePath;
+
+  /**
+   * The path to the directory containing the on-disk byte store that is to be
+   * used by any analysis drivers that are created.
+   */
+  void set byteStorePath(String value) {
+    assert(value != null);
+    this._byteStorePath = value;
+  }
+
+  /**
+   * The version number of the plugin spec supported by the analysis server
+   * that is executing the plugin.
+   */
+  String get version => _version;
+
+  /**
+   * The version number of the plugin spec supported by the analysis server
+   * that is executing the plugin.
+   */
+  void set version(String value) {
+    assert(value != null);
+    this._version = value;
+  }
+
+  PluginVersionCheckParams(String byteStorePath, String version) {
+    this.byteStorePath = byteStorePath;
+    this.version = version;
+  }
+
+  factory PluginVersionCheckParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String byteStorePath;
+      if (json.containsKey("byteStorePath")) {
+        byteStorePath = jsonDecoder.decodeString(jsonPath + ".byteStorePath", json["byteStorePath"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "byteStorePath");
+      }
+      String version;
+      if (json.containsKey("version")) {
+        version = jsonDecoder.decodeString(jsonPath + ".version", json["version"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "version");
+      }
+      return new PluginVersionCheckParams(byteStorePath, version);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "plugin.versionCheck params", json);
+    }
+  }
+
+  factory PluginVersionCheckParams.fromRequest(Request request) {
+    return new PluginVersionCheckParams.fromJson(
+        new RequestDecoder(request), "params", request.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["byteStorePath"] = byteStorePath;
+    result["version"] = version;
+    return result;
+  }
+
+  @override
+  Request toRequest(String id) {
+    return new Request(id, "plugin.versionCheck", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is PluginVersionCheckParams) {
+      return byteStorePath == other.byteStorePath &&
+          version == other.version;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, byteStorePath.hashCode);
+    hash = JenkinsSmiHash.combine(hash, version.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * plugin.versionCheck result
+ *
+ * {
+ *   "isCompatible": bool
+ *   "name": String
+ *   "version": String
+ *   "contactInfo": optional String
+ *   "interestingFiles": List<String>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class PluginVersionCheckResult implements ResponseResult {
+  bool _isCompatible;
+
+  String _name;
+
+  String _version;
+
+  String _contactInfo;
+
+  List<String> _interestingFiles;
+
+  /**
+   * A flag indicating whether the plugin supports the same version of the
+   * plugin spec as the analysis server. If the value is false, then the plugin
+   * is expected to shutdown after returning the response.
+   */
+  bool get isCompatible => _isCompatible;
+
+  /**
+   * A flag indicating whether the plugin supports the same version of the
+   * plugin spec as the analysis server. If the value is false, then the plugin
+   * is expected to shutdown after returning the response.
+   */
+  void set isCompatible(bool value) {
+    assert(value != null);
+    this._isCompatible = value;
+  }
+
+  /**
+   * The name of the plugin. This value is only used when the server needs to
+   * identify the plugin, either to the user or for debugging purposes.
+   */
+  String get name => _name;
+
+  /**
+   * The name of the plugin. This value is only used when the server needs to
+   * identify the plugin, either to the user or for debugging purposes.
+   */
+  void set name(String value) {
+    assert(value != null);
+    this._name = value;
+  }
+
+  /**
+   * The version of the plugin. This value is only used when the server needs
+   * to identify the plugin, either to the user or for debugging purposes.
+   */
+  String get version => _version;
+
+  /**
+   * The version of the plugin. This value is only used when the server needs
+   * to identify the plugin, either to the user or for debugging purposes.
+   */
+  void set version(String value) {
+    assert(value != null);
+    this._version = value;
+  }
+
+  /**
+   * Information that the user can use to use to contact the maintainers of the
+   * plugin when there is a problem.
+   */
+  String get contactInfo => _contactInfo;
+
+  /**
+   * Information that the user can use to use to contact the maintainers of the
+   * plugin when there is a problem.
+   */
+  void set contactInfo(String value) {
+    this._contactInfo = value;
+  }
+
+  /**
+   * The glob patterns of the files for which the plugin will provide
+   * information. This value is ignored if the isCompatible field is false.
+   * Otherwise, it will be used to identify the files for which the plugin
+   * should be notified of changes.
+   */
+  List<String> get interestingFiles => _interestingFiles;
+
+  /**
+   * The glob patterns of the files for which the plugin will provide
+   * information. This value is ignored if the isCompatible field is false.
+   * Otherwise, it will be used to identify the files for which the plugin
+   * should be notified of changes.
+   */
+  void set interestingFiles(List<String> value) {
+    assert(value != null);
+    this._interestingFiles = value;
+  }
+
+  PluginVersionCheckResult(bool isCompatible, String name, String version, List<String> interestingFiles, {String contactInfo}) {
+    this.isCompatible = isCompatible;
+    this.name = name;
+    this.version = version;
+    this.contactInfo = contactInfo;
+    this.interestingFiles = interestingFiles;
+  }
+
+  factory PluginVersionCheckResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      bool isCompatible;
+      if (json.containsKey("isCompatible")) {
+        isCompatible = jsonDecoder.decodeBool(jsonPath + ".isCompatible", json["isCompatible"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "isCompatible");
+      }
+      String name;
+      if (json.containsKey("name")) {
+        name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "name");
+      }
+      String version;
+      if (json.containsKey("version")) {
+        version = jsonDecoder.decodeString(jsonPath + ".version", json["version"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "version");
+      }
+      String contactInfo;
+      if (json.containsKey("contactInfo")) {
+        contactInfo = jsonDecoder.decodeString(jsonPath + ".contactInfo", json["contactInfo"]);
+      }
+      List<String> interestingFiles;
+      if (json.containsKey("interestingFiles")) {
+        interestingFiles = jsonDecoder.decodeList(jsonPath + ".interestingFiles", json["interestingFiles"], jsonDecoder.decodeString);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "interestingFiles");
+      }
+      return new PluginVersionCheckResult(isCompatible, name, version, interestingFiles, contactInfo: contactInfo);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "plugin.versionCheck result", json);
+    }
+  }
+
+  factory PluginVersionCheckResult.fromResponse(Response response) {
+    return new PluginVersionCheckResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response.result);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["isCompatible"] = isCompatible;
+    result["name"] = name;
+    result["version"] = version;
+    if (contactInfo != null) {
+      result["contactInfo"] = contactInfo;
+    }
+    result["interestingFiles"] = interestingFiles;
+    return result;
+  }
+
+  @override
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is PluginVersionCheckResult) {
+      return isCompatible == other.isCompatible &&
+          name == other.name &&
+          version == other.version &&
+          contactInfo == other.contactInfo &&
+          listEqual(interestingFiles, other.interestingFiles, (String a, String b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, isCompatible.hashCode);
+    hash = JenkinsSmiHash.combine(hash, name.hashCode);
+    hash = JenkinsSmiHash.combine(hash, version.hashCode);
+    hash = JenkinsSmiHash.combine(hash, contactInfo.hashCode);
+    hash = JenkinsSmiHash.combine(hash, interestingFiles.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * Position
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Position implements HasToJson {
+  String _file;
+
+  int _offset;
+
+  /**
+   * The file containing the position.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the position.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The offset of the position.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the position.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  Position(String file, int offset) {
+    this.file = file;
+    this.offset = offset;
+  }
+
+  factory Position.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      return new Position(file, offset);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "Position", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["offset"] = offset;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is Position) {
+      return file == other.file &&
+          offset == other.offset;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * PrioritizedSourceChange
+ *
+ * {
+ *   "priority": int
+ *   "change": SourceChange
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class PrioritizedSourceChange implements HasToJson {
+  int _priority;
+
+  SourceChange _change;
+
+  /**
+   * The priority of the change. The value is expected to be non-negative, and
+   * zero (0) is the lowest priority.
+   */
+  int get priority => _priority;
+
+  /**
+   * The priority of the change. The value is expected to be non-negative, and
+   * zero (0) is the lowest priority.
+   */
+  void set priority(int value) {
+    assert(value != null);
+    this._priority = value;
+  }
+
+  /**
+   * The change with which the relevance is associated.
+   */
+  SourceChange get change => _change;
+
+  /**
+   * The change with which the relevance is associated.
+   */
+  void set change(SourceChange value) {
+    assert(value != null);
+    this._change = value;
+  }
+
+  PrioritizedSourceChange(int priority, SourceChange change) {
+    this.priority = priority;
+    this.change = change;
+  }
+
+  factory PrioritizedSourceChange.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int priority;
+      if (json.containsKey("priority")) {
+        priority = jsonDecoder.decodeInt(jsonPath + ".priority", json["priority"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "priority");
+      }
+      SourceChange change;
+      if (json.containsKey("change")) {
+        change = new SourceChange.fromJson(jsonDecoder, jsonPath + ".change", json["change"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "change");
+      }
+      return new PrioritizedSourceChange(priority, change);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "PrioritizedSourceChange", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["priority"] = priority;
+    result["change"] = change.toJson();
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is PrioritizedSourceChange) {
+      return priority == other.priority &&
+          change == other.change;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, priority.hashCode);
+    hash = JenkinsSmiHash.combine(hash, change.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RefactoringFeedback
+ *
+ * {
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringFeedback implements HasToJson {
+  RefactoringFeedback();
+
+  factory RefactoringFeedback.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json, Map responseJson) {
+    return refactoringFeedbackFromJson(jsonDecoder, jsonPath, json, responseJson);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RefactoringFeedback) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RefactoringKind
+ *
+ * enum {
+ *   CONVERT_GETTER_TO_METHOD
+ *   CONVERT_METHOD_TO_GETTER
+ *   EXTRACT_LOCAL_VARIABLE
+ *   EXTRACT_METHOD
+ *   INLINE_LOCAL_VARIABLE
+ *   INLINE_METHOD
+ *   MOVE_FILE
+ *   RENAME
+ *   SORT_MEMBERS
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringKind implements Enum {
+  static const RefactoringKind CONVERT_GETTER_TO_METHOD = const RefactoringKind._("CONVERT_GETTER_TO_METHOD");
+
+  static const RefactoringKind CONVERT_METHOD_TO_GETTER = const RefactoringKind._("CONVERT_METHOD_TO_GETTER");
+
+  static const RefactoringKind EXTRACT_LOCAL_VARIABLE = const RefactoringKind._("EXTRACT_LOCAL_VARIABLE");
+
+  static const RefactoringKind EXTRACT_METHOD = const RefactoringKind._("EXTRACT_METHOD");
+
+  static const RefactoringKind INLINE_LOCAL_VARIABLE = const RefactoringKind._("INLINE_LOCAL_VARIABLE");
+
+  static const RefactoringKind INLINE_METHOD = const RefactoringKind._("INLINE_METHOD");
+
+  static const RefactoringKind MOVE_FILE = const RefactoringKind._("MOVE_FILE");
+
+  static const RefactoringKind RENAME = const RefactoringKind._("RENAME");
+
+  static const RefactoringKind SORT_MEMBERS = const RefactoringKind._("SORT_MEMBERS");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<RefactoringKind> VALUES = const <RefactoringKind>[CONVERT_GETTER_TO_METHOD, CONVERT_METHOD_TO_GETTER, EXTRACT_LOCAL_VARIABLE, EXTRACT_METHOD, INLINE_LOCAL_VARIABLE, INLINE_METHOD, MOVE_FILE, RENAME, SORT_MEMBERS];
+
+  @override
+  final String name;
+
+  const RefactoringKind._(this.name);
+
+  factory RefactoringKind(String name) {
+    switch (name) {
+      case "CONVERT_GETTER_TO_METHOD":
+        return CONVERT_GETTER_TO_METHOD;
+      case "CONVERT_METHOD_TO_GETTER":
+        return CONVERT_METHOD_TO_GETTER;
+      case "EXTRACT_LOCAL_VARIABLE":
+        return EXTRACT_LOCAL_VARIABLE;
+      case "EXTRACT_METHOD":
+        return EXTRACT_METHOD;
+      case "INLINE_LOCAL_VARIABLE":
+        return INLINE_LOCAL_VARIABLE;
+      case "INLINE_METHOD":
+        return INLINE_METHOD;
+      case "MOVE_FILE":
+        return MOVE_FILE;
+      case "RENAME":
+        return RENAME;
+      case "SORT_MEMBERS":
+        return SORT_MEMBERS;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory RefactoringKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new RefactoringKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "RefactoringKind", json);
+  }
+
+  @override
+  String toString() => "RefactoringKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * RefactoringMethodParameter
+ *
+ * {
+ *   "id": optional String
+ *   "kind": RefactoringMethodParameterKind
+ *   "type": String
+ *   "name": String
+ *   "parameters": optional String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringMethodParameter implements HasToJson {
+  String _id;
+
+  RefactoringMethodParameterKind _kind;
+
+  String _type;
+
+  String _name;
+
+  String _parameters;
+
+  /**
+   * The unique identifier of the parameter. Clients may omit this field for
+   * the parameters they want to add.
+   */
+  String get id => _id;
+
+  /**
+   * The unique identifier of the parameter. Clients may omit this field for
+   * the parameters they want to add.
+   */
+  void set id(String value) {
+    this._id = value;
+  }
+
+  /**
+   * The kind of the parameter.
+   */
+  RefactoringMethodParameterKind get kind => _kind;
+
+  /**
+   * The kind of the parameter.
+   */
+  void set kind(RefactoringMethodParameterKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The type that should be given to the parameter, or the return type of the
+   * parameter's function type.
+   */
+  String get type => _type;
+
+  /**
+   * The type that should be given to the parameter, or the return type of the
+   * parameter's function type.
+   */
+  void set type(String value) {
+    assert(value != null);
+    this._type = value;
+  }
+
+  /**
+   * The name that should be given to the parameter.
+   */
+  String get name => _name;
+
+  /**
+   * The name that should be given to the parameter.
+   */
+  void set name(String value) {
+    assert(value != null);
+    this._name = value;
+  }
+
+  /**
+   * The parameter list of the parameter's function type. If the parameter is
+   * not of a function type, this field will not be defined. If the function
+   * type has zero parameters, this field will have a value of '()'.
+   */
+  String get parameters => _parameters;
+
+  /**
+   * The parameter list of the parameter's function type. If the parameter is
+   * not of a function type, this field will not be defined. If the function
+   * type has zero parameters, this field will have a value of '()'.
+   */
+  void set parameters(String value) {
+    this._parameters = value;
+  }
+
+  RefactoringMethodParameter(RefactoringMethodParameterKind kind, String type, String name, {String id, String parameters}) {
+    this.id = id;
+    this.kind = kind;
+    this.type = type;
+    this.name = name;
+    this.parameters = parameters;
+  }
+
+  factory RefactoringMethodParameter.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String id;
+      if (json.containsKey("id")) {
+        id = jsonDecoder.decodeString(jsonPath + ".id", json["id"]);
+      }
+      RefactoringMethodParameterKind kind;
+      if (json.containsKey("kind")) {
+        kind = new RefactoringMethodParameterKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      String type;
+      if (json.containsKey("type")) {
+        type = jsonDecoder.decodeString(jsonPath + ".type", json["type"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "type");
+      }
+      String name;
+      if (json.containsKey("name")) {
+        name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "name");
+      }
+      String parameters;
+      if (json.containsKey("parameters")) {
+        parameters = jsonDecoder.decodeString(jsonPath + ".parameters", json["parameters"]);
+      }
+      return new RefactoringMethodParameter(kind, type, name, id: id, parameters: parameters);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "RefactoringMethodParameter", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    if (id != null) {
+      result["id"] = id;
+    }
+    result["kind"] = kind.toJson();
+    result["type"] = type;
+    result["name"] = name;
+    if (parameters != null) {
+      result["parameters"] = parameters;
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RefactoringMethodParameter) {
+      return id == other.id &&
+          kind == other.kind &&
+          type == other.type &&
+          name == other.name &&
+          parameters == other.parameters;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, id.hashCode);
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, type.hashCode);
+    hash = JenkinsSmiHash.combine(hash, name.hashCode);
+    hash = JenkinsSmiHash.combine(hash, parameters.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RefactoringMethodParameterKind
+ *
+ * enum {
+ *   REQUIRED
+ *   POSITIONAL
+ *   NAMED
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringMethodParameterKind implements Enum {
+  static const RefactoringMethodParameterKind REQUIRED = const RefactoringMethodParameterKind._("REQUIRED");
+
+  static const RefactoringMethodParameterKind POSITIONAL = const RefactoringMethodParameterKind._("POSITIONAL");
+
+  static const RefactoringMethodParameterKind NAMED = const RefactoringMethodParameterKind._("NAMED");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<RefactoringMethodParameterKind> VALUES = const <RefactoringMethodParameterKind>[REQUIRED, POSITIONAL, NAMED];
+
+  @override
+  final String name;
+
+  const RefactoringMethodParameterKind._(this.name);
+
+  factory RefactoringMethodParameterKind(String name) {
+    switch (name) {
+      case "REQUIRED":
+        return REQUIRED;
+      case "POSITIONAL":
+        return POSITIONAL;
+      case "NAMED":
+        return NAMED;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory RefactoringMethodParameterKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new RefactoringMethodParameterKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "RefactoringMethodParameterKind", json);
+  }
+
+  @override
+  String toString() => "RefactoringMethodParameterKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * RefactoringOptions
+ *
+ * {
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringOptions implements HasToJson {
+  RefactoringOptions();
+
+  factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json, RefactoringKind kind) {
+    return refactoringOptionsFromJson(jsonDecoder, jsonPath, json, kind);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RefactoringOptions) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RefactoringProblem
+ *
+ * {
+ *   "severity": RefactoringProblemSeverity
+ *   "message": String
+ *   "location": optional Location
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringProblem implements HasToJson {
+  RefactoringProblemSeverity _severity;
+
+  String _message;
+
+  Location _location;
+
+  /**
+   * The severity of the problem being represented.
+   */
+  RefactoringProblemSeverity get severity => _severity;
+
+  /**
+   * The severity of the problem being represented.
+   */
+  void set severity(RefactoringProblemSeverity value) {
+    assert(value != null);
+    this._severity = value;
+  }
+
+  /**
+   * A human-readable description of the problem being represented.
+   */
+  String get message => _message;
+
+  /**
+   * A human-readable description of the problem being represented.
+   */
+  void set message(String value) {
+    assert(value != null);
+    this._message = value;
+  }
+
+  /**
+   * The location of the problem being represented. This field is omitted
+   * unless there is a specific location associated with the problem (such as a
+   * location where an element being renamed will be shadowed).
+   */
+  Location get location => _location;
+
+  /**
+   * The location of the problem being represented. This field is omitted
+   * unless there is a specific location associated with the problem (such as a
+   * location where an element being renamed will be shadowed).
+   */
+  void set location(Location value) {
+    this._location = value;
+  }
+
+  RefactoringProblem(RefactoringProblemSeverity severity, String message, {Location location}) {
+    this.severity = severity;
+    this.message = message;
+    this.location = location;
+  }
+
+  factory RefactoringProblem.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      RefactoringProblemSeverity severity;
+      if (json.containsKey("severity")) {
+        severity = new RefactoringProblemSeverity.fromJson(jsonDecoder, jsonPath + ".severity", json["severity"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "severity");
+      }
+      String message;
+      if (json.containsKey("message")) {
+        message = jsonDecoder.decodeString(jsonPath + ".message", json["message"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "message");
+      }
+      Location location;
+      if (json.containsKey("location")) {
+        location = new Location.fromJson(jsonDecoder, jsonPath + ".location", json["location"]);
+      }
+      return new RefactoringProblem(severity, message, location: location);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "RefactoringProblem", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["severity"] = severity.toJson();
+    result["message"] = message;
+    if (location != null) {
+      result["location"] = location.toJson();
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RefactoringProblem) {
+      return severity == other.severity &&
+          message == other.message &&
+          location == other.location;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, severity.hashCode);
+    hash = JenkinsSmiHash.combine(hash, message.hashCode);
+    hash = JenkinsSmiHash.combine(hash, location.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RefactoringProblemSeverity
+ *
+ * enum {
+ *   INFO
+ *   WARNING
+ *   ERROR
+ *   FATAL
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RefactoringProblemSeverity implements Enum {
+  /**
+   * A minor code problem. No example, because it is not used yet.
+   */
+  static const RefactoringProblemSeverity INFO = const RefactoringProblemSeverity._("INFO");
+
+  /**
+   * A minor code problem. For example names of local variables should be camel
+   * case and start with a lower case letter. Staring the name of a variable
+   * with an upper case is OK from the language point of view, but it is nice
+   * to warn the user.
+   */
+  static const RefactoringProblemSeverity WARNING = const RefactoringProblemSeverity._("WARNING");
+
+  /**
+   * The refactoring technically can be performed, but there is a logical
+   * problem. For example the name of a local variable being extracted
+   * conflicts with another name in the scope, or duplicate parameter names in
+   * the method being extracted, or a conflict between a parameter name and a
+   * local variable, etc. In some cases the location of the problem is also
+   * provided, so the IDE can show user the location and the problem, and let
+   * the user decide whether they want to perform the refactoring. For example
+   * the name conflict might be expected, and the user wants to fix it
+   * afterwards.
+   */
+  static const RefactoringProblemSeverity ERROR = const RefactoringProblemSeverity._("ERROR");
+
+  /**
+   * A fatal error, which prevents performing the refactoring. For example the
+   * name of a local variable being extracted is not a valid identifier, or
+   * selection is not a valid expression.
+   */
+  static const RefactoringProblemSeverity FATAL = const RefactoringProblemSeverity._("FATAL");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<RefactoringProblemSeverity> VALUES = const <RefactoringProblemSeverity>[INFO, WARNING, ERROR, FATAL];
+
+  @override
+  final String name;
+
+  const RefactoringProblemSeverity._(this.name);
+
+  factory RefactoringProblemSeverity(String name) {
+    switch (name) {
+      case "INFO":
+        return INFO;
+      case "WARNING":
+        return WARNING;
+      case "ERROR":
+        return ERROR;
+      case "FATAL":
+        return FATAL;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory RefactoringProblemSeverity.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new RefactoringProblemSeverity(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "RefactoringProblemSeverity", json);
+  }
+
+  /**
+   * Returns the [RefactoringProblemSeverity] with the maximal severity.
+   */
+  static RefactoringProblemSeverity max(RefactoringProblemSeverity a, RefactoringProblemSeverity b) =>
+      maxRefactoringProblemSeverity(a, b);
+
+  @override
+  String toString() => "RefactoringProblemSeverity.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * RemoveContentOverlay
+ *
+ * {
+ *   "type": "remove"
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RemoveContentOverlay implements HasToJson {
+  RemoveContentOverlay();
+
+  factory RemoveContentOverlay.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      if (json["type"] != "remove") {
+        throw jsonDecoder.mismatch(jsonPath, "equal " + "remove", json);
+      }
+      return new RemoveContentOverlay();
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "RemoveContentOverlay", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["type"] = "remove";
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RemoveContentOverlay) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, 114870849);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * rename feedback
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "elementKindName": String
+ *   "oldName": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RenameFeedback extends RefactoringFeedback {
+  int _offset;
+
+  int _length;
+
+  String _elementKindName;
+
+  String _oldName;
+
+  /**
+   * The offset to the beginning of the name selected to be renamed.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset to the beginning of the name selected to be renamed.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the name selected to be renamed.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the name selected to be renamed.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The human-readable description of the kind of element being renamed (such
+   * as “class” or “function type alias”).
+   */
+  String get elementKindName => _elementKindName;
+
+  /**
+   * The human-readable description of the kind of element being renamed (such
+   * as “class” or “function type alias”).
+   */
+  void set elementKindName(String value) {
+    assert(value != null);
+    this._elementKindName = value;
+  }
+
+  /**
+   * The old name of the element before the refactoring.
+   */
+  String get oldName => _oldName;
+
+  /**
+   * The old name of the element before the refactoring.
+   */
+  void set oldName(String value) {
+    assert(value != null);
+    this._oldName = value;
+  }
+
+  RenameFeedback(int offset, int length, String elementKindName, String oldName) {
+    this.offset = offset;
+    this.length = length;
+    this.elementKindName = elementKindName;
+    this.oldName = oldName;
+  }
+
+  factory RenameFeedback.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      String elementKindName;
+      if (json.containsKey("elementKindName")) {
+        elementKindName = jsonDecoder.decodeString(jsonPath + ".elementKindName", json["elementKindName"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "elementKindName");
+      }
+      String oldName;
+      if (json.containsKey("oldName")) {
+        oldName = jsonDecoder.decodeString(jsonPath + ".oldName", json["oldName"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "oldName");
+      }
+      return new RenameFeedback(offset, length, elementKindName, oldName);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "rename feedback", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["offset"] = offset;
+    result["length"] = length;
+    result["elementKindName"] = elementKindName;
+    result["oldName"] = oldName;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RenameFeedback) {
+      return offset == other.offset &&
+          length == other.length &&
+          elementKindName == other.elementKindName &&
+          oldName == other.oldName;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, elementKindName.hashCode);
+    hash = JenkinsSmiHash.combine(hash, oldName.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * rename options
+ *
+ * {
+ *   "newName": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RenameOptions extends RefactoringOptions {
+  String _newName;
+
+  /**
+   * The name that the element should have after the refactoring.
+   */
+  String get newName => _newName;
+
+  /**
+   * The name that the element should have after the refactoring.
+   */
+  void set newName(String value) {
+    assert(value != null);
+    this._newName = value;
+  }
+
+  RenameOptions(String newName) {
+    this.newName = newName;
+  }
+
+  factory RenameOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String newName;
+      if (json.containsKey("newName")) {
+        newName = jsonDecoder.decodeString(jsonPath + ".newName", json["newName"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "newName");
+      }
+      return new RenameOptions(newName);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "rename options", json);
+    }
+  }
+
+  factory RenameOptions.fromRefactoringParams(EditGetRefactoringParams refactoringParams, Request request) {
+    return new RenameOptions.fromJson(
+        new RequestDecoder(request), "options", refactoringParams.options);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["newName"] = newName;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RenameOptions) {
+      return newName == other.newName;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, newName.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RequestError
+ *
+ * {
+ *   "code": RequestErrorCode
+ *   "message": String
+ *   "stackTrace": optional String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RequestError implements HasToJson {
+  RequestErrorCode _code;
+
+  String _message;
+
+  String _stackTrace;
+
+  /**
+   * A code that uniquely identifies the error that occurred.
+   */
+  RequestErrorCode get code => _code;
+
+  /**
+   * A code that uniquely identifies the error that occurred.
+   */
+  void set code(RequestErrorCode value) {
+    assert(value != null);
+    this._code = value;
+  }
+
+  /**
+   * A short description of the error.
+   */
+  String get message => _message;
+
+  /**
+   * A short description of the error.
+   */
+  void set message(String value) {
+    assert(value != null);
+    this._message = value;
+  }
+
+  /**
+   * The stack trace associated with processing the request, used for debugging
+   * the plugin.
+   */
+  String get stackTrace => _stackTrace;
+
+  /**
+   * The stack trace associated with processing the request, used for debugging
+   * the plugin.
+   */
+  void set stackTrace(String value) {
+    this._stackTrace = value;
+  }
+
+  RequestError(RequestErrorCode code, String message, {String stackTrace}) {
+    this.code = code;
+    this.message = message;
+    this.stackTrace = stackTrace;
+  }
+
+  factory RequestError.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      RequestErrorCode code;
+      if (json.containsKey("code")) {
+        code = new RequestErrorCode.fromJson(jsonDecoder, jsonPath + ".code", json["code"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "code");
+      }
+      String message;
+      if (json.containsKey("message")) {
+        message = jsonDecoder.decodeString(jsonPath + ".message", json["message"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "message");
+      }
+      String stackTrace;
+      if (json.containsKey("stackTrace")) {
+        stackTrace = jsonDecoder.decodeString(jsonPath + ".stackTrace", json["stackTrace"]);
+      }
+      return new RequestError(code, message, stackTrace: stackTrace);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "RequestError", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["code"] = code.toJson();
+    result["message"] = message;
+    if (stackTrace != null) {
+      result["stackTrace"] = stackTrace;
+    }
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is RequestError) {
+      return code == other.code &&
+          message == other.message &&
+          stackTrace == other.stackTrace;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, code.hashCode);
+    hash = JenkinsSmiHash.combine(hash, message.hashCode);
+    hash = JenkinsSmiHash.combine(hash, stackTrace.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * RequestErrorCode
+ *
+ * enum {
+ *   INVALID_OVERLAY_CHANGE
+ *   INVALID_PARAMETER
+ *   PLUGIN_ERROR
+ *   UNKNOWN_REQUEST
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class RequestErrorCode implements Enum {
+  /**
+   * An "analysis.updateContent" request contained a ChangeContentOverlay
+   * object that can't be applied. This can happen for two reasons:
+   *
+   * - there was no preceding AddContentOverlay and hence no content to which
+   *   the edits could be applied, or
+   * - one or more of the specified edits have an offset or length that is out
+   *   of range.
+   */
+  static const RequestErrorCode INVALID_OVERLAY_CHANGE = const RequestErrorCode._("INVALID_OVERLAY_CHANGE");
+
+  /**
+   * One of the method parameters was invalid.
+   */
+  static const RequestErrorCode INVALID_PARAMETER = const RequestErrorCode._("INVALID_PARAMETER");
+
+  /**
+   * An internal error occurred in the plugin while attempting to respond to a
+   * request. Also see the plugin.error notification for errors that occur
+   * outside of handling a request.
+   */
+  static const RequestErrorCode PLUGIN_ERROR = const RequestErrorCode._("PLUGIN_ERROR");
+
+  /**
+   * A request was received that the plugin does not recognize, or cannot
+   * handle in its current configuration.
+   */
+  static const RequestErrorCode UNKNOWN_REQUEST = const RequestErrorCode._("UNKNOWN_REQUEST");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, PLUGIN_ERROR, UNKNOWN_REQUEST];
+
+  @override
+  final String name;
+
+  const RequestErrorCode._(this.name);
+
+  factory RequestErrorCode(String name) {
+    switch (name) {
+      case "INVALID_OVERLAY_CHANGE":
+        return INVALID_OVERLAY_CHANGE;
+      case "INVALID_PARAMETER":
+        return INVALID_PARAMETER;
+      case "PLUGIN_ERROR":
+        return PLUGIN_ERROR;
+      case "UNKNOWN_REQUEST":
+        return UNKNOWN_REQUEST;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory RequestErrorCode.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new RequestErrorCode(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "RequestErrorCode", json);
+  }
+
+  @override
+  String toString() => "RequestErrorCode.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * SourceChange
+ *
+ * {
+ *   "message": String
+ *   "edits": List<SourceFileEdit>
+ *   "linkedEditGroups": List<LinkedEditGroup>
+ *   "selection": optional Position
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class SourceChange implements HasToJson {
+  String _message;
+
+  List<SourceFileEdit> _edits;
+
+  List<LinkedEditGroup> _linkedEditGroups;
+
+  Position _selection;
+
+  /**
+   * A human-readable description of the change to be applied.
+   */
+  String get message => _message;
+
+  /**
+   * A human-readable description of the change to be applied.
+   */
+  void set message(String value) {
+    assert(value != null);
+    this._message = value;
+  }
+
+  /**
+   * A list of the edits used to effect the change, grouped by file.
+   */
+  List<SourceFileEdit> get edits => _edits;
+
+  /**
+   * A list of the edits used to effect the change, grouped by file.
+   */
+  void set edits(List<SourceFileEdit> value) {
+    assert(value != null);
+    this._edits = value;
+  }
+
+  /**
+   * A list of the linked editing groups used to customize the changes that
+   * were made.
+   */
+  List<LinkedEditGroup> get linkedEditGroups => _linkedEditGroups;
+
+  /**
+   * A list of the linked editing groups used to customize the changes that
+   * were made.
+   */
+  void set linkedEditGroups(List<LinkedEditGroup> value) {
+    assert(value != null);
+    this._linkedEditGroups = value;
+  }
+
+  /**
+   * The position that should be selected after the edits have been applied.
+   */
+  Position get selection => _selection;
+
+  /**
+   * The position that should be selected after the edits have been applied.
+   */
+  void set selection(Position value) {
+    this._selection = value;
+  }
+
+  SourceChange(String message, {List<SourceFileEdit> edits, List<LinkedEditGroup> linkedEditGroups, Position selection}) {
+    this.message = message;
+    if (edits == null) {
+      this.edits = <SourceFileEdit>[];
+    } else {
+      this.edits = edits;
+    }
+    if (linkedEditGroups == null) {
+      this.linkedEditGroups = <LinkedEditGroup>[];
+    } else {
+      this.linkedEditGroups = linkedEditGroups;
+    }
+    this.selection = selection;
+  }
+
+  factory SourceChange.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String message;
+      if (json.containsKey("message")) {
+        message = jsonDecoder.decodeString(jsonPath + ".message", json["message"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "message");
+      }
+      List<SourceFileEdit> edits;
+      if (json.containsKey("edits")) {
+        edits = jsonDecoder.decodeList(jsonPath + ".edits", json["edits"], (String jsonPath, Object json) => new SourceFileEdit.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "edits");
+      }
+      List<LinkedEditGroup> linkedEditGroups;
+      if (json.containsKey("linkedEditGroups")) {
+        linkedEditGroups = jsonDecoder.decodeList(jsonPath + ".linkedEditGroups", json["linkedEditGroups"], (String jsonPath, Object json) => new LinkedEditGroup.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "linkedEditGroups");
+      }
+      Position selection;
+      if (json.containsKey("selection")) {
+        selection = new Position.fromJson(jsonDecoder, jsonPath + ".selection", json["selection"]);
+      }
+      return new SourceChange(message, edits: edits, linkedEditGroups: linkedEditGroups, selection: selection);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "SourceChange", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["message"] = message;
+    result["edits"] = edits.map((SourceFileEdit value) => value.toJson()).toList();
+    result["linkedEditGroups"] = linkedEditGroups.map((LinkedEditGroup value) => value.toJson()).toList();
+    if (selection != null) {
+      result["selection"] = selection.toJson();
+    }
+    return result;
+  }
+
+  /**
+   * Adds [edit] to the [FileEdit] for the given [file].
+   */
+  void addEdit(String file, int fileStamp, SourceEdit edit) =>
+      addEditToSourceChange(this, file, fileStamp, edit);
+
+  /**
+   * Adds the given [FileEdit].
+   */
+  void addFileEdit(SourceFileEdit edit) {
+    edits.add(edit);
+  }
+
+  /**
+   * Adds the given [LinkedEditGroup].
+   */
+  void addLinkedEditGroup(LinkedEditGroup linkedEditGroup) {
+    linkedEditGroups.add(linkedEditGroup);
+  }
+
+  /**
+   * Returns the [FileEdit] for the given [file], maybe `null`.
+   */
+  SourceFileEdit getFileEdit(String file) =>
+      getChangeFileEdit(this, file);
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is SourceChange) {
+      return message == other.message &&
+          listEqual(edits, other.edits, (SourceFileEdit a, SourceFileEdit b) => a == b) &&
+          listEqual(linkedEditGroups, other.linkedEditGroups, (LinkedEditGroup a, LinkedEditGroup b) => a == b) &&
+          selection == other.selection;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, message.hashCode);
+    hash = JenkinsSmiHash.combine(hash, edits.hashCode);
+    hash = JenkinsSmiHash.combine(hash, linkedEditGroups.hashCode);
+    hash = JenkinsSmiHash.combine(hash, selection.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * SourceEdit
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "replacement": String
+ *   "id": optional String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class SourceEdit implements HasToJson {
+  /**
+   * Get the result of applying a set of [edits] to the given [code]. Edits are
+   * applied in the order they appear in [edits].
+   */
+  static String applySequence(String code, Iterable<SourceEdit> edits) =>
+      applySequenceOfEdits(code, edits);
+
+  int _offset;
+
+  int _length;
+
+  String _replacement;
+
+  String _id;
+
+  /**
+   * The offset of the region to be modified.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the region to be modified.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  /**
+   * The length of the region to be modified.
+   */
+  int get length => _length;
+
+  /**
+   * The length of the region to be modified.
+   */
+  void set length(int value) {
+    assert(value != null);
+    this._length = value;
+  }
+
+  /**
+   * The code that is to replace the specified region in the original code.
+   */
+  String get replacement => _replacement;
+
+  /**
+   * The code that is to replace the specified region in the original code.
+   */
+  void set replacement(String value) {
+    assert(value != null);
+    this._replacement = value;
+  }
+
+  /**
+   * An identifier that uniquely identifies this source edit from other edits
+   * in the same response. This field is omitted unless a containing structure
+   * needs to be able to identify the edit for some reason.
+   *
+   * For example, some refactoring operations can produce edits that might not
+   * be appropriate (referred to as potential edits). Such edits will have an
+   * id so that they can be referenced. Edits in the same response that do not
+   * need to be referenced will not have an id.
+   */
+  String get id => _id;
+
+  /**
+   * An identifier that uniquely identifies this source edit from other edits
+   * in the same response. This field is omitted unless a containing structure
+   * needs to be able to identify the edit for some reason.
+   *
+   * For example, some refactoring operations can produce edits that might not
+   * be appropriate (referred to as potential edits). Such edits will have an
+   * id so that they can be referenced. Edits in the same response that do not
+   * need to be referenced will not have an id.
+   */
+  void set id(String value) {
+    this._id = value;
+  }
+
+  SourceEdit(int offset, int length, String replacement, {String id}) {
+    this.offset = offset;
+    this.length = length;
+    this.replacement = replacement;
+    this.id = id;
+  }
+
+  factory SourceEdit.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      int length;
+      if (json.containsKey("length")) {
+        length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "length");
+      }
+      String replacement;
+      if (json.containsKey("replacement")) {
+        replacement = jsonDecoder.decodeString(jsonPath + ".replacement", json["replacement"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "replacement");
+      }
+      String id;
+      if (json.containsKey("id")) {
+        id = jsonDecoder.decodeString(jsonPath + ".id", json["id"]);
+      }
+      return new SourceEdit(offset, length, replacement, id: id);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "SourceEdit", json);
+    }
+  }
+
+  /**
+   * The end of the region to be modified.
+   */
+  int get end => offset + length;
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["offset"] = offset;
+    result["length"] = length;
+    result["replacement"] = replacement;
+    if (id != null) {
+      result["id"] = id;
+    }
+    return result;
+  }
+
+  /**
+   * Get the result of applying the edit to the given [code].
+   */
+  String apply(String code) => applyEdit(code, this);
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is SourceEdit) {
+      return offset == other.offset &&
+          length == other.length &&
+          replacement == other.replacement &&
+          id == other.id;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+    hash = JenkinsSmiHash.combine(hash, length.hashCode);
+    hash = JenkinsSmiHash.combine(hash, replacement.hashCode);
+    hash = JenkinsSmiHash.combine(hash, id.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * SourceFileEdit
+ *
+ * {
+ *   "file": FilePath
+ *   "fileStamp": long
+ *   "edits": List<SourceEdit>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class SourceFileEdit implements HasToJson {
+  String _file;
+
+  int _fileStamp;
+
+  List<SourceEdit> _edits;
+
+  /**
+   * The file containing the code to be modified.
+   */
+  String get file => _file;
+
+  /**
+   * The file containing the code to be modified.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  /**
+   * The modification stamp of the file at the moment when the change was
+   * created, in milliseconds since the "Unix epoch". Will be -1 if the file
+   * did not exist and should be created. The client may use this field to make
+   * sure that the file was not changed since then, so it is safe to apply the
+   * change.
+   */
+  int get fileStamp => _fileStamp;
+
+  /**
+   * The modification stamp of the file at the moment when the change was
+   * created, in milliseconds since the "Unix epoch". Will be -1 if the file
+   * did not exist and should be created. The client may use this field to make
+   * sure that the file was not changed since then, so it is safe to apply the
+   * change.
+   */
+  void set fileStamp(int value) {
+    assert(value != null);
+    this._fileStamp = value;
+  }
+
+  /**
+   * A list of the edits used to effect the change.
+   */
+  List<SourceEdit> get edits => _edits;
+
+  /**
+   * A list of the edits used to effect the change.
+   */
+  void set edits(List<SourceEdit> value) {
+    assert(value != null);
+    this._edits = value;
+  }
+
+  SourceFileEdit(String file, int fileStamp, {List<SourceEdit> edits}) {
+    this.file = file;
+    this.fileStamp = fileStamp;
+    if (edits == null) {
+      this.edits = <SourceEdit>[];
+    } else {
+      this.edits = edits;
+    }
+  }
+
+  factory SourceFileEdit.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "file");
+      }
+      int fileStamp;
+      if (json.containsKey("fileStamp")) {
+        fileStamp = jsonDecoder.decodeInt(jsonPath + ".fileStamp", json["fileStamp"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "fileStamp");
+      }
+      List<SourceEdit> edits;
+      if (json.containsKey("edits")) {
+        edits = jsonDecoder.decodeList(jsonPath + ".edits", json["edits"], (String jsonPath, Object json) => new SourceEdit.fromJson(jsonDecoder, jsonPath, json));
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "edits");
+      }
+      return new SourceFileEdit(file, fileStamp, edits: edits);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "SourceFileEdit", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    result["fileStamp"] = fileStamp;
+    result["edits"] = edits.map((SourceEdit value) => value.toJson()).toList();
+    return result;
+  }
+
+  /**
+   * Adds the given [Edit] to the list.
+   */
+  void add(SourceEdit edit) => addEditForSource(this, edit);
+
+  /**
+   * Adds the given [Edit]s.
+   */
+  void addAll(Iterable<SourceEdit> edits) =>
+      addAllEditsForSource(this, edits);
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is SourceFileEdit) {
+      return file == other.file &&
+          fileStamp == other.fileStamp &&
+          listEqual(edits, other.edits, (SourceEdit a, SourceEdit b) => a == b);
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = JenkinsSmiHash.combine(hash, fileStamp.hashCode);
+    hash = JenkinsSmiHash.combine(hash, edits.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * WatchEvent
+ *
+ * {
+ *   "type": WatchEventType
+ *   "path": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class WatchEvent implements HasToJson {
+  WatchEventType _type;
+
+  String _path;
+
+  /**
+   * The type of change represented by this event.
+   */
+  WatchEventType get type => _type;
+
+  /**
+   * The type of change represented by this event.
+   */
+  void set type(WatchEventType value) {
+    assert(value != null);
+    this._type = value;
+  }
+
+  /**
+   * The absolute path of the file or directory that changed.
+   */
+  String get path => _path;
+
+  /**
+   * The absolute path of the file or directory that changed.
+   */
+  void set path(String value) {
+    assert(value != null);
+    this._path = value;
+  }
+
+  WatchEvent(WatchEventType type, String path) {
+    this.type = type;
+    this.path = path;
+  }
+
+  factory WatchEvent.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      WatchEventType type;
+      if (json.containsKey("type")) {
+        type = new WatchEventType.fromJson(jsonDecoder, jsonPath + ".type", json["type"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "type");
+      }
+      String path;
+      if (json.containsKey("path")) {
+        path = jsonDecoder.decodeString(jsonPath + ".path", json["path"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "path");
+      }
+      return new WatchEvent(type, path);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "WatchEvent", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["type"] = type.toJson();
+    result["path"] = path;
+    return result;
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is WatchEvent) {
+      return type == other.type &&
+          path == other.path;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, type.hashCode);
+    hash = JenkinsSmiHash.combine(hash, path.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * WatchEventType
+ *
+ * enum {
+ *   ADD
+ *   MODIFY
+ *   REMOVE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class WatchEventType implements Enum {
+  /**
+   * An indication that the file or directory was added.
+   */
+  static const WatchEventType ADD = const WatchEventType._("ADD");
+
+  /**
+   * An indication that the file was modified.
+   */
+  static const WatchEventType MODIFY = const WatchEventType._("MODIFY");
+
+  /**
+   * An indication that the file or directory was removed.
+   */
+  static const WatchEventType REMOVE = const WatchEventType._("REMOVE");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<WatchEventType> VALUES = const <WatchEventType>[ADD, MODIFY, REMOVE];
+
+  @override
+  final String name;
+
+  const WatchEventType._(this.name);
+
+  factory WatchEventType(String name) {
+    switch (name) {
+      case "ADD":
+        return ADD;
+      case "MODIFY":
+        return MODIFY;
+      case "REMOVE":
+        return REMOVE;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory WatchEventType.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new WatchEventType(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "WatchEventType", json);
+  }
+
+  @override
+  String toString() => "WatchEventType.$name";
+
+  String toJson() => name;
+}
diff --git a/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart b/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
new file mode 100644
index 0000000..c3048d4
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:analyzer_plugin/channel/channel.dart';
+import 'package:analyzer_plugin/protocol/protocol.dart';
+
+/**
+ * The object that allows a [ServerPlugin] to receive [Request]s and to return
+ * both [Response]s and [Notification]s. It communicates with the analysis
+ * server by passing data to the server's main isolate.
+ */
+class PluginIsolateChannel implements PluginCommunicationChannel {
+  /**
+   * The port used to send notifications and responses to the server.
+   */
+  SendPort _sendPort;
+
+  /**
+   * The port used to receive requests from the server.
+   */
+  ReceivePort _receivePort;
+
+  /**
+   * The subscription that needs to be cancelled when the channel is closed.
+   */
+  StreamSubscription _subscription;
+
+  /**
+   * Initialize a newly created channel to communicate with the server.
+   */
+  PluginIsolateChannel(this._sendPort) {
+    _receivePort = new ReceivePort();
+    _sendPort.send(_receivePort.sendPort);
+  }
+
+  @override
+  void close() {
+    if (_subscription != null) {
+      _subscription.cancel();
+      _subscription = null;
+    }
+  }
+
+  @override
+  void listen(void onRequest(Request request),
+      {Function onError, void onDone()}) {
+    void onData(data) {
+      Map<String, Object> requestMap = data;
+      Request request = new Request.fromJson(requestMap);
+      if (request != null) {
+        onRequest(request);
+      }
+    }
+
+    if (_subscription != null) {
+      throw new StateError('Only one listener is allowed per channel');
+    }
+    _subscription = _receivePort.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: false);
+  }
+
+  @override
+  void sendNotification(Notification notification) {
+    _sendPort.send(notification.toJson());
+  }
+
+  @override
+  void sendResponse(Response response) {
+    _sendPort.send(response.toJson());
+  }
+}
+
+/**
+ * The communication channel that allows an analysis server to send [Request]s
+ * to, and to receive both [Response]s and [Notification]s from, a plugin.
+ */
+class ServerIsolateChannel implements ServerCommunicationChannel {
+  /**
+   * The URI for the plugin that will be run in the isolate that this channel
+   * communicates with.
+   */
+  final Uri uri;
+
+  /**
+   * The isolate in which the plugin is running, or `null` if the plugin has
+   * not yet been started by invoking [listen].
+   */
+  Isolate _isolate;
+
+  /**
+   * The port used to send requests to the plugin, or `null` if the plugin has
+   * not yet been started by invoking [listen].
+   */
+  SendPort _sendPort;
+
+  /**
+   * Initialize a newly created channel to communicate with an isolate running
+   * the code at the given [uri].
+   */
+  ServerIsolateChannel(this.uri);
+
+  @override
+  void close() {
+    // TODO(brianwilkerson) Is there anything useful to do here?
+    _isolate = null;
+    _sendPort = null;
+  }
+
+  @override
+  Future<Null> listen(void onResponse(Response response),
+      void onNotification(Notification notification),
+      {Function onError, void onDone()}) async {
+    if (_isolate != null) {
+      throw new StateError('Cannot listen to the same channel more than once.');
+    }
+    ReceivePort receivePort = new ReceivePort();
+    ReceivePort errorPort;
+    if (onError != null) {
+      errorPort = new ReceivePort();
+      errorPort.listen((error) {
+        onError(error);
+      });
+    }
+    ReceivePort exitPort;
+    if (onDone != null) {
+      exitPort = new ReceivePort();
+      exitPort.listen((_) {
+        onDone();
+      });
+    }
+    _isolate = await Isolate.spawnUri(uri, <String>[], receivePort.sendPort,
+        automaticPackageResolution: true,
+        onError: errorPort?.sendPort,
+        onExit: exitPort?.sendPort);
+    _sendPort = await receivePort.first as SendPort;
+    receivePort.listen((dynamic input) {
+      if (input is Map) {
+        if (input.containsKey('id') != null) {
+          onResponse(new Response.fromJson(input));
+        } else if (input.containsKey('event')) {
+          onNotification(new Notification.fromJson(input));
+        }
+      }
+    });
+  }
+
+  @override
+  void sendRequest(Request request) {
+    _sendPort.send(request.toJson());
+  }
+}
diff --git a/pkg/analyzer_plugin/lib/src/driver.dart b/pkg/analyzer_plugin/lib/src/driver.dart
new file mode 100644
index 0000000..3005d0f
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/src/driver.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate';
+
+import 'package:analyzer_plugin/plugin/plugin.dart';
+import 'package:analyzer_plugin/src/channel/isolate_channel.dart';
+import 'package:analyzer_plugin/starter.dart';
+
+/**
+ * The [Driver] class represents a single running instance of an analysis
+ * server plugin. It is responsible for handling the communications with the
+ * server and forwarding requests on to the plugin.
+ */
+class Driver implements ServerPluginStarter {
+  /**
+   * The plugin that will be started.
+   */
+  final ServerPlugin plugin;
+
+  /**
+   * Initialize a newly created driver that can be used to start the given
+   * plugin.
+   */
+  Driver(this.plugin);
+
+  @override
+  void start(SendPort sendPort) {
+    PluginIsolateChannel channel = new PluginIsolateChannel(sendPort);
+    plugin.start(channel);
+  }
+}
diff --git a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
new file mode 100644
index 0000000..38dd3df
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
@@ -0,0 +1,522 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:convert' hide JsonDecoder;
+
+import 'package:analyzer_plugin/protocol/protocol.dart';
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+
+final Map<String, RefactoringKind> REQUEST_ID_REFACTORING_KINDS =
+    new HashMap<String, RefactoringKind>();
+
+/**
+ * Adds the given [sourceEdits] to the list in [sourceFileEdit].
+ */
+void addAllEditsForSource(
+    SourceFileEdit sourceFileEdit, Iterable<SourceEdit> edits) {
+  edits.forEach(sourceFileEdit.add);
+}
+
+/**
+ * Adds the given [sourceEdit] to the list in [sourceFileEdit].
+ */
+void addEditForSource(SourceFileEdit sourceFileEdit, SourceEdit sourceEdit) {
+  List<SourceEdit> edits = sourceFileEdit.edits;
+  int index = 0;
+  while (index < edits.length && edits[index].offset > sourceEdit.offset) {
+    index++;
+  }
+  edits.insert(index, sourceEdit);
+}
+
+/**
+ * Adds [edit] to the [FileEdit] for the given [file].
+ */
+void addEditToSourceChange(
+    SourceChange change, String file, int fileStamp, SourceEdit edit) {
+  SourceFileEdit fileEdit = change.getFileEdit(file);
+  if (fileEdit == null) {
+    fileEdit = new SourceFileEdit(file, fileStamp);
+    change.addFileEdit(fileEdit);
+  }
+  fileEdit.add(edit);
+}
+
+/**
+ * Get the result of applying the edit to the given [code].  Access via
+ * SourceEdit.apply().
+ */
+String applyEdit(String code, SourceEdit edit) {
+  if (edit.length < 0) {
+    throw new RangeError('length is negative');
+  }
+  return code.replaceRange(edit.offset, edit.end, edit.replacement);
+}
+
+/**
+ * Get the result of applying a set of [edits] to the given [code].  Edits
+ * are applied in the order they appear in [edits].  Access via
+ * SourceEdit.applySequence().
+ */
+String applySequenceOfEdits(String code, Iterable<SourceEdit> edits) {
+  edits.forEach((SourceEdit edit) {
+    code = edit.apply(code);
+  });
+  return code;
+}
+
+/**
+ * Returns the [FileEdit] for the given [file], maybe `null`.
+ */
+SourceFileEdit getChangeFileEdit(SourceChange change, String file) {
+  for (SourceFileEdit fileEdit in change.edits) {
+    if (fileEdit.file == file) {
+      return fileEdit;
+    }
+  }
+  return null;
+}
+
+/**
+ * Compare the lists [listA] and [listB], using [itemEqual] to compare
+ * list elements.
+ */
+bool listEqual(List listA, List listB, bool itemEqual(a, b)) {
+  if (listA == null) {
+    return listB == null;
+  }
+  if (listB == null) {
+    return false;
+  }
+  if (listA.length != listB.length) {
+    return false;
+  }
+  for (int i = 0; i < listA.length; i++) {
+    if (!itemEqual(listA[i], listB[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * Compare the maps [mapA] and [mapB], using [valueEqual] to compare map
+ * values.
+ */
+bool mapEqual(Map mapA, Map mapB, bool valueEqual(a, b)) {
+  if (mapA == null) {
+    return mapB == null;
+  }
+  if (mapB == null) {
+    return false;
+  }
+  if (mapA.length != mapB.length) {
+    return false;
+  }
+  for (var key in mapA.keys) {
+    if (!mapB.containsKey(key)) {
+      return false;
+    }
+    if (!valueEqual(mapA[key], mapB[key])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * Translate the input [map], applying [keyCallback] to all its keys, and
+ * [valueCallback] to all its values.
+ */
+Map/*<KR, VR>*/ mapMap/*<KP, VP, KR, VR>*/(Map/*<KP, VP>*/ map,
+    {dynamic/*=KR*/ keyCallback(/*<KP>*/ key),
+    dynamic/*=VR*/ valueCallback(/*<VP>*/ value)}) {
+  Map/*<KR, VR>*/ result = new HashMap/*<KR, VR>*/();
+  map.forEach((key, value) {
+    Object/*=KR*/ resultKey;
+    Object/*=VR*/ resultValue;
+    if (keyCallback != null) {
+      resultKey = keyCallback(key);
+    } else {
+      resultKey = key as Object/*=KR*/;
+    }
+    if (valueCallback != null) {
+      resultValue = valueCallback(value);
+    } else {
+      resultValue = value as Object/*=VR*/;
+    }
+    result[resultKey] = resultValue;
+  });
+  return result;
+}
+
+RefactoringProblemSeverity maxRefactoringProblemSeverity(
+    RefactoringProblemSeverity a, RefactoringProblemSeverity b) {
+  if (b == null) {
+    return a;
+  }
+  if (a == null) {
+    return b;
+  } else if (a == RefactoringProblemSeverity.INFO) {
+    return b;
+  } else if (a == RefactoringProblemSeverity.WARNING) {
+    if (b == RefactoringProblemSeverity.ERROR ||
+        b == RefactoringProblemSeverity.FATAL) {
+      return b;
+    }
+  } else if (a == RefactoringProblemSeverity.ERROR) {
+    if (b == RefactoringProblemSeverity.FATAL) {
+      return b;
+    }
+  }
+  return a;
+}
+
+/**
+ * Create a [RefactoringFeedback] corresponding the given [kind].
+ */
+RefactoringFeedback refactoringFeedbackFromJson(
+    JsonDecoder jsonDecoder, String jsonPath, Object json, Map feedbackJson) {
+  RefactoringKind kind = jsonDecoder.refactoringKind;
+  if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) {
+    return new ExtractLocalVariableFeedback.fromJson(
+        jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.EXTRACT_METHOD) {
+    return new ExtractMethodFeedback.fromJson(jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
+    return new InlineLocalVariableFeedback.fromJson(
+        jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.INLINE_METHOD) {
+    return new InlineMethodFeedback.fromJson(jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.RENAME) {
+    return new RenameFeedback.fromJson(jsonDecoder, jsonPath, json);
+  }
+  return null;
+}
+
+/**
+ * Create a [RefactoringOptions] corresponding the given [kind].
+ */
+RefactoringOptions refactoringOptionsFromJson(JsonDecoder jsonDecoder,
+    String jsonPath, Object json, RefactoringKind kind) {
+  if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) {
+    return new ExtractLocalVariableOptions.fromJson(
+        jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.EXTRACT_METHOD) {
+    return new ExtractMethodOptions.fromJson(jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.INLINE_METHOD) {
+    return new InlineMethodOptions.fromJson(jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.MOVE_FILE) {
+    return new MoveFileOptions.fromJson(jsonDecoder, jsonPath, json);
+  }
+  if (kind == RefactoringKind.RENAME) {
+    return new RenameOptions.fromJson(jsonDecoder, jsonPath, json);
+  }
+  return null;
+}
+
+///**
+// * Create a [RefactoringFeedback] corresponding the given [kind].
+// */
+//RefactoringFeedback refactoringFeedbackFromJson(
+//    JsonDecoder jsonDecoder, String jsonPath, Object json, Map feedbackJson) {
+//  RefactoringKind kind = jsonDecoder.refactoringKind;
+//  if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) {
+//    return new ExtractLocalVariableFeedback.fromJson(
+//        jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.EXTRACT_METHOD) {
+//    return new ExtractMethodFeedback.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
+//    return new InlineLocalVariableFeedback.fromJson(
+//        jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.INLINE_METHOD) {
+//    return new InlineMethodFeedback.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.RENAME) {
+//    return new RenameFeedback.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  return null;
+//}
+//
+///**
+// * Create a [RefactoringOptions] corresponding the given [kind].
+// */
+//RefactoringOptions refactoringOptionsFromJson(JsonDecoder jsonDecoder,
+//    String jsonPath, Object json, RefactoringKind kind) {
+//  if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) {
+//    return new ExtractLocalVariableOptions.fromJson(
+//        jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.EXTRACT_METHOD) {
+//    return new ExtractMethodOptions.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.INLINE_METHOD) {
+//    return new InlineMethodOptions.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.MOVE_FILE) {
+//    return new MoveFileOptions.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  if (kind == RefactoringKind.RENAME) {
+//    return new RenameOptions.fromJson(jsonDecoder, jsonPath, json);
+//  }
+//  return null;
+//}
+
+/**
+ * Type of callbacks used to decode parts of JSON objects.  [jsonPath] is a
+ * string describing the part of the JSON object being decoded, and [value] is
+ * the part to decode.
+ */
+typedef E JsonDecoderCallback<E>(String jsonPath, Object value);
+
+/**
+ * Instances of the class [HasToJson] implement [toJson] method that returns
+ * a JSON presentation.
+ */
+abstract class HasToJson {
+  /**
+   * Returns a JSON presentation of the object.
+   */
+  Map<String, Object> toJson();
+}
+
+/**
+ * Base class for decoding JSON objects.  The derived class must implement
+ * error reporting logic.
+ */
+abstract class JsonDecoder {
+  /**
+   * Retrieve the RefactoringKind that should be assumed when decoding
+   * refactoring feedback objects, or null if no refactoring feedback object is
+   * expected to be encountered.
+   */
+  RefactoringKind get refactoringKind;
+
+  /**
+   * Decode a JSON object that is expected to be a boolean.  The strings "true"
+   * and "false" are also accepted.
+   */
+  bool decodeBool(String jsonPath, Object json) {
+    if (json is bool) {
+      return json;
+    } else if (json == 'true') {
+      return true;
+    } else if (json == 'false') {
+      return false;
+    }
+    throw mismatch(jsonPath, 'bool', json);
+  }
+
+  /**
+   * Decode a JSON object that is expected to be an integer.  A string
+   * representation of an integer is also accepted.
+   */
+  int decodeInt(String jsonPath, Object json) {
+    if (json is int) {
+      return json;
+    } else if (json is String) {
+      return int.parse(json, onError: (String value) {
+        throw mismatch(jsonPath, 'int', json);
+      });
+    }
+    throw mismatch(jsonPath, 'int', json);
+  }
+
+  /**
+   * Decode a JSON object that is expected to be a List. The [decoder] is used
+   * to decode the items in the list.
+   *
+   * The type parameter [E] is the expected type of the elements in the list.
+   */
+  List/*<E>*/ decodeList/*<E>*/(String jsonPath, Object json,
+      [JsonDecoderCallback/*<E>*/ decoder]) {
+    if (json == null) {
+      return/*<E>*/ [];
+    } else if (json is List) {
+      List/*<E>*/ result = /*<E>*/ [];
+      for (int i = 0; i < json.length; i++) {
+        result.add(decoder('$jsonPath[$i]', json[i]));
+      }
+      return result;
+    } else {
+      throw mismatch(jsonPath, 'List', json);
+    }
+  }
+
+  /**
+   * Decode a JSON object that is expected to be a Map.  [keyDecoder] is used
+   * to decode the keys, and [valueDecoder] is used to decode the values.
+   */
+  Map/*<K, V>*/ decodeMap/*<K, V>*/(String jsonPath, Object json,
+      {JsonDecoderCallback/*<K>*/ keyDecoder,
+      JsonDecoderCallback/*<V>*/ valueDecoder}) {
+    if (json == null) {
+      return {};
+    } else if (json is Map) {
+      Map/*<K, V>*/ result = /*<K, V>*/ {};
+      json.forEach((String key, value) {
+        Object/*=K*/ decodedKey;
+        if (keyDecoder != null) {
+          decodedKey = keyDecoder('$jsonPath.key', key);
+        } else {
+          decodedKey = key as Object/*=K*/;
+        }
+        if (valueDecoder != null) {
+          value = valueDecoder('$jsonPath[${JSON.encode(key)}]', value);
+        }
+        result[decodedKey] = value as Object/*=V*/;
+      });
+      return result;
+    } else {
+      throw mismatch(jsonPath, 'Map', json);
+    }
+  }
+
+  /**
+   * Decode a JSON object that is expected to be a string.
+   */
+  String decodeString(String jsonPath, Object json) {
+    if (json is String) {
+      return json;
+    } else {
+      throw mismatch(jsonPath, 'String', json);
+    }
+  }
+
+  /**
+   * Decode a JSON object that is expected to be one of several choices,
+   * where the choices are disambiguated by the contents of the field [field].
+   * [decoders] is a map from each possible string in the field to the decoder
+   * that should be used to decode the JSON object.
+   */
+  Object decodeUnion(String jsonPath, Map json, String field,
+      Map<String, JsonDecoderCallback> decoders) {
+    if (json is Map) {
+      if (!json.containsKey(field)) {
+        throw missingKey(jsonPath, field);
+      }
+      var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]';
+      String disambiguator = decodeString(disambiguatorPath, json[field]);
+      if (!decoders.containsKey(disambiguator)) {
+        throw mismatch(
+            disambiguatorPath, 'One of: ${decoders.keys.toList()}', json);
+      }
+      return decoders[disambiguator](jsonPath, json);
+    } else {
+      throw mismatch(jsonPath, 'Map', json);
+    }
+  }
+
+  /**
+   * Create an exception to throw if the JSON object at [jsonPath] fails to
+   * match the API definition of [expected].
+   */
+  dynamic mismatch(String jsonPath, String expected, [Object actual]);
+
+  /**
+   * Create an exception to throw if the JSON object at [jsonPath] is missing
+   * the key [key].
+   */
+  dynamic missingKey(String jsonPath, String key);
+}
+
+/**
+ * JsonDecoder for decoding requests.  Errors are reporting by throwing a
+ * [RequestFailure].
+ */
+class RequestDecoder extends JsonDecoder {
+  /**
+   * The request being deserialized.
+   */
+  final Request _request;
+
+  RequestDecoder(this._request);
+
+  @override
+  RefactoringKind get refactoringKind {
+    // Refactoring feedback objects should never appear in requests.
+    return null;
+  }
+
+  @override
+  dynamic mismatch(String jsonPath, String expected, [Object actual]) {
+    StringBuffer buffer = new StringBuffer();
+    buffer.write('Expected to be ');
+    buffer.write(expected);
+    if (actual != null) {
+      buffer.write('; found "');
+      buffer.write(JSON.encode(actual));
+      buffer.write('"');
+    }
+    return new RequestFailure(RequestErrorFactory.invalidParameter(
+        _request, jsonPath, buffer.toString()));
+  }
+
+  @override
+  dynamic missingKey(String jsonPath, String key) {
+    return new RequestFailure(RequestErrorFactory.invalidParameter(
+        _request, jsonPath, 'Expected to contain key ${JSON.encode(key)}'));
+  }
+}
+
+abstract class RequestParams implements HasToJson {
+  /**
+   * Return a request whose parameters are taken from this object and that has
+   * the given [id].
+   */
+  Request toRequest(String id);
+}
+
+/**
+ * JsonDecoder for decoding responses from the server.  This is intended to be
+ * used only for testing.  Errors are reported using bare [Exception] objects.
+ */
+class ResponseDecoder extends JsonDecoder {
+  @override
+  final RefactoringKind refactoringKind;
+
+  ResponseDecoder(this.refactoringKind);
+
+  @override
+  dynamic mismatch(String jsonPath, String expected, [Object actual]) {
+    StringBuffer buffer = new StringBuffer();
+    buffer.write('Expected ');
+    buffer.write(expected);
+    if (actual != null) {
+      buffer.write(' found "');
+      buffer.write(JSON.encode(actual));
+      buffer.write('"');
+    }
+    buffer.write(' at ');
+    buffer.write(jsonPath);
+    return new Exception(buffer.toString());
+  }
+
+  @override
+  dynamic missingKey(String jsonPath, String key) {
+    return new Exception('Missing key $key at $jsonPath');
+  }
+}
+
+/**
+ * The result data associated with a response.
+ */
+abstract class ResponseResult implements HasToJson {
+  /**
+   * Return a response whose result data is this object for the request with the
+   * given [id].
+   */
+  Response toResponse(String id);
+}
diff --git a/pkg/analyzer_plugin/lib/src/utilities/null_string_sink.dart b/pkg/analyzer_plugin/lib/src/utilities/null_string_sink.dart
new file mode 100644
index 0000000..7a3c940
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/src/utilities/null_string_sink.dart
@@ -0,0 +1,20 @@
+// 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.
+
+/**
+ * A string sink that ignores everything written to it.
+ */
+class NullStringSink implements StringSink {
+  @override
+  void write(Object obj) {}
+
+  @override
+  void writeAll(Iterable objects, [String separator = ""]) {}
+
+  @override
+  void writeCharCode(int charCode) {}
+
+  @override
+  void writeln([Object obj = ""]) {}
+}
diff --git a/pkg/analyzer_plugin/lib/starter.dart b/pkg/analyzer_plugin/lib/starter.dart
new file mode 100644
index 0000000..fbd2bca
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/starter.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate';
+
+import 'package:analyzer_plugin/plugin/plugin.dart';
+import 'package:analyzer_plugin/src/driver.dart';
+
+/**
+ * An object that can be used to start an analysis server plugin. This class
+ * exists so that clients can configure a plugin before starting it.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ServerPluginStarter {
+  /**
+   * Create a starter that can be used to start the given [plugin].
+   */
+  factory ServerPluginStarter(ServerPlugin plugin) => new Driver(plugin);
+
+  /**
+   * Establish the channel used to communicate with the server and start the
+   * plugin.
+   */
+  void start(SendPort sendPort);
+}
diff --git a/pkg/analyzer_plugin/lib/utilities/subscription_manager.dart b/pkg/analyzer_plugin/lib/utilities/subscription_manager.dart
new file mode 100644
index 0000000..59f9758
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/utilities/subscription_manager.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+
+/**
+ * An object that manages the subscriptions for analysis results.
+ */
+class SubscriptionManager {
+  /**
+   * The current set of subscriptions.
+   */
+  Map<AnalysisService, List<String>> _subscriptions;
+
+  /**
+   * Initialize a newly created subscription manager to have no subscriptions.
+   */
+  SubscriptionManager();
+
+  /**
+   * Return a list of the services for which the file with the given [filePath]
+   * has been subscribed.
+   */
+  List<AnalysisService> servicesForFile(String filePath) {
+    List<AnalysisService> services = <AnalysisService>[];
+    if (_subscriptions != null) {
+      _subscriptions.forEach((AnalysisService service, List<String> files) {
+        if (files.contains(filePath)) {
+          services.add(service);
+        }
+      });
+    }
+    return services;
+  }
+
+  /**
+   * Set the current set of subscriptions to those described by the given map of
+   * [subscriptions].
+   */
+  void setSubscriptions(Map<AnalysisService, List<String>> subscriptions) {
+    _subscriptions = subscriptions;
+  }
+}
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
new file mode 100644
index 0000000..8315bf9
--- /dev/null
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -0,0 +1,16 @@
+name: analyzer_plugin
+description: A framework for building plugins for the analysis server.
+version: 0.0.1-alpha.0
+author: Dart Team <misc@dartlang.org>
+
+environment:
+  sdk: '>=1.0.0 <2.0.0'
+
+dependencies:
+  analyzer: 0.30.0-alpha.0
+  html: any
+  path: any
+
+dev_dependencies:
+  test_reflective_loader: ^0.1.0
+  test: ^0.12.0
diff --git a/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart b/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart
new file mode 100644
index 0000000..391101b
--- /dev/null
+++ b/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart
@@ -0,0 +1,736 @@
+// 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 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".
+
+/**
+ * Convenience methods for running integration tests
+ */
+import 'dart:async';
+
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+import 'package:test/test.dart';
+
+import 'integration_tests.dart';
+import 'protocol_matchers.dart';
+
+/**
+ * Convenience methods for running integration tests
+ */
+abstract class IntegrationTestMixin {
+  Server get server;
+
+  /**
+   * Used to request that the plugin perform a version check to confirm that it
+   * works with the version of the analysis server that is executing it.
+   *
+   * Parameters
+   *
+   * byteStorePath (String)
+   *
+   *   The path to the directory containing the on-disk byte store that is to
+   *   be used by any analysis drivers that are created.
+   *
+   * version (String)
+   *
+   *   The version number of the plugin spec supported by the analysis server
+   *   that is executing the plugin.
+   *
+   * Returns
+   *
+   * isCompatible (bool)
+   *
+   *   A flag indicating whether the plugin supports the same version of the
+   *   plugin spec as the analysis server. If the value is false, then the
+   *   plugin is expected to shutdown after returning the response.
+   *
+   * name (String)
+   *
+   *   The name of the plugin. This value is only used when the server needs to
+   *   identify the plugin, either to the user or for debugging purposes.
+   *
+   * version (String)
+   *
+   *   The version of the plugin. This value is only used when the server needs
+   *   to identify the plugin, either to the user or for debugging purposes.
+   *
+   * contactInfo (optional String)
+   *
+   *   Information that the user can use to use to contact the maintainers of
+   *   the plugin when there is a problem.
+   *
+   * interestingFiles (List<String>)
+   *
+   *   The glob patterns of the files for which the plugin will provide
+   *   information. This value is ignored if the isCompatible field is false.
+   *   Otherwise, it will be used to identify the files for which the plugin
+   *   should be notified of changes.
+   */
+  Future<PluginVersionCheckResult> sendPluginVersionCheck(String byteStorePath, String version) async {
+    var params = new PluginVersionCheckParams(byteStorePath, version).toJson();
+    var result = await server.send("plugin.versionCheck", params);
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    return new PluginVersionCheckResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
+   * Used to request that the plugin exit. The server will not send any other
+   * requests after this request. The plugin should not send any responses or
+   * notifications after sending the response to this request.
+   */
+  Future sendPluginShutdown() async {
+    var result = await server.send("plugin.shutdown", null);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to report that an unexpected error has occurred while executing the
+   * plugin. This notification is not used for problems with specific requests
+   * (which should be returned as part of the response) but is used for
+   * exceptions that occur while performing other tasks, such as analysis or
+   * preparing notifications.
+   *
+   * Parameters
+   *
+   * isFatal (bool)
+   *
+   *   A flag indicating whether the error is a fatal error, meaning that the
+   *   plugin will shutdown automatically after sending this notification. If
+   *   true, the server will not expect any other responses or notifications
+   *   from the plugin.
+   *
+   * message (String)
+   *
+   *   The error message indicating what kind of error was encountered.
+   *
+   * stackTrace (String)
+   *
+   *   The stack trace associated with the generation of the error, used for
+   *   debugging the plugin.
+   */
+  Stream<PluginErrorParams> onPluginError;
+
+  /**
+   * Stream controller for [onPluginError].
+   */
+  StreamController<PluginErrorParams> _onPluginError;
+
+  /**
+   * Used to inform the plugin of changes to files in the file system. Only
+   * events associated with files that match the interestingFiles glob patterns
+   * will be forwarded to the plugin.
+   *
+   * Parameters
+   *
+   * events (List<WatchEvent>)
+   *
+   *   The watch events that the plugin should handle.
+   */
+  Future sendAnalysisHandleWatchEvents(List<WatchEvent> events) async {
+    var params = new AnalysisHandleWatchEventsParams(events).toJson();
+    var result = await server.send("analysis.handleWatchEvents", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to force the re-analysis of everything contained in the specified
+   * context roots. This should cause all previously computed analysis results
+   * to be discarded and recomputed, and should cause all subscribed
+   * notifications to be re-sent.
+   *
+   * Parameters
+   *
+   * roots (optional List<FilePath>)
+   *
+   *   A list of the context roots that are to be re-analyzed.
+   *
+   *   If no context roots are provided, then all current context roots should
+   *   be re-analyzed.
+   */
+  Future sendAnalysisReanalyze({List<String> roots}) async {
+    var params = new AnalysisReanalyzeParams(roots: roots).toJson();
+    var result = await server.send("analysis.reanalyze", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to set the options used to build analysis contexts. This request will
+   * be sent exactly once before any context roots have been specified.
+   *
+   * Parameters
+   *
+   * options (ContextBuilderOptions)
+   *
+   *   The options used to build the analysis contexts.
+   */
+  Future sendAnalysisSetContextBuilderOptions(ContextBuilderOptions options) async {
+    var params = new AnalysisSetContextBuilderOptionsParams(options).toJson();
+    var result = await server.send("analysis.setContextBuilderOptions", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Set the list of context roots that should be analyzed.
+   *
+   * Parameters
+   *
+   * roots (List<ContextRoot>)
+   *
+   *   A list of the context roots that should be analyzed.
+   */
+  Future sendAnalysisSetContextRoots(List<ContextRoot> roots) async {
+    var params = new AnalysisSetContextRootsParams(roots).toJson();
+    var result = await server.send("analysis.setContextRoots", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to set the priority files to the files in the given list. A priority
+   * file is a file that should be given priority when scheduling which
+   * analysis work to do first. The list typically contains those files that
+   * are visible to the user and those for which analysis results will have the
+   * biggest impact on the user experience. The order of the files within the
+   * list is significant: the first file will be given higher priority than the
+   * second, the second higher priority than the third, and so on.
+   *
+   * Parameters
+   *
+   * files (List<FilePath>)
+   *
+   *   The files that are to be a priority for analysis.
+   */
+  Future sendAnalysisSetPriorityFiles(List<String> files) async {
+    var params = new AnalysisSetPriorityFilesParams(files).toJson();
+    var result = await server.send("analysis.setPriorityFiles", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to subscribe for services that are specific to individual files. All
+   * previous subscriptions should be replaced by the current set of
+   * subscriptions. If a given service is not included as a key in the map then
+   * no files should be subscribed to the service, exactly as if the service
+   * had been included in the map with an explicit empty list of files.
+   *
+   * Parameters
+   *
+   * subscriptions (Map<AnalysisService, List<FilePath>>)
+   *
+   *   A table mapping services to a list of the files being subscribed to the
+   *   service.
+   */
+  Future sendAnalysisSetSubscriptions(Map<AnalysisService, List<String>> subscriptions) async {
+    var params = new AnalysisSetSubscriptionsParams(subscriptions).toJson();
+    var result = await server.send("analysis.setSubscriptions", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to update the content of one or more files. Files that were
+   * previously updated but not included in this update remain unchanged. This
+   * effectively represents an overlay of the filesystem. The files whose
+   * content is overridden are therefore seen by the plugin as being files with
+   * the given content, even if the files do not exist on the filesystem or if
+   * the file path represents the path to a directory on the filesystem.
+   *
+   * Parameters
+   *
+   * files (Map<FilePath, AddContentOverlay | ChangeContentOverlay |
+   * RemoveContentOverlay>)
+   *
+   *   A table mapping the files whose content has changed to a description of
+   *   the content change.
+   */
+  Future sendAnalysisUpdateContent(Map<String, dynamic> files) async {
+    var params = new AnalysisUpdateContentParams(files).toJson();
+    var result = await server.send("analysis.updateContent", params);
+    outOfTestExpect(result, isNull);
+    return null;
+  }
+
+  /**
+   * Used to report the errors associated with a given file. The set of errors
+   * included in the notification is always a complete list that supersedes any
+   * previously reported errors.
+   *
+   * TODO: Decide whether we need to support the '--no-error-notification'
+   * option.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the errors.
+   *
+   * errors (List<AnalysisError>)
+   *
+   *   The errors contained in the file.
+   */
+  Stream<AnalysisErrorsParams> onAnalysisErrors;
+
+  /**
+   * Stream controller for [onAnalysisErrors].
+   */
+  StreamController<AnalysisErrorsParams> _onAnalysisErrors;
+
+  /**
+   * Used to report the folding regions associated with a given file. Folding
+   * regions can be nested, but cannot be overlapping. Nesting occurs when a
+   * foldable element, such as a method, is nested inside another foldable
+   * element such as a class.
+   *
+   * Folding regions that overlap a folding region computed by the server, or
+   * by one of the other plugins that are currently running, might be dropped
+   * by the server in order to present a consistent view to the client.
+   *
+   * This notification should only be sent if the server has subscribed to it
+   * by including the value "FOLDING" in the list of services passed in an
+   * analysis.setSubscriptions request.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the folding regions.
+   *
+   * regions (List<FoldingRegion>)
+   *
+   *   The folding regions contained in the file.
+   */
+  Stream<AnalysisFoldingParams> onAnalysisFolding;
+
+  /**
+   * Stream controller for [onAnalysisFolding].
+   */
+  StreamController<AnalysisFoldingParams> _onAnalysisFolding;
+
+  /**
+   * Used to report the highlight regions associated with a given file. Each
+   * highlight region represents a particular syntactic or semantic meaning
+   * associated with some range. Note that the highlight regions that are
+   * returned can overlap other highlight regions if there is more than one
+   * meaning associated with a particular region.
+   *
+   * This notification should only be sent if the server has subscribed to it
+   * by including the value "HIGHLIGHTS" in the list of services passed in an
+   * analysis.setSubscriptions request.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the highlight regions.
+   *
+   * regions (List<HighlightRegion>)
+   *
+   *   The highlight regions contained in the file.
+   */
+  Stream<AnalysisHighlightsParams> onAnalysisHighlights;
+
+  /**
+   * Stream controller for [onAnalysisHighlights].
+   */
+  StreamController<AnalysisHighlightsParams> _onAnalysisHighlights;
+
+  /**
+   * Used to report the navigation regions associated with a given file. Each
+   * navigation region represents a list of targets associated with some range.
+   * The lists will usually contain a single target, but can contain more in
+   * the case of a part that is included in multiple libraries or in Dart code
+   * that is compiled against multiple versions of a package. Note that the
+   * navigation regions that are returned should not overlap other navigation
+   * regions.
+   *
+   * Navigation regions that overlap a navigation region computed by the
+   * server, or by one of the other plugins that are currently running, might
+   * be dropped or modified by the server in order to present a consistent view
+   * to the client.
+   *
+   * This notification should only be sent if the server has subscribed to it
+   * by including the value "NAVIGATION" in the list of services passed in an
+   * analysis.setSubscriptions request.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the navigation regions.
+   *
+   * regions (List<NavigationRegion>)
+   *
+   *   The navigation regions contained in the file.
+   *
+   * targets (List<NavigationTarget>)
+   *
+   *   The navigation targets referenced in the file. They are referenced by
+   *   NavigationRegions by their index in this array.
+   *
+   * files (List<FilePath>)
+   *
+   *   The files containing navigation targets referenced in the file. They are
+   *   referenced by NavigationTargets by their index in this array.
+   */
+  Stream<AnalysisNavigationParams> onAnalysisNavigation;
+
+  /**
+   * Stream controller for [onAnalysisNavigation].
+   */
+  StreamController<AnalysisNavigationParams> _onAnalysisNavigation;
+
+  /**
+   * Used to report the occurrences of references to elements within a single
+   * file. None of the occurrence regions should overlap.
+   *
+   * Occurrence regions that overlap an occurrence region computed by the
+   * server, or by one of the other plugins that are currently running, might
+   * be dropped or modified by the server in order to present a consistent view
+   * to the client.
+   *
+   * This notification should only be sent if the server has subscribed to it
+   * by including the value "OCCURRENCES" in the list of services passed in an
+   * analysis.setSubscriptions request.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file in which the references occur.
+   *
+   * occurrences (List<Occurrences>)
+   *
+   *   The occurrences of references to elements within the file.
+   */
+  Stream<AnalysisOccurrencesParams> onAnalysisOccurrences;
+
+  /**
+   * Stream controller for [onAnalysisOccurrences].
+   */
+  StreamController<AnalysisOccurrencesParams> _onAnalysisOccurrences;
+
+  /**
+   * Used to report the outline fragments associated with a single file.
+   *
+   * The outline fragments will be merged with any outline produced by the
+   * server and with any fragments produced by other plugins. If the server
+   * cannot create a coherent outline, some fragments might be dropped.
+   *
+   * This notification should only be sent if the server has subscribed to it
+   * by including the value "OUTLINE" in the list of services passed in an
+   * analysis.setSubscriptions request.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file with which the outline is associated.
+   *
+   * outline (List<Outline>)
+   *
+   *   The outline fragments associated with the file.
+   */
+  Stream<AnalysisOutlineParams> onAnalysisOutline;
+
+  /**
+   * Stream controller for [onAnalysisOutline].
+   */
+  StreamController<AnalysisOutlineParams> _onAnalysisOutline;
+
+  /**
+   * Used to request that completion suggestions for the given offset in the
+   * given file be returned.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the point at which suggestions are to be made.
+   *
+   * offset (int)
+   *
+   *   The offset within the file at which suggestions are to be made.
+   *
+   * Returns
+   *
+   * replacementOffset (int)
+   *
+   *   The offset of the start of the text to be replaced. This will be
+   *   different than the offset used to request the completion suggestions if
+   *   there was a portion of an identifier before the original offset. In
+   *   particular, the replacementOffset will be the offset of the beginning of
+   *   said identifier.
+   *
+   * replacementLength (int)
+   *
+   *   The length of the text to be replaced if the remainder of the identifier
+   *   containing the cursor is to be replaced when the suggestion is applied
+   *   (that is, the number of characters in the existing identifier).
+   *
+   * results (List<CompletionSuggestion>)
+   *
+   *   The completion suggestions being reported. The notification contains all
+   *   possible completions at the requested cursor position, even those that
+   *   do not match the characters the user has already typed. This allows the
+   *   client to respond to further keystrokes from the user without having to
+   *   make additional requests.
+   */
+  Future<CompletionGetSuggestionsResult> sendCompletionGetSuggestions(String file, int offset) async {
+    var params = new CompletionGetSuggestionsParams(file, offset).toJson();
+    var result = await server.send("completion.getSuggestions", params);
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    return new CompletionGetSuggestionsResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
+   * Used to request the set of assists that are available at the given
+   * location. An assist is distinguished from a refactoring primarily by the
+   * fact that it affects a single file and does not require user input in
+   * order to be performed.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the code for which assists are being requested.
+   *
+   * offset (int)
+   *
+   *   The offset of the code for which assists are being requested.
+   *
+   * length (int)
+   *
+   *   The length of the code for which assists are being requested.
+   *
+   * Returns
+   *
+   * assists (List<PrioritizedSourceChange>)
+   *
+   *   The assists that are available at the given location.
+   */
+  Future<EditGetAssistsResult> sendEditGetAssists(String file, int offset, int length) async {
+    var params = new EditGetAssistsParams(file, offset, length).toJson();
+    var result = await server.send("edit.getAssists", params);
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    return new EditGetAssistsResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
+   * Used to request a list of the kinds of refactorings that are valid for the
+   * given selection in the given file.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the code on which the refactoring would be based.
+   *
+   * offset (int)
+   *
+   *   The offset of the code on which the refactoring would be based.
+   *
+   * length (int)
+   *
+   *   The length of the code on which the refactoring would be based.
+   *
+   * Returns
+   *
+   * kinds (List<RefactoringKind>)
+   *
+   *   The kinds of refactorings that are valid for the given selection.
+   *
+   *   The list of refactoring kinds is currently limited to those defined by
+   *   the server API, preventing plugins from adding their own refactorings.
+   *   However, plugins can support pre-defined refactorings, such as a rename
+   *   refactoring, at locations not supported by server.
+   */
+  Future<EditGetAvailableRefactoringsResult> sendEditGetAvailableRefactorings(String file, int offset, int length) async {
+    var params = new EditGetAvailableRefactoringsParams(file, offset, length).toJson();
+    var result = await server.send("edit.getAvailableRefactorings", params);
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    return new EditGetAvailableRefactoringsResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
+   * Used to request the set of fixes that are available for the errors at a
+   * given offset in a given file.
+   *
+   * Parameters
+   *
+   * file (FilePath)
+   *
+   *   The file containing the errors for which fixes are being requested.
+   *
+   * offset (int)
+   *
+   *   The offset used to select the errors for which fixes will be returned.
+   *
+   * Returns
+   *
+   * fixes (List<AnalysisErrorFixes>)
+   *
+   *   The fixes that are available for the errors at the given offset.
+   */
+  Future<EditGetFixesResult> sendEditGetFixes(String file, int offset) async {
+    var params = new EditGetFixesParams(file, offset).toJson();
+    var result = await server.send("edit.getFixes", params);
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    return new EditGetFixesResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
+   * Used to request the changes required to perform a refactoring.
+   *
+   * Parameters
+   *
+   * kind (RefactoringKind)
+   *
+   *   The kind of refactoring to be performed.
+   *
+   * file (FilePath)
+   *
+   *   The file containing the code involved in the refactoring.
+   *
+   * offset (int)
+   *
+   *   The offset of the region involved in the refactoring.
+   *
+   * length (int)
+   *
+   *   The length of the region involved in the refactoring.
+   *
+   * validateOnly (bool)
+   *
+   *   True if the client is only requesting that the values of the options be
+   *   validated and no change be generated.
+   *
+   * options (optional RefactoringOptions)
+   *
+   *   Data used to provide values provided by the user. The structure of the
+   *   data is dependent on the kind of refactoring being performed. The data
+   *   that is expected is documented in the section titled Refactorings,
+   *   labeled as "Options". This field can be omitted if the refactoring does
+   *   not require any options or if the values of those options are not known.
+   *
+   * Returns
+   *
+   * initialProblems (List<RefactoringProblem>)
+   *
+   *   The initial status of the refactoring, that is, problems related to the
+   *   context in which the refactoring is requested. The list should be empty
+   *   if there are no known problems.
+   *
+   * optionsProblems (List<RefactoringProblem>)
+   *
+   *   The options validation status, that is, problems in the given options,
+   *   such as light-weight validation of a new name, flags compatibility, etc.
+   *   The list should be empty if there are no known problems.
+   *
+   * finalProblems (List<RefactoringProblem>)
+   *
+   *   The final status of the refactoring, that is, problems identified in the
+   *   result of a full, potentially expensive validation and / or change
+   *   creation. The list should be empty if there are no known problems.
+   *
+   * feedback (optional RefactoringFeedback)
+   *
+   *   Data used to provide feedback to the user. The structure of the data is
+   *   dependent on the kind of refactoring being created. The data that is
+   *   returned is documented in the section titled Refactorings, labeled as
+   *   "Feedback".
+   *
+   * change (optional SourceChange)
+   *
+   *   The changes that are to be applied to affect the refactoring. This field
+   *   can be omitted if there are problems that prevent a set of changes from
+   *   being computed, such as having no options specified for a refactoring
+   *   that requires them, or if only validation was requested.
+   *
+   * potentialEdits (optional List<String>)
+   *
+   *   The ids of source edits that are not known to be valid. An edit is not
+   *   known to be valid if there was insufficient type information for the
+   *   plugin to be able to determine whether or not the code needs to be
+   *   modified, such as when a member is being renamed and there is a
+   *   reference to a member from an unknown type. This field can be omitted if
+   *   the change field is omitted or if there are no potential edits for the
+   *   refactoring.
+   */
+  Future<EditGetRefactoringResult> sendEditGetRefactoring(RefactoringKind kind, String file, int offset, int length, bool validateOnly, {RefactoringOptions options}) async {
+    var params = new EditGetRefactoringParams(kind, file, offset, length, validateOnly, options: options).toJson();
+    var result = await server.send("edit.getRefactoring", params);
+    ResponseDecoder decoder = new ResponseDecoder(kind);
+    return new EditGetRefactoringResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
+   * Initialize the fields in InttestMixin, and ensure that notifications will
+   * be handled.
+   */
+  void initializeInttestMixin() {
+    _onPluginError = new StreamController<PluginErrorParams>(sync: true);
+    onPluginError = _onPluginError.stream.asBroadcastStream();
+    _onAnalysisErrors = new StreamController<AnalysisErrorsParams>(sync: true);
+    onAnalysisErrors = _onAnalysisErrors.stream.asBroadcastStream();
+    _onAnalysisFolding = new StreamController<AnalysisFoldingParams>(sync: true);
+    onAnalysisFolding = _onAnalysisFolding.stream.asBroadcastStream();
+    _onAnalysisHighlights = new StreamController<AnalysisHighlightsParams>(sync: true);
+    onAnalysisHighlights = _onAnalysisHighlights.stream.asBroadcastStream();
+    _onAnalysisNavigation = new StreamController<AnalysisNavigationParams>(sync: true);
+    onAnalysisNavigation = _onAnalysisNavigation.stream.asBroadcastStream();
+    _onAnalysisOccurrences = new StreamController<AnalysisOccurrencesParams>(sync: true);
+    onAnalysisOccurrences = _onAnalysisOccurrences.stream.asBroadcastStream();
+    _onAnalysisOutline = new StreamController<AnalysisOutlineParams>(sync: true);
+    onAnalysisOutline = _onAnalysisOutline.stream.asBroadcastStream();
+  }
+
+  /**
+   * Dispatch the notification named [event], and containing parameters
+   * [params], to the appropriate stream.
+   */
+  void dispatchNotification(String event, params) {
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    switch (event) {
+      case "plugin.error":
+        outOfTestExpect(params, isPluginErrorParams);
+        _onPluginError.add(new PluginErrorParams.fromJson(decoder, 'params', params));
+        break;
+      case "analysis.errors":
+        outOfTestExpect(params, isAnalysisErrorsParams);
+        _onAnalysisErrors.add(new AnalysisErrorsParams.fromJson(decoder, 'params', params));
+        break;
+      case "analysis.folding":
+        outOfTestExpect(params, isAnalysisFoldingParams);
+        _onAnalysisFolding.add(new AnalysisFoldingParams.fromJson(decoder, 'params', params));
+        break;
+      case "analysis.highlights":
+        outOfTestExpect(params, isAnalysisHighlightsParams);
+        _onAnalysisHighlights.add(new AnalysisHighlightsParams.fromJson(decoder, 'params', params));
+        break;
+      case "analysis.navigation":
+        outOfTestExpect(params, isAnalysisNavigationParams);
+        _onAnalysisNavigation.add(new AnalysisNavigationParams.fromJson(decoder, 'params', params));
+        break;
+      case "analysis.occurrences":
+        outOfTestExpect(params, isAnalysisOccurrencesParams);
+        _onAnalysisOccurrences.add(new AnalysisOccurrencesParams.fromJson(decoder, 'params', params));
+        break;
+      case "analysis.outline":
+        outOfTestExpect(params, isAnalysisOutlineParams);
+        _onAnalysisOutline.add(new AnalysisOutlineParams.fromJson(decoder, 'params', params));
+        break;
+      default:
+        fail('Unexpected notification: $event');
+        break;
+    }
+  }
+}
diff --git a/pkg/analyzer_plugin/test/integration/support/integration_tests.dart b/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
new file mode 100644
index 0000000..80c7a20
--- /dev/null
+++ b/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
@@ -0,0 +1,959 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:path/path.dart';
+import 'package:test/test.dart';
+
+import 'integration_test_methods.dart';
+import 'protocol_matchers.dart';
+
+const Matcher isBool = const isInstanceOf<bool>();
+
+const Matcher isInt = const isInstanceOf<int>();
+
+const Matcher isNotification = const MatchesJsonObject(
+    'notification', const {'event': isString},
+    optionalFields: const {'params': isMap});
+
+const Matcher isObject = isMap;
+
+const Matcher isString = const isInstanceOf<String>();
+
+final Matcher isResponse = new MatchesJsonObject('response', {'id': isString},
+    optionalFields: {'result': anything, 'error': isRequestError});
+
+Matcher isListOf(Matcher elementMatcher) => new _ListOf(elementMatcher);
+
+Matcher isMapOf(Matcher keyMatcher, Matcher valueMatcher) =>
+    new _MapOf(keyMatcher, valueMatcher);
+
+Matcher isOneOf(List<Matcher> choiceMatchers) => new _OneOf(choiceMatchers);
+
+/**
+ * Assert that [actual] matches [matcher].
+ */
+void outOfTestExpect(actual, matcher,
+    {String reason, skip, bool verbose: false}) {
+  var matchState = {};
+  try {
+    if (matcher.matches(actual, matchState)) return;
+  } catch (e, trace) {
+    if (reason == null) {
+      reason = '${(e is String) ? e : e.toString()} at $trace';
+    }
+  }
+  fail(_defaultFailFormatter(actual, matcher, reason, matchState, verbose));
+}
+
+String _defaultFailFormatter(
+    actual, Matcher matcher, String reason, Map matchState, bool verbose) {
+  var description = new StringDescription();
+  description.add('Expected: ').addDescriptionOf(matcher).add('\n');
+  description.add('  Actual: ').addDescriptionOf(actual).add('\n');
+
+  var mismatchDescription = new StringDescription();
+  matcher.describeMismatch(actual, mismatchDescription, matchState, verbose);
+
+  if (mismatchDescription.length > 0) {
+    description.add('   Which: $mismatchDescription\n');
+  }
+  if (reason != null) description.add(reason).add('\n');
+  return description.toString();
+}
+
+/**
+ * Type of closures used by LazyMatcher.
+ */
+typedef Matcher MatcherCreator();
+
+/**
+ * Type of closures used by MatchesJsonObject to record field mismatches.
+ */
+typedef Description MismatchDescriber(Description mismatchDescription);
+
+/**
+ * Type of callbacks used to process notifications.
+ */
+typedef void NotificationProcessor(String event, params);
+
+/**
+ * Base class for analysis server integration tests.
+ */
+abstract class AbstractAnalysisServerIntegrationTest
+    extends IntegrationTestMixin {
+  /**
+   * Amount of time to give the server to respond to a shutdown request before
+   * forcibly terminating it.
+   */
+  static const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 5);
+
+  /**
+   * Connection to the analysis server.
+   */
+  @override
+  final Server server = new Server();
+
+  /**
+   * Temporary directory in which source files can be stored.
+   */
+  Directory sourceDirectory;
+
+  /**
+   * Map from file path to the list of analysis errors which have most recently
+   * been received for the file.
+   */
+  HashMap<String, List<AnalysisError>> currentAnalysisErrors =
+      new HashMap<String, List<AnalysisError>>();
+
+  /**
+   * True if the teardown process should skip sending a "server.shutdown"
+   * request (e.g. because the server is known to have already shutdown).
+   */
+  bool skipShutdown = false;
+
+  AbstractAnalysisServerIntegrationTest() {
+    initializeInttestMixin();
+  }
+
+//  /**
+//   * Return a future which will complete when a 'server.status' notification is
+//   * received from the server with 'analyzing' set to false.
+//   *
+//   * The future will only be completed by 'server.status' notifications that are
+//   * received after this function call.  So it is safe to use this getter
+//   * multiple times in one test; each time it is used it will wait afresh for
+//   * analysis to finish.
+//   */
+//  Future get analysisFinished {
+//    Completer completer = new Completer();
+//    StreamSubscription subscription;
+//    // This will only work if the caller has already subscribed to
+//    // SERVER_STATUS (e.g. using sendServerSetSubscriptions(['STATUS']))
+//    outOfTestExpect(_subscribedToServerStatus, isTrue);
+//    subscription = onServerStatus.listen((PluginStatusParams params) {
+//      if (params.analysis != null && !params.analysis.isAnalyzing) {
+//        completer.complete(params);
+//        subscription.cancel();
+//      }
+//    });
+//    return completer.future;
+//  }
+
+  /**
+   * Print out any messages exchanged with the server.  If some messages have
+   * already been exchanged with the server, they are printed out immediately.
+   */
+  void debugStdio() {
+    server.debugStdio();
+  }
+
+  /**
+   * The server is automatically started before every test, and a temporary
+   * [sourceDirectory] is created.
+   */
+  Future setUp() {
+    sourceDirectory = Directory.systemTemp.createTempSync('analysisServer');
+
+    onAnalysisErrors.listen((AnalysisErrorsParams params) {
+      currentAnalysisErrors[params.file] = params.errors;
+    });
+    Completer serverConnected = new Completer();
+    // TODO(brianwilkerson) Implement this.
+//    onServerConnected.listen((_) {
+//      outOfTestExpect(serverConnected.isCompleted, isFalse);
+//      serverConnected.complete();
+//    });
+    onPluginError.listen((PluginErrorParams params) {
+      // A plugin error should never happen during an integration test.
+      fail('${params.message}\n${params.stackTrace}');
+    });
+    return startServer().then((_) {
+      server.listenToOutput(dispatchNotification);
+      server.exitCode.then((_) {
+        skipShutdown = true;
+      });
+      return serverConnected.future;
+    });
+  }
+
+  /**
+   * If [skipShutdown] is not set, shut down the server.
+   */
+  Future shutdownIfNeeded() {
+    if (skipShutdown) {
+      return new Future.value();
+    }
+    // Give the server a short time to comply with the shutdown request; if it
+    // doesn't exit, then forcibly terminate it.
+    sendPluginShutdown();
+    return server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () {
+      return server.kill('server failed to exit');
+    });
+  }
+
+  /**
+   * Convert the given [relativePath] to an absolute path, by interpreting it
+   * relative to [sourceDirectory].  On Windows any forward slashes in
+   * [relativePath] are converted to backslashes.
+   */
+  String sourcePath(String relativePath) {
+    return join(sourceDirectory.path, relativePath.replaceAll('/', separator));
+  }
+
+  /**
+   * Send the server an 'analysis.setAnalysisRoots' command directing it to
+   * analyze [sourceDirectory].  If [subscribeStatus] is true (the default),
+   * then also enable [SERVER_STATUS] notifications so that [analysisFinished]
+   * can be used.
+   */
+  Future standardAnalysisSetup({bool subscribeStatus: true}) {
+    List<Future> futures = <Future>[];
+    // TODO(brianwilkerson) Implement this.
+//    if (subscribeStatus) {
+//      futures.add(sendServerSetSubscriptions([ServerService.STATUS]));
+//    }
+//    futures.add(sendAnalysisSetAnalysisRoots([sourceDirectory.path], []));
+    return Future.wait(futures);
+  }
+
+  /**
+   * Start [server].
+   */
+  Future startServer(
+          {bool checked: true, int diagnosticPort, int servicesPort}) =>
+      server.start(
+          checked: checked,
+          diagnosticPort: diagnosticPort,
+          servicesPort: servicesPort);
+
+  /**
+   * After every test, the server is stopped and [sourceDirectory] is deleted.
+   */
+  Future tearDown() {
+    return shutdownIfNeeded().then((_) {
+      sourceDirectory.deleteSync(recursive: true);
+    });
+  }
+
+  /**
+   * Write a source file with the given absolute [pathname] and [contents].
+   *
+   * If the file didn't previously exist, it is created.  If it did, it is
+   * overwritten.
+   *
+   * Parent directories are created as necessary.
+   *
+   * Return a normalized path to the file (with symbolic links resolved).
+   */
+  String writeFile(String pathname, String contents) {
+    new Directory(dirname(pathname)).createSync(recursive: true);
+    File file = new File(pathname);
+    file.writeAsStringSync(contents);
+    return file.resolveSymbolicLinksSync();
+  }
+}
+
+/**
+ * An error result from a server request.
+ */
+class ServerErrorMessage {
+  final Map message;
+
+  ServerErrorMessage(this.message);
+
+  dynamic get error => message['error'];
+}
+
+/**
+ * Wrapper class for Matcher which doesn't create the underlying Matcher object
+ * until it is needed.  This is necessary in order to create matchers that can
+ * refer to themselves (so that recursive data structures can be represented).
+ */
+class LazyMatcher implements Matcher {
+  /**
+   * Callback that will be used to create the matcher the first time it is
+   * needed.
+   */
+  final MatcherCreator _creator;
+
+  /**
+   * The matcher returned by [_creator], if it has already been called.
+   * Otherwise null.
+   */
+  Matcher _wrappedMatcher;
+
+  LazyMatcher(this._creator);
+
+  @override
+  Description describe(Description description) {
+    _createMatcher();
+    return _wrappedMatcher.describe(description);
+  }
+
+  @override
+  Description describeMismatch(
+      item, Description mismatchDescription, Map matchState, bool verbose) {
+    _createMatcher();
+    return _wrappedMatcher.describeMismatch(
+        item, mismatchDescription, matchState, verbose);
+  }
+
+  @override
+  bool matches(item, Map matchState) {
+    _createMatcher();
+    return _wrappedMatcher.matches(item, matchState);
+  }
+
+  /**
+   * Create the wrapped matcher object, if it hasn't been created already.
+   */
+  void _createMatcher() {
+    if (_wrappedMatcher == null) {
+      _wrappedMatcher = _creator();
+    }
+  }
+}
+
+/**
+ * Matcher that matches a String drawn from a limited set.
+ */
+class MatchesEnum extends Matcher {
+  /**
+   * Short description of the expected type.
+   */
+  final String description;
+
+  /**
+   * The set of enum values that are allowed.
+   */
+  final List<String> allowedValues;
+
+  const MatchesEnum(this.description, this.allowedValues);
+
+  @override
+  Description describe(Description description) =>
+      description.add(this.description);
+
+  @override
+  bool matches(item, Map matchState) {
+    return allowedValues.contains(item);
+  }
+}
+
+/**
+ * Matcher that matches a JSON object, with a given set of required and
+ * optional fields, and their associated types (expressed as [Matcher]s).
+ */
+class MatchesJsonObject extends _RecursiveMatcher {
+  /**
+   * Short description of the expected type.
+   */
+  final String description;
+
+  /**
+   * Fields that are required to be in the JSON object, and [Matcher]s describing
+   * their expected types.
+   */
+  final Map<String, Matcher> requiredFields;
+
+  /**
+   * Fields that are optional in the JSON object, and [Matcher]s describing
+   * their expected types.
+   */
+  final Map<String, Matcher> optionalFields;
+
+  const MatchesJsonObject(this.description, this.requiredFields,
+      {this.optionalFields});
+
+  @override
+  Description describe(Description description) =>
+      description.add(this.description);
+
+  @override
+  void populateMismatches(item, List<MismatchDescriber> mismatches) {
+    if (item is! Map) {
+      mismatches.add(simpleDescription('is not a map'));
+      return;
+    }
+    if (requiredFields != null) {
+      requiredFields.forEach((String key, Matcher valueMatcher) {
+        if (!item.containsKey(key)) {
+          mismatches.add((Description mismatchDescription) =>
+              mismatchDescription
+                  .add('is missing field ')
+                  .addDescriptionOf(key)
+                  .add(' (')
+                  .addDescriptionOf(valueMatcher)
+                  .add(')'));
+        } else {
+          _checkField(key, item[key], valueMatcher, mismatches);
+        }
+      });
+    }
+    item.forEach((key, value) {
+      if (requiredFields != null && requiredFields.containsKey(key)) {
+        // Already checked this field
+      } else if (optionalFields != null && optionalFields.containsKey(key)) {
+        _checkField(key, value, optionalFields[key], mismatches);
+      } else {
+        mismatches.add((Description mismatchDescription) => mismatchDescription
+            .add('has unexpected field ')
+            .addDescriptionOf(key));
+      }
+    });
+  }
+
+  /**
+   * Check the type of a field called [key], having value [value], using
+   * [valueMatcher].  If it doesn't match, record a closure in [mismatches]
+   * which can describe the mismatch.
+   */
+  void _checkField(String key, value, Matcher valueMatcher,
+      List<MismatchDescriber> mismatches) {
+    checkSubstructure(
+        value,
+        valueMatcher,
+        mismatches,
+        (Description description) =>
+            description.add('field ').addDescriptionOf(key));
+  }
+}
+
+/**
+ * Instances of the class [Server] manage a connection to a server process, and
+ * facilitate communication to and from the server.
+ */
+class Server {
+  /**
+   * Server process object, or null if server hasn't been started yet.
+   */
+  Process _process = null;
+
+  /**
+   * Commands that have been sent to the server but not yet acknowledged, and
+   * the [Completer] objects which should be completed when acknowledgement is
+   * received.
+   */
+  final Map<String, Completer> _pendingCommands = <String, Completer>{};
+
+  /**
+   * Number which should be used to compute the 'id' to send in the next command
+   * sent to the server.
+   */
+  int _nextId = 0;
+
+  /**
+   * Messages which have been exchanged with the server; we buffer these
+   * up until the test finishes, so that they can be examined in the debugger
+   * or printed out in response to a call to [debugStdio].
+   */
+  final List<String> _recordedStdio = <String>[];
+
+  /**
+   * True if we are currently printing out messages exchanged with the server.
+   */
+  bool _debuggingStdio = false;
+
+  /**
+   * True if we've received bad data from the server, and we are aborting the
+   * test.
+   */
+  bool _receivedBadDataFromServer = false;
+
+  /**
+   * Stopwatch that we use to generate timing information for debug output.
+   */
+  Stopwatch _time = new Stopwatch();
+
+  /**
+   * The [currentElapseTime] at which the last communication was received from the server
+   * or `null` if no communication has been received.
+   */
+  double lastCommunicationTime;
+
+  /**
+   * The current elapse time (seconds) since the server was started.
+   */
+  double get currentElapseTime => _time.elapsedTicks / _time.frequency;
+
+  /**
+   * Future that completes when the server process exits.
+   */
+  Future<int> get exitCode => _process.exitCode;
+
+  /**
+   * Print out any messages exchanged with the server.  If some messages have
+   * already been exchanged with the server, they are printed out immediately.
+   */
+  void debugStdio() {
+    if (_debuggingStdio) {
+      return;
+    }
+    _debuggingStdio = true;
+    for (String line in _recordedStdio) {
+      print(line);
+    }
+  }
+
+  /**
+   * Find the root directory of the analysis_server package by proceeding
+   * upward to the 'test' dir, and then going up one more directory.
+   */
+  String findRoot(String pathname) {
+    while (!['benchmark', 'test'].contains(basename(pathname))) {
+      String parent = dirname(pathname);
+      if (parent.length >= pathname.length) {
+        throw new Exception("Can't find root directory");
+      }
+      pathname = parent;
+    }
+    return dirname(pathname);
+  }
+
+  /**
+   * Return a future that will complete when all commands that have been sent
+   * to the server so far have been flushed to the OS buffer.
+   */
+  Future flushCommands() {
+    return _process.stdin.flush();
+  }
+
+  /**
+   * Stop the server.
+   */
+  Future kill(String reason) {
+    debugStdio();
+    _recordStdio('FORCIBLY TERMINATING PROCESS: $reason');
+    _process.kill();
+    return _process.exitCode;
+  }
+
+  /**
+   * Start listening to output from the server, and deliver notifications to
+   * [notificationProcessor].
+   */
+  void listenToOutput(NotificationProcessor notificationProcessor) {
+    _process.stdout
+        .transform((new Utf8Codec()).decoder)
+        .transform(new LineSplitter())
+        .listen((String line) {
+      lastCommunicationTime = currentElapseTime;
+      String trimmedLine = line.trim();
+      if (trimmedLine.startsWith('Observatory listening on ')) {
+        return;
+      }
+      _recordStdio('RECV: $trimmedLine');
+      var message;
+      try {
+        message = JSON.decoder.convert(trimmedLine);
+      } catch (exception) {
+        _badDataFromServer('JSON decode failure: $exception');
+        return;
+      }
+      outOfTestExpect(message, isMap);
+      Map messageAsMap = message;
+      if (messageAsMap.containsKey('id')) {
+        outOfTestExpect(messageAsMap['id'], isString);
+        String id = message['id'];
+        Completer completer = _pendingCommands[id];
+        if (completer == null) {
+          fail('Unexpected response from server: id=$id');
+        } else {
+          _pendingCommands.remove(id);
+        }
+        if (messageAsMap.containsKey('error')) {
+          completer.completeError(new ServerErrorMessage(messageAsMap));
+        } else {
+          completer.complete(messageAsMap['result']);
+        }
+        // Check that the message is well-formed.  We do this after calling
+        // completer.complete() or completer.completeError() so that we don't
+        // stall the test in the event of an error.
+        outOfTestExpect(message, isResponse);
+      } else {
+        // Message is a notification.  It should have an event and possibly
+        // params.
+        outOfTestExpect(messageAsMap, contains('event'));
+        outOfTestExpect(messageAsMap['event'], isString);
+        notificationProcessor(messageAsMap['event'], messageAsMap['params']);
+        // Check that the message is well-formed.  We do this after calling
+        // notificationController.add() so that we don't stall the test in the
+        // event of an error.
+        outOfTestExpect(message, isNotification);
+      }
+    });
+    _process.stderr
+        .transform((new Utf8Codec()).decoder)
+        .transform(new LineSplitter())
+        .listen((String line) {
+      String trimmedLine = line.trim();
+      _recordStdio('ERR:  $trimmedLine');
+      _badDataFromServer('Message received on stderr', silent: true);
+    });
+  }
+
+  /**
+   * Send a command to the server.  An 'id' will be automatically assigned.
+   * The returned [Future] will be completed when the server acknowledges the
+   * command with a response.  If the server acknowledges the command with a
+   * normal (non-error) response, the future will be completed with the 'result'
+   * field from the response.  If the server acknowledges the command with an
+   * error response, the future will be completed with an error.
+   */
+  Future send(String method, Map<String, dynamic> params) {
+    String id = '${_nextId++}';
+    Map<String, dynamic> command = <String, dynamic>{
+      'id': id,
+      'method': method
+    };
+    if (params != null) {
+      command['params'] = params;
+    }
+    Completer completer = new Completer();
+    _pendingCommands[id] = completer;
+    String line = JSON.encode(command);
+    _recordStdio('SEND: $line');
+    _process.stdin.add(UTF8.encoder.convert("$line\n"));
+    return completer.future;
+  }
+
+  /**
+   * Start the server.  If [debugServer] is `true`, the server will be started
+   * with "--debug", allowing a debugger to be attached. If [profileServer] is
+   * `true`, the server will be started with "--observe" and
+   * "--pause-isolates-on-exit", allowing the observatory to be used.
+   */
+  Future start(
+      {bool checked: true,
+      bool debugServer: false,
+      int diagnosticPort,
+      bool profileServer: false,
+      String sdkPath,
+      int servicesPort,
+      bool useAnalysisHighlight2: false}) {
+    if (_process != null) {
+      throw new Exception('Process already started');
+    }
+    _time.start();
+    String dartBinary = Platform.executable;
+    String rootDir =
+        findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
+    String serverPath = normalize(join(rootDir, 'bin', 'server.dart'));
+    List<String> arguments = [];
+    //
+    // Add VM arguments.
+    //
+    if (debugServer) {
+      arguments.add('--debug');
+    }
+    if (profileServer) {
+      if (servicesPort == null) {
+        arguments.add('--observe');
+      } else {
+        arguments.add('--observe=$servicesPort');
+      }
+      arguments.add('--pause-isolates-on-exit');
+    } else if (servicesPort != null) {
+      arguments.add('--enable-vm-service=$servicesPort');
+    }
+    if (Platform.packageRoot != null) {
+      arguments.add('--package-root=${Platform.packageRoot}');
+    }
+    if (Platform.packageConfig != null) {
+      arguments.add('--packages=${Platform.packageConfig}');
+    }
+    if (checked) {
+      arguments.add('--checked');
+    }
+    //
+    // Add the server executable.
+    //
+    arguments.add(serverPath);
+    //
+    // Add server arguments.
+    //
+    if (diagnosticPort != null) {
+      arguments.add('--port');
+      arguments.add(diagnosticPort.toString());
+    }
+    if (sdkPath != null) {
+      arguments.add('--sdk=$sdkPath');
+    }
+    if (useAnalysisHighlight2) {
+      arguments.add('--useAnalysisHighlight2');
+    }
+//    print('Launching $serverPath');
+//    print('$dartBinary ${arguments.join(' ')}');
+    return Process.start(dartBinary, arguments).then((Process process) {
+      _process = process;
+      process.exitCode.then((int code) {
+        if (code != 0) {
+          _badDataFromServer('server terminated with exit code $code');
+        }
+      });
+    });
+  }
+
+  /**
+   * Deal with bad data received from the server.
+   */
+  void _badDataFromServer(String details, {bool silent: false}) {
+    if (!silent) {
+      _recordStdio('BAD DATA FROM SERVER: $details');
+    }
+    if (_receivedBadDataFromServer) {
+      // We're already dealing with it.
+      return;
+    }
+    _receivedBadDataFromServer = true;
+    debugStdio();
+    // Give the server 1 second to continue outputting bad data before we kill
+    // the test.  This is helpful if the server has had an unhandled exception
+    // and is outputting a stacktrace, because it ensures that we see the
+    // entire stacktrace.  Use expectAsync() to prevent the test from
+    // ending during this 1 second.
+    new Future.delayed(new Duration(seconds: 1), expectAsync(() {
+      fail('Bad data received from server: $details');
+    }));
+  }
+
+  /**
+   * Record a message that was exchanged with the server, and print it out if
+   * [debugStdio] has been called.
+   */
+  void _recordStdio(String line) {
+    double elapsedTime = currentElapseTime;
+    line = "$elapsedTime: $line";
+    if (_debuggingStdio) {
+      print(line);
+    }
+    _recordedStdio.add(line);
+  }
+}
+
+/**
+ * Matcher that matches a list of objects, each of which satisfies the given
+ * matcher.
+ */
+class _ListOf extends Matcher {
+  /**
+   * Matcher which every element of the list must satisfy.
+   */
+  final Matcher elementMatcher;
+
+  /**
+   * Iterable matcher which we use to test the contents of the list.
+   */
+  final Matcher iterableMatcher;
+
+  _ListOf(elementMatcher)
+      : elementMatcher = elementMatcher,
+        iterableMatcher = everyElement(elementMatcher);
+
+  @override
+  Description describe(Description description) =>
+      description.add('List of ').addDescriptionOf(elementMatcher);
+
+  @override
+  Description describeMismatch(
+      item, Description mismatchDescription, Map matchState, bool verbose) {
+    if (item is! List) {
+      return super
+          .describeMismatch(item, mismatchDescription, matchState, verbose);
+    } else {
+      return iterableMatcher.describeMismatch(
+          item, mismatchDescription, matchState, verbose);
+    }
+  }
+
+  @override
+  bool matches(item, Map matchState) {
+    if (item is! List) {
+      return false;
+    }
+    return iterableMatcher.matches(item, matchState);
+  }
+}
+
+/**
+ * Matcher that matches a map of objects, where each key/value pair in the
+ * map satisies the given key and value matchers.
+ */
+class _MapOf extends _RecursiveMatcher {
+  /**
+   * Matcher which every key in the map must satisfy.
+   */
+  final Matcher keyMatcher;
+
+  /**
+   * Matcher which every value in the map must satisfy.
+   */
+  final Matcher valueMatcher;
+
+  _MapOf(this.keyMatcher, this.valueMatcher);
+
+  @override
+  Description describe(Description description) => description
+      .add('Map from ')
+      .addDescriptionOf(keyMatcher)
+      .add(' to ')
+      .addDescriptionOf(valueMatcher);
+
+  @override
+  void populateMismatches(item, List<MismatchDescriber> mismatches) {
+    if (item is! Map) {
+      mismatches.add(simpleDescription('is not a map'));
+      return;
+    }
+    item.forEach((key, value) {
+      checkSubstructure(
+          key,
+          keyMatcher,
+          mismatches,
+          (Description description) =>
+              description.add('key ').addDescriptionOf(key));
+      checkSubstructure(
+          value,
+          valueMatcher,
+          mismatches,
+          (Description description) =>
+              description.add('field ').addDescriptionOf(key));
+    });
+  }
+}
+
+/**
+ * Matcher that matches a union of different types, each of which is described
+ * by a matcher.
+ */
+class _OneOf extends Matcher {
+  /**
+   * Matchers for the individual choices.
+   */
+  final List<Matcher> choiceMatchers;
+
+  _OneOf(this.choiceMatchers);
+
+  @override
+  Description describe(Description description) {
+    for (int i = 0; i < choiceMatchers.length; i++) {
+      if (i != 0) {
+        if (choiceMatchers.length == 2) {
+          description = description.add(' or ');
+        } else {
+          description = description.add(', ');
+          if (i == choiceMatchers.length - 1) {
+            description = description.add('or ');
+          }
+        }
+      }
+      description = description.addDescriptionOf(choiceMatchers[i]);
+    }
+    return description;
+  }
+
+  @override
+  bool matches(item, Map matchState) {
+    for (Matcher choiceMatcher in choiceMatchers) {
+      Map subState = {};
+      if (choiceMatcher.matches(item, subState)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
+/**
+ * Base class for matchers that operate by recursing through the contents of
+ * an object.
+ */
+abstract class _RecursiveMatcher extends Matcher {
+  const _RecursiveMatcher();
+
+  /**
+   * Check the type of a substructure whose value is [item], using [matcher].
+   * If it doesn't match, record a closure in [mismatches] which can describe
+   * the mismatch.  [describeSubstructure] is used to describe which
+   * substructure did not match.
+   */
+  checkSubstructure(item, Matcher matcher, List<MismatchDescriber> mismatches,
+      Description describeSubstructure(Description)) {
+    Map subState = {};
+    if (!matcher.matches(item, subState)) {
+      mismatches.add((Description mismatchDescription) {
+        mismatchDescription = mismatchDescription.add('contains malformed ');
+        mismatchDescription = describeSubstructure(mismatchDescription);
+        mismatchDescription =
+            mismatchDescription.add(' (should be ').addDescriptionOf(matcher);
+        String subDescription = matcher
+            .describeMismatch(item, new StringDescription(), subState, false)
+            .toString();
+        if (subDescription.isNotEmpty) {
+          mismatchDescription =
+              mismatchDescription.add('; ').add(subDescription);
+        }
+        return mismatchDescription.add(')');
+      });
+    }
+  }
+
+  @override
+  Description describeMismatch(
+      item, Description mismatchDescription, Map matchState, bool verbose) {
+    List<MismatchDescriber> mismatches =
+        matchState['mismatches'] as List<MismatchDescriber>;
+    if (mismatches != null) {
+      for (int i = 0; i < mismatches.length; i++) {
+        MismatchDescriber mismatch = mismatches[i];
+        if (i > 0) {
+          if (mismatches.length == 2) {
+            mismatchDescription = mismatchDescription.add(' and ');
+          } else if (i == mismatches.length - 1) {
+            mismatchDescription = mismatchDescription.add(', and ');
+          } else {
+            mismatchDescription = mismatchDescription.add(', ');
+          }
+        }
+        mismatchDescription = mismatch(mismatchDescription);
+      }
+      return mismatchDescription;
+    } else {
+      return super
+          .describeMismatch(item, mismatchDescription, matchState, verbose);
+    }
+  }
+
+  @override
+  bool matches(item, Map matchState) {
+    List<MismatchDescriber> mismatches = <MismatchDescriber>[];
+    populateMismatches(item, mismatches);
+    if (mismatches.isEmpty) {
+      return true;
+    } else {
+      addStateInfo(matchState, {'mismatches': mismatches});
+      return false;
+    }
+  }
+
+  /**
+   * Populate [mismatches] with descriptions of all the ways in which [item]
+   * does not match.
+   */
+  void populateMismatches(item, List<MismatchDescriber> mismatches);
+
+  /**
+   * Create a [MismatchDescriber] describing a mismatch with a simple string.
+   */
+  MismatchDescriber simpleDescription(String description) =>
+      (Description mismatchDescription) {
+        mismatchDescription.add(description);
+      };
+}
diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
new file mode 100644
index 0000000..6f0b2c4
--- /dev/null
+++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
@@ -0,0 +1,1574 @@
+// 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 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".
+
+/**
+ * Matchers for data types defined in the analysis server API
+ */
+import 'package:test/test.dart';
+
+import 'integration_tests.dart';
+
+/**
+ * plugin.versionCheck params
+ *
+ * {
+ *   "byteStorePath": String
+ *   "version": String
+ * }
+ */
+final Matcher isPluginVersionCheckParams = new LazyMatcher(() => new MatchesJsonObject(
+  "plugin.versionCheck params", {
+    "byteStorePath": isString,
+    "version": isString
+  }));
+
+/**
+ * plugin.versionCheck result
+ *
+ * {
+ *   "isCompatible": bool
+ *   "name": String
+ *   "version": String
+ *   "contactInfo": optional String
+ *   "interestingFiles": List<String>
+ * }
+ */
+final Matcher isPluginVersionCheckResult = new LazyMatcher(() => new MatchesJsonObject(
+  "plugin.versionCheck result", {
+    "isCompatible": isBool,
+    "name": isString,
+    "version": isString,
+    "interestingFiles": isListOf(isString)
+  }, optionalFields: {
+    "contactInfo": isString
+  }));
+
+/**
+ * plugin.shutdown params
+ */
+final Matcher isPluginShutdownParams = isNull;
+
+/**
+ * plugin.shutdown result
+ */
+final Matcher isPluginShutdownResult = isNull;
+
+/**
+ * plugin.error params
+ *
+ * {
+ *   "isFatal": bool
+ *   "message": String
+ *   "stackTrace": String
+ * }
+ */
+final Matcher isPluginErrorParams = new LazyMatcher(() => new MatchesJsonObject(
+  "plugin.error params", {
+    "isFatal": isBool,
+    "message": isString,
+    "stackTrace": isString
+  }));
+
+/**
+ * analysis.handleWatchEvents params
+ *
+ * {
+ *   "events": List<WatchEvent>
+ * }
+ */
+final Matcher isAnalysisHandleWatchEventsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.handleWatchEvents params", {
+    "events": isListOf(isWatchEvent)
+  }));
+
+/**
+ * analysis.handleWatchEvents result
+ */
+final Matcher isAnalysisHandleWatchEventsResult = isNull;
+
+/**
+ * analysis.reanalyze params
+ *
+ * {
+ *   "roots": optional List<FilePath>
+ * }
+ */
+final Matcher isAnalysisReanalyzeParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.reanalyze params", null, optionalFields: {
+    "roots": isListOf(isFilePath)
+  }));
+
+/**
+ * analysis.reanalyze result
+ */
+final Matcher isAnalysisReanalyzeResult = isNull;
+
+/**
+ * analysis.setContextBuilderOptions params
+ *
+ * {
+ *   "options": ContextBuilderOptions
+ * }
+ */
+final Matcher isAnalysisSetContextBuilderOptionsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.setContextBuilderOptions params", {
+    "options": isContextBuilderOptions
+  }));
+
+/**
+ * analysis.setContextBuilderOptions result
+ */
+final Matcher isAnalysisSetContextBuilderOptionsResult = isNull;
+
+/**
+ * analysis.setContextRoots params
+ *
+ * {
+ *   "roots": List<ContextRoot>
+ * }
+ */
+final Matcher isAnalysisSetContextRootsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.setContextRoots params", {
+    "roots": isListOf(isContextRoot)
+  }));
+
+/**
+ * analysis.setContextRoots result
+ */
+final Matcher isAnalysisSetContextRootsResult = isNull;
+
+/**
+ * analysis.setPriorityFiles params
+ *
+ * {
+ *   "files": List<FilePath>
+ * }
+ */
+final Matcher isAnalysisSetPriorityFilesParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.setPriorityFiles params", {
+    "files": isListOf(isFilePath)
+  }));
+
+/**
+ * analysis.setPriorityFiles result
+ */
+final Matcher isAnalysisSetPriorityFilesResult = isNull;
+
+/**
+ * analysis.setSubscriptions params
+ *
+ * {
+ *   "subscriptions": Map<AnalysisService, List<FilePath>>
+ * }
+ */
+final Matcher isAnalysisSetSubscriptionsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.setSubscriptions params", {
+    "subscriptions": isMapOf(isAnalysisService, isListOf(isFilePath))
+  }));
+
+/**
+ * analysis.setSubscriptions result
+ */
+final Matcher isAnalysisSetSubscriptionsResult = isNull;
+
+/**
+ * analysis.updateContent params
+ *
+ * {
+ *   "files": Map<FilePath, AddContentOverlay | ChangeContentOverlay | RemoveContentOverlay>
+ * }
+ */
+final Matcher isAnalysisUpdateContentParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.updateContent params", {
+    "files": isMapOf(isFilePath, isOneOf([isAddContentOverlay, isChangeContentOverlay, isRemoveContentOverlay]))
+  }));
+
+/**
+ * analysis.updateContent result
+ */
+final Matcher isAnalysisUpdateContentResult = isNull;
+
+/**
+ * analysis.errors params
+ *
+ * {
+ *   "file": FilePath
+ *   "errors": List<AnalysisError>
+ * }
+ */
+final Matcher isAnalysisErrorsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.errors params", {
+    "file": isFilePath,
+    "errors": isListOf(isAnalysisError)
+  }));
+
+/**
+ * analysis.folding params
+ *
+ * {
+ *   "file": FilePath
+ *   "regions": List<FoldingRegion>
+ * }
+ */
+final Matcher isAnalysisFoldingParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.folding params", {
+    "file": isFilePath,
+    "regions": isListOf(isFoldingRegion)
+  }));
+
+/**
+ * analysis.highlights params
+ *
+ * {
+ *   "file": FilePath
+ *   "regions": List<HighlightRegion>
+ * }
+ */
+final Matcher isAnalysisHighlightsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.highlights params", {
+    "file": isFilePath,
+    "regions": isListOf(isHighlightRegion)
+  }));
+
+/**
+ * analysis.navigation params
+ *
+ * {
+ *   "file": FilePath
+ *   "regions": List<NavigationRegion>
+ *   "targets": List<NavigationTarget>
+ *   "files": List<FilePath>
+ * }
+ */
+final Matcher isAnalysisNavigationParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.navigation params", {
+    "file": isFilePath,
+    "regions": isListOf(isNavigationRegion),
+    "targets": isListOf(isNavigationTarget),
+    "files": isListOf(isFilePath)
+  }));
+
+/**
+ * analysis.occurrences params
+ *
+ * {
+ *   "file": FilePath
+ *   "occurrences": List<Occurrences>
+ * }
+ */
+final Matcher isAnalysisOccurrencesParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.occurrences params", {
+    "file": isFilePath,
+    "occurrences": isListOf(isOccurrences)
+  }));
+
+/**
+ * analysis.outline params
+ *
+ * {
+ *   "file": FilePath
+ *   "outline": List<Outline>
+ * }
+ */
+final Matcher isAnalysisOutlineParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.outline params", {
+    "file": isFilePath,
+    "outline": isListOf(isOutline)
+  }));
+
+/**
+ * completion.getSuggestions params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ * }
+ */
+final Matcher isCompletionGetSuggestionsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "completion.getSuggestions params", {
+    "file": isFilePath,
+    "offset": isInt
+  }));
+
+/**
+ * completion.getSuggestions result
+ *
+ * {
+ *   "replacementOffset": int
+ *   "replacementLength": int
+ *   "results": List<CompletionSuggestion>
+ * }
+ */
+final Matcher isCompletionGetSuggestionsResult = new LazyMatcher(() => new MatchesJsonObject(
+  "completion.getSuggestions result", {
+    "replacementOffset": isInt,
+    "replacementLength": isInt,
+    "results": isListOf(isCompletionSuggestion)
+  }));
+
+/**
+ * edit.getAssists params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ * }
+ */
+final Matcher isEditGetAssistsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getAssists params", {
+    "file": isFilePath,
+    "offset": isInt,
+    "length": isInt
+  }));
+
+/**
+ * edit.getAssists result
+ *
+ * {
+ *   "assists": List<PrioritizedSourceChange>
+ * }
+ */
+final Matcher isEditGetAssistsResult = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getAssists result", {
+    "assists": isListOf(isPrioritizedSourceChange)
+  }));
+
+/**
+ * edit.getAvailableRefactorings params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ * }
+ */
+final Matcher isEditGetAvailableRefactoringsParams = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getAvailableRefactorings params", {
+    "file": isFilePath,
+    "offset": isInt,
+    "length": isInt
+  }));
+
+/**
+ * edit.getAvailableRefactorings result
+ *
+ * {
+ *   "kinds": List<RefactoringKind>
+ * }
+ */
+final Matcher isEditGetAvailableRefactoringsResult = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getAvailableRefactorings result", {
+    "kinds": isListOf(isRefactoringKind)
+  }));
+
+/**
+ * edit.getFixes params
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ * }
+ */
+final Matcher isEditGetFixesParams = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getFixes params", {
+    "file": isFilePath,
+    "offset": isInt
+  }));
+
+/**
+ * edit.getFixes result
+ *
+ * {
+ *   "fixes": List<AnalysisErrorFixes>
+ * }
+ */
+final Matcher isEditGetFixesResult = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getFixes result", {
+    "fixes": isListOf(isAnalysisErrorFixes)
+  }));
+
+/**
+ * edit.getRefactoring params
+ *
+ * {
+ *   "kind": RefactoringKind
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ *   "validateOnly": bool
+ *   "options": optional RefactoringOptions
+ * }
+ */
+final Matcher isEditGetRefactoringParams = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getRefactoring params", {
+    "kind": isRefactoringKind,
+    "file": isFilePath,
+    "offset": isInt,
+    "length": isInt,
+    "validateOnly": isBool
+  }, optionalFields: {
+    "options": isRefactoringOptions
+  }));
+
+/**
+ * edit.getRefactoring result
+ *
+ * {
+ *   "initialProblems": List<RefactoringProblem>
+ *   "optionsProblems": List<RefactoringProblem>
+ *   "finalProblems": List<RefactoringProblem>
+ *   "feedback": optional RefactoringFeedback
+ *   "change": optional SourceChange
+ *   "potentialEdits": optional List<String>
+ * }
+ */
+final Matcher isEditGetRefactoringResult = new LazyMatcher(() => new MatchesJsonObject(
+  "edit.getRefactoring result", {
+    "initialProblems": isListOf(isRefactoringProblem),
+    "optionsProblems": isListOf(isRefactoringProblem),
+    "finalProblems": isListOf(isRefactoringProblem)
+  }, optionalFields: {
+    "feedback": isRefactoringFeedback,
+    "change": isSourceChange,
+    "potentialEdits": isListOf(isString)
+  }));
+
+/**
+ * AddContentOverlay
+ *
+ * {
+ *   "type": "add"
+ *   "content": String
+ * }
+ */
+final Matcher isAddContentOverlay = new LazyMatcher(() => new MatchesJsonObject(
+  "AddContentOverlay", {
+    "type": equals("add"),
+    "content": isString
+  }));
+
+/**
+ * AnalysisError
+ *
+ * {
+ *   "severity": AnalysisErrorSeverity
+ *   "type": AnalysisErrorType
+ *   "location": Location
+ *   "message": String
+ *   "correction": optional String
+ *   "code": String
+ *   "hasFix": optional bool
+ * }
+ */
+final Matcher isAnalysisError = new LazyMatcher(() => new MatchesJsonObject(
+  "AnalysisError", {
+    "severity": isAnalysisErrorSeverity,
+    "type": isAnalysisErrorType,
+    "location": isLocation,
+    "message": isString,
+    "code": isString
+  }, optionalFields: {
+    "correction": isString,
+    "hasFix": isBool
+  }));
+
+/**
+ * AnalysisErrorFixes
+ *
+ * {
+ *   "error": AnalysisError
+ *   "fixes": List<PrioritizedSourceChange>
+ * }
+ */
+final Matcher isAnalysisErrorFixes = new LazyMatcher(() => new MatchesJsonObject(
+  "AnalysisErrorFixes", {
+    "error": isAnalysisError,
+    "fixes": isListOf(isPrioritizedSourceChange)
+  }));
+
+/**
+ * AnalysisErrorSeverity
+ *
+ * enum {
+ *   INFO
+ *   WARNING
+ *   ERROR
+ * }
+ */
+final Matcher isAnalysisErrorSeverity = new MatchesEnum("AnalysisErrorSeverity", [
+  "INFO",
+  "WARNING",
+  "ERROR"
+]);
+
+/**
+ * AnalysisErrorType
+ *
+ * enum {
+ *   CHECKED_MODE_COMPILE_TIME_ERROR
+ *   COMPILE_TIME_ERROR
+ *   HINT
+ *   LINT
+ *   STATIC_TYPE_WARNING
+ *   STATIC_WARNING
+ *   SYNTACTIC_ERROR
+ *   TODO
+ * }
+ */
+final Matcher isAnalysisErrorType = new MatchesEnum("AnalysisErrorType", [
+  "CHECKED_MODE_COMPILE_TIME_ERROR",
+  "COMPILE_TIME_ERROR",
+  "HINT",
+  "LINT",
+  "STATIC_TYPE_WARNING",
+  "STATIC_WARNING",
+  "SYNTACTIC_ERROR",
+  "TODO"
+]);
+
+/**
+ * AnalysisService
+ *
+ * enum {
+ *   FOLDING
+ *   HIGHLIGHTS
+ *   NAVIGATION
+ *   OCCURRENCES
+ *   OUTLINE
+ * }
+ */
+final Matcher isAnalysisService = new MatchesEnum("AnalysisService", [
+  "FOLDING",
+  "HIGHLIGHTS",
+  "NAVIGATION",
+  "OCCURRENCES",
+  "OUTLINE"
+]);
+
+/**
+ * ChangeContentOverlay
+ *
+ * {
+ *   "type": "change"
+ *   "edits": List<SourceEdit>
+ * }
+ */
+final Matcher isChangeContentOverlay = new LazyMatcher(() => new MatchesJsonObject(
+  "ChangeContentOverlay", {
+    "type": equals("change"),
+    "edits": isListOf(isSourceEdit)
+  }));
+
+/**
+ * CompletionSuggestion
+ *
+ * {
+ *   "kind": CompletionSuggestionKind
+ *   "relevance": int
+ *   "completion": String
+ *   "selectionOffset": int
+ *   "selectionLength": int
+ *   "isDeprecated": bool
+ *   "isPotential": bool
+ *   "docSummary": optional String
+ *   "docComplete": optional String
+ *   "declaringType": optional String
+ *   "element": optional Element
+ *   "returnType": optional String
+ *   "parameterNames": optional List<String>
+ *   "parameterTypes": optional List<String>
+ *   "requiredParameterCount": optional int
+ *   "hasNamedParameters": optional bool
+ *   "parameterName": optional String
+ *   "parameterType": optional String
+ *   "importUri": optional String
+ * }
+ */
+final Matcher isCompletionSuggestion = new LazyMatcher(() => new MatchesJsonObject(
+  "CompletionSuggestion", {
+    "kind": isCompletionSuggestionKind,
+    "relevance": isInt,
+    "completion": isString,
+    "selectionOffset": isInt,
+    "selectionLength": isInt,
+    "isDeprecated": isBool,
+    "isPotential": isBool
+  }, optionalFields: {
+    "docSummary": isString,
+    "docComplete": isString,
+    "declaringType": isString,
+    "element": isElement,
+    "returnType": isString,
+    "parameterNames": isListOf(isString),
+    "parameterTypes": isListOf(isString),
+    "requiredParameterCount": isInt,
+    "hasNamedParameters": isBool,
+    "parameterName": isString,
+    "parameterType": isString,
+    "importUri": isString
+  }));
+
+/**
+ * CompletionSuggestionKind
+ *
+ * enum {
+ *   ARGUMENT_LIST
+ *   IMPORT
+ *   IDENTIFIER
+ *   INVOCATION
+ *   KEYWORD
+ *   NAMED_ARGUMENT
+ *   OPTIONAL_ARGUMENT
+ *   PARAMETER
+ * }
+ */
+final Matcher isCompletionSuggestionKind = new MatchesEnum("CompletionSuggestionKind", [
+  "ARGUMENT_LIST",
+  "IMPORT",
+  "IDENTIFIER",
+  "INVOCATION",
+  "KEYWORD",
+  "NAMED_ARGUMENT",
+  "OPTIONAL_ARGUMENT",
+  "PARAMETER"
+]);
+
+/**
+ * ContextBuilderOptions
+ *
+ * {
+ *   "dartSdkSummaryPath": optional String
+ *   "defaultAnalysisOptionsFilePath": optional List<String>
+ *   "declaredVariables": optional Map<String, String>
+ *   "defaultPackageFilePath": optional List<String>
+ *   "defaultPackagesDirectoryPath": optional List<String>
+ * }
+ */
+final Matcher isContextBuilderOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "ContextBuilderOptions", null, optionalFields: {
+    "dartSdkSummaryPath": isString,
+    "defaultAnalysisOptionsFilePath": isListOf(isString),
+    "declaredVariables": isMapOf(isString, isString),
+    "defaultPackageFilePath": isListOf(isString),
+    "defaultPackagesDirectoryPath": isListOf(isString)
+  }));
+
+/**
+ * ContextRoot
+ *
+ * {
+ *   "root": String
+ *   "exclude": List<String>
+ * }
+ */
+final Matcher isContextRoot = new LazyMatcher(() => new MatchesJsonObject(
+  "ContextRoot", {
+    "root": isString,
+    "exclude": isListOf(isString)
+  }));
+
+/**
+ * Element
+ *
+ * {
+ *   "kind": ElementKind
+ *   "name": String
+ *   "location": optional Location
+ *   "flags": int
+ *   "parameters": optional String
+ *   "returnType": optional String
+ *   "typeParameters": optional String
+ * }
+ */
+final Matcher isElement = new LazyMatcher(() => new MatchesJsonObject(
+  "Element", {
+    "kind": isElementKind,
+    "name": isString,
+    "flags": isInt
+  }, optionalFields: {
+    "location": isLocation,
+    "parameters": isString,
+    "returnType": isString,
+    "typeParameters": isString
+  }));
+
+/**
+ * ElementKind
+ *
+ * enum {
+ *   CLASS
+ *   CLASS_TYPE_ALIAS
+ *   COMPILATION_UNIT
+ *   CONSTRUCTOR
+ *   ENUM
+ *   ENUM_CONSTANT
+ *   FIELD
+ *   FILE
+ *   FUNCTION
+ *   FUNCTION_TYPE_ALIAS
+ *   GETTER
+ *   LABEL
+ *   LIBRARY
+ *   LOCAL_VARIABLE
+ *   METHOD
+ *   PARAMETER
+ *   PREFIX
+ *   SETTER
+ *   TOP_LEVEL_VARIABLE
+ *   TYPE_PARAMETER
+ *   UNKNOWN
+ * }
+ */
+final Matcher isElementKind = new MatchesEnum("ElementKind", [
+  "CLASS",
+  "CLASS_TYPE_ALIAS",
+  "COMPILATION_UNIT",
+  "CONSTRUCTOR",
+  "ENUM",
+  "ENUM_CONSTANT",
+  "FIELD",
+  "FILE",
+  "FUNCTION",
+  "FUNCTION_TYPE_ALIAS",
+  "GETTER",
+  "LABEL",
+  "LIBRARY",
+  "LOCAL_VARIABLE",
+  "METHOD",
+  "PARAMETER",
+  "PREFIX",
+  "SETTER",
+  "TOP_LEVEL_VARIABLE",
+  "TYPE_PARAMETER",
+  "UNKNOWN"
+]);
+
+/**
+ * FilePath
+ *
+ * String
+ */
+final Matcher isFilePath = isString;
+
+/**
+ * FoldingKind
+ *
+ * enum {
+ *   COMMENT
+ *   CLASS_MEMBER
+ *   DIRECTIVES
+ *   DOCUMENTATION_COMMENT
+ *   TOP_LEVEL_DECLARATION
+ * }
+ */
+final Matcher isFoldingKind = new MatchesEnum("FoldingKind", [
+  "COMMENT",
+  "CLASS_MEMBER",
+  "DIRECTIVES",
+  "DOCUMENTATION_COMMENT",
+  "TOP_LEVEL_DECLARATION"
+]);
+
+/**
+ * FoldingRegion
+ *
+ * {
+ *   "kind": FoldingKind
+ *   "offset": int
+ *   "length": int
+ * }
+ */
+final Matcher isFoldingRegion = new LazyMatcher(() => new MatchesJsonObject(
+  "FoldingRegion", {
+    "kind": isFoldingKind,
+    "offset": isInt,
+    "length": isInt
+  }));
+
+/**
+ * HighlightRegion
+ *
+ * {
+ *   "type": HighlightRegionType
+ *   "offset": int
+ *   "length": int
+ * }
+ */
+final Matcher isHighlightRegion = new LazyMatcher(() => new MatchesJsonObject(
+  "HighlightRegion", {
+    "type": isHighlightRegionType,
+    "offset": isInt,
+    "length": isInt
+  }));
+
+/**
+ * HighlightRegionType
+ *
+ * enum {
+ *   ANNOTATION
+ *   BUILT_IN
+ *   CLASS
+ *   COMMENT_BLOCK
+ *   COMMENT_DOCUMENTATION
+ *   COMMENT_END_OF_LINE
+ *   CONSTRUCTOR
+ *   DIRECTIVE
+ *   DYNAMIC_TYPE
+ *   DYNAMIC_LOCAL_VARIABLE_DECLARATION
+ *   DYNAMIC_LOCAL_VARIABLE_REFERENCE
+ *   DYNAMIC_PARAMETER_DECLARATION
+ *   DYNAMIC_PARAMETER_REFERENCE
+ *   ENUM
+ *   ENUM_CONSTANT
+ *   FIELD
+ *   FIELD_STATIC
+ *   FUNCTION
+ *   FUNCTION_DECLARATION
+ *   FUNCTION_TYPE_ALIAS
+ *   GETTER_DECLARATION
+ *   IDENTIFIER_DEFAULT
+ *   IMPORT_PREFIX
+ *   INSTANCE_FIELD_DECLARATION
+ *   INSTANCE_FIELD_REFERENCE
+ *   INSTANCE_GETTER_DECLARATION
+ *   INSTANCE_GETTER_REFERENCE
+ *   INSTANCE_METHOD_DECLARATION
+ *   INSTANCE_METHOD_REFERENCE
+ *   INSTANCE_SETTER_DECLARATION
+ *   INSTANCE_SETTER_REFERENCE
+ *   INVALID_STRING_ESCAPE
+ *   KEYWORD
+ *   LABEL
+ *   LIBRARY_NAME
+ *   LITERAL_BOOLEAN
+ *   LITERAL_DOUBLE
+ *   LITERAL_INTEGER
+ *   LITERAL_LIST
+ *   LITERAL_MAP
+ *   LITERAL_STRING
+ *   LOCAL_FUNCTION_DECLARATION
+ *   LOCAL_FUNCTION_REFERENCE
+ *   LOCAL_VARIABLE
+ *   LOCAL_VARIABLE_DECLARATION
+ *   LOCAL_VARIABLE_REFERENCE
+ *   METHOD
+ *   METHOD_DECLARATION
+ *   METHOD_DECLARATION_STATIC
+ *   METHOD_STATIC
+ *   PARAMETER
+ *   SETTER_DECLARATION
+ *   TOP_LEVEL_VARIABLE
+ *   PARAMETER_DECLARATION
+ *   PARAMETER_REFERENCE
+ *   STATIC_FIELD_DECLARATION
+ *   STATIC_GETTER_DECLARATION
+ *   STATIC_GETTER_REFERENCE
+ *   STATIC_METHOD_DECLARATION
+ *   STATIC_METHOD_REFERENCE
+ *   STATIC_SETTER_DECLARATION
+ *   STATIC_SETTER_REFERENCE
+ *   TOP_LEVEL_FUNCTION_DECLARATION
+ *   TOP_LEVEL_FUNCTION_REFERENCE
+ *   TOP_LEVEL_GETTER_DECLARATION
+ *   TOP_LEVEL_GETTER_REFERENCE
+ *   TOP_LEVEL_SETTER_DECLARATION
+ *   TOP_LEVEL_SETTER_REFERENCE
+ *   TOP_LEVEL_VARIABLE_DECLARATION
+ *   TYPE_NAME_DYNAMIC
+ *   TYPE_PARAMETER
+ *   UNRESOLVED_INSTANCE_MEMBER_REFERENCE
+ *   VALID_STRING_ESCAPE
+ * }
+ */
+final Matcher isHighlightRegionType = new MatchesEnum("HighlightRegionType", [
+  "ANNOTATION",
+  "BUILT_IN",
+  "CLASS",
+  "COMMENT_BLOCK",
+  "COMMENT_DOCUMENTATION",
+  "COMMENT_END_OF_LINE",
+  "CONSTRUCTOR",
+  "DIRECTIVE",
+  "DYNAMIC_TYPE",
+  "DYNAMIC_LOCAL_VARIABLE_DECLARATION",
+  "DYNAMIC_LOCAL_VARIABLE_REFERENCE",
+  "DYNAMIC_PARAMETER_DECLARATION",
+  "DYNAMIC_PARAMETER_REFERENCE",
+  "ENUM",
+  "ENUM_CONSTANT",
+  "FIELD",
+  "FIELD_STATIC",
+  "FUNCTION",
+  "FUNCTION_DECLARATION",
+  "FUNCTION_TYPE_ALIAS",
+  "GETTER_DECLARATION",
+  "IDENTIFIER_DEFAULT",
+  "IMPORT_PREFIX",
+  "INSTANCE_FIELD_DECLARATION",
+  "INSTANCE_FIELD_REFERENCE",
+  "INSTANCE_GETTER_DECLARATION",
+  "INSTANCE_GETTER_REFERENCE",
+  "INSTANCE_METHOD_DECLARATION",
+  "INSTANCE_METHOD_REFERENCE",
+  "INSTANCE_SETTER_DECLARATION",
+  "INSTANCE_SETTER_REFERENCE",
+  "INVALID_STRING_ESCAPE",
+  "KEYWORD",
+  "LABEL",
+  "LIBRARY_NAME",
+  "LITERAL_BOOLEAN",
+  "LITERAL_DOUBLE",
+  "LITERAL_INTEGER",
+  "LITERAL_LIST",
+  "LITERAL_MAP",
+  "LITERAL_STRING",
+  "LOCAL_FUNCTION_DECLARATION",
+  "LOCAL_FUNCTION_REFERENCE",
+  "LOCAL_VARIABLE",
+  "LOCAL_VARIABLE_DECLARATION",
+  "LOCAL_VARIABLE_REFERENCE",
+  "METHOD",
+  "METHOD_DECLARATION",
+  "METHOD_DECLARATION_STATIC",
+  "METHOD_STATIC",
+  "PARAMETER",
+  "SETTER_DECLARATION",
+  "TOP_LEVEL_VARIABLE",
+  "PARAMETER_DECLARATION",
+  "PARAMETER_REFERENCE",
+  "STATIC_FIELD_DECLARATION",
+  "STATIC_GETTER_DECLARATION",
+  "STATIC_GETTER_REFERENCE",
+  "STATIC_METHOD_DECLARATION",
+  "STATIC_METHOD_REFERENCE",
+  "STATIC_SETTER_DECLARATION",
+  "STATIC_SETTER_REFERENCE",
+  "TOP_LEVEL_FUNCTION_DECLARATION",
+  "TOP_LEVEL_FUNCTION_REFERENCE",
+  "TOP_LEVEL_GETTER_DECLARATION",
+  "TOP_LEVEL_GETTER_REFERENCE",
+  "TOP_LEVEL_SETTER_DECLARATION",
+  "TOP_LEVEL_SETTER_REFERENCE",
+  "TOP_LEVEL_VARIABLE_DECLARATION",
+  "TYPE_NAME_DYNAMIC",
+  "TYPE_PARAMETER",
+  "UNRESOLVED_INSTANCE_MEMBER_REFERENCE",
+  "VALID_STRING_ESCAPE"
+]);
+
+/**
+ * LinkedEditGroup
+ *
+ * {
+ *   "positions": List<Position>
+ *   "length": int
+ *   "suggestions": List<LinkedEditSuggestion>
+ * }
+ */
+final Matcher isLinkedEditGroup = new LazyMatcher(() => new MatchesJsonObject(
+  "LinkedEditGroup", {
+    "positions": isListOf(isPosition),
+    "length": isInt,
+    "suggestions": isListOf(isLinkedEditSuggestion)
+  }));
+
+/**
+ * LinkedEditSuggestion
+ *
+ * {
+ *   "value": String
+ *   "kind": LinkedEditSuggestionKind
+ * }
+ */
+final Matcher isLinkedEditSuggestion = new LazyMatcher(() => new MatchesJsonObject(
+  "LinkedEditSuggestion", {
+    "value": isString,
+    "kind": isLinkedEditSuggestionKind
+  }));
+
+/**
+ * LinkedEditSuggestionKind
+ *
+ * enum {
+ *   METHOD
+ *   PARAMETER
+ *   TYPE
+ *   VARIABLE
+ * }
+ */
+final Matcher isLinkedEditSuggestionKind = new MatchesEnum("LinkedEditSuggestionKind", [
+  "METHOD",
+  "PARAMETER",
+  "TYPE",
+  "VARIABLE"
+]);
+
+/**
+ * Location
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ *   "length": int
+ *   "startLine": int
+ *   "startColumn": int
+ * }
+ */
+final Matcher isLocation = new LazyMatcher(() => new MatchesJsonObject(
+  "Location", {
+    "file": isFilePath,
+    "offset": isInt,
+    "length": isInt,
+    "startLine": isInt,
+    "startColumn": isInt
+  }));
+
+/**
+ * NavigationRegion
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "targets": List<int>
+ * }
+ */
+final Matcher isNavigationRegion = new LazyMatcher(() => new MatchesJsonObject(
+  "NavigationRegion", {
+    "offset": isInt,
+    "length": isInt,
+    "targets": isListOf(isInt)
+  }));
+
+/**
+ * NavigationTarget
+ *
+ * {
+ *   "kind": ElementKind
+ *   "fileIndex": int
+ *   "offset": int
+ *   "length": int
+ *   "startLine": int
+ *   "startColumn": int
+ * }
+ */
+final Matcher isNavigationTarget = new LazyMatcher(() => new MatchesJsonObject(
+  "NavigationTarget", {
+    "kind": isElementKind,
+    "fileIndex": isInt,
+    "offset": isInt,
+    "length": isInt,
+    "startLine": isInt,
+    "startColumn": isInt
+  }));
+
+/**
+ * Occurrences
+ *
+ * {
+ *   "element": Element
+ *   "offsets": List<int>
+ *   "length": int
+ * }
+ */
+final Matcher isOccurrences = new LazyMatcher(() => new MatchesJsonObject(
+  "Occurrences", {
+    "element": isElement,
+    "offsets": isListOf(isInt),
+    "length": isInt
+  }));
+
+/**
+ * Outline
+ *
+ * {
+ *   "element": Element
+ *   "offset": int
+ *   "length": int
+ *   "children": optional List<Outline>
+ * }
+ */
+final Matcher isOutline = new LazyMatcher(() => new MatchesJsonObject(
+  "Outline", {
+    "element": isElement,
+    "offset": isInt,
+    "length": isInt
+  }, optionalFields: {
+    "children": isListOf(isOutline)
+  }));
+
+/**
+ * Position
+ *
+ * {
+ *   "file": FilePath
+ *   "offset": int
+ * }
+ */
+final Matcher isPosition = new LazyMatcher(() => new MatchesJsonObject(
+  "Position", {
+    "file": isFilePath,
+    "offset": isInt
+  }));
+
+/**
+ * PrioritizedSourceChange
+ *
+ * {
+ *   "priority": int
+ *   "change": SourceChange
+ * }
+ */
+final Matcher isPrioritizedSourceChange = new LazyMatcher(() => new MatchesJsonObject(
+  "PrioritizedSourceChange", {
+    "priority": isInt,
+    "change": isSourceChange
+  }));
+
+/**
+ * RefactoringFeedback
+ *
+ * {
+ * }
+ */
+final Matcher isRefactoringFeedback = new LazyMatcher(() => new MatchesJsonObject(
+  "RefactoringFeedback", null));
+
+/**
+ * RefactoringKind
+ *
+ * enum {
+ *   CONVERT_GETTER_TO_METHOD
+ *   CONVERT_METHOD_TO_GETTER
+ *   EXTRACT_LOCAL_VARIABLE
+ *   EXTRACT_METHOD
+ *   INLINE_LOCAL_VARIABLE
+ *   INLINE_METHOD
+ *   MOVE_FILE
+ *   RENAME
+ *   SORT_MEMBERS
+ * }
+ */
+final Matcher isRefactoringKind = new MatchesEnum("RefactoringKind", [
+  "CONVERT_GETTER_TO_METHOD",
+  "CONVERT_METHOD_TO_GETTER",
+  "EXTRACT_LOCAL_VARIABLE",
+  "EXTRACT_METHOD",
+  "INLINE_LOCAL_VARIABLE",
+  "INLINE_METHOD",
+  "MOVE_FILE",
+  "RENAME",
+  "SORT_MEMBERS"
+]);
+
+/**
+ * RefactoringMethodParameter
+ *
+ * {
+ *   "id": optional String
+ *   "kind": RefactoringMethodParameterKind
+ *   "type": String
+ *   "name": String
+ *   "parameters": optional String
+ * }
+ */
+final Matcher isRefactoringMethodParameter = new LazyMatcher(() => new MatchesJsonObject(
+  "RefactoringMethodParameter", {
+    "kind": isRefactoringMethodParameterKind,
+    "type": isString,
+    "name": isString
+  }, optionalFields: {
+    "id": isString,
+    "parameters": isString
+  }));
+
+/**
+ * RefactoringOptions
+ *
+ * {
+ * }
+ */
+final Matcher isRefactoringOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "RefactoringOptions", null));
+
+/**
+ * RefactoringMethodParameterKind
+ *
+ * enum {
+ *   REQUIRED
+ *   POSITIONAL
+ *   NAMED
+ * }
+ */
+final Matcher isRefactoringMethodParameterKind = new MatchesEnum("RefactoringMethodParameterKind", [
+  "REQUIRED",
+  "POSITIONAL",
+  "NAMED"
+]);
+
+/**
+ * RefactoringProblem
+ *
+ * {
+ *   "severity": RefactoringProblemSeverity
+ *   "message": String
+ *   "location": optional Location
+ * }
+ */
+final Matcher isRefactoringProblem = new LazyMatcher(() => new MatchesJsonObject(
+  "RefactoringProblem", {
+    "severity": isRefactoringProblemSeverity,
+    "message": isString
+  }, optionalFields: {
+    "location": isLocation
+  }));
+
+/**
+ * RefactoringProblemSeverity
+ *
+ * enum {
+ *   INFO
+ *   WARNING
+ *   ERROR
+ *   FATAL
+ * }
+ */
+final Matcher isRefactoringProblemSeverity = new MatchesEnum("RefactoringProblemSeverity", [
+  "INFO",
+  "WARNING",
+  "ERROR",
+  "FATAL"
+]);
+
+/**
+ * RemoveContentOverlay
+ *
+ * {
+ *   "type": "remove"
+ * }
+ */
+final Matcher isRemoveContentOverlay = new LazyMatcher(() => new MatchesJsonObject(
+  "RemoveContentOverlay", {
+    "type": equals("remove")
+  }));
+
+/**
+ * RequestError
+ *
+ * {
+ *   "code": RequestErrorCode
+ *   "message": String
+ *   "stackTrace": optional String
+ * }
+ */
+final Matcher isRequestError = new LazyMatcher(() => new MatchesJsonObject(
+  "RequestError", {
+    "code": isRequestErrorCode,
+    "message": isString
+  }, optionalFields: {
+    "stackTrace": isString
+  }));
+
+/**
+ * RequestErrorCode
+ *
+ * enum {
+ *   INVALID_OVERLAY_CHANGE
+ *   INVALID_PARAMETER
+ *   PLUGIN_ERROR
+ *   UNKNOWN_REQUEST
+ * }
+ */
+final Matcher isRequestErrorCode = new MatchesEnum("RequestErrorCode", [
+  "INVALID_OVERLAY_CHANGE",
+  "INVALID_PARAMETER",
+  "PLUGIN_ERROR",
+  "UNKNOWN_REQUEST"
+]);
+
+/**
+ * SourceChange
+ *
+ * {
+ *   "message": String
+ *   "edits": List<SourceFileEdit>
+ *   "linkedEditGroups": List<LinkedEditGroup>
+ *   "selection": optional Position
+ * }
+ */
+final Matcher isSourceChange = new LazyMatcher(() => new MatchesJsonObject(
+  "SourceChange", {
+    "message": isString,
+    "edits": isListOf(isSourceFileEdit),
+    "linkedEditGroups": isListOf(isLinkedEditGroup)
+  }, optionalFields: {
+    "selection": isPosition
+  }));
+
+/**
+ * SourceEdit
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "replacement": String
+ *   "id": optional String
+ * }
+ */
+final Matcher isSourceEdit = new LazyMatcher(() => new MatchesJsonObject(
+  "SourceEdit", {
+    "offset": isInt,
+    "length": isInt,
+    "replacement": isString
+  }, optionalFields: {
+    "id": isString
+  }));
+
+/**
+ * SourceFileEdit
+ *
+ * {
+ *   "file": FilePath
+ *   "fileStamp": long
+ *   "edits": List<SourceEdit>
+ * }
+ */
+final Matcher isSourceFileEdit = new LazyMatcher(() => new MatchesJsonObject(
+  "SourceFileEdit", {
+    "file": isFilePath,
+    "fileStamp": isInt,
+    "edits": isListOf(isSourceEdit)
+  }));
+
+/**
+ * WatchEvent
+ *
+ * {
+ *   "type": WatchEventType
+ *   "path": String
+ * }
+ */
+final Matcher isWatchEvent = new LazyMatcher(() => new MatchesJsonObject(
+  "WatchEvent", {
+    "type": isWatchEventType,
+    "path": isString
+  }));
+
+/**
+ * WatchEventType
+ *
+ * enum {
+ *   ADD
+ *   MODIFY
+ *   REMOVE
+ * }
+ */
+final Matcher isWatchEventType = new MatchesEnum("WatchEventType", [
+  "ADD",
+  "MODIFY",
+  "REMOVE"
+]);
+
+/**
+ * convertGetterToMethod feedback
+ */
+final Matcher isConvertGetterToMethodFeedback = isNull;
+
+/**
+ * convertGetterToMethod options
+ */
+final Matcher isConvertGetterToMethodOptions = isNull;
+
+/**
+ * convertMethodToGetter feedback
+ */
+final Matcher isConvertMethodToGetterFeedback = isNull;
+
+/**
+ * convertMethodToGetter options
+ */
+final Matcher isConvertMethodToGetterOptions = isNull;
+
+/**
+ * extractLocalVariable feedback
+ *
+ * {
+ *   "coveringExpressionOffsets": optional List<int>
+ *   "coveringExpressionLengths": optional List<int>
+ *   "names": List<String>
+ *   "offsets": List<int>
+ *   "lengths": List<int>
+ * }
+ */
+final Matcher isExtractLocalVariableFeedback = new LazyMatcher(() => new MatchesJsonObject(
+  "extractLocalVariable feedback", {
+    "names": isListOf(isString),
+    "offsets": isListOf(isInt),
+    "lengths": isListOf(isInt)
+  }, optionalFields: {
+    "coveringExpressionOffsets": isListOf(isInt),
+    "coveringExpressionLengths": isListOf(isInt)
+  }));
+
+/**
+ * extractLocalVariable options
+ *
+ * {
+ *   "name": String
+ *   "extractAll": bool
+ * }
+ */
+final Matcher isExtractLocalVariableOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "extractLocalVariable options", {
+    "name": isString,
+    "extractAll": isBool
+  }));
+
+/**
+ * extractMethod feedback
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "returnType": String
+ *   "names": List<String>
+ *   "canCreateGetter": bool
+ *   "parameters": List<RefactoringMethodParameter>
+ *   "offsets": List<int>
+ *   "lengths": List<int>
+ * }
+ */
+final Matcher isExtractMethodFeedback = new LazyMatcher(() => new MatchesJsonObject(
+  "extractMethod feedback", {
+    "offset": isInt,
+    "length": isInt,
+    "returnType": isString,
+    "names": isListOf(isString),
+    "canCreateGetter": isBool,
+    "parameters": isListOf(isRefactoringMethodParameter),
+    "offsets": isListOf(isInt),
+    "lengths": isListOf(isInt)
+  }));
+
+/**
+ * extractMethod options
+ *
+ * {
+ *   "returnType": String
+ *   "createGetter": bool
+ *   "name": String
+ *   "parameters": List<RefactoringMethodParameter>
+ *   "extractAll": bool
+ * }
+ */
+final Matcher isExtractMethodOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "extractMethod options", {
+    "returnType": isString,
+    "createGetter": isBool,
+    "name": isString,
+    "parameters": isListOf(isRefactoringMethodParameter),
+    "extractAll": isBool
+  }));
+
+/**
+ * inlineLocalVariable feedback
+ *
+ * {
+ *   "name": String
+ *   "occurrences": int
+ * }
+ */
+final Matcher isInlineLocalVariableFeedback = new LazyMatcher(() => new MatchesJsonObject(
+  "inlineLocalVariable feedback", {
+    "name": isString,
+    "occurrences": isInt
+  }));
+
+/**
+ * inlineLocalVariable options
+ */
+final Matcher isInlineLocalVariableOptions = isNull;
+
+/**
+ * inlineMethod feedback
+ *
+ * {
+ *   "className": optional String
+ *   "methodName": String
+ *   "isDeclaration": bool
+ * }
+ */
+final Matcher isInlineMethodFeedback = new LazyMatcher(() => new MatchesJsonObject(
+  "inlineMethod feedback", {
+    "methodName": isString,
+    "isDeclaration": isBool
+  }, optionalFields: {
+    "className": isString
+  }));
+
+/**
+ * inlineMethod options
+ *
+ * {
+ *   "deleteSource": bool
+ *   "inlineAll": bool
+ * }
+ */
+final Matcher isInlineMethodOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "inlineMethod options", {
+    "deleteSource": isBool,
+    "inlineAll": isBool
+  }));
+
+/**
+ * moveFile feedback
+ */
+final Matcher isMoveFileFeedback = isNull;
+
+/**
+ * moveFile options
+ *
+ * {
+ *   "newFile": FilePath
+ * }
+ */
+final Matcher isMoveFileOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "moveFile options", {
+    "newFile": isFilePath
+  }));
+
+/**
+ * rename feedback
+ *
+ * {
+ *   "offset": int
+ *   "length": int
+ *   "elementKindName": String
+ *   "oldName": String
+ * }
+ */
+final Matcher isRenameFeedback = new LazyMatcher(() => new MatchesJsonObject(
+  "rename feedback", {
+    "offset": isInt,
+    "length": isInt,
+    "elementKindName": isString,
+    "oldName": isString
+  }));
+
+/**
+ * rename options
+ *
+ * {
+ *   "newName": String
+ * }
+ */
+final Matcher isRenameOptions = new LazyMatcher(() => new MatchesJsonObject(
+  "rename options", {
+    "newName": isString
+  }));
+
diff --git a/pkg/analyzer_plugin/test/src/channel/isolate_channel_test.dart b/pkg/analyzer_plugin/test/src/channel/isolate_channel_test.dart
new file mode 100644
index 0000000..3334780
--- /dev/null
+++ b/pkg/analyzer_plugin/test/src/channel/isolate_channel_test.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:analyzer_plugin/protocol/protocol.dart';
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/src/channel/isolate_channel.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+  defineReflectiveTests(PluginIsolateChannelTest);
+}
+
+@reflectiveTest
+class PluginIsolateChannelTest {
+  TestSendPort sendPort;
+  PluginIsolateChannel channel;
+
+  void setUp() {
+    sendPort = new TestSendPort();
+    channel = new PluginIsolateChannel(sendPort);
+  }
+
+  void tearDown() {
+    // If the test doesn't listen to the channel, then close will not cancel the
+    // subscription and the process will not terminate.
+    try {
+      channel.listen((request) {});
+    } catch (exception) {
+      // Ignore the exception if the test has already registered a listener.
+    }
+    channel.close();
+  }
+
+  @failingTest
+  Future<Null> test_close() async {
+    bool done = false;
+    channel.listen((Request request) {}, onDone: () {
+      done = true;
+    });
+    channel.close();
+    // TODO(brianwilkerson) Figure out how to wait until the handler has been
+    // called.
+    await _pumpEventQueue();
+    expect(done, isTrue);
+  }
+
+  Future<Null> test_listen() async {
+    Request sentRequest = new PluginShutdownParams().toRequest('5');
+    Request receivedRequest;
+    channel.listen((Request request) {
+      receivedRequest = request;
+    });
+    sendPort.receivePort.send(sentRequest.toJson());
+    await _pumpEventQueue(1);
+    expect(receivedRequest, sentRequest);
+  }
+
+  void test_sendNotification() {
+    Notification notification =
+        new PluginErrorParams(false, '', '').toNotification();
+    channel.sendNotification(notification);
+    expect(sendPort.sentMessages, hasLength(1));
+    expect(sendPort.sentMessages[0], notification.toJson());
+  }
+
+  void test_sendResponse() {
+    Response response = new PluginShutdownResult().toResponse('3');
+    channel.sendResponse(response);
+    expect(sendPort.sentMessages, hasLength(1));
+    expect(sendPort.sentMessages[0], response.toJson());
+  }
+
+  /**
+   * Returns a [Future] that completes after pumping the event queue [times]
+   * times. By default, this should pump the event queue enough times to allow
+   * any code to run, as long as it's not waiting on some external event.
+   */
+  Future<Null> _pumpEventQueue([int times = 5000]) {
+    if (times == 0) return new Future.value();
+    // We use a delayed future to allow microtask events to finish. The
+    // Future.value or Future() constructors use scheduleMicrotask themselves and
+    // would therefore not wait for microtask callbacks that are scheduled after
+    // invoking this method.
+    return new Future.delayed(Duration.ZERO, () => _pumpEventQueue(times - 1));
+  }
+}
+
+/**
+ * A send port used in tests.
+ */
+class TestSendPort implements SendPort {
+  /**
+   * The receive port used to receive messages from the server.
+   */
+  SendPort receivePort;
+
+  /**
+   * The messages sent to the server.
+   */
+  List<Object> sentMessages = <Object>[];
+
+  @override
+  void send(message) {
+    if (receivePort == null) {
+      if (message is SendPort) {
+        receivePort = message;
+      } else {
+        fail('Did not receive a receive port as the first communication.');
+      }
+    } else {
+      sentMessages.add(message);
+    }
+  }
+}
diff --git a/pkg/analyzer_plugin/test/src/channel/test_all.dart b/pkg/analyzer_plugin/test/src/channel/test_all.dart
new file mode 100644
index 0000000..45836df
--- /dev/null
+++ b/pkg/analyzer_plugin/test/src/channel/test_all.dart
@@ -0,0 +1,13 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'isolate_channel_test.dart' as isolate_channel_test;
+
+main() {
+  defineReflectiveSuite(() {
+    isolate_channel_test.main();
+  }, name: 'channel');
+}
diff --git a/pkg/analyzer_plugin/test/src/test_all.dart b/pkg/analyzer_plugin/test/src/test_all.dart
new file mode 100644
index 0000000..59b5c31
--- /dev/null
+++ b/pkg/analyzer_plugin/test/src/test_all.dart
@@ -0,0 +1,13 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'channel/test_all.dart' as channel;
+
+main() {
+  defineReflectiveSuite(() {
+    channel.main();
+  }, name: 'src');
+}
diff --git a/pkg/analyzer_plugin/test/test_all.dart b/pkg/analyzer_plugin/test/test_all.dart
new file mode 100644
index 0000000..9b9fa63
--- /dev/null
+++ b/pkg/analyzer_plugin/test/test_all.dart
@@ -0,0 +1,15 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'src/test_all.dart' as src;
+import 'utilities/test_all.dart' as utilities;
+
+main() {
+  defineReflectiveSuite(() {
+    src.main();
+    utilities.main();
+  }, name: 'analyzer_plugin');
+}
diff --git a/pkg/analyzer_plugin/test/utilities/subscription_manager_test.dart b/pkg/analyzer_plugin/test/utilities/subscription_manager_test.dart
new file mode 100644
index 0000000..ef8f422
--- /dev/null
+++ b/pkg/analyzer_plugin/test/utilities/subscription_manager_test.dart
@@ -0,0 +1,38 @@
+// 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:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/utilities/subscription_manager.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+  defineReflectiveTests(SubscriptionManagerTest);
+}
+
+@reflectiveTest
+class SubscriptionManagerTest {
+  SubscriptionManager manager = new SubscriptionManager();
+
+  test_servicesForFile() {
+    expect(manager.servicesForFile('/project/lib/test.dart'), hasLength(0));
+  }
+
+  test_setSubscriptions() {
+    manager.setSubscriptions({
+      AnalysisService.HIGHLIGHTS: [
+        '/project/lib/foo.dart',
+        '/project/lib/bar.dart'
+      ],
+      AnalysisService.NAVIGATION: ['/project/lib/foo.dart']
+    });
+    expect(manager.servicesForFile('/project/lib/test.dart'), hasLength(0));
+    expect(manager.servicesForFile('/project/lib/bar.dart'),
+        unorderedEquals([AnalysisService.HIGHLIGHTS]));
+    expect(
+        manager.servicesForFile('/project/lib/foo.dart'),
+        unorderedEquals(
+            [AnalysisService.HIGHLIGHTS, AnalysisService.NAVIGATION]));
+  }
+}
diff --git a/pkg/analyzer_plugin/test/utilities/test_all.dart b/pkg/analyzer_plugin/test/utilities/test_all.dart
new file mode 100644
index 0000000..0a87c37
--- /dev/null
+++ b/pkg/analyzer_plugin/test/utilities/test_all.dart
@@ -0,0 +1,13 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'subscription_manager_test.dart' as subscription_manager_test;
+
+main() {
+  defineReflectiveSuite(() {
+    subscription_manager_test.main();
+  }, name: 'utilities');
+}
diff --git a/pkg/analyzer_plugin/tool/spec/api.dart b/pkg/analyzer_plugin/tool/spec/api.dart
new file mode 100644
index 0000000..0c73c88
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/api.dart
@@ -0,0 +1,514 @@
+// 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.
+
+/**
+ * Data structures representing an API definition, and visitor base classes
+ * for visiting those data structures.
+ */
+import 'dart:collection';
+
+import 'package:html/dom.dart' as dom;
+
+/**
+ * Toplevel container for the API.
+ */
+class Api extends ApiNode {
+  final String version;
+  final List<Domain> domains;
+  final Types types;
+  final Refactorings refactorings;
+
+  Api(this.version, this.domains, this.types, this.refactorings,
+      dom.Element html,
+      {bool experimental})
+      : super(html, experimental);
+}
+
+/**
+ * Base class for objects in the API model.
+ */
+class ApiNode {
+  /**
+   * A flag to indicate if this API is experimental.
+   */
+  final bool experimental;
+
+  /**
+   * Html element representing this part of the API.
+   */
+  final dom.Element html;
+
+  ApiNode(this.html, bool experimental)
+      : this.experimental = experimental ?? false;
+}
+
+/**
+ * Base class for visiting the API definition.
+ */
+abstract class ApiVisitor<T> {
+  /**
+   * Dispatch the given [type] to the visitor.
+   */
+  T visitTypeDecl(TypeDecl type) => type.accept(this) as T;
+  T visitTypeEnum(TypeEnum typeEnum);
+  T visitTypeList(TypeList typeList);
+  T visitTypeMap(TypeMap typeMap);
+  T visitTypeObject(TypeObject typeObject);
+  T visitTypeReference(TypeReference typeReference);
+
+  T visitTypeUnion(TypeUnion typeUnion);
+}
+
+/**
+ * Definition of a single domain.
+ */
+class Domain extends ApiNode {
+  final String name;
+  final List<Request> requests;
+  final List<Notification> notifications;
+
+  Domain(this.name, this.requests, this.notifications, dom.Element html,
+      {bool experimental})
+      : super(html, experimental);
+}
+
+/**
+ * API visitor that visits the entire API hierarchically by default.
+ */
+class HierarchicalApiVisitor extends ApiVisitor {
+  /**
+   * The API to visit.
+   */
+  final Api api;
+
+  HierarchicalApiVisitor(this.api);
+
+  /**
+   * If [type] is a [TypeReference] that is defined in the API, follow the
+   * chain until a non-[TypeReference] is found, if possible.
+   *
+   * If it is not possible (because the chain ends with a [TypeReference] that
+   * is not defined in the API), then that final [TypeReference] is returned.
+   */
+  TypeDecl resolveTypeReferenceChain(TypeDecl type) {
+    while (type is TypeReference && api.types.containsKey(type.typeName)) {
+      type = api.types[(type as TypeReference).typeName].type;
+    }
+    return type;
+  }
+
+  void visitApi() {
+    api.domains.forEach(visitDomain);
+    visitTypes(api.types);
+    visitRefactorings(api.refactorings);
+  }
+
+  void visitDomain(Domain domain) {
+    domain.requests.forEach(visitRequest);
+    domain.notifications.forEach(visitNotification);
+  }
+
+  void visitNotification(Notification notification) {
+    if (notification.params != null) {
+      visitTypeDecl(notification.params);
+    }
+  }
+
+  void visitRefactoring(Refactoring refactoring) {
+    if (refactoring.feedback != null) {
+      visitTypeDecl(refactoring.feedback);
+    }
+    if (refactoring.options != null) {
+      visitTypeDecl(refactoring.options);
+    }
+  }
+
+  void visitRefactorings(Refactorings refactorings) {
+    refactorings?.forEach(visitRefactoring);
+  }
+
+  void visitRequest(Request request) {
+    if (request.params != null) {
+      visitTypeDecl(request.params);
+    }
+    if (request.result != null) {
+      visitTypeDecl(request.result);
+    }
+  }
+
+  void visitTypeDefinition(TypeDefinition typeDefinition) {
+    visitTypeDecl(typeDefinition.type);
+  }
+
+  @override
+  void visitTypeEnum(TypeEnum typeEnum) {
+    typeEnum.values.forEach(visitTypeEnumValue);
+  }
+
+  void visitTypeEnumValue(TypeEnumValue typeEnumValue) {}
+
+  @override
+  void visitTypeList(TypeList typeList) {
+    visitTypeDecl(typeList.itemType);
+  }
+
+  @override
+  void visitTypeMap(TypeMap typeMap) {
+    visitTypeDecl(typeMap.keyType);
+    visitTypeDecl(typeMap.valueType);
+  }
+
+  @override
+  void visitTypeObject(TypeObject typeObject) {
+    typeObject.fields.forEach(visitTypeObjectField);
+  }
+
+  void visitTypeObjectField(TypeObjectField typeObjectField) {
+    visitTypeDecl(typeObjectField.type);
+  }
+
+  @override
+  void visitTypeReference(TypeReference typeReference) {}
+
+  void visitTypes(Types types) {
+    types.forEach(visitTypeDefinition);
+  }
+
+  @override
+  void visitTypeUnion(TypeUnion typeUnion) {
+    typeUnion.choices.forEach(visitTypeDecl);
+  }
+}
+
+/**
+ * Description of a notification method.
+ */
+class Notification extends ApiNode {
+  /**
+   * Name of the domain enclosing this request.
+   */
+  final String domainName;
+
+  /**
+   * Name of the notification, without the domain prefix.
+   */
+  final String event;
+
+  /**
+   * Type of the object associated with the "params" key in the notification
+   * object, or null if the notification has no parameters.
+   */
+  final TypeObject params;
+
+  Notification(this.domainName, this.event, this.params, dom.Element html,
+      {bool experimental})
+      : super(html, experimental);
+
+  /**
+   * Get the name of the notification, including the domain prefix.
+   */
+  String get longEvent => '$domainName.$event';
+
+  /**
+   * Get the full type of the notification object, including the common "id"
+   * and "error" fields.
+   */
+  TypeDecl get notificationType {
+    List<TypeObjectField> fields = [
+      new TypeObjectField('event', new TypeReference('String', null), null,
+          value: '$domainName.$event')
+    ];
+    if (params != null) {
+      fields.add(new TypeObjectField('params', params, null));
+    }
+    return new TypeObject(fields, null);
+  }
+}
+
+/**
+ * Description of a single refactoring.
+ */
+class Refactoring extends ApiNode {
+  /**
+   * Name of the refactoring.  This should match one of the values allowed for
+   * RefactoringKind.
+   */
+  final String kind;
+
+  /**
+   * Type of the refactoring feedback, or null if the refactoring has no
+   * feedback.
+   */
+  final TypeObject feedback;
+
+  /**
+   * Type of the refactoring options, or null if the refactoring has no options.
+   */
+  final TypeObject options;
+
+  Refactoring(this.kind, this.feedback, this.options, dom.Element html,
+      {bool experimental})
+      : super(html, experimental);
+}
+
+/**
+ * A collection of refactoring definitions.
+ */
+class Refactorings extends ApiNode with IterableMixin<Refactoring> {
+  final List<Refactoring> refactorings;
+
+  Refactorings(this.refactorings, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  Iterator<Refactoring> get iterator => refactorings.iterator;
+}
+
+/**
+ * Description of a request method.
+ */
+class Request extends ApiNode {
+  /**
+   * Name of the domain enclosing this request.
+   */
+  final String domainName;
+
+  /**
+   * Name of the request, without the domain prefix.
+   */
+  final String method;
+
+  /**
+   * Type of the object associated with the "params" key in the request object,
+   * or null if the request has no parameters.
+   */
+  final TypeObject params;
+
+  /**
+   * Type of the object associated with the "result" key in the response object,
+   * or null if the response has no results.
+   */
+  final TypeObject result;
+
+  Request(
+      this.domainName, this.method, this.params, this.result, dom.Element html,
+      {bool experimental})
+      : super(html, experimental);
+
+  /**
+   * Get the name of the request, including the domain prefix.
+   */
+  String get longMethod => '$domainName.$method';
+
+  /**
+   * Get the full type of the request object, including the common "id" and
+   * "method" fields.
+   */
+  TypeDecl get requestType {
+    List<TypeObjectField> fields = [
+      new TypeObjectField('id', new TypeReference('String', null), null),
+      new TypeObjectField('method', new TypeReference('String', null), null,
+          value: '$domainName.$method')
+    ];
+    if (params != null) {
+      fields.add(new TypeObjectField('params', params, null));
+    }
+    return new TypeObject(fields, null);
+  }
+
+  /**
+   * Get the full type of the response object, including the common "id" and
+   * "error" fields.
+   */
+  TypeDecl get responseType {
+    List<TypeObjectField> fields = [
+      new TypeObjectField('id', new TypeReference('String', null), null),
+      new TypeObjectField(
+          'error', new TypeReference('RequestError', null), null,
+          optional: true)
+    ];
+    if (result != null) {
+      fields.add(new TypeObjectField('result', result, null));
+    }
+    return new TypeObject(fields, null);
+  }
+}
+
+/**
+ * Base class for all possible types.
+ */
+abstract class TypeDecl extends ApiNode {
+  TypeDecl(dom.Element html, bool experimental) : super(html, experimental);
+
+  accept(ApiVisitor visitor);
+}
+
+/**
+ * Description of a named type definition.
+ */
+class TypeDefinition extends ApiNode {
+  final String name;
+  final TypeDecl type;
+
+  TypeDefinition(this.name, this.type, dom.Element html, {bool experimental})
+      : super(html, experimental);
+}
+
+/**
+ * Type of an enum.  We represent enums in JSON as strings, so this type
+ * declaration simply lists the allowed values.
+ */
+class TypeEnum extends TypeDecl {
+  final List<TypeEnumValue> values;
+
+  TypeEnum(this.values, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  accept(ApiVisitor visitor) => visitor.visitTypeEnum(this);
+}
+
+/**
+ * Description of a single allowed value for an enum.
+ */
+class TypeEnumValue extends ApiNode {
+  final String value;
+
+  TypeEnumValue(this.value, dom.Element html, {bool experimental})
+      : super(html, experimental);
+}
+
+/**
+ * Type of a JSON list.
+ */
+class TypeList extends TypeDecl {
+  final TypeDecl itemType;
+
+  TypeList(this.itemType, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  accept(ApiVisitor visitor) => visitor.visitTypeList(this);
+}
+
+/**
+ * Type of a JSON map.
+ */
+class TypeMap extends TypeDecl {
+  /**
+   * Type of map keys.  Note that since JSON map keys must always be strings,
+   * this must either be a [TypeReference] for [String], or a [TypeReference]
+   * to a type which is defined in the API as an enum or a synonym for [String].
+   */
+  final TypeReference keyType;
+
+  /**
+   * Type of map values.
+   */
+  final TypeDecl valueType;
+
+  TypeMap(this.keyType, this.valueType, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  accept(ApiVisitor visitor) => visitor.visitTypeMap(this);
+}
+
+/**
+ * Type of a JSON object with specified fields, some of which may be optional.
+ */
+class TypeObject extends TypeDecl {
+  final List<TypeObjectField> fields;
+
+  TypeObject(this.fields, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  accept(ApiVisitor visitor) => visitor.visitTypeObject(this);
+
+  /**
+   * Return the field with the given [name], or null if there is no such field.
+   */
+  TypeObjectField getField(String name) {
+    for (TypeObjectField field in fields) {
+      if (field.name == name) {
+        return field;
+      }
+    }
+    return null;
+  }
+}
+
+/**
+ * Description of a single field in a [TypeObject].
+ */
+class TypeObjectField extends ApiNode {
+  final String name;
+  final TypeDecl type;
+  final bool optional;
+
+  /**
+   * Value that the field is required to contain, or null if it may vary.
+   */
+  final Object value;
+
+  TypeObjectField(this.name, this.type, dom.Element html,
+      {this.optional: false, this.value, bool experimental})
+      : super(html, experimental);
+}
+
+/**
+ * A reference to a type which is either defined elsewhere in the API or which
+ * is built-in ([String], [bool], or [int]).
+ */
+class TypeReference extends TypeDecl {
+  final String typeName;
+
+  TypeReference(this.typeName, dom.Element html, {bool experimental})
+      : super(html, experimental) {
+    if (typeName.isEmpty) {
+      throw new Exception('Empty type name');
+    }
+  }
+
+  @override
+  accept(ApiVisitor visitor) => visitor.visitTypeReference(this);
+}
+
+/**
+ * A collection of type definitions.
+ */
+class Types extends ApiNode with IterableMixin<TypeDefinition> {
+  final Map<String, TypeDefinition> types;
+
+  Types(this.types, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  Iterator<TypeDefinition> get iterator => types.values.iterator;
+
+  Iterable<String> get keys => types.keys;
+
+  TypeDefinition operator [](String typeName) => types[typeName];
+
+  bool containsKey(String typeName) => types.containsKey(typeName);
+}
+
+/**
+ * Type which represents a union among multiple choices.
+ */
+class TypeUnion extends TypeDecl {
+  final List<TypeDecl> choices;
+
+  /**
+   * The field that is used to disambiguate this union
+   */
+  final String field;
+
+  TypeUnion(this.choices, this.field, dom.Element html, {bool experimental})
+      : super(html, experimental);
+
+  @override
+  accept(ApiVisitor visitor) => visitor.visitTypeUnion(this);
+}
diff --git a/pkg/analyzer_plugin/tool/spec/check_all_test.dart b/pkg/analyzer_plugin/tool/spec/check_all_test.dart
new file mode 100644
index 0000000..694b0fa
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/check_all_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:analyzer/src/codegen/tools.dart';
+import 'package:path/path.dart';
+
+import 'generate_all.dart';
+
+/**
+ * Check that all targets have been code generated.  If they haven't tell the
+ * user to run generate_all.dart.
+ */
+main() {
+  String script = Platform.script.toFilePath(windows: Platform.isWindows);
+  String pkgPath = normalize(join(dirname(script), '..', '..'));
+  GeneratedContent.checkAll(pkgPath, 'tool/spec/generate_all.dart', allTargets);
+}
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_dart.dart b/pkg/analyzer_plugin/tool/spec/codegen_dart.dart
new file mode 100644
index 0000000..e213893
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/codegen_dart.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'api.dart';
+
+/**
+ * Visitor specialized for generating Dart code.
+ */
+class DartCodegenVisitor extends HierarchicalApiVisitor {
+  /**
+   * Type references in the spec that are named something else in Dart.
+   */
+  static const Map<String, String> _typeRenames = const {
+    'long': 'int',
+    'object': 'Map',
+  };
+
+  DartCodegenVisitor(Api api) : super(api);
+
+  /**
+   * Convert the given [TypeDecl] to a Dart type.
+   */
+  String dartType(TypeDecl type) {
+    if (type is TypeReference) {
+      String typeName = type.typeName;
+      TypeDefinition referencedDefinition = api.types[typeName];
+      if (_typeRenames.containsKey(typeName)) {
+        return _typeRenames[typeName];
+      }
+      if (referencedDefinition == null) {
+        return typeName;
+      }
+      TypeDecl referencedType = referencedDefinition.type;
+      if (referencedType is TypeObject || referencedType is TypeEnum) {
+        return typeName;
+      }
+      return dartType(referencedType);
+    } else if (type is TypeList) {
+      return 'List<${dartType(type.itemType)}>';
+    } else if (type is TypeMap) {
+      return 'Map<${dartType(type.keyType)}, ${dartType(type.valueType)}>';
+    } else if (type is TypeUnion) {
+      return 'dynamic';
+    } else {
+      throw new Exception("Can't convert to a dart type");
+    }
+  }
+}
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
new file mode 100644
index 0000000..5f85c65
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
@@ -0,0 +1,1282 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:analyzer/src/codegen/tools.dart';
+import 'package:html/dom.dart' as dom;
+
+import 'api.dart';
+import 'codegen_dart.dart';
+import 'from_html.dart';
+import 'implied_types.dart';
+import 'to_html.dart';
+
+/**
+ * Special flags that need to be inserted into the declaration of the Element
+ * class.
+ */
+const Map<String, String> specialElementFlags = const {
+  'abstract': '0x01',
+  'const': '0x02',
+  'final': '0x04',
+  'static': '0x08',
+  'private': '0x10',
+  'deprecated': '0x20'
+};
+
+final GeneratedFile target =
+    new GeneratedFile('lib/protocol/protocol_generated.dart', (String pkgPath) {
+  CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi(pkgPath));
+  return visitor.collectCode(visitor.visitApi);
+});
+
+/**
+ * Callback type used to represent arbitrary code generation.
+ */
+typedef void CodegenCallback();
+
+typedef String FromJsonSnippetCallback(String jsonPath, String json);
+
+typedef String ToJsonSnippetCallback(String value);
+
+/**
+ * Visitor which produces Dart code representing the API.
+ */
+class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
+  /**
+   * Class members for which the constructor argument should be optional, even
+   * if the member is not an optional part of the protocol.  For list types,
+   * the constructor will default the member to the empty list.
+   */
+  static const Map<String, List<String>> _optionalConstructorArguments = const {
+    'AnalysisErrorFixes': const ['fixes'],
+    'SourceChange': const ['edits', 'linkedEditGroups'],
+    'SourceFileEdit': const ['edits'],
+    'TypeHierarchyItem': const ['interfaces', 'mixins', 'subclasses'],
+  };
+
+  /**
+   * The disclaimer added to the documentation comment for each of the classes
+   * that are generated.
+   */
+  static const String disclaimer =
+      'Clients may not extend, implement or mix-in this class.';
+
+  /**
+   * Visitor used to produce doc comments.
+   */
+  final ToHtmlVisitor toHtmlVisitor;
+
+  /**
+   * Types implied by the API.  This includes types explicitly named in the
+   * API as well as those implied by the definitions of requests, responses,
+   * notifications, etc.
+   */
+  final Map<String, ImpliedType> impliedTypes;
+
+  CodegenProtocolVisitor(Api api)
+      : toHtmlVisitor = new ToHtmlVisitor(api),
+        impliedTypes = computeImpliedTypes(api),
+        super(api) {
+    codeGeneratorSettings.commentLineLength = 79;
+    codeGeneratorSettings.languageName = 'dart';
+  }
+
+  /**
+   * Compute the code necessary to compare two objects for equality.
+   */
+  String compareEqualsCode(TypeDecl type, String thisVar, String otherVar) {
+    TypeDecl resolvedType = resolveTypeReferenceChain(type);
+    if (resolvedType is TypeReference ||
+        resolvedType is TypeEnum ||
+        resolvedType is TypeObject ||
+        resolvedType is TypeUnion) {
+      return '$thisVar == $otherVar';
+    } else if (resolvedType is TypeList) {
+      String itemTypeName = dartType(resolvedType.itemType);
+      String subComparison = compareEqualsCode(resolvedType.itemType, 'a', 'b');
+      String closure = '($itemTypeName a, $itemTypeName b) => $subComparison';
+      return 'listEqual($thisVar, $otherVar, $closure)';
+    } else if (resolvedType is TypeMap) {
+      String valueTypeName = dartType(resolvedType.valueType);
+      String subComparison =
+          compareEqualsCode(resolvedType.valueType, 'a', 'b');
+      String closure = '($valueTypeName a, $valueTypeName b) => $subComparison';
+      return 'mapEqual($thisVar, $otherVar, $closure)';
+    }
+    throw new Exception(
+        "Don't know how to compare for equality: $resolvedType");
+  }
+
+  /**
+   * Translate each type implied by the API to a class.
+   */
+  void emitClasses() {
+    List<ImpliedType> types = impliedTypes.values.toList();
+    types.sort((first, second) =>
+        capitalize(first.camelName).compareTo(capitalize(second.camelName)));
+    for (ImpliedType impliedType in types) {
+      TypeDecl type = impliedType.type;
+      String dartTypeName = capitalize(impliedType.camelName);
+      if (type == null) {
+        writeln();
+        emitEmptyObjectClass(dartTypeName, impliedType);
+      } else if (type is TypeObject) {
+        writeln();
+        emitObjectClass(dartTypeName, type, impliedType);
+      } else if (type is TypeEnum) {
+        writeln();
+        emitEnumClass(dartTypeName, type, impliedType);
+      }
+    }
+  }
+
+  /**
+   * Emit a convenience constructor for decoding a piece of protocol, if
+   * appropriate.  Return true if a constructor was emitted.
+   */
+  bool emitConvenienceConstructor(String className, ImpliedType impliedType) {
+    // The type of object from which this piece of protocol should be decoded.
+    String inputType;
+    // The name of the input object.
+    String inputName;
+    // The field within the input object to decode.
+    String fieldName;
+    // Constructor call to create the JsonDecoder object.
+    String makeDecoder;
+    // Name of the constructor to create.
+    String constructorName;
+    // Extra arguments for the constructor.
+    List<String> extraArgs = <String>[];
+    switch (impliedType.kind) {
+      case 'requestParams':
+        inputType = 'Request';
+        inputName = 'request';
+        fieldName = 'params';
+        makeDecoder = 'new RequestDecoder(request)';
+        constructorName = 'fromRequest';
+        break;
+      case 'requestResult':
+        inputType = 'Response';
+        inputName = 'response';
+        fieldName = 'result';
+        makeDecoder =
+            'new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id))';
+        constructorName = 'fromResponse';
+        break;
+      case 'notificationParams':
+        inputType = 'Notification';
+        inputName = 'notification';
+        fieldName = 'params';
+        makeDecoder = 'new ResponseDecoder(null)';
+        constructorName = 'fromNotification';
+        break;
+      case 'refactoringOptions':
+        inputType = 'EditGetRefactoringParams';
+        inputName = 'refactoringParams';
+        fieldName = 'options';
+        makeDecoder = 'new RequestDecoder(request)';
+        constructorName = 'fromRefactoringParams';
+        extraArgs.add('Request request');
+        break;
+      default:
+        return false;
+    }
+    List<String> args = ['$inputType $inputName'];
+    args.addAll(extraArgs);
+    writeln('factory $className.$constructorName(${args.join(', ')}) {');
+    indent(() {
+      String fieldNameString =
+          literalString(fieldName.replaceFirst(new RegExp('^_'), ''));
+      if (className == 'EditGetRefactoringParams') {
+        writeln('var params = new $className.fromJson(');
+        writeln('    $makeDecoder, $fieldNameString, $inputName.$fieldName);');
+        writeln('REQUEST_ID_REFACTORING_KINDS[request.id] = params.kind;');
+        writeln('return params;');
+      } else {
+        writeln('return new $className.fromJson(');
+        writeln('    $makeDecoder, $fieldNameString, $inputName.$fieldName);');
+      }
+    });
+    writeln('}');
+    return true;
+  }
+
+  /**
+   * Emit a class representing an data structure that doesn't exist in the
+   * protocol because it is empty (e.g. the "params" object for a request that
+   * doesn't have any parameters).
+   */
+  void emitEmptyObjectClass(String className, ImpliedType impliedType) {
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(impliedType.humanReadableName);
+      });
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(disclaimer);
+      });
+    }));
+    write('class $className');
+    if (impliedType.kind == 'refactoringFeedback') {
+      writeln(' extends RefactoringFeedback implements HasToJson {');
+    } else if (impliedType.kind == 'refactoringOptions') {
+      writeln(' extends RefactoringOptions implements HasToJson {');
+    } else if (impliedType.kind == 'requestParams') {
+      writeln(' implements RequestParams {');
+    } else if (impliedType.kind == 'requestResult') {
+      writeln(' implements ResponseResult {');
+    } else {
+      writeln(' {');
+    }
+    indent(() {
+      if (impliedType.kind == 'requestResult' ||
+          impliedType.kind == 'requestParams') {
+        emitEmptyToJsonMember();
+        writeln();
+      }
+      if (emitToRequestMember(impliedType)) {
+        writeln();
+      }
+      if (emitToResponseMember(impliedType)) {
+        writeln();
+      }
+      if (emitToNotificationMember(impliedType)) {
+        writeln();
+      }
+      emitObjectEqualsMember(null, className);
+      writeln();
+      emitObjectHashCode(null, className);
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the toJson() code for an empty class.
+   */
+  void emitEmptyToJsonMember() {
+    writeln('@override');
+    writeln('Map<String, dynamic> toJson() => <String, dynamic>{};');
+  }
+
+  /**
+   * Emit a class to encapsulate an enum.
+   */
+  void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) {
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(impliedType.humanReadableName);
+      });
+      if (impliedType.type != null) {
+        toHtmlVisitor.showType(null, impliedType.type);
+      }
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(disclaimer);
+      });
+    }));
+    writeln('class $className implements Enum {');
+    indent(() {
+      if (emitSpecialStaticMembers(className)) {
+        writeln();
+      }
+      for (TypeEnumValue value in type.values) {
+        docComment(toHtmlVisitor.collectHtml(() {
+          toHtmlVisitor.translateHtml(value.html);
+        }));
+        String valueString = literalString(value.value);
+        writeln(
+            'static const $className ${value.value} = const $className._($valueString);');
+        writeln();
+      }
+
+      writeln('/**');
+      writeln(' * A list containing all of the enum values that are defined.');
+      writeln(' */');
+      write('static const List<');
+      write(className);
+      write('> VALUES = const <');
+      write(className);
+      write('>[');
+      bool first = true;
+      for (TypeEnumValue value in type.values) {
+        if (first) {
+          first = false;
+        } else {
+          write(', ');
+        }
+        write(value.value);
+      }
+      writeln('];');
+      writeln();
+
+      writeln('@override');
+      writeln('final String name;');
+      writeln();
+      writeln('const $className._(this.name);');
+      writeln();
+      emitEnumClassConstructor(className, type);
+      writeln();
+      emitEnumFromJsonConstructor(className, type, impliedType);
+      writeln();
+      if (emitSpecialConstructors(className)) {
+        writeln();
+      }
+      if (emitSpecialGetters(className)) {
+        writeln();
+      }
+      if (emitSpecialMethods(className)) {
+        writeln();
+      }
+      writeln('@override');
+      writeln('String toString() => "$className.\$name";');
+      writeln();
+      writeln('String toJson() => name;');
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the constructor for an enum class.
+   */
+  void emitEnumClassConstructor(String className, TypeEnum type) {
+    writeln('factory $className(String name) {');
+    indent(() {
+      writeln('switch (name) {');
+      indent(() {
+        for (TypeEnumValue value in type.values) {
+          String valueString = literalString(value.value);
+          writeln('case $valueString:');
+          indent(() {
+            writeln('return ${value.value};');
+          });
+        }
+      });
+      writeln('}');
+      writeln(r"throw new Exception('Illegal enum value: $name');");
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the method for decoding an enum from JSON.
+   */
+  void emitEnumFromJsonConstructor(
+      String className, TypeEnum type, ImpliedType impliedType) {
+    writeln(
+        'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {');
+    indent(() {
+      writeln('if (json is String) {');
+      indent(() {
+        writeln('try {');
+        indent(() {
+          writeln('return new $className(json);');
+        });
+        writeln('} catch(_) {');
+        indent(() {
+          writeln('// Fall through');
+        });
+        writeln('}');
+      });
+      writeln('}');
+      String humanReadableNameString =
+          literalString(impliedType.humanReadableName);
+      writeln(
+          'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString, json);');
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the class to encapsulate an object type.
+   */
+  void emitObjectClass(
+      String className, TypeObject type, ImpliedType impliedType) {
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(impliedType.humanReadableName);
+      });
+      if (impliedType.type != null) {
+        toHtmlVisitor.showType(null, impliedType.type);
+      }
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(disclaimer);
+      });
+    }));
+    write('class $className');
+    if (impliedType.kind == 'refactoringFeedback') {
+      writeln(' extends RefactoringFeedback {');
+    } else if (impliedType.kind == 'refactoringOptions') {
+      writeln(' extends RefactoringOptions {');
+    } else if (impliedType.kind == 'requestParams') {
+      writeln(' implements RequestParams {');
+    } else if (impliedType.kind == 'requestResult') {
+      writeln(' implements ResponseResult {');
+    } else {
+      writeln(' implements HasToJson {');
+    }
+    indent(() {
+      if (emitSpecialStaticMembers(className)) {
+        writeln();
+      }
+      for (TypeObjectField field in type.fields) {
+        if (field.value != null) {
+          continue;
+        }
+        writeln('${dartType(field.type)} _${field.name};');
+        writeln();
+      }
+      for (TypeObjectField field in type.fields) {
+        if (field.value != null) {
+          continue;
+        }
+        docComment(toHtmlVisitor.collectHtml(() {
+          toHtmlVisitor.translateHtml(field.html);
+        }));
+        writeln('${dartType(field.type)} get ${field.name} => _${field.name};');
+        writeln();
+        docComment(toHtmlVisitor.collectHtml(() {
+          toHtmlVisitor.translateHtml(field.html);
+        }));
+        writeln('void set ${field.name}(${dartType(field.type)} value) {');
+        indent(() {
+          if (!field.optional) {
+            writeln('assert(value != null);');
+          }
+          writeln('this._${field.name} = value;');
+        });
+        writeln('}');
+        writeln();
+      }
+      emitObjectConstructor(type, className);
+      writeln();
+      emitObjectFromJsonConstructor(className, type, impliedType);
+      writeln();
+      if (emitConvenienceConstructor(className, impliedType)) {
+        writeln();
+      }
+      if (emitSpecialConstructors(className)) {
+        writeln();
+      }
+      if (emitSpecialGetters(className)) {
+        writeln();
+      }
+      emitToJsonMember(type);
+      writeln();
+      if (emitToRequestMember(impliedType)) {
+        writeln();
+      }
+      if (emitToResponseMember(impliedType)) {
+        writeln();
+      }
+      if (emitToNotificationMember(impliedType)) {
+        writeln();
+      }
+      if (emitSpecialMethods(className)) {
+        writeln();
+      }
+      writeln('@override');
+      writeln('String toString() => JSON.encode(toJson());');
+      writeln();
+      emitObjectEqualsMember(type, className);
+      writeln();
+      emitObjectHashCode(type, className);
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the constructor for an object class.
+   */
+  void emitObjectConstructor(TypeObject type, String className) {
+    List<String> args = <String>[];
+    List<String> optionalArgs = <String>[];
+    List<CodegenCallback> extraInitCode = <CodegenCallback>[];
+    for (TypeObjectField field in type.fields) {
+      if (field.value != null) {
+        continue;
+      }
+      String arg = '${dartType(field.type)} ${field.name}';
+      String setValueFromArg = 'this.${field.name} = ${field.name};';
+      if (isOptionalConstructorArg(className, field)) {
+        optionalArgs.add(arg);
+        if (!field.optional) {
+          // Optional constructor arg, but non-optional field.  If no arg is
+          // given, the constructor should populate with the empty list.
+          TypeDecl fieldType = field.type;
+          if (fieldType is TypeList) {
+            extraInitCode.add(() {
+              writeln('if (${field.name} == null) {');
+              indent(() {
+                writeln(
+                    'this.${field.name} = <${dartType(fieldType.itemType)}>[];');
+              });
+              writeln('} else {');
+              indent(() {
+                writeln(setValueFromArg);
+              });
+              writeln('}');
+            });
+          } else {
+            throw new Exception(
+                "Don't know how to create default field value.");
+          }
+        } else {
+          extraInitCode.add(() {
+            writeln(setValueFromArg);
+          });
+        }
+      } else {
+        args.add(arg);
+        extraInitCode.add(() {
+          writeln(setValueFromArg);
+        });
+      }
+    }
+    if (optionalArgs.isNotEmpty) {
+      args.add('{${optionalArgs.join(', ')}}');
+    }
+    write('$className(${args.join(', ')})');
+    if (extraInitCode.isEmpty) {
+      writeln(';');
+    } else {
+      writeln(' {');
+      indent(() {
+        for (CodegenCallback callback in extraInitCode) {
+          callback();
+        }
+      });
+      writeln('}');
+    }
+  }
+
+  /**
+   * Emit the operator== code for an object class.
+   */
+  void emitObjectEqualsMember(TypeObject type, String className) {
+    writeln('@override');
+    writeln('bool operator==(other) {');
+    indent(() {
+      writeln('if (other is $className) {');
+      indent(() {
+        var comparisons = <String>[];
+        if (type != null) {
+          for (TypeObjectField field in type.fields) {
+            if (field.value != null) {
+              continue;
+            }
+            comparisons.add(compareEqualsCode(
+                field.type, field.name, 'other.${field.name}'));
+          }
+        }
+        if (comparisons.isEmpty) {
+          writeln('return true;');
+        } else {
+          String concatenated = comparisons.join(' &&\n    ');
+          writeln('return $concatenated;');
+        }
+      });
+      writeln('}');
+      writeln('return false;');
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the method for decoding an object from JSON.
+   */
+  void emitObjectFromJsonConstructor(
+      String className, TypeObject type, ImpliedType impliedType) {
+    String humanReadableNameString =
+        literalString(impliedType.humanReadableName);
+    if (className == 'RefactoringFeedback') {
+      writeln('factory RefactoringFeedback.fromJson(JsonDecoder jsonDecoder, '
+          'String jsonPath, Object json, Map responseJson) {');
+      indent(() {
+        writeln('return refactoringFeedbackFromJson(jsonDecoder, jsonPath, '
+            'json, responseJson);');
+      });
+      writeln('}');
+      return;
+    }
+    if (className == 'RefactoringOptions') {
+      writeln('factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, '
+          'String jsonPath, Object json, RefactoringKind kind) {');
+      indent(() {
+        writeln('return refactoringOptionsFromJson(jsonDecoder, jsonPath, '
+            'json, kind);');
+      });
+      writeln('}');
+      return;
+    }
+    writeln(
+        'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {');
+    indent(() {
+      writeln('if (json == null) {');
+      indent(() {
+        writeln('json = {};');
+      });
+      writeln('}');
+      writeln('if (json is Map) {');
+      indent(() {
+        List<String> args = <String>[];
+        List<String> optionalArgs = <String>[];
+        for (TypeObjectField field in type.fields) {
+          String fieldNameString = literalString(field.name);
+          String fieldAccessor = 'json[$fieldNameString]';
+          String jsonPath = 'jsonPath + ${literalString('.${field.name}')}';
+          if (field.value != null) {
+            String valueString = literalString(field.value);
+            writeln('if ($fieldAccessor != $valueString) {');
+            indent(() {
+              writeln(
+                  'throw jsonDecoder.mismatch(jsonPath, "equal " + $valueString, json);');
+            });
+            writeln('}');
+            continue;
+          }
+          if (isOptionalConstructorArg(className, field)) {
+            optionalArgs.add('${field.name}: ${field.name}');
+          } else {
+            args.add(field.name);
+          }
+          TypeDecl fieldType = field.type;
+          String fieldDartType = dartType(fieldType);
+          writeln('$fieldDartType ${field.name};');
+          writeln('if (json.containsKey($fieldNameString)) {');
+          indent(() {
+            String fromJson =
+                fromJsonCode(fieldType).asSnippet(jsonPath, fieldAccessor);
+            writeln('${field.name} = $fromJson;');
+          });
+          write('}');
+          if (!field.optional) {
+            writeln(' else {');
+            indent(() {
+              writeln(
+                  "throw jsonDecoder.mismatch(jsonPath, $fieldNameString);");
+            });
+            writeln('}');
+          } else {
+            writeln();
+          }
+        }
+        args.addAll(optionalArgs);
+        writeln('return new $className(${args.join(', ')});');
+      });
+      writeln('} else {');
+      indent(() {
+        writeln(
+            'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString, json);');
+      });
+      writeln('}');
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the hashCode getter for an object class.
+   */
+  void emitObjectHashCode(TypeObject type, String className) {
+    writeln('@override');
+    writeln('int get hashCode {');
+    indent(() {
+      if (type == null) {
+        writeln('return ${className.hashCode};');
+      } else {
+        writeln('int hash = 0;');
+        for (TypeObjectField field in type.fields) {
+          String valueToCombine;
+          if (field.value != null) {
+            valueToCombine = field.value.hashCode.toString();
+          } else {
+            valueToCombine = '${field.name}.hashCode';
+          }
+          writeln('hash = JenkinsSmiHash.combine(hash, $valueToCombine);');
+        }
+        writeln('return JenkinsSmiHash.finish(hash);');
+      }
+    });
+    writeln('}');
+  }
+
+  /**
+   * If the class named [className] requires special constructors, emit them
+   * and return true.
+   */
+  bool emitSpecialConstructors(String className) {
+    switch (className) {
+      case 'LinkedEditGroup':
+        docComment([new dom.Text('Construct an empty LinkedEditGroup.')]);
+        writeln(
+            'LinkedEditGroup.empty() : this(<Position>[], 0, <LinkedEditSuggestion>[]);');
+        return true;
+      case 'RefactoringProblemSeverity':
+        docComment([
+          new dom.Text(
+              'Returns the [RefactoringProblemSeverity] with the maximal severity.')
+        ]);
+        writeln(
+            'static RefactoringProblemSeverity max(RefactoringProblemSeverity a, RefactoringProblemSeverity b) =>');
+        writeln('    maxRefactoringProblemSeverity(a, b);');
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * If the class named [className] requires special getters, emit them and
+   * return true.
+   */
+  bool emitSpecialGetters(String className) {
+    switch (className) {
+      case 'Element':
+        for (String name in specialElementFlags.keys) {
+          String flag = 'FLAG_${name.toUpperCase()}';
+          writeln(
+              'bool get ${camelJoin(['is', name])} => (flags & $flag) != 0;');
+        }
+        return true;
+      case 'SourceEdit':
+        docComment([new dom.Text('The end of the region to be modified.')]);
+        writeln('int get end => offset + length;');
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * If the class named [className] requires special methods, emit them and
+   * return true.
+   */
+  bool emitSpecialMethods(String className) {
+    switch (className) {
+      case 'LinkedEditGroup':
+        docComment([new dom.Text('Add a new position and change the length.')]);
+        writeln('void addPosition(Position position, int length) {');
+        indent(() {
+          writeln('positions.add(position);');
+          writeln('this.length = length;');
+        });
+        writeln('}');
+        writeln();
+        docComment([new dom.Text('Add a new suggestion.')]);
+        writeln('void addSuggestion(LinkedEditSuggestion suggestion) {');
+        indent(() {
+          writeln('suggestions.add(suggestion);');
+        });
+        writeln('}');
+        return true;
+      case 'SourceChange':
+        docComment([
+          new dom.Text('Adds [edit] to the [FileEdit] for the given [file].')
+        ]);
+        writeln('void addEdit(String file, int fileStamp, SourceEdit edit) =>');
+        writeln('    addEditToSourceChange(this, file, fileStamp, edit);');
+        writeln();
+        docComment([new dom.Text('Adds the given [FileEdit].')]);
+        writeln('void addFileEdit(SourceFileEdit edit) {');
+        indent(() {
+          writeln('edits.add(edit);');
+        });
+        writeln('}');
+        writeln();
+        docComment([new dom.Text('Adds the given [LinkedEditGroup].')]);
+        writeln('void addLinkedEditGroup(LinkedEditGroup linkedEditGroup) {');
+        indent(() {
+          writeln('linkedEditGroups.add(linkedEditGroup);');
+        });
+        writeln('}');
+        writeln();
+        docComment([
+          new dom.Text(
+              'Returns the [FileEdit] for the given [file], maybe `null`.')
+        ]);
+        writeln('SourceFileEdit getFileEdit(String file) =>');
+        writeln('    getChangeFileEdit(this, file);');
+        return true;
+      case 'SourceEdit':
+        docComment([
+          new dom.Text(
+              'Get the result of applying the edit to the given [code].')
+        ]);
+        writeln('String apply(String code) => applyEdit(code, this);');
+        return true;
+      case 'SourceFileEdit':
+        docComment([new dom.Text('Adds the given [Edit] to the list.')]);
+        writeln('void add(SourceEdit edit) => addEditForSource(this, edit);');
+        writeln();
+        docComment([new dom.Text('Adds the given [Edit]s.')]);
+        writeln('void addAll(Iterable<SourceEdit> edits) =>');
+        writeln('    addAllEditsForSource(this, edits);');
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * If the class named [className] requires special static members, emit them
+   * and return true.
+   */
+  bool emitSpecialStaticMembers(String className) {
+    switch (className) {
+      case 'Element':
+        List<String> makeFlagsArgs = <String>[];
+        List<String> makeFlagsStatements = <String>[];
+        specialElementFlags.forEach((String name, String value) {
+          String flag = 'FLAG_${name.toUpperCase()}';
+          String camelName = camelJoin(['is', name]);
+          writeln('static const int $flag = $value;');
+          makeFlagsArgs.add('$camelName: false');
+          makeFlagsStatements.add('if ($camelName) flags |= $flag;');
+        });
+        writeln();
+        writeln('static int makeFlags({${makeFlagsArgs.join(', ')}}) {');
+        indent(() {
+          writeln('int flags = 0;');
+          for (String statement in makeFlagsStatements) {
+            writeln(statement);
+          }
+          writeln('return flags;');
+        });
+        writeln('}');
+        return true;
+      case 'SourceEdit':
+        docComment([
+          new dom.Text('Get the result of applying a set of ' +
+              '[edits] to the given [code].  Edits are applied in the order ' +
+              'they appear in [edits].')
+        ]);
+        writeln(
+            'static String applySequence(String code, Iterable<SourceEdit> edits) =>');
+        writeln('    applySequenceOfEdits(code, edits);');
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * Emit the toJson() code for an object class.
+   */
+  void emitToJsonMember(TypeObject type) {
+    writeln('@override');
+    writeln('Map<String, dynamic> toJson() {');
+    indent(() {
+      writeln('Map<String, dynamic> result = {};');
+      for (TypeObjectField field in type.fields) {
+        String fieldNameString = literalString(field.name);
+        if (field.value != null) {
+          writeln('result[$fieldNameString] = ${literalString(field.value)};');
+          continue;
+        }
+        String fieldToJson = toJsonCode(field.type).asSnippet(field.name);
+        String populateField = 'result[$fieldNameString] = $fieldToJson;';
+        if (field.optional) {
+          writeln('if (${field.name} != null) {');
+          indent(() {
+            writeln(populateField);
+          });
+          writeln('}');
+        } else {
+          writeln(populateField);
+        }
+      }
+      writeln('return result;');
+    });
+    writeln('}');
+  }
+
+  /**
+   * Emit the toNotification() code for a class, if appropriate.  Returns true
+   * if code was emitted.
+   */
+  bool emitToNotificationMember(ImpliedType impliedType) {
+    if (impliedType.kind == 'notificationParams') {
+      writeln('Notification toNotification() {');
+      indent(() {
+        String eventString =
+            literalString((impliedType.apiNode as Notification).longEvent);
+        String jsonPart = impliedType.type != null ? 'toJson()' : 'null';
+        writeln('return new Notification($eventString, $jsonPart);');
+      });
+      writeln('}');
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Emit the toRequest() code for a class, if appropriate.  Returns true if
+   * code was emitted.
+   */
+  bool emitToRequestMember(ImpliedType impliedType) {
+    if (impliedType.kind == 'requestParams') {
+      writeln('@override');
+      writeln('Request toRequest(String id) {');
+      indent(() {
+        String methodString =
+            literalString((impliedType.apiNode as Request).longMethod);
+        String jsonPart = impliedType.type != null ? 'toJson()' : 'null';
+        writeln('return new Request(id, $methodString, $jsonPart);');
+      });
+      writeln('}');
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Emit the toResponse() code for a class, if appropriate.  Returns true if
+   * code was emitted.
+   */
+  bool emitToResponseMember(ImpliedType impliedType) {
+    if (impliedType.kind == 'requestResult') {
+      writeln('@override');
+      writeln('Response toResponse(String id) {');
+      indent(() {
+        String jsonPart = impliedType.type != null ? 'toJson()' : 'null';
+        writeln('return new Response(id, result: $jsonPart);');
+      });
+      writeln('}');
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Compute the code necessary to translate [type] from JSON.
+   */
+  FromJsonCode fromJsonCode(TypeDecl type) {
+    if (type is TypeReference) {
+      TypeDefinition referencedDefinition = api.types[type.typeName];
+      if (referencedDefinition != null) {
+        TypeDecl referencedType = referencedDefinition.type;
+        if (referencedType is TypeObject || referencedType is TypeEnum) {
+          return new FromJsonSnippet((String jsonPath, String json) {
+            String typeName = dartType(type);
+            if (typeName == 'RefactoringFeedback') {
+              return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json, json)';
+            } else if (typeName == 'RefactoringOptions') {
+              return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json, kind)';
+            } else {
+              return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json)';
+            }
+          });
+        } else {
+          return fromJsonCode(referencedType);
+        }
+      } else {
+        switch (type.typeName) {
+          case 'String':
+            return new FromJsonFunction('jsonDecoder.decodeString');
+          case 'bool':
+            return new FromJsonFunction('jsonDecoder.decodeBool');
+          case 'int':
+          case 'long':
+            return new FromJsonFunction('jsonDecoder.decodeInt');
+          case 'object':
+            return new FromJsonIdentity();
+          default:
+            throw new Exception('Unexpected type name ${type.typeName}');
+        }
+      }
+    } else if (type is TypeMap) {
+      FromJsonCode keyCode;
+      if (dartType(type.keyType) != 'String') {
+        keyCode = fromJsonCode(type.keyType);
+      } else {
+        keyCode = new FromJsonIdentity();
+      }
+      FromJsonCode valueCode = fromJsonCode(type.valueType);
+      if (keyCode.isIdentity && valueCode.isIdentity) {
+        return new FromJsonFunction('jsonDecoder.decodeMap');
+      } else {
+        return new FromJsonSnippet((String jsonPath, String json) {
+          StringBuffer result = new StringBuffer();
+          result.write('jsonDecoder.decodeMap($jsonPath, $json');
+          if (!keyCode.isIdentity) {
+            result.write(', keyDecoder: ${keyCode.asClosure}');
+          }
+          if (!valueCode.isIdentity) {
+            result.write(', valueDecoder: ${valueCode.asClosure}');
+          }
+          result.write(')');
+          return result.toString();
+        });
+      }
+    } else if (type is TypeList) {
+      FromJsonCode itemCode = fromJsonCode(type.itemType);
+      if (itemCode.isIdentity) {
+        return new FromJsonFunction('jsonDecoder.decodeList');
+      } else {
+        return new FromJsonSnippet((String jsonPath, String json) =>
+            'jsonDecoder.decodeList($jsonPath, $json, ${itemCode.asClosure})');
+      }
+    } else if (type is TypeUnion) {
+      List<String> decoders = <String>[];
+      for (TypeDecl choice in type.choices) {
+        TypeDecl resolvedChoice = resolveTypeReferenceChain(choice);
+        if (resolvedChoice is TypeObject) {
+          TypeObjectField field = resolvedChoice.getField(type.field);
+          if (field == null) {
+            throw new Exception(
+                'Each choice in the union needs a field named ${type.field}');
+          }
+          if (field.value == null) {
+            throw new Exception(
+                'Each choice in the union needs a constant value for the field ${type.field}');
+          }
+          String closure = fromJsonCode(choice).asClosure;
+          decoders.add('${literalString(field.value)}: $closure');
+        } else {
+          throw new Exception('Union types must be unions of objects.');
+        }
+      }
+      return new FromJsonSnippet((String jsonPath, String json) =>
+          'jsonDecoder.decodeUnion($jsonPath, $json, ${literalString(type.field)}, {${decoders.join(', ')}})');
+    } else {
+      throw new Exception("Can't convert $type from JSON");
+    }
+  }
+
+  /**
+   * True if the constructor argument for the given field should be optional.
+   */
+  bool isOptionalConstructorArg(String className, TypeObjectField field) {
+    if (field.optional) {
+      return true;
+    }
+    List<String> forceOptional = _optionalConstructorArguments[className];
+    if (forceOptional != null && forceOptional.contains(field.name)) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Create a string literal that evaluates to [s].
+   */
+  String literalString(String s) {
+    return JSON.encode(s);
+  }
+
+  /**
+   * Compute the code necessary to convert [type] to JSON.
+   */
+  ToJsonCode toJsonCode(TypeDecl type) {
+    TypeDecl resolvedType = resolveTypeReferenceChain(type);
+    if (resolvedType is TypeReference) {
+      return new ToJsonIdentity(dartType(type));
+    } else if (resolvedType is TypeList) {
+      ToJsonCode itemCode = toJsonCode(resolvedType.itemType);
+      if (itemCode.isIdentity) {
+        return new ToJsonIdentity(dartType(type));
+      } else {
+        return new ToJsonSnippet(dartType(type),
+            (String value) => '$value.map(${itemCode.asClosure}).toList()');
+      }
+    } else if (resolvedType is TypeMap) {
+      ToJsonCode keyCode;
+      if (dartType(resolvedType.keyType) != 'String') {
+        keyCode = toJsonCode(resolvedType.keyType);
+      } else {
+        keyCode = new ToJsonIdentity(dartType(resolvedType.keyType));
+      }
+      ToJsonCode valueCode = toJsonCode(resolvedType.valueType);
+      if (keyCode.isIdentity && valueCode.isIdentity) {
+        return new ToJsonIdentity(dartType(resolvedType));
+      } else {
+        return new ToJsonSnippet(dartType(type), (String value) {
+          StringBuffer result = new StringBuffer();
+          result.write('mapMap($value');
+          if (!keyCode.isIdentity) {
+            result.write(', keyCallback: ${keyCode.asClosure}');
+          }
+          if (!valueCode.isIdentity) {
+            result.write(', valueCallback: ${valueCode.asClosure}');
+          }
+          result.write(')');
+          return result.toString();
+        });
+      }
+    } else if (resolvedType is TypeUnion) {
+      for (TypeDecl choice in resolvedType.choices) {
+        if (resolveTypeReferenceChain(choice) is! TypeObject) {
+          throw new Exception('Union types must be unions of objects');
+        }
+      }
+      return new ToJsonSnippet(
+          dartType(type), (String value) => '$value.toJson()');
+    } else if (resolvedType is TypeObject || resolvedType is TypeEnum) {
+      return new ToJsonSnippet(
+          dartType(type), (String value) => '$value.toJson()');
+    } else {
+      throw new Exception("Can't convert $resolvedType from JSON");
+    }
+  }
+
+  @override
+  visitApi() {
+    outputHeader(year: '2017');
+    writeln();
+    writeln("import 'dart:convert' hide JsonDecoder;");
+    writeln();
+    writeln("import 'package:analyzer/src/generated/utilities_general.dart';");
+    writeln("import 'package:analyzer_plugin/protocol/protocol.dart';");
+    writeln(
+        "import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';");
+    emitClasses();
+  }
+}
+
+/**
+ * Container for code that can be used to translate a data type from JSON.
+ */
+abstract class FromJsonCode {
+  /**
+   * Get the translation code in the form of a closure.
+   */
+  String get asClosure;
+
+  /**
+   * True if the data type is already in JSON form, so the translation is the
+   * identity function.
+   */
+  bool get isIdentity;
+
+  /**
+   * Get the translation code in the form of a code snippet, where [jsonPath]
+   * is the variable holding the JSON path, and [json] is the variable holding
+   * the raw JSON.
+   */
+  String asSnippet(String jsonPath, String json);
+}
+
+/**
+ * Representation of FromJsonCode for a function defined elsewhere.
+ */
+class FromJsonFunction extends FromJsonCode {
+  @override
+  final String asClosure;
+
+  FromJsonFunction(this.asClosure);
+
+  @override
+  bool get isIdentity => false;
+
+  @override
+  String asSnippet(String jsonPath, String json) =>
+      '$asClosure($jsonPath, $json)';
+}
+
+/**
+ * Representation of FromJsonCode for the identity transformation.
+ */
+class FromJsonIdentity extends FromJsonSnippet {
+  FromJsonIdentity() : super((String jsonPath, String json) => json);
+
+  @override
+  bool get isIdentity => true;
+}
+
+/**
+ * Representation of FromJsonCode for a snippet of inline code.
+ */
+class FromJsonSnippet extends FromJsonCode {
+  /**
+   * Callback that can be used to generate the code snippet, once the names
+   * of the [jsonPath] and [json] variables are known.
+   */
+  final FromJsonSnippetCallback callback;
+
+  FromJsonSnippet(this.callback);
+
+  @override
+  String get asClosure =>
+      '(String jsonPath, Object json) => ${callback('jsonPath', 'json')}';
+
+  @override
+  bool get isIdentity => false;
+
+  @override
+  String asSnippet(String jsonPath, String json) => callback(jsonPath, json);
+}
+
+/**
+ * Container for code that can be used to translate a data type to JSON.
+ */
+abstract class ToJsonCode {
+  /**
+   * Get the translation code in the form of a closure.
+   */
+  String get asClosure;
+
+  /**
+   * True if the data type is already in JSON form, so the translation is the
+   * identity function.
+   */
+  bool get isIdentity;
+
+  /**
+   * Get the translation code in the form of a code snippet, where [value]
+   * is the variable holding the object to be translated.
+   */
+  String asSnippet(String value);
+}
+
+/**
+ * Representation of ToJsonCode for a function defined elsewhere.
+ */
+class ToJsonFunction extends ToJsonCode {
+  @override
+  final String asClosure;
+
+  ToJsonFunction(this.asClosure);
+
+  @override
+  bool get isIdentity => false;
+
+  @override
+  String asSnippet(String value) => '$asClosure($value)';
+}
+
+/**
+ * Representation of FromJsonCode for the identity transformation.
+ */
+class ToJsonIdentity extends ToJsonSnippet {
+  ToJsonIdentity(String type) : super(type, (String value) => value);
+
+  @override
+  bool get isIdentity => true;
+}
+
+/**
+ * Representation of ToJsonCode for a snippet of inline code.
+ */
+class ToJsonSnippet extends ToJsonCode {
+  /**
+   * Callback that can be used to generate the code snippet, once the name
+   * of the [value] variable is known.
+   */
+  final ToJsonSnippetCallback callback;
+
+  /**
+   * Dart type of the [value] variable.
+   */
+  final String type;
+
+  ToJsonSnippet(this.type, this.callback);
+
+  @override
+  String get asClosure => '($type value) => ${callback('value')}';
+
+  @override
+  bool get isIdentity => false;
+
+  @override
+  String asSnippet(String value) => callback(value);
+}
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_inttest_methods.dart b/pkg/analyzer_plugin/tool/spec/codegen_inttest_methods.dart
new file mode 100644
index 0000000..fc92391
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/codegen_inttest_methods.dart
@@ -0,0 +1,260 @@
+// 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.
+
+/**
+ * Code generation for the file "integration_test_methods.dart".
+ */
+import 'dart:convert';
+
+import 'package:analyzer/src/codegen/tools.dart';
+
+import 'api.dart';
+import 'codegen_dart.dart';
+import 'from_html.dart';
+import 'to_html.dart';
+
+final GeneratedFile target = new GeneratedFile(
+    'test/integration/support/integration_test_methods.dart', (String pkgPath) {
+  CodegenInttestMethodsVisitor visitor =
+      new CodegenInttestMethodsVisitor(readApi(pkgPath));
+  return visitor.collectCode(visitor.visitApi);
+});
+
+/**
+ * Visitor that generates the code for integration_test_methods.dart
+ */
+class CodegenInttestMethodsVisitor extends DartCodegenVisitor
+    with CodeGenerator {
+  /**
+   * Visitor used to produce doc comments.
+   */
+  final ToHtmlVisitor toHtmlVisitor;
+
+  /**
+   * Code snippets concatenated to initialize all of the class fields.
+   */
+  List<String> fieldInitializationCode = <String>[];
+
+  /**
+   * Code snippets concatenated to produce the contents of the switch statement
+   * for dispatching notifications.
+   */
+  List<String> notificationSwitchContents = <String>[];
+
+  CodegenInttestMethodsVisitor(Api api)
+      : toHtmlVisitor = new ToHtmlVisitor(api),
+        super(api) {
+    codeGeneratorSettings.commentLineLength = 79;
+    codeGeneratorSettings.languageName = 'dart';
+  }
+
+  /**
+   * Generate a function argument for the given parameter field.
+   */
+  String formatArgument(TypeObjectField field) =>
+      '${dartType(field.type)} ${field.name}';
+
+  /**
+   * Figure out the appropriate Dart type for data having the given API
+   * protocol [type].
+   */
+  String jsonType(TypeDecl type) {
+    type = resolveTypeReferenceChain(type);
+    if (type is TypeEnum) {
+      return 'String';
+    } else if (type is TypeList) {
+      return 'List<${jsonType(type.itemType)}>';
+    } else if (type is TypeMap) {
+      return 'Map<String, ${jsonType(type.valueType)}>';
+    } else if (type is TypeObject) {
+      return 'Map<String, dynamic>';
+    } else if (type is TypeReference) {
+      switch (type.typeName) {
+        case 'String':
+        case 'int':
+        case 'bool':
+          // These types correspond exactly to Dart types
+          return type.typeName;
+        case 'object':
+          return 'Map<String, dynamic>';
+        default:
+          throw new Exception(type.typeName);
+      }
+    } else if (type is TypeUnion) {
+      return 'Object';
+    } else {
+      throw new Exception('Unexpected kind of TypeDecl');
+    }
+  }
+
+  @override
+  visitApi() {
+    outputHeader(year: '2017');
+    writeln();
+    writeln('/**');
+    writeln(' * Convenience methods for running integration tests');
+    writeln(' */');
+    writeln("import 'dart:async';");
+    writeln();
+    writeln(
+        "import 'package:analyzer_plugin/protocol/protocol_generated.dart';");
+    writeln(
+        "import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';");
+    writeln("import 'package:test/test.dart';");
+    writeln();
+    writeln("import 'integration_tests.dart';");
+    writeln("import 'protocol_matchers.dart';");
+    writeln();
+    writeln('/**');
+    writeln(' * Convenience methods for running integration tests');
+    writeln(' */');
+    writeln('abstract class IntegrationTestMixin {');
+    indent(() {
+      writeln('Server get server;');
+      super.visitApi();
+      writeln();
+      docComment(toHtmlVisitor.collectHtml(() {
+        toHtmlVisitor.writeln('Initialize the fields in InttestMixin, and');
+        toHtmlVisitor.writeln('ensure that notifications will be handled.');
+      }));
+      writeln('void initializeInttestMixin() {');
+      indent(() {
+        write(fieldInitializationCode.join());
+      });
+      writeln('}');
+      writeln();
+      docComment(toHtmlVisitor.collectHtml(() {
+        toHtmlVisitor.writeln('Dispatch the notification named [event], and');
+        toHtmlVisitor.writeln('containing parameters [params], to the');
+        toHtmlVisitor.writeln('appropriate stream.');
+      }));
+      writeln('void dispatchNotification(String event, params) {');
+      indent(() {
+        writeln('ResponseDecoder decoder = new ResponseDecoder(null);');
+        writeln('switch (event) {');
+        indent(() {
+          write(notificationSwitchContents.join());
+          writeln('default:');
+          indent(() {
+            writeln("fail('Unexpected notification: \$event');");
+            writeln('break;');
+          });
+        });
+        writeln('}');
+      });
+      writeln('}');
+    });
+    writeln('}');
+  }
+
+  @override
+  visitNotification(Notification notification) {
+    String streamName =
+        camelJoin(['on', notification.domainName, notification.event]);
+    String className = camelJoin(
+        [notification.domainName, notification.event, 'params'],
+        doCapitalize: true);
+    writeln();
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.translateHtml(notification.html);
+      toHtmlVisitor.describePayload(notification.params, 'Parameters');
+    }));
+    writeln('Stream<$className> $streamName;');
+    writeln();
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.write('Stream controller for [$streamName].');
+    }));
+    writeln('StreamController<$className> _$streamName;');
+    fieldInitializationCode.add(collectCode(() {
+      writeln('_$streamName = new StreamController<$className>(sync: true);');
+      writeln('$streamName = _$streamName.stream.asBroadcastStream();');
+    }));
+    notificationSwitchContents.add(collectCode(() {
+      writeln('case ${JSON.encode(notification.longEvent)}:');
+      indent(() {
+        String paramsValidator = camelJoin(
+            ['is', notification.domainName, notification.event, 'params']);
+        writeln('outOfTestExpect(params, $paramsValidator);');
+        String constructorCall;
+        if (notification.params == null) {
+          constructorCall = 'new $className()';
+        } else {
+          constructorCall =
+              "new $className.fromJson(decoder, 'params', params)";
+        }
+        writeln('_$streamName.add($constructorCall);');
+        writeln('break;');
+      });
+    }));
+  }
+
+  @override
+  visitRequest(Request request) {
+    String methodName = camelJoin(['send', request.domainName, request.method]);
+    List<String> args = <String>[];
+    List<String> optionalArgs = <String>[];
+    if (request.params != null) {
+      for (TypeObjectField field in request.params.fields) {
+        if (field.optional) {
+          optionalArgs.add(formatArgument(field));
+        } else {
+          args.add(formatArgument(field));
+        }
+      }
+    }
+    if (optionalArgs.isNotEmpty) {
+      args.add('{${optionalArgs.join(', ')}}');
+    }
+    writeln();
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.translateHtml(request.html);
+      toHtmlVisitor.describePayload(request.params, 'Parameters');
+      toHtmlVisitor.describePayload(request.result, 'Returns');
+    }));
+    String resultClass;
+    String futureClass;
+    if (request.result == null) {
+      futureClass = 'Future';
+    } else {
+      resultClass = camelJoin([request.domainName, request.method, 'result'],
+          doCapitalize: true);
+      futureClass = 'Future<$resultClass>';
+    }
+    writeln('$futureClass $methodName(${args.join(', ')}) async {');
+    indent(() {
+      String requestClass = camelJoin(
+          [request.domainName, request.method, 'params'],
+          doCapitalize: true);
+      String paramsVar = 'null';
+      if (request.params != null) {
+        paramsVar = 'params';
+        List<String> args = <String>[];
+        List<String> optionalArgs = <String>[];
+        for (TypeObjectField field in request.params.fields) {
+          if (field.optional) {
+            optionalArgs.add('${field.name}: ${field.name}');
+          } else {
+            args.add(field.name);
+          }
+        }
+        args.addAll(optionalArgs);
+        writeln('var params = new $requestClass(${args.join(', ')}).toJson();');
+      }
+      String methodJson = JSON.encode(request.longMethod);
+      writeln('var result = await server.send($methodJson, $paramsVar);');
+      if (request.result != null) {
+        String kind = 'null';
+        if (requestClass == 'EditGetRefactoringParams') {
+          kind = 'kind';
+        }
+        writeln('ResponseDecoder decoder = new ResponseDecoder($kind);');
+        writeln("return new $resultClass.fromJson(decoder, 'result', result);");
+      } else {
+        writeln('outOfTestExpect(result, isNull);');
+        writeln('return null;');
+      }
+    });
+    writeln('}');
+  }
+}
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_matchers.dart b/pkg/analyzer_plugin/tool/spec/codegen_matchers.dart
new file mode 100644
index 0000000..1d18ef7
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/codegen_matchers.dart
@@ -0,0 +1,187 @@
+// 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.
+
+/**
+ * Code generation for the file "matchers.dart".
+ */
+import 'dart:convert';
+
+import 'package:analyzer/src/codegen/tools.dart';
+
+import 'api.dart';
+import 'from_html.dart';
+import 'implied_types.dart';
+import 'to_html.dart';
+
+final GeneratedFile target = new GeneratedFile(
+    'test/integration/support/protocol_matchers.dart', (String pkgPath) {
+  CodegenMatchersVisitor visitor = new CodegenMatchersVisitor(readApi(pkgPath));
+  return visitor.collectCode(visitor.visitApi);
+});
+
+class CodegenMatchersVisitor extends HierarchicalApiVisitor with CodeGenerator {
+  /**
+   * Visitor used to produce doc comments.
+   */
+  final ToHtmlVisitor toHtmlVisitor;
+
+  /**
+   * Short human-readable string describing the context of the matcher being
+   * created.
+   */
+  String context;
+
+  CodegenMatchersVisitor(Api api)
+      : toHtmlVisitor = new ToHtmlVisitor(api),
+        super(api) {
+    codeGeneratorSettings.commentLineLength = 79;
+    codeGeneratorSettings.languageName = 'dart';
+  }
+
+  /**
+   * Create a matcher for the part of the API called [name], optionally
+   * clarified by [nameSuffix].  The matcher should verify that its input
+   * matches the given [type].
+   */
+  void makeMatcher(ImpliedType impliedType) {
+    context = impliedType.humanReadableName;
+    docComment(toHtmlVisitor.collectHtml(() {
+      toHtmlVisitor.p(() {
+        toHtmlVisitor.write(context);
+      });
+      if (impliedType.type != null) {
+        toHtmlVisitor.showType(null, impliedType.type);
+      }
+    }));
+    write('final Matcher ${camelJoin(['is', impliedType.camelName])} = ');
+    if (impliedType.type == null) {
+      write('isNull');
+    } else {
+      visitTypeDecl(impliedType.type);
+    }
+    writeln(';');
+    writeln();
+  }
+
+  /**
+   * Generate a map describing the given set of fields, for use as the
+   * 'requiredFields' or 'optionalFields' argument to the [MatchesJsonObject]
+   * constructor.
+   */
+  void outputObjectFields(Iterable<TypeObjectField> fields) {
+    if (fields.isEmpty) {
+      write('null');
+      return;
+    }
+    writeln('{');
+    indent(() {
+      bool commaNeeded = false;
+      for (TypeObjectField field in fields) {
+        if (commaNeeded) {
+          writeln(',');
+        }
+        write('${JSON.encode(field.name)}: ');
+        if (field.value != null) {
+          write('equals(${JSON.encode(field.value)})');
+        } else {
+          visitTypeDecl(field.type);
+        }
+        commaNeeded = true;
+      }
+      writeln();
+    });
+    write('}');
+  }
+
+  @override
+  visitApi() {
+    outputHeader(year: '2017');
+    writeln();
+    writeln('/**');
+    writeln(' * Matchers for data types defined in the analysis server API');
+    writeln(' */');
+    writeln("import 'package:test/test.dart';");
+    writeln();
+    writeln("import 'integration_tests.dart';");
+    writeln();
+    for (ImpliedType impliedType in computeImpliedTypes(api).values) {
+      makeMatcher(impliedType);
+    }
+  }
+
+  @override
+  visitTypeEnum(TypeEnum typeEnum) {
+    writeln('new MatchesEnum(${JSON.encode(context)}, [');
+    indent(() {
+      bool commaNeeded = false;
+      for (TypeEnumValue value in typeEnum.values) {
+        if (commaNeeded) {
+          writeln(',');
+        }
+        write('${JSON.encode(value.value)}');
+        commaNeeded = true;
+      }
+      writeln();
+    });
+    write('])');
+  }
+
+  @override
+  visitTypeList(TypeList typeList) {
+    write('isListOf(');
+    visitTypeDecl(typeList.itemType);
+    write(')');
+  }
+
+  @override
+  visitTypeMap(TypeMap typeMap) {
+    write('isMapOf(');
+    visitTypeDecl(typeMap.keyType);
+    write(', ');
+    visitTypeDecl(typeMap.valueType);
+    write(')');
+  }
+
+  @override
+  void visitTypeObject(TypeObject typeObject) {
+    writeln('new LazyMatcher(() => new MatchesJsonObject(');
+    indent(() {
+      write('${JSON.encode(context)}, ');
+      Iterable<TypeObjectField> requiredFields =
+          typeObject.fields.where((TypeObjectField field) => !field.optional);
+      outputObjectFields(requiredFields);
+      List<TypeObjectField> optionalFields = typeObject.fields
+          .where((TypeObjectField field) => field.optional)
+          .toList();
+      if (optionalFields.isNotEmpty) {
+        write(', optionalFields: ');
+        outputObjectFields(optionalFields);
+      }
+    });
+    write('))');
+  }
+
+  @override
+  void visitTypeReference(TypeReference typeReference) {
+    String typeName = typeReference.typeName;
+    if (typeName == 'long') {
+      typeName = 'int';
+    }
+    write(camelJoin(['is', typeName]));
+  }
+
+  @override
+  void visitTypeUnion(TypeUnion typeUnion) {
+    bool commaNeeded = false;
+    write('isOneOf([');
+    for (TypeDecl choice in typeUnion.choices) {
+      if (commaNeeded) {
+        write(', ');
+      }
+      visitTypeDecl(choice);
+      commaNeeded = true;
+    }
+    write('])');
+  }
+}
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart b/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart
new file mode 100644
index 0000000..270edc0
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart
@@ -0,0 +1,161 @@
+// 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:analyzer/src/codegen/tools.dart';
+
+import 'api.dart';
+import 'codegen_dart.dart';
+import 'from_html.dart';
+
+final GeneratedFile target =
+    new GeneratedFile('lib/protocol/protocol_constants.dart', (String pkgPath) {
+  CodegenVisitor visitor = new CodegenVisitor(readApi(pkgPath));
+  return visitor.collectCode(visitor.visitApi);
+});
+
+/**
+ * A visitor that produces Dart code defining constants associated with the API.
+ */
+class CodegenVisitor extends DartCodegenVisitor with CodeGenerator {
+  CodegenVisitor(Api api) : super(api) {
+    codeGeneratorSettings.commentLineLength = 79;
+    codeGeneratorSettings.languageName = 'dart';
+  }
+
+  /**
+   * Generate all of the constants associates with the [api].
+   */
+  void generateConstants() {
+    _ConstantVisitor visitor = new _ConstantVisitor(api);
+    visitor.visitApi();
+    List<_Constant> constants = visitor.constants;
+    constants.sort((first, second) => first.name.compareTo(second.name));
+    for (_Constant constant in constants) {
+      generateContant(constant);
+    }
+  }
+
+  /**
+   * Generate the given [constant].
+   */
+  void generateContant(_Constant constant) {
+    write('const String ');
+    write(constant.name);
+    write(' = ');
+    write(constant.value);
+    writeln(';');
+  }
+
+  @override
+  visitApi() {
+    outputHeader(year: '2017');
+    writeln();
+    generateConstants();
+  }
+}
+
+/**
+ * A representation of a constant that is to be generated.
+ */
+class _Constant {
+  /**
+   * The name of the constant.
+   */
+  final String name;
+
+  /**
+   * The value of the constant.
+   */
+  final String value;
+
+  /**
+   * Initialize a newly created constant.
+   */
+  _Constant(this.name, this.value);
+}
+
+/**
+ * A visitor that visits an API to compute a list of constants to be generated.
+ */
+class _ConstantVisitor extends HierarchicalApiVisitor {
+  /**
+   * The list of constants to be generated.
+   */
+  List<_Constant> constants = <_Constant>[];
+
+  /**
+   * Initialize a newly created visitor to visit the given [api].
+   */
+  _ConstantVisitor(Api api) : super(api);
+
+  @override
+  void visitNotification(Notification notification) {
+    String domainName = notification.domainName;
+    String event = notification.event;
+
+    String constantName = _generateName(domainName, 'notification', event);
+    constants.add(new _Constant(constantName, "'$domainName.$event'"));
+    _addFieldConstants(constantName, notification.params);
+  }
+
+  @override
+  void visitRequest(Request request) {
+    String domainName = request.domainName;
+    String method = request.method;
+
+    String requestConstantName = _generateName(domainName, 'request', method);
+    constants.add(new _Constant(requestConstantName, "'$domainName.$method'"));
+    _addFieldConstants(requestConstantName, request.params);
+
+    String responseConstantName = _generateName(domainName, 'response', method);
+    _addFieldConstants(responseConstantName, request.result);
+  }
+
+  /**
+   * Generate a constant for each of the fields in the given [type], where the
+   * name of each constant will be composed from the [parentName] and the name
+   * of the field.
+   */
+  void _addFieldConstants(String parentName, TypeObject type) {
+    if (type == null) {
+      return;
+    }
+    type.fields.forEach((TypeObjectField field) {
+      String name = field.name;
+      String fieldConstantName = parentName + '_' + name.toUpperCase();
+      constants.add(new _Constant(fieldConstantName, "'$name'"));
+    });
+  }
+
+  /**
+   * Generate a name from the [domainName], [kind] and [name] components.
+   */
+  String _generateName(String domainName, String kind, String name) {
+    List<String> components = <String>[];
+    components.addAll(_split(domainName));
+    components.add(kind);
+    components.addAll(_split(name));
+    return components
+        .map((String component) => component.toUpperCase())
+        .join('_');
+  }
+
+  /**
+   * Return the components of the given [string] that are indicated by an upper
+   * case letter.
+   */
+  Iterable<String> _split(String first) {
+    RegExp regExp = new RegExp('[A-Z]');
+    List<String> components = <String>[];
+    int start = 1;
+    int index = first.indexOf(regExp, start);
+    while (index >= 0) {
+      components.add(first.substring(start - 1, index));
+      start = index + 1;
+      index = first.indexOf(regExp, start);
+    }
+    components.add(first.substring(start - 1));
+    return components;
+  }
+}
diff --git a/pkg/analyzer_plugin/tool/spec/from_html.dart b/pkg/analyzer_plugin/tool/spec/from_html.dart
new file mode 100644
index 0000000..11aa5ad
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/from_html.dart
@@ -0,0 +1,553 @@
+// 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.
+
+/**
+ * Code for reading an HTML API description.
+ */
+import 'dart:io';
+
+import 'package:analyzer/src/codegen/html.dart';
+import 'package:html/dom.dart' as dom;
+import 'package:html/parser.dart' as parser;
+import 'package:path/path.dart';
+
+import 'api.dart';
+
+const List<String> specialElements = const [
+  'domain',
+  'feedback',
+  'object',
+  'refactorings',
+  'refactoring',
+  'type',
+  'types',
+  'request',
+  'notification',
+  'params',
+  'result',
+  'field',
+  'list',
+  'map',
+  'enum',
+  'key',
+  'value',
+  'options',
+  'ref',
+  'code',
+  'version',
+  'union',
+  'index'
+];
+
+/**
+ * Create an [Api] object from an HTML representation such as:
+ *
+ * <html>
+ *   ...
+ *   <body>
+ *     ... <version>1.0</version> ...
+ *     <domain name="...">...</domain> <!-- zero or more -->
+ *     <types>...</types>
+ *     <refactorings>...</refactorings>
+ *   </body>
+ * </html>
+ *
+ * Child elements of <api> can occur in any order.
+ */
+Api apiFromHtml(dom.Element html) {
+  Api api;
+  List<String> versions = <String>[];
+  List<Domain> domains = <Domain>[];
+  Types types = null;
+  Refactorings refactorings = null;
+  recurse(html, 'api', {
+    'domain': (dom.Element element) {
+      domains.add(domainFromHtml(element));
+    },
+    'refactorings': (dom.Element element) {
+      refactorings = refactoringsFromHtml(element);
+    },
+    'types': (dom.Element element) {
+      types = typesFromHtml(element);
+    },
+    'version': (dom.Element element) {
+      versions.add(innerText(element));
+    },
+    'index': (dom.Element element) {
+      /* Ignore; generated dynamically. */
+    }
+  });
+  if (versions.length != 1) {
+    throw new Exception('The API must contain exactly one <version> element');
+  }
+  api = new Api(versions[0], domains, types, refactorings, html);
+  return api;
+}
+
+/**
+ * Check that the given [element] has all of the attributes in
+ * [requiredAttributes], possibly some of the attributes in
+ * [optionalAttributes], and no others.
+ */
+void checkAttributes(
+    dom.Element element, List<String> requiredAttributes, String context,
+    {List<String> optionalAttributes: const []}) {
+  Set<String> attributesFound = new Set<String>();
+  element.attributes.forEach((String name, String value) {
+    if (!requiredAttributes.contains(name) &&
+        !optionalAttributes.contains(name)) {
+      throw new Exception(
+          '$context: Unexpected attribute in ${element.localName}: $name');
+    }
+    attributesFound.add(name);
+  });
+  for (String expectedAttribute in requiredAttributes) {
+    if (!attributesFound.contains(expectedAttribute)) {
+      throw new Exception(
+          '$context: ${element.localName} must contain attribute $expectedAttribute');
+    }
+  }
+}
+
+/**
+ * Check that the given [element] has the given [expectedName].
+ */
+void checkName(dom.Element element, String expectedName, [String context]) {
+  if (element.localName != expectedName) {
+    if (context == null) {
+      context = element.localName;
+    }
+    throw new Exception(
+        '$context: Expected $expectedName, found ${element.localName}');
+  }
+}
+
+/**
+ * Create a [Domain] object from an HTML representation such as:
+ *
+ * <domain name="domainName">
+ *   <request method="...">...</request> <!-- zero or more -->
+ *   <notification event="...">...</notification> <!-- zero or more -->
+ * </domain>
+ *
+ * Child elements can occur in any order.
+ */
+Domain domainFromHtml(dom.Element html) {
+  checkName(html, 'domain');
+  String name = html.attributes['name'];
+  String context = name ?? 'domain';
+  bool experimental = html.attributes['experimental'] == 'true';
+  checkAttributes(html, ['name'], context,
+      optionalAttributes: ['experimental']);
+  List<Request> requests = <Request>[];
+  List<Notification> notifications = <Notification>[];
+  recurse(html, context, {
+    'request': (dom.Element child) {
+      requests.add(requestFromHtml(child, context));
+    },
+    'notification': (dom.Element child) {
+      notifications.add(notificationFromHtml(child, context));
+    }
+  });
+  return new Domain(name, requests, notifications, html,
+      experimental: experimental);
+}
+
+dom.Element getAncestor(dom.Element html, String name, String context) {
+  dom.Element ancestor = html.parent;
+  while (ancestor != null) {
+    if (ancestor.localName == name) {
+      return ancestor;
+    }
+    ancestor = ancestor.parent;
+  }
+  throw new Exception(
+      '$context: <${html.localName}> must be nested within <$name>');
+}
+
+/**
+ * Create a [Notification] object from an HTML representation such as:
+ *
+ * <notification event="methodName">
+ *   <params>...</params> <!-- optional -->
+ * </notification>
+ *
+ * Note that the event name should not include the domain name.
+ *
+ * <params> has the same form as <object>, as described in [typeDeclFromHtml].
+ *
+ * Child elements can occur in any order.
+ */
+Notification notificationFromHtml(dom.Element html, String context) {
+  String domainName = getAncestor(html, 'domain', context).attributes['name'];
+  checkName(html, 'notification', context);
+  String event = html.attributes['event'];
+  context = '$context.${event != null ? event : 'event'}';
+  checkAttributes(html, ['event'], context);
+  TypeDecl params;
+  recurse(html, context, {
+    'params': (dom.Element child) {
+      params = typeObjectFromHtml(child, '$context.params');
+    }
+  });
+  return new Notification(domainName, event, params, html);
+}
+
+/**
+ * Create a single of [TypeDecl] corresponding to the type defined inside the
+ * given HTML element.
+ */
+TypeDecl processContentsAsType(dom.Element html, String context) {
+  List<TypeDecl> types = processContentsAsTypes(html, context);
+  if (types.length != 1) {
+    throw new Exception('$context: Exactly one type must be specified');
+  }
+  return types[0];
+}
+
+/**
+ * Create a list of [TypeDecl]s corresponding to the types defined inside the
+ * given HTML element.  The following forms are supported.
+ *
+ * To refer to a type declared elsewhere (or a built-in type):
+ *
+ *   <ref>typeName</ref>
+ *
+ * For a list: <list>ItemType</list>
+ *
+ * For a map: <map><key>KeyType</key><value>ValueType</value></map>
+ *
+ * For a JSON object:
+ *
+ *   <object>
+ *     <field name="...">...</field> <!-- zero or more -->
+ *   </object>
+ *
+ * For an enum:
+ *
+ *   <enum>
+ *     <value>...</value> <!-- zero or more -->
+ *   </enum>
+ *
+ * For a union type:
+ *   <union>
+ *     TYPE <!-- zero or more -->
+ *   </union>
+ */
+List<TypeDecl> processContentsAsTypes(dom.Element html, String context) {
+  List<TypeDecl> types = <TypeDecl>[];
+  recurse(html, context, {
+    'object': (dom.Element child) {
+      types.add(typeObjectFromHtml(child, context));
+    },
+    'list': (dom.Element child) {
+      checkAttributes(child, [], context);
+      types.add(new TypeList(processContentsAsType(child, context), child));
+    },
+    'map': (dom.Element child) {
+      checkAttributes(child, [], context);
+      TypeDecl keyType;
+      TypeDecl valueType;
+      recurse(child, context, {
+        'key': (dom.Element child) {
+          if (keyType != null) {
+            throw new Exception('$context: Key type already specified');
+          }
+          keyType = processContentsAsType(child, '$context.key');
+        },
+        'value': (dom.Element child) {
+          if (valueType != null) {
+            throw new Exception('$context: Value type already specified');
+          }
+          valueType = processContentsAsType(child, '$context.value');
+        }
+      });
+      if (keyType == null) {
+        throw new Exception('$context: Key type not specified');
+      }
+      if (valueType == null) {
+        throw new Exception('$context: Value type not specified');
+      }
+      types.add(new TypeMap(keyType, valueType, child));
+    },
+    'enum': (dom.Element child) {
+      types.add(typeEnumFromHtml(child, context));
+    },
+    'ref': (dom.Element child) {
+      checkAttributes(child, [], context);
+      types.add(new TypeReference(innerText(child), child));
+    },
+    'union': (dom.Element child) {
+      checkAttributes(child, ['field'], context);
+      String field = child.attributes['field'];
+      types.add(
+          new TypeUnion(processContentsAsTypes(child, context), field, child));
+    }
+  });
+  return types;
+}
+
+/**
+ * Read the API description from the file 'spec_input.html'.  [pkgPath] is the
+ * path to the current package.
+ */
+Api readApi(String pkgPath) {
+  File htmlFile = new File(join(pkgPath, 'tool', 'spec', 'plugin_spec.html'));
+  String htmlContents = htmlFile.readAsStringSync();
+  dom.Document document = parser.parse(htmlContents);
+  dom.Element htmlElement = document.children
+      .singleWhere((element) => element.localName.toLowerCase() == 'html');
+  return apiFromHtml(htmlElement);
+}
+
+void recurse(dom.Element parent, String context,
+    Map<String, ElementProcessor> elementProcessors) {
+  for (String key in elementProcessors.keys) {
+    if (!specialElements.contains(key)) {
+      throw new Exception('$context: $key is not a special element');
+    }
+  }
+  for (dom.Node node in parent.nodes) {
+    if (node is dom.Element) {
+      if (elementProcessors.containsKey(node.localName)) {
+        elementProcessors[node.localName](node);
+      } else if (specialElements.contains(node.localName)) {
+        throw new Exception('$context: Unexpected use of <${node.localName}>');
+      } else {
+        recurse(node, context, elementProcessors);
+      }
+    }
+  }
+}
+
+/**
+ * Create a [Refactoring] object from an HTML representation such as:
+ *
+ * <refactoring kind="refactoringKind">
+ *   <feedback>...</feedback> <!-- optional -->
+ *   <options>...</options> <!-- optional -->
+ * </refactoring>
+ *
+ * <feedback> and <options> have the same form as <object>, as described in
+ * [typeDeclFromHtml].
+ *
+ * Child elements can occur in any order.
+ */
+Refactoring refactoringFromHtml(dom.Element html) {
+  checkName(html, 'refactoring');
+  String kind = html.attributes['kind'];
+  String context = kind != null ? kind : 'refactoring';
+  checkAttributes(html, ['kind'], context);
+  TypeDecl feedback;
+  TypeDecl options;
+  recurse(html, context, {
+    'feedback': (dom.Element child) {
+      feedback = typeObjectFromHtml(child, '$context.feedback');
+    },
+    'options': (dom.Element child) {
+      options = typeObjectFromHtml(child, '$context.options');
+    }
+  });
+  return new Refactoring(kind, feedback, options, html);
+}
+
+/**
+ * Create a [Refactorings] object from an HTML representation such as:
+ *
+ * <refactorings>
+ *   <refactoring kind="...">...</refactoring> <!-- zero or more -->
+ * </refactorings>
+ */
+Refactorings refactoringsFromHtml(dom.Element html) {
+  checkName(html, 'refactorings');
+  String context = 'refactorings';
+  checkAttributes(html, [], context);
+  List<Refactoring> refactorings = <Refactoring>[];
+  recurse(html, context, {
+    'refactoring': (dom.Element child) {
+      refactorings.add(refactoringFromHtml(child));
+    }
+  });
+  return new Refactorings(refactorings, html);
+}
+
+/**
+ * Create a [Request] object from an HTML representation such as:
+ *
+ * <request method="methodName">
+ *   <params>...</params> <!-- optional -->
+ *   <result>...</result> <!-- optional -->
+ * </request>
+ *
+ * Note that the method name should not include the domain name.
+ *
+ * <params> and <result> have the same form as <object>, as described in
+ * [typeDeclFromHtml].
+ *
+ * Child elements can occur in any order.
+ */
+Request requestFromHtml(dom.Element html, String context) {
+  String domainName = getAncestor(html, 'domain', context).attributes['name'];
+  checkName(html, 'request', context);
+  String method = html.attributes['method'];
+  context = '$context.${method != null ? method : 'method'}';
+  checkAttributes(html, ['method'], context);
+  TypeDecl params;
+  TypeDecl result;
+  recurse(html, context, {
+    'params': (dom.Element child) {
+      params = typeObjectFromHtml(child, '$context.params');
+    },
+    'result': (dom.Element child) {
+      result = typeObjectFromHtml(child, '$context.result');
+    }
+  });
+  return new Request(domainName, method, params, result, html);
+}
+
+/**
+ * Create a [TypeDefinition] object from an HTML representation such as:
+ *
+ * <type name="typeName">
+ *   TYPE
+ * </type>
+ *
+ * Where TYPE is any HTML that can be parsed by [typeDeclFromHtml].
+ *
+ * Child elements can occur in any order.
+ */
+TypeDefinition typeDefinitionFromHtml(dom.Element html) {
+  checkName(html, 'type');
+  String name = html.attributes['name'];
+  String context = name != null ? name : 'type';
+  checkAttributes(html, ['name'], context,
+      optionalAttributes: ['experimental']);
+  TypeDecl type = processContentsAsType(html, context);
+  bool experimental = html.attributes['experimental'] == 'true';
+  return new TypeDefinition(name, type, html, experimental: experimental);
+}
+
+/**
+ * Create a [TypeEnum] from an HTML description.
+ */
+TypeEnum typeEnumFromHtml(dom.Element html, String context) {
+  checkName(html, 'enum', context);
+  checkAttributes(html, [], context);
+  List<TypeEnumValue> values = <TypeEnumValue>[];
+  recurse(html, context, {
+    'value': (dom.Element child) {
+      values.add(typeEnumValueFromHtml(child, context));
+    }
+  });
+  return new TypeEnum(values, html);
+}
+
+/**
+ * Create a [TypeEnumValue] from an HTML description such as:
+ *
+ * <enum>
+ *   <code>VALUE</code>
+ * </enum>
+ *
+ * Where VALUE is the text of the enumerated value.
+ *
+ * Child elements can occur in any order.
+ */
+TypeEnumValue typeEnumValueFromHtml(dom.Element html, String context) {
+  checkName(html, 'value', context);
+  checkAttributes(html, [], context);
+  List<String> values = <String>[];
+  recurse(html, context, {
+    'code': (dom.Element child) {
+      String text = innerText(child).trim();
+      values.add(text);
+    }
+  });
+  if (values.length != 1) {
+    throw new Exception('$context: Exactly one value must be specified');
+  }
+  return new TypeEnumValue(values[0], html);
+}
+
+/**
+ * Create a [TypeObjectField] from an HTML description such as:
+ *
+ * <field name="fieldName">
+ *   TYPE
+ * </field>
+ *
+ * Where TYPE is any HTML that can be parsed by [typeDeclFromHtml].
+ *
+ * In addition, the attribute optional="true" may be used to specify that the
+ * field is optional, and the attribute value="..." may be used to specify that
+ * the field is required to have a certain value.
+ *
+ * Child elements can occur in any order.
+ */
+TypeObjectField typeObjectFieldFromHtml(dom.Element html, String context) {
+  checkName(html, 'field', context);
+  String name = html.attributes['name'];
+  context = '$context.${name != null ? name : 'field'}';
+  checkAttributes(html, ['name'], context,
+      optionalAttributes: ['optional', 'value']);
+  bool optional = false;
+  String optionalString = html.attributes['optional'];
+  if (optionalString != null) {
+    switch (optionalString) {
+      case 'true':
+        optional = true;
+        break;
+      case 'false':
+        optional = false;
+        break;
+      default:
+        throw new Exception(
+            '$context: field contains invalid "optional" attribute: "$optionalString"');
+    }
+  }
+  String value = html.attributes['value'];
+  TypeDecl type = processContentsAsType(html, context);
+  return new TypeObjectField(name, type, html,
+      optional: optional, value: value);
+}
+
+/**
+ * Create a [TypeObject] from an HTML description.
+ */
+TypeObject typeObjectFromHtml(dom.Element html, String context) {
+  checkAttributes(html, [], context, optionalAttributes: ['experimental']);
+  List<TypeObjectField> fields = <TypeObjectField>[];
+  recurse(html, context, {
+    'field': (dom.Element child) {
+      fields.add(typeObjectFieldFromHtml(child, context));
+    }
+  });
+  bool experimental = html.attributes['experimental'] == 'true';
+  return new TypeObject(fields, html, experimental: experimental);
+}
+
+/**
+ * Create a [Types] object from an HTML representation such as:
+ *
+ * <types>
+ *   <type name="...">...</type> <!-- zero or more -->
+ * </types>
+ */
+Types typesFromHtml(dom.Element html) {
+  checkName(html, 'types');
+  String context = 'types';
+  checkAttributes(html, [], context);
+  Map<String, TypeDefinition> types = <String, TypeDefinition>{};
+  recurse(html, context, {
+    'type': (dom.Element child) {
+      TypeDefinition typeDefinition = typeDefinitionFromHtml(child);
+      types[typeDefinition.name] = typeDefinition;
+    }
+  });
+  return new Types(types, html);
+}
+
+typedef void ElementProcessor(dom.Element element);
+
+typedef void TextProcessor(dom.Text text);
diff --git a/pkg/analyzer_plugin/tool/spec/generate_all.dart b/pkg/analyzer_plugin/tool/spec/generate_all.dart
new file mode 100644
index 0000000..f0c4065
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/generate_all.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:analyzer/src/codegen/tools.dart';
+import 'package:path/path.dart';
+
+import 'codegen_dart_protocol.dart' as codegen_dart_protocol;
+import 'codegen_inttest_methods.dart' as codegen_inttest_methods;
+import 'codegen_matchers.dart' as codegen_matchers;
+import 'codegen_protocol_constants.dart' as codegen_protocol_constants;
+import 'to_html.dart' as to_html;
+
+/**
+ * Generate all targets.
+ */
+main() {
+  String script = Platform.script.toFilePath(windows: Platform.isWindows);
+  String pkgPath = normalize(join(dirname(script), '..', '..'));
+  GeneratedContent.generateAll(pkgPath, allTargets);
+}
+
+/**
+ * Get a list of all generated targets.
+ */
+List<GeneratedContent> get allTargets {
+  List<GeneratedContent> targets = <GeneratedContent>[];
+//  targets.add(codegen_analysis_server.target);
+  targets.add(codegen_dart_protocol.target);
+  targets.add(codegen_inttest_methods.target);
+  targets.add(codegen_matchers.target);
+  targets.add(codegen_protocol_constants.target);
+  targets.add(to_html.target);
+  return targets;
+}
diff --git a/pkg/analyzer_plugin/tool/spec/generate_files b/pkg/analyzer_plugin/tool/spec/generate_files
new file mode 100755
index 0000000..f958926
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/generate_files
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# 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 script generates the following files, based on the contents of
+# spec_input.html:
+#
+# - ../../doc/api.html: The human-readable API spec.
+#
+# - ../../test/integration/protocol_matchers.dart: matchers to be used by
+#   integration tests.
+#
+# - ../../test/integration/integration_test_methods.dart: convenience methods
+#   to be used by integration tests.
+
+set -e
+
+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")"
+
+SCRIPT_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+ROOT_DIR="$(cd "${SCRIPT_DIR}/../../../.." ; pwd -P)"
+
+if [[ $1 == '--arch' && $2 == 'x64' ]];
+then
+  DART_CONFIGURATION="ReleaseX64"
+elif [ -z "$DART_CONFIGURATION" ];
+then
+  DART_CONFIGURATION="ReleaseIA32"
+fi
+
+if [[ `uname` == 'Darwin' ]];
+then
+  if [[ $GYP_GENERATORS == 'ninja' ]];
+  then
+    BUILD_DIR="${ROOT_DIR}/out/$DART_CONFIGURATION"
+  else
+    BUILD_DIR="${ROOT_DIR}/xcodebuild/$DART_CONFIGURATION"
+  fi
+fi
+
+PKG_FILE="${ROOT_DIR}/pkg/analysis_server/.packages"
+if [[ !(-e $PKG_FILE) ]];
+then
+  PKG_FILE="${ROOT_DIR}/.packages"
+fi
+
+DART="${BUILD_DIR}/dart-sdk/bin/dart"
+
+declare -a VM_OPTIONS
+VM_OPTIONS+=("--checked")
+VM_OPTIONS+=("--packages=${PKG_FILE}")
+
+echo "${SCRIPT_DIR}"
+echo "${DART}" "${VM_OPTIONS[@]}" "generate_all.dart"
+cd "${SCRIPT_DIR}"
+"${DART}" "${VM_OPTIONS[@]}" "generate_all.dart"
diff --git a/pkg/analyzer_plugin/tool/spec/implied_types.dart b/pkg/analyzer_plugin/tool/spec/implied_types.dart
new file mode 100644
index 0000000..e7086fe
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/implied_types.dart
@@ -0,0 +1,89 @@
+// 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.
+
+/**
+ * Code for enumerating the set of types implied by the API.
+ */
+import 'package:analyzer/src/codegen/tools.dart';
+
+import 'api.dart';
+
+Map<String, ImpliedType> computeImpliedTypes(Api api) {
+  _ImpliedTypesVisitor visitor = new _ImpliedTypesVisitor(api);
+  visitor.visitApi();
+  return visitor.impliedTypes;
+}
+
+class ImpliedType {
+  final String camelName;
+  final String humanReadableName;
+  final TypeDecl type;
+
+  /**
+   * Kind of implied type this is.  One of:
+   * - 'requestParams'
+   * - 'requestResult'
+   * - 'notificationParams'
+   * - 'refactoringFeedback'
+   * - 'refactoringOptions'
+   * - 'typeDefinition'
+   */
+  final String kind;
+
+  /**
+   * API node from which this type was inferred.
+   */
+  final ApiNode apiNode;
+
+  ImpliedType(this.camelName, this.humanReadableName, this.type, this.kind,
+      this.apiNode);
+}
+
+class _ImpliedTypesVisitor extends HierarchicalApiVisitor {
+  Map<String, ImpliedType> impliedTypes = <String, ImpliedType>{};
+
+  _ImpliedTypesVisitor(Api api) : super(api);
+
+  void storeType(String name, String nameSuffix, TypeDecl type, String kind,
+      ApiNode apiNode) {
+    String humanReadableName = name;
+    List<String> camelNameParts = name.split('.');
+    if (nameSuffix != null) {
+      humanReadableName += ' $nameSuffix';
+      camelNameParts.add(nameSuffix);
+    }
+    String camelName = camelJoin(camelNameParts);
+    impliedTypes[camelName] =
+        new ImpliedType(camelName, humanReadableName, type, kind, apiNode);
+  }
+
+  @override
+  visitNotification(Notification notification) {
+    storeType(notification.longEvent, 'params', notification.params,
+        'notificationParams', notification);
+  }
+
+  @override
+  visitRefactoring(Refactoring refactoring) {
+    String camelKind = camelJoin(refactoring.kind.toLowerCase().split('_'));
+    storeType(camelKind, 'feedback', refactoring.feedback,
+        'refactoringFeedback', refactoring);
+    storeType(camelKind, 'options', refactoring.options, 'refactoringOptions',
+        refactoring);
+  }
+
+  @override
+  visitRequest(Request request) {
+    storeType(
+        request.longMethod, 'params', request.params, 'requestParams', request);
+    storeType(
+        request.longMethod, 'result', request.result, 'requestResult', request);
+  }
+
+  @override
+  visitTypeDefinition(TypeDefinition typeDefinition) {
+    storeType(typeDefinition.name, null, typeDefinition.type, 'typeDefinition',
+        typeDefinition);
+  }
+}
diff --git a/pkg/analyzer_plugin/tool/spec/plugin_spec.html b/pkg/analyzer_plugin/tool/spec/plugin_spec.html
new file mode 100644
index 0000000..461ff9a
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/plugin_spec.html
@@ -0,0 +1,2807 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset="UTF-8"/>
+  <title>Analysis Server Plugin API Specification</title>
+</head>
+<body>
+<h1>Analysis Server Plugin API Specification</h1>
+<h1 style="color:#999999">Version
+  <version>1.0.0-alpha.0</version>
+</h1>
+<p>
+  This document contains a specification of the API used by the analysis
+  server to communicate with analysis server plugins. Changes to the API will be
+  accompanied by an update to the protocol version number according to the
+  principles of semantic versioning
+  (<a href="http://semver.org/">semver.org</a>).
+</p>
+<h2>Overview</h2>
+<p>
+  TBD
+</p>
+<domain name="plugin">
+  <p>
+    The plugin domain contains API’s related to the execution of a plugin.
+  </p>
+  <p>
+    TODO: Provide notifications by which plugins can report instrumentation
+    and/or DartSilo data.
+  </p>
+  <p>
+    TODO: Add a notification to the server protocol to inform the client of
+    problems related to the execution of plugins.
+  </p>
+  <request method="versionCheck">
+    <p>
+      Used to request that the plugin perform a version check to confirm that it
+      works with the version of the analysis server that is executing it.
+    </p>
+    <params>
+      <field name="byteStorePath">
+        <ref>String</ref>
+        <p>
+          The path to the directory containing the on-disk byte store that is to
+          be used by any analysis drivers that are created.
+        </p>
+      </field>
+      <field name="version">
+        <ref>String</ref>
+        <p>
+          The version number of the plugin spec supported by the analysis server
+          that is executing the plugin.
+        </p>
+      </field>
+    </params>
+    <result>
+      <field name="isCompatible">
+        <ref>bool</ref>
+        <p>
+          A flag indicating whether the plugin supports the same version of the
+          plugin spec as the analysis server. If the value is <tt>false</tt>,
+          then the plugin is expected to shutdown after returning the response.
+        </p>
+      </field>
+      <field name="name">
+        <ref>String</ref>
+        <p>
+          The name of the plugin. This value is only used when the server needs
+          to identify the plugin, either to the user or for debugging purposes.
+        </p>
+      </field>
+      <field name="version">
+        <ref>String</ref>
+        <p>
+          The version of the plugin. This value is only used when the server
+          needs to identify the plugin, either to the user or for debugging
+          purposes.
+        </p>
+      </field>
+      <field name="contactInfo" optional="true">
+        <ref>String</ref>
+        <p>
+          Information that the user can use to use to contact the maintainers of
+          the plugin when there is a problem.
+        </p>
+      </field>
+      <field name="interestingFiles">
+        <list>
+          <ref>String</ref>
+        </list>
+        <p>
+          The glob patterns of the files for which the plugin will provide
+          information. This value is ignored if the <tt>isCompatible</tt>
+          field is <tt>false</tt>. Otherwise, it will be used to identify
+          the files for which the plugin should be notified of changes.
+        </p>
+      </field>
+    </result>
+  </request>
+  <request method="shutdown">
+    <p>
+      Used to request that the plugin exit. The server will not send any other
+      requests after this request. The plugin should not send any responses or
+      notifications after sending the response to this request.
+    </p>
+  </request>
+  <notification event="error">
+    <p>
+      Used to report that an unexpected error has occurred while executing the
+      plugin. This notification is not used for problems with specific requests
+      (which should be returned as part of the response) but is used for
+      exceptions that occur while performing other tasks, such as analysis or
+      preparing notifications.
+    </p>
+    <params>
+      <field name="isFatal">
+        <ref>bool</ref>
+        <p>
+          A flag indicating whether the error is a fatal error, meaning that the
+          plugin will shutdown automatically after sending this notification. If
+          <tt>true</tt>, the server will not expect any other responses or
+          notifications from the plugin.
+        </p>
+      </field>
+      <field name="message">
+        <ref>String</ref>
+        <p>
+          The error message indicating what kind of error was encountered.
+        </p>
+      </field>
+      <field name="stackTrace">
+        <ref>String</ref>
+        <p>
+          The stack trace associated with the generation of the error, used for
+          debugging the plugin.
+        </p>
+      </field>
+    </params>
+  </notification>
+</domain>
+<domain name="analysis">
+  <p>
+    The analysis domain contains API’s related to the analysis of files.
+  </p>
+  <request method="handleWatchEvents">
+    <p>
+      Used to inform the plugin of changes to files in the file system. Only
+      events associated with files that match the <tt>interestingFiles</tt> glob
+      patterns will be forwarded to the plugin.
+    </p>
+    <params>
+      <field name="events">
+        <list>
+          <ref>WatchEvent</ref>
+        </list>
+        <p>
+          The watch events that the plugin should handle.
+        </p>
+      </field>
+    </params>
+  </request>
+  <request method="reanalyze">
+    <p>
+      Used to force the re-analysis of everything contained in the specified
+      context roots. This should cause all previously computed analysis results
+      to be discarded and recomputed, and should cause all subscribed
+      notifications to be re-sent.
+    </p>
+    <params>
+      <field name="roots" optional="true">
+        <list>
+          <ref>FilePath</ref>
+        </list>
+        <p>
+          A list of the context roots that are to be re-analyzed.
+        </p>
+        <p>
+          If no context roots are provided, then all current context roots
+          should be re-analyzed.
+        </p>
+      </field>
+    </params>
+  </request>
+  <request method="setContextBuilderOptions">
+    <p>
+      Used to set the options used to build analysis contexts. This request will
+      be sent exactly once before any context roots have been specified.
+    </p>
+    <params>
+      <field name="options">
+        <ref>ContextBuilderOptions</ref>
+        <p>
+          The options used to build the analysis contexts.
+        </p>
+      </field>
+    </params>
+  </request>
+  <request method="setContextRoots">
+    <p>
+      Set the list of context roots that should be analyzed.
+    </p>
+    <params>
+      <field name="roots">
+        <list>
+          <ref>ContextRoot</ref>
+        </list>
+        <p>
+          A list of the context roots that should be analyzed.
+        </p>
+      </field>
+    </params>
+  </request>
+  <request method="setPriorityFiles">
+    <p>
+      Used to set the priority files to the files in the given list. A priority
+      file is a file that should be given priority when scheduling which
+      analysis work to do first. The list typically contains those files that
+      are visible to the user and those for which analysis results will have the
+      biggest impact on the user experience. The order of the files within the
+      list is significant: the first file will be given higher priority than
+      the second, the second higher priority than the third, and so on.
+    </p>
+    <params>
+      <field name="files">
+        <list>
+          <ref>FilePath</ref>
+        </list>
+        <p>
+          The files that are to be a priority for analysis.
+        </p>
+      </field>
+    </params>
+  </request>
+  <request method="setSubscriptions">
+    <p>
+      Used to subscribe for services that are specific to individual files. All
+      previous subscriptions should be replaced by the current set of
+      subscriptions. If a given service is not included as a key in the map then
+      no files should be subscribed to the service, exactly as if the service
+      had been included in the map with an explicit empty list of files.
+    </p>
+    <params>
+      <field name="subscriptions">
+        <map>
+          <key>
+            <ref>AnalysisService</ref>
+          </key>
+          <value>
+            <list>
+              <ref>FilePath</ref>
+            </list>
+          </value>
+        </map>
+        <p>
+          A table mapping services to a list of the files being subscribed to
+          the service.
+        </p>
+      </field>
+    </params>
+  </request>
+  <request method="updateContent">
+    <p>
+      Used to update the content of one or more files. Files that were
+      previously updated but not included in this update remain unchanged. This
+      effectively represents an overlay of the filesystem. The files whose
+      content is overridden are therefore seen by the plugin as being files with
+      the given content, even if the files do not exist on the filesystem or if
+      the file path represents the path to a directory on the filesystem.
+    </p>
+    <params>
+      <field name="files">
+        <map>
+          <key>
+            <ref>FilePath</ref>
+          </key>
+          <value>
+            <union field="type">
+              <ref>AddContentOverlay</ref>
+              <ref>ChangeContentOverlay</ref>
+              <ref>RemoveContentOverlay</ref>
+            </union>
+          </value>
+        </map>
+        <p>
+          A table mapping the files whose content has changed to a description
+          of the content change.
+        </p>
+      </field>
+    </params>
+  </request>
+  <notification event="errors">
+    <p>
+      Used to report the errors associated with a given file. The set of errors
+      included in the notification is always a complete list that supersedes any
+      previously reported errors.
+    </p>
+    <p>
+      TODO: Decide whether we need to support the '--no-error-notification'
+      option.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the errors.
+        </p>
+      </field>
+      <field name="errors">
+        <list>
+          <ref>AnalysisError</ref>
+        </list>
+        <p>
+          The errors contained in the file.
+        </p>
+      </field>
+    </params>
+  </notification>
+  <notification event="folding">
+    <p>
+      Used to report the folding regions associated with a given file. Folding
+      regions can be nested, but cannot be overlapping. Nesting occurs when a
+      foldable element, such as a method, is nested inside another foldable
+      element such as a class.
+    </p>
+    <p>
+      Folding regions that overlap a folding region computed by the server, or
+      by one of the other plugins that are currently running, might be dropped
+      by the server in order to present a consistent view to the client.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"FOLDING"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the folding regions.
+        </p>
+      </field>
+      <field name="regions">
+        <list>
+          <ref>FoldingRegion</ref>
+        </list>
+        <p>
+          The folding regions contained in the file.
+        </p>
+      </field>
+    </params>
+  </notification>
+  <notification event="highlights">
+    <p>
+      Used to report the highlight regions associated with a given file. Each
+      highlight region represents a particular syntactic or semantic meaning
+      associated with some range. Note that the highlight regions that are
+      returned can overlap other highlight regions if there is more than one
+      meaning associated with a particular region.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"HIGHLIGHTS"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the highlight regions.
+        </p>
+      </field>
+      <field name="regions">
+        <list>
+          <ref>HighlightRegion</ref>
+        </list>
+        <p>
+          The highlight regions contained in the file.
+        </p>
+      </field>
+    </params>
+  </notification>
+  <notification event="navigation">
+    <p>
+      Used to report the navigation regions associated with a given file. Each
+      navigation region represents a list of targets associated with some range.
+      The lists will usually contain a single target, but can contain more in
+      the case of a part that is included in multiple libraries or in Dart code
+      that is compiled against multiple versions of a package. Note that the
+      navigation regions that are returned should not overlap other navigation
+      regions.
+    </p>
+    <p>
+      Navigation regions that overlap a navigation region computed by the
+      server, or by one of the other plugins that are currently running, might
+      be dropped or modified by the server in order to present a consistent view
+      to the client.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"NAVIGATION"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the navigation regions.
+        </p>
+      </field>
+      <field name="regions">
+        <list>
+          <ref>NavigationRegion</ref>
+        </list>
+        <p>
+          The navigation regions contained in the file.
+        </p>
+      </field>
+      <field name="targets">
+        <list>
+          <ref>NavigationTarget</ref>
+        </list>
+        <p>
+          The navigation targets referenced in the file. They are referenced by
+          <a href="#type_NavigationRegion">NavigationRegion</a>s by their index
+          in this array.
+        </p>
+      </field>
+      <field name="files">
+        <list>
+          <ref>FilePath</ref>
+        </list>
+        <p>
+          The files containing navigation targets referenced in the file. They
+          are referenced by
+          <a href="#type_NavigationTarget">NavigationTarget</a>s by their index
+          in this array.
+        </p>
+      </field>
+    </params>
+  </notification>
+  <notification event="occurrences">
+    <p>
+      Used to report the occurrences of references to elements within a single
+      file. None of the occurrence regions should overlap.
+    </p>
+    <p>
+      Occurrence regions that overlap an occurrence region computed by the
+      server, or by one of the other plugins that are currently running, might
+      be dropped or modified by the server in order to present a consistent view
+      to the client.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"OCCURRENCES"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file in which the references occur.
+        </p>
+      </field>
+      <field name="occurrences">
+        <list>
+          <ref>Occurrences</ref>
+        </list>
+        <p>
+          The occurrences of references to elements within the file.
+        </p>
+      </field>
+    </params>
+  </notification>
+  <notification event="outline">
+    <p>
+      Used to report the outline fragments associated with a single file.
+    </p>
+    <p>
+      The outline fragments will be merged with any outline produced by the
+      server and with any fragments produced by other plugins. If the server
+      cannot create a coherent outline, some fragments might be dropped.
+    </p>
+    <p>
+      This notification should only be sent if the server has subscribed to it
+      by including the value <tt>"OUTLINE"</tt> in the list of services
+      passed in an analysis.setSubscriptions request.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file with which the outline is associated.
+        </p>
+      </field>
+      <field name="outline">
+        <list>
+          <ref>Outline</ref>
+        </list>
+        <p>
+          The outline fragments associated with the file.
+        </p>
+      </field>
+    </params>
+  </notification>
+</domain>
+<domain name="completion">
+  <p>
+    The code completion domain contains API's related to getting code completion
+    suggestions.
+  </p>
+  <request method="getSuggestions">
+    <p>
+      Used to request that completion suggestions for the given offset in the
+      given file be returned.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the point at which suggestions are to be made.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset within the file at which suggestions are to be made.
+        </p>
+      </field>
+    </params>
+    <result>
+      <field name="replacementOffset">
+        <ref>int</ref>
+        <p>
+          The offset of the start of the text to be replaced. This will be
+          different than the offset used to request the completion suggestions
+          if there was a portion of an identifier before the original offset. In
+          particular, the replacementOffset will be the offset of the beginning
+          of said identifier.
+        </p>
+      </field>
+      <field name="replacementLength">
+        <ref>int</ref>
+        <p>
+          The length of the text to be replaced if the remainder of the
+          identifier containing the cursor is to be replaced when the suggestion
+          is applied (that is, the number of characters in the existing
+          identifier).
+        </p>
+      </field>
+      <field name="results">
+        <list>
+          <ref>CompletionSuggestion</ref>
+        </list>
+        <p>
+          The completion suggestions being reported. The notification contains
+          all possible completions at the requested cursor position, even those
+          that do not match the characters the user has already typed. This
+          allows the client to respond to further keystrokes from the user
+          without having to make additional requests.
+        </p>
+      </field>
+    </result>
+  </request>
+</domain>
+<domain name="edit">
+  <p>
+    The edit domain contains API's related to edits that can be applied to the
+    code.
+  </p>
+  <request method="getAssists">
+    <p>
+      Used to request the set of assists that are available at the given
+      location. An assist is distinguished from a refactoring primarily by the
+      fact that it affects a single file and does not require user input in
+      order to be performed.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the code for which assists are being requested.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the code for which assists are being requested.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the code for which assists are being requested.
+        </p>
+      </field>
+    </params>
+    <result>
+      <field name="assists">
+        <list>
+          <ref>PrioritizedSourceChange</ref>
+        </list>
+        <p>
+          The assists that are available at the given location.
+        </p>
+      </field>
+    </result>
+  </request>
+  <request method="getAvailableRefactorings">
+    <p>
+      Used to request a list of the kinds of refactorings that are valid for the
+      given selection in the given file.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the code on which the refactoring would be based.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the code on which the refactoring would be based.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the code on which the refactoring would be based.
+        </p>
+      </field>
+    </params>
+    <result>
+      <field name="kinds">
+        <list>
+          <ref>RefactoringKind</ref>
+        </list>
+        <p>
+          The kinds of refactorings that are valid for the given selection.
+        </p>
+        <p>
+          The list of refactoring kinds is currently limited to those defined by
+          the server API, preventing plugins from adding their own refactorings.
+          However, plugins can support pre-defined refactorings, such as a
+          rename refactoring, at locations not supported by server.
+        </p>
+      </field>
+    </result>
+  </request>
+  <request method="getFixes">
+    <p>
+      Used to request the set of fixes that are available for the errors at a
+      given offset in a given file.
+    </p>
+    <params>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the errors for which fixes are being requested.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset used to select the errors for which fixes will be returned.
+        </p>
+      </field>
+    </params>
+    <result>
+      <field name="fixes">
+        <list>
+          <ref>AnalysisErrorFixes</ref>
+        </list>
+        <p>
+          The fixes that are available for the errors at the given offset.
+        </p>
+      </field>
+    </result>
+  </request>
+  <request method="getRefactoring">
+    <p>
+      Used to request the changes required to perform a refactoring.
+    </p>
+    <params>
+      <field name="kind">
+        <ref>RefactoringKind</ref>
+        <p>
+          The kind of refactoring to be performed.
+        </p>
+      </field>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the code involved in the refactoring.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the region involved in the refactoring.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the region involved in the refactoring.
+        </p>
+      </field>
+      <field name="validateOnly">
+        <ref>bool</ref>
+        <p>
+          True if the client is only requesting that the values of the options
+          be validated and no change be generated.
+        </p>
+      </field>
+      <field name="options" optional="true">
+        <ref>RefactoringOptions</ref>
+        <p>
+          Data used to provide values provided by the user. The structure of the
+          data is dependent on the kind of refactoring being performed. The data
+          that is expected is documented in the section titled
+          <a href="#refactorings">Refactorings</a>, labeled as "Options". This
+          field can be omitted if the refactoring does not require any options
+          or if the values of those options are not known.
+        </p>
+      </field>
+    </params>
+    <result>
+      <field name="initialProblems">
+        <list>
+          <ref>RefactoringProblem</ref>
+        </list>
+        <p>
+          The initial status of the refactoring, that is, problems related to
+          the context in which the refactoring is requested. The list should be
+          empty if there are no known problems.
+        </p>
+      </field>
+      <field name="optionsProblems">
+        <list>
+          <ref>RefactoringProblem</ref>
+        </list>
+        <p>
+          The options validation status, that is, problems in the given options,
+          such as light-weight validation of a new name, flags compatibility,
+          etc. The list should be empty if there are no known problems.
+        </p>
+      </field>
+      <field name="finalProblems">
+        <list>
+          <ref>RefactoringProblem</ref>
+        </list>
+        <p>
+          The final status of the refactoring, that is, problems identified in
+          the result of a full, potentially expensive validation and / or change
+          creation. The list should be empty if there are no known problems.
+        </p>
+      </field>
+      <field name="feedback" optional="true">
+        <ref>RefactoringFeedback</ref>
+        <p>
+          Data used to provide feedback to the user. The structure of the data
+          is dependent on the kind of refactoring being created. The data that
+          is returned is documented in the section titled
+          <a href="#refactorings">Refactorings</a>, labeled as "Feedback".
+        </p>
+      </field>
+      <field name="change" optional="true">
+        <ref>SourceChange</ref>
+        <p>
+          The changes that are to be applied to affect the refactoring. This
+          field can be omitted if there are problems that prevent a set of
+          changes from being computed, such as having no options specified for a
+          refactoring that requires them, or if only validation was requested.
+        </p>
+      </field>
+      <field name="potentialEdits" optional="true">
+        <list>
+          <ref>String</ref>
+        </list>
+        <p>
+          The ids of source edits that are not known to be valid. An edit is not
+          known to be valid if there was insufficient type information for the
+          plugin to be able to determine whether or not the code needs to be
+          modified, such as when a member is being renamed and there is a
+          reference to a member from an unknown type. This field can be omitted
+          if the change field is omitted or if there are no potential edits for
+          the refactoring.
+        </p>
+      </field>
+    </result>
+  </request>
+</domain>
+<types>
+  <h2 class="domain"><a name="types">Types</a></h2>
+  <p>
+    This section contains descriptions of the data types referenced in the API’s
+    of the various domains.
+  </p>
+  <type name="AddContentOverlay">
+    <p>
+      A directive to begin overlaying the contents of a file. The supplied
+      content will be used for analysis in place of the file contents in the
+      filesystem.
+    </p>
+    <p>
+      If this directive is used on a file that already has a file content
+      overlay, the old overlay is discarded and replaced with the new one.
+    </p>
+    <object>
+      <field name="type" value="add"><ref>String</ref></field>
+      <field name="content">
+        <ref>String</ref>
+        <p>
+          The new content of the file.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="AnalysisError">
+    <p>
+      An indication of an error, warning, or hint that was produced by the
+      analysis.
+    </p>
+    <object>
+      <field name="severity">
+        <ref>AnalysisErrorSeverity</ref>
+        <p>
+          The severity of the error.
+        </p>
+      </field>
+      <field name="type">
+        <ref>AnalysisErrorType</ref>
+        <p>
+          The type of the error.
+        </p>
+      </field>
+      <field name="location">
+        <ref>Location</ref>
+        <p>
+          The location associated with the error.
+        </p>
+      </field>
+      <field name="message">
+        <ref>String</ref>
+        <p>
+          The message to be displayed for this error. The message should
+          indicate what is wrong with the code and why it is wrong.
+        </p>
+      </field>
+      <field name="correction" optional="true">
+        <ref>String</ref>
+        <p>
+          The correction message to be displayed for this error. The correction
+          message should indicate how the user can fix the error. The field is
+          omitted if there is no correction message associated with the error
+          code.
+        </p>
+      </field>
+      <field name="code">
+        <ref>String</ref>
+        <p>
+          The name, as a string, of the error code associated with this error.
+        </p>
+      </field>
+      <field name="hasFix" optional="true">
+        <ref>bool</ref>
+        <p>
+          A hint to indicate to interested clients that this error has an
+          associated fix (or fixes). The absence of this field implies there
+          are not known to be fixes. Note that since the operation to calculate
+          whether fixes apply needs to be performant it is possible that
+          complicated tests will be skipped and a false negative returned. For
+          this reason, this attribute should be treated as a "hint". Despite the
+          possibility of false negatives, no false positives should be returned.
+          If a client sees this flag set they can proceed with the confidence
+          that there are in fact associated fixes.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="AnalysisErrorFixes">
+    <p>
+      A list of fixes associated with a specific error
+    </p>
+    <object>
+      <field name="error">
+        <ref>AnalysisError</ref>
+        <p>
+          The error with which the fixes are associated.
+        </p>
+      </field>
+      <field name="fixes">
+        <list><ref>PrioritizedSourceChange</ref></list>
+        <p>
+          The fixes associated with the error.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="AnalysisErrorSeverity">
+    <p>
+      An enumeration of the possible severities of analysis errors.
+    </p>
+    <enum>
+      <value><code>INFO</code></value>
+      <value><code>WARNING</code></value>
+      <value><code>ERROR</code></value>
+    </enum>
+  </type>
+  <type name="AnalysisErrorType">
+    <p>
+      An enumeration of the possible types of analysis errors.
+    </p>
+    <enum>
+      <value><code>CHECKED_MODE_COMPILE_TIME_ERROR</code></value>
+      <value><code>COMPILE_TIME_ERROR</code></value>
+      <value><code>HINT</code></value>
+      <value><code>LINT</code></value>
+      <value><code>STATIC_TYPE_WARNING</code></value>
+      <value><code>STATIC_WARNING</code></value>
+      <value><code>SYNTACTIC_ERROR</code></value>
+      <value><code>TODO</code></value>
+    </enum>
+  </type>
+  <type name="AnalysisService">
+    <p>
+      An enumeration of the services provided by the analysis domain that are
+      related to a specific list of files.
+    </p>
+    <enum>
+      <value><code>FOLDING</code></value>
+      <value><code>HIGHLIGHTS</code></value>
+      <value><code>NAVIGATION</code></value>
+      <value><code>OCCURRENCES</code></value>
+      <value><code>OUTLINE</code></value>
+    </enum>
+  </type>
+  <type name="ChangeContentOverlay">
+    <p>
+      A directive to modify an existing file content overlay. One or more ranges
+      of text are deleted from the old file content overlay and replaced with
+      new text.
+    </p>
+    <p>
+      The edits are applied in the order in which they occur in the list. This
+      means that the offset of each edit must be correct under the assumption
+      that all previous edits have been applied.
+    </p>
+    <p>
+      It is an error to use this overlay on a file that does not yet have a file
+      content overlay or that has had its overlay removed via
+      <a href="#type_RemoveContentOverlay">RemoveContentOverlay</a>.
+    </p>
+    <p>
+      If any of the edits cannot be applied due to its offset or length being
+      out of range, an <tt>INVALID_OVERLAY_CHANGE</tt> error will be reported.
+    </p>
+    <object>
+      <field name="type" value="change"><ref>String</ref></field>
+      <field name="edits">
+        <list><ref>SourceEdit</ref></list>
+        <p>
+          The edits to be applied to the file.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="CompletionSuggestion">
+    <p>
+      A suggestion for how to complete partially entered text. Many of the
+      fields are optional, depending on the kind of element being suggested.
+    </p>
+    <object>
+      <field name="kind">
+        <ref>CompletionSuggestionKind</ref>
+        <p>
+          The kind of element being suggested.
+        </p>
+      </field>
+      <field name="relevance">
+        <ref>int</ref>
+        <p>
+          The relevance of this completion suggestion where a higher number
+          indicates a higher relevance.
+        </p>
+      </field>
+      <field name="completion">
+        <ref>String</ref>
+        <p>
+          The identifier to be inserted if the suggestion is selected. If the
+          suggestion is for a method or function, the client might want to
+          additionally insert a template for the parameters. The information
+          required in order to do so is contained in other fields.
+        </p>
+      </field>
+      <field name="selectionOffset">
+        <ref>int</ref>
+        <p>
+          The offset, relative to the beginning of the completion, of where the
+          selection should be placed after insertion.
+        </p>
+      </field>
+      <field name="selectionLength">
+        <ref>int</ref>
+        <p>
+          The number of characters that should be selected after insertion.
+        </p>
+      </field>
+      <field name="isDeprecated">
+        <ref>bool</ref>
+        <p>
+          True if the suggested element is deprecated.
+        </p>
+      </field>
+      <field name="isPotential">
+        <ref>bool</ref>
+        <p>
+          True if the element is not known to be valid for the target. This
+          happens if the type of the target is dynamic.
+        </p>
+      </field>
+      <field name="docSummary" optional="true">
+        <ref>String</ref>
+        <p>
+          An abbreviated version of the Dartdoc associated with the element
+          being suggested, This field is omitted if there is no Dartdoc
+          associated with the element.
+        </p>
+      </field>
+      <field name="docComplete" optional="true">
+        <ref>String</ref>
+        <p>
+          The Dartdoc associated with the element being suggested. This field is
+          omitted if there is no Dartdoc associated with the element.
+        </p>
+      </field>
+      <field name="declaringType" optional="true">
+        <ref>String</ref>
+        <p>
+          The class that declares the element being suggested. This field is
+          omitted if the suggested element is not a member of a class.
+        </p>
+      </field>
+      <field name="element" optional="true">
+        <ref>Element</ref>
+        <p>
+          Information about the element reference being suggested.
+        </p>
+      </field>
+      <field name="returnType" optional="true">
+        <ref>String</ref>
+        <p>
+          The return type of the getter, function or method or the type of the
+          field being suggested. This field is omitted if the suggested element
+          is not a getter, function or method.
+        </p>
+      </field>
+      <field name="parameterNames" optional="true">
+        <list><ref>String</ref></list>
+        <p>
+          The names of the parameters of the function or method being suggested.
+          This field is omitted if the suggested element is not a setter,
+          function or method.
+        </p>
+      </field>
+      <field name="parameterTypes" optional="true">
+        <list><ref>String</ref></list>
+        <p>
+          The types of the parameters of the function or method being suggested.
+          This field is omitted if the parameterNames field is omitted.
+        </p>
+      </field>
+      <field name="requiredParameterCount" optional="true">
+        <ref>int</ref>
+        <p>
+          The number of required parameters for the function or method being
+          suggested. This field is omitted if the parameterNames field is
+          omitted.
+        </p>
+      </field>
+      <field name="hasNamedParameters" optional="true">
+        <ref>bool</ref>
+        <p>
+          True if the function or method being suggested has at least one named
+          parameter. This field is omitted if the parameterNames field is
+          omitted.
+        </p>
+      </field>
+      <field name="parameterName" optional="true">
+        <ref>String</ref>
+        <p>
+          The name of the optional parameter being suggested. This field is
+          omitted if the suggestion is not the addition of an optional argument
+          within an argument list.
+        </p>
+      </field>
+      <field name="parameterType" optional="true">
+        <ref>String</ref>
+        <p>
+          The type of the options parameter being suggested. This field is
+          omitted if the parameterName field is omitted.
+        </p>
+      </field>
+      <field name="importUri" optional="true">
+        <ref>String</ref>
+        <p>
+          The import to be added if the suggestion is out of scope and needs
+          an import to be added to be in scope.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="CompletionSuggestionKind">
+    <p>
+      An enumeration of the kinds of elements that can be included in a
+      completion suggestion.
+    </p>
+    <enum>
+      <value>
+        <code>ARGUMENT_LIST</code>
+        <p>
+          A list of arguments for the method or function that is being
+          invoked. For this suggestion kind, the completion field is a
+          textual representation of the invocation and the parameterNames,
+          parameterTypes, and requiredParameterCount attributes are defined.
+        </p>
+      </value>
+      <value><code>IMPORT</code></value>
+      <value>
+        <code>IDENTIFIER</code>
+        <p>
+          The element identifier should be inserted at the completion
+          location. For example "someMethod" in <tt>import 'myLib.dart' show
+          someMethod;</tt>. For suggestions of this kind, the element
+          attribute is defined and the completion field is the element's
+          identifier.
+        </p>
+      </value>
+      <value>
+        <code>INVOCATION</code>
+        <p>
+          The element is being invoked at the completion location. For
+          example, 'someMethod' in <tt>x.someMethod();</tt>. For suggestions
+          of this kind, the element attribute is defined and the completion
+          field is the element's identifier.
+        </p>
+      </value>
+      <value>
+        <code>KEYWORD</code>
+        <p>
+          A keyword is being suggested. For suggestions of this kind, the
+          completion is the keyword.
+        </p>
+      </value>
+      <value>
+        <code>NAMED_ARGUMENT</code>
+        <p>
+          A named argument for the current call site is being suggested. For
+          suggestions of this kind, the completion is the named argument
+          identifier including a trailing ':' and a space.
+        </p>
+      </value>
+      <value><code>OPTIONAL_ARGUMENT</code></value>
+      <value><code>PARAMETER</code></value>
+    </enum>
+  </type>
+  <type name="ContextBuilderOptions">
+    <p>
+      The options used to build an analysis context.
+    </p>
+    <object>
+      <field name="dartSdkSummaryPath" optional="true">
+        <ref>String</ref>
+        <p>
+          The file path of the file containing the summary of the SDK that
+          should be used to "analyze" the SDK. The field will be omitted if the
+          summary should be found in the SDK.
+        </p>
+      </field>
+      <field name="defaultAnalysisOptionsFilePath" optional="true">
+        <list>
+          <ref>String</ref>
+        </list>
+        <p>
+          The file path of the analysis options file that should be used in
+          place of any file in the root directory or a parent of the root
+          directory. The field will be omitted if the normal lookup mechanism
+          should be used.
+        </p>
+      </field>
+      <field name="declaredVariables" optional="true">
+        <map>
+          <key>
+            <ref>String</ref>
+          </key>
+          <value>
+            <ref>String</ref>
+          </value>
+        </map>
+        <p>
+          A table mapping variable names to values for the declared variables.
+          The field will be omitted if no additional variables need to be
+          declared.
+        </p>
+      </field>
+      <!--
+      TODO(brianwilkerson) Figure out how to handle analysis options.
+      <field name="defaultOptions" optional="true">
+        <ref>AnalysisOptions</ref>
+        <p>
+          The default analysis options that should be used unless some or all of
+          them are overridden in the analysis options file. The field will be
+          omitted if the default defaults should be used.
+        </p>
+      </field>
+      -->
+      <field name="defaultPackageFilePath" optional="true">
+        <list>
+          <ref>String</ref>
+        </list>
+        <p>
+          The file path of the .packages file that should be used in place of
+          any file found using the normal (Package Specification DEP) lookup
+          mechanism. The field will be omitted if the normal lookup mechanism
+          should be used.
+        </p>
+      </field>
+      <field name="defaultPackagesDirectoryPath" optional="true">
+        <list>
+          <ref>String</ref>
+        </list>
+        <p>
+          The file path of the packages directory that should be used in place
+          of any file found using the normal (Package Specification DEP) lookup
+          mechanism. The field will be omitted if the normal lookup mechanism
+          should be used.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="ContextRoot">
+    <p>
+      A description of an analysis context.
+    </p>
+    <object>
+      <field name="root">
+        <ref>String</ref>
+        <p>
+          The absolute path of the root directory containing the files to be
+          analyzed.
+        </p>
+      </field>
+      <field name="exclude">
+        <list>
+          <ref>String</ref>
+        </list>
+        <p>
+          A list of the absolute paths of files and directories within the root
+          directory that should not be analyzed.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="Element">
+    <p>
+      Information about an element (something that can be declared in code).
+    </p>
+    <object>
+      <field name="kind">
+        <ref>ElementKind</ref>
+        <p>
+          The kind of the element.
+        </p>
+      </field>
+      <field name="name">
+        <ref>String</ref>
+        <p>
+          The name of the element. This is typically used as the label in the outline.
+        </p>
+      </field>
+      <field name="location" optional="true">
+        <ref>Location</ref>
+        <p>
+          The location of the name in the declaration of the element.
+        </p>
+      </field>
+      <field name="flags">
+        <ref>int</ref>
+        <p>
+          A bit-map containing the following flags:
+        </p>
+        <ul>
+          <li>
+            0x01 - set if the element is explicitly or implicitly abstract
+          </li>
+          <li>
+            0x02 - set if the element was declared to be ‘const’
+          </li>
+          <li>
+            0x04 - set if the element was declared to be ‘final’
+          </li>
+          <li>
+            0x08 - set if the element is a static member of a class or is a
+            top-level function or field
+          </li>
+          <li>
+            0x10 - set if the element is private
+          </li>
+          <li>
+            0x20 - set if the element is deprecated
+          </li>
+        </ul>
+      </field>
+      <field name="parameters" optional="true">
+        <ref>String</ref>
+        <p>
+          The parameter list for the element. If the element is not a method or
+          function this field will not be defined. If the element doesn't have
+          parameters (e.g. getter), this field will not be defined. If the
+          element has zero parameters, this field will have a value of "()".
+        </p>
+      </field>
+      <field name="returnType" optional="true">
+        <ref>String</ref>
+        <p>
+          The return type of the element. If the element is not a method or
+          function this field will not be defined. If the element does not have
+          a declared return type, this field will contain an empty string.
+        </p>
+      </field>
+      <field name="typeParameters" optional="true">
+        <ref>String</ref>
+        <p>
+          The type parameter list for the element. If the element doesn't have
+          type parameters, this field will not be defined.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="ElementKind">
+    <p>
+      An enumeration of the kinds of elements.
+    </p>
+    <enum>
+      <value><code>CLASS</code></value>
+      <value><code>CLASS_TYPE_ALIAS</code></value>
+      <value><code>COMPILATION_UNIT</code></value>
+      <value><code>CONSTRUCTOR</code></value>
+      <value><code>ENUM</code></value>
+      <value><code>ENUM_CONSTANT</code></value>
+      <value><code>FIELD</code></value>
+      <value><code>FILE</code></value>
+      <value><code>FUNCTION</code></value>
+      <value><code>FUNCTION_TYPE_ALIAS</code></value>
+      <value><code>GETTER</code></value>
+      <value><code>LABEL</code></value>
+      <value><code>LIBRARY</code></value>
+      <value><code>LOCAL_VARIABLE</code></value>
+      <value><code>METHOD</code></value>
+      <value><code>PARAMETER</code></value>
+      <value><code>PREFIX</code></value>
+      <value><code>SETTER</code></value>
+      <value><code>TOP_LEVEL_VARIABLE</code></value>
+      <value><code>TYPE_PARAMETER</code></value>
+      <value><code>UNKNOWN</code></value>
+    </enum>
+  </type>
+  <type name="FilePath">
+    <ref>String</ref>
+    <p>
+      The absolute, normalized path of a file.
+    </p>
+    <p>
+      If the format of a file path in a request is not valid, e.g. the path is
+      not absolute or is not normalized, then an error of type
+      <tt>INVALID_FILE_PATH_FORMAT</tt> will be generated.
+    </p>
+  </type>
+  <type name="FoldingKind">
+    <p>
+      An enumeration of the kinds of folding regions.
+    </p>
+    <enum>
+      <value><code>COMMENT</code></value>
+      <value><code>CLASS_MEMBER</code></value>
+      <value><code>DIRECTIVES</code></value>
+      <value><code>DOCUMENTATION_COMMENT</code></value>
+      <value><code>TOP_LEVEL_DECLARATION</code></value>
+    </enum>
+  </type>
+  <type name="FoldingRegion">
+    <p>
+      A description of a region that can be folded.
+    </p>
+    <object>
+      <field name="kind">
+        <ref>FoldingKind</ref>
+        <p>
+          The kind of the region.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the region to be folded.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the region to be folded.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="HighlightRegion">
+    <p>
+      A description of a region that could have special highlighting associated
+      with it.
+    </p>
+    <object>
+      <field name="type">
+        <ref>HighlightRegionType</ref>
+        <p>
+          The type of highlight associated with the region.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the region to be highlighted.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the region to be highlighted.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="HighlightRegionType">
+    <p>
+      An enumeration of the kinds of highlighting that can be applied to files.
+    </p>
+    <enum>
+      <value><code>ANNOTATION</code></value>
+      <value><code>BUILT_IN</code></value>
+      <value><code>CLASS</code></value>
+      <value><code>COMMENT_BLOCK</code></value>
+      <value><code>COMMENT_DOCUMENTATION</code></value>
+      <value><code>COMMENT_END_OF_LINE</code></value>
+      <value><code>CONSTRUCTOR</code></value>
+      <value><code>DIRECTIVE</code></value>
+      <value>
+        <code>DYNAMIC_TYPE</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>DYNAMIC_LOCAL_VARIABLE_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>DYNAMIC_LOCAL_VARIABLE_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>DYNAMIC_PARAMETER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>DYNAMIC_PARAMETER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value><code>ENUM</code></value>
+      <value><code>ENUM_CONSTANT</code></value>
+      <value>
+        <code>FIELD</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>FIELD_STATIC</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>FUNCTION</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>FUNCTION_DECLARATION</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value><code>FUNCTION_TYPE_ALIAS</code></value>
+      <value>
+        <code>GETTER_DECLARATION</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value><code>IDENTIFIER_DEFAULT</code></value>
+      <value><code>IMPORT_PREFIX</code></value>
+      <value>
+        <code>INSTANCE_FIELD_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_FIELD_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_GETTER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_GETTER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_METHOD_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_METHOD_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_SETTER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INSTANCE_SETTER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>INVALID_STRING_ESCAPE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value><code>KEYWORD</code></value>
+      <value><code>LABEL</code></value>
+      <value>
+        <code>LIBRARY_NAME</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value><code>LITERAL_BOOLEAN</code></value>
+      <value><code>LITERAL_DOUBLE</code></value>
+      <value><code>LITERAL_INTEGER</code></value>
+      <value><code>LITERAL_LIST</code></value>
+      <value><code>LITERAL_MAP</code></value>
+      <value><code>LITERAL_STRING</code></value>
+      <value>
+        <code>LOCAL_FUNCTION_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>LOCAL_FUNCTION_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>LOCAL_VARIABLE</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value><code>LOCAL_VARIABLE_DECLARATION</code></value>
+      <value>
+        <code>LOCAL_VARIABLE_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>METHOD</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>METHOD_DECLARATION</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>METHOD_DECLARATION_STATIC</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>METHOD_STATIC</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>PARAMETER</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>SETTER_DECLARATION</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_VARIABLE</code>
+        <p>Only for version 1 of highlight.</p>
+      </value>
+      <value>
+        <code>PARAMETER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>PARAMETER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_FIELD_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_GETTER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_GETTER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_METHOD_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_METHOD_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_SETTER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>STATIC_SETTER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_FUNCTION_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_FUNCTION_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_GETTER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_GETTER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_SETTER_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_SETTER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>TOP_LEVEL_VARIABLE_DECLARATION</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value><code>TYPE_NAME_DYNAMIC</code></value>
+      <value><code>TYPE_PARAMETER</code></value>
+      <value>
+        <code>UNRESOLVED_INSTANCE_MEMBER_REFERENCE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+      <value>
+        <code>VALID_STRING_ESCAPE</code>
+        <p>Only for version 2 of highlight.</p>
+      </value>
+    </enum>
+  </type>
+  <type name="LinkedEditGroup">
+    <p>
+      A collection of positions that should be linked (edited simultaneously)
+      for the purposes of updating code after a source change. For example, if a
+      set of edits introduced a new variable name, the group would contain all
+      of the positions of the variable name so that if the client wanted to let
+      the user edit the variable name after the operation, all occurrences of
+      the name could be edited simultaneously.
+    </p>
+    <object>
+      <field name="positions">
+        <list><ref>Position</ref></list>
+        <p>
+          The positions of the regions that should be edited simultaneously.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the regions that should be edited simultaneously.
+        </p>
+      </field>
+      <field name="suggestions">
+        <list><ref>LinkedEditSuggestion</ref></list>
+        <p>
+          Pre-computed suggestions for what every region might want to be
+          changed to.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="LinkedEditSuggestion">
+    <p>
+      A suggestion of a value that could be used to replace all of the linked
+      edit regions in a <a href="#type_LinkedEditGroup">LinkedEditGroup</a>.
+    </p>
+    <object>
+      <field name="value">
+        <ref>String</ref>
+        <p>
+          The value that could be used to replace all of the linked edit
+          regions.
+        </p>
+      </field>
+      <field name="kind">
+        <ref>LinkedEditSuggestionKind</ref>
+        <p>
+          The kind of value being proposed.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="LinkedEditSuggestionKind">
+    <p>
+      An enumeration of the kind of values that can be suggested for a linked
+      edit.
+    </p>
+    <enum>
+      <value><code>METHOD</code></value>
+      <value><code>PARAMETER</code></value>
+      <value><code>TYPE</code></value>
+      <value><code>VARIABLE</code></value>
+    </enum>
+  </type>
+  <type name="Location">
+    <p>
+      A location (character range) within a file.
+    </p>
+    <object>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the range.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the range.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the range.
+        </p>
+      </field>
+      <field name="startLine">
+        <ref>int</ref>
+        <p>
+          The one-based index of the line containing the first character of the
+          range.
+        </p>
+      </field>
+      <field name="startColumn">
+        <ref>int</ref>
+        <p>
+          The one-based index of the column containing the first character of
+          the range.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="NavigationRegion">
+    <p>
+      A description of a region from which the user can navigate to the
+      declaration of an element.
+    </p>
+    <object>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the region from which the user can navigate.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the region from which the user can navigate.
+        </p>
+      </field>
+      <field name="targets">
+        <list><ref>int</ref></list>
+        <p>
+          The indexes of the targets (in the enclosing navigation response) to
+          which the given region is bound. By opening the target, clients can
+          implement one form of navigation. This list cannot be empty.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="NavigationTarget">
+    <p>
+      A description of a target to which the user can navigate.
+    </p>
+    <object>
+      <field name="kind">
+        <ref>ElementKind</ref>
+        <p>
+          The kind of the element.
+        </p>
+      </field>
+      <field name="fileIndex">
+        <ref>int</ref>
+        <p>
+          The index of the file (in the enclosing navigation response) to
+          navigate to.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the region to which the user can navigate.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the region to which the user can navigate.
+        </p>
+      </field>
+      <field name="startLine">
+        <ref>int</ref>
+        <p>
+          The one-based index of the line containing the first character of the
+          region.
+        </p>
+      </field>
+      <field name="startColumn">
+        <ref>int</ref>
+        <p>
+          The one-based index of the column containing the first character of
+          the region.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="Occurrences">
+    <p>
+      A description of the references to a single element within a single file.
+    </p>
+    <object>
+      <field name="element">
+        <ref>Element</ref>
+        <p>
+          The element that was referenced.
+        </p>
+      </field>
+      <field name="offsets">
+        <list><ref>int</ref></list>
+        <p>
+          The offsets of the name of the referenced element within the file.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the name of the referenced element.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="Outline">
+    <p>
+      An node in the outline structure of a file.
+    </p>
+    <object>
+      <field name="element">
+        <ref>Element</ref>
+        <p>
+          A description of the element represented by this node.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the first character of the element. This is different
+          than the offset in the Element, which is the offset of the name of the
+          element. It can be used, for example, to map locations in the file
+          back to an outline.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the element.
+        </p>
+      </field>
+      <field name="children" optional="true">
+        <list><ref>Outline</ref></list>
+        <p>
+          The children of the node. The field will be omitted if the node has no
+          children.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="Position">
+    <p>
+      A position within a file.
+    </p>
+    <object>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the position.
+        </p>
+      </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the position.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="PrioritizedSourceChange">
+    <p>
+      A source change that has a priority associated with it.
+    </p>
+    <object>
+      <field name="priority">
+        <ref>int</ref>
+        <p>
+          The priority of the change. The value is expected to be non-negative,
+          and zero (0) is the lowest priority.
+        </p>
+      </field>
+      <field name="change">
+        <ref>SourceChange</ref>
+        <p>
+          The change with which the relevance is associated.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="RefactoringFeedback">
+    <p>
+      An abstract superclass of all refactoring feedbacks.
+    </p>
+    <object>
+    </object>
+  </type>
+  <type name="RefactoringKind">
+    <p>
+      An enumeration of the kinds of refactorings that can be created.
+    </p>
+    <enum>
+      <value><code>CONVERT_GETTER_TO_METHOD</code></value>
+      <value><code>CONVERT_METHOD_TO_GETTER</code></value>
+      <value><code>EXTRACT_LOCAL_VARIABLE</code></value>
+      <value><code>EXTRACT_METHOD</code></value>
+      <value><code>INLINE_LOCAL_VARIABLE</code></value>
+      <value><code>INLINE_METHOD</code></value>
+      <value><code>MOVE_FILE</code></value>
+      <value><code>RENAME</code></value>
+      <value><code>SORT_MEMBERS</code></value>
+    </enum>
+  </type>
+  <type name="RefactoringMethodParameter">
+    <!-- This type does not appear to be referenced yet. -->
+    <p>
+      A description of a parameter in a method refactoring.
+    </p>
+    <object>
+      <field name="id" optional="true">
+        <ref>String</ref>
+        <p>
+          The unique identifier of the parameter. Clients may omit this field
+          for the parameters they want to add.
+        </p>
+      </field>
+      <field name="kind">
+        <ref>RefactoringMethodParameterKind</ref>
+        <p>
+          The kind of the parameter.
+        </p>
+      </field>
+      <field name="type">
+        <ref>String</ref>
+        <p>
+          The type that should be given to the parameter, or the return type of
+          the parameter's function type.
+        </p>
+      </field>
+      <field name="name">
+        <ref>String</ref>
+        <p>
+          The name that should be given to the parameter.
+        </p>
+      </field>
+      <field name="parameters" optional="true">
+        <ref>String</ref>
+        <p>
+          The parameter list of the parameter's function type. If the parameter
+          is not of a function type, this field will not be defined. If the
+          function type has zero parameters, this field will have a value of
+          '()'.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="RefactoringOptions">
+    <p>
+      An abstract superclass of all refactoring options.
+    </p>
+    <object>
+    </object>
+  </type>
+  <type name="RefactoringMethodParameterKind">
+    <p>
+      An enumeration of the kinds of parameters.
+    </p>
+    <enum>
+      <value><code>REQUIRED</code></value>
+      <value><code>POSITIONAL</code></value>
+      <value><code>NAMED</code></value>
+    </enum>
+  </type>
+  <type name="RefactoringProblem">
+    <p>
+      A description of a problem related to a refactoring.
+    </p>
+    <object>
+      <field name="severity">
+        <ref>RefactoringProblemSeverity</ref>
+        <p>
+          The severity of the problem being represented.
+        </p>
+      </field>
+      <field name="message">
+        <ref>String</ref>
+        <p>
+          A human-readable description of the problem being represented.
+        </p>
+      </field>
+      <field name="location" optional="true">
+        <ref>Location</ref>
+        <p>
+          The location of the problem being represented. This field is omitted
+          unless there is a specific location associated with the problem (such
+          as a location where an element being renamed will be shadowed).
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="RefactoringProblemSeverity">
+    <p>
+      An enumeration of the severities of problems that can be returned by the
+      refactoring requests.
+    </p>
+    <enum>
+      <value>
+        <code>INFO</code>
+        <p>
+          A minor code problem. No example, because it is not used yet.
+        </p>
+      </value>
+      <value>
+        <code>WARNING</code>
+        <p>
+          A minor code problem. For example names of local variables should be
+          camel case and start with a lower case letter. Staring the name of a
+          variable with an upper case is OK from the language point of view, but
+          it is nice to warn the user.
+        </p>
+      </value>
+      <value>
+        <code>ERROR</code>
+        <p>
+          The refactoring technically can be performed, but there is a logical
+          problem. For example the name of a local variable being extracted
+          conflicts with another name in the scope, or duplicate parameter names
+          in the method being extracted, or a conflict between a parameter name
+          and a local variable, etc. In some cases the location of the problem
+          is also provided, so the IDE can show user the location and the
+          problem, and let the user decide whether they want to perform the
+          refactoring. For example the name conflict might be expected, and the
+          user wants to fix it afterwards.
+        </p>
+      </value>
+      <value>
+        <code>FATAL</code>
+        <p>
+          A fatal error, which prevents performing the refactoring. For example
+          the name of a local variable being extracted is not a valid
+          identifier, or selection is not a valid expression.
+        </p>
+      </value>
+    </enum>
+  </type>
+  <type name="RemoveContentOverlay">
+    <p>
+      A directive to remove an existing file content overlay. After processing
+      this directive, the file contents will once again be read from the file
+      system.
+    </p>
+    <p>
+      If this directive is used on a file that doesn't currently have a content
+      overlay, it has no effect.
+    </p>
+    <object>
+      <field name="type" value="remove"><ref>String</ref></field>
+    </object>
+  </type>
+  <type name="RequestError">
+    <p>
+      An indication of a problem with the execution of the server,
+      typically in response to a request.
+    </p>
+    <object>
+      <field name="code">
+        <ref>RequestErrorCode</ref>
+        <p>
+          A code that uniquely identifies the error that occurred.
+        </p>
+      </field>
+      <field name="message">
+        <ref>String</ref>
+        <p>
+          A short description of the error.
+        </p>
+      </field>
+      <field name="stackTrace" optional="true">
+        <ref>String</ref>
+        <p>
+          The stack trace associated with processing the request, used for
+          debugging the plugin.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="RequestErrorCode">
+    <p>
+      An enumeration of the types of errors that can occur in the execution of
+      the plugin.
+    </p>
+    <enum>
+      <value>
+        <code>INVALID_OVERLAY_CHANGE</code>
+        <p>
+          An "analysis.updateContent" request contained a
+          <a href="#type_ChangeContentOverlay">ChangeContentOverlay</a> object
+          that can't be applied. This can happen for two reasons:
+        </p>
+        <ul>
+          <li>
+            there was no preceding
+            <a href="#type_AddContentOverlay">AddContentOverlay</a> and hence no
+            content to which the edits could be applied, or
+          </li>
+          <li>
+            one or more of the specified edits have an offset or length that is
+            out of range.
+          </li>
+        </ul>
+      </value>
+      <value>
+        <code>INVALID_PARAMETER</code>
+        <p>
+          One of the method parameters was invalid.
+        </p>
+      </value>
+      <value>
+        <code>PLUGIN_ERROR</code>
+        <p>
+          An internal error occurred in the plugin while attempting to respond
+          to a request. Also see the plugin.error notification for errors that
+          occur outside of handling a request.
+        </p>
+      </value>
+      <value>
+        <code>UNKNOWN_REQUEST</code>
+        <p>
+          A request was received that the plugin does not recognize, or cannot
+          handle in its current configuration.
+        </p>
+      </value>
+      <!--
+      <value>
+        <code>CONTENT_MODIFIED</code>
+        <p>
+          An "analysis.getErrors" or "analysis.getNavigation" request could
+          not be satisfied because the content of the file changed before
+          the requested results could be computed.
+        </p>
+      </value>
+      <value>
+        <code>FILE_NOT_ANALYZED</code>
+        <p>
+          A request specified a FilePath which does not match a file in
+          an analysis root, or the requested operation is not available
+          for the file.
+        </p>
+      </value>
+      <value>
+        <code>FORMAT_WITH_ERRORS</code>
+        <p>
+          An "edit.format" request specified a file that contains syntax
+          errors.
+        </p>
+      </value>
+      <value>
+        <code>GET_ERRORS_INVALID_FILE</code>
+        <p>
+          An "analysis.getErrors" request specified a FilePath
+          which does not match a file currently subject to
+          analysis.
+        </p>
+      </value>
+      <value>
+        <code>GET_NAVIGATION_INVALID_FILE</code>
+        <p>
+          An "analysis.getNavigation" request specified a FilePath
+          which does not match a file currently subject to
+          analysis.
+        </p>
+      </value>
+      <value>
+        <code>GET_REACHABLE_SOURCES_INVALID_FILE</code>
+        <p>
+          An "analysis.getReachableSources" request specified a FilePath
+          which does not match a file currently subject to
+          analysis.
+        </p>
+      </value>
+      <value>
+        <code>INVALID_ANALYSIS_ROOT</code>
+        <p>
+          A path passed as an argument to a request (such as
+          analysis.reanalyze) is required to be an analysis root, but isn't.
+        </p>
+      </value>
+      <value>
+        <code>INVALID_EXECUTION_CONTEXT</code>
+        <p>
+          The context root used to create an execution context does not
+          exist.
+        </p>
+      </value>
+      <value>
+        <code>INVALID_FILE_PATH_FORMAT</code>
+        <p>
+          The format of the given file path is invalid, that is, it is not
+          absolute and normalized.
+        </p>
+      </value>
+      <value>
+        <code>INVALID_REQUEST</code>
+        <p>
+          A malformed request was received.
+        </p>
+      </value>
+      <value>
+        <code>REFACTORING_REQUEST_CANCELLED</code>
+        <p>
+          Another refactoring request was received during processing of
+          this one.
+        </p>
+      </value>
+      <value>
+        <code>UNANALYZED_PRIORITY_FILES</code>
+        <p>
+          An "analysis.setPriorityFiles" request includes one or
+          more files that are not being analyzed.
+        </p>
+        <p>
+          This is a legacy error; it will be removed before the
+          API reaches version 1.0.
+        </p>
+      </value>
+      <value>
+        <code>UNKNOWN_SOURCE</code>
+        <p>
+          The analysis server was requested to perform an action
+          on a source that does not exist.
+        </p>
+      </value>
+      <value>
+        <code>UNSUPPORTED_FEATURE</code>
+        <p>
+          The plugin received a requested to perform an action that is not
+          supported.
+        </p>
+      </value>
+      -->
+    </enum>
+  </type>
+  <type name="SourceChange">
+    <p>
+      A description of a set of edits that implement a single conceptual change.
+    </p>
+    <object>
+      <field name="message">
+        <ref>String</ref>
+        <p>
+          A human-readable description of the change to be applied.
+        </p>
+      </field>
+      <field name="edits">
+        <list><ref>SourceFileEdit</ref></list>
+        <p>
+          A list of the edits used to effect the change, grouped by file.
+        </p>
+      </field>
+      <field name="linkedEditGroups">
+        <list><ref>LinkedEditGroup</ref></list>
+        <p>
+          A list of the linked editing groups used to customize the changes that
+          were made.
+        </p>
+      </field>
+      <field name="selection" optional="true">
+        <ref>Position</ref>
+        <p>
+          The position that should be selected after the edits have been
+          applied.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="SourceEdit">
+    <p>
+      A description of a single change to a single file.
+    </p>
+    <object>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the region to be modified.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the region to be modified.
+        </p>
+      </field>
+      <field name="replacement">
+        <ref>String</ref>
+        <p>
+          The code that is to replace the specified region in the original code.
+        </p>
+      </field>
+      <field name="id" optional="true">
+        <ref>String</ref>
+        <p>
+          An identifier that uniquely identifies this source edit from other
+          edits in the same response. This field is omitted unless a containing
+          structure needs to be able to identify the edit for some reason.
+        </p>
+        <p>
+          For example, some refactoring operations can produce edits that might
+          not be appropriate (referred to as potential edits). Such edits will
+          have an id so that they can be referenced. Edits in the same response
+          that do not need to be referenced will not have an id.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="SourceFileEdit">
+    <p>
+      A description of a set of changes to a single file.
+    </p>
+    <object>
+      <field name="file">
+        <ref>FilePath</ref>
+        <p>
+          The file containing the code to be modified.
+        </p>
+      </field>
+      <field name="fileStamp">
+        <ref>long</ref>
+        <p>
+          The modification stamp of the file at the moment when the change was
+          created, in milliseconds since the "Unix epoch". Will be -1 if the
+          file did not exist and should be created. The client may use this
+          field to make sure that the file was not changed since then, so it is
+          safe to apply the change.
+        </p>
+      </field>
+      <field name="edits">
+        <list><ref>SourceEdit</ref></list>
+        <p>
+          A list of the edits used to effect the change.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="WatchEvent">
+    <p>
+      A watch event sent by the server when the file system has been modified.
+    </p>
+    <object>
+      <field name="type">
+        <ref>WatchEventType</ref>
+        <p>
+          The type of change represented by this event.
+        </p>
+      </field>
+      <field name="path">
+        <ref>String</ref>
+        <p>
+          The absolute path of the file or directory that changed.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="WatchEventType">
+    <p>
+      An indication of the type of change associated with a watch event.
+    </p>
+    <enum>
+      <value>
+        <code>ADD</code>
+        <p>
+          An indication that the file or directory was added.
+        </p>
+      </value>
+      <value>
+        <code>MODIFY</code>
+        <p>
+          An indication that the file was modified.
+        </p>
+      </value>
+      <value>
+        <code>REMOVE</code>
+        <p>
+          An indication that the file or directory was removed.
+        </p>
+      </value>
+    </enum>
+  </type>
+</types>
+<refactorings>
+  <h2><a name="refactorings">Refactorings</a></h2>
+  <p>
+    This section contains additional information for each kind of refactoring.
+    In addition to a brief description of the refactoring, there is a
+    specification of the feedback that is provided when a refactoring is
+    requested using the
+    <a href="request_edit.getRefactoring">edit.getRefactoring</a> request
+    (designed to improve the UX) and the options that may be provided to
+    <a href="request_edit.getRefactoring">edit.getRefactoring</a>.
+  </p>
+  <refactoring kind="CONVERT_GETTER_TO_METHOD">
+    <p>
+      Convert a getter into a method by removing the keyword get and adding an
+      empty parameter list.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single getter.
+    </p>
+  </refactoring>
+  <refactoring kind="CONVERT_METHOD_TO_GETTER">
+    <p>
+      Convert a method into a getter by adding the keyword get and removing the
+      parameter list.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single method or if the method has a non-empty parameter
+      list.
+    </p>
+  </refactoring>
+  <refactoring kind="EXTRACT_LOCAL_VARIABLE">
+    <p>
+      Create a local variable initialized by the expression that covers the
+      specified selection.
+    </p>
+    <p>
+      It is an error if the selection range is not covered by a complete
+      expression.
+    </p>
+    <feedback>
+      <field name="coveringExpressionOffsets" optional="true">
+        <list><ref>int</ref></list>
+        <p>
+          The offsets of the expressions that cover the specified selection,
+          from the down most to the up most.
+        </p>
+      </field>
+      <field name="coveringExpressionLengths" optional="true">
+        <list><ref>int</ref></list>
+        <p>
+          The lengths of the expressions that cover the specified selection,
+          from the down most to the up most.
+        </p>
+      </field>
+      <field name="names">
+        <list><ref>String</ref></list>
+        <p>
+          The proposed names for the local variable.
+        </p>
+      </field>
+      <field name="offsets">
+        <list><ref>int</ref></list>
+        <p>
+          The offsets of the expressions that would be replaced by a reference
+          to the variable.
+        </p>
+      </field>
+      <field name="lengths">
+        <list><ref>int</ref></list>
+        <p>
+          The lengths of the expressions that would be replaced by a reference
+          to the variable. The lengths correspond to the offsets. In other
+          words, for a given expression, if the offset of that expression is
+          offsets[i], then the length of that expression is lengths[i].
+        </p>
+      </field>
+    </feedback>
+    <options>
+      <field name="name">
+        <ref>String</ref>
+        <p>
+          The name that the local variable should be given.
+        </p>
+      </field>
+      <field name="extractAll">
+        <ref>bool</ref>
+        <p>
+          True if all occurrences of the expression within the scope in which
+          the variable will be defined should be replaced by a reference to the
+          local variable. The expression used to initiate the refactoring will
+          always be replaced.
+        </p>
+      </field>
+    </options>
+  </refactoring>
+  <refactoring kind="EXTRACT_METHOD">
+    <p>
+      Create a method whose body is the specified expression or list of
+      statements, possibly augmented with a return statement.
+    </p>
+    <p>
+      It is an error if the range contains anything other than a complete
+      expression (no partial expressions are allowed) or a complete sequence of
+      statements.
+    </p>
+    <feedback>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset to the beginning of the expression or statements that will
+          be extracted.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the expression or statements that will be extracted.
+        </p>
+      </field>
+      <field name="returnType">
+        <ref>String</ref>
+        <p>
+          The proposed return type for the method. If the returned element does
+          not have a declared return type, this field will contain an empty
+          string.
+        </p>
+      </field>
+      <field name="names">
+        <list><ref>String</ref></list>
+        <p>
+          The proposed names for the method.
+        </p>
+      </field>
+      <field name="canCreateGetter">
+        <ref>bool</ref>
+        <p>
+          True if a getter could be created rather than a method.
+        </p>
+      </field>
+      <field name="parameters">
+        <list><ref>RefactoringMethodParameter</ref></list>
+        <p>
+          The proposed parameters for the method.
+        </p>
+      </field>
+      <field name="offsets">
+        <list><ref>int</ref></list>
+        <p>
+          The offsets of the expressions or statements that would be replaced by
+          an invocation of the method.
+        </p>
+      </field>
+      <field name="lengths">
+        <list><ref>int</ref></list>
+        <p>
+          The lengths of the expressions or statements that would be replaced by
+          an invocation of the method. The lengths correspond to the offsets. In
+          other words, for a given expression (or block of statements), if the
+          offset of that expression is offsets[i], then the length of that
+          expression is lengths[i].
+        </p>
+      </field>
+    </feedback>
+    <options>
+      <field name="returnType">
+        <ref>String</ref>
+        <p>
+          The return type that should be defined for the method.
+        </p>
+      </field>
+      <field name="createGetter">
+        <ref>bool</ref>
+        <p>
+          True if a getter should be created rather than a method. It is an
+          error if this field is true and the list of parameters is non-empty.
+        </p>
+      </field>
+      <field name="name">
+        <ref>String</ref>
+        <p>
+          The name that the method should be given.
+        </p>
+      </field>
+      <field name="parameters">
+        <list><ref>RefactoringMethodParameter</ref></list>
+        <p>
+          The parameters that should be defined for the method.
+        </p>
+        <p>
+          It is an error if a REQUIRED or NAMED parameter follows a POSITIONAL
+          parameter. It is an error if a REQUIRED or POSITIONAL parameter
+          follows a NAMED parameter.
+        </p>
+        <ul>
+          <li>
+            To change the order and/or update proposed parameters, add
+            parameters with the same identifiers as proposed.
+          </li>
+          <li>
+            To add new parameters, omit their identifier.
+          </li>
+          <li>
+            To remove some parameters, omit them in this list.
+          </li>
+        </ul>
+      </field>
+      <field name="extractAll">
+        <ref>bool</ref>
+        <p>
+          True if all occurrences of the expression or statements should be
+          replaced by an invocation of the method. The expression or statements
+          used to initiate the refactoring will always be replaced.
+        </p>
+      </field>
+    </options>
+  </refactoring>
+  <refactoring kind="INLINE_LOCAL_VARIABLE">
+    <p>
+      Inline the initializer expression of a local variable in place of any
+      references to that variable.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single local variable.
+    </p>
+    <feedback>
+      <field name="name">
+        <ref>String</ref>
+        <p>
+          The name of the variable being inlined.
+        </p>
+      </field>
+      <field name="occurrences">
+        <ref>int</ref>
+        <p>
+          The number of times the variable occurs.
+        </p>
+      </field>
+    </feedback>
+  </refactoring>
+  <refactoring kind="INLINE_METHOD">
+    <p>
+      Inline a method in place of one or all references to that method.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single method.
+    </p>
+    <feedback>
+      <field name="className" optional="true">
+        <ref>String</ref>
+        <p>
+          The name of the class enclosing the method being inlined. If not a
+          class member is being inlined, this field will be absent.
+        </p>
+      </field>
+      <field name="methodName">
+        <ref>String</ref>
+        <p>
+          The name of the method (or function) being inlined.
+        </p>
+      </field>
+      <field name="isDeclaration">
+        <ref>bool</ref>
+        <p>
+          True if the declaration of the method is selected and all references
+          should be inlined.
+        </p>
+      </field>
+    </feedback>
+    <options>
+      <field name="deleteSource">
+        <ref>bool</ref>
+        <p>
+          True if the method being inlined should be removed. It is an error if
+          this field is true and inlineAll is false.
+        </p>
+      </field>
+      <field name="inlineAll">
+        <ref>bool</ref>
+        <p>
+          True if all invocations of the method should be inlined, or false if
+          only the invocation site used to create this refactoring should be
+          inlined.
+        </p>
+      </field>
+    </options>
+  </refactoring>
+  <refactoring kind="MOVE_FILE">
+    <p>
+      Move the given file and update all of the references to that file and from
+      it. The move operation is supported in general case - for renaming a file
+      in the same folder, moving it to a different folder or both.
+    </p>
+    <p>
+      The refactoring must be activated before an actual file moving operation
+      is performed.
+    </p>
+    <p>
+      The "offset" and "length" fields from the request are ignored, but the
+      file specified in the request specifies the file to be moved.
+    </p>
+    <options>
+      <field name="newFile">
+        <ref>FilePath</ref>
+        <p>
+          The new file path to which the given file is being moved.
+        </p>
+      </field>
+    </options>
+  </refactoring>
+  <refactoring kind="RENAME">
+    <p>
+      Rename a given element and all of the references to that element.
+    </p>
+    <p>
+      It is an error if the range contains anything other than all or part of
+      the name of a single function (including methods, getters and setters),
+      variable (including fields, parameters and local variables), class or
+      function type.
+    </p>
+    <feedback>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset to the beginning of the name selected to be renamed.
+        </p>
+      </field>
+      <field name="length">
+        <ref>int</ref>
+        <p>
+          The length of the name selected to be renamed.
+        </p>
+      </field>
+      <field name="elementKindName">
+        <ref>String</ref>
+        <p>
+          The human-readable description of the kind of element being renamed
+          (such as “class” or “function type alias”).
+        </p>
+      </field>
+      <field name="oldName">
+        <ref>String</ref>
+        <p>
+          The old name of the element before the refactoring.
+        </p>
+      </field>
+    </feedback>
+    <options>
+      <field name="newName">
+        <ref>String</ref>
+        <p>
+          The name that the element should have after the refactoring.
+        </p>
+      </field>
+    </options>
+  </refactoring>
+</refactorings>
+<h2 class="domain"><a name="index">Index</a></h2>
+<index></index>
+</body>
+</html>
diff --git a/pkg/analyzer_plugin/tool/spec/to_html.dart b/pkg/analyzer_plugin/tool/spec/to_html.dart
new file mode 100644
index 0000000..85502f1
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/to_html.dart
@@ -0,0 +1,773 @@
+// 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.
+
+/**
+ * Code for displaying the API as HTML.  This is used both for generating a
+ * full description of the API as a web page, and for generating doc comments
+ * in generated code.
+ */
+import 'dart:convert';
+
+import 'package:analyzer/src/codegen/html.dart';
+import 'package:analyzer/src/codegen/tools.dart';
+import 'package:html/dom.dart' as dom;
+
+import 'api.dart';
+import 'from_html.dart';
+
+/**
+ * Embedded stylesheet
+ */
+final String stylesheet = '''
+body {
+  font-family: 'Roboto', sans-serif;
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 0 16px;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #111;
+  background-color: #fdfdfd;
+  font-weight: 300;
+  -webkit-font-smoothing: auto;
+}
+
+h1 {
+  text-align: center;
+}
+
+h2, h3, h4, h5 {
+  margin-bottom: 0;
+}
+
+h2.domain {
+  border-bottom: 1px solid rgb(200, 200, 200);
+  margin-bottom: 0.5em;
+}
+
+h4 {
+  font-size: 18px;
+}
+
+h5 {
+  font-size: 16px;
+}
+
+p {
+  margin-top: 0;
+}
+
+pre {
+  margin: 0;
+  font-family: 'Source Code Pro', monospace;
+  font-size: 15px;
+}
+
+div.box {
+  background-color: rgb(240, 245, 240);
+  border-radius: 4px;
+  padding: 4px 12px;
+  margin: 16px 0;
+}
+
+div.hangingIndent {
+  padding-left: 3em;
+  text-indent: -3em;
+}
+
+dl dt {
+  font-weight: bold;
+}
+
+dl dd {
+  margin-left: 16px;
+}
+
+dt {
+  margin-top: 1em;
+}
+
+dt.notification {
+  font-weight: bold;
+}
+
+dt.refactoring {
+  font-weight: bold;
+}
+
+dt.request {
+  font-weight: bold;
+}
+
+dt.typeDefinition {
+  font-weight: bold;
+}
+
+a {
+  text-decoration: none;
+}
+
+a:focus, a:hover {
+  text-decoration: underline;
+}
+
+/* Styles for index */
+
+.subindex {
+}
+
+.subindex ul {
+  padding-left: 0;
+  margin-left: 0;
+
+  -webkit-margin-before: 0;
+  -webkit-margin-start: 0;
+  -webkit-padding-start: 0;
+
+  list-style-type: none;
+}
+'''
+    .trim();
+
+final GeneratedFile target =
+    new GeneratedFile('doc/api.html', (String pkgPath) {
+  ToHtmlVisitor visitor = new ToHtmlVisitor(readApi(pkgPath));
+  dom.Document document = new dom.Document();
+  document.append(new dom.DocumentType('html', null, null));
+  for (dom.Node node in visitor.collectHtml(visitor.visitApi)) {
+    document.append(node);
+  }
+  return document.outerHtml;
+});
+
+/**
+ * Visitor that records the mapping from HTML elements to various kinds of API
+ * nodes.
+ */
+class ApiMappings extends HierarchicalApiVisitor {
+  Map<dom.Element, Domain> domains = <dom.Element, Domain>{};
+
+  ApiMappings(Api api) : super(api);
+
+  @override
+  void visitDomain(Domain domain) {
+    domains[domain.html] = domain;
+  }
+}
+
+/**
+ * Helper methods for creating HTML elements.
+ */
+abstract class HtmlMixin {
+  void anchor(String id, void callback()) {
+    element('a', {'name': id}, callback);
+  }
+
+  void b(void callback()) => element('b', {}, callback);
+  void body(void callback()) => element('body', {}, callback);
+  void box(void callback()) {
+    element('div', {'class': 'box'}, callback);
+  }
+
+  void br() => element('br', {});
+  void dd(void callback()) => element('dd', {}, callback);
+  void dl(void callback()) => element('dl', {}, callback);
+  void dt(String cls, void callback()) =>
+      element('dt', {'class': cls}, callback);
+  void element(String name, Map<dynamic, String> attributes, [void callback()]);
+  void gray(void callback()) =>
+      element('span', {'style': 'color:#999999'}, callback);
+  void h1(void callback()) => element('h1', {}, callback);
+  void h2(String cls, void callback()) {
+    if (cls == null) {
+      return element('h2', {}, callback);
+    }
+    return element('h2', {'class': cls}, callback);
+  }
+
+  void h3(void callback()) => element('h3', {}, callback);
+  void h4(void callback()) => element('h4', {}, callback);
+  void h5(void callback()) => element('h5', {}, callback);
+  void hangingIndent(void callback()) =>
+      element('div', {'class': 'hangingIndent'}, callback);
+  void head(void callback()) => element('head', {}, callback);
+  void html(void callback()) => element('html', {}, callback);
+  void i(void callback()) => element('i', {}, callback);
+  void link(String id, void callback()) {
+    element('a', {'href': '#$id'}, callback);
+  }
+
+  void p(void callback()) => element('p', {}, callback);
+  void pre(void callback()) => element('pre', {}, callback);
+  void title(void callback()) => element('title', {}, callback);
+  void tt(void callback()) => element('tt', {}, callback);
+}
+
+/**
+ * Visitor that generates HTML documentation of the API.
+ */
+class ToHtmlVisitor extends HierarchicalApiVisitor
+    with HtmlMixin, HtmlGenerator {
+  /**
+   * Set of types defined in the API.
+   */
+  Set<String> definedTypes = new Set<String>();
+
+  /**
+   * Mappings from HTML elements to API nodes.
+   */
+  ApiMappings apiMappings;
+
+  ToHtmlVisitor(Api api)
+      : apiMappings = new ApiMappings(api),
+        super(api) {
+    apiMappings.visitApi();
+  }
+
+  /**
+   * Describe the payload of request, response, notification, refactoring
+   * feedback, or refactoring options.
+   *
+   * If [force] is true, then a section is inserted even if the payload is
+   * null.
+   */
+  void describePayload(TypeObject subType, String name, {bool force: false}) {
+    if (force || subType != null) {
+      h4(() {
+        write(name);
+      });
+      if (subType == null) {
+        p(() {
+          write('none');
+        });
+      } else {
+        visitTypeDecl(subType);
+      }
+    }
+  }
+
+  void generateDomainIndex(Domain domain) {
+    h4(() {
+      write(domain.name);
+      write(' (');
+      link('domain_${domain.name}', () => write('\u2191'));
+      write(')');
+    });
+    if (domain.requests.length > 0) {
+      element('div', {'class': 'subindex'}, () {
+        generateRequestsIndex(domain.requests);
+        if (domain.notifications.length > 0) {
+          generateNotificationsIndex(domain.notifications);
+        }
+      });
+    } else if (domain.notifications.length > 0) {
+      element('div', {'class': 'subindex'}, () {
+        generateNotificationsIndex(domain.notifications);
+      });
+    }
+  }
+
+  void generateIndex() {
+    h3(() => write('Domains'));
+    for (var domain in api.domains) {
+      if (domain.experimental ||
+          (domain.requests.length == 0 && domain.notifications == 0)) {
+        continue;
+      }
+      generateDomainIndex(domain);
+    }
+
+    generateTypesIndex(definedTypes);
+    generateRefactoringsIndex(api.refactorings);
+  }
+
+  void generateNotificationsIndex(Iterable<Notification> notifications) {
+    h5(() => write("Notifications"));
+    element('div', {'class': 'subindex'}, () {
+      element('ul', {}, () {
+        for (var notification in notifications) {
+          element(
+              'li',
+              {},
+              () => link('notification_${notification.longEvent}',
+                  () => write(notification.event)));
+        }
+      });
+    });
+  }
+
+  void generateRefactoringsIndex(Iterable<Refactoring> refactorings) {
+    if (refactorings == null) {
+      return;
+    }
+    h3(() {
+      write("Refactorings");
+      write(' (');
+      link('refactorings', () => write('\u2191'));
+      write(')');
+    });
+    // TODO: Individual refactorings are not yet hyperlinked.
+    element('div', {'class': 'subindex'}, () {
+      element('ul', {}, () {
+        for (var refactoring in refactorings) {
+          element(
+              'li',
+              {},
+              () => link('refactoring_${refactoring.kind}',
+                  () => write(refactoring.kind)));
+        }
+      });
+    });
+  }
+
+  void generateRequestsIndex(Iterable<Request> requests) {
+    h5(() => write("Requests"));
+    element('ul', {}, () {
+      for (var request in requests) {
+        element(
+            'li',
+            {},
+            () => link(
+                'request_${request.longMethod}', () => write(request.method)));
+      }
+    });
+  }
+
+  void generateTypesIndex(Set<String> types) {
+    h3(() {
+      write("Types");
+      write(' (');
+      link('types', () => write('\u2191'));
+      write(')');
+    });
+    element('div', {'class': 'subindex'}, () {
+      element('ul', {}, () {
+        for (var type in types) {
+          element('li', {}, () => link('type_$type', () => write(type)));
+        }
+      });
+    });
+  }
+
+  void javadocParams(TypeObject typeObject) {
+    if (typeObject != null) {
+      for (TypeObjectField field in typeObject.fields) {
+        hangingIndent(() {
+          write('@param ${field.name} ');
+          translateHtml(field.html, squashParagraphs: true);
+        });
+      }
+    }
+  }
+
+  /**
+   * Generate a description of [type] using [TypeVisitor].
+   *
+   * If [shortDesc] is non-null, the output is prefixed with this string
+   * and a colon.
+   *
+   * If [typeForBolding] is supplied, then fields in this type are shown in
+   * boldface.
+   */
+  void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) {
+    Set<String> fieldsToBold = new Set<String>();
+    if (typeForBolding != null) {
+      for (TypeObjectField field in typeForBolding.fields) {
+        fieldsToBold.add(field.name);
+      }
+    }
+    pre(() {
+      if (shortDesc != null) {
+        write('$shortDesc: ');
+      }
+      TypeVisitor typeVisitor =
+          new TypeVisitor(api, fieldsToBold: fieldsToBold);
+      addAll(typeVisitor.collectHtml(() {
+        typeVisitor.visitTypeDecl(type);
+      }));
+    });
+  }
+
+  /**
+   * Copy the contents of the given HTML element, translating the special
+   * elements that define the API appropriately.
+   */
+  void translateHtml(dom.Element html, {bool squashParagraphs: false}) {
+    for (dom.Node node in html.nodes) {
+      if (node is dom.Element) {
+        if (squashParagraphs && node.localName == 'p') {
+          translateHtml(node, squashParagraphs: squashParagraphs);
+          continue;
+        }
+        switch (node.localName) {
+          case 'domain':
+            visitDomain(apiMappings.domains[node]);
+            break;
+          case 'head':
+            head(() {
+              translateHtml(node, squashParagraphs: squashParagraphs);
+              element('link', {
+                'rel': 'stylesheet',
+                'href':
+                    'https://fonts.googleapis.com/css?family=Source+Code+Pro|Roboto:500,400italic,300,400',
+                'type': 'text/css'
+              });
+              element('style', {}, () {
+                writeln(stylesheet);
+              });
+            });
+            break;
+          case 'refactorings':
+            visitRefactorings(api.refactorings);
+            break;
+          case 'types':
+            visitTypes(api.types);
+            break;
+          case 'version':
+            translateHtml(node, squashParagraphs: squashParagraphs);
+            break;
+          case 'index':
+            generateIndex();
+            break;
+          default:
+            if (!specialElements.contains(node.localName)) {
+              element(node.localName, node.attributes, () {
+                translateHtml(node, squashParagraphs: squashParagraphs);
+              });
+            }
+        }
+      } else if (node is dom.Text) {
+        String text = node.text;
+        write(text);
+      }
+    }
+  }
+
+  @override
+  void visitApi() {
+    Iterable<TypeDefinition> apiTypes =
+        api.types.where((TypeDefinition td) => !td.experimental);
+    definedTypes = apiTypes.map((TypeDefinition td) => td.name).toSet();
+
+    html(() {
+      translateHtml(api.html);
+    });
+  }
+
+  @override
+  void visitDomain(Domain domain) {
+    if (domain.experimental) {
+      return;
+    }
+    h2('domain', () {
+      anchor('domain_${domain.name}', () {
+        write('${domain.name} domain');
+      });
+    });
+    translateHtml(domain.html);
+    if (domain.requests.isNotEmpty) {
+      h3(() {
+        write('Requests');
+      });
+      dl(() {
+        domain.requests.forEach(visitRequest);
+      });
+    }
+    if (domain.notifications.isNotEmpty) {
+      h3(() {
+        write('Notifications');
+      });
+      dl(() {
+        domain.notifications.forEach(visitNotification);
+      });
+    }
+  }
+
+  @override
+  void visitNotification(Notification notification) {
+    dt('notification', () {
+      anchor('notification_${notification.longEvent}', () {
+        write(notification.longEvent);
+      });
+      write(' (');
+      link('notification_${notification.longEvent}', () {
+        write('#');
+      });
+      write(')');
+    });
+    dd(() {
+      box(() {
+        showType(
+            'notification', notification.notificationType, notification.params);
+      });
+      translateHtml(notification.html);
+      describePayload(notification.params, 'parameters:');
+    });
+  }
+
+  @override
+  visitRefactoring(Refactoring refactoring) {
+    dt('refactoring', () {
+      write(refactoring.kind);
+    });
+    dd(() {
+      translateHtml(refactoring.html);
+      describePayload(refactoring.feedback, 'Feedback:', force: true);
+      describePayload(refactoring.options, 'Options:', force: true);
+    });
+  }
+
+  @override
+  void visitRefactorings(Refactorings refactorings) {
+    translateHtml(refactorings.html);
+    dl(() {
+      super.visitRefactorings(refactorings);
+    });
+  }
+
+  @override
+  void visitRequest(Request request) {
+    dt('request', () {
+      anchor('request_${request.longMethod}', () {
+        write(request.longMethod);
+      });
+      write(' (');
+      link('request_${request.longMethod}', () {
+        write('#');
+      });
+      write(')');
+    });
+    dd(() {
+      box(() {
+        showType('request', request.requestType, request.params);
+        br();
+        showType('response', request.responseType, request.result);
+      });
+      translateHtml(request.html);
+      describePayload(request.params, 'parameters:');
+      describePayload(request.result, 'returns:');
+    });
+  }
+
+  @override
+  void visitTypeDefinition(TypeDefinition typeDefinition) {
+    if (typeDefinition.experimental) {
+      return;
+    }
+    dt('typeDefinition', () {
+      anchor('type_${typeDefinition.name}', () {
+        write('${typeDefinition.name}: ');
+        TypeVisitor typeVisitor = new TypeVisitor(api, short: true);
+        addAll(typeVisitor.collectHtml(() {
+          typeVisitor.visitTypeDecl(typeDefinition.type);
+        }));
+      });
+    });
+    dd(() {
+      translateHtml(typeDefinition.html);
+      visitTypeDecl(typeDefinition.type);
+    });
+  }
+
+  @override
+  void visitTypeEnum(TypeEnum typeEnum) {
+    dl(() {
+      super.visitTypeEnum(typeEnum);
+    });
+  }
+
+  @override
+  void visitTypeEnumValue(TypeEnumValue typeEnumValue) {
+    bool isDocumented = false;
+    for (dom.Node node in typeEnumValue.html.nodes) {
+      if ((node is dom.Element && node.localName != 'code') ||
+          (node is dom.Text && node.text.trim().isNotEmpty)) {
+        isDocumented = true;
+        break;
+      }
+    }
+    dt('value', () {
+      write(typeEnumValue.value);
+    });
+    if (isDocumented) {
+      dd(() {
+        translateHtml(typeEnumValue.html);
+      });
+    }
+  }
+
+  @override
+  void visitTypeList(TypeList typeList) {
+    visitTypeDecl(typeList.itemType);
+  }
+
+  @override
+  void visitTypeMap(TypeMap typeMap) {
+    visitTypeDecl(typeMap.valueType);
+  }
+
+  @override
+  void visitTypeObject(TypeObject typeObject) {
+    dl(() {
+      super.visitTypeObject(typeObject);
+    });
+  }
+
+  @override
+  void visitTypeObjectField(TypeObjectField typeObjectField) {
+    dt('field', () {
+      b(() {
+        write(typeObjectField.name);
+        if (typeObjectField.value != null) {
+          write(' = ${JSON.encode(typeObjectField.value)}');
+        } else {
+          write(' (');
+          if (typeObjectField.optional) {
+            gray(() {
+              write('optional');
+            });
+            write(' ');
+          }
+          TypeVisitor typeVisitor = new TypeVisitor(api, short: true);
+          addAll(typeVisitor.collectHtml(() {
+            typeVisitor.visitTypeDecl(typeObjectField.type);
+          }));
+          write(')');
+        }
+      });
+    });
+    dd(() {
+      translateHtml(typeObjectField.html);
+    });
+  }
+
+  @override
+  void visitTypeReference(TypeReference typeReference) {}
+
+  @override
+  void visitTypes(Types types) {
+    translateHtml(types.html);
+    dl(() {
+      super.visitTypes(types);
+    });
+  }
+}
+
+/**
+ * Visitor that generates a compact representation of a type, such as:
+ *
+ * {
+ *   "id": String
+ *   "error": optional Error
+ *   "result": {
+ *     "version": String
+ *   }
+ * }
+ */
+class TypeVisitor extends HierarchicalApiVisitor
+    with HtmlMixin, HtmlCodeGenerator {
+  /**
+   * Set of fields which should be shown in boldface, or null if no field
+   * should be shown in boldface.
+   */
+  final Set<String> fieldsToBold;
+
+  /**
+   * True if a short description should be generated.  In a short description,
+   * objects are shown as simply "object", and enums are shown as "String".
+   */
+  final bool short;
+
+  TypeVisitor(Api api, {this.fieldsToBold, this.short: false}) : super(api);
+
+  @override
+  void visitTypeEnum(TypeEnum typeEnum) {
+    if (short) {
+      write('String');
+      return;
+    }
+    writeln('enum {');
+    indent(() {
+      for (TypeEnumValue value in typeEnum.values) {
+        writeln(value.value);
+      }
+    });
+    write('}');
+  }
+
+  @override
+  void visitTypeList(TypeList typeList) {
+    write('List<');
+    visitTypeDecl(typeList.itemType);
+    write('>');
+  }
+
+  @override
+  void visitTypeMap(TypeMap typeMap) {
+    write('Map<');
+    visitTypeDecl(typeMap.keyType);
+    write(', ');
+    visitTypeDecl(typeMap.valueType);
+    write('>');
+  }
+
+  @override
+  void visitTypeObject(TypeObject typeObject) {
+    if (short) {
+      write('object');
+      return;
+    }
+    writeln('{');
+    indent(() {
+      for (TypeObjectField field in typeObject.fields) {
+        write('"');
+        if (fieldsToBold != null && fieldsToBold.contains(field.name)) {
+          b(() {
+            write(field.name);
+          });
+        } else {
+          write(field.name);
+        }
+        write('": ');
+        if (field.value != null) {
+          write(JSON.encode(field.value));
+        } else {
+          if (field.optional) {
+            gray(() {
+              write('optional');
+            });
+            write(' ');
+          }
+          visitTypeDecl(field.type);
+        }
+        writeln();
+      }
+    });
+    write('}');
+  }
+
+  @override
+  void visitTypeReference(TypeReference typeReference) {
+    String displayName = typeReference.typeName;
+    if (api.types.containsKey(typeReference.typeName)) {
+      link('type_${typeReference.typeName}', () {
+        write(displayName);
+      });
+    } else {
+      write(displayName);
+    }
+  }
+
+  @override
+  void visitTypeUnion(TypeUnion typeUnion) {
+    bool verticalBarNeeded = false;
+    for (TypeDecl choice in typeUnion.choices) {
+      if (verticalBarNeeded) {
+        write(' | ');
+      }
+      visitTypeDecl(choice);
+      verticalBarNeeded = true;
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 2861f6b..69302df 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -47,7 +47,7 @@
 
   CompilerImpl(this.provider, api.CompilerOutput outputProvider, this.handler,
       CompilerOptions options,
-      {MakeBackendFunction makeBackend, MakeReporterFunction makeReporter})
+      {MakeReporterFunction makeReporter})
       // NOTE: allocating measurer is done upfront to ensure the wallclock is
       // started before other computations.
       : measurer = new Measurer(enableTaskMeasurements: options.verbose),
@@ -56,7 +56,6 @@
             options: options,
             outputProvider: outputProvider,
             environment: new _Environment(options.environment),
-            makeBackend: makeBackend,
             makeReporter: makeReporter) {
     _Environment env = environment;
     env.compiler = this;
@@ -222,10 +221,12 @@
             .load(options.platformConfigUri, provider)
             .then((Map<String, Uri> mapping) {
           resolvedUriTranslator.resolvedUriTranslator =
-              new ResolvedUriTranslator(mapping, reporter);
+              new ResolvedUriTranslator(
+                  mapping, reporter, options.platformConfigUri);
         });
       });
     }
+    // TODO(johnniwinther): This does not apply anymore.
     // The incremental compiler sets up the sdk before run.
     // Therefore this will be called a second time.
     return future;
@@ -391,6 +392,19 @@
       }
       return "true";
     }
+
+    // Note: we return null on `dart:io` here, even if we allow users to
+    // unconditionally import it.
+    //
+    // In the past it was invalid to import `dart:io` for client apps. We just
+    // made it valid to import it as a stopgap measure to support packages like
+    // `http`. This is temporary until we support config-imports in the
+    // language.
+    //
+    // Because it is meant to be temporary and because the returned `dart:io`
+    // implementation will throw on most APIs, we still preserve that
+    // when compiling client apps the `dart:io` library is technically not
+    // supported, and so `const bool.fromEnvironment(dart.library.io)` is false.
     return null;
   }
 }
diff --git a/pkg/compiler/lib/src/cache_strategy.dart b/pkg/compiler/lib/src/cache_strategy.dart
deleted file mode 100644
index 3136a18..0000000
--- a/pkg/compiler/lib/src/cache_strategy.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:collection' show HashMap, HashSet;
-
-/**
- * Helper class for allocating sets and maps appropriate for caching objects
- * that can be assumed to be canonicalized.
- *
- * When compiling dart2js to JavaScript, profiling reveals that identity maps
- * and sets have superior performance.  However, we know that [Object.hashCode]
- * is slow on the Dart VM.  This class is meant to encapsulate the decision
- * about which data structure is best, and we anticipate specific subclasses
- * for JavaScript and Dart VM in the future.
- */
-class CacheStrategy {
-  final bool hasIncrementalSupport;
-
-  CacheStrategy(this.hasIncrementalSupport);
-
-  Map newMap() => hasIncrementalSupport ? new HashMap.identity() : null;
-
-  Set newSet() => hasIncrementalSupport ? new HashSet.identity() : null;
-}
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 07987db..7c5ab6a 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -12,12 +12,13 @@
 import 'constants/expressions.dart';
 import 'elements/resolution_types.dart';
 import 'elements/elements.dart';
+import 'elements/entities.dart';
 import 'elements/modelx.dart'
     show BaseFunctionElementX, ClassElementX, ElementX;
 import 'elements/visitor.dart' show ElementVisitor;
 import 'js_backend/js_backend.dart' show JavaScriptBackend;
 import 'resolution/tree_elements.dart' show TreeElements;
-import 'tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import 'tree/tree.dart';
 import 'util/util.dart';
 import 'world.dart' show ClosedWorldRefiner;
@@ -114,19 +115,6 @@
       });
     });
   }
-
-  void forgetElement(var closure) {
-    ClosureClassElement cls;
-    if (closure is ClosureFieldElement) {
-      cls = closure.closureClass;
-    } else if (closure is SynthesizedCallMethodElementX) {
-      cls = closure.closureClass;
-    } else {
-      throw new SpannableAssertionFailure(
-          closure, 'Not a closure: $closure (${closure.runtimeType}).');
-    }
-    compiler.enqueuer.codegen.forgetEntity(cls, compiler);
-  }
 }
 
 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as
@@ -286,6 +274,9 @@
 
   BoxLocal(this.name, this.executableContext);
 
+  @override
+  MemberElement get memberContext => executableContext.memberContext;
+
   String toString() => 'BoxLocal($name)';
 }
 
@@ -359,6 +350,9 @@
 
   ThisLocal(this.executableContext);
 
+  @override
+  MemberElement get memberContext => executableContext.memberContext;
+
   String get name => 'this';
 
   ClassElement get enclosingClass => executableContext.enclosingClass;
@@ -1202,6 +1196,9 @@
 
   TypeVariableLocal(this.typeVariable, this.executableContext);
 
+  @override
+  MemberElement get memberContext => executableContext.memberContext;
+
   String get name => typeVariable.name;
 
   int get hashCode => typeVariable.hashCode;
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 81248d9..40bd9e0 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -27,7 +27,6 @@
   static const String fatalWarnings = '--fatal-warnings';
   static const String generateCodeWithCompileTimeErrors =
       '--generate-code-with-compile-time-errors';
-  static const String incrementalSupport = '--incremental-support';
   static const String minify = '--minify';
   static const String noFrequencyBasedMinification =
       '--no-frequency-based-minification';
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 73e22cd..462be2a 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -4,352 +4,19 @@
 
 library dart2js.backend_api;
 
-import 'dart:async' show Future;
-
 import '../common.dart';
 import '../common/codegen.dart' show CodegenImpact;
-import '../common/resolution.dart' show ResolutionImpact, Frontend, Target;
-import '../compile_time_constants.dart'
-    show BackendConstantEnvironment, ConstantCompilerTask;
-import '../compiler.dart' show Compiler;
-import '../constants/constant_system.dart' show ConstantSystem;
+import '../common/resolution.dart' show ResolutionImpact;
 import '../constants/expressions.dart' show ConstantExpression;
-import '../constants/values.dart' show ConstantValue;
+import '../elements/types.dart';
 import '../elements/resolution_types.dart'
     show ResolutionDartType, ResolutionInterfaceType;
-import '../elements/elements.dart'
-    show
-        ClassElement,
-        Element,
-        FunctionElement,
-        MemberElement,
-        MethodElement,
-        LibraryElement;
 import '../elements/entities.dart';
-import '../enqueue.dart' show Enqueuer, EnqueueTask, ResolutionEnqueuer;
-import '../io/code_output.dart' show CodeBuffer;
-import '../io/source_information.dart' show SourceInformationStrategy;
-import '../js_backend/backend_helpers.dart' as js_backend show BackendHelpers;
-import '../js_backend/js_backend.dart' as js_backend;
-import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
-import '../native/native.dart' as native show NativeEnqueuer, maybeEnableNative;
-import '../patch_parser.dart'
-    show checkNativeAnnotation, checkJsInteropAnnotation;
+import '../enqueue.dart' show ResolutionEnqueuer;
 import '../serialization/serialization.dart'
     show DeserializerPlugin, SerializerPlugin;
 import '../tree/tree.dart' show Node;
-import '../universe/world_impact.dart'
-    show ImpactStrategy, WorldImpact, WorldImpactBuilder;
-import '../world.dart' show ClosedWorld, ClosedWorldRefiner;
-import 'codegen.dart' show CodegenWorkItem;
-import 'tasks.dart' show CompilerTask;
-
-abstract class Backend extends Target {
-  final Compiler compiler;
-
-  Backend(this.compiler);
-
-  /// Returns true if the backend supports reflection.
-  bool get supportsReflection;
-
-  /// The [ConstantSystem] used to interpret compile-time constants for this
-  /// backend.
-  ConstantSystem get constantSystem;
-
-  /// The constant environment for the backend interpretation of compile-time
-  /// constants.
-  BackendConstantEnvironment get constants;
-
-  /// The compiler task responsible for the compilation of constants for both
-  /// the frontend and the backend.
-  ConstantCompilerTask get constantCompilerTask;
-
-  /// Backend transformation methods for the world impacts.
-  ImpactTransformer get impactTransformer;
-
-  /// The strategy used for collecting and emitting source information.
-  SourceInformationStrategy get sourceInformationStrategy {
-    return const SourceInformationStrategy();
-  }
-
-  /// Common classes used by the backend.
-  BackendClasses get backendClasses;
-
-  /// Interface for serialization of backend specific data.
-  BackendSerialization get serialization => const BackendSerialization();
-
-  // TODO(johnniwinther): Move this to the JavaScriptBackend.
-  String get patchVersion => null;
-
-  /// Set of classes that need to be considered for reflection although not
-  /// otherwise visible during resolution.
-  Iterable<ClassElement> classesRequiredForReflection = const [];
-
-  // Given a [FunctionElement], return a buffer with the code generated for it
-  // or null if no code was generated.
-  CodeBuffer codeOf(Element element) => null;
-
-  void initializeHelperClasses() {}
-
-  /// Compute the [WorldImpact] for backend helper methods.
-  WorldImpact computeHelpersImpact();
-
-  /// Creates an [Enqueuer] for code generation specific to this backend.
-  Enqueuer createCodegenEnqueuer(CompilerTask task, Compiler compiler);
-
-  WorldImpact codegen(CodegenWorkItem work);
-
-  // The backend determines the native resolution enqueuer, with a no-op
-  // default, so tools like dart2dart can ignore the native classes.
-  native.NativeEnqueuer nativeResolutionEnqueuer() {
-    return new native.NativeEnqueuer();
-  }
-
-  native.NativeEnqueuer nativeCodegenEnqueuer() {
-    return new native.NativeEnqueuer();
-  }
-
-  /// Generates the output and returns the total size of the generated code.
-  int assembleProgram(ClosedWorld closedWorld);
-
-  List<CompilerTask> get tasks;
-
-  void onResolutionComplete(
-      ClosedWorld closedWorld, ClosedWorldRefiner closedWorldRefiner) {}
-  void onTypeInferenceComplete() {}
-
-  bool classNeedsRti(ClassElement cls);
-  bool methodNeedsRti(FunctionElement function);
-
-  /// Enable compilation of code with compile time errors. Returns `true` if
-  /// supported by the backend.
-  bool enableCodegenWithErrorsIfSupported(Spannable node);
-
-  /// Enable deferred loading. Returns `true` if the backend supports deferred
-  /// loading.
-  bool enableDeferredLoadingIfSupported(Spannable node);
-
-  /// Returns the [WorldImpact] of enabling deferred loading.
-  WorldImpact computeDeferredLoadingImpact() => const WorldImpact();
-
-  /// Called during codegen when [constant] has been used.
-  void computeImpactForCompileTimeConstant(ConstantValue constant,
-      WorldImpactBuilder impactBuilder, bool isForResolution) {}
-
-  /// Called to notify to the backend that a class is being instantiated. Any
-  /// backend specific [WorldImpact] of this is returned.
-  WorldImpact registerInstantiatedClass(ClassElement cls,
-          {bool forResolution}) =>
-      const WorldImpact();
-
-  /// Called to notify to the backend that a class is implemented by an
-  /// instantiated class. Any backend specific [WorldImpact] of this is
-  /// returned.
-  WorldImpact registerImplementedClass(ClassElement cls,
-          {bool forResolution}) =>
-      const WorldImpact();
-
-  /// Called to instruct to the backend register [type] as instantiated on
-  /// [enqueuer].
-  void registerInstantiatedType(ResolutionInterfaceType type) {}
-
-  /// Register a runtime type variable bound tests between [typeArgument] and
-  /// [bound].
-  void registerTypeVariableBoundsSubtypeCheck(
-      ResolutionDartType typeArgument, ResolutionDartType bound) {}
-
-  /// Called to instruct the backend to register that a closure exists for a
-  /// function on an instantiated generic class. Any backend specific
-  /// [WorldImpact] of this is returned.
-  WorldImpact registerClosureWithFreeTypeVariables(Element closure,
-          {bool forResolution}) =>
-      const WorldImpact();
-
-  /// Called to register that a member has been closurized. Any backend specific
-  /// [WorldImpact] of this is returned.
-  WorldImpact registerBoundClosure() => const WorldImpact();
-
-  /// Called to register that a static function has been closurized. Any backend
-  /// specific [WorldImpact] of this is returned.
-  WorldImpact registerGetOfStaticFunction() => const WorldImpact();
-
-  /// Returns whether or not `noSuchMethod` support has been enabled.
-  bool get enabledNoSuchMethod => false;
-
-  /// Called to enable support for isolates. Any backend specific [WorldImpact]
-  /// of this is returned.
-  WorldImpact enableIsolateSupport({bool forResolution});
-
-  void registerConstSymbol(String name) {}
-
-  ClassElement defaultSuperclass(ClassElement element) {
-    return compiler.commonElements.objectClass;
-  }
-
-  bool isInterceptorClass(ClassElement element) => false;
-
-  /// Returns `true` if [element] is implemented via typed JavaScript interop.
-  // TODO(johnniwinther): Move this to [JavaScriptBackend].
-  bool isJsInterop(Element element) => false;
-
-  /// Returns `true` if the `native` pseudo keyword is supported for [library].
-  bool canLibraryUseNative(LibraryElement library) {
-    // TODO(johnniwinther): Move this to [JavaScriptBackend].
-    return native.maybeEnableNative(compiler, library);
-  }
-
-  @override
-  bool isTargetSpecificLibrary(LibraryElement library) {
-    // TODO(johnniwinther): Remove this when patching is only done by the
-    // JavaScript backend.
-    Uri canonicalUri = library.canonicalUri;
-    if (canonicalUri == js_backend.BackendHelpers.DART_JS_HELPER ||
-        canonicalUri == js_backend.BackendHelpers.DART_INTERCEPTORS) {
-      return true;
-    }
-    return false;
-  }
-
-  /// Called to register that [element] is statically known to be used. Any
-  /// backend specific [WorldImpact] of this is returned.
-  WorldImpact registerUsedElement(MemberElement element,
-          {bool forResolution}) =>
-      const WorldImpact();
-
-  /// This method is called immediately after the [LibraryElement] [library] has
-  /// been created.
-  void onLibraryCreated(LibraryElement library) {}
-
-  /// This method is called immediately after the [library] and its parts have
-  /// been scanned.
-  Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
-    // TODO(johnniwinther): Move this to [JavaScriptBackend].
-    if (!compiler.serialization.isDeserialized(library)) {
-      if (canLibraryUseNative(library)) {
-        library.forEachLocalMember((Element element) {
-          if (element.isClass) {
-            checkNativeAnnotation(compiler, element);
-          }
-        });
-      }
-      checkJsInteropAnnotation(compiler, library);
-      library.forEachLocalMember((Element element) {
-        checkJsInteropAnnotation(compiler, element);
-        if (element.isClass && isJsInterop(element)) {
-          ClassElement classElement = element;
-          classElement.forEachMember((_, memberElement) {
-            checkJsInteropAnnotation(compiler, memberElement);
-          });
-        }
-      });
-    }
-    return new Future.value();
-  }
-
-  /// This method is called when all new libraries loaded through
-  /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
-  /// have been computed.
-  Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
-    return new Future.value();
-  }
-
-  /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
-  /// annotations. The arguments corresponds to the unions of the corresponding
-  /// fields of the annotations.
-  void registerMirrorUsage(
-      Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) {}
-
-  /// Returns true if this element needs reflection information at runtime.
-  bool isAccessibleByReflection(Element element) => true;
-
-  /// Returns true if this member element needs reflection information at
-  /// runtime.
-  bool isMemberAccessibleByReflection(MemberElement element) => true;
-
-  /// Returns true if this element is covered by a mirrorsUsed annotation.
-  ///
-  /// Note that it might still be ok to tree shake the element away if no
-  /// reflection is used in the program (and thus [isTreeShakingDisabled] is
-  /// still false). Therefore _do not_ use this predicate to decide inclusion
-  /// in the tree, use [requiredByMirrorSystem] instead.
-  bool referencedFromMirrorSystem(Element element, [recursive]) => false;
-
-  /// Returns true if this element has to be enqueued due to
-  /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if
-  /// normal tree shaking is still active ([isTreeShakingDisabled] is false).
-  bool requiredByMirrorSystem(Element element) => false;
-
-  /// Returns true if global optimizations such as type inferencing
-  /// can apply to this element. One category of elements that do not
-  /// apply is runtime helpers that the backend calls, but the
-  /// optimizations don't see those calls.
-  bool canBeUsedForGlobalOptimizations(Element element) => true;
-
-  /// Called when [enqueuer]'s queue is empty, but before it is closed.
-  /// This is used, for example, by the JS backend to enqueue additional
-  /// elements needed for reflection. [recentClasses] is a collection of
-  /// all classes seen for the first time by the [enqueuer] since the last call
-  /// to [onQueueEmpty].
-  ///
-  /// A return value of [:true:] indicates that [recentClasses] has been
-  /// processed and its elements do not need to be seen in the next round. When
-  /// [:false:] is returned, [onQueueEmpty] will be called again once the
-  /// resolution queue has drained and [recentClasses] will be a superset of the
-  /// current value.
-  ///
-  /// There is no guarantee that a class is only present once in
-  /// [recentClasses], but every class seen by the [enqueuer] will be present in
-  /// [recentClasses] at least once.
-  bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) {
-    return true;
-  }
-
-  /// Called after the queue is closed. [onQueueEmpty] may be called multiple
-  /// times, but [onQueueClosed] is only called once.
-  void onQueueClosed() {}
-
-  /// Called when the compiler starts running the codegen enqueuer. The
-  /// [WorldImpact] of enabled backend features is returned.
-  WorldImpact onCodegenStart(ClosedWorld closedWorld) => const WorldImpact();
-
-  /// Called when code generation has been completed.
-  void onCodegenEnd() {}
-
-  // Does this element belong in the output
-  bool shouldOutput(Element element) => true;
-
-  FunctionElement helperForBadMain() => null;
-
-  FunctionElement helperForMissingMain() => null;
-
-  FunctionElement helperForMainArity() => null;
-
-  void forgetElement(Element element) {}
-
-  /// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
-  WorldImpact computeMainImpact(MethodElement mainMethod,
-          {bool forResolution}) =>
-      const WorldImpact();
-
-  /// Returns the location of the patch-file associated with [libraryName]
-  /// resolved from [plaformConfigUri].
-  ///
-  /// Returns null if there is none.
-  Uri resolvePatchUri(String libraryName, Uri plaformConfigUri);
-
-  /// Creates an impact strategy to use for compilation.
-  ImpactStrategy createImpactStrategy(
-      {bool supportDeferredLoad: true,
-      bool supportDumpInfo: true,
-      bool supportSerialization: true}) {
-    return const ImpactStrategy();
-  }
-
-  /// Backend access to the front-end.
-  Frontend get frontend => compiler.resolution;
-
-  EnqueueTask makeEnqueuer() => new EnqueueTask(compiler);
-}
+import '../universe/world_impact.dart' show WorldImpact;
 
 /// Interface for resolving native data for a target specific element.
 abstract class NativeRegistry {
@@ -396,34 +63,136 @@
 
 /// Interface providing access to core classes used by the backend.
 abstract class BackendClasses {
-  ClassElement get intImplementation;
-  ClassElement get doubleImplementation;
-  ClassElement get numImplementation;
-  ClassElement get stringImplementation;
-  ClassElement get listImplementation;
-  ClassElement get mutableListImplementation;
-  ClassElement get growableListImplementation;
-  ClassElement get fixedListImplementation;
-  ClassElement get constListImplementation;
-  ClassElement get mapImplementation;
-  ClassElement get constMapImplementation;
-  ClassElement get functionImplementation;
-  ClassElement get typeImplementation;
-  ClassElement get boolImplementation;
-  ClassElement get nullImplementation;
-  ClassElement get uint32Implementation;
-  ClassElement get uint31Implementation;
-  ClassElement get positiveIntImplementation;
-  ClassElement get syncStarIterableImplementation;
-  ClassElement get asyncFutureImplementation;
-  ClassElement get asyncStarStreamImplementation;
-  ClassElement get indexableImplementation;
-  ClassElement get mutableIndexableImplementation;
-  ClassElement get indexingBehaviorImplementation;
-  ClassElement get interceptorImplementation;
+  /// Returns the backend implementation class for `int`. This is the `JSInt`
+  /// class.
+  ClassEntity get intClass;
 
-  bool isDefaultEqualityImplementation(MemberElement element);
-  bool isInterceptorClass(ClassElement cls);
-  bool isNativeClass(ClassElement element);
-  bool isNativeMember(MemberElement element);
+  /// Returns the backend implementation class for `double`. This is the
+  /// `JSDouble` class.
+  ClassEntity get doubleClass;
+
+  /// Returns the backend implementation class for `num`. This is the `JSNum`
+  /// class.
+  ClassEntity get numClass;
+
+  /// Returns the backend implementation class for `String`. This is the
+  /// `JSString` class.
+  ClassEntity get stringClass;
+
+  /// Returns the backend implementation class for `List`. This is the
+  /// `JSArray` class.
+  ClassEntity get listClass;
+
+  /// Returns the backend dummy class used to track mutable implementations of
+  /// `List` in type masks. This is the `JSMutableArray` class.
+  ClassEntity get mutableListClass;
+
+  /// Returns the backend dummy class used to track growable implementations of
+  /// `List` in type masks. This is the `JSExtendableArray` class.
+  ClassEntity get growableListClass;
+
+  /// Returns the backend dummy class used to track fixed-sized implementations
+  /// of `List` in type masks. This is the `JSFixedArray` class.
+  ClassEntity get fixedListClass;
+
+  /// Returns the backend dummy class used to track unmodifiable (constant)
+  /// implementations of `List` in type masks. This is the `JSUnmodifiableArray`
+  /// class.
+  ClassEntity get constListClass;
+
+  /// Returns the backend implementation class for map literals. This is the
+  /// `LinkedHashMap` class.
+  ClassEntity get mapClass;
+
+  /// Returns the backend superclass for implementations of constant map
+  /// literals. This is the `ConstantMap` class.
+  ClassEntity get constMapClass;
+
+  /// Returns the backend implementation class for `Function`. This is the
+  /// `Function` class from 'dart:core'.
+  ClassEntity get functionClass;
+
+  /// Returns the backend implementation class for `Type`. This is the
+  /// `TypeImpl` class.
+  ClassEntity get typeClass;
+
+  /// Returns the type of the implementation class for `Type`.
+  InterfaceType get typeType;
+
+  /// Returns the backend implementation class for `bool`. This is the `JSBool`
+  /// class.
+  ClassEntity get boolClass;
+
+  /// Returns the backend implementation class for `null`. This is the `JSNull`
+  /// class.
+  ClassEntity get nullClass;
+
+  /// Returns the backend dummy class used to track unsigned 32-bit integer
+  /// values in type masks. This is the `JSUint32` class.
+  ClassEntity get uint32Class;
+
+  /// Returns the backend dummy class used to track unsigned 31-bit integer
+  /// values in type masks. This is the `JSUint31` class.
+  ClassEntity get uint31Class;
+
+  /// Returns the backend dummy class used to track position values in type
+  /// masks. This is the `JSPositiveInt` class.
+  ClassEntity get positiveIntClass;
+
+  /// Returns the backend implementation class for the `Iterable` used in
+  /// `sync*` methods. This is the `_SyncStarIterable` class in dart:async.
+  ClassEntity get syncStarIterableClass;
+
+  /// Returns the backend implementation class for the `Future` used in
+  /// `async` methods. This is the `_Future` class in dart:async.
+  ClassEntity get asyncFutureClass;
+
+  /// Returns the backend implementation class for the `Stream` used in
+  /// `async*` methods. This is the `_ControllerStream` class in dart:async.
+  ClassEntity get asyncStarStreamClass;
+
+  /// Returns the backend superclass directly indexable class, that is classes
+  /// that natively support the `[]` operator. This is the `JSIndexable` class.
+  ClassEntity get indexableClass;
+
+  /// Returns the backend superclass directly indexable class, that is classes
+  /// that natively support the `[]=` operator. This is the `JSMutableIndexable`
+  /// class.
+  ClassEntity get mutableIndexableClass;
+
+  /// Returns the backend class used to mark native classes that support integer
+  /// indexing, that is `[]` and `[]=` where the key is an integer. This is the
+  /// `JavaScriptIndexingBehavior` class.
+  ClassEntity get indexingBehaviorClass;
+
+  /// Returns the backend superclass for all intercepted classes. This is the
+  /// `Interceptor` class.
+  ClassEntity get interceptorClass;
+
+  /// Returns `true` if [element] is a default implementation of `Object.==`.
+  /// This either `Object.==`, `Intercepter.==` or `Null.==`.
+  bool isDefaultEqualityImplementation(MemberEntity element);
+
+  /// Returns `true` if [cls] is an intercepted class.
+  // TODO(johnniwinther): Rename this to `isInterceptedClass`.
+  bool isInterceptorClass(ClassEntity cls);
+
+  /// Returns `true` if [cls] is a native class.
+  bool isNativeClass(ClassEntity element);
+
+  /// Returns `true` if [element] is a native member of a native class.
+  bool isNativeMember(MemberEntity element);
+
+  /// Returns the type of the constant map implementation for a const map
+  /// literal of [sourceType]. If [hasProtoKey] the map contains key of value
+  /// '__proto__' and if [onlyStringKeys] all keys are string constants.
+  InterfaceType getConstantMapTypeFor(InterfaceType sourceType,
+      {bool hasProtoKey: false, bool onlyStringKeys: false});
+
+  /// Returns the type of the constant symbol implementation class.
+  InterfaceType get symbolType;
+
+  /// Returns the field of the constant symbol implementation class that holds
+  /// its internal name.
+  FieldEntity get symbolField;
 }
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index cd17e56..91f6d67 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -5,7 +5,6 @@
 library dart2js.common.codegen;
 
 import '../common.dart';
-import '../common/backend_api.dart' show Backend;
 import '../constants/values.dart' show ConstantValue;
 import '../elements/resolution_types.dart'
     show ResolutionDartType, ResolutionInterfaceType;
@@ -17,7 +16,7 @@
         FunctionElement,
         LocalFunctionElement,
         ResolvedAst;
-import '../enqueue.dart' show Enqueuer;
+import '../js_backend/backend.dart' show JavaScriptBackend;
 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
 import '../universe/world_impact.dart'
     show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
@@ -226,9 +225,9 @@
 class CodegenWorkItem extends WorkItem {
   CodegenRegistry registry;
   final ResolvedAst resolvedAst;
-  final Backend backend;
+  final JavaScriptBackend backend;
 
-  factory CodegenWorkItem(Backend backend, AstElement element) {
+  factory CodegenWorkItem(JavaScriptBackend backend, AstElement element) {
     // If this assertion fails, the resolution callbacks of the backend may be
     // missing call of form registry.registerXXX. Alternatively, the code
     // generation could spuriously be adding dependencies on things we know we
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 715d8cf..0d056ea 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -162,9 +162,20 @@
   /// The URI for 'dart:html'.
   static final Uri dart_html = new Uri(scheme: 'dart', path: 'html');
 
+  /// The URI for 'dart:html_common'.
+  static final Uri dart_html_common =
+      new Uri(scheme: 'dart', path: 'html_common');
+
+  /// The URI for 'dart:indexed_db'.
+  static final Uri dart_indexed_db =
+      new Uri(scheme: 'dart', path: 'indexed_db');
+
   /// The URI for 'dart:isolate'.
   static final Uri dart_isolate = new Uri(scheme: 'dart', path: 'isolate');
 
+  /// The URI for 'dart:math'.
+  static final Uri dart_math = new Uri(scheme: 'dart', path: 'math');
+
   /// The URI for 'dart:mirrors'.
   static final Uri dart_mirrors = new Uri(scheme: 'dart', path: 'mirrors');
 
@@ -175,6 +186,10 @@
   static final Uri dart__native_typed_data =
       new Uri(scheme: 'dart', path: '_native_typed_data');
 
+  /// The URI for 'dart:typed_data'.
+  static final Uri dart_typed_data =
+      new Uri(scheme: 'dart', path: 'typed_data');
+
   /// The URI for 'dart:svg'.
   static final Uri dart_svg = new Uri(scheme: 'dart', path: 'svg');
 
@@ -183,4 +198,7 @@
 
   /// The URI for 'dart:web_gl'.
   static final Uri dart_web_gl = new Uri(scheme: 'dart', path: 'web_gl');
+
+  /// The URI for 'dart:web_sql'.
+  static final Uri dart_web_sql = new Uri(scheme: 'dart', path: 'web_sql');
 }
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 0ccd78e..3cf8de5 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -6,7 +6,6 @@
 
 import '../common.dart';
 import '../compile_time_constants.dart';
-import '../compiler.dart' show Compiler;
 import '../constants/expressions.dart' show ConstantExpression;
 import '../constants/values.dart' show ConstantValue;
 import '../core_types.dart' show CommonElements;
@@ -16,7 +15,6 @@
         AstElement,
         ClassElement,
         Element,
-        Entity,
         ExecutableElement,
         FunctionElement,
         FunctionSignature,
@@ -25,12 +23,15 @@
         MethodElement,
         ResolvedAst,
         TypedefElement;
+import '../elements/entities.dart';
 import '../enqueue.dart' show ResolutionEnqueuer;
 import '../id_generator.dart';
+import '../js_backend/backend.dart' show JavaScriptBackend;
 import '../mirrors_used.dart';
 import '../options.dart' show CompilerOptions;
 import '../parser/element_listener.dart' show ScannerOptions;
 import '../parser/parser_task.dart';
+import '../scanner/scanner_task.dart';
 import '../patch_parser.dart';
 import '../resolution/resolution.dart';
 import '../tree/tree.dart' show Send, TypeAnnotation;
@@ -206,8 +207,6 @@
   /// impact.
   void emptyCache();
 
-  void forgetElement(Element element);
-
   /// Returns `true` if [value] is the top-level [proxy] annotation from the
   /// core library.
   bool isProxyConstant(ConstantValue value);
@@ -215,11 +214,16 @@
 
 /// A container of commonly used dependencies for tasks that involve parsing.
 abstract class ParsingContext {
-  factory ParsingContext(DiagnosticReporter reporter, ParserTask parser,
-      PatchParserTask patchParser, Backend backend) = _ParsingContext;
+  factory ParsingContext(
+      DiagnosticReporter reporter,
+      ParserTask parser,
+      ScannerTask scanner,
+      PatchParserTask patchParser,
+      JavaScriptBackend backend) = _ParsingContext;
 
   DiagnosticReporter get reporter;
   ParserTask get parser;
+  ScannerTask get scanner;
   PatchParserTask get patchParser;
 
   /// Use [patchParser] directly instead.
@@ -237,10 +241,12 @@
 class _ParsingContext implements ParsingContext {
   final DiagnosticReporter reporter;
   final ParserTask parser;
+  final ScannerTask scanner;
   final PatchParserTask patchParser;
-  final Backend backend;
+  final JavaScriptBackend backend;
 
-  _ParsingContext(this.reporter, this.parser, this.patchParser, this.backend);
+  _ParsingContext(
+      this.reporter, this.parser, this.scanner, this.patchParser, this.backend);
 
   @override
   measure(f()) => parser.measure(f);
diff --git a/pkg/compiler/lib/src/common/tasks.dart b/pkg/compiler/lib/src/common/tasks.dart
index 2c5d62c..c9ecaca 100644
--- a/pkg/compiler/lib/src/common/tasks.dart
+++ b/pkg/compiler/lib/src/common/tasks.dart
@@ -188,14 +188,6 @@
   int getSubtaskTime(String subtask) => _subtasks[subtask].timing;
 
   bool getSubtaskIsRunning(String subtask) => _subtasks[subtask].isRunning;
-
-  /// Used by the dart2js_incremental to provide measurements on each
-  /// incremental compile.
-  clearMeasurements() {
-    if (_isDisabled) return;
-    _watch.reset();
-    _subtasks.values.forEach((s) => s.clearMeasurements());
-  }
 }
 
 class GenericTask extends CompilerTask {
diff --git a/pkg/compiler/lib/src/common/work.dart b/pkg/compiler/lib/src/common/work.dart
index c36a2a5..b8cd351 100644
--- a/pkg/compiler/lib/src/common/work.dart
+++ b/pkg/compiler/lib/src/common/work.dart
@@ -5,9 +5,7 @@
 library dart2js.common.work;
 
 import '../common.dart';
-import '../compiler.dart' show Compiler;
 import '../elements/elements.dart' show AstElement;
-import '../enqueue.dart' show Enqueuer;
 import '../universe/world_impact.dart' show WorldImpact;
 
 abstract class WorkItem {
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 82459f3..bcb4613 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -4,18 +4,21 @@
 
 library dart2js.compile_time_constant_evaluator;
 
+import 'common/backend_api.dart' show BackendClasses;
 import 'common/resolution.dart' show Resolution;
 import 'common/tasks.dart' show CompilerTask, Measurer;
 import 'common.dart';
 import 'compiler.dart' show Compiler;
 import 'constant_system_dart.dart';
 import 'constants/constant_system.dart';
+import 'constants/constructors.dart';
 import 'constants/evaluation.dart';
 import 'constants/expressions.dart';
 import 'constants/values.dart';
 import 'core_types.dart' show CommonElements;
 import 'elements/resolution_types.dart';
 import 'elements/elements.dart';
+import 'elements/entities.dart';
 import 'elements/modelx.dart' show ConstantVariableMixin;
 import 'resolution/operators.dart';
 import 'resolution/tree_elements.dart' show TreeElements;
@@ -353,16 +356,6 @@
       MetadataAnnotation metadata, Node node, TreeElements elements) {
     return compileNodeWithDefinitions(node, elements);
   }
-
-  void forgetElement(Element element) {
-    initialVariableValues.remove(element);
-    if (element is ScopeContainerElement) {
-      element.forEachLocalMember(initialVariableValues.remove);
-    }
-    if (element is FunctionElement && element.hasFunctionSignature) {
-      element.functionSignature.forEachParameter(this.forgetElement);
-    }
-  }
 }
 
 /// [ConstantCompiler] that uses the Dart semantics for the compile-time
@@ -470,7 +463,7 @@
       argumentExpressions.add(argument.expression);
       argumentValues.add(argument.value);
     }
-    ResolutionDartType type = elements.getType(node);
+    ResolutionInterfaceType type = elements.getType(node);
     return new AstConstant(
         context,
         node,
@@ -514,7 +507,11 @@
         node,
         new MapConstantExpression(type, keyExpressions, valueExpressions),
         constantSystem.createMap(
-            compiler, type, keyValues, map.values.toList()));
+            compiler.commonElements,
+            compiler.backend.backendClasses,
+            type,
+            keyValues,
+            map.values.toList()));
   }
 
   AstConstant visitLiteralNull(LiteralNull node) {
@@ -609,7 +606,8 @@
   }
 
   ConstantValue makeTypeConstant(ResolutionDartType elementType) {
-    return constantSystem.createType(compiler, elementType);
+    return constantSystem.createType(
+        compiler.commonElements, compiler.backend.backendClasses, elementType);
   }
 
   /// Returns true if the prefix of the send resolves to a deferred import
@@ -625,7 +623,10 @@
     if (Elements.isClass(element) || Elements.isTypedef(element)) {
       TypeDeclarationElement typeDeclarationElement = element;
       ResolutionDartType type = typeDeclarationElement.rawType;
-      return new AstConstant(element, node, new TypeConstantExpression(type),
+      return new AstConstant(
+          element,
+          node,
+          new TypeConstantExpression(type, typeDeclarationElement.name),
           makeTypeConstant(type));
     }
     return signalNotCompileTimeConstant(node);
@@ -642,7 +643,7 @@
         result = new AstConstant(
             context,
             send,
-            new FunctionConstantExpression(function),
+            new FunctionConstantExpression(function, function.type),
             new FunctionConstantValue(function, function.type));
       } else if (Elements.isStaticOrTopLevelField(element)) {
         ConstantExpression elementExpression;
@@ -652,10 +653,11 @@
           elementExpression = handler.compileVariable(element);
         }
         if (elementExpression != null) {
+          FieldElement field = element;
           result = new AstConstant(
               context,
               send,
-              new VariableConstantExpression(element),
+              new FieldConstantExpression(field),
               handler.getConstantValue(elementExpression));
         }
       } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
@@ -664,7 +666,7 @@
         result = new AstConstant(
             context,
             send,
-            new TypeConstantExpression(elementType),
+            new TypeConstantExpression(elementType, element.name),
             makeTypeConstant(elementType));
       } else if (send.receiver != null) {
         if (send.selector.asIdentifier().source == "length") {
@@ -681,13 +683,13 @@
       } else if (!Elements.isUnresolved(element) &&
           element.isVariable &&
           element.isConst) {
-        ConstantExpression variableExpression =
-            handler.compileConstant(element);
+        LocalVariableElement local = element;
+        ConstantExpression variableExpression = handler.compileConstant(local);
         if (variableExpression != null) {
           result = new AstConstant(
               context,
               send,
-              new VariableConstantExpression(element),
+              new LocalVariableConstantExpression(local),
               handler.getConstantValue(variableExpression));
         }
       }
@@ -1264,8 +1266,8 @@
           new ConstructedConstantExpression(
               type, targetConstructor, callStructure, arguments);
 
-      Map<FieldElement, ConstantExpression> fields =
-          expression.computeInstanceFields();
+      Map<FieldEntity, ConstantExpression> fields =
+          expression.computeInstanceFields(new _CompilerEnvironment(compiler));
       fields.forEach((FieldElement field, ConstantExpression expression) {
         ConstantValue value = expression.evaluate(
             new _CompilerEnvironment(compiler), constantSystem);
@@ -1294,7 +1296,7 @@
       Function compileArgument = (element) => definitions[element];
       Function compileConstant = handler.compileConstant;
       FunctionElement target = constructor.definingConstructor.implementation;
-      Elements.addForwardingElementArgumentsToList<AstConstant>(constructor,
+      Elements.addForwardingElementArgumentsToList(constructor,
           compiledArguments, target, compileArgument, compileConstant);
       CallStructure callStructure = new CallStructure(
           target.functionSignature.parameterCount, target.type.namedParameters);
@@ -1446,12 +1448,39 @@
 }
 
 class _CompilerEnvironment implements Environment {
-  final Compiler compiler;
+  final Compiler _compiler;
 
-  _CompilerEnvironment(this.compiler);
+  _CompilerEnvironment(this._compiler);
+
+  @override
+  BackendClasses get backendClasses => _compiler.backend.backendClasses;
+
+  @override
+  CommonElements get commonElements => _compiler.commonElements;
 
   @override
   String readFromEnvironment(String name) {
-    return compiler.fromEnvironment(name);
+    return _compiler.fromEnvironment(name);
+  }
+
+  @override
+  ResolutionInterfaceType substByContext(
+      ResolutionInterfaceType base, ResolutionInterfaceType target) {
+    return base.substByContext(target);
+  }
+
+  @override
+  ConstantConstructor getConstructorConstant(ConstructorElement constructor) {
+    return constructor.constantConstructor;
+  }
+
+  @override
+  ConstantExpression getFieldConstant(FieldElement field) {
+    return field.constant;
+  }
+
+  @override
+  ConstantExpression getLocalConstant(LocalVariableElement local) {
+    return local.constant;
   }
 }
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 795b81c..dd3249e 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -7,9 +7,7 @@
 import 'dart:async' show EventSink, Future;
 
 import '../compiler_new.dart' as api;
-import 'cache_strategy.dart' show CacheStrategy;
 import 'closure.dart' as closureMapping show ClosureTask;
-import 'common/backend_api.dart' show Backend;
 import 'common/names.dart' show Selectors;
 import 'common/names.dart' show Identifiers, Uris;
 import 'common/resolution.dart'
@@ -24,13 +22,8 @@
 import 'common.dart';
 import 'compile_time_constants.dart';
 import 'constants/values.dart';
-import 'core_types.dart' show CommonElements;
-import 'elements/resolution_types.dart'
-    show
-        ResolutionDartType,
-        ResolutionDynamicType,
-        ResolutionInterfaceType,
-        Types;
+import 'core_types.dart'
+    show CommonElements, CommonElementsMixin, ElementEnvironment;
 import 'deferred_load.dart' show DeferredLoadTask;
 import 'diagnostics/code_location.dart';
 import 'diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
@@ -38,7 +31,14 @@
 import 'diagnostics/messages.dart' show Message, MessageTemplate;
 import 'dump_info.dart' show DumpInfoTask;
 import 'elements/elements.dart';
+import 'elements/entities.dart';
 import 'elements/modelx.dart' show ErroneousElementX;
+import 'elements/resolution_types.dart'
+    show
+        ResolutionDartType,
+        ResolutionDynamicType,
+        ResolutionInterfaceType,
+        Types;
 import 'enqueue.dart' show Enqueuer, EnqueueTask, ResolutionEnqueuer;
 import 'environment.dart';
 import 'id_generator.dart';
@@ -52,6 +52,7 @@
         LibraryLoaderTask,
         LoadedLibraries,
         LibraryLoaderListener,
+        LibraryProvider,
         ScriptLoader;
 import 'mirrors_used.dart' show MirrorUsageAnalyzerTask;
 import 'null_compiler_output.dart' show NullCompilerOutput, NullSink;
@@ -65,9 +66,8 @@
 import 'script.dart' show Script;
 import 'serialization/task.dart' show SerializationTask;
 import 'ssa/nodes.dart' show HInstruction;
-import 'tokens/token.dart' show StringToken, Token, TokenPair;
+import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token;
 import 'tokens/token_map.dart' show TokenMap;
-import 'tracer.dart' show Tracer;
 import 'tree/tree.dart' show Node, TypeAnnotation;
 import 'typechecker.dart' show TypeCheckerTask;
 import 'types/types.dart' show GlobalTypeInferenceTask;
@@ -76,16 +76,10 @@
     show ResolutionWorldBuilder, CodegenWorldBuilder;
 import 'universe/use.dart' show StaticUse, TypeUse;
 import 'universe/world_impact.dart'
-    show
-        ImpactStrategy,
-        WorldImpact,
-        WorldImpactBuilder,
-        WorldImpactBuilderImpl;
+    show ImpactStrategy, WorldImpact, WorldImpactBuilderImpl;
 import 'util/util.dart' show Link, Setlet;
 import 'world.dart' show ClosedWorld, ClosedWorldRefiner, ClosedWorldImpl;
 
-typedef Backend MakeBackendFunction(Compiler compiler);
-
 typedef CompilerDiagnosticReporter MakeReporterFunction(
     Compiler compiler, CompilerOptions options);
 
@@ -95,12 +89,11 @@
   final IdGenerator idGenerator = new IdGenerator();
   Types types;
   _CompilerCommonElements _commonElements;
+  _CompilerElementEnvironment _elementEnvironment;
   CompilerDiagnosticReporter _reporter;
   CompilerResolution _resolution;
   ParsingContext _parsingContext;
 
-  final CacheStrategy cacheStrategy;
-
   ImpactStrategy impactStrategy = const ImpactStrategy();
 
   /**
@@ -137,6 +130,7 @@
   MethodElement mainFunction;
 
   DiagnosticReporter get reporter => _reporter;
+  ElementEnvironment get elementEnvironment => _elementEnvironment;
   CommonElements get commonElements => _commonElements;
   Resolution get resolution => _resolution;
   ParsingContext get parsingContext => _parsingContext;
@@ -166,7 +160,7 @@
   closureMapping.ClosureTask closureToClassMapper;
   TypeCheckerTask checker;
   GlobalTypeInferenceTask globalInference;
-  Backend backend;
+  js_backend.JavaScriptBackend backend;
 
   GenericTask selfTask;
 
@@ -199,10 +193,8 @@
       {CompilerOptions options,
       api.CompilerOutput outputProvider,
       this.environment: const _EmptyEnvironment(),
-      MakeBackendFunction makeBackend,
       MakeReporterFunction makeReporter})
       : this.options = options,
-        this.cacheStrategy = new CacheStrategy(options.hasIncrementalSupport),
         this.userOutputProvider = outputProvider == null
             ? const NullCompilerOutput()
             : outputProvider {
@@ -212,7 +204,9 @@
       _reporter = new CompilerDiagnosticReporter(this, options);
     }
     _resolution = createResolution();
-    _commonElements = new _CompilerCommonElements(_resolution, reporter);
+    _elementEnvironment = new _CompilerElementEnvironment(this);
+    _commonElements =
+        new _CompilerCommonElements(_elementEnvironment, _resolution, reporter);
     types = new Types(_resolution);
 
     if (options.verbose) {
@@ -223,11 +217,7 @@
     // for global dependencies.
     globalDependencies = new GlobalDependencyRegistry();
 
-    if (makeBackend != null) {
-      backend = makeBackend(this);
-    } else {
-      backend = createBackend();
-    }
+    backend = createBackend();
     enqueuer = backend.makeEnqueuer();
 
     tasks = [
@@ -265,7 +255,7 @@
     }
 
     _parsingContext =
-        new ParsingContext(reporter, parser, patchParser, backend);
+        new ParsingContext(reporter, parser, scanner, patchParser, backend);
 
     tasks.addAll(backend.tasks);
   }
@@ -273,7 +263,7 @@
   /// Creates the backend.
   ///
   /// Override this to mock the backend for testing.
-  Backend createBackend() {
+  js_backend.JavaScriptBackend createBackend() {
     return new js_backend.JavaScriptBackend(this,
         generateSourceMap: options.generateSourceMap,
         useStartupEmitter: options.useStartupEmitter,
@@ -341,7 +331,6 @@
   /// been resolved.
   void onLibraryCreated(LibraryElement library) {
     _commonElements.onLibraryCreated(library);
-    backend.onLibraryCreated(library);
   }
 
   /// This method is called immediately after the [library] and its parts have
@@ -488,7 +477,7 @@
           .add(selector);
     }
 
-    assert(uri != null || options.analyzeOnly || options.hasIncrementalSupport);
+    assert(uri != null || options.analyzeOnly);
     return new Future.sync(() {
       if (librariesToAnalyzeWhenRun != null) {
         return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
@@ -1071,18 +1060,6 @@
     return libraryUri;
   }
 
-  void forgetElement(Element element) {
-    resolution.forgetElement(element);
-    enqueuer.forgetEntity(element);
-    if (element is MemberElement) {
-      for (Element closure in element.nestedClosures) {
-        // TODO(ahe): It would be nice to reuse names of nested closures.
-        closureToClassMapper.forgetElement(closure);
-      }
-    }
-    backend.forgetElement(element);
-  }
-
   /// Returns [true] if a compile-time error has been reported for element.
   bool elementHasCompileTimeError(Element element) {
     return elementsWithCompileTimeErrors.containsKey(element);
@@ -1123,319 +1100,22 @@
   int hints = 0;
 }
 
-class _CompilerCommonElements implements CommonElements {
+class _CompilerCommonElements extends CommonElementsMixin {
   final Resolution resolution;
   final DiagnosticReporter reporter;
 
+  final ElementEnvironment environment;
+
   LibraryElement coreLibrary;
   LibraryElement asyncLibrary;
   LibraryElement mirrorsLibrary;
   LibraryElement typedDataLibrary;
 
-  // TODO(sigmund): possibly move this to target-specific collection of
-  // elements, or refactor the library so that the helpers we need are in a
-  // target-agnostic place.  Currently we are using @patch and @Native from
-  // here. We hope we can make those independent of the backend and generic
-  // enough so the patching algorithm can work without being configured for a
-  // specific backend.
-  LibraryElement jsHelperLibrary;
-
-  _CompilerCommonElements(this.resolution, this.reporter);
-
-  // From dart:core
-
-  ClassElement _objectClass;
-  ClassElement get objectClass =>
-      _objectClass ??= _findRequired(coreLibrary, 'Object');
-
-  ClassElement _boolClass;
-  ClassElement get boolClass =>
-      _boolClass ??= _findRequired(coreLibrary, 'bool');
-
-  ClassElement _numClass;
-  ClassElement get numClass => _numClass ??= _findRequired(coreLibrary, 'num');
-
-  ClassElement _intClass;
-  ClassElement get intClass => _intClass ??= _findRequired(coreLibrary, 'int');
-
-  ClassElement _doubleClass;
-  ClassElement get doubleClass =>
-      _doubleClass ??= _findRequired(coreLibrary, 'double');
-
-  ClassElement _stringClass;
-  ClassElement get stringClass =>
-      _stringClass ??= _findRequired(coreLibrary, 'String');
-
-  ClassElement _functionClass;
-  ClassElement get functionClass =>
-      _functionClass ??= _findRequired(coreLibrary, 'Function');
-
-  MethodElement _functionApplyMethod;
-  MethodElement get functionApplyMethod {
-    if (_functionApplyMethod == null) {
-      functionClass.ensureResolved(resolution);
-      _functionApplyMethod = functionClass.lookupLocalMember('apply');
-      assert(invariant(functionClass, _functionApplyMethod != null,
-          message: "Member `apply` not found in ${functionClass}."));
-    }
-    return _functionApplyMethod;
-  }
-
-  bool isFunctionApplyMethod(MemberElement element) =>
-      element.name == 'apply' && element.enclosingClass == functionClass;
-
-  ClassElement _nullClass;
-  ClassElement get nullClass =>
-      _nullClass ??= _findRequired(coreLibrary, 'Null');
-
-  ClassElement _listClass;
-  ClassElement get listClass =>
-      _listClass ??= _findRequired(coreLibrary, 'List');
-
-  ClassElement _typeClass;
-  ClassElement get typeClass =>
-      _typeClass ??= _findRequired(coreLibrary, 'Type');
-
-  ClassElement _mapClass;
-  ClassElement get mapClass => _mapClass ??= _findRequired(coreLibrary, 'Map');
-
-  ClassElement _symbolClass;
-  ClassElement get symbolClass =>
-      _symbolClass ??= _findRequired(coreLibrary, 'Symbol');
-
-  ConstructorElement _symbolConstructor;
-  ConstructorElement get symbolConstructor {
-    if (_symbolConstructor == null) {
-      symbolClass.ensureResolved(resolution);
-      _symbolConstructor = symbolClass.lookupConstructor('');
-      assert(invariant(symbolClass, _symbolConstructor != null,
-          message: "Default constructor not found ${symbolClass}."));
-    }
-    return _symbolConstructor;
-  }
-
-  bool isSymbolConstructor(Element e) =>
-      e.enclosingClass == symbolClass && e == symbolConstructor;
-
-  ClassElement _stackTraceClass;
-  ClassElement get stackTraceClass =>
-      _stackTraceClass ??= _findRequired(coreLibrary, 'StackTrace');
-
-  ClassElement _iterableClass;
-  ClassElement get iterableClass =>
-      _iterableClass ??= _findRequired(coreLibrary, 'Iterable');
-
-  ClassElement _resourceClass;
-  ClassElement get resourceClass =>
-      _resourceClass ??= _findRequired(coreLibrary, 'Resource');
-
-  MethodElement _identicalFunction;
-  MethodElement get identicalFunction =>
-      _identicalFunction ??= coreLibrary.find('identical');
-
-  // From dart:async
-
-  ClassElement _futureClass;
-  ClassElement get futureClass =>
-      _futureClass ??= _findRequired(asyncLibrary, 'Future');
-
-  ClassElement _streamClass;
-  ClassElement get streamClass =>
-      _streamClass ??= _findRequired(asyncLibrary, 'Stream');
-
-  ClassElement _deferredLibraryClass;
-  ClassElement get deferredLibraryClass =>
-      _deferredLibraryClass ??= _findRequired(asyncLibrary, "DeferredLibrary");
-
-  // From dart:mirrors
-
-  ClassElement _mirrorSystemClass;
-  ClassElement get mirrorSystemClass =>
-      _mirrorSystemClass ??= _findRequired(mirrorsLibrary, 'MirrorSystem');
-
-  FunctionElement _mirrorSystemGetNameFunction;
-  bool isMirrorSystemGetNameFunction(MemberElement element) {
-    if (_mirrorSystemGetNameFunction == null) {
-      if (!element.isFunction || mirrorsLibrary == null) return false;
-      ClassElement cls = mirrorSystemClass;
-      if (element.enclosingClass != cls) return false;
-      if (cls != null) {
-        cls.ensureResolved(resolution);
-        _mirrorSystemGetNameFunction = cls.lookupLocalMember('getName');
-      }
-    }
-    return element == _mirrorSystemGetNameFunction;
-  }
-
-  ClassElement _mirrorsUsedClass;
-  ClassElement get mirrorsUsedClass =>
-      _mirrorsUsedClass ??= _findRequired(mirrorsLibrary, 'MirrorsUsed');
-
-  bool isMirrorsUsedConstructor(ConstructorElement element) =>
-      mirrorsLibrary != null && mirrorsUsedClass == element.enclosingClass;
-
-  ConstructorElement _mirrorsUsedConstructor;
-  @override
-  ConstructorElement get mirrorsUsedConstructor {
-    if (_mirrorsUsedConstructor == null) {
-      ClassElement cls = mirrorsUsedClass;
-      if (cls != null) {
-        cls.ensureResolved(resolution);
-        _mirrorsUsedConstructor = cls.constructors.head;
-      }
-    }
-    return _mirrorsUsedConstructor;
-  }
-
-  // From dart:typed_data
-
-  ClassElement _typedDataClass;
-  ClassElement get typedDataClass =>
-      _typedDataClass ??= _findRequired(typedDataLibrary, 'NativeTypedData');
-
-  // From dart:_js_helper
-  // TODO(sigmund,johnniwinther): refactor needed: either these move to a
-  // backend-specific collection of helpers, or the helper code moves to a
-  // backend agnostic library (see commend above on [jsHelperLibrary].
-
-  ClassElement _patchAnnotationClass;
-  ClassElement get patchAnnotationClass =>
-      _patchAnnotationClass ??= _findRequired(jsHelperLibrary, '_Patch');
-
-  ClassElement _nativeAnnotationClass;
-  ClassElement get nativeAnnotationClass =>
-      _nativeAnnotationClass ??= _findRequired(jsHelperLibrary, 'Native');
+  _CompilerCommonElements(this.environment, this.resolution, this.reporter);
 
   @override
   ResolutionDynamicType get dynamicType => const ResolutionDynamicType();
 
-  @override
-  ResolutionInterfaceType get objectType {
-    objectClass.ensureResolved(resolution);
-    return objectClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get boolType {
-    boolClass.ensureResolved(resolution);
-    return boolClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get doubleType {
-    doubleClass.ensureResolved(resolution);
-    return doubleClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get functionType {
-    functionClass.ensureResolved(resolution);
-    return functionClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get intType {
-    intClass.ensureResolved(resolution);
-    return intClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get resourceType {
-    resourceClass.ensureResolved(resolution);
-    return resourceClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType listType([ResolutionDartType elementType]) {
-    listClass.ensureResolved(resolution);
-    ResolutionInterfaceType type = listClass.rawType;
-    if (elementType == null) {
-      return type;
-    }
-    return type.createInstantiation([elementType]);
-  }
-
-  @override
-  ResolutionInterfaceType mapType(
-      [ResolutionDartType keyType, ResolutionDartType valueType]) {
-    mapClass.ensureResolved(resolution);
-    ResolutionInterfaceType type = mapClass.rawType;
-    if (keyType == null && valueType == null) {
-      return type;
-    } else if (keyType == null) {
-      keyType = const ResolutionDynamicType();
-    } else if (valueType == null) {
-      valueType = const ResolutionDynamicType();
-    }
-    return type.createInstantiation([keyType, valueType]);
-  }
-
-  @override
-  ResolutionInterfaceType get nullType {
-    nullClass.ensureResolved(resolution);
-    return nullClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get numType {
-    numClass.ensureResolved(resolution);
-    return numClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get stringType {
-    stringClass.ensureResolved(resolution);
-    return stringClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get symbolType {
-    symbolClass.ensureResolved(resolution);
-    return symbolClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get typeType {
-    typeClass.ensureResolved(resolution);
-    return typeClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType get stackTraceType {
-    stackTraceClass.ensureResolved(resolution);
-    return stackTraceClass.rawType;
-  }
-
-  @override
-  ResolutionInterfaceType iterableType([ResolutionDartType elementType]) {
-    iterableClass.ensureResolved(resolution);
-    ResolutionInterfaceType type = iterableClass.rawType;
-    if (elementType == null) {
-      return type;
-    }
-    return type.createInstantiation([elementType]);
-  }
-
-  @override
-  ResolutionInterfaceType futureType([ResolutionDartType elementType]) {
-    futureClass.ensureResolved(resolution);
-    ResolutionInterfaceType type = futureClass.rawType;
-    if (elementType == null) {
-      return type;
-    }
-    return type.createInstantiation([elementType]);
-  }
-
-  @override
-  ResolutionInterfaceType streamType([ResolutionDartType elementType]) {
-    streamClass.ensureResolved(resolution);
-    ResolutionInterfaceType type = streamClass.rawType;
-    if (elementType == null) {
-      return type;
-    }
-    return type.createInstantiation([elementType]);
-  }
-
   void onLibraryCreated(LibraryElement library) {
     Uri uri = library.canonicalUri;
     if (uri == Uris.dart_core) {
@@ -1446,12 +1126,74 @@
       typedDataLibrary = library;
     } else if (uri == Uris.dart_mirrors) {
       mirrorsLibrary = library;
-    } else if (uri == js_backend.BackendHelpers.DART_JS_HELPER) {
-      jsHelperLibrary = library;
     }
   }
 
-  Element _findRequired(LibraryElement library, String name) {
+  @override
+  MemberElement findLibraryMember(LibraryElement library, String name,
+      {bool setter: false, bool required: true}) {
+    Element member = _findLibraryMember(library, name, required: required);
+    if (member != null && member.isAbstractField) {
+      AbstractFieldElement abstractField = member;
+      if (setter) {
+        member = abstractField.setter;
+      } else {
+        member = abstractField.getter;
+      }
+      if (member == null && required) {
+        reporter.internalError(
+            library,
+            "The library '${library.canonicalUri}' does not contain required "
+            "${setter ? 'setter' : 'getter'}: '$name'.");
+      }
+    }
+    return member;
+  }
+
+  @override
+  MemberElement findClassMember(ClassElement cls, String name,
+      {bool setter: false, bool required: true}) {
+    cls.ensureResolved(resolution);
+    Element member = cls.lookupLocalMember(name);
+    if (member != null && member.isAbstractField) {
+      AbstractFieldElement abstractField = member;
+      if (setter) {
+        member = abstractField.setter;
+      } else {
+        member = abstractField.getter;
+      }
+    }
+    if (member == null && required) {
+      reporter.internalError(
+          cls,
+          "The class '${cls}' in '${cls.library.canonicalUri}' does not "
+          "contain required member: '$name'.");
+    }
+    return member;
+  }
+
+  @override
+  ConstructorElement findConstructor(ClassElement cls, String name,
+      {bool required: true}) {
+    cls.ensureResolved(resolution);
+    ConstructorElement constructor = cls.lookupConstructor(name);
+    if (constructor == null && required) {
+      reporter.internalError(
+          cls,
+          "The class '${cls}' in '${cls.library.canonicalUri}' does not "
+          "contain required constructor: '$name'.");
+    }
+    return constructor;
+  }
+
+  @override
+  ClassElement findClass(LibraryElement library, String name,
+      {bool required: true}) {
+    return _findLibraryMember(library, name, required: required);
+  }
+
+  Element _findLibraryMember(LibraryElement library, String name,
+      {bool required: true}) {
     // If the script of the library is synthesized, the library does not exist
     // and we do not try to load the helpers.
     //
@@ -1459,8 +1201,8 @@
     // should not try to find the given element.
     if (library == null || library.isSynthesized) return null;
 
-    var element = library.find(name);
-    if (element == null) {
+    Element element = library.find(name);
+    if (element == null && required) {
       reporter.internalError(
           library,
           "The library '${library.canonicalUri}' does not contain required "
@@ -1468,26 +1210,6 @@
     }
     return element;
   }
-
-  ConstructorElement _unnamedListConstructor;
-  ConstructorElement get unnamedListConstructor =>
-      _unnamedListConstructor ??= listClass.lookupDefaultConstructor();
-
-  ConstructorElement _filledListConstructor;
-  ConstructorElement get filledListConstructor =>
-      _filledListConstructor ??= listClass.lookupConstructor("filled");
-
-  // TODO(johnniwinther): Change types to `ClassElement` when these are not
-  // called with unrelated elements.
-  bool isNumberOrStringSupertype(/*Class*/ Entity element) {
-    return element == coreLibrary.find('Comparable');
-  }
-
-  bool isStringOnlySupertype(/*Class*/ Entity element) {
-    return element == coreLibrary.find('Pattern');
-  }
-
-  bool isListSupertype(/*Class*/ Entity element) => element == iterableClass;
 }
 
 class CompilerDiagnosticReporter extends DiagnosticReporter {
@@ -1638,6 +1360,9 @@
         api.Diagnostic.CRASH);
   }
 
+  @override
+  SourceSpan spanFromToken(Token token) => spanFromTokens(token, token);
+
   SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
     if (begin == null || end == null) {
       // TODO(ahe): We can almost always do better. Often it is only
@@ -1786,10 +1511,6 @@
       return node;
     } else if (node is Node) {
       return spanFromNode(node);
-    } else if (node is TokenPair) {
-      return spanFromTokens(node.begin, node.end);
-    } else if (node is Token) {
-      return spanFromTokens(node, node);
     } else if (node is HInstruction) {
       return spanFromHInstruction(node);
     } else if (node is Element) {
@@ -1799,6 +1520,8 @@
     } else if (node is Local) {
       Local local = node;
       return spanFromElement(local.executableContext);
+    } else if (node is Entity) {
+      return spanFromElement(currentElement);
     } else {
       throw 'No error location.';
     }
@@ -1953,7 +1676,6 @@
   MirrorUsageAnalyzerTask get mirrorUsageAnalyzerTask =>
       _compiler.mirrorUsageAnalyzerTask;
 
-  @override
   LibraryElement get coreLibrary => _compiler._commonElements.coreLibrary;
 
   @override
@@ -2161,12 +1883,6 @@
     }
   }
 
-  @override
-  void forgetElement(Element element) {
-    _worldImpactCache.remove(element);
-    _resolutionImpactCache.remove(element);
-  }
-
   ConstantValue _proxyConstant;
 
   @override
@@ -2234,3 +1950,127 @@
 
   String valueOf(String key) => null;
 }
+
+/// An element environment base on a [Compiler].
+class _CompilerElementEnvironment implements ElementEnvironment {
+  final Compiler _compiler;
+
+  _CompilerElementEnvironment(this._compiler);
+
+  LibraryProvider get _libraryProvider => _compiler.libraryLoader;
+  Resolution get _resolution => _compiler.resolution;
+
+  @override
+  ResolutionInterfaceType getThisType(ClassElement cls) {
+    cls.ensureResolved(_resolution);
+    return cls.thisType;
+  }
+
+  @override
+  ResolutionInterfaceType getRawType(ClassElement cls) {
+    cls.ensureResolved(_resolution);
+    return cls.rawType;
+  }
+
+  @override
+  ResolutionInterfaceType createInterfaceType(
+      ClassElement cls, List<ResolutionDartType> typeArguments) {
+    cls.ensureResolved(_resolution);
+    return cls.thisType.createInstantiation(typeArguments);
+  }
+
+  @override
+  MemberElement lookupClassMember(ClassElement cls, String name,
+      {bool setter: false, bool required: false}) {
+    cls.ensureResolved(_resolution);
+    Element member = cls.implementation.lookupLocalMember(name);
+    if (member != null && member.isAbstractField) {
+      AbstractFieldElement abstractField = member;
+      if (setter) {
+        member = abstractField.setter;
+      } else {
+        member = abstractField.getter;
+      }
+      if (member == null && required) {
+        throw new SpannableAssertionFailure(
+            cls,
+            "The class '${cls.name}' does not contain required "
+            "${setter ? 'setter' : 'getter'}: '$name'.");
+      }
+    }
+    if (member == null && required) {
+      throw new SpannableAssertionFailure(
+          cls,
+          "The class '${cls.name}' does not "
+          "contain required member: '$name'.");
+    }
+    return member?.declaration;
+  }
+
+  @override
+  ConstructorElement lookupConstructor(ClassElement cls, String name,
+      {bool required: false}) {
+    cls.ensureResolved(_resolution);
+    ConstructorElement constructor = cls.implementation.lookupConstructor(name);
+    if (constructor == null && required) {
+      throw new SpannableAssertionFailure(
+          cls,
+          "The class '${cls.name}' does not contain "
+          "required constructor: '$name'.");
+    }
+    return constructor?.declaration;
+  }
+
+  @override
+  MemberElement lookupLibraryMember(LibraryElement library, String name,
+      {bool setter: false, bool required: false}) {
+    Element member = library.implementation.findLocal(name);
+    if (member != null && member.isAbstractField) {
+      AbstractFieldElement abstractField = member;
+      if (setter) {
+        member = abstractField.setter;
+      } else {
+        member = abstractField.getter;
+      }
+      if (member == null && required) {
+        throw new SpannableAssertionFailure(
+            library,
+            "The library '${library.canonicalUri}' does not contain required "
+            "${setter ? 'setter' : 'getter'}: '$name'.");
+      }
+    }
+    if (member == null && required) {
+      throw new SpannableAssertionFailure(
+          member,
+          "The library '${library.libraryName}' does not "
+          "contain required member: '$name'.");
+    }
+    return member?.declaration;
+  }
+
+  @override
+  ClassElement lookupClass(LibraryElement library, String name,
+      {bool required: false}) {
+    ClassElement cls = library.implementation.findLocal(name);
+    if (cls == null && required) {
+      throw new SpannableAssertionFailure(
+          cls,
+          "The library '${library.libraryName}' does not "
+          "contain required class: '$name'.");
+    }
+    return cls?.declaration;
+  }
+
+  @override
+  LibraryElement lookupLibrary(Uri uri, {bool required: false}) {
+    LibraryElement library = _libraryProvider.lookupLibrary(uri);
+    if (library != null && library.isSynthesized) {
+      return null;
+    }
+    if (library == null && required) {
+      throw new SpannableAssertionFailure(
+          library, "The library '${uri}' was not found.");
+    }
+    return library;
+  }
+}
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
index 7c3ebc1..7097cd9 100644
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ b/pkg/compiler/lib/src/constant_system_dart.dart
@@ -4,10 +4,12 @@
 
 library dart2js.constant_system.dart;
 
-import 'compiler.dart' show Compiler;
+import 'common/backend_api.dart' show BackendClasses;
 import 'constants/constant_system.dart';
 import 'constants/values.dart';
-import 'elements/resolution_types.dart';
+import 'core_types.dart' show CommonElements;
+import 'elements/types.dart';
+import 'elements/resolution_types.dart' show DartTypes;
 import 'tree/dartstring.dart' show DartString;
 
 const DART_CONSTANT_SYSTEM = const DartConstantSystem();
@@ -442,31 +444,34 @@
   NullConstantValue createNull() => new NullConstantValue();
 
   @override
-  ListConstantValue createList(
-      ResolutionInterfaceType type, List<ConstantValue> values) {
+  ListConstantValue createList(InterfaceType type, List<ConstantValue> values) {
     return new ListConstantValue(type, values);
   }
 
   @override
-  MapConstantValue createMap(Compiler compiler, ResolutionInterfaceType type,
-      List<ConstantValue> keys, List<ConstantValue> values) {
+  MapConstantValue createMap(
+      CommonElements commonElements,
+      BackendClasses backendClasses,
+      InterfaceType type,
+      List<ConstantValue> keys,
+      List<ConstantValue> values) {
     return new MapConstantValue(type, keys, values);
   }
 
   @override
-  ConstantValue createType(Compiler compiler, ResolutionDartType type) {
+  ConstantValue createType(CommonElements commonElements,
+      BackendClasses backendClasses, DartType type) {
     // TODO(johnniwinther): Change the `Type` type to
     // `compiler.commonElements.typeType` and check the backend specific value
     // in [checkConstMapKeysDontOverrideEquals] in 'members.dart'.
-    ResolutionInterfaceType implementationType = compiler
-        .backend.backendClasses.typeImplementation
-        .computeType(compiler.resolution);
+    InterfaceType implementationType = backendClasses.typeType;
     return new TypeConstantValue(type, implementationType);
   }
 
   @override
-  ConstantValue createSymbol(Compiler compiler, String text) {
-    throw new UnsupportedError('DartConstantSystem.evaluate');
+  ConstantValue createSymbol(CommonElements commonElements,
+      BackendClasses backendClasses, String text) {
+    throw new UnsupportedError('DartConstantSystem.createSymbol');
   }
 
   bool isInt(ConstantValue constant) => constant.isInt;
@@ -475,7 +480,7 @@
   bool isBool(ConstantValue constant) => constant.isBool;
   bool isNull(ConstantValue constant) => constant.isNull;
 
-  bool isSubtype(DartTypes types, ResolutionDartType s, ResolutionDartType t) {
+  bool isSubtype(DartTypes types, DartType s, DartType t) {
     return types.isSubtype(s, t);
   }
 }
diff --git a/pkg/compiler/lib/src/constants/constant_constructors.dart b/pkg/compiler/lib/src/constants/constant_constructors.dart
index 38a182d..3ffae34 100644
--- a/pkg/compiler/lib/src/constants/constant_constructors.dart
+++ b/pkg/compiler/lib/src/constants/constant_constructors.dart
@@ -287,12 +287,18 @@
 
   @override
   ConstantExpression visitStaticFieldGet(Send node, FieldElement field, _) {
-    return new VariableConstantExpression(field);
+    return new FieldConstantExpression(field);
+  }
+
+  @override
+  ConstantExpression visitTopLevelFunctionGet(
+      Send node, MethodElement method, _) {
+    return new FunctionConstantExpression(method, method.type);
   }
 
   @override
   ConstantExpression visitTopLevelFieldGet(Send node, FieldElement field, _) {
-    return new VariableConstantExpression(field);
+    return new FieldConstantExpression(field);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/constants/constant_system.dart b/pkg/compiler/lib/src/constants/constant_system.dart
index 14d0941..49d5e81 100644
--- a/pkg/compiler/lib/src/constants/constant_system.dart
+++ b/pkg/compiler/lib/src/constants/constant_system.dart
@@ -4,8 +4,10 @@
 
 library dart2js.constant_system;
 
-import '../compiler.dart' show Compiler;
-import '../elements/resolution_types.dart';
+import '../common/backend_api.dart' show BackendClasses;
+import '../core_types.dart' show CommonElements;
+import '../elements/resolution_types.dart' show DartTypes;
+import '../elements/types.dart';
 import '../resolution/operators.dart';
 import '../tree/dartstring.dart' show DartString;
 import 'values.dart';
@@ -64,19 +66,21 @@
   ConstantValue createString(DartString string);
   ConstantValue createBool(bool value);
   ConstantValue createNull();
-  ConstantValue createList(
-      ResolutionInterfaceType type, List<ConstantValue> values);
-  // TODO(johnniwinther): Remove the need for [compiler].
-  ConstantValue createMap(Compiler compiler, ResolutionInterfaceType type,
-      List<ConstantValue> keys, List<ConstantValue> values);
-  // TODO(johnniwinther): Remove the need for [compiler].
-  ConstantValue createType(Compiler compiler, ResolutionDartType type);
-  // TODO(johnniwinther): Remove the need for [compiler].
-  ConstantValue createSymbol(Compiler compiler, String text);
+  ConstantValue createList(InterfaceType type, List<ConstantValue> values);
+  ConstantValue createMap(
+      CommonElements commonElements,
+      BackendClasses backendClasses,
+      InterfaceType type,
+      List<ConstantValue> keys,
+      List<ConstantValue> values);
+  ConstantValue createType(CommonElements commonElements,
+      BackendClasses backendClasses, DartType type);
+  ConstantValue createSymbol(CommonElements commonElements,
+      BackendClasses backendClasses, String text);
 
   // We need to special case the subtype check for JavaScript constant
   // system because an int is a double at runtime.
-  bool isSubtype(DartTypes types, ResolutionDartType s, ResolutionDartType t);
+  bool isSubtype(DartTypes types, DartType s, DartType t);
 
   /** Returns true if the [constant] is an integer at runtime. */
   bool isInt(ConstantValue constant);
diff --git a/pkg/compiler/lib/src/constants/constructors.dart b/pkg/compiler/lib/src/constants/constructors.dart
index 8199bbc..f5d5ab7 100644
--- a/pkg/compiler/lib/src/constants/constructors.dart
+++ b/pkg/compiler/lib/src/constants/constructors.dart
@@ -4,8 +4,8 @@
 
 library dart2js.constants.constructors;
 
-import '../elements/resolution_types.dart';
-import '../elements/elements.dart' show FieldElement;
+import '../elements/entities.dart' show FieldEntity;
+import '../elements/types.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import '../util/util.dart';
 import 'evaluation.dart';
@@ -23,12 +23,15 @@
 
   /// Computes the type of the instance created in a const constructor
   /// invocation with type [newType].
-  ResolutionInterfaceType computeInstanceType(ResolutionInterfaceType newType);
+  InterfaceType computeInstanceType(
+      Environment environment, InterfaceType newType);
 
   /// Computes the constant expressions of the fields of the created instance
   /// in a const constructor invocation with [arguments].
-  Map<FieldElement, ConstantExpression> computeInstanceFields(
-      List<ConstantExpression> arguments, CallStructure callStructure);
+  Map<FieldEntity, ConstantExpression> computeInstanceFields(
+      Environment environment,
+      List<ConstantExpression> arguments,
+      CallStructure callStructure);
 
   accept(ConstantConstructorVisitor visitor, arg);
 }
@@ -49,9 +52,9 @@
 
 /// A generative constant constructor.
 class GenerativeConstantConstructor implements ConstantConstructor {
-  final ResolutionInterfaceType type;
+  final InterfaceType type;
   final Map<dynamic /*int|String*/, ConstantExpression> defaultValues;
-  final Map<FieldElement, ConstantExpression> fieldMap;
+  final Map<FieldEntity, ConstantExpression> fieldMap;
   final ConstructedConstantExpression superConstructorInvocation;
 
   GenerativeConstantConstructor(this.type, this.defaultValues, this.fieldMap,
@@ -59,17 +62,20 @@
 
   ConstantConstructorKind get kind => ConstantConstructorKind.GENERATIVE;
 
-  ResolutionInterfaceType computeInstanceType(ResolutionInterfaceType newType) {
-    return type.substByContext(newType);
+  InterfaceType computeInstanceType(
+      Environment environment, InterfaceType newType) {
+    return environment.substByContext(type, newType);
   }
 
-  Map<FieldElement, ConstantExpression> computeInstanceFields(
-      List<ConstantExpression> arguments, CallStructure callStructure) {
+  Map<FieldEntity, ConstantExpression> computeInstanceFields(
+      Environment environment,
+      List<ConstantExpression> arguments,
+      CallStructure callStructure) {
     NormalizedArguments args =
         new NormalizedArguments(defaultValues, callStructure, arguments);
-    Map<FieldElement, ConstantExpression> appliedFieldMap =
-        applyFields(args, superConstructorInvocation);
-    fieldMap.forEach((FieldElement field, ConstantExpression constant) {
+    Map<FieldEntity, ConstantExpression> appliedFieldMap =
+        applyFields(environment, args, superConstructorInvocation);
+    fieldMap.forEach((FieldEntity field, ConstantExpression constant) {
       appliedFieldMap[field] = constant.apply(args);
     });
     return appliedFieldMap;
@@ -101,7 +107,7 @@
     defaultValues.forEach((key, ConstantExpression expression) {
       sb.write(",\n 'default:${key}': ${expression.toDartText()}");
     });
-    fieldMap.forEach((FieldElement field, ConstantExpression expression) {
+    fieldMap.forEach((FieldEntity field, ConstantExpression expression) {
       sb.write(",\n 'field:${field}': ${expression.toDartText()}");
     });
     if (superConstructorInvocation != null) {
@@ -124,15 +130,16 @@
   /// Creates the field-to-constant map from applying [args] to
   /// [constructorInvocation]. If [constructorInvocation] is `null`, an empty
   /// map is created.
-  static Map<FieldElement, ConstantExpression> applyFields(
+  static Map<FieldEntity, ConstantExpression> applyFields(
+      Environment environment,
       NormalizedArguments args,
       ConstructedConstantExpression constructorInvocation) {
-    Map<FieldElement, ConstantExpression> appliedFieldMap =
-        <FieldElement, ConstantExpression>{};
+    Map<FieldEntity, ConstantExpression> appliedFieldMap =
+        <FieldEntity, ConstantExpression>{};
     if (constructorInvocation != null) {
-      Map<FieldElement, ConstantExpression> fieldMap =
-          constructorInvocation.computeInstanceFields();
-      fieldMap.forEach((FieldElement field, ConstantExpression constant) {
+      Map<FieldEntity, ConstantExpression> fieldMap =
+          constructorInvocation.computeInstanceFields(environment);
+      fieldMap.forEach((FieldEntity field, ConstantExpression constant) {
         appliedFieldMap[field] = constant.apply(args);
       });
     }
@@ -152,19 +159,21 @@
     return ConstantConstructorKind.REDIRECTING_GENERATIVE;
   }
 
-  ResolutionInterfaceType computeInstanceType(ResolutionInterfaceType newType) {
-    return thisConstructorInvocation
-        .computeInstanceType()
-        .substByContext(newType);
+  InterfaceType computeInstanceType(
+      Environment environment, InterfaceType newType) {
+    return environment.substByContext(
+        thisConstructorInvocation.computeInstanceType(environment), newType);
   }
 
-  Map<FieldElement, ConstantExpression> computeInstanceFields(
-      List<ConstantExpression> arguments, CallStructure callStructure) {
+  Map<FieldEntity, ConstantExpression> computeInstanceFields(
+      Environment environment,
+      List<ConstantExpression> arguments,
+      CallStructure callStructure) {
     NormalizedArguments args =
         new NormalizedArguments(defaultValues, callStructure, arguments);
-    Map<FieldElement, ConstantExpression> appliedFieldMap =
+    Map<FieldEntity, ConstantExpression> appliedFieldMap =
         GenerativeConstantConstructor.applyFields(
-            args, thisConstructorInvocation);
+            environment, args, thisConstructorInvocation);
     return appliedFieldMap;
   }
 
@@ -207,17 +216,20 @@
     return ConstantConstructorKind.REDIRECTING_FACTORY;
   }
 
-  ResolutionInterfaceType computeInstanceType(ResolutionInterfaceType newType) {
-    return targetConstructorInvocation
-        .computeInstanceType()
-        .substByContext(newType);
+  InterfaceType computeInstanceType(
+      Environment environment, InterfaceType newType) {
+    return environment.substByContext(
+        targetConstructorInvocation.computeInstanceType(environment), newType);
   }
 
-  Map<FieldElement, ConstantExpression> computeInstanceFields(
-      List<ConstantExpression> arguments, CallStructure callStructure) {
+  Map<FieldEntity, ConstantExpression> computeInstanceFields(
+      Environment environment,
+      List<ConstantExpression> arguments,
+      CallStructure callStructure) {
     ConstantConstructor constantConstructor =
-        targetConstructorInvocation.target.constantConstructor;
-    return constantConstructor.computeInstanceFields(arguments, callStructure);
+        environment.getConstructorConstant(targetConstructorInvocation.target);
+    return constantConstructor.computeInstanceFields(
+        environment, arguments, callStructure);
   }
 
   accept(ConstantConstructorVisitor visitor, arg) {
diff --git a/pkg/compiler/lib/src/constants/evaluation.dart b/pkg/compiler/lib/src/constants/evaluation.dart
index 5b2428b..8721230 100644
--- a/pkg/compiler/lib/src/constants/evaluation.dart
+++ b/pkg/compiler/lib/src/constants/evaluation.dart
@@ -4,18 +4,39 @@
 
 library dart2js.constants.evaluation;
 
-import '../compiler.dart' show Compiler;
+import '../common.dart';
+import '../common/backend_api.dart' show BackendClasses;
+import '../core_types.dart' show CommonElements;
+import '../elements/entities.dart';
+import '../elements/types.dart';
 import '../universe/call_structure.dart' show CallStructure;
+import 'constructors.dart';
 import 'expressions.dart';
 
 /// Environment used for evaluating constant expressions.
 abstract class Environment {
   // TODO(johnniwinther): Replace this with [CommonElements] and maybe
   // [Backend].
-  Compiler get compiler;
+  CommonElements get commonElements;
+
+  BackendClasses get backendClasses;
 
   /// Read environments string passed in using the '-Dname=value' option.
   String readFromEnvironment(String name);
+
+  /// Returns the [ConstantExpression] for the value of the constant [local].
+  ConstantExpression getLocalConstant(Local local);
+
+  /// Returns the [ConstantExpression] for the value of the constant [field].
+  ConstantExpression getFieldConstant(FieldEntity field);
+
+  /// Returns the [ConstantConstructor] corresponding to the constant
+  /// [constructor].
+  ConstantConstructor getConstructorConstant(ConstructorEntity constructor);
+
+  /// Performs the substitution of the type arguments of [target] for their
+  /// corresponding type variables in [type].
+  InterfaceType substByContext(InterfaceType base, InterfaceType target);
 }
 
 /// The normalized arguments passed to a const constructor computed from the
@@ -32,17 +53,62 @@
     int index = callStructure.namedArguments.indexOf(name);
     if (index == -1) {
       // The named argument is not provided.
+      invariant(CURRENT_ELEMENT_SPANNABLE, defaultValues[name] != null,
+          message: "No default value for named argument '$name' in $this.");
       return defaultValues[name];
     }
-    return arguments[index + callStructure.positionalArgumentCount];
+    ConstantExpression value =
+        arguments[index + callStructure.positionalArgumentCount];
+    invariant(CURRENT_ELEMENT_SPANNABLE, value != null,
+        message: "No value for named argument '$name' in $this.");
+    return value;
   }
 
   /// Returns the normalized [index]th positional argument.
   ConstantExpression getPositionalArgument(int index) {
     if (index >= callStructure.positionalArgumentCount) {
       // The positional argument is not provided.
+      invariant(CURRENT_ELEMENT_SPANNABLE, defaultValues[index] != null,
+          message: "No default value for positional argument $index in $this.");
       return defaultValues[index];
     }
-    return arguments[index];
+    ConstantExpression value = arguments[index];
+    invariant(CURRENT_ELEMENT_SPANNABLE, value != null,
+        message: "No value for positional argument $index in $this.");
+    return value;
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('NormalizedArguments[');
+    sb.write('defaultValues={');
+    bool needsComma = false;
+    defaultValues.forEach((var key, ConstantExpression value) {
+      if (needsComma) {
+        sb.write(',');
+      }
+      if (key is String) {
+        sb.write('"');
+        sb.write(key);
+        sb.write('"');
+      } else {
+        sb.write(key);
+      }
+      sb.write(':');
+      sb.write(value.toStructuredText());
+      needsComma = true;
+    });
+    sb.write('},callStructure=');
+    sb.write(callStructure);
+    sb.write(',arguments=[');
+    arguments.forEach((ConstantExpression value) {
+      if (needsComma) {
+        sb.write(',');
+      }
+      sb.write(value.toStructuredText());
+      needsComma = true;
+    });
+    sb.write(']]');
+    return sb.toString();
   }
 }
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index ed2143d..6ed3a6f 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -7,17 +7,12 @@
 import '../common.dart';
 import '../constants/constant_system.dart';
 import '../core_types.dart';
-import '../elements/resolution_types.dart';
-import '../elements/elements.dart'
-    show
-        ConstructorElement,
-        FieldElement,
-        MethodElement,
-        PrefixElement,
-        VariableElement;
+import '../elements/types.dart';
+import '../elements/entities.dart';
 import '../resolution/operators.dart';
 import '../tree/dartstring.dart' show DartString;
 import '../universe/call_structure.dart' show CallStructure;
+import 'constructors.dart';
 import 'evaluation.dart';
 import 'values.dart';
 
@@ -32,6 +27,7 @@
   DOUBLE,
   ERRONEOUS,
   FUNCTION,
+  FIELD,
   IDENTICAL,
   INT,
   INT_FROM_ENVIRONMENT,
@@ -45,7 +41,7 @@
   SYNTHETIC,
   TYPE,
   UNARY,
-  VARIABLE,
+  LOCAL_VARIABLE,
   POSITIONAL_REFERENCE,
   NAMED_REFERENCE,
 }
@@ -80,7 +76,7 @@
 
   /// Returns the type of this constant expression, if it is independent of the
   /// environment values.
-  ResolutionDartType getKnownType(CommonElements commonElements) => null;
+  DartType getKnownType(CommonElements commonElements) => null;
 
   /// Returns a text string resembling the Dart code creating this constant.
   String toDartText() {
@@ -236,7 +232,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.boolType;
 }
 
@@ -272,7 +268,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.intType;
 }
 
@@ -308,7 +304,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.doubleType;
 }
 
@@ -344,7 +340,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.stringType;
 }
 
@@ -378,13 +374,13 @@
   bool _equals(NullConstantExpression other) => true;
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.nullType;
 }
 
 /// Literal list constant.
 class ListConstantExpression extends ConstantExpression {
-  final ResolutionInterfaceType type;
+  final InterfaceType type;
   final List<ConstantExpression> values;
 
   ListConstantExpression(this.type, this.values);
@@ -439,7 +435,7 @@
   }
 
   @override
-  ResolutionDartType getKnownType(CommonElements commonElements) => type;
+  DartType getKnownType(CommonElements commonElements) => type;
 
   @override
   bool get isImplicit => false;
@@ -450,7 +446,7 @@
 
 /// Literal map constant.
 class MapConstantExpression extends ConstantExpression {
-  final ResolutionInterfaceType type;
+  final InterfaceType type;
   final List<ConstantExpression> keys;
   final List<ConstantExpression> values;
 
@@ -486,8 +482,12 @@
       ConstantValue value = values[index].evaluate(environment, constantSystem);
       valueMap[key] = value;
     }
-    return constantSystem.createMap(environment.compiler, type,
-        valueMap.keys.toList(), valueMap.values.toList());
+    return constantSystem.createMap(
+        environment.commonElements,
+        environment.backendClasses,
+        type,
+        valueMap.keys.toList(),
+        valueMap.values.toList());
   }
 
   ConstantExpression apply(NormalizedArguments arguments) {
@@ -518,7 +518,7 @@
   }
 
   @override
-  ResolutionDartType getKnownType(CommonElements commonElements) => type;
+  DartType getKnownType(CommonElements commonElements) => type;
 
   @override
   bool get isImplicit => false;
@@ -531,8 +531,8 @@
 
 /// Invocation of a const constructor.
 class ConstructedConstantExpression extends ConstantExpression {
-  final ResolutionInterfaceType type;
-  final ConstructorElement target;
+  final InterfaceType type;
+  final ConstructorEntity target;
   final CallStructure callStructure;
   final List<ConstantExpression> arguments;
 
@@ -561,15 +561,20 @@
     sb.write('])');
   }
 
-  Map<FieldElement, ConstantExpression> computeInstanceFields() {
-    assert(invariant(target, target.constantConstructor != null,
+  Map<FieldEntity, ConstantExpression> computeInstanceFields(
+      Environment environment) {
+    ConstantConstructor constantConstructor =
+        environment.getConstructorConstant(target);
+    assert(invariant(target, constantConstructor != null,
         message: "No constant constructor computed for $target."));
-    return target.constantConstructor
-        .computeInstanceFields(arguments, callStructure);
+    return constantConstructor.computeInstanceFields(
+        environment, arguments, callStructure);
   }
 
-  ResolutionInterfaceType computeInstanceType() {
-    return target.constantConstructor.computeInstanceType(type);
+  InterfaceType computeInstanceType(Environment environment) {
+    return environment
+        .getConstructorConstant(target)
+        .computeInstanceType(environment, type);
   }
 
   ConstructedConstantExpression apply(NormalizedArguments arguments) {
@@ -580,13 +585,14 @@
   @override
   ConstantValue evaluate(
       Environment environment, ConstantSystem constantSystem) {
-    Map<FieldElement, ConstantValue> fieldValues =
-        <FieldElement, ConstantValue>{};
-    computeInstanceFields()
-        .forEach((FieldElement field, ConstantExpression constant) {
+    Map<FieldEntity, ConstantValue> fieldValues =
+        <FieldEntity, ConstantValue>{};
+    computeInstanceFields(environment)
+        .forEach((FieldEntity field, ConstantExpression constant) {
       fieldValues[field] = constant.evaluate(environment, constantSystem);
     });
-    return new ConstructedConstantValue(computeInstanceType(), fieldValues);
+    return new ConstructedConstantValue(
+        computeInstanceType(environment), fieldValues);
   }
 
   @override
@@ -695,7 +701,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.stringType;
 
   @override
@@ -732,21 +738,26 @@
   @override
   ConstantValue evaluate(
       Environment environment, ConstantSystem constantSystem) {
-    return constantSystem.createSymbol(environment.compiler, name);
+    return constantSystem.createSymbol(
+        environment.commonElements, environment.backendClasses, name);
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.symbolType;
 }
 
 /// Type literal.
 class TypeConstantExpression extends ConstantExpression {
-  /// Either [ResolutionDynamicType] or a raw [GenericType].
-  final ResolutionDartType type;
+  /// Either [DynamicType] or a raw [GenericType].
+  final DartType type;
+  final String name;
 
-  TypeConstantExpression(this.type) {
-    assert(type is GenericType || type is ResolutionDynamicType);
+  TypeConstantExpression(this.type, this.name) {
+    assert(type.isInterfaceType ||
+        type.isTypedef ||
+        type.isFunctionType ||
+        type.isDynamic);
   }
 
   ConstantExpressionKind get kind => ConstantExpressionKind.TYPE;
@@ -763,7 +774,8 @@
   @override
   ConstantValue evaluate(
       Environment environment, ConstantSystem constantSystem) {
-    return constantSystem.createType(environment.compiler, type);
+    return constantSystem.createType(
+        environment.commonElements, environment.backendClasses, type);
   }
 
   @override
@@ -775,47 +787,82 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.typeType;
 }
 
-/// Reference to a constant local, top-level, or static variable.
-class VariableConstantExpression extends ConstantExpression {
-  final VariableElement element;
+/// Reference to a constant top-level or static field.
+class FieldConstantExpression extends ConstantExpression {
+  final FieldEntity element;
 
-  VariableConstantExpression(this.element);
+  FieldConstantExpression(this.element);
 
-  ConstantExpressionKind get kind => ConstantExpressionKind.VARIABLE;
+  ConstantExpressionKind get kind => ConstantExpressionKind.FIELD;
 
   accept(ConstantExpressionVisitor visitor, [context]) {
-    return visitor.visitVariable(this, context);
+    return visitor.visitField(this, context);
   }
 
   @override
   void _createStructuredText(StringBuffer sb) {
-    sb.write('Variable(element=$element)');
+    sb.write('Field(element=$element)');
   }
 
   @override
   ConstantValue evaluate(
       Environment environment, ConstantSystem constantSystem) {
-    return element.constant.evaluate(environment, constantSystem);
+    ConstantExpression constant = environment.getFieldConstant(element);
+    return constant.evaluate(environment, constantSystem);
   }
 
   @override
   int _computeHashCode() => 13 * element.hashCode;
 
   @override
-  bool _equals(VariableConstantExpression other) {
+  bool _equals(FieldConstantExpression other) {
+    return element == other.element;
+  }
+}
+
+/// Reference to a constant local variable.
+class LocalVariableConstantExpression extends ConstantExpression {
+  final Local element;
+
+  LocalVariableConstantExpression(this.element);
+
+  ConstantExpressionKind get kind => ConstantExpressionKind.LOCAL_VARIABLE;
+
+  accept(ConstantExpressionVisitor visitor, [context]) {
+    return visitor.visitLocalVariable(this, context);
+  }
+
+  @override
+  void _createStructuredText(StringBuffer sb) {
+    sb.write('LocalVariable(element=$element)');
+  }
+
+  @override
+  ConstantValue evaluate(
+      Environment environment, ConstantSystem constantSystem) {
+    ConstantExpression constant = environment.getLocalConstant(element);
+    return constant.evaluate(environment, constantSystem);
+  }
+
+  @override
+  int _computeHashCode() => 13 * element.hashCode;
+
+  @override
+  bool _equals(LocalVariableConstantExpression other) {
     return element == other.element;
   }
 }
 
 /// Reference to a top-level or static function.
 class FunctionConstantExpression extends ConstantExpression {
-  final MethodElement element;
+  final FunctionEntity element;
+  final FunctionType type;
 
-  FunctionConstantExpression(this.element);
+  FunctionConstantExpression(this.element, this.type);
 
   ConstantExpressionKind get kind => ConstantExpressionKind.FUNCTION;
 
@@ -831,7 +878,7 @@
   @override
   ConstantValue evaluate(
       Environment environment, ConstantSystem constantSystem) {
-    return new FunctionConstantValue(element, element.type);
+    return new FunctionConstantValue(element, type);
   }
 
   @override
@@ -843,7 +890,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.functionType;
 }
 
@@ -894,9 +941,9 @@
         left.apply(arguments), operator, right.apply(arguments));
   }
 
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) {
-    ResolutionDartType knownLeftType = left.getKnownType(commonElements);
-    ResolutionDartType knownRightType = right.getKnownType(commonElements);
+  InterfaceType getKnownType(CommonElements commonElements) {
+    DartType knownLeftType = left.getKnownType(commonElements);
+    DartType knownRightType = right.getKnownType(commonElements);
     switch (operator.kind) {
       case BinaryOperatorKind.EQ:
       case BinaryOperatorKind.NOT_EQ:
@@ -1036,7 +1083,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.boolType;
 
   @override
@@ -1092,7 +1139,7 @@
   }
 
   @override
-  ResolutionDartType getKnownType(CommonElements commonElements) {
+  DartType getKnownType(CommonElements commonElements) {
     return expression.getKnownType(commonElements);
   }
 
@@ -1155,7 +1202,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.intType;
 
   @override
@@ -1227,9 +1274,9 @@
   }
 
   @override
-  ResolutionDartType getKnownType(CommonElements commonElements) {
-    ResolutionDartType trueType = trueExp.getKnownType(commonElements);
-    ResolutionDartType falseType = falseExp.getKnownType(commonElements);
+  DartType getKnownType(CommonElements commonElements) {
+    DartType trueType = trueExp.getKnownType(commonElements);
+    DartType falseType = falseExp.getKnownType(commonElements);
     if (trueType == falseType) {
       return trueType;
     }
@@ -1408,7 +1455,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.boolType;
 }
 
@@ -1474,7 +1521,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.intType;
 }
 
@@ -1536,7 +1583,7 @@
   }
 
   @override
-  ResolutionInterfaceType getKnownType(CommonElements commonElements) =>
+  InterfaceType getKnownType(CommonElements commonElements) =>
       commonElements.stringType;
 }
 
@@ -1544,7 +1591,7 @@
 /// For example `lib.C`.
 class DeferredConstantExpression extends ConstantExpression {
   final ConstantExpression expression;
-  final PrefixElement prefix;
+  final Entity prefix;
 
   DeferredConstantExpression(this.expression, this.prefix);
 
@@ -1607,7 +1654,8 @@
   R visitConcatenate(ConcatenateConstantExpression exp, A context);
   R visitSymbol(SymbolConstantExpression exp, A context);
   R visitType(TypeConstantExpression exp, A context);
-  R visitVariable(VariableConstantExpression exp, A context);
+  R visitLocalVariable(LocalVariableConstantExpression exp, A context);
+  R visitField(FieldConstantExpression exp, A context);
   R visitFunction(FunctionConstantExpression exp, A context);
   R visitBinary(BinaryConstantExpression exp, A context);
   R visitIdentical(IdenticalConstantExpression exp, A context);
@@ -1641,11 +1689,11 @@
     }
   }
 
-  void writeTypeArguments(ResolutionInterfaceType type) {
+  void writeTypeArguments(InterfaceType type) {
     if (type.treatAsRaw) return;
     sb.write('<');
     bool needsComma = false;
-    for (ResolutionDartType value in type.typeArguments) {
+    for (DartType value in type.typeArguments) {
       if (needsComma) {
         sb.write(', ');
       }
@@ -1779,11 +1827,11 @@
 
   @override
   void visitType(TypeConstantExpression exp, [_]) {
-    sb.write(exp.type.name);
+    sb.write(exp.name);
   }
 
   @override
-  void visitVariable(VariableConstantExpression exp, [_]) {
+  void visitField(FieldConstantExpression exp, [_]) {
     if (exp.element.isStatic) {
       sb.write(exp.element.enclosingClass.name);
       sb.write('.');
@@ -1792,6 +1840,11 @@
   }
 
   @override
+  void visitLocalVariable(LocalVariableConstantExpression exp, [_]) {
+    sb.write(exp.element.name);
+  }
+
+  @override
   void visitFunction(FunctionConstantExpression exp, [_]) {
     if (exp.element.isStatic) {
       sb.write(exp.element.enclosingClass.name);
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 36c14cc..5fdea05 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -6,7 +6,6 @@
 
 import '../common.dart';
 import '../core_types.dart';
-import '../elements/elements.dart' show Entity;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../tree/dartstring.dart';
diff --git a/pkg/compiler/lib/src/core_types.dart b/pkg/compiler/lib/src/core_types.dart
index 3108c1a..f69355d 100644
--- a/pkg/compiler/lib/src/core_types.dart
+++ b/pkg/compiler/lib/src/core_types.dart
@@ -5,9 +5,9 @@
 // TODO(sigmund): rename and move to common/elements.dart
 library dart2js.type_system;
 
+import 'common.dart';
 import 'elements/types.dart';
 import 'elements/entities.dart';
-import 'elements/elements.dart' show Entity;
 
 /// The common elements and types in Dart.
 abstract class CommonElements {
@@ -77,19 +77,13 @@
   /// The `NativeTypedData` class from dart:typed_data.
   ClassEntity get typedDataClass;
 
-  // TODO(johnniwinther): Move this to the JavaScriptBackend.
-  /// The class for patch annotation defined in dart:_js_helper.
-  ClassEntity get patchAnnotationClass;
-
-  // TODO(johnniwinther): Move this to the JavaScriptBackend.
-  ClassEntity get nativeAnnotationClass;
-
   /// Constructor of the `Symbol` class. This getter will ensure that `Symbol`
   /// is resolved and lookup the constructor on demand.
-  FunctionEntity get symbolConstructor;
+  ConstructorEntity get symbolConstructor;
 
   /// Whether [element] is the same as [symbolConstructor]. Used to check
   /// for the constructor without computing it until it is likely to be seen.
+  // TODO(johnniwinther): Change type of [e] to [MemberEntity].
   bool isSymbolConstructor(Entity e);
 
   /// The `MirrorSystem` class in dart:mirrors.
@@ -106,7 +100,7 @@
   /// Whether [element] is the constructor of the `MirrorsUsed` class. Used to
   /// check for the constructor without forcing the resolution of the
   /// `MirrorsUsed` class until it is necessary.
-  bool isMirrorsUsedConstructor(FunctionEntity element);
+  bool isMirrorsUsedConstructor(ConstructorEntity element);
 
   /// The `DeferredLibrary` annotation in dart:async that was used before the
   /// deferred import syntax was introduced.
@@ -123,11 +117,15 @@
   /// resolve the apply method if it hasn't been seen yet during compilation.
   bool isFunctionApplyMethod(MemberEntity element);
 
-  /// The unnamed constructor of `List`.
-  FunctionEntity get unnamedListConstructor;
+  /// Returns `true` if [element] is the unnamed constructor of `List`. This
+  /// will not resolve the constructor if it hasn't been seen yet during
+  /// compilation.
+  bool isUnnamedListConstructor(ConstructorEntity element);
 
-  /// The 'filled' constructor of `List`.
-  FunctionEntity get filledListConstructor;
+  /// Returns `true` if [element] is the 'filled' constructor of `List`. This
+  /// will not resolve the constructor if it hasn't been seen yet during
+  /// compilation.
+  bool isFilledListConstructor(ConstructorEntity element);
 
   /// The `dynamic` type.
   DynamicType get dynamicType;
@@ -207,3 +205,297 @@
   /// Returns `true` if [element] is a superclass of `List`.
   bool isListSupertype(ClassEntity element);
 }
+
+/// Interface for accessing libraries, classes and members.
+///
+/// The environment makes private and injected members directly available and
+/// should therefore not be used to determine scopes.
+abstract class ElementEnvironment {
+  LibraryEntity lookupLibrary(Uri uri, {bool required: false});
+
+  /// Lookup the class [name] in [library], fail if the class is missing and
+  /// [required].
+  ClassEntity lookupClass(LibraryEntity library, String name,
+      {bool required: false});
+
+  /// Lookup the member [name] in [library], fail if the class is missing and
+  /// [required].
+  MemberEntity lookupLibraryMember(LibraryEntity library, String name,
+      {bool setter: false, bool required: false});
+
+  /// Lookup the member [name] in [cls], fail if the class is missing and
+  /// [required].
+  MemberEntity lookupClassMember(ClassEntity cls, String name,
+      {bool setter: false, bool required: false});
+
+  /// Lookup the constructor [name] in [cls], fail if the class is missing and
+  /// [required].
+  ConstructorEntity lookupConstructor(ClassEntity cls, String name,
+      {bool required: false});
+
+  /// Create the instantiation of [cls] with the given [typeArguments].
+  InterfaceType createInterfaceType(
+      ClassEntity cls, List<DartType> typeArguments);
+
+  /// Returns the 'raw type' of [cls]. That is, the instantiation of [cls]
+  /// where all types arguments are `dynamic`.
+  InterfaceType getRawType(ClassEntity cls);
+
+  /// Returns the 'this type' of [cls]. That is, the instantiation of [cls]
+  /// where the type arguments are the type variables of [cls].
+  InterfaceType getThisType(ClassEntity cls);
+}
+
+abstract class CommonElementsMixin implements CommonElements {
+  ElementEnvironment get environment;
+
+  ClassEntity findClass(LibraryEntity library, String name,
+      {bool required: true}) {
+    return environment.lookupClass(library, name, required: required);
+  }
+
+  MemberEntity findLibraryMember(LibraryEntity library, String name,
+      {bool setter: false, bool required: true}) {
+    return environment.lookupLibraryMember(library, name,
+        setter: setter, required: required);
+  }
+
+  MemberEntity findClassMember(ClassEntity cls, String name,
+      {bool setter: false, bool required: true}) {
+    return environment.lookupClassMember(cls, name,
+        setter: setter, required: required);
+  }
+
+  ConstructorEntity findConstructor(ClassEntity cls, String name,
+      {bool required: true}) {
+    return environment.lookupConstructor(cls, name, required: required);
+  }
+
+  /// Return the raw type of [cls].
+  InterfaceType getRawType(ClassEntity cls) {
+    return environment.getRawType(cls);
+  }
+
+  /// Create the instantiation of [cls] with the given [typeArguments].
+  InterfaceType createInterfaceType(
+      ClassEntity cls, List<DartType> typeArguments) {
+    return environment.createInterfaceType(cls, typeArguments);
+  }
+
+  // From dart:core
+
+  ClassEntity _objectClass;
+  ClassEntity get objectClass =>
+      _objectClass ??= findClass(coreLibrary, 'Object');
+
+  ClassEntity _boolClass;
+  ClassEntity get boolClass => _boolClass ??= findClass(coreLibrary, 'bool');
+
+  ClassEntity _numClass;
+  ClassEntity get numClass => _numClass ??= findClass(coreLibrary, 'num');
+
+  ClassEntity _intClass;
+  ClassEntity get intClass => _intClass ??= findClass(coreLibrary, 'int');
+
+  ClassEntity _doubleClass;
+  ClassEntity get doubleClass =>
+      _doubleClass ??= findClass(coreLibrary, 'double');
+
+  ClassEntity _stringClass;
+  ClassEntity get stringClass =>
+      _stringClass ??= findClass(coreLibrary, 'String');
+
+  ClassEntity _functionClass;
+  ClassEntity get functionClass =>
+      _functionClass ??= findClass(coreLibrary, 'Function');
+
+  FunctionEntity _functionApplyMethod;
+  FunctionEntity get functionApplyMethod =>
+      _functionApplyMethod ??= findClassMember(functionClass, 'apply');
+
+  bool isFunctionApplyMethod(MemberEntity element) =>
+      element.name == 'apply' && element.enclosingClass == functionClass;
+
+  ClassEntity _nullClass;
+  ClassEntity get nullClass => _nullClass ??= findClass(coreLibrary, 'Null');
+
+  ClassEntity _listClass;
+  ClassEntity get listClass => _listClass ??= findClass(coreLibrary, 'List');
+
+  ClassEntity _typeClass;
+  ClassEntity get typeClass => _typeClass ??= findClass(coreLibrary, 'Type');
+
+  ClassEntity _mapClass;
+  ClassEntity get mapClass => _mapClass ??= findClass(coreLibrary, 'Map');
+
+  ClassEntity _symbolClass;
+  ClassEntity get symbolClass =>
+      _symbolClass ??= findClass(coreLibrary, 'Symbol');
+
+  ConstructorEntity _symbolConstructor;
+  ConstructorEntity get symbolConstructor =>
+      _symbolConstructor ??= findConstructor(symbolClass, '');
+
+  bool isSymbolConstructor(Entity e) => e == symbolConstructor;
+
+  ClassEntity _stackTraceClass;
+  ClassEntity get stackTraceClass =>
+      _stackTraceClass ??= findClass(coreLibrary, 'StackTrace');
+
+  ClassEntity _iterableClass;
+  ClassEntity get iterableClass =>
+      _iterableClass ??= findClass(coreLibrary, 'Iterable');
+
+  ClassEntity _resourceClass;
+  ClassEntity get resourceClass =>
+      _resourceClass ??= findClass(coreLibrary, 'Resource');
+
+  FunctionEntity _identicalFunction;
+  FunctionEntity get identicalFunction =>
+      _identicalFunction ??= findLibraryMember(coreLibrary, 'identical');
+
+  // From dart:async
+
+  ClassEntity _futureClass;
+  ClassEntity get futureClass =>
+      _futureClass ??= findClass(asyncLibrary, 'Future');
+
+  ClassEntity _streamClass;
+  ClassEntity get streamClass =>
+      _streamClass ??= findClass(asyncLibrary, 'Stream');
+
+  ClassEntity _deferredLibraryClass;
+  ClassEntity get deferredLibraryClass =>
+      _deferredLibraryClass ??= findClass(asyncLibrary, "DeferredLibrary");
+
+  // From dart:mirrors
+
+  ClassEntity _mirrorSystemClass;
+  ClassEntity get mirrorSystemClass => _mirrorSystemClass ??=
+      findClass(mirrorsLibrary, 'MirrorSystem', required: false);
+
+  FunctionEntity _mirrorSystemGetNameFunction;
+  bool isMirrorSystemGetNameFunction(MemberEntity element) {
+    if (_mirrorSystemGetNameFunction == null) {
+      if (!element.isFunction || mirrorsLibrary == null) return false;
+      ClassEntity cls = mirrorSystemClass;
+      if (element.enclosingClass != cls) return false;
+      if (cls != null) {
+        _mirrorSystemGetNameFunction =
+            findClassMember(cls, 'getName', required: false);
+      }
+    }
+    return element == _mirrorSystemGetNameFunction;
+  }
+
+  ClassEntity _mirrorsUsedClass;
+  ClassEntity get mirrorsUsedClass => _mirrorsUsedClass ??=
+      findClass(mirrorsLibrary, 'MirrorsUsed', required: false);
+
+  bool isMirrorsUsedConstructor(ConstructorEntity element) =>
+      mirrorsLibrary != null && mirrorsUsedClass == element.enclosingClass;
+
+  // From dart:typed_data
+
+  ClassEntity _typedDataClass;
+  ClassEntity get typedDataClass =>
+      _typedDataClass ??= findClass(typedDataLibrary, 'NativeTypedData');
+
+  bool isUnnamedListConstructor(ConstructorEntity element) =>
+      element.name == '' && element.enclosingClass == listClass;
+
+  bool isFilledListConstructor(ConstructorEntity element) =>
+      element.name == 'filled' && element.enclosingClass == listClass;
+
+  // TODO(johnniwinther): Change types to `ClassEntity` when these are not
+  // called with unrelated elements.
+  bool isNumberOrStringSupertype(/*Class*/ Entity element) {
+    return element == findClass(coreLibrary, 'Comparable', required: false);
+  }
+
+  bool isStringOnlySupertype(/*Class*/ Entity element) {
+    return element == findClass(coreLibrary, 'Pattern', required: false);
+  }
+
+  bool isListSupertype(/*Class*/ Entity element) => element == iterableClass;
+
+  @override
+  InterfaceType get objectType => getRawType(objectClass);
+
+  @override
+  InterfaceType get boolType => getRawType(boolClass);
+
+  @override
+  InterfaceType get doubleType => getRawType(doubleClass);
+
+  @override
+  InterfaceType get functionType => getRawType(functionClass);
+
+  @override
+  InterfaceType get intType => getRawType(intClass);
+
+  @override
+  InterfaceType get resourceType => getRawType(resourceClass);
+
+  @override
+  InterfaceType listType([DartType elementType]) {
+    if (elementType == null) {
+      return getRawType(listClass);
+    }
+    return createInterfaceType(listClass, [elementType]);
+  }
+
+  @override
+  InterfaceType mapType([DartType keyType, DartType valueType]) {
+    if (keyType == null && valueType == null) {
+      return getRawType(mapClass);
+    } else if (keyType == null) {
+      keyType = dynamicType;
+    } else if (valueType == null) {
+      valueType = dynamicType;
+    }
+    return createInterfaceType(mapClass, [keyType, valueType]);
+  }
+
+  @override
+  InterfaceType get nullType => getRawType(nullClass);
+
+  @override
+  InterfaceType get numType => getRawType(numClass);
+
+  @override
+  InterfaceType get stringType => getRawType(stringClass);
+
+  @override
+  InterfaceType get symbolType => getRawType(symbolClass);
+
+  @override
+  InterfaceType get typeType => getRawType(typeClass);
+
+  @override
+  InterfaceType get stackTraceType => getRawType(stackTraceClass);
+
+  @override
+  InterfaceType iterableType([DartType elementType]) {
+    if (elementType == null) {
+      return getRawType(iterableClass);
+    }
+    return createInterfaceType(iterableClass, [elementType]);
+  }
+
+  @override
+  InterfaceType futureType([DartType elementType]) {
+    if (elementType == null) {
+      return getRawType(futureClass);
+    }
+    return createInterfaceType(futureClass, [elementType]);
+  }
+
+  @override
+  InterfaceType streamType([DartType elementType]) {
+    if (elementType == null) {
+      return getRawType(streamClass);
+    }
+    return createInterfaceType(streamClass, [elementType]);
+  }
+}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index cb39e78..812460a 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -122,7 +122,6 @@
   Uri resolutionOutput = currentDirectory.resolve('out.data');
   bool allowNativeExtensions = false;
   bool trustTypeAnnotations = false;
-  bool trustJSInteropTypeAnnotations = false;
   bool checkedMode = false;
   List<String> hints = <String>[];
   bool verbose;
@@ -243,7 +242,6 @@
   }
 
   void setTrustJSInteropTypeAnnotations(String argument) {
-    trustJSInteropTypeAnnotations = true;
     implyCompilation(argument);
   }
 
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 6055e03..4b5c2cc 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -4,7 +4,6 @@
 
 library deferred_load;
 
-import 'common/backend_api.dart' show Backend;
 import 'common/tasks.dart' show CompilerTask;
 import 'common.dart';
 import 'compiler.dart' show Compiler;
@@ -40,7 +39,7 @@
     show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
 import 'util/setlet.dart' show Setlet;
 import 'util/uri_extras.dart' as uri_extras;
-import 'util/util.dart' show Link, makeUnique;
+import 'util/util.dart' show makeUnique;
 
 /// A "hunk" of the program that will be loaded whenever one of its [imports]
 /// are loaded.
@@ -157,7 +156,7 @@
     mainOutputUnit.imports.add(_fakeMainImport);
   }
 
-  Backend get backend => compiler.backend;
+  JavaScriptBackend get backend => compiler.backend;
   DiagnosticReporter get reporter => compiler.reporter;
 
   /// Returns the [OutputUnit] where [element] belongs.
diff --git a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
index e12c09c..b853b5b 100644
--- a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
+++ b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
@@ -4,6 +4,7 @@
 
 library dart2js.diagnostic_listener;
 
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../elements/elements.dart' show Element;
 import '../options.dart' show DiagnosticOptions;
 import 'messages.dart';
@@ -21,11 +22,16 @@
 
   /// Creates a [SourceSpan] for [node] in scope of the current element.
   ///
-  /// If [node] is a [Node] or [Token] we assert in checked mode that the
-  /// corresponding tokens can be found within the tokens of the current
-  /// element.
+  /// If [node] is a [Node] we assert in checked mode that the corresponding
+  /// tokens can be found within the tokens of the current element.
   SourceSpan spanFromSpannable(Spannable node);
 
+  /// Creates a [SourceSpan] for [token] in scope of the current element.
+  ///
+  /// In checked mode we assert that the token can be found within the tokens
+  /// of the current element.
+  SourceSpan spanFromToken(Token token);
+
   void reportErrorMessage(Spannable spannable, MessageKind messageKind,
       [Map arguments = const {}]) {
     reportError(createMessage(spannable, messageKind, arguments));
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 7563cea..d9785c6 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -62,7 +62,7 @@
 
 library dart2js.messages;
 
-import '../tokens/token.dart' show ErrorToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' show ErrorToken, Token;
 import 'generated/shared_messages.dart' as shared_messages;
 import 'invariant.dart' show invariant;
 import 'spannable.dart' show CURRENT_ELEMENT_SPANNABLE;
@@ -3090,7 +3090,9 @@
           examples: const [
             "main(",
             "main(){",
-            "main(){]}",
+            "main(){[}",
+            // TODO(ahe): https://github.com/dart-lang/sdk/issues/28495
+            // "main(){]}",
           ]),
 
       MessageKind.UNTERMINATED_TOKEN: const MessageTemplate(
diff --git a/pkg/compiler/lib/src/diagnostics/source_span.dart b/pkg/compiler/lib/src/diagnostics/source_span.dart
index d53ebae..638a923 100644
--- a/pkg/compiler/lib/src/diagnostics/source_span.dart
+++ b/pkg/compiler/lib/src/diagnostics/source_span.dart
@@ -4,7 +4,7 @@
 
 library dart2js.diagnostics.source_span;
 
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../tree/tree.dart' show Node;
 import 'spannable.dart' show Spannable;
 
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index bcb5627..9f1efbc 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -16,10 +16,10 @@
 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
 import 'deferred_load.dart' show OutputUnit;
 import 'elements/elements.dart';
+import 'elements/entities.dart';
 import 'elements/visitor.dart';
 import 'js/js.dart' as jsAst;
 import 'js_backend/js_backend.dart' show JavaScriptBackend;
-import 'js_emitter/full_emitter/emitter.dart' as full show Emitter;
 import 'types/types.dart' show TypeMask;
 import 'universe/world_builder.dart' show ReceiverConstraint;
 import 'universe/world_impact.dart'
@@ -130,9 +130,6 @@
 
     FieldInfo info = new FieldInfo(
         name: element.name,
-        // We use element.hashCode because it is globally unique and it is
-        // available while we are doing codegen.
-        coverageId: '${element.hashCode}',
         type: '${element.type}',
         inferredType: '$inferredType',
         code: code,
@@ -147,6 +144,12 @@
       }
     }
 
+    if (JavaScriptBackend.TRACE_METHOD == 'post') {
+      // We use element.hashCode because it is globally unique and it is
+      // available while we are doing codegen.
+      info.coverageId = '${element.hashCode}';
+    }
+
     int closureSize = _addClosureInfo(info, element);
     info.size = size + closureSize;
 
@@ -274,9 +277,6 @@
     FunctionInfo info = new FunctionInfo(
         name: name,
         functionKind: kind,
-        // We use element.hashCode because it is globally unique and it is
-        // available while we are doing codegen.
-        coverageId: '${element.hashCode}',
         modifiers: modifiers,
         returnType: returnType,
         inferredReturnType: inferredReturnType,
@@ -295,6 +295,12 @@
       info.closures = <ClosureInfo>[];
     }
 
+    if (JavaScriptBackend.TRACE_METHOD == 'post') {
+      // We use element.hashCode because it is globally unique and it is
+      // available while we are doing codegen.
+      info.coverageId = '${element.hashCode}';
+    }
+
     info.size = size;
 
     result.functions.add(info);
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart
index 167582f..1d656c57c 100644
--- a/pkg/compiler/lib/src/elements/common.dart
+++ b/pkg/compiler/lib/src/elements/common.dart
@@ -174,7 +174,7 @@
   bool get isInternalLibrary =>
       isPlatformLibrary && canonicalUri.path.startsWith('_');
 
-  String get libraryOrScriptName {
+  String get name {
     if (hasLibraryName) {
       return libraryName;
     } else {
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index dcf3f09..ab27bf0 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -6,7 +6,6 @@
 
 import '../common.dart';
 import '../common/resolution.dart' show Resolution;
-import '../compiler.dart' show Compiler;
 import '../constants/constructors.dart';
 import '../constants/expressions.dart';
 import '../core_types.dart' show CommonElements;
@@ -14,11 +13,11 @@
 import '../resolution/scope.dart' show Scope;
 import '../resolution/tree_elements.dart' show TreeElements;
 import '../script.dart';
-import '../tokens/token.dart'
+import 'package:front_end/src/fasta/scanner.dart'
     show Token, isUserDefinableOperator, isMinusOperator;
 import '../tree/tree.dart';
 import '../universe/call_structure.dart';
-import '../util/characters.dart' show $_;
+import 'package:front_end/src/fasta/scanner/characters.dart' show $_;
 import '../util/util.dart';
 import '../world.dart' show ClosedWorld;
 import 'entities.dart';
@@ -118,19 +117,6 @@
   toString() => id;
 }
 
-/// Abstract interface for entities.
-///
-/// Implement this directly if the entity is not a Dart language entity.
-/// Entities defined within the Dart language should implement [Element].
-///
-/// For instance, the JavaScript backend need to create synthetic variables for
-/// calling intercepted classes and such variables do not correspond to an
-/// entity in the Dart source code nor in the terminology of the Dart language
-/// and should therefore implement [Entity] directly.
-abstract class Entity implements Spannable {
-  String get name;
-}
-
 /**
  * A declared element of a program.
  *
@@ -757,23 +743,23 @@
   }
 
   static bool isFixedListConstructorCall(
-      Element element, Send node, CommonElements commonElements) {
-    return element == commonElements.unnamedListConstructor &&
+      ConstructorEntity element, Send node, CommonElements commonElements) {
+    return commonElements.isUnnamedListConstructor(element) &&
         node.isCall &&
         !node.arguments.isEmpty &&
         node.arguments.tail.isEmpty;
   }
 
   static bool isGrowableListConstructorCall(
-      Element element, Send node, CommonElements commonElements) {
-    return element == commonElements.unnamedListConstructor &&
+      ConstructorEntity element, Send node, CommonElements commonElements) {
+    return commonElements.isUnnamedListConstructor(element) &&
         node.isCall &&
         node.arguments.isEmpty;
   }
 
   static bool isFilledListConstructorCall(
-      Element element, Send node, CommonElements commonElements) {
-    return element == commonElements.filledListConstructor &&
+      ConstructorEntity element, Send node, CommonElements commonElements) {
+    return commonElements.isFilledListConstructor(element) &&
         node.isCall &&
         !node.arguments.isEmpty &&
         !node.arguments.tail.isEmpty &&
@@ -1092,13 +1078,12 @@
   /// or the empty string if there is no library tag.
   String get libraryName;
 
-  /// Returns the library name (as defined by the library tag) or for script
-  /// (which have no library tag) the script file name. The latter case is used
-  /// to provide a 'library name' for scripts to use for instance in dartdoc.
+  /// Returns the library name (as defined by the library tag) or for scripts
+  /// (which have no library tag) the script file name.
   ///
   /// Note: the returned filename is still escaped ("a%20b.dart" instead of
   /// "a b.dart").
-  String get libraryOrScriptName;
+  String get name;
 }
 
 /// The implicit scope defined by a import declaration with a prefix clause.
@@ -1171,7 +1156,9 @@
 
 /// A function, variable or parameter defined in an executable context.
 abstract class LocalElement extends Element
-    implements AstElement, TypedElement, Local {}
+    implements AstElement, TypedElement, Local {
+  ExecutableElement get executableContext;
+}
 
 /// A top level, static or instance field, a formal parameter or local variable.
 abstract class VariableElement extends ExecutableElement {
@@ -1190,24 +1177,6 @@
   ConstantExpression get constant;
 }
 
-/// An entity that defines a local entity (memory slot) in generated code.
-///
-/// Parameters, local variables and local functions (can) define local entity
-/// and thus implement [Local] through [LocalElement]. For non-element locals,
-/// like `this` and boxes, specialized [Local] classes are created.
-///
-/// Type variables can introduce locals in factories and constructors
-/// but since one type variable can introduce different locals in different
-/// factories and constructors it is not itself a [Local] but instead
-/// a non-element [Local] is created through a specialized class.
-// TODO(johnniwinther): Should [Local] have `isAssignable` or `type`?
-// TODO(johnniwinther): Move this to 'entities.dart' when it does not refer
-// to [ExecutableElement].
-abstract class Local extends Entity {
-  /// The context in which this local is defined.
-  ExecutableElement get executableContext;
-}
-
 /// A variable or parameter that is local to an executable context.
 ///
 /// The executable context is the [ExecutableElement] in which this variable
@@ -1416,7 +1385,8 @@
     implements LocalElement {}
 
 /// A constructor.
-abstract class ConstructorElement extends MethodElement {
+abstract class ConstructorElement extends MethodElement
+    implements ConstructorEntity {
   /// Returns `true` if [effectiveTarget] has been computed for this
   /// constructor.
   bool get hasEffectiveTarget;
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index 6fd1f50..1cc4d7f 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -4,15 +4,26 @@
 
 library entities;
 
-import 'elements.dart' show Entity;
+import '../common.dart';
+
+/// Abstract interface for entities.
+///
+/// Implement this directly if the entity is not a Dart language entity.
+/// Entities defined within the Dart language should implement [Element].
+///
+/// For instance, the JavaScript backend need to create synthetic variables for
+/// calling intercepted classes and such variables do not correspond to an
+/// entity in the Dart source code nor in the terminology of the Dart language
+/// and should therefore implement [Entity] directly.
+abstract class Entity implements Spannable {
+  String get name;
+}
 
 /// Stripped down super interface for library like entities.
 ///
 /// Currently only [LibraryElement] but later also kernel based Dart classes
 /// and/or Dart-in-JS classes.
-abstract class LibraryEntity extends Entity {
-  String get libraryName;
-}
+abstract class LibraryEntity extends Entity {}
 
 /// Stripped down super interface for class like entities.
 ///
@@ -53,6 +64,41 @@
 
 /// Stripped down super interface for function like entities.
 ///
-/// Currently only [FieldElement] but later also kernel based Dart constructors
+/// Currently only [MethodElement] but later also kernel based Dart constructors
 /// and methods and/or Dart-in-JS function-like properties.
 abstract class FunctionEntity extends MemberEntity {}
+
+/// Stripped down super interface for constructor like entities.
+///
+/// Currently only [ConstructorElement] but later also kernel based Dart
+/// constructors and/or Dart-in-JS constructor-like properties.
+// TODO(johnniwinther): Remove factory constructors from the set of
+// constructors.
+abstract class ConstructorEntity extends FunctionEntity {
+  bool get isGenerativeConstructor;
+  bool get isFactoryConstructor;
+}
+
+/// An entity that defines a local entity (memory slot) in generated code.
+///
+/// Parameters, local variables and local functions (can) define local entity
+/// and thus implement [Local] through [LocalElement]. For non-element locals,
+/// like `this` and boxes, specialized [Local] classes are created.
+///
+/// Type variables can introduce locals in factories and constructors
+/// but since one type variable can introduce different locals in different
+/// factories and constructors it is not itself a [Local] but instead
+/// a non-element [Local] is created through a specialized class.
+// TODO(johnniwinther): Should [Local] have `isAssignable` or `type`?
+abstract class Local extends Entity {
+  /// The context in which this local is defined.
+  Entity get executableContext;
+
+  /// The outermost member that contains this element.
+  ///
+  /// For top level, static or instance members, the member context is the
+  /// element itself. For parameters, local variables and nested closures, the
+  /// member context is the top level, static or instance member in which it is
+  /// defined.
+  MemberEntity get memberContext;
+}
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 7f887ac..88eee67 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -20,8 +20,8 @@
 import '../resolution/tree_elements.dart' show TreeElements;
 import '../resolution/typedefs.dart' show TypedefCyclicVisitor;
 import '../script.dart';
-import '../tokens/token.dart' show ErrorToken, Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
+import 'package:front_end/src/fasta/scanner.dart' show ErrorToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
 import '../tree/tree.dart';
 import '../util/util.dart';
 import 'common.dart';
@@ -314,7 +314,6 @@
   @override
   bool isRedirectingGenerativeInternal;
 
-  @override
   void set isRedirectingGenerative(_) {
     throw new UnsupportedError("isRedirectingGenerative");
   }
@@ -1224,16 +1223,6 @@
     return libraryTag.name.toString();
   }
 
-  String get libraryOrScriptName {
-    if (libraryTag != null) {
-      return libraryTag.name.toString();
-    } else {
-      // Use the file name as script name.
-      String path = canonicalUri.path;
-      return path.substring(path.lastIndexOf('/') + 1);
-    }
-  }
-
   Scope buildScope() => new LibraryScope(this);
 
   String toString() {
@@ -3269,6 +3258,9 @@
 
   JumpTargetX(this.statement, this.nestingLevel, this.executableContext);
 
+  @override
+  MemberElement get memberContext => executableContext.memberContext;
+
   String get name => "target";
 
   bool get isTarget => isBreakTarget || isContinueTarget;
diff --git a/pkg/compiler/lib/src/elements/names.dart b/pkg/compiler/lib/src/elements/names.dart
index a4a6f7a..88e2522 100644
--- a/pkg/compiler/lib/src/elements/names.dart
+++ b/pkg/compiler/lib/src/elements/names.dart
@@ -11,7 +11,7 @@
   /// Create a [Name] for an identifier [text]. If [text] begins with '_' a
   /// private name with respect to [library] is created. If [isSetter] is `true`
   /// the created name represents the setter name 'text='.
-  factory Name(String text, LibraryElement library, {bool isSetter: false}) {
+  factory Name(String text, LibraryEntity library, {bool isSetter: false}) {
     if (isPrivateName(text)) {
       return new PrivateName(text, library, isSetter: isSetter);
     }
@@ -109,5 +109,5 @@
     return super == (other) && library == other.library;
   }
 
-  String toString() => '${library.libraryName}#${super.toString()}';
+  String toString() => '${library.name}#${super.toString()}';
 }
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index 3d564b3..d3f6883 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'entities.dart';
+import '../util/util.dart' show equalElements;
 
 /// Hierarchy to describe types in Dart.
 ///
@@ -20,6 +21,8 @@
 /// on kernel ir without the need for [Element].
 
 abstract class DartType {
+  const DartType();
+
   /// Returns the unaliased type of this type.
   ///
   /// The unaliased type of a typedef'd type is the unaliased type to which its
@@ -28,61 +31,209 @@
   /// For example, the unaliased type of `typedef A Func<A,B>(B b)` is the
   /// function type `(B) -> A` and the unaliased type of `Func<int,String>`
   /// is the function type `(String) -> int`.
-  DartType get unaliased;
+  DartType get unaliased => this;
 
   /// Is `true` if this type has no non-dynamic type arguments.
-  bool get treatAsRaw;
+  bool get treatAsRaw => true;
 
   /// Is `true` if this type should be treated as the dynamic type.
-  bool get treatAsDynamic;
+  bool get treatAsDynamic => false;
 
   /// Is `true` if this type is the dynamic type.
-  bool get isDynamic;
+  bool get isDynamic => false;
 
   /// Is `true` if this type is the void type.
-  bool get isVoid;
-
-  /// Is `true` if this is the type of `Object` from dart:core.
-  bool get isObject;
+  bool get isVoid => false;
 
   /// Is `true` if this type is an interface type.
-  bool get isInterfaceType;
+  bool get isInterfaceType => false;
 
   /// Is `true` if this type is a typedef.
-  bool get isTypedef;
+  bool get isTypedef => false;
 
   /// Is `true` if this type is a function type.
-  bool get isFunctionType;
+  bool get isFunctionType => false;
 
   /// Is `true` if this type is a type variable.
-  bool get isTypeVariable;
+  bool get isTypeVariable => false;
 
   /// Is `true` if this type is a malformed type.
-  bool get isMalformed;
+  bool get isMalformed => false;
 }
 
-abstract class InterfaceType extends DartType {
-  ClassEntity get element;
-  List<DartType> get typeArguments;
+class InterfaceType extends DartType {
+  final ClassEntity element;
+  final List<DartType> typeArguments;
+
+  InterfaceType(this.element, this.typeArguments);
+
+  int get hashCode {
+    int hash = element.hashCode;
+    for (DartType argument in typeArguments) {
+      int argumentHash = argument != null ? argument.hashCode : 0;
+      hash = 17 * hash + 3 * argumentHash;
+    }
+    return hash;
+  }
+
+  bool operator ==(other) {
+    if (other is! InterfaceType) return false;
+    return identical(element, other.element) &&
+        equalElements(typeArguments, other.typeArguments);
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write(element.name);
+    if (typeArguments.isNotEmpty) {
+      sb.write('<');
+      bool needsComma = false;
+      for (DartType typeArgument in typeArguments) {
+        if (needsComma) {
+          sb.write(',');
+        }
+        sb.write(typeArgument);
+        needsComma = true;
+      }
+      sb.write('>');
+    }
+    return sb.toString();
+  }
 }
 
-abstract class TypeVariableType extends DartType {
-  TypeVariableEntity get element;
+class TypeVariableType extends DartType {
+  final TypeVariableEntity element;
+
+  TypeVariableType(this.element);
+
+  bool get isTypeVariable => true;
+
+  int get hashCode => 17 * element.hashCode;
+
+  bool operator ==(other) {
+    if (other is! TypeVariableType) return false;
+    return identical(other.element, element);
+  }
+
+  String toString() => '${element.typeDeclaration.name}.${element.name}';
 }
 
-abstract class VoidType extends DartType {}
+class VoidType extends DartType {
+  const VoidType();
 
-abstract class DynamicType extends DartType {}
+  bool get isVoid => true;
 
-abstract class FunctionType extends DartType {
-  DartType get returnType;
-  List<DartType> get parameterTypes;
-  List<DartType> get optionalParameterTypes;
+  int get hashCode => 6007;
+
+  String toString() => 'void';
+}
+
+class DynamicType extends DartType {
+  const DynamicType();
+
+  @override
+  bool get isDynamic => true;
+
+  @override
+  bool get treatAsDynamic => true;
+
+  int get hashCode => 91;
+
+  String toString() => 'dynamic';
+}
+
+class FunctionType extends DartType {
+  final DartType returnType;
+  final List<DartType> parameterTypes;
+  final List<DartType> optionalParameterTypes;
 
   /// The names of the named parameters ordered lexicographically.
-  List<String> get namedParameters;
+  final List<String> namedParameters;
 
   /// The types of the named parameters in the order corresponding to the
   /// [namedParameters].
-  List<DartType> get namedParameterTypes;
+  final List<DartType> namedParameterTypes;
+
+  FunctionType(
+      this.returnType,
+      this.parameterTypes,
+      this.optionalParameterTypes,
+      this.namedParameters,
+      this.namedParameterTypes);
+
+  bool get isFunctionType => true;
+
+  int get hashCode {
+    int hash = 3 * returnType.hashCode;
+    for (DartType parameter in parameterTypes) {
+      hash = 17 * hash + 5 * parameter.hashCode;
+    }
+    for (DartType parameter in optionalParameterTypes) {
+      hash = 19 * hash + 7 * parameter.hashCode;
+    }
+    for (String name in namedParameters) {
+      hash = 23 * hash + 11 * name.hashCode;
+    }
+    for (DartType parameter in namedParameterTypes) {
+      hash = 29 * hash + 13 * parameter.hashCode;
+    }
+    return hash;
+  }
+
+  bool operator ==(other) {
+    if (other is! FunctionType) return false;
+    return returnType == other.returnType &&
+        equalElements(parameterTypes, other.parameterTypes) &&
+        equalElements(optionalParameterTypes, other.optionalParameterTypes) &&
+        equalElements(namedParameters, other.namedParameters) &&
+        equalElements(namedParameterTypes, other.namedParameterTypes);
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write(returnType);
+    sb.write(' Function(');
+    bool needsComma = false;
+    for (DartType parameterType in parameterTypes) {
+      if (needsComma) {
+        sb.write(',');
+      }
+      sb.write(parameterType);
+      needsComma = true;
+    }
+    if (optionalParameterTypes.isNotEmpty) {
+      if (needsComma) {
+        sb.write(',');
+      }
+      sb.write('[');
+      bool needsOptionalComma = false;
+      for (DartType typeArgument in optionalParameterTypes) {
+        if (needsOptionalComma) {
+          sb.write(',');
+        }
+        sb.write(typeArgument);
+        needsOptionalComma = true;
+      }
+      sb.write(']');
+      needsComma = true;
+    }
+    if (namedParameters.isNotEmpty) {
+      if (needsComma) {
+        sb.write(',');
+      }
+      sb.write('{');
+      bool needsNamedComma = false;
+      for (int index = 0; index < namedParameters.length; index++) {
+        if (needsNamedComma) {
+          sb.write(',');
+        }
+        sb.write(namedParameterTypes[index]);
+        sb.write(' ');
+        sb.write(namedParameters[index]);
+        needsNamedComma = true;
+      }
+      sb.write('}');
+    }
+    return sb.toString();
+  }
 }
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index efbcc50..ef939cd 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -6,8 +6,6 @@
 
 import 'dart:collection' show Queue;
 
-import 'cache_strategy.dart';
-import 'common/backend_api.dart' show Backend;
 import 'common/resolution.dart' show Resolution;
 import 'common/tasks.dart' show CompilerTask;
 import 'common/work.dart' show WorkItem;
@@ -20,11 +18,11 @@
         ClassElement,
         ConstructorElement,
         Element,
-        Entity,
         MemberElement;
 import 'elements/entities.dart';
 import 'elements/resolution_types.dart'
     show ResolutionDartType, ResolutionInterfaceType;
+import 'js_backend/backend.dart' show JavaScriptBackend;
 import 'native/native.dart' as native;
 import 'universe/world_builder.dart';
 import 'universe/use.dart'
@@ -52,24 +50,17 @@
             ? const DirectEnqueuerStrategy()
             : const TreeShakingEnqueuerStrategy(),
         compiler.globalDependencies,
-        compiler.backend,
-        compiler.cacheStrategy);
+        compiler.backend);
     _codegen = compiler.backend.createCodegenEnqueuer(this, compiler);
   }
 
   ResolutionEnqueuer get resolution => _resolution;
   Enqueuer get codegen => _codegen;
-
-  void forgetEntity(Entity entity) {
-    resolution.forgetEntity(entity, compiler);
-    codegen.forgetEntity(entity, compiler);
-  }
 }
 
 abstract class Enqueuer {
   WorldBuilder get worldBuilder;
   native.NativeEnqueuer get nativeEnqueuer;
-  void forgetEntity(Entity entity, Compiler compiler);
 
   // TODO(johnniwinther): Initialize [_impactStrategy] to `null`.
   ImpactStrategy _impactStrategy = const ImpactStrategy();
@@ -127,7 +118,7 @@
   final String name;
   final Resolution _resolution;
   final CompilerOptions _options;
-  final Backend backend;
+  final JavaScriptBackend backend;
   final GlobalDependencyRegistry _globalDependencies;
   final native.NativeEnqueuer nativeEnqueuer;
 
@@ -149,20 +140,14 @@
   /// has been emptied.
   final Queue<_DeferredAction> _deferredQueue = new Queue<_DeferredAction>();
 
-  ResolutionEnqueuer(
-      this.task,
-      this._options,
-      Resolution resolution,
-      this.strategy,
-      this._globalDependencies,
-      Backend backend,
-      CacheStrategy cacheStrategy,
+  ResolutionEnqueuer(this.task, this._options, Resolution resolution,
+      this.strategy, this._globalDependencies, JavaScriptBackend backend,
       [this.name = 'resolution enqueuer'])
       : this.backend = backend,
         this._resolution = resolution,
         this.nativeEnqueuer = backend.nativeResolutionEnqueuer(),
         _universe = new ResolutionWorldBuilderImpl(
-            backend, resolution, cacheStrategy, const OpenWorldStrategy()),
+            backend, resolution, const OpenWorldStrategy()),
         _workItemBuilder = new ResolutionWorkItemBuilder(resolution) {
     _impactVisitor = new EnqueuerImplImpactVisitor(this);
   }
@@ -419,11 +404,6 @@
       _reporter.withCurrentElement(task.element, task.action);
     }
   }
-
-  void forgetEntity(Entity entity, Compiler compiler) {
-    _universe.forgetEntity(entity, compiler);
-    _processedEntities.remove(entity);
-  }
 }
 
 /// Strategy used by the enqueuer to populate the world.
diff --git a/pkg/compiler/lib/src/hash/sha1.dart b/pkg/compiler/lib/src/hash/sha1.dart
index 56ae8b9..7b04aed 100644
--- a/pkg/compiler/lib/src/hash/sha1.dart
+++ b/pkg/compiler/lib/src/hash/sha1.dart
@@ -78,7 +78,6 @@
 // functions.
 abstract class _HashBase implements Hash {
   final int _chunkSizeInWords;
-  final int _digestSizeInWords;
   final bool _bigEndianWords;
   final List<int> _currentChunk;
   final List<int> _h;
@@ -91,8 +90,7 @@
       : _pendingData = [],
         _currentChunk = new List(chunkSizeInWords),
         _h = new List(digestSizeInWords),
-        _chunkSizeInWords = chunkSizeInWords,
-        _digestSizeInWords = digestSizeInWords;
+        _chunkSizeInWords = chunkSizeInWords;
 
   // Update the hasher with more data.
   void add(List<int> data) {
diff --git a/pkg/compiler/lib/src/helpers/trace.dart b/pkg/compiler/lib/src/helpers/trace.dart
index 021ba97..49c9324 100644
--- a/pkg/compiler/lib/src/helpers/trace.dart
+++ b/pkg/compiler/lib/src/helpers/trace.dart
@@ -102,7 +102,6 @@
         rangeEnd: rangeEnd,
         filePrefix: stackTraceFilePrefix);
   }
-  return null;
 }
 
 /// A stack trace as a sequence of [StackTraceLine]s.
diff --git a/pkg/compiler/lib/src/inferrer/builder.dart b/pkg/compiler/lib/src/inferrer/builder.dart
index 526357dd..f50ab31 100644
--- a/pkg/compiler/lib/src/inferrer/builder.dart
+++ b/pkg/compiler/lib/src/inferrer/builder.dart
@@ -14,6 +14,7 @@
 import '../elements/resolution_types.dart'
     show ResolutionDartType, ResolutionInterfaceType;
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../js_backend/backend_helpers.dart';
 import '../js_backend/js_backend.dart' as js;
 import '../native/native.dart' as native;
@@ -1214,7 +1215,6 @@
         (element != null && element.isInstanceMember);
   }
 
-  @override
   TypeInformation handleSendSet(ast.SendSet node) {
     Element element = elements[node];
     if (!Elements.isUnresolved(element) && element.impliesType) {
@@ -2279,7 +2279,6 @@
     return inferrer.registerAwait(node, futureType);
   }
 
-  @override
   TypeInformation handleTypeLiteralInvoke(ast.NodeList arguments) {
     // This is reached when users forget to put a `new` in front of a type
     // literal. The emitter will generate an actual call (even though it is
@@ -2913,7 +2912,7 @@
     TypeMask moveNextMask = inTreeData.typeOfIteratorMoveNext(node);
 
     js.JavaScriptBackend backend = compiler.backend;
-    Element ctor = backend.helpers.streamIteratorConstructor;
+    ConstructorElement ctor = backend.helpers.streamIteratorConstructor;
 
     /// Synthesize a call to the [StreamIterator] constructor.
     TypeInformation iteratorType = handleStaticSend(
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index fc6d0bf..959bea7 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -9,6 +9,7 @@
 import '../constants/values.dart';
 import '../core_types.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../js_backend/js_backend.dart';
 import '../native/behavior.dart' as native;
 import '../resolution/tree_elements.dart';
diff --git a/pkg/compiler/lib/src/inferrer/locals_handler.dart b/pkg/compiler/lib/src/inferrer/locals_handler.dart
index 1f588e7..afdbea2 100644
--- a/pkg/compiler/lib/src/inferrer/locals_handler.dart
+++ b/pkg/compiler/lib/src/inferrer/locals_handler.dart
@@ -8,6 +8,7 @@
 
 import '../options.dart' show CompilerOptions;
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../tree/tree.dart';
 import '../util/util.dart';
 import 'inferrer_engine.dart';
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index 5261780..f07e46c 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -336,8 +336,7 @@
    */
   bool isParameterOfListAddingMethod(Element element) {
     if (!element.isRegularParameter) return false;
-    if (element.enclosingClass !=
-        compiler.backend.backendClasses.listImplementation) {
+    if (element.enclosingClass != compiler.backend.backendClasses.listClass) {
       return false;
     }
     Element method = element.enclosingElement;
@@ -353,8 +352,7 @@
    */
   bool isParameterOfMapAddingMethod(Element element) {
     if (!element.isRegularParameter) return false;
-    if (element.enclosingClass !=
-        compiler.backend.backendClasses.mapImplementation) {
+    if (element.enclosingClass != compiler.backend.backendClasses.mapClass) {
       return false;
     }
     Element method = element.enclosingElement;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 0155c28..5c75b9a 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -6,7 +6,6 @@
 
 import 'dart:collection' show Queue;
 
-import '../common.dart';
 import '../compiler.dart' show Compiler;
 import '../elements/elements.dart';
 import '../tree/tree.dart' as ast show Node;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 16c9260..45b7ed6 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -10,13 +10,14 @@
 import '../common/names.dart' show Identifiers;
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
+import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../elements/resolution_types.dart'
     show
         ResolutionDartType,
         ResolutionFunctionType,
         ResolutionInterfaceType,
         ResolutionTypeKind;
-import '../elements/elements.dart';
 import '../js_backend/backend.dart';
 import '../tree/dartstring.dart' show DartString;
 import '../tree/tree.dart' as ast show Node, LiteralBool, Send;
@@ -870,7 +871,8 @@
   TypeInformation handleIntrisifiedSelector(
       Selector selector, TypeMask mask, InferrerEngine inferrer) {
     ClosedWorld closedWorld = inferrer.closedWorld;
-    if (!closedWorld.backendClasses.intImplementation.isResolved) return null;
+    ClassElement intClass = closedWorld.backendClasses.intClass;
+    if (!intClass.isResolved) return null;
     if (mask == null) return null;
     if (!mask.containsOnlyInt(closedWorld)) {
       return null;
@@ -879,8 +881,7 @@
     if (!arguments.named.isEmpty) return null;
     if (arguments.positional.length > 1) return null;
 
-    ClassElement uint31Implementation =
-        closedWorld.backendClasses.uint31Implementation;
+    ClassElement uint31Implementation = closedWorld.backendClasses.uint31Class;
     bool isInt(info) => info.type.containsOnlyInt(closedWorld);
     bool isEmpty(info) => info.type.isEmpty;
     bool isUInt31(info) {
@@ -888,8 +889,8 @@
     }
 
     bool isPositiveInt(info) {
-      return info.type.satisfies(
-          closedWorld.backendClasses.positiveIntImplementation, closedWorld);
+      return info.type
+          .satisfies(closedWorld.backendClasses.positiveIntClass, closedWorld);
     }
 
     TypeInformation tryLater() => inferrer.types.nonNullEmptyType;
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index 9f51271..2d66363 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -4,6 +4,7 @@
 
 import '../common.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../elements/resolution_types.dart'
     show ResolutionDartType, ResolutionInterfaceType;
 import '../tree/dartstring.dart';
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 17e8397..b1d58e6 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -425,7 +425,7 @@
 
 /// Processor that associates [SourceLocation]s from [SourceInformation] on
 /// [js.Node]s with the target offsets in a [SourceMapper].
-class PositionSourceInformationProcessor implements SourceInformationProcessor {
+class PositionSourceInformationProcessor extends SourceInformationProcessor {
   final CodePositionRecorder codePositionRecorder = new CodePositionRecorder();
   CodePositionMap codePositionMap;
   List<TraceListener> traceListeners;
@@ -542,7 +542,9 @@
     switch (kind) {
       case StepKind.FUN_ENTRY:
         // TODO(johnniwinther): Remove this when fully transitioned to the
-        // new source info system.
+        // new source info system. Verify that tools no longer expect JS
+        // function signatures to map to the origin. The main method may still
+        // need mapping to enable breakpoints before calling main.
         registerPosition(SourcePositionKind.START);
         break;
       case StepKind.FUN_EXIT:
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index b246958..71a3aec 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -12,7 +12,7 @@
 import '../elements/elements.dart' show ResolvedAst, ResolvedAstKind;
 import '../js/js.dart' as js;
 import '../js/js_source_mapping.dart';
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../tree/tree.dart' show Node;
 import 'source_file.dart';
 import 'source_information.dart';
@@ -129,8 +129,27 @@
   /// registered for the top-most node with source information.
   bool hasRegisteredRoot = false;
 
+  /// The root of the tree. Used to add a [NoSourceLocationMarker] to the start
+  /// of the output.
+  js.Node root;
+
+  /// The root of the current subtree with source information. Used to add
+  /// [NoSourceLocationMarker] after areas with source information.
+  js.Node subRoot;
+
   StartEndSourceInformationProcessor(this.sourceMapper);
 
+  void onStartPosition(js.Node node, int startPosition) {
+    if (root == null) {
+      root = node;
+      sourceMapper.register(
+          node, startPosition, const NoSourceLocationMarker());
+    }
+    if (subRoot == null && node.sourceInformation != null) {
+      subRoot = node;
+    }
+  }
+
   @override
   void onPositions(
       js.Node node, int startPosition, int endPosition, int closingPosition) {
@@ -145,6 +164,11 @@
         sourceMapper.register(node, endPosition, null);
         hasRegisteredRoot = true;
       }
+      if (node == subRoot) {
+        sourceMapper.register(
+            node, endPosition, const NoSourceLocationMarker());
+        subRoot = null;
+      }
     }
   }
 }
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index bad0d12..cbb3bdb 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -75,7 +75,9 @@
   }
 
   @override
-  void enterNode(Node, int startPosition) {}
+  void enterNode(Node node, int startPosition) {
+    codePositionListener.onStartPosition(node, startPosition);
+  }
 
   @override
   void exitNode(
@@ -129,7 +131,6 @@
 /// This is used when generated code needs to be represented as a string,
 /// for example by the lazy emitter or when generating code generators.
 class UnparsedNode extends DeferredString implements AstContainer {
-  @override
   final Node tree;
   final Compiler _compiler;
   final bool _protectForEval;
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
index df49903..1127837 100644
--- a/pkg/compiler/lib/src/js/js_source_mapping.dart
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -25,8 +25,15 @@
 class CodePositionListener {
   const CodePositionListener();
 
+  /// Called to associate [node] with the provided start position.
+  ///
+  /// The nodes are seen in pre-traversal order.
+  void onStartPosition(Node node, int startPosition) {}
+
   /// Called to associate [node] with the provided start, end and closing
   /// positions.
+  ///
+  /// The nodes are seen in post-traversal order.
   void onPositions(
       Node node, int startPosition, int endPosition, int closingPosition) {}
 }
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index f5a2453..c881cb9 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -11,28 +11,25 @@
 import '../closure.dart';
 import '../common.dart';
 import '../common/backend_api.dart'
-    show
-        Backend,
-        BackendClasses,
-        ImpactTransformer,
-        ForeignResolver,
-        NativeRegistry;
+    show BackendClasses, ImpactTransformer, ForeignResolver, NativeRegistry;
 import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem;
 import '../common/names.dart' show Identifiers, Uris;
-import '../common/resolution.dart' show Frontend, Resolution, ResolutionImpact;
+import '../common/resolution.dart'
+    show Frontend, Resolution, ResolutionImpact, Target;
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../constants/constant_system.dart';
 import '../constants/expressions.dart';
 import '../constants/values.dart';
-import '../core_types.dart' show CommonElements;
-import '../elements/resolution_types.dart';
+import '../core_types.dart' show CommonElements, ElementEnvironment;
 import '../deferred_load.dart' show DeferredLoadTask;
 import '../dump_info.dart' show DumpInfoTask;
 import '../elements/elements.dart';
 import '../elements/entities.dart';
+import '../elements/resolution_types.dart';
+import '../elements/types.dart';
 import '../enqueue.dart'
-    show Enqueuer, ResolutionEnqueuer, TreeShakingEnqueuerStrategy;
+    show Enqueuer, EnqueueTask, ResolutionEnqueuer, TreeShakingEnqueuerStrategy;
 import '../io/position_information.dart' show PositionSourceInformationStrategy;
 import '../io/source_information.dart' show SourceInformationStrategy;
 import '../io/start_end_information.dart'
@@ -42,12 +39,14 @@
 import '../js/js_source_mapping.dart' show JavaScriptSourceInformationStrategy;
 import '../js/rewrite_async.dart';
 import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
+import '../kernel/task.dart';
 import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
 import '../native/native.dart' as native;
+import '../patch_parser.dart'
+    show checkNativeAnnotation, checkJsInteropAnnotation;
 import '../ssa/ssa.dart' show SsaFunctionCompiler;
 import '../tracer.dart';
 import '../tree/tree.dart';
-import '../types/types.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/feature.dart';
 import '../universe/selector.dart' show Selector;
@@ -73,8 +72,8 @@
 import 'constant_handler_javascript.dart';
 import 'custom_elements_analysis.dart';
 import 'enqueuer.dart';
+import 'interceptor_data.dart' show InterceptorData;
 import 'js_interop_analysis.dart' show JsInteropAnalysis;
-import '../kernel/task.dart';
 import 'lookup_map_analysis.dart' show LookupMapAnalysis;
 import 'mirrors_analysis.dart';
 import 'namer.dart';
@@ -113,8 +112,8 @@
   static const int _canInline = 4;
   static const int _mustInline = 5;
 
-  final Map<FunctionElement, int> _cachedDecisions =
-      new Map<FunctionElement, int>();
+  final Map<MethodElement, int> _cachedDecisions =
+      new Map<MethodElement, int>();
 
   /// Returns the current cache decision. This should only be used for testing.
   int getCurrentCacheDecisionForTesting(Element element) {
@@ -123,7 +122,7 @@
 
   // Returns `true`/`false` if we have a cached decision.
   // Returns `null` otherwise.
-  bool canInline(FunctionElement element, {bool insideLoop}) {
+  bool canInline(MethodElement element, {bool insideLoop}) {
     int decision = _cachedDecisions[element];
 
     if (decision == null) {
@@ -178,7 +177,7 @@
     return null;
   }
 
-  void markAsInlinable(FunctionElement element, {bool insideLoop}) {
+  void markAsInlinable(MethodElement element, {bool insideLoop}) {
     int oldDecision = _cachedDecisions[element];
 
     if (oldDecision == null) {
@@ -233,7 +232,7 @@
     }
   }
 
-  void markAsNonInlinable(FunctionElement element, {bool insideLoop: true}) {
+  void markAsNonInlinable(MethodElement element, {bool insideLoop: true}) {
     int oldDecision = _cachedDecisions[element];
 
     if (oldDecision == null) {
@@ -291,7 +290,7 @@
     }
   }
 
-  void markAsMustInline(FunctionElement element) {
+  void markAsMustInline(MethodElement element) {
     _cachedDecisions[element] = _mustInline;
   }
 }
@@ -303,9 +302,12 @@
   NAME
 }
 
-class JavaScriptBackend extends Backend {
+class JavaScriptBackend extends Target {
+  final Compiler compiler;
+
   String get patchVersion => emitter.patchVersion;
 
+  /// Returns true if the backend supports reflection.
   bool get supportsReflection => emitter.supportsReflection;
 
   final Annotations annotations;
@@ -352,56 +354,6 @@
   }
 
   /**
-   * A collection of selectors that must have a one shot interceptor
-   * generated.
-   */
-  final Map<jsAst.Name, Selector> oneShotInterceptors;
-
-  /**
-   * The members of instantiated interceptor classes: maps a member name to the
-   * list of members that have that name. This map is used by the codegen to
-   * know whether a send must be intercepted or not.
-   */
-  final Map<String, Set<Element>> interceptedElements;
-
-  /**
-   * The members of mixin classes that are mixed into an instantiated
-   * interceptor class.  This is a cached subset of [interceptedElements].
-   *
-   * Mixin methods are not specialized for the class they are mixed into.
-   * Methods mixed into intercepted classes thus always make use of the explicit
-   * receiver argument, even when mixed into non-interceptor classes.
-   *
-   * These members must be invoked with a correct explicit receiver even when
-   * the receiver is not an intercepted class.
-   */
-  final Map<String, Set<Element>> interceptedMixinElements =
-      new Map<String, Set<Element>>();
-
-  /**
-   * A map of specialized versions of the [getInterceptorMethod].
-   * Since [getInterceptorMethod] is a hot method at runtime, we're
-   * always specializing it based on the incoming type. The keys in
-   * the map are the names of these specialized versions. Note that
-   * the generic version that contains all possible type checks is
-   * also stored in this map.
-   */
-  final Map<jsAst.Name, Set<ClassElement>> specializedGetInterceptors;
-
-  /**
-   * Set of classes whose methods are intercepted.
-   */
-  final Set<ClassElement> _interceptedClasses = new Set<ClassElement>();
-
-  /**
-   * Set of classes used as mixins on intercepted (native and primitive)
-   * classes.  Methods on these classes might also be mixed in to regular Dart
-   * (unintercepted) classes.
-   */
-  final Set<ClassElement> classesMixedIntoInterceptedClasses =
-      new Set<ClassElement>();
-
-  /**
    * Set of classes whose `operator ==` methods handle `null` themselves.
    */
   final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>();
@@ -460,9 +412,6 @@
   /// `true` if access to [BackendHelpers.invokeOnMethod] is supported.
   bool hasInvokeOnSupport = false;
 
-  /// `true` if tear-offs are supported for incremental compilation.
-  bool hasIncrementalTearOffSupport = false;
-
   /// `true` of `Object.runtimeType` is supported.
   bool hasRuntimeTypeSupport = false;
 
@@ -532,17 +481,23 @@
   /// Builds kernel representation for the program.
   KernelTask kernelTask;
 
+  /// The compiler task responsible for the compilation of constants for both
+  /// the frontend and the backend.
   JavaScriptConstantTask constantCompilerTask;
 
+  /// Backend transformation methods for the world impacts.
   JavaScriptImpactTransformer impactTransformer;
 
   PatchResolverTask patchResolverTask;
 
+  /// Whether or not `noSuchMethod` support has been enabled.
   bool enabledNoSuchMethod = false;
   bool _noSuchMethodEnabledForCodegen = false;
 
+  /// The strategy used for collecting and emitting source information.
   SourceInformationStrategy sourceInformationStrategy;
 
+  /// Interface for serialization of backend specific data.
   JavaScriptBackendSerialization serialization;
 
   StagedWorldImpactBuilder constantImpactsForResolution =
@@ -552,11 +507,15 @@
       new StagedWorldImpactBuilder();
 
   final NativeData nativeData = new NativeData();
+  InterceptorData _interceptorData;
 
-  final BackendHelpers helpers;
+  BackendHelpers helpers;
   final BackendImpacts impacts;
+
+  /// Common classes used by the backend.
   BackendClasses backendClasses;
 
+  /// Backend access to the front-end.
   final JSFrontendAccess frontend;
 
   Tracer tracer;
@@ -566,21 +525,18 @@
       bool useStartupEmitter: false,
       bool useNewSourceInfo: false,
       bool useKernel: false})
-      : oneShotInterceptors = new Map<jsAst.Name, Selector>(),
-        interceptedElements = new Map<String, Set<Element>>(),
-        rti = new _RuntimeTypes(compiler),
+      : rti = new _RuntimeTypes(compiler),
         rtiEncoder = new _RuntimeTypesEncoder(compiler),
-        specializedGetInterceptors = new Map<jsAst.Name, Set<ClassElement>>(),
         annotations = new Annotations(compiler),
         this.sourceInformationStrategy = generateSourceMap
             ? (useNewSourceInfo
                 ? new PositionSourceInformationStrategy()
                 : const StartEndSourceInformationStrategy())
             : const JavaScriptSourceInformationStrategy(),
-        helpers = new BackendHelpers(compiler),
         impacts = new BackendImpacts(compiler),
         frontend = new JSFrontendAccess(compiler),
-        super(compiler) {
+        this.compiler = compiler {
+    helpers = new BackendHelpers(compiler.elementEnvironment, commonElements);
     emitter =
         new CodeEmitterTask(compiler, generateSourceMap, useStartupEmitter);
     typeVariableHandler = new TypeVariableHandler(compiler);
@@ -597,9 +553,13 @@
     functionCompiler =
         new SsaFunctionCompiler(this, sourceInformationStrategy, useKernel);
     serialization = new JavaScriptBackendSerialization(this);
-    backendClasses = new JavaScriptBackendClasses(helpers);
+    _interceptorData = new InterceptorData(nativeData, helpers, commonElements);
+    backendClasses = new JavaScriptBackendClasses(
+        compiler.elementEnvironment, helpers, nativeData, _interceptorData);
   }
 
+  /// The [ConstantSystem] used to interpret compile-time constants for this
+  /// backend.
   ConstantSystem get constantSystem => constants.constantSystem;
 
   DiagnosticReporter get reporter => compiler.reporter;
@@ -608,6 +568,8 @@
 
   Resolution get resolution => compiler.resolution;
 
+  InterceptorData get interceptorData => _interceptorData;
+
   /// Returns constant environment for the JavaScript interpretation of the
   /// constants.
   JavaScriptConstantCompiler get constants {
@@ -674,11 +636,14 @@
 
   bool _isValidBackendUse(Element element) {
     assert(invariant(element, element.isDeclaration, message: ""));
-    if (element == helpers.streamIteratorConstructor ||
-        compiler.commonElements.isSymbolConstructor(element) ||
-        helpers.isSymbolValidatedConstructor(element) ||
-        element == helpers.syncCompleterConstructor ||
-        element == commonElements.symbolClass ||
+    if (element is ConstructorElement &&
+        (element == helpers.streamIteratorConstructor ||
+            compiler.commonElements.isSymbolConstructor(element) ||
+            helpers.isSymbolValidatedConstructor(element) ||
+            element == helpers.syncCompleterConstructor)) {
+      // TODO(johnniwinther): These are valid but we could be more precise.
+      return true;
+    } else if (element == commonElements.symbolClass ||
         element == helpers.objectNoSuchMethod) {
       // TODO(johnniwinther): These are valid but we could be more precise.
       return true;
@@ -732,28 +697,14 @@
     return isAccessibleByReflection(element.declaration);
   }
 
+  /// Returns true if global optimizations such as type inferencing
+  /// can apply to this element. One category of elements that do not
+  /// apply is runtime helpers that the backend calls, but the
+  /// optimizations don't see those calls.
   bool canBeUsedForGlobalOptimizations(Element element) {
     return !usedByBackend(element) && !invokedReflectively(element);
   }
 
-  bool isInterceptorClass(ClassElement element) {
-    if (element == null) return false;
-    if (isNativeOrExtendsNative(element)) return true;
-    if (interceptedClasses.contains(element)) return true;
-    if (classesMixedIntoInterceptedClasses.contains(element)) return true;
-    return false;
-  }
-
-  jsAst.Name registerOneShotInterceptor(Selector selector) {
-    Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
-    jsAst.Name name = namer.nameForGetOneShotInterceptor(selector, classes);
-    if (!oneShotInterceptors.containsKey(name)) {
-      registerSpecializedGetInterceptor(classes);
-      oneShotInterceptors[name] = selector;
-    }
-    return name;
-  }
-
   /**
    * Record that [method] is called from a subclass via `super`.
    */
@@ -762,9 +713,6 @@
     if (!canUseAliasedSuperMember(member, selector)) {
       // Invoking a super getter isn't supported, this would require changes to
       // compact field descriptors in the emitter.
-      // We also turn off this optimization in incremental compilation, to
-      // avoid having to regenerate a method just because someone started
-      // calling it through super.
       return false;
     }
     aliasedSuperMembers.add(member);
@@ -772,7 +720,7 @@
   }
 
   bool canUseAliasedSuperMember(Element member, Selector selector) {
-    return !selector.isGetter && !compiler.options.hasIncrementalSupport;
+    return !selector.isGetter;
   }
 
   /**
@@ -782,7 +730,7 @@
     return aliasedSuperMembers.contains(member);
   }
 
-  /// Returns `true` if [element] is part of JsInterop.
+  /// Returns `true` if [element] is implemented via typed JavaScript interop.
   @override
   bool isJsInterop(Element element) => nativeData.isJsInterop(element);
 
@@ -834,8 +782,8 @@
       if (isNative(element)) {
         native.NativeBehavior fieldLoadBehavior =
             native.NativeBehavior.ofFieldElementLoad(element, compiler);
-        native.NativeBehavior fieldStoreBehavior = native.NativeBehavior
-            .ofFieldElementStore(element, compiler.resolution);
+        native.NativeBehavior fieldStoreBehavior =
+            native.NativeBehavior.ofFieldElementStore(element, compiler);
         nativeData.setNativeFieldLoadBehavior(element, fieldLoadBehavior);
         nativeData.setNativeFieldStoreBehavior(element, fieldStoreBehavior);
 
@@ -849,77 +797,6 @@
     }
   }
 
-  bool isNativeOrExtendsNative(ClassElement element) {
-    if (element == null) return false;
-    if (isNative(element) || isJsInterop(element)) {
-      return true;
-    }
-    assert(element.isResolved);
-    return isNativeOrExtendsNative(element.superclass);
-  }
-
-  bool isInterceptedMethod(MemberElement element) {
-    if (!element.isInstanceMember) return false;
-    if (element.isGenerativeConstructorBody) {
-      return isNativeOrExtendsNative(element.enclosingClass);
-    }
-    return interceptedElements[element.name] != null;
-  }
-
-  bool fieldHasInterceptedGetter(Element element) {
-    assert(element.isField);
-    return interceptedElements[element.name] != null;
-  }
-
-  bool fieldHasInterceptedSetter(Element element) {
-    assert(element.isField);
-    return interceptedElements[element.name] != null;
-  }
-
-  bool isInterceptedName(String name) {
-    return interceptedElements[name] != null;
-  }
-
-  bool isInterceptedSelector(Selector selector) {
-    return interceptedElements[selector.name] != null;
-  }
-
-  /**
-   * Returns `true` iff [selector] matches an element defined in a class mixed
-   * into an intercepted class.  These selectors are not eligible for the 'dummy
-   * explicit receiver' optimization.
-   */
-  bool isInterceptedMixinSelector(Selector selector, TypeMask mask) {
-    Set<Element> elements =
-        interceptedMixinElements.putIfAbsent(selector.name, () {
-      Set<Element> elements = interceptedElements[selector.name];
-      if (elements == null) return null;
-      return elements
-          .where((element) => classesMixedIntoInterceptedClasses
-              .contains(element.enclosingClass))
-          .toSet();
-    });
-
-    if (elements == null) return false;
-    if (elements.isEmpty) return false;
-    return elements.any((element) {
-      return selector.applies(element) &&
-          (mask == null || mask.canHit(element, selector, _closedWorld));
-    });
-  }
-
-  /// True if the given class is an internal class used for type inference
-  /// and never exists at runtime.
-  bool isCompileTimeOnlyClass(ClassElement class_) {
-    return class_ == helpers.jsPositiveIntClass ||
-        class_ == helpers.jsUInt32Class ||
-        class_ == helpers.jsUInt31Class ||
-        class_ == helpers.jsFixedArrayClass ||
-        class_ == helpers.jsUnmodifiableArrayClass ||
-        class_ == helpers.jsMutableArrayClass ||
-        class_ == helpers.jsExtendableArrayClass;
-  }
-
   /// Maps compile-time classes to their runtime class.  The runtime class is
   /// always a superclass or the class itself.
   ClassElement getRuntimeClass(ClassElement class_) {
@@ -928,51 +805,6 @@
     return class_;
   }
 
-  final Map<String, Set<ClassElement>> interceptedClassesCache =
-      new Map<String, Set<ClassElement>>();
-  final Set<ClassElement> _noClasses = new Set<ClassElement>();
-
-  /// Returns a set of interceptor classes that contain a member named [name]
-  ///
-  /// Returns an empty set if there is no class. Do not modify the returned set.
-  Set<ClassElement> getInterceptedClassesOn(String name) {
-    Set<Element> intercepted = interceptedElements[name];
-    if (intercepted == null) return _noClasses;
-    return interceptedClassesCache.putIfAbsent(name, () {
-      // Populate the cache by running through all the elements and
-      // determine if the given selector applies to them.
-      Set<ClassElement> result = new Set<ClassElement>();
-      for (Element element in intercepted) {
-        ClassElement classElement = element.enclosingClass;
-        if (isCompileTimeOnlyClass(classElement)) continue;
-        if (isNativeOrExtendsNative(classElement) ||
-            interceptedClasses.contains(classElement)) {
-          result.add(classElement);
-        }
-        if (classesMixedIntoInterceptedClasses.contains(classElement)) {
-          Set<ClassElement> nativeSubclasses =
-              nativeSubclassesOfMixin(classElement);
-          if (nativeSubclasses != null) result.addAll(nativeSubclasses);
-        }
-      }
-      return result;
-    });
-  }
-
-  Set<ClassElement> nativeSubclassesOfMixin(ClassElement mixin) {
-    Iterable<MixinApplicationElement> uses = _closedWorld.mixinUsesOf(mixin);
-    Set<ClassElement> result = null;
-    for (MixinApplicationElement use in uses) {
-      _closedWorld.forEachStrictSubclassOf(use, (ClassElement subclass) {
-        if (isNativeOrExtendsNative(subclass)) {
-          if (result == null) result = new Set<ClassElement>();
-          result.add(subclass);
-        }
-      });
-    }
-    return result;
-  }
-
   bool operatorEqHandlesNullArgument(FunctionElement operatorEqfunction) {
     return specialOperatorEqClasses.contains(operatorEqfunction.enclosingClass);
   }
@@ -1000,62 +832,20 @@
       {bool forResolution}) {
     if (forResolution) {
       cls.ensureResolved(resolution);
-      cls.forEachMember((ClassElement classElement, Element member) {
-        if (member.name == Identifiers.call) {
-          return;
-        }
-        if (member.isSynthesized) return;
-        // All methods on [Object] are shadowed by [Interceptor].
-        if (classElement == commonElements.objectClass) return;
-        Set<Element> set = interceptedElements.putIfAbsent(
-            member.name, () => new Set<Element>());
-        set.add(member);
-      }, includeSuperAndInjectedMembers: true);
-
-      // Walk superclass chain to find mixins.
-      for (; cls != null; cls = cls.superclass) {
-        if (cls.isMixinApplication) {
-          MixinApplicationElement mixinApplication = cls;
-          classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
-        }
-      }
+      interceptorData.addInterceptorsForNativeClassMembers(cls);
     }
   }
 
   void addInterceptors(ClassElement cls, WorldImpactBuilder impactBuilder,
       {bool forResolution}) {
     if (forResolution) {
-      if (_interceptedClasses.add(cls)) {
-        cls.ensureResolved(resolution);
-        cls.forEachMember((ClassElement classElement, Element member) {
-          // All methods on [Object] are shadowed by [Interceptor].
-          if (classElement == commonElements.objectClass) return;
-          Set<Element> set = interceptedElements.putIfAbsent(
-              member.name, () => new Set<Element>());
-          set.add(member);
-        }, includeSuperAndInjectedMembers: true);
-      }
-      _interceptedClasses.add(helpers.jsInterceptorClass);
+      cls.ensureResolved(resolution);
+      interceptorData.addInterceptors(cls);
     }
     impactTransformer.registerBackendInstantiation(impactBuilder, cls);
   }
 
-  Set<ClassElement> get interceptedClasses {
-    assert(compiler.enqueuer.resolution.queueIsClosed);
-    return _interceptedClasses;
-  }
-
-  void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
-    jsAst.Name name = namer.nameForGetInterceptor(classes);
-    if (classes.contains(helpers.jsInterceptorClass)) {
-      // We can't use a specialized [getInterceptorMethod], so we make
-      // sure we emit the one with all checks.
-      specializedGetInterceptors[name] = interceptedClasses;
-    } else {
-      specializedGetInterceptors[name] = classes;
-    }
-  }
-
+  /// Called during codegen when [constant] has been used.
   void computeImpactForCompileTimeConstant(ConstantValue constant,
       WorldImpactBuilder impactBuilder, bool isForResolution) {
     computeImpactForCompileTimeConstantInternal(
@@ -1093,20 +883,21 @@
       computeImpactForInstantiatedConstantType(cls.thisType, impactBuilder);
     } else if (constant.isType) {
       if (isForResolution) {
+        MethodElement helper = helpers.createRuntimeType;
         impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
             // TODO(johnniwinther): Find the right [CallStructure].
-            helpers.createRuntimeType,
+            helper,
             null));
-        registerBackendUse(helpers.createRuntimeType);
+        registerBackendUse(helper);
       }
-      impactBuilder.registerTypeUse(
-          new TypeUse.instantiation(backendClasses.typeImplementation.rawType));
+      impactBuilder
+          .registerTypeUse(new TypeUse.instantiation(backendClasses.typeType));
     }
     lookupMapAnalysis.registerConstantKey(constant);
   }
 
   void computeImpactForInstantiatedConstantType(
-      ResolutionDartType type, WorldImpactBuilder impactBuilder) {
+      DartType type, WorldImpactBuilder impactBuilder) {
     if (type is ResolutionInterfaceType) {
       impactBuilder.registerTypeUse(new TypeUse.instantiation(type));
       if (classNeedsRtiField(type.element)) {
@@ -1115,7 +906,7 @@
             helpers.setRuntimeTypeInfo,
             null));
       }
-      if (type.element == backendClasses.typeImplementation) {
+      if (type.element == backendClasses.typeClass) {
         // If we use a type literal in a constant, the compile time
         // constant emitter will generate a call to the createRuntimeType
         // helper so we register a use of that.
@@ -1127,11 +918,16 @@
     }
   }
 
+  /// Called to notify to the backend that a class is being instantiated. Any
+  /// backend specific [WorldImpact] of this is returned.
   WorldImpact registerInstantiatedClass(ClassElement cls,
       {bool forResolution}) {
     return _processClass(cls, forResolution: forResolution);
   }
 
+  /// Called to notify to the backend that a class is implemented by an
+  /// instantiated class. Any backend specific [WorldImpact] of this is
+  /// returned.
   WorldImpact registerImplementedClass(ClassElement cls, {bool forResolution}) {
     return _processClass(cls, forResolution: forResolution);
   }
@@ -1166,7 +962,7 @@
       } else if (cls == helpers.boundClosureClass) {
         impactTransformer.registerBackendImpact(
             impactBuilder, impacts.boundClosureClass);
-      } else if (isNativeOrExtendsNative(cls)) {
+      } else if (nativeData.isNativeOrExtendsNative(cls)) {
         impactTransformer.registerBackendImpact(
             impactBuilder, impacts.nativeOrExtendsClass);
       } else if (cls == helpers.mapLiteralClass) {
@@ -1248,7 +1044,7 @@
     } else if (cls == helpers.jsJavaScriptFunctionClass) {
       addInterceptors(helpers.jsJavaScriptFunctionClass, impactBuilder,
           forResolution: forResolution);
-    } else if (isNativeOrExtendsNative(cls)) {
+    } else if (nativeData.isNativeOrExtendsNative(cls)) {
       addInterceptorsForNativeClassMembers(cls, forResolution: forResolution);
     } else if (cls == helpers.jsIndexingBehaviorInterface) {
       impactTransformer.registerBackendImpact(
@@ -1264,11 +1060,13 @@
     return impactBuilder;
   }
 
+  /// Called to instruct to the backend register [type] as instantiated on
+  /// [enqueuer].
   void registerInstantiatedType(ResolutionInterfaceType type) {
     lookupMapAnalysis.registerInstantiatedType(type);
   }
 
-  @override
+  /// Compute the [WorldImpact] for backend helper methods.
   WorldImpact computeHelpersImpact() {
     assert(helpers.interceptorsLibrary != null);
     WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
@@ -1292,7 +1090,7 @@
     return impactBuilder;
   }
 
-  onResolutionComplete(
+  void onResolutionComplete(
       ClosedWorld closedWorld, ClosedWorldRefiner closedWorldRefiner) {
     for (Entity entity in compiler.enqueuer.resolution.processedEntities) {
       processAnnotations(entity, closedWorldRefiner);
@@ -1301,10 +1099,10 @@
     rti.computeClassesNeedingRti(
         compiler.enqueuer.resolution.worldBuilder, closedWorld);
     _registeredMetadata.clear();
+    interceptorData.onResolutionComplete(closedWorld);
   }
 
-  onTypeInferenceComplete() {
-    super.onTypeInferenceComplete();
+  void onTypeInferenceComplete() {
     noSuchMethodRegistry.onTypeInferenceComplete();
   }
 
@@ -1321,6 +1119,9 @@
     return const WorldImpact();
   }
 
+  /// Called to instruct the backend to register that a closure exists for a
+  /// function on an instantiated generic class. Any backend specific
+  /// [WorldImpact] of this is returned.
   WorldImpact registerClosureWithFreeTypeVariables(Element closure,
       {bool forResolution}) {
     if (forResolution || methodNeedsRti(closure)) {
@@ -1329,10 +1130,14 @@
     return const WorldImpact();
   }
 
+  /// Called to register that a member has been closurized. Any backend specific
+  /// [WorldImpact] of this is returned.
   WorldImpact registerBoundClosure() {
     return impactTransformer.createImpactFor(impacts.memberClosure);
   }
 
+  /// Called to register that a static function has been closurized. Any backend
+  /// specific [WorldImpact] of this is returned.
   WorldImpact registerGetOfStaticFunction() {
     return impactTransformer.createImpactFor(impacts.staticClosure);
   }
@@ -1347,11 +1152,14 @@
     return impactTransformer.createImpactFor(impacts.runtimeTypeSupport);
   }
 
+  /// Register a runtime type variable bound tests between [typeArgument] and
+  /// [bound].
   void registerTypeVariableBoundsSubtypeCheck(
       ResolutionDartType typeArgument, ResolutionDartType bound) {
     rti.registerTypeVariableBoundsSubtypeCheck(typeArgument, bound);
   }
 
+  /// Returns the [WorldImpact] of enabling deferred loading.
   WorldImpact computeDeferredLoadingImpact() {
     return impactTransformer.createImpactFor(impacts.deferredLoading);
   }
@@ -1399,6 +1207,8 @@
     return impactTransformer.createImpactFor(impacts.noSuchMethodSupport);
   }
 
+  /// Called to enable support for isolates. Any backend specific [WorldImpact]
+  /// of this is returned.
   WorldImpact enableIsolateSupport({bool forResolution}) {
     WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
     // TODO(floitsch): We should also ensure that the class IsolateMessage is
@@ -1443,9 +1253,10 @@
 
   CodegenEnqueuer get codegenEnqueuer => compiler.enqueuer.codegen;
 
+  /// Creates an [Enqueuer] for code generation specific to this backend.
   CodegenEnqueuer createCodegenEnqueuer(CompilerTask task, Compiler compiler) {
-    return new CodegenEnqueuer(task, compiler.cacheStrategy, this,
-        compiler.options, const TreeShakingEnqueuerStrategy());
+    return new CodegenEnqueuer(
+        task, this, compiler.options, const TreeShakingEnqueuerStrategy());
   }
 
   WorldImpact codegen(CodegenWorkItem work) {
@@ -1547,6 +1358,7 @@
     return jsAst.prettyPrint(generatedCode[element], compiler);
   }
 
+  /// Generates the output and returns the total size of the generated code.
   int assembleProgram(ClosedWorld closedWorld) {
     int programSize = emitter.assembleProgram(namer, closedWorld);
     noSuchMethodRegistry.emitDiagnostic();
@@ -1764,10 +1576,12 @@
 
     if (!type.isRaw) return false;
     ClassElement classElement = type.element;
-    if (isInterceptorClass(classElement)) return false;
+    if (interceptorData.isInterceptorClass(classElement)) return false;
     return _closedWorld.hasOnlySubclasses(classElement);
   }
 
+  /// Called to register that [element] is statically known to be used. Any
+  /// backend specific [WorldImpact] of this is returned.
   WorldImpact registerUsedElement(MemberElement element, {bool forResolution}) {
     WorldImpactBuilderImpl worldImpact = new WorldImpactBuilderImpl();
     if (element == helpers.disableTreeShakingMarker) {
@@ -1891,36 +1705,53 @@
     return false;
   }
 
-  void onLibraryCreated(LibraryElement library) {
-    helpers.onLibraryCreated(library);
-  }
-
+  /// This method is called immediately after the [library] and its parts have
+  /// been scanned.
   Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
-    return super.onLibraryScanned(library, loader).then((_) {
-      if (library.isPlatformLibrary &&
-          // Don't patch library currently disallowed.
-          !library.isSynthesized &&
-          !library.isPatched &&
-          // Don't patch deserialized libraries.
-          !compiler.serialization.isDeserialized(library)) {
-        // Apply patch, if any.
-        Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
-        if (patchUri != null) {
-          return compiler.patchParser.patchLibrary(loader, patchUri, library);
+    if (!compiler.serialization.isDeserialized(library)) {
+      if (canLibraryUseNative(library)) {
+        library.forEachLocalMember((Element element) {
+          if (element.isClass) {
+            checkNativeAnnotation(compiler, element);
+          }
+        });
+      }
+      checkJsInteropAnnotation(compiler, library);
+      library.forEachLocalMember((Element element) {
+        checkJsInteropAnnotation(compiler, element);
+        if (element.isClass && isJsInterop(element)) {
+          ClassElement classElement = element;
+          classElement.forEachMember((_, memberElement) {
+            checkJsInteropAnnotation(compiler, memberElement);
+          });
         }
+      });
+    }
+    if (library.isPlatformLibrary &&
+        // Don't patch library currently disallowed.
+        !library.isSynthesized &&
+        !library.isPatched &&
+        // Don't patch deserialized libraries.
+        !compiler.serialization.isDeserialized(library)) {
+      // Apply patch, if any.
+      Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
+      if (patchUri != null) {
+        return compiler.patchParser.patchLibrary(loader, patchUri, library);
       }
-    }).then((_) {
-      helpers.onLibraryScanned(library);
-      Uri uri = library.canonicalUri;
-      if (uri == Uris.dart_html) {
-        htmlLibraryIsLoaded = true;
-      } else if (uri == LookupMapAnalysis.PACKAGE_LOOKUP_MAP) {
-        lookupMapAnalysis.init(library);
-      }
-      annotations.onLibraryScanned(library);
-    });
+    }
+    Uri uri = library.canonicalUri;
+    if (uri == Uris.dart_html) {
+      htmlLibraryIsLoaded = true;
+    } else if (uri == LookupMapAnalysis.PACKAGE_LOOKUP_MAP) {
+      lookupMapAnalysis.init(library);
+    }
+    annotations.onLibraryScanned(library);
+    return new Future.value();
   }
 
+  /// This method is called when all new libraries loaded through
+  /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
+  /// have been computed.
   Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
     if (!loadedLibraries.containsLibrary(Uris.dart_core)) {
       return new Future.value();
@@ -1953,6 +1784,9 @@
     return new Future.value();
   }
 
+  /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
+  /// annotations. The arguments corresponds to the unions of the corresponding
+  /// fields of the annotations.
   void registerMirrorUsage(
       Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) {
     if (symbols == null && targets == null && metaTargets == null) {
@@ -1992,26 +1826,27 @@
     return membersNeededForReflection.contains(element);
   }
 
+  /// Returns `true` if this member element needs reflection information at
+  /// runtime.
   bool isMemberAccessibleByReflection(MemberElement element) {
     return membersNeededForReflection.contains(element);
   }
 
-  /**
-   * Returns true if the element has to be resolved due to a mirrorsUsed
-   * annotation. If we have insufficient mirrors used annotations, we only
-   * keep additional elements if treeshaking has been disabled.
-   */
+  /// Returns true if this element has to be enqueued due to
+  /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if
+  /// normal tree shaking is still active ([isTreeShakingDisabled] is false).
   bool requiredByMirrorSystem(Element element) {
     return hasInsufficientMirrorsUsed && isTreeShakingDisabled ||
         matchesMirrorsMetaTarget(element) ||
         targetsUsed.contains(element);
   }
 
-  /**
-   * Returns true if the element matches a mirrorsUsed annotation. If
-   * we have insufficient mirrorsUsed information, this returns true for
-   * all elements, as they might all be potentially referenced.
-   */
+  /// Returns true if this element is covered by a mirrorsUsed annotation.
+  ///
+  /// Note that it might still be ok to tree shake the element away if no
+  /// reflection is used in the program (and thus [isTreeShakingDisabled] is
+  /// still false). Therefore _do not_ use this predicate to decide inclusion
+  /// in the tree, use [requiredByMirrorSystem] instead.
   bool referencedFromMirrorSystem(Element element, [recursive = true]) {
     Element enclosing = recursive ? element.enclosingElement : null;
 
@@ -2138,7 +1973,8 @@
         List<LocalFunctionElement> closures = closureMap[cls];
         if (closures != null) {
           for (LocalFunctionElement closure in closures) {
-            if (referencedFromMirrorSystem(closure.memberContext, false)) {
+            MemberElement member = closure.memberContext;
+            if (referencedFromMirrorSystem(member, false)) {
               reflectableMembers.add(closure);
               foundClosure = true;
             }
@@ -2172,12 +2008,14 @@
     // As we do not think about closures as classes, yet, we have to make sure
     // their superclasses are available for reflection manually.
     if (foundClosure) {
-      reflectableMembers.add(helpers.closureClass);
+      ClassElement cls = helpers.closureClass;
+      reflectableMembers.add(cls);
     }
     Set<Element> closurizedMembers =
         compiler.resolutionWorldBuilder.closurizedMembers;
     if (closurizedMembers.any(reflectableMembers.contains)) {
-      reflectableMembers.add(helpers.boundClosureClass);
+      ClassElement cls = helpers.boundClosureClass;
+      reflectableMembers.add(cls);
     }
     // Add typedefs.
     reflectableMembers
@@ -2245,7 +2083,22 @@
     return staticFields;
   }
 
-  /// Called when [enqueuer] is empty, but before it is closed.
+  /// Called when [enqueuer]'s queue is empty, but before it is closed.
+  ///
+  /// This is used, for example, by the JS backend to enqueue additional
+  /// elements needed for reflection. [recentClasses] is a collection of
+  /// all classes seen for the first time by the [enqueuer] since the last call
+  /// to [onQueueEmpty].
+  ///
+  /// A return value of [:true:] indicates that [recentClasses] has been
+  /// processed and its elements do not need to be seen in the next round. When
+  /// [:false:] is returned, [onQueueEmpty] will be called again once the
+  /// resolution queue has drained and [recentClasses] will be a superset of the
+  /// current value.
+  ///
+  /// There is no guarantee that a class is only present once in
+  /// [recentClasses], but every class seen by the [enqueuer] will be present in
+  /// [recentClasses] at least once.
   bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) {
     // Add elements used synthetically, that is, through features rather than
     // syntax, for instance custom elements.
@@ -2288,17 +2141,6 @@
       kernelTask.buildKernelIr();
     }
 
-    if (compiler.options.hasIncrementalSupport &&
-        !hasIncrementalTearOffSupport) {
-      // Always enable tear-off closures during incremental compilation.
-      Element element = helpers.closureFromTearOff;
-      if (element != null) {
-        enqueuer.applyImpact(
-            impactTransformer.createImpactFor(impacts.closureClass));
-      }
-      hasIncrementalTearOffSupport = true;
-    }
-
     if (!enqueuer.isResolutionQueue && preMirrorsMethodCount == 0) {
       preMirrorsMethodCount = generatedCode.length;
     }
@@ -2397,6 +2239,8 @@
     entities.forEach(processElementMetadata);
   }
 
+  /// Called after the queue is closed. [onQueueEmpty] may be called multiple
+  /// times, but [onQueueClosed] is only called once.
   void onQueueClosed() {
     lookupMapAnalysis.onQueueClosed();
     jsInteropAnalysis.onQueueClosed();
@@ -2415,6 +2259,8 @@
     _closedWorldCache = value;
   }
 
+  /// Called when the compiler starts running the codegen enqueuer. The
+  /// [WorldImpact] of enabled backend features is returned.
   WorldImpact onCodegenStart(ClosedWorld closedWorld) {
     _closedWorld = closedWorld;
     _namer = determineNamer(_closedWorld, compiler.codegenWorldBuilder);
@@ -2427,11 +2273,30 @@
     return const WorldImpact();
   }
 
+  /// Called when code generation has been completed.
   void onCodegenEnd() {
     sourceInformationStrategy.onComplete();
     tracer.close();
   }
 
+  // Does this element belong in the output
+  bool shouldOutput(Element element) => true;
+
+  /// Returns `true` if the `native` pseudo keyword is supported for [library].
+  bool canLibraryUseNative(LibraryElement library) {
+    return native.maybeEnableNative(compiler, library);
+  }
+
+  @override
+  bool isTargetSpecificLibrary(LibraryElement library) {
+    Uri canonicalUri = library.canonicalUri;
+    if (canonicalUri == BackendHelpers.DART_JS_HELPER ||
+        canonicalUri == BackendHelpers.DART_INTERCEPTORS) {
+      return true;
+    }
+    return false;
+  }
+
   /// Process backend specific annotations.
   void processAnnotations(
       Element element, ClosedWorldRefiner closedWorldRefiner) {
@@ -2512,25 +2377,13 @@
     }
   }
 
-  FunctionElement helperForBadMain() => helpers.badMain;
+  MethodElement helperForBadMain() => helpers.badMain;
 
-  FunctionElement helperForMissingMain() => helpers.missingMain;
+  MethodElement helperForMissingMain() => helpers.missingMain;
 
-  FunctionElement helperForMainArity() => helpers.mainHasTooManyParameters;
+  MethodElement helperForMainArity() => helpers.mainHasTooManyParameters;
 
-  void forgetElement(Element element) {
-    constants.forgetElement(element);
-    constantCompilerTask.dartConstantCompiler.forgetElement(element);
-    aliasedSuperMembers.remove(element);
-    generatedCode.remove(element);
-    if (element is MemberElement) {
-      for (Element closure in element.nestedClosures) {
-        generatedCode.remove(closure);
-      }
-    }
-  }
-
-  @override
+  /// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
   WorldImpact computeMainImpact(MethodElement mainMethod,
       {bool forResolution}) {
     WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
@@ -2564,10 +2417,12 @@
     return "${outName}_$name$extension";
   }
 
-  @override
+  /// Enable deferred loading. Returns `true` if the backend supports deferred
+  /// loading.
   bool enableDeferredLoadingIfSupported(Spannable node) => true;
 
-  @override
+  /// Enable compilation of code with compile time errors. Returns `true` if
+  /// supported by the backend.
   bool enableCodegenWithErrorsIfSupported(Spannable node) => true;
 
   jsAst.Expression rewriteAsync(
@@ -2634,14 +2489,17 @@
     "_internal": "_internal/js_runtime/lib/internal_patch.dart"
   };
 
-  @override
+  /// Returns the location of the patch-file associated with [libraryName]
+  /// resolved from [plaformConfigUri].
+  ///
+  /// Returns null if there is none.
   Uri resolvePatchUri(String libraryName, Uri platformConfigUri) {
     String patchLocation = _patchLocations[libraryName];
     if (patchLocation == null) return null;
     return platformConfigUri.resolve(patchLocation);
   }
 
-  @override
+  /// Creates an impact strategy to use for compilation.
   ImpactStrategy createImpactStrategy(
       {bool supportDeferredLoad: true,
       bool supportDumpInfo: true,
@@ -2651,6 +2509,8 @@
         supportDumpInfo: supportDumpInfo,
         supportSerialization: supportSerialization);
   }
+
+  EnqueueTask makeEnqueuer() => new EnqueueTask(compiler);
 }
 
 class JSFrontendAccess implements Frontend {
@@ -2891,7 +2751,8 @@
         transformed
             .registerTypeUse(new TypeUse.instantiation(mapLiteralUse.type));
       }
-      registerRequiredType(mapLiteralUse.type);
+      ResolutionInterfaceType type = mapLiteralUse.type;
+      registerRequiredType(type);
     }
 
     for (ListLiteralUse listLiteralUse in worldImpact.listLiterals) {
@@ -2899,7 +2760,8 @@
       // factory constructors are registered directly.
       transformed
           .registerTypeUse(new TypeUse.instantiation(listLiteralUse.type));
-      registerRequiredType(listLiteralUse.type);
+      ResolutionInterfaceType type = listLiteralUse.type;
+      registerRequiredType(type);
     }
 
     if (worldImpact.constSymbolNames.isNotEmpty) {
@@ -3028,6 +2890,7 @@
 
   /// Register [type] as required for the runtime type information system.
   void registerRequiredType(ResolutionDartType type) {
+    if (!type.isInterfaceType) return;
     // If [argument] has type variables or is a type variable, this method
     // registers a RTI dependency between the class where the type variable is
     // defined (that is the enclosing class of the current element being
@@ -3162,7 +3025,8 @@
     }
 
     for (Set<ClassElement> classes in impact.specializedGetInterceptors) {
-      backend.registerSpecializedGetInterceptor(classes);
+      backend.interceptorData
+          .registerSpecializedGetInterceptor(classes, backend.namer);
     }
 
     if (impact.usesInterceptor) {
@@ -3252,38 +3116,41 @@
 }
 
 class JavaScriptBackendClasses implements BackendClasses {
+  final ElementEnvironment _env;
   final BackendHelpers helpers;
+  final NativeData _nativeData;
+  final InterceptorData _interceptorData;
 
-  JavaScriptBackendClasses(this.helpers);
+  JavaScriptBackendClasses(
+      this._env, this.helpers, this._nativeData, this._interceptorData);
 
-  ClassElement get intImplementation => helpers.jsIntClass;
-  ClassElement get uint32Implementation => helpers.jsUInt32Class;
-  ClassElement get uint31Implementation => helpers.jsUInt31Class;
-  ClassElement get positiveIntImplementation => helpers.jsPositiveIntClass;
-  ClassElement get doubleImplementation => helpers.jsDoubleClass;
-  ClassElement get numImplementation => helpers.jsNumberClass;
-  ClassElement get stringImplementation => helpers.jsStringClass;
-  ClassElement get listImplementation => helpers.jsArrayClass;
-  ClassElement get mutableListImplementation => helpers.jsMutableArrayClass;
-  ClassElement get constListImplementation => helpers.jsUnmodifiableArrayClass;
-  ClassElement get fixedListImplementation => helpers.jsFixedArrayClass;
-  ClassElement get growableListImplementation => helpers.jsExtendableArrayClass;
-  ClassElement get mapImplementation => helpers.mapLiteralClass;
-  ClassElement get constMapImplementation => helpers.constMapLiteralClass;
-  ClassElement get typeImplementation => helpers.typeLiteralClass;
-  ClassElement get boolImplementation => helpers.jsBoolClass;
-  ClassElement get nullImplementation => helpers.jsNullClass;
-  ClassElement get syncStarIterableImplementation => helpers.syncStarIterable;
-  ClassElement get asyncFutureImplementation => helpers.futureImplementation;
-  ClassElement get asyncStarStreamImplementation => helpers.controllerStream;
-  ClassElement get functionImplementation =>
-      helpers.commonElements.functionClass;
-  ClassElement get indexableImplementation => helpers.jsIndexableClass;
-  ClassElement get mutableIndexableImplementation =>
-      helpers.jsMutableIndexableClass;
-  ClassElement get indexingBehaviorImplementation =>
-      helpers.jsIndexingBehaviorInterface;
-  ClassElement get interceptorImplementation => helpers.jsInterceptorClass;
+  ClassElement get intClass => helpers.jsIntClass;
+  ClassElement get uint32Class => helpers.jsUInt32Class;
+  ClassElement get uint31Class => helpers.jsUInt31Class;
+  ClassElement get positiveIntClass => helpers.jsPositiveIntClass;
+  ClassElement get doubleClass => helpers.jsDoubleClass;
+  ClassElement get numClass => helpers.jsNumberClass;
+  ClassElement get stringClass => helpers.jsStringClass;
+  ClassElement get listClass => helpers.jsArrayClass;
+  ClassElement get mutableListClass => helpers.jsMutableArrayClass;
+  ClassElement get constListClass => helpers.jsUnmodifiableArrayClass;
+  ClassElement get fixedListClass => helpers.jsFixedArrayClass;
+  ClassElement get growableListClass => helpers.jsExtendableArrayClass;
+  ClassElement get mapClass => helpers.mapLiteralClass;
+  ClassElement get constMapClass => helpers.constMapLiteralClass;
+  ClassElement get typeClass => helpers.typeLiteralClass;
+  InterfaceType get typeType => _env.getRawType(typeClass);
+
+  ClassElement get boolClass => helpers.jsBoolClass;
+  ClassElement get nullClass => helpers.jsNullClass;
+  ClassElement get syncStarIterableClass => helpers.syncStarIterable;
+  ClassElement get asyncFutureClass => helpers.futureImplementation;
+  ClassElement get asyncStarStreamClass => helpers.controllerStream;
+  ClassElement get functionClass => helpers.commonElements.functionClass;
+  ClassElement get indexableClass => helpers.jsIndexableClass;
+  ClassElement get mutableIndexableClass => helpers.jsMutableIndexableClass;
+  ClassElement get indexingBehaviorClass => helpers.jsIndexingBehaviorInterface;
+  ClassElement get interceptorClass => helpers.jsInterceptorClass;
 
   bool isDefaultEqualityImplementation(MemberElement element) {
     assert(element.name == '==');
@@ -3295,16 +3162,39 @@
 
   @override
   bool isInterceptorClass(ClassElement cls) {
-    return helpers.backend.isInterceptorClass(cls);
+    return _interceptorData.isInterceptorClass(cls);
   }
 
   @override
   bool isNativeClass(ClassElement element) {
-    return helpers.backend.isNative(element);
+    return _nativeData.isNative(element);
   }
 
   @override
   bool isNativeMember(MemberElement element) {
-    return helpers.backend.isNative(element);
+    return _nativeData.isNative(element);
+  }
+
+  InterfaceType getConstantMapTypeFor(InterfaceType sourceType,
+      {bool hasProtoKey: false, bool onlyStringKeys: false}) {
+    ClassElement classElement = onlyStringKeys
+        ? (hasProtoKey
+            ? helpers.constantProtoMapClass
+            : helpers.constantStringMapClass)
+        : helpers.generalConstantMapClass;
+    List<DartType> typeArgument = sourceType.typeArguments;
+    if (sourceType.treatAsRaw) {
+      return _env.getRawType(classElement);
+    } else {
+      return _env.createInterfaceType(classElement, typeArgument);
+    }
+  }
+
+  @override
+  FieldEntity get symbolField => helpers.symbolImplementationField;
+
+  @override
+  InterfaceType get symbolType {
+    return _env.getRawType(helpers.symbolImplementationClass);
   }
 }
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index 5c2834a..47f6ee8 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -6,22 +6,10 @@
 
 import '../common.dart';
 import '../common/names.dart' show Identifiers, Uris;
-import '../common/resolution.dart' show Resolution;
 import '../compiler.dart' show Compiler;
-import '../core_types.dart' show CommonElements;
-import '../elements/elements.dart'
-    show
-        AbstractFieldElement,
-        ClassElement,
-        ConstructorElement,
-        Element,
-        EnumClassElement,
-        FunctionElement,
-        LibraryElement,
-        MemberElement,
-        MethodElement,
-        Name,
-        PublicName;
+import '../core_types.dart' show CommonElements, ElementEnvironment;
+import '../elements/elements.dart' show PublicName;
+import '../elements/entities.dart';
 import '../library_loader.dart' show LoadedLibraries;
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/selector.dart' show Selector;
@@ -52,377 +40,442 @@
   static const String JS_EMBEDDED_GLOBAL = 'JS_EMBEDDED_GLOBAL';
   static const String JS_INTERCEPTOR_CONSTANT = 'JS_INTERCEPTOR_CONSTANT';
 
-  final Compiler compiler;
+  final ElementEnvironment _env;
 
-  Element cachedCheckConcurrentModificationError;
+  final CommonElements commonElements;
 
-  BackendHelpers(this.compiler);
+  BackendHelpers(this._env, this.commonElements);
 
-  JavaScriptBackend get backend => compiler.backend;
+  ClassEntity _findInterceptorsClass(String name) =>
+      _findClass(interceptorsLibrary, name);
 
-  Resolution get resolution => backend.resolution;
+  FunctionEntity _findInterceptorsFunction(String name) =>
+      _findLibraryMember(interceptorsLibrary, name);
 
-  CommonElements get commonElements => compiler.commonElements;
+  ClassEntity _findHelperClass(String name) =>
+      _findClass(jsHelperLibrary, name);
 
-  DiagnosticReporter get reporter => compiler.reporter;
+  FunctionEntity _findHelperFunction(String name) =>
+      _findLibraryMember(jsHelperLibrary, name);
 
-  MethodElement assertTest;
-  MethodElement assertThrow;
-  MethodElement assertHelper;
+  ClassEntity _findAsyncHelperClass(String name) =>
+      _findClass(asyncLibrary, name);
 
-  LibraryElement jsHelperLibrary;
-  LibraryElement asyncLibrary;
-  LibraryElement interceptorsLibrary;
-  LibraryElement foreignLibrary;
-  LibraryElement isolateHelperLibrary;
+  FunctionEntity _findAsyncHelperFunction(String name) =>
+      _findLibraryMember(asyncLibrary, name);
 
-  /// Reference to the internal library to lookup functions to always inline.
-  LibraryElement internalLibrary;
-
-  ClassElement closureClass;
-  ClassElement boundClosureClass;
-  Element assertUnreachableMethod;
-  Element invokeOnMethod;
-
-  ClassElement jsInterceptorClass;
-  ClassElement jsStringClass;
-  ClassElement jsArrayClass;
-  ClassElement jsNumberClass;
-  ClassElement jsIntClass;
-  ClassElement jsDoubleClass;
-  ClassElement jsNullClass;
-  ClassElement jsBoolClass;
-  ClassElement jsPlainJavaScriptObjectClass;
-  ClassElement jsUnknownJavaScriptObjectClass;
-  ClassElement jsJavaScriptFunctionClass;
-  ClassElement jsJavaScriptObjectClass;
-
-  ClassElement jsIndexableClass;
-  ClassElement jsMutableIndexableClass;
-
-  ClassElement jsMutableArrayClass;
-  ClassElement jsFixedArrayClass;
-  ClassElement jsExtendableArrayClass;
-  ClassElement jsUnmodifiableArrayClass;
-  ClassElement jsPositiveIntClass;
-  ClassElement jsUInt32Class;
-  ClassElement jsUInt31Class;
-
-  MemberElement jsIndexableLength;
-  Element jsArrayTypedConstructor;
-  MethodElement jsArrayRemoveLast;
-  MethodElement jsArrayAdd;
-  MethodElement jsStringSplit;
-  MethodElement jsStringToString;
-  MethodElement jsStringOperatorAdd;
-  MethodElement objectEquals;
-
-  ClassElement typeLiteralClass;
-  ClassElement mapLiteralClass;
-  ClassElement constMapLiteralClass;
-  ClassElement typeVariableClass;
-
-  ClassElement noSideEffectsClass;
-  ClassElement noThrowsClass;
-  ClassElement noInlineClass;
-  ClassElement forceInlineClass;
-  ClassElement irRepresentationClass;
-
-  ClassElement jsAnnotationClass;
-  ClassElement jsAnonymousClass;
-
-  Element getInterceptorMethod;
-
-  ClassElement jsInvocationMirrorClass;
-
-  ClassElement typedArrayClass;
-  ClassElement typedArrayOfIntClass;
-
-  /**
-   * Interface used to determine if an object has the JavaScript
-   * indexing behavior. The interface is only visible to specific
-   * libraries.
-   */
-  ClassElement jsIndexingBehaviorInterface;
-
-  MethodElement getNativeInterceptorMethod;
-
-  /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been
-  /// loaded.
-  FunctionElement getIsolateAffinityTagMarker;
-
-  /// Holds the method "disableTreeShaking" in js_mirrors when
-  /// dart:mirrors has been loaded.
-  FunctionElement disableTreeShakingMarker;
-
-  /// Holds the method "preserveNames" in js_mirrors when
-  /// dart:mirrors has been loaded.
-  FunctionElement preserveNamesMarker;
-
-  /// Holds the method "preserveMetadata" in js_mirrors when
-  /// dart:mirrors has been loaded.
-  FunctionElement preserveMetadataMarker;
-
-  /// Holds the method "preserveUris" in js_mirrors when
-  /// dart:mirrors has been loaded.
-  FunctionElement preserveUrisMarker;
-
-  /// Holds the method "preserveLibraryNames" in js_mirrors when
-  /// dart:mirrors has been loaded.
-  FunctionElement preserveLibraryNamesMarker;
-
-  /// Holds the method "requiresPreamble" in _js_helper.
-  FunctionElement requiresPreambleMarker;
-
-  /// Holds the class for the [JsGetName] enum.
-  EnumClassElement jsGetNameEnum;
-
-  /// Holds the class for the [JsBuiltins] enum.
-  EnumClassElement jsBuiltinEnum;
-
-  ClassElement _symbolImplementationClass;
-  ClassElement get symbolImplementationClass {
-    return _symbolImplementationClass ??= _find(internalLibrary, 'Symbol');
+  FunctionEntity _findMirrorsFunction(String name) {
+    LibraryEntity library = _env.lookupLibrary(DART_JS_MIRRORS);
+    if (library == null) return null;
+    return _env.lookupLibraryMember(library, name, required: true);
   }
 
-  final Selector symbolValidatedConstructorSelector =
-      new Selector.call(const PublicName('validated'), CallStructure.ONE_ARG);
-
-  ConstructorElement _symbolValidatedConstructor;
-
-  bool isSymbolValidatedConstructor(Element element) {
-    if (_symbolValidatedConstructor != null) {
-      return element == _symbolValidatedConstructor;
-    }
-    return false;
+  ClassEntity _findClass(LibraryEntity library, String name) {
+    return _env.lookupClass(library, name, required: true);
   }
 
-  ConstructorElement get symbolValidatedConstructor {
-    return _symbolValidatedConstructor ??= _findConstructor(
-        symbolImplementationClass, symbolValidatedConstructorSelector.name);
+  MemberEntity _findClassMember(ClassEntity cls, String name) {
+    return _env.lookupClassMember(cls, name, required: true);
   }
 
-  // TODO(johnniwinther): Make these private.
-  // TODO(johnniwinther): Split into _findHelperFunction and _findHelperClass
-  // and add a check that the element has the expected kind.
-  Element _findHelper(String name) => _find(jsHelperLibrary, name);
-  FunctionElement _findHelperFunction(String name) =>
-      _find(jsHelperLibrary, name);
-  Element _findAsyncHelper(String name) => _find(asyncLibrary, name);
-  Element _findInterceptor(String name) => _find(interceptorsLibrary, name);
-  Element _find(LibraryElement library, String name) {
-    Element element = library.implementation.findLocal(name);
-    assert(invariant(library, element != null,
-        message: "Element '$name' not found in '${library.canonicalUri}'."));
-    return element;
+  MemberEntity _findLibraryMember(LibraryEntity library, String name) {
+    return _env.lookupLibraryMember(library, name, required: true);
   }
 
-  Element findCoreHelper(String name) {
-    LibraryElement coreLibrary = compiler.commonElements.coreLibrary;
-    return coreLibrary.implementation.localLookup(name);
-  }
+  FunctionEntity findCoreHelper(String name) => _env
+      .lookupLibraryMember(commonElements.coreLibrary, name, required: true);
 
-  ConstructorElement _findConstructor(ClassElement cls, String name) {
-    cls.ensureResolved(resolution);
-    ConstructorElement constructor = cls.lookupConstructor(name);
-    assert(invariant(cls, constructor != null,
-        message: "Constructor '$name' not found in '${cls}'."));
-    return constructor;
-  }
-
-  void onLibraryCreated(LibraryElement library) {
-    Uri uri = library.canonicalUri;
-    if (uri == DART_JS_HELPER) {
-      jsHelperLibrary = library;
-    } else if (uri == Uris.dart_async) {
-      asyncLibrary = library;
-    } else if (uri == Uris.dart__internal) {
-      internalLibrary = library;
-    } else if (uri == DART_INTERCEPTORS) {
-      interceptorsLibrary = library;
-    } else if (uri == DART_FOREIGN_HELPER) {
-      foreignLibrary = library;
-    } else if (uri == DART_ISOLATE_HELPER) {
-      isolateHelperLibrary = library;
-    }
-  }
-
-  void initializeHelperClasses(DiagnosticReporter reporter) {
-    final List missingHelperClasses = [];
-    ClassElement lookupHelperClass(String name) {
-      ClassElement result = _findHelper(name);
-      if (result == null) {
-        missingHelperClasses.add(name);
-      }
-      return result;
-    }
-
-    jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror');
-    boundClosureClass = lookupHelperClass('BoundClosure');
-    closureClass = lookupHelperClass('Closure');
-    if (!missingHelperClasses.isEmpty) {
-      reporter.internalError(
-          jsHelperLibrary,
-          'dart:_js_helper library does not contain required classes: '
-          '$missingHelperClasses');
-    }
-  }
-
-  void onLibraryScanned(LibraryElement library) {
-    Uri uri = library.canonicalUri;
-
-    FunctionElement findMethod(String name) {
-      return _find(library, name);
-    }
-
-    ClassElement findClass(String name) {
-      return _find(library, name);
-    }
-
-    if (uri == DART_INTERCEPTORS) {
-      getInterceptorMethod = findMethod('getInterceptor');
-      getNativeInterceptorMethod = findMethod('getNativeInterceptor');
-      jsInterceptorClass = findClass('Interceptor');
-      jsStringClass = findClass('JSString');
-      jsArrayClass = findClass('JSArray');
-      // The int class must be before the double class, because the
-      // emitter relies on this list for the order of type checks.
-      jsIntClass = findClass('JSInt');
-      jsPositiveIntClass = findClass('JSPositiveInt');
-      jsUInt32Class = findClass('JSUInt32');
-      jsUInt31Class = findClass('JSUInt31');
-      jsDoubleClass = findClass('JSDouble');
-      jsNumberClass = findClass('JSNumber');
-      jsNullClass = findClass('JSNull');
-      jsBoolClass = findClass('JSBool');
-      jsMutableArrayClass = findClass('JSMutableArray');
-      jsFixedArrayClass = findClass('JSFixedArray');
-      jsExtendableArrayClass = findClass('JSExtendableArray');
-      jsUnmodifiableArrayClass = findClass('JSUnmodifiableArray');
-      jsPlainJavaScriptObjectClass = findClass('PlainJavaScriptObject');
-      jsJavaScriptObjectClass = findClass('JavaScriptObject');
-      jsJavaScriptFunctionClass = findClass('JavaScriptFunction');
-      jsUnknownJavaScriptObjectClass = findClass('UnknownJavaScriptObject');
-      jsIndexableClass = findClass('JSIndexable');
-      jsMutableIndexableClass = findClass('JSMutableIndexable');
-    } else if (uri == DART_JS_HELPER) {
-      initializeHelperClasses(reporter);
-      assertTest = _findHelper('assertTest');
-      assertThrow = _findHelper('assertThrow');
-      assertHelper = _findHelper('assertHelper');
-      assertUnreachableMethod = _findHelper('assertUnreachable');
-
-      typeLiteralClass = findClass('TypeImpl');
-      constMapLiteralClass = findClass('ConstantMap');
-      typeVariableClass = findClass('TypeVariable');
-
-      jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior');
-
-      noSideEffectsClass = findClass('NoSideEffects');
-      noThrowsClass = findClass('NoThrows');
-      noInlineClass = findClass('NoInline');
-      forceInlineClass = findClass('ForceInline');
-      irRepresentationClass = findClass('IrRepresentation');
-
-      getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag');
-
-      requiresPreambleMarker = findMethod('requiresPreamble');
-    } else if (uri == DART_JS_MIRRORS) {
-      disableTreeShakingMarker = _find(library, 'disableTreeShaking');
-      preserveMetadataMarker = _find(library, 'preserveMetadata');
-      preserveUrisMarker = _find(library, 'preserveUris');
-      preserveLibraryNamesMarker = _find(library, 'preserveLibraryNames');
-    } else if (uri == DART_JS_NAMES) {
-      preserveNamesMarker = _find(library, 'preserveNames');
-    } else if (uri == DART_EMBEDDED_NAMES) {
-      jsGetNameEnum = _find(library, 'JsGetName');
-      jsBuiltinEnum = _find(library, 'JsBuiltin');
-    } else if (uri == Uris.dart__native_typed_data) {
-      typedArrayClass = findClass('NativeTypedArray');
-      typedArrayOfIntClass = findClass('NativeTypedArrayOfInt');
-    } else if (uri == PACKAGE_JS) {
-      jsAnnotationClass = _find(library, 'JS');
-      jsAnonymousClass = _find(library, '_Anonymous');
-    }
-  }
+  ConstructorEntity _findConstructor(ClassEntity cls, String name) =>
+      _env.lookupConstructor(cls, name, required: true);
 
   void onLibrariesLoaded(LoadedLibraries loadedLibraries) {
     assert(loadedLibraries.containsLibrary(Uris.dart_core));
     assert(loadedLibraries.containsLibrary(DART_INTERCEPTORS));
     assert(loadedLibraries.containsLibrary(DART_JS_HELPER));
 
-    if (jsInvocationMirrorClass != null) {
-      jsInvocationMirrorClass.ensureResolved(resolution);
-      invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
-    }
-
-    // [LinkedHashMap] is reexported from dart:collection and can therefore not
-    // be loaded from dart:core in [onLibraryScanned].
-    LibraryElement coreLibrary = compiler.commonElements.coreLibrary;
-    mapLiteralClass = coreLibrary.find('LinkedHashMap');
-    assert(invariant(
-        compiler.commonElements.coreLibrary, mapLiteralClass != null,
-        message: "Element 'LinkedHashMap' not found in 'dart:core'."));
-
-    // TODO(kasperl): Some tests do not define the special JSArray
-    // subclasses, so we check to see if they are defined before
-    // trying to resolve them.
-    if (jsFixedArrayClass != null) {
-      jsFixedArrayClass.ensureResolved(resolution);
-    }
-    if (jsExtendableArrayClass != null) {
-      jsExtendableArrayClass.ensureResolved(resolution);
-    }
-    if (jsUnmodifiableArrayClass != null) {
-      jsUnmodifiableArrayClass.ensureResolved(resolution);
-    }
-
-    jsIndexableClass.ensureResolved(resolution);
-    Element jsIndexableLengthElement =
-        compiler.lookupElementIn(jsIndexableClass, 'length');
-    if (jsIndexableLengthElement != null &&
-        jsIndexableLengthElement.isAbstractField) {
-      AbstractFieldElement element = jsIndexableLengthElement;
-      jsIndexableLength = element.getter;
-    } else {
-      jsIndexableLength = jsIndexableLengthElement;
-    }
-
-    jsArrayClass.ensureResolved(resolution);
-    jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed');
-    jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast');
-    jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add');
-
-    jsStringClass.ensureResolved(resolution);
-    jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split');
-    jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+');
-    jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString');
-
-    ClassElement objectClass = commonElements.objectClass;
-    objectEquals = compiler.lookupElementIn(objectClass, '==');
+    // TODO(johnniwinther): Avoid these. Currently needed to ensure resolution
+    // of the classes for various queries in native behavior computation,
+    // inference and codegen.
+    _env.getThisType(jsArrayClass);
+    _env.getThisType(jsExtendableArrayClass);
   }
 
-  ConstructorElement _mapLiteralConstructor;
-  ConstructorElement _mapLiteralConstructorEmpty;
-  Element _mapLiteralUntypedMaker;
-  Element _mapLiteralUntypedEmptyMaker;
+  LibraryEntity _jsHelperLibrary;
+  LibraryEntity get jsHelperLibrary =>
+      _jsHelperLibrary ??= _env.lookupLibrary(DART_JS_HELPER);
 
-  ConstructorElement get mapLiteralConstructor {
+  LibraryEntity _asyncLibrary;
+  LibraryEntity get asyncLibrary =>
+      _asyncLibrary ??= _env.lookupLibrary(Uris.dart_async);
+
+  LibraryEntity _interceptorsLibrary;
+  LibraryEntity get interceptorsLibrary =>
+      _interceptorsLibrary ??= _env.lookupLibrary(DART_INTERCEPTORS);
+
+  LibraryEntity _foreignLibrary;
+  LibraryEntity get foreignLibrary =>
+      _foreignLibrary ??= _env.lookupLibrary(DART_FOREIGN_HELPER);
+
+  LibraryEntity _isolateHelperLibrary;
+  LibraryEntity get isolateHelperLibrary =>
+      _isolateHelperLibrary ??= _env.lookupLibrary(DART_ISOLATE_HELPER);
+
+  /// Reference to the internal library to lookup functions to always inline.
+  LibraryEntity _internalLibrary;
+  LibraryEntity get internalLibrary =>
+      _internalLibrary ??= _env.lookupLibrary(Uris.dart__internal);
+
+  FunctionEntity _assertTest;
+  FunctionEntity get assertTest =>
+      _assertTest ??= _findHelperFunction('assertTest');
+
+  FunctionEntity _assertThrow;
+  FunctionEntity get assertThrow =>
+      _assertThrow ??= _findHelperFunction('assertThrow');
+
+  FunctionEntity _assertHelper;
+  FunctionEntity get assertHelper =>
+      _assertHelper ??= _findHelperFunction('assertHelper');
+
+  FunctionEntity _assertUnreachableMethod;
+  FunctionEntity get assertUnreachableMethod =>
+      _assertUnreachableMethod ??= _findHelperFunction('assertUnreachable');
+
+  ClassEntity _closureClass;
+  ClassEntity get closureClass => _closureClass ??= _findHelperClass('Closure');
+
+  ClassEntity _boundClosureClass;
+  ClassEntity get boundClosureClass =>
+      _boundClosureClass ??= _findHelperClass('BoundClosure');
+
+  FunctionEntity _invokeOnMethod;
+  FunctionEntity get invokeOnMethod => _invokeOnMethod ??=
+      _env.lookupClassMember(jsInvocationMirrorClass, INVOKE_ON);
+
+  ClassEntity _jsInterceptorClass;
+  ClassEntity get jsInterceptorClass =>
+      _jsInterceptorClass ??= _findInterceptorsClass('Interceptor');
+
+  ClassEntity _jsStringClass;
+  ClassEntity get jsStringClass =>
+      _jsStringClass ??= _findInterceptorsClass('JSString');
+
+  ClassEntity _jsArrayClass;
+  ClassEntity get jsArrayClass =>
+      _jsArrayClass ??= _findInterceptorsClass('JSArray');
+
+  ClassEntity _jsNumberClass;
+  ClassEntity get jsNumberClass =>
+      _jsNumberClass ??= _findInterceptorsClass('JSNumber');
+
+  ClassEntity _jsIntClass;
+  ClassEntity get jsIntClass => _jsIntClass ??= _findInterceptorsClass('JSInt');
+
+  ClassEntity _jsDoubleClass;
+  ClassEntity get jsDoubleClass =>
+      _jsDoubleClass ??= _findInterceptorsClass('JSDouble');
+
+  ClassEntity _jsNullClass;
+  ClassEntity get jsNullClass =>
+      _jsNullClass ??= _findInterceptorsClass('JSNull');
+
+  ClassEntity _jsBoolClass;
+  ClassEntity get jsBoolClass =>
+      _jsBoolClass ??= _findInterceptorsClass('JSBool');
+
+  ClassEntity _jsPlainJavaScriptObjectClass;
+  ClassEntity get jsPlainJavaScriptObjectClass =>
+      _jsPlainJavaScriptObjectClass ??=
+          _findInterceptorsClass('PlainJavaScriptObject');
+
+  ClassEntity _jsUnknownJavaScriptObjectClass;
+  ClassEntity get jsUnknownJavaScriptObjectClass =>
+      _jsUnknownJavaScriptObjectClass ??=
+          _findInterceptorsClass('UnknownJavaScriptObject');
+
+  ClassEntity _jsJavaScriptFunctionClass;
+  ClassEntity get jsJavaScriptFunctionClass => _jsJavaScriptFunctionClass ??=
+      _findInterceptorsClass('JavaScriptFunction');
+
+  ClassEntity _jsJavaScriptObjectClass;
+  ClassEntity get jsJavaScriptObjectClass =>
+      _jsJavaScriptObjectClass ??= _findInterceptorsClass('JavaScriptObject');
+
+  ClassEntity _jsIndexableClass;
+  ClassEntity get jsIndexableClass =>
+      _jsIndexableClass ??= _findInterceptorsClass('JSIndexable');
+
+  ClassEntity _jsMutableIndexableClass;
+  ClassEntity get jsMutableIndexableClass =>
+      _jsMutableIndexableClass ??= _findInterceptorsClass('JSMutableIndexable');
+
+  ClassEntity _jsMutableArrayClass;
+  ClassEntity get jsMutableArrayClass =>
+      _jsMutableArrayClass ??= _findInterceptorsClass('JSMutableArray');
+
+  ClassEntity _jsFixedArrayClass;
+  ClassEntity get jsFixedArrayClass =>
+      _jsFixedArrayClass ??= _findInterceptorsClass('JSFixedArray');
+
+  ClassEntity _jsExtendableArrayClass;
+  ClassEntity get jsExtendableArrayClass =>
+      _jsExtendableArrayClass ??= _findInterceptorsClass('JSExtendableArray');
+
+  ClassEntity _jsUnmodifiableArrayClass;
+  ClassEntity get jsUnmodifiableArrayClass => _jsUnmodifiableArrayClass ??=
+      _findInterceptorsClass('JSUnmodifiableArray');
+
+  ClassEntity _jsPositiveIntClass;
+  ClassEntity get jsPositiveIntClass =>
+      _jsPositiveIntClass ??= _findInterceptorsClass('JSPositiveInt');
+
+  ClassEntity _jsUInt32Class;
+  ClassEntity get jsUInt32Class =>
+      _jsUInt32Class ??= _findInterceptorsClass('JSUInt32');
+
+  ClassEntity _jsUInt31Class;
+  ClassEntity get jsUInt31Class =>
+      _jsUInt31Class ??= _findInterceptorsClass('JSUInt31');
+
+  MemberEntity _jsIndexableLength;
+  MemberEntity get jsIndexableLength =>
+      _jsIndexableLength ??= _findClassMember(jsIndexableClass, 'length');
+
+  ConstructorEntity _jsArrayTypedConstructor;
+  ConstructorEntity get jsArrayTypedConstructor =>
+      _jsArrayTypedConstructor ??= _findConstructor(jsArrayClass, 'typed');
+
+  FunctionEntity _jsArrayRemoveLast;
+  FunctionEntity get jsArrayRemoveLast =>
+      _jsArrayRemoveLast ??= _findClassMember(jsArrayClass, 'removeLast');
+
+  FunctionEntity _jsArrayAdd;
+  FunctionEntity get jsArrayAdd =>
+      _jsArrayAdd ??= _findClassMember(jsArrayClass, 'add');
+
+  FunctionEntity _jsStringSplit;
+  FunctionEntity get jsStringSplit =>
+      _jsStringSplit ??= _findClassMember(jsStringClass, 'split');
+
+  FunctionEntity _jsStringToString;
+  FunctionEntity get jsStringToString =>
+      _jsStringToString ??= _findClassMember(jsStringClass, 'toString');
+
+  FunctionEntity _jsStringOperatorAdd;
+  FunctionEntity get jsStringOperatorAdd =>
+      _jsStringOperatorAdd ??= _findClassMember(jsStringClass, '+');
+
+  FunctionEntity _objectEquals;
+  FunctionEntity get objectEquals =>
+      _objectEquals ??= _findClassMember(commonElements.objectClass, '==');
+
+  ClassEntity _typeLiteralClass;
+  ClassEntity get typeLiteralClass =>
+      _typeLiteralClass ??= _findHelperClass('TypeImpl');
+
+  ClassEntity _mapLiteralClass;
+  ClassEntity get mapLiteralClass {
+    if (_mapLiteralClass == null) {
+      _mapLiteralClass =
+          _env.lookupClass(commonElements.coreLibrary, 'LinkedHashMap');
+      if (_mapLiteralClass == null) {
+        _mapLiteralClass = _findClass(
+            _env.lookupLibrary(Uris.dart_collection), 'LinkedHashMap');
+      }
+    }
+    return _mapLiteralClass;
+  }
+
+  ClassEntity _constMapLiteralClass;
+  ClassEntity get constMapLiteralClass =>
+      _constMapLiteralClass ??= _findHelperClass('ConstantMap');
+
+  ClassEntity _typeVariableClass;
+  ClassEntity get typeVariableClass =>
+      _typeVariableClass ??= _findHelperClass('TypeVariable');
+
+  ClassEntity _noSideEffectsClass;
+  ClassEntity get noSideEffectsClass =>
+      _noSideEffectsClass ??= _findHelperClass('NoSideEffects');
+
+  ClassEntity _noThrowsClass;
+  ClassEntity get noThrowsClass =>
+      _noThrowsClass ??= _findHelperClass('NoThrows');
+
+  ClassEntity _noInlineClass;
+  ClassEntity get noInlineClass =>
+      _noInlineClass ??= _findHelperClass('NoInline');
+
+  ClassEntity _forceInlineClass;
+  ClassEntity get forceInlineClass =>
+      _forceInlineClass ??= _findHelperClass('ForceInline');
+
+  ClassEntity _irRepresentationClass;
+  ClassEntity get irRepresentationClass =>
+      _irRepresentationClass ??= _findHelperClass('IrRepresentation');
+
+  ClassEntity _jsAnnotationClass;
+  ClassEntity get jsAnnotationClass {
+    if (_jsAnnotationClass == null) {
+      LibraryEntity library = _env.lookupLibrary(PACKAGE_JS);
+      if (library == null) return null;
+      _jsAnnotationClass = _findClass(library, 'JS');
+    }
+    return _jsAnnotationClass;
+  }
+
+  ClassEntity _jsAnonymousClass;
+  ClassEntity get jsAnonymousClass {
+    if (_jsAnonymousClass == null) {
+      LibraryEntity library = _env.lookupLibrary(PACKAGE_JS);
+      if (library == null) return null;
+      _jsAnonymousClass = _findClass(library, '_Anonymous');
+    }
+    return _jsAnonymousClass;
+  }
+
+  FunctionEntity _getInterceptorMethod;
+  FunctionEntity get getInterceptorMethod =>
+      _getInterceptorMethod ??= _findInterceptorsFunction('getInterceptor');
+
+  ClassEntity _jsInvocationMirrorClass;
+  ClassEntity get jsInvocationMirrorClass =>
+      _jsInvocationMirrorClass ??= _findHelperClass('JSInvocationMirror');
+
+  ClassEntity _typedArrayClass;
+  ClassEntity get typedArrayClass => _typedArrayClass ??= _findClass(
+      _env.lookupLibrary(Uris.dart__native_typed_data, required: true),
+      'NativeTypedArray');
+
+  ClassEntity _typedArrayOfIntClass;
+  ClassEntity get typedArrayOfIntClass => _typedArrayOfIntClass ??= _findClass(
+      _env.lookupLibrary(Uris.dart__native_typed_data, required: true),
+      'NativeTypedArrayOfInt');
+
+  /**
+   * Interface used to determine if an object has the JavaScript
+   * indexing behavior. The interface is only visible to specific
+   * libraries.
+   */
+  ClassEntity _jsIndexingBehaviorInterface;
+  ClassEntity get jsIndexingBehaviorInterface =>
+      _jsIndexingBehaviorInterface ??=
+          _findHelperClass('JavaScriptIndexingBehavior');
+
+  FunctionEntity _getNativeInterceptorMethod;
+  FunctionEntity get getNativeInterceptorMethod =>
+      _getNativeInterceptorMethod ??=
+          _findInterceptorsFunction('getNativeInterceptor');
+
+  /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been
+  /// loaded.
+  FunctionEntity _getIsolateAffinityTagMarker;
+  FunctionEntity get getIsolateAffinityTagMarker =>
+      _getIsolateAffinityTagMarker ??=
+          _findHelperFunction('getIsolateAffinityTag');
+
+  /// Holds the method "disableTreeShaking" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionEntity _disableTreeShakingMarker;
+  FunctionEntity get disableTreeShakingMarker =>
+      _disableTreeShakingMarker ??= _findMirrorsFunction('disableTreeShaking');
+
+  /// Holds the method "preserveNames" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionEntity _preserveNamesMarker;
+  FunctionEntity get preserveNamesMarker {
+    if (_preserveNamesMarker == null) {
+      LibraryEntity library = _env.lookupLibrary(DART_JS_NAMES);
+      if (library != null) {
+        _preserveNamesMarker = _findLibraryMember(library, 'preserveNames');
+      }
+    }
+    return _preserveNamesMarker;
+  }
+
+  /// Holds the method "preserveMetadata" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionEntity _preserveMetadataMarker;
+  FunctionEntity get preserveMetadataMarker =>
+      _preserveMetadataMarker ??= _findMirrorsFunction('preserveMetadata');
+
+  /// Holds the method "preserveUris" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionEntity _preserveUrisMarker;
+  FunctionEntity get preserveUrisMarker =>
+      _preserveUrisMarker ??= _findMirrorsFunction('preserveUris');
+
+  /// Holds the method "preserveLibraryNames" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionEntity _preserveLibraryNamesMarker;
+  FunctionEntity get preserveLibraryNamesMarker =>
+      _preserveLibraryNamesMarker ??=
+          _findMirrorsFunction('preserveLibraryNames');
+
+  /// Holds the method "requiresPreamble" in _js_helper.
+  FunctionEntity _requiresPreambleMarker;
+  FunctionEntity get requiresPreambleMarker =>
+      _requiresPreambleMarker ??= _findHelperFunction('requiresPreamble');
+
+  /// Holds the class for the [JsGetName] enum.
+  ClassEntity _jsGetNameEnum;
+  ClassEntity get jsGetNameEnum => _jsGetNameEnum ??= _findClass(
+      _env.lookupLibrary(DART_EMBEDDED_NAMES, required: true), 'JsGetName');
+
+  /// Holds the class for the [JsBuiltins] enum.
+  ClassEntity _jsBuiltinEnum;
+  ClassEntity get jsBuiltinEnum => _jsBuiltinEnum ??= _findClass(
+      _env.lookupLibrary(DART_EMBEDDED_NAMES, required: true), 'JsBuiltin');
+
+  final Selector symbolValidatedConstructorSelector =
+      new Selector.call(const PublicName('validated'), CallStructure.ONE_ARG);
+
+  ConstructorEntity get symbolValidatedConstructor =>
+      _symbolValidatedConstructor ??= _findConstructor(
+          symbolImplementationClass, symbolValidatedConstructorSelector.name);
+
+  ClassEntity _symbolImplementationClass;
+  ClassEntity get symbolImplementationClass =>
+      _symbolImplementationClass ??= _findClass(internalLibrary, 'Symbol');
+
+  FieldEntity _symbolImplementationField;
+
+  /// Returns the field that holds the internal name in the implementation class
+  /// for `Symbol`.
+  FieldEntity get symbolImplementationField => _symbolImplementationField ??=
+      _env.lookupClassMember(symbolImplementationClass, '_name',
+          required: true);
+
+  ConstructorEntity _symbolValidatedConstructor;
+
+  bool isSymbolValidatedConstructor(ConstructorEntity element) {
+    if (_symbolValidatedConstructor != null) {
+      return element == _symbolValidatedConstructor;
+    }
+    return false;
+  }
+
+  ConstructorEntity _mapLiteralConstructor;
+  ConstructorEntity _mapLiteralConstructorEmpty;
+  FunctionEntity _mapLiteralUntypedMaker;
+  FunctionEntity _mapLiteralUntypedEmptyMaker;
+
+  ConstructorEntity get mapLiteralConstructor {
     _ensureMapLiteralHelpers();
     return _mapLiteralConstructor;
   }
 
-  ConstructorElement get mapLiteralConstructorEmpty {
+  ConstructorEntity get mapLiteralConstructorEmpty {
     _ensureMapLiteralHelpers();
     return _mapLiteralConstructorEmpty;
   }
 
-  Element get mapLiteralUntypedMaker {
+  FunctionEntity get mapLiteralUntypedMaker {
     _ensureMapLiteralHelpers();
     return _mapLiteralUntypedMaker;
   }
 
-  Element get mapLiteralUntypedEmptyMaker {
+  FunctionEntity get mapLiteralUntypedEmptyMaker {
     _ensureMapLiteralHelpers();
     return _mapLiteralUntypedEmptyMaker;
   }
@@ -430,460 +483,324 @@
   void _ensureMapLiteralHelpers() {
     if (_mapLiteralConstructor != null) return;
 
-    // For map literals, the dependency between the implementation class
-    // and [Map] is not visible, so we have to add it manually.
-    Element getFactory(String name, int arity) {
-      // The constructor is on the patch class, but dart2js unit tests don't
-      // have a patch class.
-      ClassElement implementation = mapLiteralClass.implementation;
-      ConstructorElement ctor = implementation.lookupConstructor(name);
-      if (ctor == null ||
-          (Name.isPrivateName(name) &&
-              ctor.library != mapLiteralClass.library)) {
-        reporter.internalError(
-            mapLiteralClass,
-            "Map literal class ${mapLiteralClass} missing "
-            "'$name' constructor"
-            "  ${mapLiteralClass.constructors}");
-      }
-      return ctor;
-    }
-
-    Element getMember(String name) {
-      // The constructor is on the patch class, but dart2js unit tests don't
-      // have a patch class.
-      ClassElement implementation = mapLiteralClass.implementation;
-      Element element = implementation.lookupLocalMember(name);
-      if (element == null || !element.isFunction || !element.isStatic) {
-        reporter.internalError(
-            mapLiteralClass,
-            "Map literal class ${mapLiteralClass} missing "
-            "'$name' static member function");
-      }
-      return element;
-    }
-
-    _mapLiteralConstructor = getFactory('_literal', 1);
-    _mapLiteralConstructorEmpty = getFactory('_empty', 0);
-    _mapLiteralUntypedMaker = getMember('_makeLiteral');
-    _mapLiteralUntypedEmptyMaker = getMember('_makeEmpty');
+    _mapLiteralConstructor =
+        _env.lookupConstructor(mapLiteralClass, '_literal');
+    _mapLiteralConstructorEmpty =
+        _env.lookupConstructor(mapLiteralClass, '_empty');
+    _mapLiteralUntypedMaker =
+        _env.lookupClassMember(mapLiteralClass, '_makeLiteral');
+    _mapLiteralUntypedEmptyMaker =
+        _env.lookupClassMember(mapLiteralClass, '_makeEmpty');
   }
 
-  Element get badMain {
-    return _findHelper('badMain');
+  FunctionEntity get badMain {
+    return _findHelperFunction('badMain');
   }
 
-  Element get missingMain {
-    return _findHelper('missingMain');
+  FunctionEntity get missingMain {
+    return _findHelperFunction('missingMain');
   }
 
-  Element get mainHasTooManyParameters {
-    return _findHelper('mainHasTooManyParameters');
+  FunctionEntity get mainHasTooManyParameters {
+    return _findHelperFunction('mainHasTooManyParameters');
   }
 
-  MethodElement get loadLibraryWrapper {
-    return _findHelper("_loadLibraryWrapper");
+  FunctionEntity get loadLibraryWrapper {
+    return _findHelperFunction("_loadLibraryWrapper");
   }
 
-  Element get boolConversionCheck {
-    return _findHelper('boolConversionCheck');
+  FunctionEntity get boolConversionCheck {
+    return _findHelperFunction('boolConversionCheck');
   }
 
-  MethodElement _traceHelper;
+  FunctionEntity _traceHelper;
 
-  MethodElement get traceHelper {
+  FunctionEntity get traceHelper {
     return _traceHelper ??= JavaScriptBackend.TRACE_METHOD == 'console'
         ? _consoleTraceHelper
         : _postTraceHelper;
   }
 
-  MethodElement get _consoleTraceHelper {
-    return _findHelper('consoleTraceHelper');
-  }
+  FunctionEntity get _consoleTraceHelper =>
+      _findHelperFunction('consoleTraceHelper');
 
-  MethodElement get _postTraceHelper {
-    return _findHelper('postTraceHelper');
-  }
+  FunctionEntity get _postTraceHelper => _findHelperFunction('postTraceHelper');
 
-  MethodElement get closureFromTearOff {
-    return _findHelper('closureFromTearOff');
-  }
+  FunctionEntity get closureFromTearOff =>
+      _findHelperFunction('closureFromTearOff');
 
-  MethodElement get isJsIndexable {
-    return _findHelper('isJsIndexable');
-  }
+  FunctionEntity get isJsIndexable => _findHelperFunction('isJsIndexable');
 
-  MethodElement get throwIllegalArgumentException {
-    return _findHelper('iae');
-  }
+  FunctionEntity get throwIllegalArgumentException =>
+      _findHelperFunction('iae');
 
-  MethodElement get throwIndexOutOfRangeException {
-    return _findHelper('ioore');
-  }
+  FunctionEntity get throwIndexOutOfRangeException =>
+      _findHelperFunction('ioore');
 
-  Element get exceptionUnwrapper {
-    return _findHelper('unwrapException');
-  }
+  FunctionEntity get exceptionUnwrapper =>
+      _findHelperFunction('unwrapException');
 
-  Element get throwRuntimeError {
-    return _findHelper('throwRuntimeError');
-  }
+  FunctionEntity get throwRuntimeError =>
+      _findHelperFunction('throwRuntimeError');
 
-  Element get throwTypeError {
-    return _findHelper('throwTypeError');
-  }
+  FunctionEntity get throwTypeError => _findHelperFunction('throwTypeError');
 
-  Element get throwAbstractClassInstantiationError {
-    return _findHelper('throwAbstractClassInstantiationError');
-  }
+  FunctionEntity get throwAbstractClassInstantiationError =>
+      _findHelperFunction('throwAbstractClassInstantiationError');
 
-  Element get checkConcurrentModificationError {
-    if (cachedCheckConcurrentModificationError == null) {
-      cachedCheckConcurrentModificationError =
-          _findHelper('checkConcurrentModificationError');
-    }
-    return cachedCheckConcurrentModificationError;
-  }
+  FunctionEntity _cachedCheckConcurrentModificationError;
+  FunctionEntity get checkConcurrentModificationError =>
+      _cachedCheckConcurrentModificationError ??=
+          _findHelperFunction('checkConcurrentModificationError');
 
-  MethodElement get throwConcurrentModificationError {
-    return _findHelper('throwConcurrentModificationError');
-  }
+  FunctionEntity get throwConcurrentModificationError =>
+      _findHelperFunction('throwConcurrentModificationError');
 
-  Element get checkInt => _checkInt ??= _findHelper('checkInt');
-  Element _checkInt;
+  FunctionEntity _checkInt;
+  FunctionEntity get checkInt => _checkInt ??= _findHelperFunction('checkInt');
 
-  Element get checkNum => _checkNum ??= _findHelper('checkNum');
-  Element _checkNum;
+  FunctionEntity _checkNum;
+  FunctionEntity get checkNum => _checkNum ??= _findHelperFunction('checkNum');
 
-  Element get checkString => _checkString ??= _findHelper('checkString');
-  Element _checkString;
+  FunctionEntity _checkString;
+  FunctionEntity get checkString =>
+      _checkString ??= _findHelperFunction('checkString');
 
-  MethodElement get stringInterpolationHelper {
-    return _findHelper('S');
-  }
+  FunctionEntity get stringInterpolationHelper => _findHelperFunction('S');
 
-  MethodElement get wrapExceptionHelper {
-    return _findHelper(r'wrapException');
-  }
+  FunctionEntity get wrapExceptionHelper =>
+      _findHelperFunction('wrapException');
 
-  MethodElement get throwExpressionHelper {
-    return _findHelper('throwExpression');
-  }
+  FunctionEntity get throwExpressionHelper =>
+      _findHelperFunction('throwExpression');
 
-  MethodElement get closureConverter {
-    return _findHelper('convertDartClosureToJS');
-  }
+  FunctionEntity get closureConverter =>
+      _findHelperFunction('convertDartClosureToJS');
 
-  Element get traceFromException {
-    return _findHelper('getTraceFromException');
-  }
+  FunctionEntity get traceFromException =>
+      _findHelperFunction('getTraceFromException');
 
-  MethodElement get setRuntimeTypeInfo {
-    return _findHelper('setRuntimeTypeInfo');
-  }
+  FunctionEntity get setRuntimeTypeInfo =>
+      _findHelperFunction('setRuntimeTypeInfo');
 
-  Element get getRuntimeTypeInfo {
-    return _findHelper('getRuntimeTypeInfo');
-  }
+  FunctionEntity get getRuntimeTypeInfo =>
+      _findHelperFunction('getRuntimeTypeInfo');
 
-  MethodElement get getTypeArgumentByIndex {
-    return _findHelper('getTypeArgumentByIndex');
-  }
+  FunctionEntity get getTypeArgumentByIndex =>
+      _findHelperFunction('getTypeArgumentByIndex');
 
-  MethodElement get computeSignature {
-    return _findHelper('computeSignature');
-  }
+  FunctionEntity get computeSignature =>
+      _findHelperFunction('computeSignature');
 
-  Element get getRuntimeTypeArguments {
-    return _findHelper('getRuntimeTypeArguments');
-  }
+  FunctionEntity get getRuntimeTypeArguments =>
+      _findHelperFunction('getRuntimeTypeArguments');
 
-  MethodElement get getRuntimeTypeArgument {
-    return _findHelper('getRuntimeTypeArgument');
-  }
+  FunctionEntity get getRuntimeTypeArgument =>
+      _findHelperFunction('getRuntimeTypeArgument');
 
-  Element get runtimeTypeToString {
-    return _findHelper('runtimeTypeToString');
-  }
+  FunctionEntity get runtimeTypeToString =>
+      _findHelperFunction('runtimeTypeToString');
 
-  Element get assertIsSubtype {
-    return _findHelper('assertIsSubtype');
-  }
+  FunctionEntity get assertIsSubtype => _findHelperFunction('assertIsSubtype');
 
-  Element get checkSubtype {
-    return _findHelper('checkSubtype');
-  }
+  FunctionEntity get checkSubtype => _findHelperFunction('checkSubtype');
 
-  Element get assertSubtype {
-    return _findHelper('assertSubtype');
-  }
+  FunctionEntity get assertSubtype => _findHelperFunction('assertSubtype');
 
-  Element get subtypeCast {
-    return _findHelper('subtypeCast');
-  }
+  FunctionEntity get subtypeCast => _findHelperFunction('subtypeCast');
 
-  Element get checkSubtypeOfRuntimeType {
-    return _findHelper('checkSubtypeOfRuntimeType');
-  }
+  FunctionEntity get checkSubtypeOfRuntimeType =>
+      _findHelperFunction('checkSubtypeOfRuntimeType');
 
-  Element get assertSubtypeOfRuntimeType {
-    return _findHelper('assertSubtypeOfRuntimeType');
-  }
+  FunctionEntity get assertSubtypeOfRuntimeType =>
+      _findHelperFunction('assertSubtypeOfRuntimeType');
 
-  Element get subtypeOfRuntimeTypeCast {
-    return _findHelper('subtypeOfRuntimeTypeCast');
-  }
+  FunctionEntity get subtypeOfRuntimeTypeCast =>
+      _findHelperFunction('subtypeOfRuntimeTypeCast');
 
-  Element get checkDeferredIsLoaded {
-    return _findHelper('checkDeferredIsLoaded');
-  }
+  FunctionEntity get checkDeferredIsLoaded =>
+      _findHelperFunction('checkDeferredIsLoaded');
 
-  Element get throwNoSuchMethod {
-    return _findHelper('throwNoSuchMethod');
-  }
+  FunctionEntity get throwNoSuchMethod =>
+      _findHelperFunction('throwNoSuchMethod');
 
-  Element get malformedTypeError => _cachedCoreHelper('_malformedTypeError');
-  Element get genericNoSuchMethod => _cachedCoreHelper('_genericNoSuchMethod');
-  Element get unresolvedConstructorError =>
+  FunctionEntity get malformedTypeError =>
+      _cachedCoreHelper('_malformedTypeError');
+  FunctionEntity get genericNoSuchMethod =>
+      _cachedCoreHelper('_genericNoSuchMethod');
+  FunctionEntity get unresolvedConstructorError =>
       _cachedCoreHelper('_unresolvedConstructorError');
-  Element get unresolvedStaticGetterError =>
+  FunctionEntity get unresolvedStaticGetterError =>
       _cachedCoreHelper('_unresolvedStaticGetterError');
-  Element get unresolvedStaticSetterError =>
+  FunctionEntity get unresolvedStaticSetterError =>
       _cachedCoreHelper('_unresolvedStaticSetterError');
-  Element get unresolvedStaticMethodError =>
+  FunctionEntity get unresolvedStaticMethodError =>
       _cachedCoreHelper('_unresolvedStaticMethodError');
-  Element get unresolvedTopLevelGetterError =>
+  FunctionEntity get unresolvedTopLevelGetterError =>
       _cachedCoreHelper('_unresolvedTopLevelGetterError');
-  Element get unresolvedTopLevelSetterError =>
+  FunctionEntity get unresolvedTopLevelSetterError =>
       _cachedCoreHelper('_unresolvedTopLevelSetterError');
-  Element get unresolvedTopLevelMethodError =>
+  FunctionEntity get unresolvedTopLevelMethodError =>
       _cachedCoreHelper('_unresolvedTopLevelMethodError');
 
-  Map<String, Element> _cachedCoreHelpers = <String, Element>{};
-  Element _cachedCoreHelper(String name) =>
+  Map<String, FunctionEntity> _cachedCoreHelpers = <String, FunctionEntity>{};
+  FunctionEntity _cachedCoreHelper(String name) =>
       _cachedCoreHelpers[name] ??= findCoreHelper(name);
 
-  MethodElement get createRuntimeType {
-    return _findHelper('createRuntimeType');
-  }
+  FunctionEntity get createRuntimeType =>
+      _findHelperFunction('createRuntimeType');
 
-  Element get fallThroughError {
-    return _findHelper("getFallThroughError");
-  }
+  FunctionEntity get fallThroughError =>
+      _findHelperFunction("getFallThroughError");
 
-  MethodElement get createInvocationMirror {
-    return _findHelper('createInvocationMirror');
-  }
+  FunctionEntity get createInvocationMirror =>
+      _findHelperFunction('createInvocationMirror');
 
-  MethodElement get cyclicThrowHelper {
-    return _findHelper("throwCyclicInit");
-  }
+  FunctionEntity get cyclicThrowHelper =>
+      _findHelperFunction("throwCyclicInit");
 
-  MethodElement get asyncHelper {
-    return _findAsyncHelper("_asyncHelper");
-  }
+  FunctionEntity get asyncHelper => _findAsyncHelperFunction("_asyncHelper");
 
-  MethodElement get wrapBody {
-    return _findAsyncHelper("_wrapJsFunctionForAsync");
-  }
+  FunctionEntity get wrapBody =>
+      _findAsyncHelperFunction("_wrapJsFunctionForAsync");
 
-  MethodElement get yieldStar {
-    ClassElement classElement = _findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(resolution);
-    return classElement.lookupLocalMember("yieldStar");
-  }
+  FunctionEntity get yieldStar => _env.lookupClassMember(
+      _findAsyncHelperClass("_IterationMarker"), "yieldStar");
 
-  MethodElement get yieldSingle {
-    ClassElement classElement = _findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(resolution);
-    return classElement.lookupLocalMember("yieldSingle");
-  }
+  FunctionEntity get yieldSingle => _env.lookupClassMember(
+      _findAsyncHelperClass("_IterationMarker"), "yieldSingle");
 
-  MethodElement get syncStarUncaughtError {
-    ClassElement classElement = _findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(resolution);
-    return classElement.lookupLocalMember("uncaughtError");
-  }
+  FunctionEntity get syncStarUncaughtError => _env.lookupClassMember(
+      _findAsyncHelperClass("_IterationMarker"), "uncaughtError");
 
-  MethodElement get asyncStarHelper {
-    return _findAsyncHelper("_asyncStarHelper");
-  }
+  FunctionEntity get asyncStarHelper =>
+      _findAsyncHelperFunction("_asyncStarHelper");
 
-  MethodElement get streamOfController {
-    return _findAsyncHelper("_streamOfController");
-  }
+  FunctionEntity get streamOfController =>
+      _findAsyncHelperFunction("_streamOfController");
 
-  MethodElement get endOfIteration {
-    ClassElement classElement = _findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(resolution);
-    return classElement.lookupLocalMember("endOfIteration");
-  }
+  FunctionEntity get endOfIteration => _env.lookupClassMember(
+      _findAsyncHelperClass("_IterationMarker"), "endOfIteration");
 
-  ClassElement get syncStarIterable {
-    ClassElement classElement = _findAsyncHelper("_SyncStarIterable");
-    classElement.ensureResolved(resolution);
-    return classElement;
-  }
+  ClassEntity get syncStarIterable =>
+      _findAsyncHelperClass("_SyncStarIterable");
 
-  Element get futureImplementation {
-    ClassElement classElement = _findAsyncHelper('_Future');
-    classElement.ensureResolved(resolution);
-    return classElement;
-  }
+  ClassEntity get futureImplementation => _findAsyncHelperClass('_Future');
 
-  ClassElement get controllerStream {
-    ClassElement classElement = _findAsyncHelper("_ControllerStream");
-    classElement.ensureResolved(resolution);
-    return classElement;
-  }
+  ClassEntity get controllerStream =>
+      _findAsyncHelperClass("_ControllerStream");
 
-  ConstructorElement get syncStarIterableConstructor {
-    ClassElement classElement = syncStarIterable;
-    classElement.ensureResolved(resolution);
-    return classElement.lookupConstructor("");
-  }
+  ConstructorEntity get syncStarIterableConstructor =>
+      _env.lookupConstructor(syncStarIterable, "");
 
-  ConstructorElement get syncCompleterConstructor {
-    ClassElement classElement = _find(asyncLibrary, "Completer");
-    classElement.ensureResolved(resolution);
-    return classElement.lookupConstructor("sync");
-  }
+  ConstructorEntity get syncCompleterConstructor =>
+      _env.lookupConstructor(_findAsyncHelperClass("Completer"), "sync");
 
-  ClassElement get asyncStarController {
-    ClassElement classElement = _findAsyncHelper("_AsyncStarStreamController");
-    classElement.ensureResolved(resolution);
-    return classElement;
-  }
+  ClassEntity get asyncStarController =>
+      _findAsyncHelperClass("_AsyncStarStreamController");
 
-  ConstructorElement get asyncStarControllerConstructor {
-    ClassElement classElement = asyncStarController;
-    return classElement.lookupConstructor("");
-  }
+  ConstructorEntity get asyncStarControllerConstructor =>
+      _env.lookupConstructor(asyncStarController, "", required: true);
 
-  ConstructorElement get streamIteratorConstructor {
-    ClassElement classElement = _find(asyncLibrary, "StreamIterator");
-    classElement.ensureResolved(resolution);
-    return classElement.lookupConstructor("");
-  }
+  ConstructorEntity get streamIteratorConstructor =>
+      _env.lookupConstructor(_findAsyncHelperClass("StreamIterator"), "");
 
-  ClassElement get VoidRuntimeType {
-    return _findHelper('VoidRuntimeType');
-  }
+  ClassEntity get VoidRuntimeType => _findHelperClass('VoidRuntimeType');
 
-  ClassElement get RuntimeType {
-    return _findHelper('RuntimeType');
-  }
+  ClassEntity get RuntimeType => _findHelperClass('RuntimeType');
 
-  ClassElement get RuntimeFunctionType {
-    return _findHelper('RuntimeFunctionType');
-  }
+  ClassEntity get RuntimeFunctionType =>
+      _findHelperClass('RuntimeFunctionType');
 
-  ClassElement get RuntimeTypePlain {
-    return _findHelper('RuntimeTypePlain');
-  }
+  ClassEntity get RuntimeTypePlain => _findHelperClass('RuntimeTypePlain');
 
-  ClassElement get RuntimeTypeGeneric {
-    return _findHelper('RuntimeTypeGeneric');
-  }
+  ClassEntity get RuntimeTypeGeneric => _findHelperClass('RuntimeTypeGeneric');
 
-  ClassElement get DynamicRuntimeType {
-    return _findHelper('DynamicRuntimeType');
-  }
+  ClassEntity get DynamicRuntimeType => _findHelperClass('DynamicRuntimeType');
 
-  MethodElement get getDynamicRuntimeType {
+  FunctionEntity get getDynamicRuntimeType {
     // TODO(johnniwinther): Support this in mocks.
-    return jsHelperLibrary.find('getDynamicRuntimeType');
+    return _env.lookupLibraryMember(jsHelperLibrary, 'getDynamicRuntimeType');
   }
 
-  MethodElement get getVoidRuntimeType {
+  FunctionEntity get getVoidRuntimeType {
     // TODO(johnniwinther): Support this in mocks.
-    return jsHelperLibrary.find('getVoidRuntimeType');
+    return _env.lookupLibraryMember(jsHelperLibrary, 'getVoidRuntimeType');
   }
 
-  MethodElement get buildInterfaceType {
+  FunctionEntity get buildInterfaceType {
     // TODO(johnniwinther): Support this in mocks.
-    return jsHelperLibrary.find('buildInterfaceType');
+    return _env.lookupLibraryMember(jsHelperLibrary, 'buildInterfaceType');
   }
 
-  MethodElement get buildFunctionType {
+  FunctionEntity get buildFunctionType {
     // TODO(johnniwinther): Support this in mocks.
-    return jsHelperLibrary.find('buildFunctionType');
+    return _env.lookupLibraryMember(jsHelperLibrary, 'buildFunctionType');
   }
 
-  MethodElement get buildNamedFunctionType {
+  FunctionEntity get buildNamedFunctionType {
     // TODO(johnniwinther): Support this in mocks.
-    return jsHelperLibrary.find('buildNamedFunctionType');
+    return _env.lookupLibraryMember(jsHelperLibrary, 'buildNamedFunctionType');
   }
 
-  MethodElement get functionTypeTestMetaHelper {
-    return _findHelper('functionTypeTestMetaHelper');
+  FunctionEntity get functionTypeTestMetaHelper =>
+      _findHelperFunction('functionTypeTestMetaHelper');
+
+  FunctionEntity get defineProperty => _findHelperFunction('defineProperty');
+
+  FunctionEntity get startRootIsolate =>
+      _findLibraryMember(isolateHelperLibrary, START_ROOT_ISOLATE);
+
+  FunctionEntity get currentIsolate =>
+      _findLibraryMember(isolateHelperLibrary, '_currentIsolate');
+
+  FunctionEntity get callInIsolate =>
+      _findLibraryMember(isolateHelperLibrary, '_callInIsolate');
+
+  FunctionEntity get findIndexForNativeSubclassType =>
+      _findLibraryMember(interceptorsLibrary, 'findIndexForNativeSubclassType');
+
+  FunctionEntity get convertRtiToRuntimeType =>
+      _findHelperFunction('convertRtiToRuntimeType');
+
+  ClassEntity get stackTraceClass => _findHelperClass('_StackTrace');
+
+  FunctionEntity _objectNoSuchMethod;
+  FunctionEntity get objectNoSuchMethod {
+    return _objectNoSuchMethod ??= _env.lookupClassMember(
+        commonElements.objectClass, Identifiers.noSuchMethod_);
   }
 
-  MethodElement get defineProperty {
-    return _findHelper('defineProperty');
-  }
+  ClassEntity get constantMapClass =>
+      _findHelperClass(JavaScriptMapConstant.DART_CLASS);
+  ClassEntity get constantStringMapClass =>
+      _findHelperClass(JavaScriptMapConstant.DART_STRING_CLASS);
+  ClassEntity get constantProtoMapClass =>
+      _findHelperClass(JavaScriptMapConstant.DART_PROTO_CLASS);
+  ClassEntity get generalConstantMapClass =>
+      _findHelperClass(JavaScriptMapConstant.DART_GENERAL_CLASS);
 
-  MethodElement get startRootIsolate {
-    return _find(isolateHelperLibrary, START_ROOT_ISOLATE);
-  }
+  ClassEntity get annotationCreatesClass => _findHelperClass('Creates');
 
-  Element get currentIsolate {
-    return _find(isolateHelperLibrary, '_currentIsolate');
-  }
+  ClassEntity get annotationReturnsClass => _findHelperClass('Returns');
 
-  Element get callInIsolate {
-    return _find(isolateHelperLibrary, '_callInIsolate');
-  }
+  ClassEntity get annotationJSNameClass => _findHelperClass('JSName');
 
-  Element get findIndexForNativeSubclassType {
-    return _findInterceptor('findIndexForNativeSubclassType');
-  }
+  FunctionEntity get toStringForNativeObject =>
+      _findHelperFunction('toStringForNativeObject');
 
-  MethodElement get convertRtiToRuntimeType {
-    return _findHelper('convertRtiToRuntimeType');
-  }
+  FunctionEntity get hashCodeForNativeObject =>
+      _findHelperFunction('hashCodeForNativeObject');
 
-  ClassElement get stackTraceClass {
-    return _findHelper('_StackTrace');
-  }
+  ClassEntity _patchAnnotationClass;
 
-  MethodElement _objectNoSuchMethod;
+  /// The class for patch annotations defined in dart:_js_helper.
+  ClassEntity get patchAnnotationClass =>
+      _patchAnnotationClass ??= _findHelperClass('_Patch');
 
-  MethodElement get objectNoSuchMethod {
-    if (_objectNoSuchMethod == null) {
-      ClassElement objectClass = commonElements.objectClass;
-      _objectNoSuchMethod =
-          objectClass.lookupLocalMember(Identifiers.noSuchMethod_);
-    }
-    return _objectNoSuchMethod;
-  }
+  ClassEntity _nativeAnnotationClass;
 
-  ClassElement get constantMapClass =>
-      _findHelper(JavaScriptMapConstant.DART_CLASS);
-  ClassElement get constantStringMapClass =>
-      _findHelper(JavaScriptMapConstant.DART_STRING_CLASS);
-  ClassElement get constantProtoMapClass =>
-      _findHelper(JavaScriptMapConstant.DART_PROTO_CLASS);
-  ClassElement get generalConstantMapClass =>
-      _findHelper(JavaScriptMapConstant.DART_GENERAL_CLASS);
-
-  ClassElement get annotationCreatesClass {
-    return _findHelper('Creates');
-  }
-
-  ClassElement get annotationReturnsClass {
-    return _findHelper('Returns');
-  }
-
-  ClassElement get annotationJSNameClass {
-    return _findHelper('JSName');
-  }
-
-  MethodElement get toStringForNativeObject {
-    return _findHelper('toStringForNativeObject');
-  }
-
-  MethodElement get hashCodeForNativeObject {
-    return _findHelper('hashCodeForNativeObject');
-  }
+  /// The class for native annotations defined in dart:_js_helper.
+  ClassEntity get nativeAnnotationClass =>
+      _nativeAnnotationClass ??= _findHelperClass('Native');
 }
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 97da9b7..0ba422f 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -12,7 +12,6 @@
 import '../universe/selector.dart';
 import '../util/enumset.dart';
 import 'backend_helpers.dart';
-import 'constant_system_javascript.dart';
 import 'js_backend.dart';
 
 /// Backend specific features required by a backend impact.
@@ -397,7 +396,7 @@
 
   BackendImpact get typeLiteral {
     return _typeLiteral ??= new BackendImpact(
-        instantiatedClasses: [backend.backendClasses.typeImplementation],
+        instantiatedClasses: [backend.backendClasses.typeClass],
         staticUses: [helpers.createRuntimeType]);
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/backend_serialization.dart b/pkg/compiler/lib/src/js_backend/backend_serialization.dart
index 834daae..1b61abf 100644
--- a/pkg/compiler/lib/src/js_backend/backend_serialization.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_serialization.dart
@@ -5,8 +5,9 @@
 library js_backend.serialization;
 
 import '../common/backend_api.dart' show BackendSerialization;
-import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
+import '../elements/resolution_types.dart';
+import '../elements/types.dart';
 import '../js/js.dart' as js;
 import '../native/native.dart';
 import '../serialization/keys.dart';
@@ -156,12 +157,12 @@
   static const int SPECIAL_TYPE = 2;
 
   static int getTypeKind(var type) {
-    if (type is ResolutionDartType) {
+    if (type is DartType) {
       // TODO(johnniwinther): Remove this when annotation are no longer resolved
       // to this-types.
-      if (type is GenericType &&
-          type.isGeneric &&
-          type == type.element.thisType) {
+      if (type is InterfaceType &&
+          type.typeArguments.isNotEmpty &&
+          type.typeArguments.first is TypeVariableType) {
         return THIS_TYPE;
       }
       return NORMAL_TYPE;
diff --git a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
index 613abf9..044cdd5 100644
--- a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
@@ -22,7 +22,8 @@
     JavaScriptBackend backend = compiler.backend;
     // TODO(johnniwinther): Refactor this to avoid looking up directly in the
     // js helper library but instead access helpers directly on backend helpers.
-    MethodElement method = backend.helpers.jsHelperLibrary.find(name);
+    LibraryElement jsHelperLibrary = backend.helpers.jsHelperLibrary;
+    MethodElement method = jsHelperLibrary.find(name);
     return new StaticUse.staticInvoke(method, callStructure);
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
index 4847928..479ab20 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -234,14 +234,6 @@
     metadataConstantMap[metadata] = constant;
     return constant;
   }
-
-  void forgetElement(Element element) {
-    super.forgetElement(element);
-    const ForgetConstantElementVisitor().visit(element, this);
-    if (element is AstElement && element.hasNode) {
-      element.node.accept(new ForgetConstantNodeVisitor(this));
-    }
-  }
 }
 
 class ForgetConstantElementVisitor
diff --git a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
index 1571c41..44c2095 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -4,15 +4,15 @@
 
 library dart2js.constant_system.js;
 
-import '../compiler.dart' show Compiler;
+import '../common/backend_api.dart' show BackendClasses;
 import '../constant_system_dart.dart';
 import '../constants/constant_system.dart';
 import '../constants/values.dart';
 import '../core_types.dart' show CommonElements;
-import '../elements/resolution_types.dart';
-import '../elements/elements.dart' show ClassElement, FieldElement;
+import '../elements/types.dart';
+import '../elements/resolution_types.dart' show DartTypes;
+import '../elements/entities.dart';
 import '../tree/dartstring.dart' show DartString, LiteralDartString;
-import 'js_backend.dart';
 
 const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem();
 
@@ -313,16 +313,14 @@
   NullConstantValue createNull() => new NullConstantValue();
 
   @override
-  ListConstantValue createList(
-      ResolutionInterfaceType type, List<ConstantValue> values) {
+  ListConstantValue createList(InterfaceType type, List<ConstantValue> values) {
     return new ListConstantValue(type, values);
   }
 
   @override
-  ConstantValue createType(Compiler compiler, ResolutionDartType type) {
-    ResolutionInterfaceType instanceType = compiler
-        .backend.backendClasses.typeImplementation
-        .computeType(compiler.resolution);
+  ConstantValue createType(CommonElements commonElements,
+      BackendClasses backendClasses, DartType type) {
+    InterfaceType instanceType = backendClasses.typeType;
     return new TypeConstantValue(type, instanceType);
   }
 
@@ -345,7 +343,7 @@
   bool isBool(ConstantValue constant) => constant.isBool;
   bool isNull(ConstantValue constant) => constant.isNull;
 
-  bool isSubtype(DartTypes types, ResolutionDartType s, ResolutionDartType t) {
+  bool isSubtype(DartTypes types, DartType s, DartType t) {
     // At runtime, an integer is both an integer and a double: the
     // integer type check is Math.floor, which will return true only
     // for real integers, and our double type check is 'typeof number'
@@ -358,13 +356,11 @@
   }
 
   MapConstantValue createMap(
-      Compiler compiler,
-      ResolutionInterfaceType sourceType,
+      CommonElements commonElements,
+      BackendClasses backendClasses,
+      InterfaceType sourceType,
       List<ConstantValue> keys,
       List<ConstantValue> values) {
-    JavaScriptBackend backend = compiler.backend;
-    CommonElements commonElements = compiler.commonElements;
-
     bool onlyStringKeys = true;
     ConstantValue protoValue = null;
     for (int i = 0; i < keys.length; i++) {
@@ -382,43 +378,30 @@
     }
 
     bool hasProtoKey = (protoValue != null);
-    ResolutionInterfaceType keysType;
+    InterfaceType keysType;
     if (sourceType.treatAsRaw) {
       keysType = commonElements.listType();
     } else {
       keysType = commonElements.listType(sourceType.typeArguments.first);
     }
     ListConstantValue keysList = new ListConstantValue(keysType, keys);
-    ClassElement classElement = onlyStringKeys
-        ? (hasProtoKey
-            ? backend.helpers.constantProtoMapClass
-            : backend.helpers.constantStringMapClass)
-        : backend.helpers.generalConstantMapClass;
-    classElement.ensureResolved(compiler.resolution);
-    List<ResolutionDartType> typeArgument = sourceType.typeArguments;
-    ResolutionInterfaceType type;
-    if (sourceType.treatAsRaw) {
-      type = classElement.rawType;
-    } else {
-      type = new ResolutionInterfaceType(classElement, typeArgument);
-    }
+    InterfaceType type = backendClasses.getConstantMapTypeFor(sourceType,
+        hasProtoKey: hasProtoKey, onlyStringKeys: onlyStringKeys);
     return new JavaScriptMapConstant(
         type, keysList, values, protoValue, onlyStringKeys);
   }
 
   @override
-  ConstantValue createSymbol(Compiler compiler, String text) {
-    // TODO(johnniwinther): Create a backend agnostic value.
-    JavaScriptBackend backend = compiler.backend;
-    ClassElement symbolClass = backend.helpers.symbolImplementationClass;
-    ResolutionInterfaceType type = symbolClass.rawType;
+  ConstantValue createSymbol(CommonElements commonElements,
+      BackendClasses backendClasses, String text) {
+    InterfaceType type = backendClasses.symbolType;
+    FieldEntity field = backendClasses.symbolField;
     ConstantValue argument = createString(new DartString.literal(text));
-    Map<FieldElement, ConstantValue> fields = <FieldElement, ConstantValue>{};
-    symbolClass.forEachInstanceField(
-        (ClassElement enclosingClass, FieldElement field) {
-      fields[field] = argument;
-    }, includeSuperAndInjectedMembers: true);
-    assert(fields.length == 1);
+    // TODO(johnniwinther): Use type arguments when all uses no longer expect
+    // a [FieldElement].
+    Map<FieldEntity, ConstantValue> fields = /*<FieldElement, ConstantValue>*/ {
+      field: argument
+    };
     return new ConstructedConstantValue(type, fields);
   }
 }
@@ -446,7 +429,7 @@
   final ConstantValue protoValue;
   final bool onlyStringKeys;
 
-  JavaScriptMapConstant(ResolutionInterfaceType type, ListConstantValue keyList,
+  JavaScriptMapConstant(InterfaceType type, ListConstantValue keyList,
       List<ConstantValue> values, this.protoValue, this.onlyStringKeys)
       : this.keyList = keyList,
         super(type, keyList.entries, values);
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index 3a55345..aacaaee8 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -6,7 +6,6 @@
 import '../constants/values.dart';
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
-import '../enqueue.dart' show Enqueuer;
 import '../universe/use.dart' show StaticUse;
 import '../universe/world_impact.dart'
     show WorldImpact, StagedWorldImpactBuilder;
@@ -55,7 +54,7 @@
   final CustomElementsAnalysisJoin resolutionJoin;
   final CustomElementsAnalysisJoin codegenJoin;
   bool fetchedTableAccessorMethod = false;
-  Element tableAccessorMethod;
+  MethodElement tableAccessorMethod;
 
   CustomElementsAnalysis(JavaScriptBackend backend)
       : this.backend = backend,
@@ -77,7 +76,7 @@
   void registerInstantiatedClass(ClassElement classElement,
       {bool forResolution}) {
     classElement.ensureResolved(compiler.resolution);
-    if (!backend.isNativeOrExtendsNative(classElement)) return;
+    if (!backend.nativeData.isNativeOrExtendsNative(classElement)) return;
     if (classElement.isMixinApplication) return;
     if (classElement.isAbstract) return;
     // JsInterop classes are opaque interfaces without a concrete
@@ -160,7 +159,7 @@
     for (ClassElement classElement in instantiatedClasses) {
       bool isNative = backend.isNative(classElement);
       bool isExtension =
-          !isNative && backend.isNativeOrExtendsNative(classElement);
+          !isNative && backend.nativeData.isNativeOrExtendsNative(classElement);
       // Generate table entries for native classes that are explicitly named and
       // extensions that fix our criteria.
       if ((isNative && selectedClasses.contains(classElement)) ||
@@ -190,7 +189,8 @@
 
   TypeConstantValue makeTypeConstant(ClassElement element) {
     ResolutionDartType elementType = element.rawType;
-    return backend.constantSystem.createType(compiler, elementType);
+    return backend.constantSystem.createType(
+        compiler.commonElements, compiler.backend.backendClasses, elementType);
   }
 
   List<ConstructorElement> computeEscapingConstructors(
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 603e667..f59f60c 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -6,18 +6,16 @@
 
 import 'dart:collection' show Queue;
 
-import '../cache_strategy.dart' show CacheStrategy;
-import '../common/backend_api.dart' show Backend;
 import '../common/codegen.dart' show CodegenWorkItem;
 import '../common/tasks.dart' show CompilerTask;
 import '../common/work.dart' show WorkItem;
 import '../common.dart';
-import '../compiler.dart' show Compiler;
 import '../elements/resolution_types.dart'
     show ResolutionDartType, ResolutionInterfaceType;
-import '../elements/elements.dart' show Entity, MemberElement, TypedElement;
+import '../elements/elements.dart' show MemberElement, TypedElement;
 import '../elements/entities.dart';
 import '../enqueue.dart';
+import '../js_backend/backend.dart' show JavaScriptBackend;
 import '../native/native.dart' as native;
 import '../options.dart';
 import '../types/types.dart' show TypeMaskStrategy;
@@ -41,7 +39,7 @@
   bool queueIsClosed = false;
   final CompilerTask task;
   final native.NativeEnqueuer nativeEnqueuer;
-  final Backend _backend;
+  final JavaScriptBackend _backend;
   final CompilerOptions _options;
 
   WorldImpactVisitor _impactVisitor;
@@ -51,20 +49,14 @@
   /// All declaration elements that have been processed by codegen.
   final Set<Entity> _processedEntities = new Set<Entity>();
 
-  final Set<Entity> newlyEnqueuedElements;
-
-  final Set<DynamicUse> newlySeenSelectors;
-
   static const ImpactUseCase IMPACT_USE =
       const ImpactUseCase('CodegenEnqueuer');
 
-  CodegenEnqueuer(this.task, CacheStrategy cacheStrategy, Backend backend,
-      CompilerOptions options, this.strategy)
+  CodegenEnqueuer(this.task, JavaScriptBackend backend, CompilerOptions options,
+      this.strategy)
       : _universe =
             new CodegenWorldBuilderImpl(backend, const TypeMaskStrategy()),
         _workItemBuilder = new CodegenWorkItemBuilder(backend, options),
-        newlyEnqueuedElements = cacheStrategy.newSet(),
-        newlySeenSelectors = cacheStrategy.newSet(),
         nativeEnqueuer = backend.nativeCodegenEnqueuer(),
         this._backend = backend,
         this._options = options,
@@ -87,10 +79,6 @@
     WorkItem workItem = _workItemBuilder.createWorkItem(entity);
     if (workItem == null) return;
 
-    if (_options.hasIncrementalSupport) {
-      newlyEnqueuedElements.add(entity);
-    }
-
     if (queueIsClosed) {
       throw new SpannableAssertionFailure(
           entity, "Codegen work list is closed. Trying to add $entity");
@@ -162,11 +150,7 @@
 
   void processDynamicUse(DynamicUse dynamicUse) {
     task.measure(() {
-      if (_universe.registerDynamicUse(dynamicUse, _applyMemberUse)) {
-        if (_options.hasIncrementalSupport) {
-          newlySeenSelectors.add(dynamicUse);
-        }
-      }
+      _universe.registerDynamicUse(dynamicUse, _applyMemberUse);
     });
   }
 
@@ -264,11 +248,6 @@
 
   ImpactUseCase get impactUse => IMPACT_USE;
 
-  void forgetEntity(Entity entity, Compiler compiler) {
-    _universe.forgetElement(entity, compiler);
-    _processedEntities.remove(entity);
-  }
-
   @override
   Iterable<Entity> get processedEntities => _processedEntities;
 
@@ -279,7 +258,7 @@
 /// Builder that creates the work item necessary for the code generation of a
 /// [MemberElement].
 class CodegenWorkItemBuilder extends WorkItemBuilder {
-  Backend _backend;
+  JavaScriptBackend _backend;
   CompilerOptions _options;
 
   CodegenWorkItemBuilder(this._backend, this._options);
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
new file mode 100644
index 0000000..88f236c
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -0,0 +1,245 @@
+// 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 js_backend.interceptor_data;
+
+import '../common/names.dart' show Identifiers;
+import '../core_types.dart' show CommonElements;
+import '../elements/elements.dart';
+import '../js/js.dart' as jsAst;
+import '../types/types.dart' show TypeMask;
+import '../universe/selector.dart';
+import '../world.dart' show ClosedWorld;
+import 'backend_helpers.dart';
+import 'namer.dart';
+import 'native_data.dart';
+
+class InterceptorData {
+  final NativeData _nativeData;
+  final BackendHelpers _helpers;
+  final CommonElements _commonElements;
+  ClosedWorld _closedWorld;
+
+  /// A collection of selectors that must have a one shot interceptor generated.
+  final Map<jsAst.Name, Selector> oneShotInterceptors =
+      <jsAst.Name, Selector>{};
+
+  /// The members of instantiated interceptor classes: maps a member name to the
+  /// list of members that have that name. This map is used by the codegen to
+  /// know whether a send must be intercepted or not.
+  final Map<String, Set<Element>> interceptedElements =
+      <String, Set<Element>>{};
+
+  /// The members of mixin classes that are mixed into an instantiated
+  /// interceptor class.  This is a cached subset of [interceptedElements].
+  ///
+  /// Mixin methods are not specialized for the class they are mixed into.
+  /// Methods mixed into intercepted classes thus always make use of the
+  /// explicit receiver argument, even when mixed into non-interceptor classes.
+  ///
+  /// These members must be invoked with a correct explicit receiver even when
+  /// the receiver is not an intercepted class.
+  final Map<String, Set<Element>> interceptedMixinElements =
+      new Map<String, Set<Element>>();
+
+  /// A map of specialized versions of the [getInterceptorMethod].
+  ///
+  /// Since [getInterceptorMethod] is a hot method at runtime, we're always
+  /// specializing it based on the incoming type. The keys in the map are the
+  /// names of these specialized versions. Note that the generic version that
+  /// contains all possible type checks is also stored in this map.
+  final Map<jsAst.Name, Set<ClassElement>> specializedGetInterceptors =
+      <jsAst.Name, Set<ClassElement>>{};
+
+  /// Set of classes whose methods are intercepted.
+  final Set<ClassElement> _interceptedClasses = new Set<ClassElement>();
+
+  /// Set of classes used as mixins on intercepted (native and primitive)
+  /// classes. Methods on these classes might also be mixed in to regular Dart
+  /// (unintercepted) classes.
+  final Set<ClassElement> classesMixedIntoInterceptedClasses =
+      new Set<ClassElement>();
+
+  InterceptorData(this._nativeData, this._helpers, this._commonElements);
+
+  void onResolutionComplete(ClosedWorld closedWorld) {
+    _closedWorld = closedWorld;
+  }
+
+  bool isInterceptedMethod(MemberElement element) {
+    if (!element.isInstanceMember) return false;
+    if (element.isGenerativeConstructorBody) {
+      return _nativeData.isNativeOrExtendsNative(element.enclosingClass);
+    }
+    return interceptedElements[element.name] != null;
+  }
+
+  bool fieldHasInterceptedGetter(Element element) {
+    assert(element.isField);
+    return interceptedElements[element.name] != null;
+  }
+
+  bool fieldHasInterceptedSetter(Element element) {
+    assert(element.isField);
+    return interceptedElements[element.name] != null;
+  }
+
+  bool isInterceptedName(String name) {
+    return interceptedElements[name] != null;
+  }
+
+  bool isInterceptedSelector(Selector selector) {
+    return interceptedElements[selector.name] != null;
+  }
+
+  /// Returns `true` iff [selector] matches an element defined in a class mixed
+  /// into an intercepted class.  These selectors are not eligible for the
+  /// 'dummy explicit receiver' optimization.
+  bool isInterceptedMixinSelector(Selector selector, TypeMask mask) {
+    Set<Element> elements =
+        interceptedMixinElements.putIfAbsent(selector.name, () {
+      Set<Element> elements = interceptedElements[selector.name];
+      if (elements == null) return null;
+      return elements
+          .where((element) => classesMixedIntoInterceptedClasses
+              .contains(element.enclosingClass))
+          .toSet();
+    });
+
+    if (elements == null) return false;
+    if (elements.isEmpty) return false;
+    return elements.any((element) {
+      return selector.applies(element) &&
+          (mask == null ||
+              mask.canHit(element as MemberElement, selector, _closedWorld));
+    });
+  }
+
+  /// True if the given class is an internal class used for type inference
+  /// and never exists at runtime.
+  bool isCompileTimeOnlyClass(ClassElement class_) {
+    return class_ == _helpers.jsPositiveIntClass ||
+        class_ == _helpers.jsUInt32Class ||
+        class_ == _helpers.jsUInt31Class ||
+        class_ == _helpers.jsFixedArrayClass ||
+        class_ == _helpers.jsUnmodifiableArrayClass ||
+        class_ == _helpers.jsMutableArrayClass ||
+        class_ == _helpers.jsExtendableArrayClass;
+  }
+
+  final Map<String, Set<ClassElement>> interceptedClassesCache =
+      new Map<String, Set<ClassElement>>();
+  final Set<ClassElement> _noClasses = new Set<ClassElement>();
+
+  /// Returns a set of interceptor classes that contain a member named [name]
+  ///
+  /// Returns an empty set if there is no class. Do not modify the returned set.
+  Set<ClassElement> getInterceptedClassesOn(String name) {
+    Set<Element> intercepted = interceptedElements[name];
+    if (intercepted == null) return _noClasses;
+    return interceptedClassesCache.putIfAbsent(name, () {
+      // Populate the cache by running through all the elements and
+      // determine if the given selector applies to them.
+      Set<ClassElement> result = new Set<ClassElement>();
+      for (Element element in intercepted) {
+        ClassElement classElement = element.enclosingClass;
+        if (isCompileTimeOnlyClass(classElement)) continue;
+        if (_nativeData.isNativeOrExtendsNative(classElement) ||
+            interceptedClasses.contains(classElement)) {
+          result.add(classElement);
+        }
+        if (classesMixedIntoInterceptedClasses.contains(classElement)) {
+          Set<ClassElement> nativeSubclasses =
+              nativeSubclassesOfMixin(classElement);
+          if (nativeSubclasses != null) result.addAll(nativeSubclasses);
+        }
+      }
+      return result;
+    });
+  }
+
+  Set<ClassElement> nativeSubclassesOfMixin(ClassElement mixin) {
+    Iterable<MixinApplicationElement> uses = _closedWorld.mixinUsesOf(mixin);
+    Set<ClassElement> result = null;
+    for (MixinApplicationElement use in uses) {
+      _closedWorld.forEachStrictSubclassOf(use, (ClassElement subclass) {
+        if (_nativeData.isNativeOrExtendsNative(subclass)) {
+          if (result == null) result = new Set<ClassElement>();
+          result.add(subclass);
+        }
+      });
+    }
+    return result;
+  }
+
+  bool isInterceptorClass(ClassElement element) {
+    if (element == null) return false;
+    if (_nativeData.isNativeOrExtendsNative(element)) return true;
+    if (interceptedClasses.contains(element)) return true;
+    if (classesMixedIntoInterceptedClasses.contains(element)) return true;
+    return false;
+  }
+
+  jsAst.Name registerOneShotInterceptor(Selector selector, Namer namer) {
+    Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
+    jsAst.Name name = namer.nameForGetOneShotInterceptor(selector, classes);
+    if (!oneShotInterceptors.containsKey(name)) {
+      registerSpecializedGetInterceptor(classes, namer);
+      oneShotInterceptors[name] = selector;
+    }
+    return name;
+  }
+
+  void addInterceptorsForNativeClassMembers(ClassElement cls) {
+    cls.forEachMember((ClassElement classElement, Element member) {
+      if (member.name == Identifiers.call) {
+        return;
+      }
+      if (member.isSynthesized) return;
+      // All methods on [Object] are shadowed by [Interceptor].
+      if (classElement == _commonElements.objectClass) return;
+      Set<Element> set = interceptedElements.putIfAbsent(
+          member.name, () => new Set<Element>());
+      set.add(member);
+    }, includeSuperAndInjectedMembers: true);
+
+    // Walk superclass chain to find mixins.
+    for (; cls != null; cls = cls.superclass) {
+      if (cls.isMixinApplication) {
+        MixinApplicationElement mixinApplication = cls;
+        classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
+      }
+    }
+  }
+
+  void addInterceptors(ClassElement cls) {
+    if (_interceptedClasses.add(cls)) {
+      cls.forEachMember((ClassElement classElement, Element member) {
+        // All methods on [Object] are shadowed by [Interceptor].
+        if (classElement == _commonElements.objectClass) return;
+        Set<Element> set = interceptedElements.putIfAbsent(
+            member.name, () => new Set<Element>());
+        set.add(member);
+      }, includeSuperAndInjectedMembers: true);
+    }
+    _interceptedClasses.add(_helpers.jsInterceptorClass);
+  }
+
+  Set<ClassElement> get interceptedClasses {
+    assert(_closedWorld != null);
+    return _interceptedClasses;
+  }
+
+  void registerSpecializedGetInterceptor(
+      Set<ClassElement> classes, Namer namer) {
+    jsAst.Name name = namer.nameForGetInterceptor(classes);
+    if (classes.contains(_helpers.jsInterceptorClass)) {
+      // We can't use a specialized [getInterceptorMethod], so we make
+      // sure we emit the one with all checks.
+      specializedGetInterceptors[name] = interceptedClasses;
+    } else {
+      specializedGetInterceptors[name] = classes;
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
index b2ad759..b9e3cc5 100644
--- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
@@ -45,7 +45,8 @@
     if (_inCodegen) return;
 
     if (helpers.jsAnnotationClass != null) {
-      nameField = helpers.jsAnnotationClass.lookupMember('name');
+      ClassElement cls = helpers.jsAnnotationClass;
+      nameField = cls.lookupMember('name');
       backend.compiler.libraryLoader.libraries
           .forEach(processJsInteropAnnotationsInLibrary);
     }
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
index eb9aa3c..ef2f47a 100644
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -17,7 +17,6 @@
         NullConstantValue,
         StringConstantValue,
         TypeConstantValue;
-import '../elements/resolution_types.dart' show ResolutionDartType;
 import '../elements/resolution_types.dart' show ResolutionInterfaceType;
 import '../elements/elements.dart'
     show ClassElement, FieldElement, LibraryElement, VariableElement;
@@ -234,8 +233,10 @@
       key.isPrimitive || _inUse.contains(key) || _overridesEquals(key);
 
   void _addClassUse(ClassElement cls) {
-    ConstantValue key = _typeConstants.putIfAbsent(cls,
-        () => backend.constantSystem.createType(backend.compiler, cls.rawType));
+    ConstantValue key = _typeConstants.putIfAbsent(
+        cls,
+        () => backend.constantSystem.createType(
+            backend.commonElements, backend.backendClasses, cls.rawType));
     _addUse(key);
   }
 
@@ -285,8 +286,7 @@
         // type_lookup_map/generic_type_test
         // TODO(sigmund): can we get rid of this?
         backend.computeImpactForInstantiatedConstantType(
-            backend.backendClasses.typeImplementation.rawType,
-            impactBuilderForCodegen);
+            backend.backendClasses.typeType, impactBuilderForCodegen);
         _addGenerics(arg);
       }
     }
diff --git a/pkg/compiler/lib/src/js_backend/minify_namer.dart b/pkg/compiler/lib/src/js_backend/minify_namer.dart
index f0fdcb8..2871687 100644
--- a/pkg/compiler/lib/src/js_backend/minify_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/minify_namer.dart
@@ -317,25 +317,20 @@
 
   int get numberOfConstructors => _constructors.length;
 
-  _ConstructorBodyNamingScope _superScope;
-
   _ConstructorBodyNamingScope.rootScope(ClassElement cls)
-      : _superScope = null,
-        _startIndex = 0,
+      : _startIndex = 0,
         _constructors = cls.constructors.toList(growable: false);
 
   _ConstructorBodyNamingScope.forClass(
       ClassElement cls, _ConstructorBodyNamingScope superScope)
-      : _superScope = superScope,
-        _startIndex = superScope._startIndex + superScope.numberOfConstructors,
+      : _startIndex = superScope._startIndex + superScope.numberOfConstructors,
         _constructors = cls.constructors.toList(growable: false);
 
   // Mixin Applications have constructors but we never generate code for them,
   // so they do not count in the inheritance chain.
   _ConstructorBodyNamingScope.forMixinApplication(
       ClassElement cls, _ConstructorBodyNamingScope superScope)
-      : _superScope = superScope,
-        _startIndex = superScope._startIndex + superScope.numberOfConstructors,
+      : _startIndex = superScope._startIndex + superScope.numberOfConstructors,
         _constructors = const [];
 
   factory _ConstructorBodyNamingScope(ClassElement cls,
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index ffb7800..bc9a880 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -11,7 +11,6 @@
 import '../closure.dart';
 import '../common.dart';
 import '../common/names.dart' show Identifiers, Selectors;
-import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
 import '../core_types.dart' show CommonElements;
 import '../elements/resolution_types.dart';
@@ -24,7 +23,7 @@
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/selector.dart' show Selector, SelectorKind;
 import '../universe/world_builder.dart' show CodegenWorldBuilder;
-import '../util/characters.dart';
+import 'package:front_end/src/fasta/scanner/characters.dart';
 import '../util/util.dart';
 import '../world.dart' show ClosedWorld;
 import 'backend.dart';
@@ -968,7 +967,7 @@
   /// True if [class_] is a non-native class that inherits from a native class.
   bool _isUserClassExtendingNative(ClassElement class_) {
     return !backend.isNative(class_) &&
-        backend.isNativeOrExtendsNative(class_.superclass);
+        backend.nativeData.isNativeOrExtendsNative(class_.superclass);
   }
 
   /// Annotated name for the setter of [element].
@@ -1359,11 +1358,11 @@
     }
 
     List<String> names = classes
-        .where((cls) => !backend.isNativeOrExtendsNative(cls))
+        .where((cls) => !backend.nativeData.isNativeOrExtendsNative(cls))
         .map(abbreviate)
         .toList();
     // There is one dispatch mechanism for all native classes.
-    if (classes.any((cls) => backend.isNativeOrExtendsNative(cls))) {
+    if (classes.any((cls) => backend.nativeData.isNativeOrExtendsNative(cls))) {
       names.add("x");
     }
     // Sort the names of the classes after abbreviating them to ensure
@@ -1374,7 +1373,7 @@
 
   /// Property name used for `getInterceptor` or one of its specializations.
   jsAst.Name nameForGetInterceptor(Iterable<ClassEntity> classes) {
-    FunctionElement getInterceptor = helpers.getInterceptorMethod;
+    MethodElement getInterceptor = helpers.getInterceptorMethod;
     if (classes.contains(helpers.jsInterceptorClass)) {
       // If the base Interceptor class is in the set of intercepted classes, we
       // need to go through the generic getInterceptorMethod, since any subclass
@@ -1523,8 +1522,7 @@
       if ('${library.canonicalUri}' == 'dart:html') return 'W';
       return 'P';
     }
-    return userGlobalObjects[
-        library.libraryOrScriptName.hashCode % userGlobalObjects.length];
+    return userGlobalObjects[library.name.hashCode % userGlobalObjects.length];
   }
 
   jsAst.Name deriveLazyInitializerName(jsAst.Name name) {
@@ -1711,18 +1709,6 @@
       return name;
     }
   }
-
-  String get incrementalHelperName => r'$dart_unsafe_incremental_support';
-
-  jsAst.Expression get accessIncrementalHelper {
-    return js('self.${incrementalHelperName}');
-  }
-
-  void forgetElement(Element element) {
-    jsAst.Name globalName = userGlobals[element];
-    invariant(element, globalName != null, message: 'No global name.');
-    userGlobals.remove(element);
-  }
 }
 
 /**
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index e30010d..969fc3a2 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -6,13 +6,8 @@
 
 import '../common.dart';
 import '../elements/elements.dart'
-    show
-        ClassElement,
-        Element,
-        Entity,
-        FieldElement,
-        FunctionElement,
-        MemberElement;
+    show ClassElement, Element, FieldElement, FunctionElement, MemberElement;
+import '../elements/entities.dart';
 import '../native/behavior.dart' show NativeBehavior;
 
 /// Additional element information for native classes and methods and js-interop
@@ -136,6 +131,16 @@
     }
   }
 
+  /// Returns `true` if [element] or any of its superclasses is native.
+  bool isNativeOrExtendsNative(ClassElement element) {
+    if (element == null) return false;
+    if (isNative(element) || isJsInterop(element)) {
+      return true;
+    }
+    assert(element.isResolved);
+    return isNativeOrExtendsNative(element.superclass);
+  }
+
   /// Sets the native [name] for the member [element]. This name is used for
   /// [element] in the generated JavaScript.
   void setNativeMemberName(MemberElement element, String name) {
diff --git a/pkg/compiler/lib/src/js_backend/patch_resolver.dart b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
index f7477fe..29e16d9 100644
--- a/pkg/compiler/lib/src/js_backend/patch_resolver.dart
+++ b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
@@ -42,6 +42,9 @@
 
   void checkMatchingPatchParameters(FunctionElement origin,
       List<Element> originParameters, List<Element> patchParameters) {
+    bool isUnnamedListConstructor = origin is ConstructorElement &&
+        compiler.commonElements.isUnnamedListConstructor(origin);
+
     assert(originParameters.length == patchParameters.length);
     for (int index = 0; index < originParameters.length; index++) {
       ParameterElementX originParameter = originParameters[index];
@@ -86,7 +89,7 @@
             // We special case the list constructor because of the
             // optional parameter.
             &&
-            origin != compiler.commonElements.unnamedListConstructor) {
+            !isUnnamedListConstructor) {
           reporter.reportError(
               reporter.createMessage(
                   originParameter, MessageKind.PATCH_PARAMETER_MISMATCH, {
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index dfa0813..e6e5a5d 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -29,7 +29,7 @@
   Iterable<ClassElement> get classesUsingTypeVariableExpression;
 
   void registerClassUsingTypeVariableExpression(ClassElement cls);
-  void registerRtiDependency(Element element, Element dependency);
+  void registerRtiDependency(ClassElement element, ClassElement dependency);
   void registerTypeVariableBoundsSubtypeCheck(
       ResolutionDartType typeArgument, ResolutionDartType bound);
 
@@ -142,9 +142,9 @@
   }
 
   @override
-  void registerRtiDependency(Element element, Element dependency) {
+  void registerRtiDependency(ClassElement element, ClassElement dependency) {
     // We're not dealing with typedef for now.
-    if (element == null || !element.isClass || !dependency.isClass) return;
+    assert(element != null);
     Set<ClassElement> classes =
         rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>());
     classes.add(dependency);
@@ -589,7 +589,6 @@
 
 class _RuntimeTypesEncoder implements RuntimeTypesEncoder {
   final Compiler compiler;
-  @override
   final TypeRepresentationGenerator representationGenerator;
 
   _RuntimeTypesEncoder(Compiler compiler)
diff --git a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
index 898e910..8b32bbe 100644
--- a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
+++ b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
@@ -8,12 +8,10 @@
 import '../constants/values.dart';
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
-import '../enqueue.dart' show Enqueuer;
 import '../js/js.dart' as jsAst;
 import '../js_emitter/js_emitter.dart'
     show CodeEmitterTask, MetadataCollector, Placeholder;
 import '../universe/call_structure.dart' show CallStructure;
-import '../universe/use.dart' show StaticUse;
 import '../universe/world_impact.dart';
 import '../util/util.dart';
 import 'backend.dart';
@@ -101,7 +99,6 @@
     // Do not process classes twice.
     if (_typeVariables.containsKey(cls)) return;
 
-    ResolutionInterfaceType typeVariableType = _typeVariableClass.thisType;
     List<jsAst.Expression> constants = <jsAst.Expression>[];
 
     for (ResolutionTypeVariableType currentTypeVariable in cls.typeVariables) {
@@ -111,13 +108,11 @@
           _metadataCollector.reifyType(typeVariableElement.bound);
       ConstantValue boundValue = new SyntheticConstantValue(
           SyntheticConstantKind.TYPEVARIABLE_REFERENCE, boundIndex);
-      ConstantExpression boundExpression =
-          new SyntheticConstantExpression(boundValue);
       ConstantExpression constant = new ConstructedConstantExpression(
           _typeVariableConstructor.enclosingClass.thisType,
           _typeVariableConstructor,
           const CallStructure.unnamed(3), [
-        new TypeConstantExpression(cls.rawType),
+        new TypeConstantExpression(cls.rawType, cls.name),
         new StringConstantExpression(currentTypeVariable.name),
         new SyntheticConstantExpression(boundValue)
       ]);
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index 5d7b4b5..1388ba8 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -54,15 +54,19 @@
 
   jsAst.Expression generateGetter(MemberEntity member, jsAst.Name fieldName) {
     ClassEntity cls = member.enclosingClass;
-    String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
-    List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
+    String receiver =
+        backend.interceptorData.isInterceptorClass(cls) ? 'receiver' : 'this';
+    List<String> args =
+        backend.interceptorData.isInterceptedMethod(member) ? ['receiver'] : [];
     return js('function(#) { return #.# }', [args, receiver, fieldName]);
   }
 
   jsAst.Expression generateSetter(MemberEntity member, jsAst.Name fieldName) {
     ClassEntity cls = member.enclosingClass;
-    String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
-    List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
+    String receiver =
+        backend.interceptorData.isInterceptorClass(cls) ? 'receiver' : 'this';
+    List<String> args =
+        backend.interceptorData.isInterceptedMethod(member) ? ['receiver'] : [];
     // TODO(floitsch): remove 'return'?
     return js(
         'function(#, v) { return #.# = v; }', [args, receiver, fieldName]);
@@ -77,8 +81,10 @@
       MemberEntity member, Map<Selector, SelectorConstraints> selectors) {
     // If the method is intercepted, the stub gets the
     // receiver explicitely and we need to pass it to the getter call.
-    bool isInterceptedMethod = backend.isInterceptedMethod(member);
-    bool isInterceptorClass = backend.isInterceptorClass(member.enclosingClass);
+    bool isInterceptedMethod =
+        backend.interceptorData.isInterceptedMethod(member);
+    bool isInterceptorClass =
+        backend.interceptorData.isInterceptorClass(member.enclosingClass);
 
     const String receiverArgumentName = r'$receiver';
 
@@ -175,8 +181,10 @@
     jsAst.Name methodName = namer.asName(selector.invocationMirrorMemberName);
     jsAst.Name internalName = namer.invocationMirrorInternalName(selector);
 
-    assert(backend.isInterceptedName(Identifiers.noSuchMethod_));
-    bool isIntercepted = backend.isInterceptedName(selector.name);
+    assert(
+        backend.interceptorData.isInterceptedName(Identifiers.noSuchMethod_));
+    bool isIntercepted =
+        backend.interceptorData.isInterceptedName(selector.name);
     jsAst.Expression expression = js(
         '''this.#noSuchMethodName(#receiver,
                     #createInvocationMirror(#methodName,
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index 7b9314e..430f1de 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -11,7 +11,6 @@
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
 import '../deferred_load.dart' show OutputUnit;
-import '../elements/elements.dart' show Entity;
 import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
 import '../js_backend/js_backend.dart' show JavaScriptBackend, Namer;
@@ -175,8 +174,6 @@
 
   int assembleProgram(Namer namer, ClosedWorld closedWorld) {
     return measure(() {
-      emitter.invalidateCaches();
-
       Set<ClassEntity> rtiNeededClasses = _finalizeRti();
       ProgramBuilder programBuilder = new ProgramBuilder(
           compiler, namer, this, emitter, closedWorld, rtiNeededClasses);
@@ -251,6 +248,4 @@
 
   /// Returns the size of the code generated for a given output [unit].
   int generatedSize(OutputUnit unit);
-
-  void invalidateCaches();
 }
diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
index 49b77e7..6ec0eb5 100644
--- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
+++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
@@ -5,8 +5,8 @@
 library dart2js.js_emitter.constant_ordering;
 
 import '../constants/values.dart';
-import '../elements/elements.dart' show Entity, Elements;
-import '../elements/entities.dart' show FieldEntity;
+import '../elements/elements.dart' show Elements;
+import '../elements/entities.dart' show Entity, FieldEntity;
 import '../elements/resolution_types.dart';
 import '../js_backend/js_backend.dart' show SyntheticConstantKind;
 import '../tree/dartstring.dart' show DartString;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
index f0167e1..d4fb903 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
@@ -4,7 +4,6 @@
 
 library dart2js.js_emitter.full_emitter.class_builder;
 
-import '../../elements/elements.dart' show Entity;
 import '../../elements/entities.dart';
 import '../../js/js.dart' as jsAst;
 import '../../js/js.dart' show js;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index 3e5b669..7f2c084 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -22,7 +22,6 @@
         ClassElement,
         Element,
         Elements,
-        Entity,
         FieldElement,
         FunctionElement,
         FunctionSignature,
@@ -30,6 +29,7 @@
         MethodElement,
         TypedefElement,
         VariableElement;
+import '../../elements/entities.dart';
 import '../../hash/sha1.dart' show Hasher;
 import '../../io/code_output.dart';
 import '../../io/line_column_provider.dart'
@@ -110,10 +110,7 @@
   final InterceptorEmitter interceptorEmitter;
 
   // TODO(johnniwinther): Wrap these fields in a caching strategy.
-  final Set<ConstantValue> cachedEmittedConstants;
   final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[];
-  final Map<Element, ClassBuilder> cachedClassBuilders;
-  final Set<Element> cachedElements;
 
   bool needsClassSupport = false;
   bool needsMixinSupport = false;
@@ -180,9 +177,6 @@
       this.generateSourceMap, this.task)
       : this.compiler = compiler,
         this.namer = namer,
-        cachedEmittedConstants = compiler.cacheStrategy.newSet(),
-        cachedClassBuilders = compiler.cacheStrategy.newMap(),
-        cachedElements = compiler.cacheStrategy.newSet(),
         classEmitter = new ClassEmitter(closedWorld),
         interceptorEmitter = new InterceptorEmitter(closedWorld),
         nsmEmitter = new NsmEmitter(closedWorld) {
@@ -192,14 +186,6 @@
     classEmitter.emitter = this;
     nsmEmitter.emitter = this;
     interceptorEmitter.emitter = this;
-    if (compiler.options.hasIncrementalSupport) {
-      // Much like a scout, an incremental compiler is always prepared. For
-      // mixins, classes, and lazy statics, at least.
-      needsClassSupport = true;
-      needsMixinSupport = true;
-      needsLazyInitializer = true;
-      needsStructuredMemberInfo = true;
-    }
   }
 
   DiagnosticReporter get reporter => compiler.reporter;
@@ -215,13 +201,6 @@
         outputUnit, () => new List<jsAst.Expression>());
   }
 
-  /// Erases the precompiled information for csp mode for all output units.
-  /// Used by the incremental compiler.
-  void clearCspPrecompiledNodes() {
-    _cspPrecompiledFunctions.clear();
-    _cspPrecompiledConstructorNames.clear();
-  }
-
   @override
   bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
     if (constant.isFunction) return true; // Already emitted.
@@ -596,21 +575,7 @@
       Class cls, ClassBuilder enclosingBuilder, Fragment fragment) {
     ClassElement classElement = cls.element;
     reporter.withCurrentElement(classElement, () {
-      if (compiler.options.hasIncrementalSupport) {
-        ClassBuilder cachedBuilder =
-            cachedClassBuilders.putIfAbsent(classElement, () {
-          ClassBuilder builder = new ClassBuilder.forClass(classElement, namer);
-          classEmitter.emitClass(cls, builder, fragment);
-          return builder;
-        });
-        invariant(classElement, cachedBuilder.fields.isEmpty);
-        invariant(classElement, cachedBuilder.superName == null);
-        invariant(classElement, cachedBuilder.functionType == null);
-        invariant(classElement, cachedBuilder.fieldMetadata == null);
-        enclosingBuilder.properties.addAll(cachedBuilder.properties);
-      } else {
-        classEmitter.emitClass(cls, enclosingBuilder, fragment);
-      }
+      classEmitter.emitClass(cls, enclosingBuilder, fragment);
     });
   }
 
@@ -741,50 +706,6 @@
     return laziesInfo;
   }
 
-  // TODO(sra): Remove this unused function.
-  jsAst.Expression buildLazilyInitializedStaticField(VariableElement element,
-      {String isolateProperties}) {
-    jsAst.Expression code = backend.generatedCode[element];
-    // The code is null if we ended up not needing the lazily
-    // initialized field after all because of constant folding
-    // before code generation.
-    if (code == null) return null;
-    // The code only computes the initial value. We build the lazy-check
-    // here:
-    //   lazyInitializer(fieldName, getterName, initial, name, prototype);
-    // The name is used for error reporting. The 'initial' must be a
-    // closure that constructs the initial value.
-    if (isolateProperties != null) {
-      // This is currently only used in incremental compilation to patch
-      // in new lazy values.
-      return js('#(#,#,#,#,#)', [
-        js(lazyInitializerName),
-        js.quoteName(namer.globalPropertyName(element)),
-        js.quoteName(namer.lazyInitializerName(element)),
-        code,
-        js.string(element.name),
-        isolateProperties
-      ]);
-    }
-
-    if (compiler.options.enableMinification) {
-      return js('#(#,#,#)', [
-        js(lazyInitializerName),
-        js.quoteName(namer.globalPropertyName(element)),
-        js.quoteName(namer.lazyInitializerName(element)),
-        code
-      ]);
-    } else {
-      return js('#(#,#,#,#)', [
-        js(lazyInitializerName),
-        js.quoteName(namer.globalPropertyName(element)),
-        js.quoteName(namer.lazyInitializerName(element)),
-        code,
-        js.string(element.name)
-      ]);
-    }
-  }
-
   jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) {
     List<jsAst.Statement> parts = <jsAst.Statement>[];
 
@@ -811,15 +732,8 @@
 
     if (constants.isEmpty) return js.comment("No constants in program.");
     List<jsAst.Statement> parts = <jsAst.Statement>[];
-    if (compiler.options.hasIncrementalSupport && isMainFragment) {
-      parts = cachedEmittedConstantsAst;
-    }
     for (Constant constant in constants) {
       ConstantValue constantValue = constant.value;
-      if (compiler.options.hasIncrementalSupport && isMainFragment) {
-        if (cachedEmittedConstants.contains(constantValue)) continue;
-        cachedEmittedConstants.add(constantValue);
-      }
       parts.add(buildConstantInitializer(constantValue));
     }
 
@@ -1017,10 +931,6 @@
           }
           Isolate.#functionThatReturnsNullProperty =
               oldIsolate.#functionThatReturnsNullProperty;
-          if (#hasIncrementalSupport) {
-            Isolate.#lazyInitializerProperty =
-                oldIsolate.#lazyInitializerProperty;
-          }
           return Isolate;
       }
 
@@ -1039,8 +949,6 @@
           'makeConstListProperty': makeConstListProperty,
           'functionThatReturnsNullProperty':
               backend.rtiEncoder.getFunctionThatReturnsNullName,
-          'hasIncrementalSupport': compiler.options.hasIncrementalSupport,
-          'lazyInitializerProperty': lazyInitializerProperty,
         });
   }
 
@@ -1088,40 +996,34 @@
   jsAst.Statement buildSupportsDirectProtoAccess() {
     jsAst.Statement supportsDirectProtoAccess;
 
-    if (compiler.options.hasIncrementalSupport) {
-      supportsDirectProtoAccess = js.statement(r'''
-        var supportsDirectProtoAccess = false;
-      ''');
-    } else {
-      supportsDirectProtoAccess = js.statement(r'''
-        var supportsDirectProtoAccess = (function () {
-          var cls = function () {};
-          cls.prototype = {'p': {}};
-          var object = new cls();
-          if (!(object.__proto__ && object.__proto__.p === cls.prototype.p))
-            return false;
-    
-          try {
-            // Are we running on a platform where the performance is good?
-            // (i.e. Chrome or d8).
-
-            // Chrome userAgent?
-            if (typeof navigator != "undefined" &&
-                typeof navigator.userAgent == "string" &&
-                navigator.userAgent.indexOf("Chrome/") >= 0) return true;
-
-            // d8 version() looks like "N.N.N.N", jsshell version() like "N".
-            if (typeof version == "function" &&
-                version.length == 0) {
-              var v = version();
-              if (/^\d+\.\d+\.\d+\.\d+$/.test(v)) return true;
-            }
-          } catch(_) {}
-          
+    supportsDirectProtoAccess = js.statement(r'''
+      var supportsDirectProtoAccess = (function () {
+        var cls = function () {};
+        cls.prototype = {'p': {}};
+        var object = new cls();
+        if (!(object.__proto__ && object.__proto__.p === cls.prototype.p))
           return false;
-        })();
-      ''');
-    }
+
+        try {
+          // Are we running on a platform where the performance is good?
+          // (i.e. Chrome or d8).
+
+          // Chrome userAgent?
+          if (typeof navigator != "undefined" &&
+              typeof navigator.userAgent == "string" &&
+              navigator.userAgent.indexOf("Chrome/") >= 0) return true;
+
+          // d8 version() looks like "N.N.N.N", jsshell version() like "N".
+          if (typeof version == "function" &&
+              version.length == 0) {
+            var v = version();
+            if (/^\d+\.\d+\.\d+\.\d+$/.test(v)) return true;
+          }
+        } catch(_) {}
+
+        return false;
+      })();
+    ''');
 
     return supportsDirectProtoAccess;
   }
@@ -1379,14 +1281,11 @@
   }
 
   void checkEverythingEmitted(Iterable<Element> elements) {
-    List<Element> pendingStatics;
-    if (!compiler.options.hasIncrementalSupport) {
-      pendingStatics =
-          Elements.sortedByPosition(elements.where((e) => !e.isLibrary));
+    List<Element> pendingStatics =
+        Elements.sortedByPosition(elements.where((e) => !e.isLibrary));
 
-      pendingStatics.forEach((element) => reporter.reportInfo(
-          element, MessageKind.GENERIC, {'text': 'Pending statics.'}));
-    }
+    pendingStatics.forEach((element) => reporter.reportInfo(
+        element, MessageKind.GENERIC, {'text': 'Pending statics.'}));
 
     if (pendingStatics != null && !pendingStatics.isEmpty) {
       reporter.internalError(
@@ -1465,8 +1364,7 @@
       // The program builder does not collect libraries that only
       // contain typedefs that are used for reflection.
       for (LibraryElement element in remainingLibraries) {
-        assert(element is LibraryElement ||
-            compiler.options.hasIncrementalSupport);
+        assert(element is LibraryElement);
         if (element is LibraryElement) {
           parts.add(generateLibraryDescriptor(element, mainFragment));
           descriptors.remove(element);
@@ -1486,19 +1384,6 @@
        #disableVariableRenaming;
        #supportsDirectProtoAccess;
 
-       if (#hasIncrementalSupport) {
-         #helper = #helper || Object.create(null);
-         #helper.patch = function(a) { eval(a)};
-         #helper.schemaChange = #schemaChange;
-         #helper.addMethod = #addMethod;
-         #helper.extractStubs =
-           function(array, name, isStatic, originalDescriptor) {
-             var descriptor = Object.create(null);
-             this.addStubs(descriptor, array, name, isStatic, []);
-             return descriptor;
-            };
-       }
-
        if (#isProgramSplit) {
          /// We collect all the global state, so it can be passed to the
          /// initializer of deferred files.
@@ -1591,10 +1476,6 @@
     """,
         {
           "disableVariableRenaming": js.comment("/* ::norenaming:: */"),
-          "hasIncrementalSupport": compiler.options.hasIncrementalSupport,
-          "helper": js('this.#', [namer.incrementalHelperName]),
-          "schemaChange": buildSchemaChangeFunction(),
-          "addMethod": buildIncrementalAddMethod(),
           "isProgramSplit": isProgramSplit,
           "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(),
           "globalsHolder": globalsHolder,
@@ -1670,123 +1551,6 @@
     }
   }
 
-  /// Used by incremental compilation to patch up the prototype of
-  /// [oldConstructor] for use as prototype of [newConstructor].
-  jsAst.Fun buildSchemaChangeFunction() {
-    if (!compiler.options.hasIncrementalSupport) return null;
-    return js('''
-function(newConstructor, oldConstructor, superclass) {
-  // Invariant: newConstructor.prototype has no interesting properties besides
-  // generated accessors. These are copied to oldPrototype which will be
-  // updated by other incremental changes.
-  if (superclass != null) {
-    this.inheritFrom(newConstructor, superclass);
-  }
-  var oldPrototype = oldConstructor.prototype;
-  var newPrototype = newConstructor.prototype;
-  var hasOwnProperty = Object.prototype.hasOwnProperty;
-  for (var property in newPrototype) {
-    if (hasOwnProperty.call(newPrototype, property)) {
-      // Copy generated accessors.
-      oldPrototype[property] = newPrototype[property];
-    }
-  }
-  oldPrototype.__proto__ = newConstructor.prototype.__proto__;
-  oldPrototype.constructor = newConstructor;
-  newConstructor.prototype = oldPrototype;
-  return newConstructor;
-}''');
-  }
-
-  /// Used by incremental compilation to patch up an object ([holder]) with a
-  /// new (or updated) method.  [arrayOrFunction] is either the new method, or
-  /// an array containing the method (see
-  /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the
-  /// new method. [isStatic] tells if method is static (or
-  /// top-level). [globalFunctionsAccess] is a reference to
-  /// [embeddedNames.GLOBAL_FUNCTIONS].
-  jsAst.Fun buildIncrementalAddMethod() {
-    if (!compiler.options.hasIncrementalSupport) return null;
-    return js(r"""
-function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
-  var arrayOrFunction = originalDescriptor[name];
-  var method;
-  if (arrayOrFunction.constructor === Array) {
-    var existing = holder[name];
-    var array = arrayOrFunction;
-
-    // Each method may have a number of stubs associated. For example, if an
-    // instance method supports multiple arguments, a stub for each matching
-    // selector. There is also a getter stub for tear-off getters. For example,
-    // an instance method foo([a]) may have the following stubs: foo$0, foo$1,
-    // and get$foo (here exemplified using unminified names).
-    // [extractStubs] returns a JavaScript object whose own properties
-    // corresponds to the stubs.
-    var descriptor =
-        this.extractStubs(array, name, isStatic, originalDescriptor);
-    method = descriptor[name];
-
-    // Iterate through the properties of descriptor and copy the stubs to the
-    // existing holder (for instance methods, a prototype).
-    for (var property in descriptor) {
-      if (!Object.prototype.hasOwnProperty.call(descriptor, property)) continue;
-      var stub = descriptor[property];
-      var existingStub = holder[property];
-      if (stub === method || !existingStub || !stub.$getterStub) {
-        // Not replacing an existing getter stub.
-        holder[property] = stub;
-        continue;
-      }
-      if (!stub.$getterStub) {
-        var error = new Error('Unexpected stub.');
-        error.stub = stub;
-        throw error;
-      }
-
-      // Existing getter stubs need special treatment as they may already have
-      // been called and produced a closure.
-      this.pendingStubs = this.pendingStubs || [];
-      // It isn't safe to invoke the stub yet.
-      this.pendingStubs.push((function(holder, stub, existingStub, existing,
-                                       method) {
-        return function() {
-          var receiver = isStatic ? holder : new holder.constructor();
-          // Invoke the existing stub to obtain the tear-off closure.
-          existingStub = existingStub.call(receiver);
-          // Invoke the new stub to create a tear-off closure we can use as a
-          // prototype.
-          stub = stub.call(receiver);
-
-          // Copy the properties from the new tear-off's prototype to the
-          // prototype of the existing tear-off.
-          var newProto = stub.constructor.prototype;
-          var existingProto = existingStub.constructor.prototype;
-          for (var stubProperty in newProto) {
-            if (!Object.prototype.hasOwnProperty.call(newProto, stubProperty))
-              continue;
-            existingProto[stubProperty] = newProto[stubProperty];
-          }
-
-          // Update all the existing stub's references to [existing] to
-          // [method]. Instance tear-offs are call-by-name, so this isn't
-          // necessary for those.
-          if (!isStatic) return;
-          for (var reference in existingStub) {
-            if (existingStub[reference] === existing) {
-              existingStub[reference] = method;
-            }
-          }
-        }
-      })(holder, stub, existingStub, existing, method));
-    }
-  } else {
-    method = arrayOrFunction;
-    holder[name] = method;
-  }
-  if (isStatic) globalFunctionsAccess[name] = method;
-}""");
-  }
-
   Map<OutputUnit, jsAst.Expression> buildDescriptorsForOutputUnits(
       Program program) {
     Map<OutputUnit, jsAst.Expression> outputs =
@@ -2178,14 +1942,4 @@
       ..add(const JsonEncoder.withIndent("  ").convert(mapping))
       ..close();
   }
-
-  void invalidateCaches() {
-    if (!compiler.options.hasIncrementalSupport) return;
-    if (cachedElements.isEmpty) return;
-    for (Element element in backend.codegenEnqueuer.newlyEnqueuedElements) {
-      if (element.isInstanceMember) {
-        cachedClassBuilders.remove(element.enclosingClass);
-      }
-    }
-  }
 }
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
index 516641d..2b7c16f 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
@@ -20,7 +20,7 @@
   InterceptorEmitter(this.closedWorld);
 
   void recordMangledNameOfMemberMethod(MemberEntity member, jsAst.Name name) {
-    if (backend.isInterceptedMethod(member)) {
+    if (backend.interceptorData.isInterceptedMethod(member)) {
       interceptorInvocationNames.add(name);
     }
   }
@@ -44,12 +44,12 @@
     parts.add(js.comment('getInterceptor methods'));
 
     Map<jsAst.Name, Set<ClassEntity>> specializedGetInterceptors =
-        backend.specializedGetInterceptors;
+        backend.interceptorData.specializedGetInterceptors;
     List<jsAst.Name> names = specializedGetInterceptors.keys.toList()..sort();
     for (jsAst.Name name in names) {
       Set<ClassEntity> classes = specializedGetInterceptors[name];
       parts.add(js.statement('#.# = #', [
-        namer.globalObjectFor(backend.helpers.interceptorsLibrary),
+        namer.globalObjectForLibrary(backend.helpers.interceptorsLibrary),
         name,
         buildGetInterceptorMethod(name, classes)
       ]));
@@ -60,13 +60,13 @@
 
   jsAst.Statement buildOneShotInterceptors() {
     List<jsAst.Statement> parts = <jsAst.Statement>[];
-    Iterable<jsAst.Name> names = backend.oneShotInterceptors.keys.toList()
-      ..sort();
+    Iterable<jsAst.Name> names =
+        backend.interceptorData.oneShotInterceptors.keys.toList()..sort();
 
     InterceptorStubGenerator stubGenerator =
         new InterceptorStubGenerator(compiler, namer, backend, closedWorld);
     String globalObject =
-        namer.globalObjectFor(backend.helpers.interceptorsLibrary);
+        namer.globalObjectForLibrary(backend.helpers.interceptorsLibrary);
     for (jsAst.Name name in names) {
       jsAst.Expression function =
           stubGenerator.generateOneShotInterceptor(name);
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
index 472a2c7..5b0fa47 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
@@ -9,7 +9,8 @@
 import '../../js/js.dart' show js;
 import '../../js_backend/js_backend.dart' show GetterName, SetterName;
 import '../../universe/selector.dart' show Selector;
-import '../../util/characters.dart' show $$, $A, $HASH, $Z, $a, $z;
+import 'package:front_end/src/fasta/scanner/characters.dart'
+    show $$, $A, $HASH, $Z, $a, $z;
 import '../../world.dart' show ClosedWorld;
 import '../js_emitter.dart' hide Emitter, EmitterFactory;
 import '../model.dart';
@@ -141,10 +142,10 @@
 
     // Find out how many selectors there are with the special calling
     // convention.
-    Iterable<Selector> interceptedSelectors = trivialNsmHandlers
-        .where((Selector s) => backend.isInterceptedName(s.name));
-    Iterable<Selector> ordinarySelectors = trivialNsmHandlers
-        .where((Selector s) => !backend.isInterceptedName(s.name));
+    Iterable<Selector> interceptedSelectors = trivialNsmHandlers.where(
+        (Selector s) => backend.interceptorData.isInterceptedName(s.name));
+    Iterable<Selector> ordinarySelectors = trivialNsmHandlers.where(
+        (Selector s) => !backend.interceptorData.isInterceptedName(s.name));
 
     // Get the short names (JS names, perhaps minified).
     Iterable<jsAst.Name> interceptedShorts =
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
index a8dc281..402845b 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
@@ -111,8 +111,6 @@
     'deferredAction': namer.deferredAction,
     'hasIsolateSupport': program.hasIsolateSupport,
     'fieldNamesProperty': js.string(Emitter.FIELD_NAMES_PROPERTY_NAME),
-    'hasIncrementalSupport': compiler.options.hasIncrementalSupport,
-    'incrementalHelper': namer.accessIncrementalHelper,
     'createNewIsolateFunction': createNewIsolateFunctionAccess,
     'isolateName': namer.isolateName,
     'classIdExtractor': classIdExtractorAccess,
@@ -256,10 +254,6 @@
       return str;
     }
 
-    if (#hasIncrementalSupport) {
-      #incrementalHelper.defineClass = defineClass;
-    }
-
     if (#hasIsolateSupport) {
       #createNewIsolateFunction = function() { return new #isolateName(); };
 
@@ -318,10 +312,6 @@
         };
       }();
 
-     if (#hasIncrementalSupport) {
-       #incrementalHelper.inheritFrom = inheritFrom;
-     }
-
     // Class descriptions are collected in a JS object.
     // 'finishClasses' takes all collected descriptions and sets up
     // the prototype.
@@ -762,10 +752,6 @@
     #tearOffCode;
   }
 
-  if (#hasIncrementalSupport) {
-    #incrementalHelper.addStubs = addStubs;
-  }
-
   var functionCounter = 0;
   if (!#libraries) #libraries = [];
   if (!#mangledNames) #mangledNames = map();
diff --git a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
index 7c3337e..a7853e1 100644
--- a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
@@ -46,7 +46,7 @@
      */
     jsAst.Statement buildInterceptorCheck(ClassEntity cls) {
       jsAst.Expression condition;
-      assert(backend.isInterceptorClass(cls));
+      assert(backend.interceptorData.isInterceptorClass(cls));
       if (cls == helpers.jsBoolClass) {
         condition = js('(typeof receiver) == "boolean"');
       } else if (cls == helpers.jsIntClass ||
@@ -108,7 +108,7 @@
         // unresolved PlainJavaScriptObject by testing for anyNativeClasses.
 
         if (anyNativeClasses) {
-          if (backend.isNativeOrExtendsNative(cls)) hasNative = true;
+          if (backend.nativeData.isNativeOrExtendsNative(cls)) hasNative = true;
         }
       }
     }
@@ -117,7 +117,7 @@
     }
     if (hasInt) hasNumber = true;
 
-    if (classes.containsAll(backend.interceptedClasses)) {
+    if (classes.containsAll(backend.interceptorData.interceptedClasses)) {
       // I.e. this is the general interceptor.
       hasNative = anyNativeClasses;
     }
@@ -268,7 +268,7 @@
       bool containsArray = classes.contains(helpers.jsArrayClass);
       bool containsString = classes.contains(helpers.jsStringClass);
       bool containsJsIndexable =
-          helpers.jsIndexingBehaviorInterface.isResolved &&
+          closedWorld.isImplemented(helpers.jsIndexingBehaviorInterface) &&
               classes.any((cls) {
                 return closedWorld.isSubtypeOf(
                     cls, helpers.jsIndexingBehaviorInterface);
@@ -337,8 +337,9 @@
   }
 
   jsAst.Expression generateOneShotInterceptor(jsAst.Name name) {
-    Selector selector = backend.oneShotInterceptors[name];
-    Set<ClassEntity> classes = backend.getInterceptedClassesOn(selector.name);
+    Selector selector = backend.interceptorData.oneShotInterceptors[name];
+    Set<ClassEntity> classes =
+        backend.interceptorData.getInterceptedClassesOn(selector.name);
     jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes);
 
     List<String> parameterNames = <String>[];
@@ -353,7 +354,8 @@
     }
 
     jsAst.Name invocationName = backend.namer.invocationName(selector);
-    String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary);
+    String globalObject =
+        namer.globalObjectForLibrary(helpers.interceptorsLibrary);
 
     jsAst.Statement optimizedPath =
         _fastPathForOneShotInterceptor(selector, classes);
@@ -404,7 +406,7 @@
         //
         // We expect most of the time the map will be a singleton.
         var properties = [];
-        for (FunctionEntity member in analysis.constructors(classElement)) {
+        for (ConstructorEntity member in analysis.constructors(classElement)) {
           properties.add(new jsAst.Property(js.string(member.name),
               backend.emitter.staticFunctionAccess(member)));
         }
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
index ab86f53..ab8d4e5 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
@@ -11,7 +11,8 @@
 import '../../constants/values.dart' show ConstantValue;
 import '../../deferred_load.dart' show OutputUnit;
 import '../../elements/elements.dart'
-    show ClassElement, Element, Entity, FieldElement, MethodElement;
+    show ClassElement, Element, FieldElement, MethodElement;
+import '../../elements/entities.dart';
 import '../../js/js.dart' as js;
 import '../../js_backend/js_backend.dart' show JavaScriptBackend, Namer;
 import '../../world.dart' show ClosedWorld;
@@ -191,7 +192,4 @@
   @override
   // TODO(het): Generate this correctly
   int generatedSize(OutputUnit unit) => 0;
-
-  @override
-  void invalidateCaches() {}
 }
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index 570526a..b72351f 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
@@ -861,7 +861,8 @@
 
         if (method.needsTearOff) {
           MethodElement element = method.element;
-          bool isIntercepted = backend.isInterceptedMethod(element);
+          bool isIntercepted =
+              backend.interceptorData.isInterceptedMethod(element);
           data.add(new js.LiteralBool(isIntercepted));
           data.add(js.quoteName(method.tearOffName));
           data.add((method.functionType));
diff --git a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
index 3586026..8b77975 100644
--- a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
@@ -17,10 +17,8 @@
 class MainCallStubGenerator {
   final JavaScriptBackend backend;
   final CodeEmitterTask emitterTask;
-  final bool hasIncrementalSupport;
 
-  MainCallStubGenerator(this.backend, this.emitterTask,
-      {this.hasIncrementalSupport: false});
+  MainCallStubGenerator(this.backend, this.emitterTask);
 
   BackendHelpers get helpers => backend.helpers;
 
@@ -41,9 +39,6 @@
     if (backend.hasIsolateSupport) {
       FunctionEntity isolateMain = helpers.startRootIsolate;
       mainCallClosure = _buildIsolateSetupClosure(main, isolateMain);
-    } else if (hasIncrementalSupport) {
-      mainCallClosure = js(
-          'function() { return #(); }', emitterTask.staticFunctionAccess(main));
     } else {
       mainCallClosure = emitterTask.staticFunctionAccess(main);
     }
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 6c84560..ba57077 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -116,8 +116,7 @@
   jsAst.Expression _value;
 
   void setExpression(jsAst.Expression value) {
-    // TODO(herhut): Enable the below assertion once incremental mode is gone.
-    // assert(_value == null);
+    assert(_value == null);
     assert(value.precedenceLevel == this.precedenceLevel);
     _value = value;
   }
@@ -156,12 +155,6 @@
   Map<OutputUnit, Map<ResolutionDartType, _BoundMetadataEntry>> _typesMap =
       <OutputUnit, Map<ResolutionDartType, _BoundMetadataEntry>>{};
 
-  // To support incremental compilation, we have to be able to eagerly emit
-  // metadata and add metadata later on. We use the below two counters for
-  // this.
-  int _globalMetadataCounter = 0;
-  int _globalTypesCounter = 0;
-
   MetadataCollector(this._compiler, this._emitter) {
     _globalMetadataMap = new Map<String, _BoundMetadataEntry>();
   }
@@ -320,11 +313,7 @@
     String printed =
         jsAst.prettyPrint(node, _compiler, renamerForNames: nameToKey);
     return _globalMetadataMap.putIfAbsent(printed, () {
-      _BoundMetadataEntry result = new _BoundMetadataEntry(node);
-      if (_compiler.options.hasIncrementalSupport) {
-        result.finalize(_globalMetadataCounter++);
-      }
-      return result;
+      return new _BoundMetadataEntry(node);
     });
   }
 
@@ -356,13 +345,8 @@
           new Map<ResolutionDartType, _BoundMetadataEntry>();
     }
     return _typesMap[outputUnit].putIfAbsent(type, () {
-      _BoundMetadataEntry result = new _BoundMetadataEntry(
-          _computeTypeRepresentation(type,
-              ignoreTypeVariables: ignoreTypeVariables));
-      if (_compiler.options.hasIncrementalSupport) {
-        result.finalize(_globalTypesCounter++);
-      }
-      return result;
+      return new _BoundMetadataEntry(_computeTypeRepresentation(type,
+          ignoreTypeVariables: ignoreTypeVariables));
     });
   }
 
@@ -399,11 +383,6 @@
     }
 
     jsAst.ArrayInitializer finalizeMap(Map<dynamic, _BoundMetadataEntry> map) {
-      // When in incremental mode, we allocate entries eagerly.
-      if (_compiler.options.hasIncrementalSupport) {
-        return new jsAst.ArrayInitializer(map.values.toList());
-      }
-
       bool isUsed(_BoundMetadataEntry entry) => entry.isUsed;
       List<_BoundMetadataEntry> entries = map.values.where(isUsed).toList();
       entries.sort();
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index c49895a..ef26ac6 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -346,7 +346,8 @@
   }
 
   bool isSupertypeOfNativeClass(ClassEntity element) {
-    if (backend.classesMixedIntoInterceptedClasses.contains(element)) {
+    if (backend.interceptorData.classesMixedIntoInterceptedClasses
+        .contains(element)) {
       return true;
     }
 
@@ -361,7 +362,7 @@
     // the type info.  i.e the criteria for whether or not to use an interceptor
     // is whether the receiver can be native, not the type of the test.
     ClassEntity cls = element;
-    if (backend.isNativeOrExtendsNative(cls)) return true;
+    if (backend.nativeData.isNativeOrExtendsNative(cls)) return true;
     return isSupertypeOfNativeClass(element);
   }
 }
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index 0e5d681..0dc23cf 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -81,7 +81,8 @@
     JavaScriptConstantCompiler handler = backend.constants;
     List<String> names = callStructure.getOrderedNamedArguments();
 
-    bool isInterceptedMethod = backend.isInterceptedMethod(member);
+    bool isInterceptedMethod =
+        backend.interceptorData.isInterceptedMethod(member);
 
     // If the method is intercepted, we need to also pass the actual receiver.
     int extraArgumentCount = isInterceptedMethod ? 1 : 0;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
index 01b3a99..48b333c 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
@@ -78,7 +78,7 @@
     // Go over specialized interceptors and then constants to know which
     // interceptors are needed.
     Set<ClassElement> needed = new Set<ClassElement>();
-    backend.specializedGetInterceptors
+    backend.interceptorData.specializedGetInterceptors
         .forEach((_, Iterable<ClassElement> elements) {
       needed.addAll(elements);
     });
@@ -87,7 +87,8 @@
     needed.addAll(computeInterceptorsReferencedFromConstants());
 
     // Add unneeded interceptors to the [unneededClasses] set.
-    for (ClassElement interceptor in backend.interceptedClasses) {
+    for (ClassElement interceptor
+        in backend.interceptorData.interceptedClasses) {
       if (!needed.contains(interceptor) &&
           interceptor != commonElements.objectClass) {
         unneededClasses.add(interceptor);
@@ -145,10 +146,8 @@
     }
 
     JavaScriptConstantCompiler handler = backend.constants;
-    List<ConstantValue> constants = handler.getConstantsForEmission(
-        compiler.options.hasIncrementalSupport
-            ? null
-            : emitter.compareConstants);
+    List<ConstantValue> constants =
+        handler.getConstantsForEmission(emitter.compareConstants);
     for (ConstantValue constant in constants) {
       if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue;
 
@@ -245,7 +244,7 @@
     List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
 
     for (ClassElement element in sortedClasses) {
-      if (backend.isNativeOrExtendsNative(element) &&
+      if (backend.nativeData.isNativeOrExtendsNative(element) &&
           !classesOnlyNeededForRti.contains(element)) {
         // For now, native classes and related classes cannot be deferred.
         nativeClassesAndSubclasses.add(element);
@@ -281,7 +280,6 @@
   }
 
   void computeNeededStaticNonFinalFields() {
-    JavaScriptConstantCompiler handler = backend.constants;
     addToOutputUnit(Element element) {
       List<VariableElement> list = outputStaticNonFinalFieldLists.putIfAbsent(
           compiler.deferredLoadTask.outputUnitForElement(element),
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 79eff9a..5092d19 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
@@ -183,7 +183,7 @@
     List<js.TokenFinalizer> finalizers = [_task.metadataCollector];
     if (backend.namer is js.TokenFinalizer) {
       var namingFinalizer = backend.namer;
-      finalizers.add(namingFinalizer);
+      finalizers.add(namingFinalizer as js.TokenFinalizer);
     }
 
     return new Program(fragments, holders, _buildLoadMap(), _symbolsMap,
@@ -232,9 +232,8 @@
   js.Statement _buildInvokeMain() {
     if (_compiler.isMockCompilation) return js.js.comment("Mock compilation");
 
-    MainCallStubGenerator generator = new MainCallStubGenerator(
-        backend, backend.emitter,
-        hasIncrementalSupport: _compiler.options.hasIncrementalSupport);
+    MainCallStubGenerator generator =
+        new MainCallStubGenerator(backend, backend.emitter);
     return generator.generateInvokeMain(_compiler.mainFunction);
   }
 
@@ -492,23 +491,6 @@
         library, uri, statics, classes, staticFieldsForReflection);
   }
 
-  /// HACK for Incremental Compilation.
-  ///
-  /// Returns a class that contains the fields of a class.
-  Class buildFieldsHackForIncrementalCompilation(ClassElement element) {
-    assert(_compiler.options.hasIncrementalSupport);
-
-    List<Field> instanceFields = _buildFields(element, false);
-    js.Name name = namer.className(element);
-
-    return new Class(
-        element, name, null, [], instanceFields, [], [], [], [], [], [], null,
-        isDirectlyInstantiated: true,
-        hasRtiField: backend.classNeedsRtiField(element),
-        onlyForRti: false,
-        isNative: backend.isNative(element));
-  }
-
   Class _buildClass(ClassElement element) {
     bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
     bool hasRtiField = backend.classNeedsRtiField(element);
@@ -673,10 +655,7 @@
   }
 
   bool _methodCanBeReflected(FunctionElement method) {
-    return backend.isAccessibleByReflection(method) ||
-        // During incremental compilation, we have to assume that reflection
-        // *might* get enabled.
-        _compiler.options.hasIncrementalSupport;
+    return backend.isAccessibleByReflection(method);
   }
 
   bool _methodCanBeApplied(FunctionElement method) {
@@ -684,16 +663,6 @@
         closedWorld.getMightBePassedToApply(method);
   }
 
-  // TODO(herhut): Refactor incremental compilation and remove method.
-  Method buildMethodHackForIncrementalCompilation(FunctionElement element) {
-    assert(_compiler.options.hasIncrementalSupport);
-    if (element.isInstanceMember) {
-      return _buildMethod(element);
-    } else {
-      return _buildStaticMethod(element);
-    }
-  }
-
   /* Map | List */ _computeParameterDefaultValues(FunctionSignature signature) {
     var /* Map | List */ optionalParameterDefaultValues;
     if (signature.optionalParametersAreNamed) {
@@ -837,7 +806,7 @@
   // accessible.
   void _markEagerInterceptorClasses() {
     Map<js.Name, Set<ClassElement>> specializedGetInterceptors =
-        backend.specializedGetInterceptors;
+        backend.interceptorData.specializedGetInterceptors;
     for (Set<ClassElement> classes in specializedGetInterceptors.values) {
       for (ClassElement element in classes) {
         Class cls = _classes[element];
@@ -850,13 +819,14 @@
     InterceptorStubGenerator stubGenerator =
         new InterceptorStubGenerator(_compiler, namer, backend, closedWorld);
 
-    String holderName = namer.globalObjectFor(helpers.interceptorsLibrary);
+    String holderName =
+        namer.globalObjectForLibrary(helpers.interceptorsLibrary);
     // TODO(floitsch): we shouldn't update the registry in the middle of
     // generating the interceptor methods.
     Holder holder = _registry.registerHolder(holderName);
 
     Map<js.Name, Set<ClassElement>> specializedGetInterceptors =
-        backend.specializedGetInterceptors;
+        backend.interceptorData.specializedGetInterceptors;
     List<js.Name> names = specializedGetInterceptors.keys.toList()..sort();
     return names.map((js.Name name) {
       Set<ClassElement> classes = specializedGetInterceptors[name];
@@ -878,14 +848,15 @@
 
       int getterFlags = 0;
       if (needsGetter) {
-        if (visitStatics || !backend.fieldHasInterceptedGetter(field)) {
+        if (visitStatics ||
+            !backend.interceptorData.fieldHasInterceptedGetter(field)) {
           getterFlags = 1;
         } else {
           getterFlags += 2;
           // TODO(sra): 'isInterceptorClass' might not be the correct test
           // for methods forced to use the interceptor convention because
           // the method's class was elsewhere mixed-in to an interceptor.
-          if (!backend.isInterceptorClass(holder)) {
+          if (!backend.interceptorData.isInterceptorClass(holder)) {
             getterFlags += 1;
           }
         }
@@ -893,11 +864,12 @@
 
       int setterFlags = 0;
       if (needsSetter) {
-        if (visitStatics || !backend.fieldHasInterceptedSetter(field)) {
+        if (visitStatics ||
+            !backend.interceptorData.fieldHasInterceptedSetter(field)) {
           setterFlags = 1;
         } else {
           setterFlags += 2;
-          if (!backend.isInterceptorClass(holder)) {
+          if (!backend.interceptorData.isInterceptorClass(holder)) {
             setterFlags += 1;
           }
         }
@@ -914,12 +886,14 @@
     InterceptorStubGenerator stubGenerator =
         new InterceptorStubGenerator(_compiler, namer, backend, closedWorld);
 
-    String holderName = namer.globalObjectFor(helpers.interceptorsLibrary);
+    String holderName =
+        namer.globalObjectForLibrary(helpers.interceptorsLibrary);
     // TODO(floitsch): we shouldn't update the registry in the middle of
     // generating the interceptor methods.
     Holder holder = _registry.registerHolder(holderName);
 
-    List<js.Name> names = backend.oneShotInterceptors.keys.toList()..sort();
+    List<js.Name> names =
+        backend.interceptorData.oneShotInterceptors.keys.toList()..sort();
     return names.map((js.Name name) {
       js.Expression code = stubGenerator.generateOneShotInterceptor(name);
       return new StaticStubMethod(name, holder, code);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 6fa1d3b..79c1e74 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -201,7 +201,4 @@
         .firstWhere((Fragment fragment) => fragment.outputUnit == unit);
     return _emitter.outputBuffers[key].length;
   }
-
-  @override
-  void invalidateCaches() {}
 }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index bd3a080..613336b 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -966,7 +966,7 @@
     bool isIntercepted = false;
     if (method is InstanceMethod) {
       MethodElement element = method.element;
-      isIntercepted = backend.isInterceptedMethod(element);
+      isIntercepted = backend.interceptorData.isInterceptedMethod(element);
     }
     int requiredParameterCount = 0;
     js.Expression optionalParameterDefaultValues = new js.LiteralNull();
diff --git a/pkg/compiler/lib/src/kernel/constant_visitor.dart b/pkg/compiler/lib/src/kernel/constant_visitor.dart
index 3d0405d..239bf88 100644
--- a/pkg/compiler/lib/src/kernel/constant_visitor.dart
+++ b/pkg/compiler/lib/src/kernel/constant_visitor.dart
@@ -5,6 +5,7 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../constants/expressions.dart';
+import '../elements/elements.dart' show ConstructorElement;
 import 'kernel.dart';
 
 /// Visitor that converts a [ConstantExpression] into a kernel constant
@@ -78,11 +79,17 @@
   }
 
   @override
-  ir.Node visitVariable(VariableConstantExpression exp, Kernel kernel) {
+  ir.Node visitField(FieldConstantExpression exp, Kernel kernel) {
     return new ir.StaticGet(kernel.fieldToIr(exp.element));
   }
 
   @override
+  ir.Node visitLocalVariable(
+      LocalVariableConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
   ir.Node visitType(TypeConstantExpression exp, Kernel kernel) {
     throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
   }
@@ -114,8 +121,9 @@
       }
     }
     ir.Arguments arguments = new ir.Arguments(positional, named: named);
+    ConstructorElement constructor = exp.target;
     return new ir.ConstructorInvocation(
-        kernel.functionToIr(exp.target), arguments,
+        kernel.functionToIr(constructor), arguments,
         isConst: true);
   }
 
diff --git a/pkg/compiler/lib/src/kernel/element_adapter.dart b/pkg/compiler/lib/src/kernel/element_adapter.dart
new file mode 100644
index 0000000..530e890
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/element_adapter.dart
@@ -0,0 +1,622 @@
+// 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:kernel/ast.dart' as ir;
+
+import '../common.dart';
+import '../common/names.dart';
+import '../constants/constructors.dart';
+import '../constants/expressions.dart';
+import '../core_types.dart';
+import '../elements/elements.dart';
+import '../elements/entities.dart';
+import '../elements/types.dart';
+import '../js_backend/backend_helpers.dart';
+import '../native/native.dart' as native;
+import '../universe/call_structure.dart';
+import '../universe/selector.dart';
+import 'kernel_debug.dart';
+
+/// Interface that translates between Kernel IR nodes and entities.
+abstract class KernelElementAdapter {
+  /// Access to the commonly used elements and types.
+  CommonElements get commonElements;
+
+  // Access to backend helpers.
+  BackendHelpers get helpers;
+
+  /// [ElementEnvironment] for library, class and member lookup.
+  ElementEnvironment get elementEnvironment;
+
+  /// Returns the [DartType] corresponding to [type].
+  DartType getDartType(ir.DartType type);
+
+  /// Returns the list of [DartType]s corresponding to [types].
+  List<DartType> getDartTypes(List<ir.DartType> types);
+
+  /// Returns the [InterfaceType] corresponding to [type].
+  InterfaceType getInterfaceType(ir.InterfaceType type);
+
+  /// Return the [InterfaceType] corresponding to the [cls] with the given
+  /// [typeArguments].
+  InterfaceType createInterfaceType(
+      ir.Class cls, List<ir.DartType> typeArguments);
+
+  /// Returns the [CallStructure] corresponding to the [arguments].
+  CallStructure getCallStructure(ir.Arguments arguments);
+
+  /// Returns the [Selector] corresponding to the invocation or getter/setter
+  /// access of [node].
+  Selector getSelector(ir.Expression node);
+
+  /// Returns the [ConstructorEntity] corresponding to the generative or factory
+  /// constructor [node].
+  ConstructorEntity getConstructor(ir.Member node);
+
+  /// Returns the [MemberEntity] corresponding to the member [node].
+  MemberEntity getMember(ir.Member node);
+
+  /// Returns the [FunctionEntity] corresponding to the procedure [node].
+  FunctionEntity getMethod(ir.Procedure node);
+
+  /// Returns the [FieldEntity] corresponding to the field [node].
+  FieldEntity getField(ir.Field node);
+
+  /// Returns the [ClassEntity] corresponding to the class [node].
+  ClassEntity getClass(ir.Class node);
+
+  /// Returns the [Local] corresponding to the [node]. The node must be either
+  /// a [ir.FunctionDeclaration] or [ir.FunctionExpression].
+  Local getLocalFunction(ir.TreeNode node);
+
+  /// Returns the [LibraryEntity] corresponding to the library [node].
+  LibraryEntity getLibrary(ir.Library node);
+
+  /// Returns the [Name] corresponding to [name].
+  Name getName(ir.Name name);
+
+  /// Returns `true` is [node] has a `@Native(...)` annotation.
+  bool isNativeClass(ir.Class node);
+
+  /// Return `true` if [node] is the `dart:_foreign_helper` library.
+  bool isForeignLibrary(ir.Library node);
+
+  /// Computes the native behavior for reading the native [field].
+  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field);
+
+  /// Computes the native behavior for writing to the native [field].
+  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);
+
+  /// Computes the native behavior for calling [procedure].
+  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure);
+
+  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
+  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
+
+  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
+  /// function.
+  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
+      ir.StaticInvocation node);
+
+  /// Computes the [native.NativeBehavior] for a call to the
+  /// [JS_EMBEDDED_GLOBAL] function.
+  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+      ir.StaticInvocation node);
+
+  /// Compute the kind of foreign helper function called by [node], if any.
+  ForeignKind getForeignKind(ir.StaticInvocation node);
+
+  /// Computes the [InterfaceType] referenced by a call to the
+  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
+  InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node);
+}
+
+/// Kinds of foreign functions.
+enum ForeignKind {
+  JS,
+  JS_BUILTIN,
+  JS_EMBEDDED_GLOBAL,
+  JS_INTERCEPTOR_CONSTANT,
+  NONE,
+}
+
+abstract class KernelElementAdapterMixin implements KernelElementAdapter {
+  DiagnosticReporter get reporter;
+  FunctionType getFunctionType(ir.FunctionNode node);
+  native.BehaviorBuilder get nativeBehaviorBuilder;
+  BackendHelpers _helpers;
+
+  @override
+  BackendHelpers get helpers =>
+      _helpers ??= new BackendHelpers(elementEnvironment, commonElements);
+
+  @override
+  Name getName(ir.Name name) {
+    return new Name(
+        name.name, name.isPrivate ? getLibrary(name.library) : null);
+  }
+
+  @override
+  CallStructure getCallStructure(ir.Arguments arguments) {
+    int argumentCount = arguments.positional.length + arguments.named.length;
+    List<String> namedArguments = arguments.named.map((e) => e.name).toList();
+    return new CallStructure(argumentCount, namedArguments);
+  }
+
+  @override
+  Selector getSelector(ir.Expression node) {
+    // TODO(efortuna): This is screaming for a common interface between
+    // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel
+    // folks.
+    if (node is ir.PropertyGet) {
+      return getGetterSelector(node.name);
+    }
+    if (node is ir.SuperPropertyGet) {
+      return getGetterSelector(node.name);
+    }
+    if (node is ir.PropertySet) {
+      return getSetterSelector(node.name);
+    }
+    if (node is ir.SuperPropertySet) {
+      return getSetterSelector(node.name);
+    }
+    if (node is ir.InvocationExpression) {
+      return getInvocationSelector(node);
+    }
+    throw new SpannableAssertionFailure(
+        CURRENT_ELEMENT_SPANNABLE,
+        "Can only get the selector for a property get or an invocation: "
+        "${node}");
+  }
+
+  Selector getInvocationSelector(ir.InvocationExpression invocation) {
+    Name name = getName(invocation.name);
+    SelectorKind kind;
+    if (Elements.isOperatorName(invocation.name.name)) {
+      if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
+        kind = SelectorKind.INDEX;
+      } else {
+        kind = SelectorKind.OPERATOR;
+      }
+    } else {
+      kind = SelectorKind.CALL;
+    }
+
+    CallStructure callStructure = getCallStructure(invocation.arguments);
+    return new Selector(kind, name, callStructure);
+  }
+
+  Selector getGetterSelector(ir.Name irName) {
+    Name name = new Name(
+        irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
+    return new Selector.getter(name);
+  }
+
+  Selector getSetterSelector(ir.Name irName) {
+    Name name = new Name(
+        irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
+    return new Selector.setter(name);
+  }
+
+  /// Converts [annotations] into a list of [ConstantExpression]s.
+  List<ConstantExpression> getMetadata(List<ir.Expression> annotations) {
+    List<ConstantExpression> metadata = <ConstantExpression>[];
+    annotations.forEach((ir.Expression node) {
+      ConstantExpression constant = new Constantifier(this).visit(node);
+      if (constant == null) {
+        throw new UnsupportedError(
+            'No constant for ${DebugPrinter.prettyPrint(node)}');
+      }
+      metadata.add(constant);
+    });
+    return metadata;
+  }
+
+  /// Returns `true` is [node] has a `@Native(...)` annotation.
+  // TODO(johnniwinther): Cache this for later use.
+  bool isNativeClass(ir.Class node) {
+    for (ir.Expression annotation in node.annotations) {
+      if (annotation is ir.ConstructorInvocation) {
+        FunctionEntity target = getConstructor(annotation.target);
+        if (target.enclosingClass == helpers.nativeAnnotationClass) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /// Compute the kind of foreign helper function called by [node], if any.
+  ForeignKind getForeignKind(ir.StaticInvocation node) {
+    if (isForeignLibrary(node.target.enclosingLibrary)) {
+      switch (node.target.name.name) {
+        case BackendHelpers.JS:
+          return ForeignKind.JS;
+        case BackendHelpers.JS_BUILTIN:
+          return ForeignKind.JS_BUILTIN;
+        case BackendHelpers.JS_EMBEDDED_GLOBAL:
+          return ForeignKind.JS_EMBEDDED_GLOBAL;
+        case BackendHelpers.JS_INTERCEPTOR_CONSTANT:
+          return ForeignKind.JS_INTERCEPTOR_CONSTANT;
+      }
+    }
+    return ForeignKind.NONE;
+  }
+
+  /// Return `true` if [node] is the `dart:_foreign_helper` library.
+  bool isForeignLibrary(ir.Library node) {
+    return node.importUri == BackendHelpers.DART_FOREIGN_HELPER;
+  }
+
+  /// Looks up [typeName] for use in the spec-string of a `JS` called.
+  // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
+  // the `ForeignResolver`.
+  // TODO(johnniwinther): Cache the result to avoid redundant lookups?
+  native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
+    DartType lookup(String typeName, {bool required}) {
+      DartType findIn(Uri uri) {
+        LibraryEntity library = elementEnvironment.lookupLibrary(uri);
+        if (library != null) {
+          ClassEntity cls = elementEnvironment.lookupClass(library, typeName);
+          if (cls != null) {
+            // TODO(johnniwinther): Align semantics.
+            return resolveAsRaw
+                ? elementEnvironment.getRawType(cls)
+                : elementEnvironment.getThisType(cls);
+          }
+        }
+        return null;
+      }
+
+      // TODO(johnniwinther): Narrow the set of lookups base on the depending
+      // library.
+      DartType type = findIn(Uris.dart_core);
+      type ??= findIn(BackendHelpers.DART_JS_HELPER);
+      type ??= findIn(BackendHelpers.DART_INTERCEPTORS);
+      type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER);
+      type ??= findIn(Uris.dart__native_typed_data);
+      type ??= findIn(Uris.dart_collection);
+      type ??= findIn(Uris.dart_math);
+      type ??= findIn(Uris.dart_html);
+      type ??= findIn(Uris.dart_html_common);
+      type ??= findIn(Uris.dart_svg);
+      type ??= findIn(Uris.dart_web_audio);
+      type ??= findIn(Uris.dart_web_gl);
+      type ??= findIn(Uris.dart_web_sql);
+      type ??= findIn(Uris.dart_indexed_db);
+      type ??= findIn(Uris.dart_typed_data);
+      if (type == null && required) {
+        reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
+            MessageKind.GENERIC, {'text': "Type '$typeName' not found."});
+      }
+      return type;
+    }
+
+    return lookup;
+  }
+
+  String _getStringArgument(ir.StaticInvocation node, int index) {
+    return node.arguments.positional[index].accept(new Stringifier());
+  }
+
+  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
+  // TODO(johnniwinther): Cache this for later use.
+  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+    if (node.arguments.positional.length < 2 ||
+        node.arguments.named.isNotEmpty) {
+      reporter.reportErrorMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
+      return new native.NativeBehavior();
+    }
+    String specString = _getStringArgument(node, 0);
+    if (specString == null) {
+      reporter.reportErrorMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
+      return new native.NativeBehavior();
+    }
+
+    String codeString = _getStringArgument(node, 1);
+    if (codeString == null) {
+      reporter.reportErrorMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
+      return new native.NativeBehavior();
+    }
+
+    return native.NativeBehavior.ofJsCall(
+        specString,
+        codeString,
+        typeLookup(resolveAsRaw: true),
+        CURRENT_ELEMENT_SPANNABLE,
+        reporter,
+        commonElements);
+  }
+
+  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
+  /// function.
+  // TODO(johnniwinther): Cache this for later use.
+  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
+      ir.StaticInvocation node) {
+    if (node.arguments.positional.length < 1) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
+      return new native.NativeBehavior();
+    }
+    if (node.arguments.positional.length < 2) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
+      return new native.NativeBehavior();
+    }
+    String specString = _getStringArgument(node, 0);
+    if (specString == null) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
+      return new native.NativeBehavior();
+    }
+    return native.NativeBehavior.ofJsBuiltinCall(
+        specString,
+        typeLookup(resolveAsRaw: true),
+        CURRENT_ELEMENT_SPANNABLE,
+        reporter,
+        commonElements);
+  }
+
+  /// Computes the [native.NativeBehavior] for a call to the
+  /// [JS_EMBEDDED_GLOBAL] function.
+  // TODO(johnniwinther): Cache this for later use.
+  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+      ir.StaticInvocation node) {
+    if (node.arguments.positional.length < 1) {
+      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
+          "JS embedded global expression has no type.");
+      return new native.NativeBehavior();
+    }
+    if (node.arguments.positional.length < 2) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
+      return new native.NativeBehavior();
+    }
+    if (node.arguments.positional.length > 2 ||
+        node.arguments.named.isNotEmpty) {
+      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
+          "JS embedded global has more than 2 arguments.");
+      return new native.NativeBehavior();
+    }
+    String specString = _getStringArgument(node, 0);
+    if (specString == null) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
+      return new native.NativeBehavior();
+    }
+    return native.NativeBehavior.ofJsEmbeddedGlobalCall(
+        specString,
+        typeLookup(resolveAsRaw: true),
+        CURRENT_ELEMENT_SPANNABLE,
+        reporter,
+        commonElements);
+  }
+
+  /// Computes the [InterfaceType] referenced by a call to the
+  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
+  InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
+    if (node.arguments.positional.length != 1 ||
+        node.arguments.named.isNotEmpty) {
+      reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
+          MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
+    }
+    ir.Node argument = node.arguments.positional.first;
+    if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
+      return getInterfaceType(argument.type);
+    }
+    return null;
+  }
+
+  /// Computes the native behavior for reading the native [field].
+  // TODO(johnniwinther): Cache this for later use.
+  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
+    DartType type = getDartType(field.type);
+    List<ConstantExpression> metadata = getMetadata(field.annotations);
+    // TODO(johnniwinther): Provide the correct value for [isJsInterop].
+    return nativeBehaviorBuilder.buildFieldLoadBehavior(
+        type, metadata, typeLookup(resolveAsRaw: false),
+        isJsInterop: false);
+  }
+
+  /// Computes the native behavior for writing to the native [field].
+  // TODO(johnniwinther): Cache this for later use.
+  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
+    DartType type = getDartType(field.type);
+    return nativeBehaviorBuilder.buildFieldStoreBehavior(type);
+  }
+
+  /// Computes the native behavior for calling [procedure].
+  // TODO(johnniwinther): Cache this for later use.
+  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
+    DartType type = getFunctionType(procedure.function);
+    List<ConstantExpression> metadata = getMetadata(procedure.annotations);
+    // TODO(johnniwinther): Provide the correct value for [isJsInterop].
+    return nativeBehaviorBuilder.buildMethodBehavior(
+        type, metadata, typeLookup(resolveAsRaw: false),
+        isJsInterop: false);
+  }
+}
+
+/// Visitor that converts string literals and concatenations of string literals
+/// into the string value.
+class Stringifier extends ir.ExpressionVisitor<String> {
+  @override
+  String visitStringLiteral(ir.StringLiteral node) => node.value;
+
+  @override
+  String visitStringConcatenation(ir.StringConcatenation node) {
+    StringBuffer sb = new StringBuffer();
+    for (ir.Expression expression in node.expressions) {
+      String value = expression.accept(this);
+      if (value == null) return null;
+      sb.write(value);
+    }
+    return sb.toString();
+  }
+}
+
+/// Visitor that converts a kernel constant expression into a
+/// [ConstantExpression].
+class Constantifier extends ir.ExpressionVisitor<ConstantExpression> {
+  final bool requireConstant;
+  final KernelElementAdapter elementAdapter;
+
+  Constantifier(this.elementAdapter, {this.requireConstant: true});
+
+  ConstantExpression visit(ir.Expression node) {
+    ConstantExpression constant = node.accept(this);
+    if (constant == null && requireConstant) {
+      throw new UnsupportedError(
+          "No constant computed for $node (${node.runtimeType})");
+    }
+    return constant;
+  }
+
+  ConstantExpression defaultExpression(ir.Expression node) {
+    throw new UnimplementedError(
+        'Unimplemented constant expression $node (${node.runtimeType})');
+  }
+
+  List<ConstantExpression> _computeList(List<ir.Expression> expressions) {
+    List<ConstantExpression> list = <ConstantExpression>[];
+    for (ir.Expression expression in expressions) {
+      ConstantExpression constant = visit(expression);
+      if (constant == null) return null;
+      list.add(constant);
+    }
+    return list;
+  }
+
+  List<ConstantExpression> _computeArguments(ir.Arguments node) {
+    List<ConstantExpression> arguments = <ConstantExpression>[];
+    for (ir.Expression argument in node.positional) {
+      ConstantExpression constant = visit(argument);
+      if (constant == null) return null;
+      arguments.add(constant);
+    }
+    for (ir.NamedExpression argument in node.named) {
+      ConstantExpression constant = visit(argument.value);
+      if (constant == null) return null;
+      arguments.add(constant);
+    }
+    return arguments;
+  }
+
+  ConstructedConstantExpression _computeConstructorInvocation(
+      ir.Constructor target, ir.Arguments arguments) {
+    return new ConstructedConstantExpression(
+        elementAdapter.createInterfaceType(
+            target.enclosingClass, arguments.types),
+        elementAdapter.getConstructor(target),
+        elementAdapter.getCallStructure(arguments),
+        _computeArguments(arguments));
+  }
+
+  @override
+  ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) {
+    return _computeConstructorInvocation(node.target, node.arguments);
+  }
+
+  @override
+  ConstantExpression visitVariableGet(ir.VariableGet node) {
+    if (node.variable.parent is ir.FunctionNode) {
+      ir.FunctionNode function = node.variable.parent;
+      int index = function.positionalParameters.indexOf(node.variable);
+      if (index != -1) {
+        return new PositionalArgumentReference(index);
+      } else {
+        assert(function.namedParameters.contains(node.variable));
+        return new NamedArgumentReference(node.variable.name);
+      }
+    }
+    throw new UnimplementedError(
+        'Unimplemented constant expression $node (${node.runtimeType})');
+  }
+
+  @override
+  ConstantExpression visitStaticGet(ir.StaticGet node) {
+    return new FieldConstantExpression(elementAdapter.getField(node.target));
+  }
+
+  @override
+  ConstantExpression visitStringLiteral(ir.StringLiteral node) {
+    return new StringConstantExpression(node.value);
+  }
+
+  @override
+  ConstantExpression visitStringConcatenation(ir.StringConcatenation node) {
+    return new ConcatenateConstantExpression(_computeList(node.expressions));
+  }
+
+  /// Compute the [ConstantConstructor] corresponding to the const constructor
+  /// [node].
+  ConstantConstructor computeConstantConstructor(ir.Constructor node) {
+    assert(node.isConst);
+    ir.Class cls = node.enclosingClass;
+    InterfaceType type = elementAdapter.elementEnvironment
+        .getThisType(elementAdapter.getClass(cls));
+
+    Map<dynamic, ConstantExpression> defaultValues =
+        <dynamic, ConstantExpression>{};
+    int parameterIndex = 0;
+    node.function.positionalParameters
+        .forEach((ir.VariableDeclaration parameter) {
+      if (parameterIndex >= node.function.requiredParameterCount) {
+        if (parameter.initializer != null) {
+          defaultValues[parameterIndex] = parameter.initializer.accept(this);
+        } else {
+          defaultValues[parameterIndex] = new NullConstantExpression();
+        }
+      }
+      parameterIndex++;
+    });
+    node.function.namedParameters.forEach((ir.VariableDeclaration parameter) {
+      defaultValues[parameter.name] = parameter.initializer.accept(this);
+    });
+
+    bool isRedirecting = node.initializers.length == 1 &&
+        node.initializers.single is ir.RedirectingInitializer;
+
+    Map<FieldEntity, ConstantExpression> fieldMap =
+        <FieldEntity, ConstantExpression>{};
+
+    void registerField(ir.Field field, ConstantExpression constant) {
+      fieldMap[elementAdapter.getField(field)] = constant;
+    }
+
+    if (!isRedirecting) {
+      for (ir.Field field in cls.fields) {
+        if (field.initializer != null) {
+          registerField(field, field.initializer.accept(this));
+        }
+      }
+    }
+
+    ConstructedConstantExpression superConstructorInvocation;
+    for (ir.Initializer initializer in node.initializers) {
+      if (initializer is ir.FieldInitializer) {
+        registerField(initializer.field, initializer.value.accept(this));
+      } else if (initializer is ir.SuperInitializer) {
+        superConstructorInvocation = _computeConstructorInvocation(
+            initializer.target, initializer.arguments);
+      } else if (initializer is ir.RedirectingInitializer) {
+        superConstructorInvocation = _computeConstructorInvocation(
+            initializer.target, initializer.arguments);
+      } else {
+        throw new UnsupportedError(
+            'Unexpected initializer $node (${node.runtimeType})');
+      }
+    }
+    if (isRedirecting) {
+      return new RedirectingGenerativeConstantConstructor(
+          defaultValues, superConstructorInvocation);
+    } else {
+      return new GenerativeConstantConstructor(
+          type, defaultValues, fieldMap, superConstructorInvocation);
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/elements.dart b/pkg/compiler/lib/src/kernel/elements.dart
new file mode 100644
index 0000000..7f3fc4c
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/elements.dart
@@ -0,0 +1,192 @@
+// 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.
+
+/// Entity model for elements derived from Kernel IR.
+
+import '../elements/elements.dart';
+import '../elements/entities.dart';
+
+class KLibrary implements LibraryEntity {
+  /// Library index used for fast lookup in [KernelWorldBuilder].
+  final int libraryIndex;
+  final String name;
+
+  KLibrary(this.libraryIndex, this.name);
+
+  String toString() => 'library($name)';
+}
+
+class KClass implements ClassEntity {
+  /// Class index used for fast lookup in [KernelWorldBuilder].
+  final int classIndex;
+  final String name;
+
+  KClass(this.classIndex, this.name);
+
+  @override
+  bool get isClosure => false;
+
+  String toString() => 'class($name)';
+}
+
+abstract class KMember implements MemberEntity {
+  final KClass enclosingClass;
+  final Name _name;
+  final bool _isStatic;
+
+  KMember(this.enclosingClass, this._name, {bool isStatic: false})
+      : _isStatic = isStatic;
+
+  String get name => _name.text;
+
+  @override
+  bool get isAssignable => false;
+
+  @override
+  bool get isSetter => false;
+
+  @override
+  bool get isGetter => false;
+
+  @override
+  bool get isFunction => false;
+
+  @override
+  bool get isField => false;
+
+  @override
+  bool get isConstructor => false;
+
+  @override
+  bool get isInstanceMember => enclosingClass != null && !_isStatic;
+
+  @override
+  bool get isStatic => enclosingClass != null && _isStatic;
+
+  @override
+  bool get isTopLevel => enclosingClass == null;
+
+  String get _kind;
+
+  String toString() =>
+      '$_kind(${enclosingClass != null ? '${enclosingClass.name}.' : ''}$name)';
+}
+
+abstract class KFunction extends KMember implements FunctionEntity {
+  KFunction(KClass enclosingClass, Name name, {bool isStatic: false})
+      : super(enclosingClass, name, isStatic: isStatic);
+}
+
+abstract class KConstructor extends KFunction implements ConstructorEntity {
+  /// Constructor index used for fast lookup in [KernelWorldBuilder].
+  final int constructorIndex;
+
+  KConstructor(this.constructorIndex, KClass enclosingClass, Name name)
+      : super(enclosingClass, name);
+
+  @override
+  bool get isConstructor => true;
+
+  @override
+  bool get isInstanceMember => false;
+
+  @override
+  bool get isStatic => false;
+
+  @override
+  bool get isTopLevel => false;
+
+  String get _kind => 'constructor';
+}
+
+class KGenerativeConstructor extends KConstructor {
+  KGenerativeConstructor(int constructorIndex, KClass enclosingClass, Name name)
+      : super(constructorIndex, enclosingClass, name);
+
+  @override
+  bool get isFactoryConstructor => false;
+
+  @override
+  bool get isGenerativeConstructor => true;
+}
+
+class KFactoryConstructor extends KConstructor {
+  KFactoryConstructor(int constructorIndex, KClass enclosingClass, Name name)
+      : super(constructorIndex, enclosingClass, name);
+
+  @override
+  bool get isFactoryConstructor => true;
+
+  @override
+  bool get isGenerativeConstructor => false;
+}
+
+class KMethod extends KFunction {
+  KMethod(KClass enclosingClass, Name name, {bool isStatic})
+      : super(enclosingClass, name, isStatic: isStatic);
+
+  @override
+  bool get isFunction => true;
+
+  String get _kind => 'method';
+}
+
+class KGetter extends KFunction {
+  KGetter(KClass enclosingClass, Name name, {bool isStatic})
+      : super(enclosingClass, name, isStatic: isStatic);
+
+  @override
+  bool get isGetter => true;
+
+  String get _kind => 'getter';
+}
+
+class KSetter extends KFunction {
+  KSetter(KClass enclosingClass, Name name, {bool isStatic})
+      : super(enclosingClass, name, isStatic: isStatic);
+
+  @override
+  bool get isAssignable => true;
+
+  @override
+  bool get isSetter => true;
+
+  String get _kind => 'setter';
+}
+
+class KField extends KMember implements FieldEntity {
+  /// Field index used for fast lookup in [KernelWorldBuilder].
+  final int fieldIndex;
+  final bool isAssignable;
+
+  KField(this.fieldIndex, KClass enclosingClass, Name name,
+      {bool isStatic, this.isAssignable})
+      : super(enclosingClass, name, isStatic: isStatic);
+
+  @override
+  bool get isField => true;
+
+  String get _kind => 'field';
+}
+
+class KTypeVariable implements TypeVariableEntity {
+  final Entity typeDeclaration;
+  final String name;
+  final int index;
+
+  KTypeVariable(this.typeDeclaration, this.name, this.index);
+
+  String toString() => 'type_variable(${typeDeclaration.name}.$name)';
+}
+
+class KLocalFunction implements Local {
+  final String name;
+  final MemberEntity memberContext;
+  final Entity executableContext;
+
+  KLocalFunction(this.name, this.memberContext, this.executableContext);
+
+  String toString() =>
+      'local_function(${memberContext.name}.${name ?? '<anonymous>'})';
+}
diff --git a/pkg/compiler/lib/src/kernel/kernel_visitor.dart b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
index 1bb66cc..8ba98d0 100644
--- a/pkg/compiler/lib/src/kernel/kernel_visitor.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
@@ -387,25 +387,29 @@
   }
 
   ir.LabeledStatement getBreakTarget(JumpTarget target) {
-    return breakTargets.putIfAbsent(
-        target, () => new ir.LabeledStatement(null));
+    return breakTargets.putIfAbsent(target,
+        () => associateNode(new ir.LabeledStatement(null), target.statement));
   }
 
   ir.LabeledStatement getContinueTarget(JumpTarget target) {
-    return continueTargets.putIfAbsent(
-        target, () => new ir.LabeledStatement(null));
+    return continueTargets.putIfAbsent(target,
+        () => associateNode(new ir.LabeledStatement(null), target.statement));
   }
 
   ir.SwitchCase getContinueSwitchTarget(JumpTarget target) {
     return continueSwitchTargets[target];
   }
 
+  /// The optional positional parameter isBreakTarget can be added in cases
+  /// where a break statement was added but the element model and underlying
+  /// JumpTargets don't know about it.
   ir.Statement buildBreakTarget(
-      ir.Statement statement, Node node, JumpTarget jumpTarget) {
+      ir.Statement statement, Node node, JumpTarget jumpTarget,
+      [bool isBreakTarget = false]) {
     assert(node.isValidBreakTarget());
     assert(jumpTarget == elements.getTargetDefinition(node));
     associateNode(statement, node);
-    if (jumpTarget != null && jumpTarget.isBreakTarget) {
+    if (jumpTarget != null && (jumpTarget.isBreakTarget || isBreakTarget)) {
       ir.LabeledStatement breakTarget = getBreakTarget(jumpTarget);
       breakTarget.body = statement;
       statement.parent = breakTarget;
@@ -587,7 +591,7 @@
       // One VariableDefinitions statement node (dart2js AST) may generate
       // multiple statements in Kernel IR so we sometimes fall through here.
     }
-    return new ir.Block(statements);
+    return associateNode(new ir.Block(statements), node);
   }
 
   @override
@@ -785,8 +789,10 @@
         new ir.ForStatement(variables, condition, updates, body), node);
     ir.Statement result = buildBreakTarget(forStatement, node, jumpTarget);
     if (initializer != null) {
-      result = new ir.Block(
-          <ir.Statement>[new ir.ExpressionStatement(initializer), result]);
+      result = associateNode(
+          new ir.Block(
+              <ir.Statement>[new ir.ExpressionStatement(initializer), result]),
+          node.initializer);
     }
     return result;
   }
@@ -822,6 +828,7 @@
         // its visit method (so it can build break targets correctly).
         ? statement.accept(this)
         : buildStatementInBlock(statement);
+    associateNode(result, statement);
 
     // A [LabeledStatement] isn't the actual jump target, instead, [statement]
     // is the target. This allows uniform handling of break and continue in
@@ -995,7 +1002,9 @@
     }
     // We ignore the node's statements here, they're generated below in
     // [visitSwitchStatement] once we've set up all the jump targets.
-    return new ir.SwitchCase(expressions, null, isDefault: node.isDefaultCase);
+    return associateNode(
+        new ir.SwitchCase(expressions, null, isDefault: node.isDefaultCase),
+        node);
   }
 
   /// Returns true if [node] would let execution reach the next node (aka
@@ -1011,6 +1020,7 @@
   ir.Statement visitSwitchStatement(SwitchStatement node) {
     ir.Expression expression = visitForValue(node.expression);
     List<ir.SwitchCase> cases = <ir.SwitchCase>[];
+    bool switchIsBreakTarget = elements.getTargetDefinition(node).isBreakTarget;
     for (SwitchCase caseNode in node.cases.nodes) {
       cases.add(caseNode.accept(this));
       JumpTarget jumpTarget = elements.getTargetDefinition(caseNode);
@@ -1032,17 +1042,18 @@
       }
       ir.SwitchCase irCase = casesIterator.current;
       List<ir.Statement> statements = <ir.Statement>[];
-      bool hasVariableDeclaration = false;
       for (Statement statement in caseNode.statements.nodes) {
-        if (buildStatement(statement, statements)) {
-          hasVariableDeclaration = true;
-        }
+        buildStatement(statement, statements);
       }
       if (statements.isEmpty || fallsThrough(statements.last)) {
         if (isLastCase) {
           if (!caseNode.isDefaultCase) {
             statements.add(new ir.BreakStatement(
                 getBreakTarget(elements.getTargetDefinition(node))));
+            // Because we "helpfully" add a break here, in the underlying
+            // element model the jump target doesn't actually know it's a break
+            // target, so we have to pass that information.
+            switchIsBreakTarget = true;
           }
         } else {
           statements.add(new ir.ExpressionStatement(new ir.Throw(
@@ -1058,7 +1069,7 @@
     assert(!casesIterator.moveNext());
 
     return buildBreakTarget(new ir.SwitchStatement(expression, cases), node,
-        elements.getTargetDefinition(node));
+        elements.getTargetDefinition(node), switchIsBreakTarget);
   }
 
   @override
@@ -2107,7 +2118,6 @@
       // [body] must be `null`.
     } else if (function.isConstructor) {
       // TODO(johnniwinther): Clean this up pending kernel issue #28.
-      ConstructorElement constructor = function;
       if (bodyNode == null || bodyNode.asEmptyStatement() != null) {
         body = new ir.EmptyStatement();
       } else {
diff --git a/pkg/compiler/lib/src/kernel/world_builder.dart b/pkg/compiler/lib/src/kernel/world_builder.dart
new file mode 100644
index 0000000..afedc40
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/world_builder.dart
@@ -0,0 +1,824 @@
+// 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:kernel/ast.dart' as ir;
+
+import '../common.dart';
+import '../common/backend_api.dart';
+import '../common/names.dart';
+import '../compile_time_constants.dart';
+import '../constants/constant_system.dart';
+import '../constants/constructors.dart';
+import '../constants/evaluation.dart';
+import '../constants/expressions.dart';
+import '../constants/values.dart';
+import '../core_types.dart';
+import '../elements/elements.dart';
+import '../elements/entities.dart';
+import '../elements/types.dart';
+import '../js_backend/backend_helpers.dart';
+import '../js_backend/constant_system_javascript.dart';
+import '../native/native.dart' as native;
+import 'element_adapter.dart';
+import 'elements.dart';
+
+/// World builder used for creating elements and types corresponding to Kernel
+/// IR nodes.
+// TODO(johnniwinther): Implement [ResolutionWorldBuilder].
+class KernelWorldBuilder extends KernelElementAdapterMixin {
+  CommonElements _commonElements;
+  native.BehaviorBuilder _nativeBehaviorBuilder;
+  final DiagnosticReporter reporter;
+  ElementEnvironment _elementEnvironment;
+  DartTypeConverter _typeConverter;
+
+  /// Library environment. Used for fast lookup.
+  KEnv _env;
+
+  /// List of library environments by `KLibrary.libraryIndex`. This is used for
+  /// fast lookup into library classes and members.
+  List<KLibraryEnv> _libraryEnvs = <KLibraryEnv>[];
+
+  /// List of class environments by `KClass.classIndex`. This is used for
+  /// fast lookup into class members.
+  List<KClassEnv> _classEnvs = <KClassEnv>[];
+
+  Map<ir.Library, KLibrary> _libraryMap = <ir.Library, KLibrary>{};
+  Map<ir.Class, KClass> _classMap = <ir.Class, KClass>{};
+  Map<ir.TypeParameter, KTypeVariable> _typeVariableMap =
+      <ir.TypeParameter, KTypeVariable>{};
+
+  Map<ir.Member, KConstructor> _constructorMap = <ir.Member, KConstructor>{};
+  // TODO(johnniwinther): Change this to a list of 'KConstructorData' class
+  // holding the [ConstantConstructor] if we need more data for constructors.
+  List<ir.Member> _constructorList = <ir.Member>[];
+  Map<KConstructor, ConstantConstructor> _constructorConstantMap =
+      <KConstructor, ConstantConstructor>{};
+
+  Map<ir.Procedure, KFunction> _methodMap = <ir.Procedure, KFunction>{};
+
+  Map<ir.Field, KField> _fieldMap = <ir.Field, KField>{};
+  // TODO(johnniwinther): Change this to a list of 'KFieldData' class
+  // holding the [ConstantExpression] if we need more data for fields.
+  List<ir.Field> _fieldList = <ir.Field>[];
+  Map<KField, ConstantExpression> _fieldConstantMap =
+      <KField, ConstantExpression>{};
+
+  Map<ir.TreeNode, KLocalFunction> _localFunctionMap =
+      <ir.TreeNode, KLocalFunction>{};
+
+  KernelWorldBuilder(this.reporter, ir.Program program)
+      : _env = new KEnv(program) {
+    _elementEnvironment = new KernelElementEnvironment(this);
+    _commonElements = new KernelCommonElements(_elementEnvironment);
+    ConstantEnvironment constants = new KernelConstantEnvironment(this);
+    _nativeBehaviorBuilder =
+        new KernelBehaviorBuilder(_commonElements, helpers, constants);
+    _typeConverter = new DartTypeConverter(this);
+  }
+
+  @override
+  CommonElements get commonElements => _commonElements;
+
+  @override
+  ElementEnvironment get elementEnvironment => _elementEnvironment;
+
+  @override
+  native.BehaviorBuilder get nativeBehaviorBuilder => _nativeBehaviorBuilder;
+
+  LibraryEntity lookupLibrary(Uri uri) {
+    KLibraryEnv libraryEnv = _env.lookupLibrary(uri);
+    return _getLibrary(libraryEnv.library, libraryEnv);
+  }
+
+  KLibrary _getLibrary(ir.Library node, [KLibraryEnv libraryEnv]) {
+    return _libraryMap.putIfAbsent(node, () {
+      _libraryEnvs.add(libraryEnv ?? _env.lookupLibrary(node.importUri));
+      String name = node.name;
+      if (name == null) {
+        // Use the file name as script name.
+        String path = node.importUri.path;
+        name = path.substring(path.lastIndexOf('/') + 1);
+      }
+      return new KLibrary(_libraryMap.length, name);
+    });
+  }
+
+  MemberEntity lookupLibraryMember(KLibrary library, String name,
+      {bool setter: false}) {
+    KLibraryEnv libraryEnv = _libraryEnvs[library.libraryIndex];
+    ir.Member member = libraryEnv.lookupMember(name, setter: setter);
+    return member != null ? getMember(member) : null;
+  }
+
+  ClassEntity lookupClass(KLibrary library, String name) {
+    KLibraryEnv libraryEnv = _libraryEnvs[library.libraryIndex];
+    KClassEnv classEnv = libraryEnv.lookupClass(name);
+    if (classEnv != null) {
+      return _getClass(classEnv.cls, classEnv);
+    }
+    return null;
+  }
+
+  MemberEntity lookupClassMember(KClass cls, String name,
+      {bool setter: false}) {
+    KClassEnv classEnv = _classEnvs[cls.classIndex];
+    ir.Member member = classEnv.lookupMember(name, setter: setter);
+    return member != null ? getMember(member) : null;
+  }
+
+  ConstructorEntity lookupConstructor(KClass cls, String name) {
+    KClassEnv classEnv = _classEnvs[cls.classIndex];
+    ir.Member member = classEnv.lookupConstructor(name);
+    return member != null ? getConstructor(member) : null;
+  }
+
+  KClass _getClass(ir.Class node, [KClassEnv classEnv]) {
+    return _classMap.putIfAbsent(node, () {
+      if (classEnv == null) {
+        KLibrary library = _getLibrary(node.enclosingLibrary);
+        classEnv = _libraryEnvs[library.libraryIndex].lookupClass(node.name);
+      }
+      _classEnvs.add(classEnv);
+      return new KClass(_classMap.length, node.name);
+    });
+  }
+
+  KTypeVariable _getTypeVariable(ir.TypeParameter node) {
+    return _typeVariableMap.putIfAbsent(node, () {
+      if (node.parent is ir.Class) {
+        ir.Class cls = node.parent;
+        int index = cls.typeParameters.indexOf(node);
+        return new KTypeVariable(_getClass(cls), node.name, index);
+      }
+      if (node.parent is ir.FunctionNode) {
+        ir.FunctionNode func = node.parent;
+        int index = func.typeParameters.indexOf(node);
+        if (func.parent is ir.Constructor) {
+          ir.Constructor constructor = func.parent;
+          ir.Class cls = constructor.enclosingClass;
+          return _getTypeVariable(cls.typeParameters[index]);
+        }
+        if (func.parent is ir.Procedure) {
+          ir.Procedure procedure = func.parent;
+          if (procedure.kind == ir.ProcedureKind.Factory) {
+            ir.Class cls = procedure.enclosingClass;
+            return _getTypeVariable(cls.typeParameters[index]);
+          } else {
+            return new KTypeVariable(_getMethod(procedure), node.name, index);
+          }
+        }
+      }
+      throw new UnsupportedError('Unsupported type parameter type node $node.');
+    });
+  }
+
+  KConstructor _getConstructor(ir.Member node) {
+    return _constructorMap.putIfAbsent(node, () {
+      int constructorIndex = _constructorList.length;
+      KConstructor constructor;
+      if (node is ir.Constructor) {
+        constructor = new KGenerativeConstructor(constructorIndex,
+            _getClass(node.enclosingClass), getName(node.name));
+      } else {
+        constructor = new KFactoryConstructor(constructorIndex,
+            _getClass(node.enclosingClass), getName(node.name));
+      }
+      _constructorList.add(node);
+      return constructor;
+    });
+  }
+
+  KFunction _getMethod(ir.Procedure node) {
+    return _methodMap.putIfAbsent(node, () {
+      KClass enclosingClass =
+          node.enclosingClass != null ? _getClass(node.enclosingClass) : null;
+      Name name = getName(node.name);
+      bool isStatic = node.isStatic;
+      switch (node.kind) {
+        case ir.ProcedureKind.Factory:
+          throw new UnsupportedError("Cannot create method from factory.");
+        case ir.ProcedureKind.Getter:
+          return new KGetter(enclosingClass, name, isStatic: isStatic);
+        case ir.ProcedureKind.Method:
+        case ir.ProcedureKind.Operator:
+          return new KMethod(enclosingClass, name, isStatic: isStatic);
+        case ir.ProcedureKind.Setter:
+          return new KSetter(enclosingClass, getName(node.name).setter,
+              isStatic: isStatic);
+      }
+    });
+  }
+
+  KField _getField(ir.Field node) {
+    return _fieldMap.putIfAbsent(node, () {
+      int fieldIndex = _fieldList.length;
+      KClass enclosingClass =
+          node.enclosingClass != null ? _getClass(node.enclosingClass) : null;
+      Name name = getName(node.name);
+      bool isStatic = node.isStatic;
+      _fieldList.add(node);
+      return new KField(fieldIndex, enclosingClass, name,
+          isStatic: isStatic, isAssignable: node.isMutable);
+    });
+  }
+
+  KLocalFunction _getLocal(ir.TreeNode node) {
+    return _localFunctionMap.putIfAbsent(node, () {
+      MemberEntity memberContext;
+      Entity executableContext;
+      ir.TreeNode parent = node.parent;
+      while (parent != null) {
+        if (parent is ir.Member) {
+          executableContext = memberContext = getMember(parent);
+          break;
+        }
+        if (parent is ir.FunctionDeclaration ||
+            parent is ir.FunctionExpression) {
+          KLocalFunction localFunction = _getLocal(parent);
+          executableContext = localFunction;
+          memberContext = localFunction.memberContext;
+          break;
+        }
+        parent = parent.parent;
+      }
+      String name;
+      if (node is ir.FunctionDeclaration) {
+        name = node.variable.name;
+      }
+      return new KLocalFunction(name, memberContext, executableContext);
+    });
+  }
+
+  @override
+  DartType getDartType(ir.DartType type) => _typeConverter.convert(type);
+
+  @override
+  InterfaceType createInterfaceType(
+      ir.Class cls, List<ir.DartType> typeArguments) {
+    return new InterfaceType(getClass(cls), getDartTypes(typeArguments));
+  }
+
+  @override
+  InterfaceType getInterfaceType(ir.InterfaceType type) =>
+      _typeConverter.convert(type);
+
+  @override
+  List<DartType> getDartTypes(List<ir.DartType> types) {
+    // TODO(johnniwinther): Add the type argument to the list literal when we
+    // no longer use resolution types.
+    List<DartType> list = /*<DartType>*/ [];
+    types.forEach((ir.DartType type) {
+      list.add(getDartType(type));
+    });
+    return list;
+  }
+
+  InterfaceType _getThisType(KClass cls) {
+    KClassEnv env = _classEnvs[cls.classIndex];
+    ir.Class node = env.cls;
+    // TODO(johnniwinther): Add the type argument to the list literal when we
+    // no longer use resolution types.
+    return new InterfaceType(
+        cls,
+        new List/*<DartType>*/ .generate(node.typeParameters.length,
+            (int index) {
+          return new TypeVariableType(
+              _getTypeVariable(node.typeParameters[index]));
+        }));
+  }
+
+  InterfaceType _getRawType(KClass cls) {
+    KClassEnv env = _classEnvs[cls.classIndex];
+    ir.Class node = env.cls;
+    // TODO(johnniwinther): Add the type argument to the list literal when we
+    // no longer use resolution types.
+    return new InterfaceType(
+        cls,
+        new List/*<DartType>*/ .filled(
+            node.typeParameters.length, const DynamicType()));
+  }
+
+  @override
+  FunctionType getFunctionType(ir.FunctionNode node) {
+    DartType returnType = getDartType(node.returnType);
+    List<DartType> parameterTypes = /*<DartType>*/ [];
+    List<DartType> optionalParameterTypes = /*<DartType>*/ [];
+    for (ir.VariableDeclaration variable in node.positionalParameters) {
+      if (parameterTypes.length == node.requiredParameterCount) {
+        optionalParameterTypes.add(getDartType(variable.type));
+      } else {
+        parameterTypes.add(getDartType(variable.type));
+      }
+    }
+    List<String> namedParameters = <String>[];
+    List<DartType> namedParameterTypes = /*<DartType>*/ [];
+    List<ir.VariableDeclaration> sortedNamedParameters =
+        node.namedParameters.toList()..sort((a, b) => a.name.compareTo(b.name));
+    for (ir.VariableDeclaration variable in sortedNamedParameters) {
+      namedParameters.add(variable.name);
+      namedParameterTypes.add(getDartType(variable.type));
+    }
+    return new FunctionType(returnType, parameterTypes, optionalParameterTypes,
+        namedParameters, namedParameterTypes);
+  }
+
+  LibraryEntity getLibrary(ir.Library node) => _getLibrary(node);
+
+  @override
+  Local getLocalFunction(ir.TreeNode node) => _getLocal(node);
+
+  @override
+  ClassEntity getClass(ir.Class node) => _getClass(node);
+
+  @override
+  FieldEntity getField(ir.Field node) => _getField(node);
+
+  TypeVariableEntity getTypeVariable(ir.TypeParameter node) =>
+      _getTypeVariable(node);
+
+  @override
+  FunctionEntity getMethod(ir.Procedure node) => _getMethod(node);
+
+  @override
+  MemberEntity getMember(ir.Member node) {
+    if (node is ir.Field) {
+      return _getField(node);
+    } else if (node is ir.Constructor) {
+      return _getConstructor(node);
+    } else if (node is ir.Procedure) {
+      if (node.kind == ir.ProcedureKind.Factory) {
+        return _getConstructor(node);
+      } else {
+        return _getMethod(node);
+      }
+    }
+    throw new UnsupportedError("Unexpected member: $node");
+  }
+
+  @override
+  FunctionEntity getConstructor(ir.Member node) => _getConstructor(node);
+
+  ConstantConstructor _getConstructorConstant(KConstructor constructor) {
+    return _constructorConstantMap.putIfAbsent(constructor, () {
+      ir.Member node = _constructorList[constructor.constructorIndex];
+      if (node is ir.Constructor && node.isConst) {
+        return new Constantifier(this).computeConstantConstructor(node);
+      }
+      throw new SpannableAssertionFailure(
+          constructor,
+          "Unexpected constructor $constructor in "
+          "KernelWorldBuilder._getConstructorConstant");
+    });
+  }
+
+  ConstantExpression _getFieldConstant(KField field) {
+    return _fieldConstantMap.putIfAbsent(field, () {
+      ir.Field node = _fieldList[field.fieldIndex];
+      if (node.isConst) {
+        return new Constantifier(this).visit(node.initializer);
+      }
+      throw new SpannableAssertionFailure(
+          field,
+          "Unexpected field $field in "
+          "KernelWorldBuilder._getConstructorConstant");
+    });
+  }
+}
+
+/// Environment for fast lookup of program libraries.
+class KEnv {
+  final ir.Program program;
+
+  Map<Uri, KLibraryEnv> _libraryMap;
+
+  KEnv(this.program);
+
+  /// Return the [KLibraryEnv] for the library with the canonical [uri].
+  KLibraryEnv lookupLibrary(Uri uri) {
+    if (_libraryMap == null) {
+      _libraryMap = <Uri, KLibraryEnv>{};
+      for (ir.Library library in program.libraries) {
+        _libraryMap[library.importUri] = new KLibraryEnv(library);
+      }
+    }
+    return _libraryMap[uri];
+  }
+}
+
+/// Environment for fast lookup of library classes and members.
+// TODO(johnniwinther): Add member lookup.
+class KLibraryEnv {
+  final ir.Library library;
+
+  Map<String, KClassEnv> _classMap;
+  Map<String, ir.Member> _memberMap;
+
+  KLibraryEnv(this.library);
+
+  /// Return the [KClassEnv] for the class [name] in [library].
+  KClassEnv lookupClass(String name) {
+    if (_classMap == null) {
+      _classMap = <String, KClassEnv>{};
+      for (ir.Class cls in library.classes) {
+        _classMap[cls.name] = new KClassEnv(cls);
+      }
+    }
+    return _classMap[name];
+  }
+
+  /// Return the [ir.Member] for the member [name] in [library].
+  ir.Member lookupMember(String name, {bool setter: false}) {
+    if (_memberMap == null) {
+      _memberMap = <String, ir.Member>{};
+      for (ir.Member member in library.members) {
+        // TODO(johnniwinther): Support setter vs. getter.
+        _memberMap[member.name.name] = member;
+      }
+    }
+    return _memberMap[name];
+  }
+}
+
+/// Environment for fast lookup of class members.
+// TODO(johnniwinther): Add member lookup.
+class KClassEnv {
+  final ir.Class cls;
+
+  Map<String, ir.Member> _constructorMap;
+  Map<String, ir.Member> _memberMap;
+
+  KClassEnv(this.cls);
+
+  void _ensureMaps() {
+    if (_memberMap == null) {
+      _memberMap = <String, ir.Member>{};
+      _constructorMap = <String, ir.Member>{};
+      for (ir.Member member in cls.members) {
+        if (member is ir.Procedure && member.kind == ir.ProcedureKind.Factory) {
+          _constructorMap[member.name.name] = member;
+        } else {
+          // TODO(johnniwinther): Support setter vs. getter.
+          _memberMap[member.name.name] = member;
+        }
+      }
+      for (ir.Member member in cls.constructors) {
+        _constructorMap[member.name.name] = member;
+      }
+    }
+  }
+
+  /// Return the [ir.Member] for the member [name] in [library].
+  ir.Member lookupMember(String name, {bool setter: false}) {
+    _ensureMaps();
+    return _memberMap[name];
+  }
+
+  /// Return the [ir.Member] for the member [name] in [library].
+  ir.Member lookupConstructor(String name, {bool setter: false}) {
+    _ensureMaps();
+    return _constructorMap[name];
+  }
+}
+
+class KernelElementEnvironment implements ElementEnvironment {
+  final KernelWorldBuilder worldBuilder;
+
+  KernelElementEnvironment(this.worldBuilder);
+
+  @override
+  InterfaceType getThisType(ClassEntity cls) {
+    return worldBuilder._getThisType(cls);
+  }
+
+  @override
+  InterfaceType getRawType(ClassEntity cls) {
+    return worldBuilder._getRawType(cls);
+  }
+
+  @override
+  InterfaceType createInterfaceType(
+      ClassEntity cls, List<DartType> typeArguments) {
+    return new InterfaceType(cls, typeArguments);
+  }
+
+  @override
+  ConstructorEntity lookupConstructor(ClassEntity cls, String name,
+      {bool required: false}) {
+    ConstructorEntity constructor = worldBuilder.lookupConstructor(cls, name);
+    if (constructor == null && required) {
+      throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
+          "The constructor $name was not found in class '${cls.name}'.");
+    }
+    return constructor;
+  }
+
+  @override
+  MemberEntity lookupClassMember(ClassEntity cls, String name,
+      {bool setter: false, bool required: false}) {
+    MemberEntity member =
+        worldBuilder.lookupClassMember(cls, name, setter: setter);
+    if (member == null && required) {
+      throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
+          "The member '$name' was not found in ${cls.name}.");
+    }
+    return member;
+  }
+
+  @override
+  MemberEntity lookupLibraryMember(LibraryEntity library, String name,
+      {bool setter: false, bool required: false}) {
+    MemberEntity member =
+        worldBuilder.lookupLibraryMember(library, name, setter: setter);
+    if (member == null && required) {
+      throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
+          "The member '${name}' was not found in library '${library.name}'.");
+    }
+    return member;
+  }
+
+  @override
+  ClassEntity lookupClass(LibraryEntity library, String name,
+      {bool required: false}) {
+    ClassEntity cls = worldBuilder.lookupClass(library, name);
+    if (cls == null && required) {
+      throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
+          "The class '$name'  was not found in library '${library.name}'.");
+    }
+    return cls;
+  }
+
+  @override
+  LibraryEntity lookupLibrary(Uri uri, {bool required: false}) {
+    LibraryEntity library = worldBuilder.lookupLibrary(uri);
+    if (library == null && required) {
+      throw new SpannableAssertionFailure(
+          CURRENT_ELEMENT_SPANNABLE, "The library '$uri' was not found.");
+    }
+    return library;
+  }
+}
+
+/// [CommonElements] implementation based on [KernelWorldBuilder].
+class KernelCommonElements extends CommonElementsMixin {
+  final ElementEnvironment environment;
+
+  KernelCommonElements(this.environment);
+
+  @override
+  LibraryEntity get coreLibrary {
+    return environment.lookupLibrary(Uris.dart_core, required: true);
+  }
+
+  @override
+  DynamicType get dynamicType => const DynamicType();
+
+  @override
+  ClassEntity get nativeAnnotationClass {
+    throw new UnimplementedError('KernelCommonElements.nativeAnnotationClass');
+  }
+
+  @override
+  ClassEntity get patchAnnotationClass {
+    throw new UnimplementedError('KernelCommonElements.patchAnnotationClass');
+  }
+
+  @override
+  LibraryEntity get typedDataLibrary {
+    throw new UnimplementedError('KernelCommonElements.typedDataLibrary');
+  }
+
+  @override
+  LibraryEntity get mirrorsLibrary {
+    throw new UnimplementedError('KernelCommonElements.mirrorsLibrary');
+  }
+
+  @override
+  LibraryEntity get asyncLibrary {
+    throw new UnimplementedError('KernelCommonElements.asyncLibrary');
+  }
+}
+
+/// Visitor that converts kernel dart types into [DartType].
+class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
+  final KernelWorldBuilder elementAdapter;
+  bool topLevel = true;
+
+  DartTypeConverter(this.elementAdapter);
+
+  DartType convert(ir.DartType type) {
+    topLevel = true;
+    return type.accept(this);
+  }
+
+  /// Visit a inner type.
+  DartType visitType(ir.DartType type) {
+    topLevel = false;
+    return type.accept(this);
+  }
+
+  List<DartType> visitTypes(List<ir.DartType> types) {
+    topLevel = false;
+    return new List.generate(
+        types.length, (int index) => types[index].accept(this));
+  }
+
+  @override
+  DartType visitTypeParameterType(ir.TypeParameterType node) {
+    return new TypeVariableType(elementAdapter.getTypeVariable(node.parameter));
+  }
+
+  @override
+  DartType visitFunctionType(ir.FunctionType node) {
+    return new FunctionType(
+        visitType(node.returnType),
+        visitTypes(node.positionalParameters
+            .take(node.requiredParameterCount)
+            .toList()),
+        visitTypes(node.positionalParameters
+            .skip(node.requiredParameterCount)
+            .toList()),
+        node.namedParameters.map((n) => n.name).toList(),
+        node.namedParameters.map((n) => visitType(n.type)).toList());
+  }
+
+  @override
+  DartType visitInterfaceType(ir.InterfaceType node) {
+    ClassEntity cls = elementAdapter.getClass(node.classNode);
+    return new InterfaceType(cls, visitTypes(node.typeArguments));
+  }
+
+  @override
+  DartType visitVoidType(ir.VoidType node) {
+    return const VoidType();
+  }
+
+  @override
+  DartType visitDynamicType(ir.DynamicType node) {
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitInvalidType(ir.InvalidType node) {
+    if (topLevel) {
+      throw new UnimplementedError(
+          "Outermost invalid types not currently supported");
+    }
+    // Nested invalid types are treated as `dynamic`.
+    return const DynamicType();
+  }
+}
+
+/// [native.BehaviorBuilder] for kernel based elements.
+class KernelBehaviorBuilder extends native.BehaviorBuilder {
+  final CommonElements commonElements;
+  final BackendHelpers helpers;
+  final ConstantEnvironment constants;
+
+  KernelBehaviorBuilder(this.commonElements, this.helpers, this.constants);
+
+  @override
+  bool get trustJSInteropTypeAnnotations {
+    throw new UnimplementedError(
+        "KernelNativeBehaviorComputer.trustJSInteropTypeAnnotations");
+  }
+
+  @override
+  DiagnosticReporter get reporter {
+    throw new UnimplementedError("KernelNativeBehaviorComputer.reporter");
+  }
+
+  @override
+  BackendClasses get backendClasses {
+    throw new UnimplementedError("KernelNativeBehaviorComputer.backendClasses");
+  }
+}
+
+/// Constant environment mapping [ConstantExpression]s to [ConstantValue]s using
+/// [_EvaluationEnvironment] for the evaluation.
+class KernelConstantEnvironment implements ConstantEnvironment {
+  KernelWorldBuilder _worldBuilder;
+  Map<ConstantExpression, ConstantValue> _valueMap =
+      <ConstantExpression, ConstantValue>{};
+
+  KernelConstantEnvironment(this._worldBuilder);
+
+  @override
+  ConstantSystem get constantSystem => const JavaScriptConstantSystem();
+
+  @override
+  ConstantValue getConstantValueForVariable(VariableElement element) {
+    throw new UnimplementedError(
+        "KernelConstantEnvironment.getConstantValueForVariable");
+  }
+
+  @override
+  ConstantValue getConstantValue(ConstantExpression expression) {
+    return _valueMap.putIfAbsent(expression, () {
+      return expression.evaluate(
+          new _EvaluationEnvironment(_worldBuilder), constantSystem);
+    });
+  }
+
+  @override
+  bool hasConstantValue(ConstantExpression expression) {
+    throw new UnimplementedError("KernelConstantEnvironment.hasConstantValue");
+  }
+}
+
+/// Evaluation environment used for computing [ConstantValue]s for
+/// kernel based [ConstantExpression]s.
+class _EvaluationEnvironment implements Environment {
+  final KernelWorldBuilder _worldBuilder;
+
+  _EvaluationEnvironment(this._worldBuilder);
+
+  @override
+  CommonElements get commonElements {
+    throw new UnimplementedError("_EvaluationEnvironment.commonElements");
+  }
+
+  @override
+  BackendClasses get backendClasses {
+    throw new UnimplementedError("_EvaluationEnvironment.backendClasses");
+  }
+
+  @override
+  InterfaceType substByContext(InterfaceType base, InterfaceType target) {
+    if (base.typeArguments.isNotEmpty) {
+      throw new UnimplementedError("_EvaluationEnvironment.substByContext");
+    }
+    return base;
+  }
+
+  @override
+  ConstantConstructor getConstructorConstant(ConstructorEntity constructor) {
+    return _worldBuilder._getConstructorConstant(constructor);
+  }
+
+  @override
+  ConstantExpression getFieldConstant(FieldEntity field) {
+    return _worldBuilder._getFieldConstant(field);
+  }
+
+  @override
+  ConstantExpression getLocalConstant(Local local) {
+    throw new UnimplementedError("_EvaluationEnvironment.getLocalConstant");
+  }
+
+  @override
+  String readFromEnvironment(String name) {
+    throw new UnimplementedError("_EvaluationEnvironment.readFromEnvironment");
+  }
+}
+
+// Interface for testing equivalence of Kernel-based entities.
+class WorldDeconstructionForTesting {
+  final KernelWorldBuilder builder;
+
+  WorldDeconstructionForTesting(this.builder);
+
+  Uri getLibraryUri(KLibrary library) {
+    return builder._libraryEnvs[library.libraryIndex].library.importUri;
+  }
+
+  KLibrary getLibraryForClass(KClass cls) {
+    KClassEnv env = builder._classEnvs[cls.classIndex];
+    return builder.getLibrary(env.cls.enclosingLibrary);
+  }
+
+  KLibrary _getLibrary<E>(E member, Map<ir.Member, E> map) {
+    ir.Library library;
+    map.forEach((ir.Member node, E other) {
+      if (library == null && member == other) {
+        library = node.enclosingLibrary;
+      }
+    });
+    if (library == null) {
+      throw new ArgumentError("No library found for $member");
+    }
+    return builder._getLibrary(library);
+  }
+
+  KLibrary getLibraryForFunction(KFunction function) =>
+      _getLibrary(function, builder._methodMap);
+
+  KLibrary getLibraryForField(KField field) =>
+      _getLibrary(field, builder._fieldMap);
+
+  KClass getSuperclassForClass(KClass cls) {
+    KClassEnv env = builder._classEnvs[cls.classIndex];
+    ir.Supertype supertype = env.cls.supertype;
+    if (supertype == null) return null;
+    return builder.getClass(supertype.classNode);
+  }
+
+  InterfaceType getMixinTypeForClass(KClass cls) {
+    KClassEnv env = builder._classEnvs[cls.classIndex];
+    ir.Supertype mixedInType = env.cls.mixedInType;
+    if (mixedInType == null) return null;
+    return builder.createInterfaceType(
+        mixedInType.classNode, mixedInType.typeArguments);
+  }
+}
diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart
index 08c8750..c1fde6e 100644
--- a/pkg/compiler/lib/src/mirrors_used.dart
+++ b/pkg/compiler/lib/src/mirrors_used.dart
@@ -456,7 +456,7 @@
         String libraryNameCandiate;
         for (LibraryElement l in compiler.libraryLoader.libraries) {
           if (l.hasLibraryName) {
-            String libraryName = l.libraryOrScriptName;
+            String libraryName = l.libraryName;
             if (string == libraryName) {
               // Found an exact match.
               libraryCandiate = l;
@@ -514,7 +514,7 @@
           reporter.reportHintMessage(
               spannable,
               MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
-              {'name': identifiers[0], 'library': library.libraryOrScriptName});
+              {'name': identifiers[0], 'library': library.name});
         } else {
           reporter.reportHintMessage(
               spannable,
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index e236975..28e7215 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -3,23 +3,28 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
-import '../common/backend_api.dart' show ForeignResolver;
+import '../common/backend_api.dart' show BackendClasses, ForeignResolver;
 import '../common/resolution.dart' show ParsingContext, Resolution;
 import '../compiler.dart' show Compiler;
+import '../compile_time_constants.dart' show ConstantEnvironment;
 import '../constants/expressions.dart';
 import '../constants/values.dart';
 import '../core_types.dart' show CommonElements;
-import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
+import '../elements/resolution_types.dart';
+import '../elements/types.dart';
 import '../js/js.dart' as js;
 import '../js_backend/js_backend.dart';
+import '../js_backend/backend_helpers.dart';
+import '../options.dart';
 import '../tree/tree.dart';
 import '../universe/side_effects.dart' show SideEffects;
 import '../util/util.dart';
-import 'enqueue.dart';
 import 'js.dart';
 
-typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString);
+typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString,
+    {bool required});
 
 /// This class is a temporary work-around until we get a more powerful DartType.
 class SpecialType {
@@ -313,7 +318,7 @@
         return;
       }
       for (final typeString in typesString.split('|')) {
-        onType(_parseType(typeString.trim(), spannable, reporter, lookupType));
+        onType(_parseType(typeString.trim(), lookupType));
       }
     }
 
@@ -495,8 +500,18 @@
 
   /// Returns a [TypeLookup] that uses [resolver] to perform lookup and [node]
   /// as position for errors.
-  static TypeLookup _typeLookup(Node node, ForeignResolver resolver) {
-    return (String name) => resolver.resolveTypeFromString(node, name);
+  static TypeLookup _typeLookup(
+      Node node, DiagnosticReporter reporter, ForeignResolver resolver) {
+    ResolutionDartType lookup(String name, {bool required}) {
+      ResolutionDartType type = resolver.resolveTypeFromString(node, name);
+      if (type == null && required) {
+        reporter.reportErrorMessage(
+            node, MessageKind.GENERIC, {'text': "Type '$name' not found."});
+      }
+      return type;
+    }
+
+    return lookup;
   }
 
   /// Compute the [NativeBehavior] for a [Send] node calling the 'JS' function.
@@ -529,8 +544,13 @@
     String specString = specArgument.dartString.slowToString();
     String codeString = codeArgument.dartString.slowToString();
 
-    return ofJsCall(specString, codeString, _typeLookup(specArgument, resolver),
-        specArgument, reporter, commonElements);
+    return ofJsCall(
+        specString,
+        codeString,
+        _typeLookup(specArgument, reporter, resolver),
+        specArgument,
+        reporter,
+        commonElements);
   }
 
   /// Compute the [NativeBehavior] for a call to the 'JS' function with the
@@ -655,8 +675,12 @@
 
     String specString = specLiteral.dartString.slowToString();
 
-    return ofJsBuiltinCall(specString, _typeLookup(jsBuiltinCall, resolver),
-        jsBuiltinCall, reporter, commonElements);
+    return ofJsBuiltinCall(
+        specString,
+        _typeLookup(jsBuiltinCall, reporter, resolver),
+        jsBuiltinCall,
+        reporter,
+        commonElements);
   }
 
   static NativeBehavior ofJsBuiltinCall(
@@ -720,7 +744,7 @@
 
     return ofJsEmbeddedGlobalCall(
         specString,
-        _typeLookup(jsEmbeddedGlobalCall, resolver),
+        _typeLookup(jsEmbeddedGlobalCall, reporter, resolver),
         jsEmbeddedGlobalCall,
         reporter,
         commonElements);
@@ -753,60 +777,12 @@
       metadata.add(annotation.constant);
     }
 
-    ResolutionDartType lookup(String name) {
-      Element e = element.buildScope().lookup(name);
-      if (e == null) return null;
-      if (e is! ClassElement) return null;
-      ClassElement cls = e;
-      cls.ensureResolved(compiler.resolution);
-      return cls.thisType;
-    }
-
-    return ofMethod(element, type, metadata, lookup, compiler,
+    BehaviorBuilder builder = new ResolverBehaviorBuilder(compiler);
+    return builder.buildMethodBehavior(
+        type, metadata, lookupFromElement(compiler.resolution, element),
         isJsInterop: compiler.backend.isJsInterop(element));
   }
 
-  static NativeBehavior ofMethod(
-      Spannable spannable,
-      ResolutionFunctionType type,
-      List<ConstantExpression> metadata,
-      TypeLookup lookupType,
-      Compiler compiler,
-      {bool isJsInterop}) {
-    var behavior = new NativeBehavior();
-    var returnType = type.returnType;
-    // Note: For dart:html and other internal libraries we maintain, we can
-    // trust the return type and use it to limit what we enqueue. We have to
-    // be more conservative about JS interop types and assume they can return
-    // anything (unless the user provides the experimental flag to trust the
-    // type of js-interop APIs). We do restrict the allocation effects and say
-    // that interop calls create only interop types (which may be unsound if
-    // an interop call returns a DOM type and declares a dynamic return type,
-    // but otherwise we would include a lot of code by default).
-    // TODO(sigmund,sra): consider doing something better for numeric types.
-    behavior.typesReturned.add(
-        !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
-            ? returnType
-            : const ResolutionDynamicType());
-    if (!type.returnType.isVoid) {
-      // Declared types are nullable.
-      behavior.typesReturned.add(compiler.commonElements.nullType);
-    }
-    behavior._capture(type, compiler.resolution,
-        isInterop: isJsInterop, compiler: compiler);
-
-    for (ResolutionDartType type in type.optionalParameterTypes) {
-      behavior._escape(type, compiler.resolution);
-    }
-    for (ResolutionDartType type in type.namedParameterTypes) {
-      behavior._escape(type, compiler.resolution);
-    }
-
-    behavior._overrideWithAnnotations(
-        spannable, metadata, lookupType, compiler);
-    return behavior;
-  }
-
   static NativeBehavior ofFieldElementLoad(
       MemberElement element, Compiler compiler) {
     Resolution resolution = compiler.resolution;
@@ -817,77 +793,86 @@
       metadata.add(annotation.constant);
     }
 
-    ResolutionDartType lookup(String name) {
-      Element e = element.buildScope().lookup(name);
-      if (e == null) return null;
-      if (e is! ClassElement) return null;
-      ClassElement cls = e;
-      cls.ensureResolved(compiler.resolution);
-      return cls.thisType;
-    }
-
-    return ofFieldLoad(element, type, metadata, lookup, compiler,
+    BehaviorBuilder builder = new ResolverBehaviorBuilder(compiler);
+    return builder.buildFieldLoadBehavior(
+        type, metadata, lookupFromElement(resolution, element),
         isJsInterop: compiler.backend.isJsInterop(element));
   }
 
-  static NativeBehavior ofFieldLoad(
-      Spannable spannable,
-      ResolutionDartType type,
-      List<ConstantExpression> metadata,
-      TypeLookup lookupType,
-      Compiler compiler,
-      {bool isJsInterop}) {
-    Resolution resolution = compiler.resolution;
-    var behavior = new NativeBehavior();
-    // TODO(sigmund,sra): consider doing something better for numeric types.
-    behavior.typesReturned.add(
-        !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
-            ? type
-            : const ResolutionDynamicType());
-    // Declared types are nullable.
-    behavior.typesReturned.add(resolution.commonElements.nullType);
-    behavior._capture(type, resolution,
-        isInterop: isJsInterop, compiler: compiler);
-    behavior._overrideWithAnnotations(
-        spannable, metadata, lookupType, compiler);
-    return behavior;
-  }
-
   static NativeBehavior ofFieldElementStore(
-      MemberElement field, Resolution resolution) {
-    ResolutionDartType type = field.computeType(resolution);
-    return ofFieldStore(type, resolution);
+      MemberElement field, Compiler compiler) {
+    BehaviorBuilder builder = new ResolverBehaviorBuilder(compiler);
+    ResolutionDartType type = field.computeType(compiler.resolution);
+    return builder.buildFieldStoreBehavior(type);
   }
 
-  static NativeBehavior ofFieldStore(
-      ResolutionDartType type, Resolution resolution) {
-    var behavior = new NativeBehavior();
-    behavior._escape(type, resolution);
-    // We don't override the default behaviour - the annotations apply to
-    // loading the field.
-    return behavior;
+  static TypeLookup lookupFromElement(Resolution resolution, Element element) {
+    ResolutionDartType lookup(String name, {bool required}) {
+      Element e = element.buildScope().lookup(name);
+      if (e == null || e is! ClassElement) {
+        if (required) {
+          resolution.reporter.reportErrorMessage(element, MessageKind.GENERIC,
+              {'text': "Type '$name' not found."});
+        }
+        return null;
+      }
+      ClassElement cls = e;
+      cls.ensureResolved(resolution);
+      return cls.thisType;
+    }
+
+    return lookup;
   }
 
+  static dynamic /*DartType|SpecialType*/ _parseType(
+      String typeString, TypeLookup lookupType) {
+    if (typeString == '=Object') return SpecialType.JsObject;
+    if (typeString == 'dynamic') {
+      return const ResolutionDynamicType();
+    }
+    int index = typeString.indexOf('<');
+    var type = lookupType(typeString, required: index == -1);
+    if (type != null) return type;
+
+    if (index != -1) {
+      type = lookupType(typeString.substring(0, index), required: true);
+      if (type != null) {
+        // TODO(sra): Parse type parameters.
+        return type;
+      }
+    }
+    return const ResolutionDynamicType();
+  }
+}
+
+abstract class BehaviorBuilder {
+  CommonElements get commonElements;
+  BackendClasses get backendClasses;
+  BackendHelpers get helpers;
+  DiagnosticReporter get reporter;
+  ConstantEnvironment get constants;
+  bool get trustJSInteropTypeAnnotations;
+
+  Resolution get resolution => null;
+
+  NativeBehavior _behavior;
+
   void _overrideWithAnnotations(
-      Spannable spannable,
-      Iterable<ConstantExpression> metadata,
-      TypeLookup lookupType,
-      Compiler compiler) {
+      Iterable<ConstantExpression> metadata, TypeLookup lookupType) {
     if (metadata.isEmpty) return;
 
-    NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer;
-    var creates = _collect(spannable, metadata, compiler,
-        enqueuer.annotationCreatesClass, lookupType);
-    var returns = _collect(spannable, metadata, compiler,
-        enqueuer.annotationReturnsClass, lookupType);
+    List creates =
+        _collect(metadata, helpers.annotationCreatesClass, lookupType);
+    List returns =
+        _collect(metadata, helpers.annotationReturnsClass, lookupType);
 
     if (creates != null) {
-      typesInstantiated
+      _behavior.typesInstantiated
         ..clear()
         ..addAll(creates);
     }
     if (returns != null) {
-      typesReturned
+      _behavior.typesReturned
         ..clear()
         ..addAll(returns);
     }
@@ -898,12 +883,11 @@
    * [annotationClass].
    * Returns `null` if no constraints.
    */
-  static _collect(Spannable spannable, Iterable<ConstantExpression> metadata,
-      Compiler compiler, Element annotationClass, TypeLookup lookupType) {
-    DiagnosticReporter reporter = compiler.reporter;
+  List _collect(Iterable<ConstantExpression> metadata,
+      ClassEntity annotationClass, TypeLookup lookupType) {
     var types = null;
     for (ConstantExpression constant in metadata) {
-      ConstantValue value = compiler.constants.getConstantValue(constant);
+      ConstantValue value = constants.getConstantValue(constant);
       if (!value.isConstructedObject) continue;
       ConstructedConstantValue constructedObject = value;
       if (constructedObject.type.element != annotationClass) continue;
@@ -911,13 +895,13 @@
       Iterable<ConstantValue> fields = constructedObject.fields.values;
       // TODO(sra): Better validation of the constant.
       if (fields.length != 1 || !fields.single.isString) {
-        reporter.internalError(spannable,
+        reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
             'Annotations needs one string: ${constant.toStructuredText()}');
       }
       StringConstantValue specStringConstant = fields.single;
       String specString = specStringConstant.toDartString().slowToString();
       for (final typeString in specString.split('|')) {
-        var type = _parseType(typeString, spannable, reporter, lookupType);
+        var type = NativeBehavior._parseType(typeString, lookupType);
         if (types == null) types = [];
         types.add(type);
       }
@@ -927,16 +911,18 @@
 
   /// Models the behavior of having intances of [type] escape from Dart code
   /// into native code.
-  void _escape(ResolutionDartType type, Resolution resolution) {
-    type.computeUnaliased(resolution);
+  void _escape(DartType type) {
+    if (type is ResolutionDartType) {
+      type.computeUnaliased(resolution);
+    }
     type = type.unaliased;
-    if (type is ResolutionFunctionType) {
-      ResolutionFunctionType functionType = type;
+    if (type is FunctionType) {
+      FunctionType functionType = type;
       // A function might be called from native code, passing us novel
       // parameters.
-      _escape(functionType.returnType, resolution);
-      for (ResolutionDartType parameter in functionType.parameterTypes) {
-        _capture(parameter, resolution);
+      _escape(functionType.returnType);
+      for (DartType parameter in functionType.parameterTypes) {
+        _capture(parameter);
       }
     }
   }
@@ -947,40 +933,40 @@
   ///
   /// We assume that JS-interop APIs cannot instantiate Dart types or
   /// non-JSInterop native types.
-  void _capture(ResolutionDartType type, Resolution resolution,
-      {bool isInterop: false, Compiler compiler}) {
-    type.computeUnaliased(resolution);
+  void _capture(DartType type, {bool isInterop: false}) {
+    if (type is ResolutionDartType) {
+      type.computeUnaliased(resolution);
+    }
     type = type.unaliased;
-    if (type is ResolutionFunctionType) {
-      ResolutionFunctionType functionType = type;
-      _capture(functionType.returnType, resolution,
-          isInterop: isInterop, compiler: compiler);
-      for (ResolutionDartType parameter in functionType.parameterTypes) {
-        _escape(parameter, resolution);
+    if (type is FunctionType) {
+      FunctionType functionType = type;
+      _capture(functionType.returnType, isInterop: isInterop);
+      for (DartType parameter in functionType.parameterTypes) {
+        _escape(parameter);
       }
     } else {
-      JavaScriptBackend backend = compiler?.backend;
       if (!isInterop) {
-        typesInstantiated.add(type);
+        _behavior.typesInstantiated.add(type);
       } else {
-        if (type.element != null && backend.isNative(type.element)) {
+        if (type is InterfaceType &&
+            backendClasses.isNativeClass(type.element)) {
           // Any declared native or interop type (isNative implies isJsInterop)
           // is assumed to be allocated.
-          typesInstantiated.add(type);
+          _behavior.typesInstantiated.add(type);
         }
 
-        if (!compiler.options.trustJSInteropTypeAnnotations ||
+        if (!trustJSInteropTypeAnnotations ||
             type.isDynamic ||
-            type.isObject) {
+            type == commonElements.objectType) {
           // By saying that only JS-interop types can be created, we prevent
           // pulling in every other native type (e.g. all of dart:html) when a
           // JS interop API returns dynamic or when we don't trust the type
           // annotations. This means that to some degree we still use the return
           // type to decide whether to include native types, even if we don't
           // trust the type annotation.
-          ClassElement cls = backend.helpers.jsJavaScriptObjectClass;
+          ClassElement cls = helpers.jsJavaScriptObjectClass;
           cls.ensureResolved(resolution);
-          typesInstantiated.add(cls.thisType);
+          _behavior.typesInstantiated.add(cls.thisType);
         } else {
           // Otherwise, when the declared type is a Dart type, we do not
           // register an allocation because we assume it cannot be instantiated
@@ -991,28 +977,91 @@
     }
   }
 
-  static dynamic /*DartType|SpecialType*/ _parseType(String typeString,
-      Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) {
-    if (typeString == '=Object') return SpecialType.JsObject;
-    if (typeString == 'dynamic') {
-      return const ResolutionDynamicType();
-    }
-    var type = lookupType(typeString);
-    if (type != null) return type;
-
-    int index = typeString.indexOf('<');
-    if (index < 1) {
-      reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
-          {'text': "Type '$typeString' not found."});
-      return const ResolutionDynamicType();
-    }
-    type = lookupType(typeString.substring(0, index));
-    if (type != null) {
-      // TODO(sra): Parse type parameters.
-      return type;
-    }
-    reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
-        {'text': "Type '$typeString' not found."});
-    return const ResolutionDynamicType();
+  NativeBehavior buildFieldLoadBehavior(DartType type,
+      Iterable<ConstantExpression> metadata, TypeLookup lookupType,
+      {bool isJsInterop}) {
+    _behavior = new NativeBehavior();
+    // TODO(sigmund,sra): consider doing something better for numeric types.
+    _behavior.typesReturned.add(!isJsInterop || trustJSInteropTypeAnnotations
+        ? type
+        : commonElements.dynamicType);
+    // Declared types are nullable.
+    _behavior.typesReturned.add(commonElements.nullType);
+    _capture(type, isInterop: isJsInterop);
+    _overrideWithAnnotations(metadata, lookupType);
+    return _behavior;
   }
+
+  NativeBehavior buildFieldStoreBehavior(DartType type) {
+    _behavior = new NativeBehavior();
+    _escape(type);
+    // We don't override the default behaviour - the annotations apply to
+    // loading the field.
+    return _behavior;
+  }
+
+  NativeBehavior buildMethodBehavior(FunctionType type,
+      List<ConstantExpression> metadata, TypeLookup lookupType,
+      {bool isJsInterop}) {
+    _behavior = new NativeBehavior();
+    DartType returnType = type.returnType;
+    // Note: For dart:html and other internal libraries we maintain, we can
+    // trust the return type and use it to limit what we enqueue. We have to
+    // be more conservative about JS interop types and assume they can return
+    // anything (unless the user provides the experimental flag to trust the
+    // type of js-interop APIs). We do restrict the allocation effects and say
+    // that interop calls create only interop types (which may be unsound if
+    // an interop call returns a DOM type and declares a dynamic return type,
+    // but otherwise we would include a lot of code by default).
+    // TODO(sigmund,sra): consider doing something better for numeric types.
+    _behavior.typesReturned.add(!isJsInterop || trustJSInteropTypeAnnotations
+        ? returnType
+        : commonElements.dynamicType);
+    if (!type.returnType.isVoid) {
+      // Declared types are nullable.
+      _behavior.typesReturned.add(commonElements.nullType);
+    }
+    _capture(type, isInterop: isJsInterop);
+
+    for (DartType type in type.optionalParameterTypes) {
+      _escape(type);
+    }
+    for (DartType type in type.namedParameterTypes) {
+      _escape(type);
+    }
+
+    _overrideWithAnnotations(metadata, lookupType);
+    return _behavior;
+  }
+}
+
+class ResolverBehaviorBuilder extends BehaviorBuilder {
+  final Compiler compiler;
+
+  ResolverBehaviorBuilder(this.compiler);
+
+  @override
+  CommonElements get commonElements => compiler.commonElements;
+
+  @override
+  bool get trustJSInteropTypeAnnotations =>
+      compiler.options.trustJSInteropTypeAnnotations;
+
+  @override
+  ConstantEnvironment get constants => compiler.constants;
+
+  @override
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  @override
+  BackendHelpers get helpers {
+    JavaScriptBackend backend = compiler.backend;
+    return backend.helpers;
+  }
+
+  @override
+  BackendClasses get backendClasses => compiler.backend.backendClasses;
+
+  @override
+  Resolution get resolution => compiler.resolution;
 }
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 2b804bd..3f9610e 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:collection' show Queue;
-
 import '../common.dart';
 import '../common/backend_api.dart' show ForeignResolver;
 import '../common/resolution.dart' show Resolution;
@@ -17,8 +15,8 @@
 import '../js_backend/backend_helpers.dart' show BackendHelpers;
 import '../js_backend/js_backend.dart';
 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
-import '../tokens/token.dart' show BeginGroupToken, Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
+import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
 import '../tree/tree.dart';
 import '../universe/use.dart' show StaticUse, TypeUse;
 import '../universe/world_impact.dart'
@@ -58,11 +56,6 @@
 
   /// Emits a summary information using the [log] function.
   void logSummary(log(message)) {}
-
-  // Do not use annotations in dart2dart.
-  ClassElement get annotationCreatesClass => null;
-  ClassElement get annotationReturnsClass => null;
-  ClassElement get annotationJsNameClass => null;
 }
 
 abstract class NativeEnqueuerBase implements NativeEnqueuer {
@@ -75,8 +68,6 @@
   final Set<ClassElement> _registeredClasses = new Set<ClassElement>();
   final Set<ClassElement> _unusedClasses = new Set<ClassElement>();
 
-  final Set<LibraryElement> processedLibraries;
-
   bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty;
 
   final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
@@ -84,14 +75,9 @@
   final Compiler compiler;
   final bool enableLiveTypeAnalysis;
 
-  ClassElement _annotationCreatesClass;
-  ClassElement _annotationReturnsClass;
-  ClassElement _annotationJsNameClass;
-
   /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
   NativeEnqueuerBase(Compiler compiler, this.enableLiveTypeAnalysis)
-      : this.compiler = compiler,
-        processedLibraries = compiler.cacheStrategy.newSet();
+      : this.compiler = compiler;
 
   JavaScriptBackend get backend => compiler.backend;
   BackendHelpers get helpers => backend.helpers;
@@ -114,12 +100,6 @@
 
   void _processNativeClasses(
       WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {
-    if (compiler.options.hasIncrementalSupport) {
-      // Since [Set.add] returns bool if an element was added, this restricts
-      // [libraries] to ones that haven't already been processed. This saves
-      // time during incremental compiles.
-      libraries = libraries.where(processedLibraries.add);
-    }
     libraries.forEach(processNativeClassesInLibrary);
     if (helpers.isolateHelperLibrary != null) {
       processNativeClassesInLibrary(helpers.isolateHelperLibrary);
@@ -267,34 +247,11 @@
     });
   }
 
-  ClassElement get annotationCreatesClass {
-    findAnnotationClasses();
-    return _annotationCreatesClass;
-  }
-
-  ClassElement get annotationReturnsClass {
-    findAnnotationClasses();
-    return _annotationReturnsClass;
-  }
-
-  ClassElement get annotationJsNameClass {
-    findAnnotationClasses();
-    return _annotationJsNameClass;
-  }
-
-  void findAnnotationClasses() {
-    if (_annotationCreatesClass != null) return;
-
-    _annotationCreatesClass = helpers.annotationCreatesClass;
-    _annotationReturnsClass = helpers.annotationReturnsClass;
-    _annotationJsNameClass = helpers.annotationJSNameClass;
-  }
-
   /// Returns the JSName annotation string or `null` if no JSName annotation is
   /// present.
   String findJsNameFromAnnotation(Element element) {
     String name = null;
-    ClassElement annotationClass = annotationJsNameClass;
+    ClassElement annotationClass = backend.helpers.annotationJSNameClass;
     for (MetadataAnnotation annotation in element.implementation.metadata) {
       annotation.ensureResolved(resolution);
       ConstantValue value =
@@ -437,21 +394,15 @@
         continue;
       }
       if (type is ResolutionInterfaceType) {
-        if (type == commonElements.intType) {
-          registerInstantiation(type);
-        } else if (type == commonElements.doubleType) {
-          registerInstantiation(type);
-        } else if (type == commonElements.numType) {
+        if (type == commonElements.numType) {
           registerInstantiation(commonElements.doubleType);
           registerInstantiation(commonElements.intType);
-        } else if (type == commonElements.stringType) {
-          registerInstantiation(type);
-        } else if (type == commonElements.nullType) {
-          registerInstantiation(type);
-        } else if (type == commonElements.boolType) {
-          registerInstantiation(type);
-        } else if (compiler.types.isSubtype(
-            type, backend.backendClasses.listImplementation.rawType)) {
+        } else if (type == commonElements.intType ||
+            type == commonElements.doubleType ||
+            type == commonElements.stringType ||
+            type == commonElements.nullType ||
+            type == commonElements.boolType ||
+            type.asInstanceOf(backend.backendClasses.listClass) != null) {
           registerInstantiation(type);
         }
         // TODO(johnniwinther): Improve spec string precision to handle type
diff --git a/pkg/compiler/lib/src/native/scanner.dart b/pkg/compiler/lib/src/native/scanner.dart
index c1bc40d..1ce396e 100644
--- a/pkg/compiler/lib/src/native/scanner.dart
+++ b/pkg/compiler/lib/src/native/scanner.dart
@@ -4,12 +4,13 @@
 
 import '../common.dart';
 import '../parser/element_listener.dart' show ElementListener;
-import '../tokens/token.dart' show BeginGroupToken, Token;
-import '../tokens/token_constants.dart' as Tokens show STRING_TOKEN;
+import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
+import 'package:front_end/src/fasta/scanner/token_constants.dart' as Tokens
+    show STRING_TOKEN;
 
 void checkAllowedLibrary(ElementListener listener, Token token) {
   if (listener.scannerOptions.canUseNative) return;
-  listener.reportError(token, MessageKind.NATIVE_NOT_SUPPORTED);
+  listener.reportErrorFromToken(token, MessageKind.NATIVE_NOT_SUPPORTED);
 }
 
 Token handleNativeBlockToSkip(ElementListener listener, Token token) {
diff --git a/pkg/compiler/lib/src/native/ssa.dart b/pkg/compiler/lib/src/native/ssa.dart
index 20d1ee3..ed66563 100644
--- a/pkg/compiler/lib/src/native/ssa.dart
+++ b/pkg/compiler/lib/src/native/ssa.dart
@@ -33,7 +33,7 @@
         builder.graph.addConstant(arityConstant, builder.closedWorld);
     // TODO(ngeoffray): For static methods, we could pass a method with a
     // defined arity.
-    Element helper = backend.helpers.closureConverter;
+    MethodElement helper = backend.helpers.closureConverter;
     builder.pushInvokeStatic(nativeBody, helper, [local, arity]);
     HInstruction closure = builder.pop();
     return closure;
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 59992f5..32589f3 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -160,11 +160,6 @@
   /// Whether to generate a source-map file together with the output program.
   final bool generateSourceMap;
 
-  /// Whether some values are cached for reuse in incremental compilation.
-  /// Incremental compilation allows calling `Compiler.run` more than once
-  /// (experimental).
-  final bool hasIncrementalSupport;
-
   /// URI of the main output if the compiler is generating source maps.
   final Uri outputUri;
 
@@ -280,8 +275,6 @@
         generateCodeWithCompileTimeErrors:
             _hasOption(options, Flags.generateCodeWithCompileTimeErrors),
         generateSourceMap: !_hasOption(options, Flags.noSourceMaps),
-        hasIncrementalSupport: _forceIncrementalSupport ||
-            _hasOption(options, Flags.incrementalSupport),
         outputUri: _extractUriOption(options, '--out='),
         platformConfigUri:
             _resolvePlatformConfigFromOptions(libraryRoot, options),
@@ -343,7 +336,6 @@
       bool enableUserAssertions: false,
       bool generateCodeWithCompileTimeErrors: false,
       bool generateSourceMap: true,
-      bool hasIncrementalSupport: false,
       Uri outputUri: null,
       Uri platformConfigUri: null,
       bool preserveComments: false,
@@ -402,7 +394,7 @@
         suppressWarnings: suppressWarnings,
         suppressHints: suppressHints,
         shownPackageWarnings: shownPackageWarnings,
-        disableInlining: disableInlining || hasIncrementalSupport,
+        disableInlining: disableInlining,
         disableTypeInference: disableTypeInference,
         dumpInfo: dumpInfo,
         enableAssertMessage: enableAssertMessage,
@@ -413,7 +405,6 @@
         enableUserAssertions: enableUserAssertions,
         generateCodeWithCompileTimeErrors: generateCodeWithCompileTimeErrors,
         generateSourceMap: generateSourceMap,
-        hasIncrementalSupport: hasIncrementalSupport,
         outputUri: outputUri,
         platformConfigUri: platformConfigUri ??
             _resolvePlatformConfig(libraryRoot, null, const []),
@@ -462,7 +453,6 @@
       this.enableUserAssertions: false,
       this.generateCodeWithCompileTimeErrors: false,
       this.generateSourceMap: true,
-      this.hasIncrementalSupport: false,
       this.outputUri: null,
       this.platformConfigUri: null,
       this.preserveComments: false,
@@ -518,7 +508,6 @@
       enableUserAssertions,
       generateCodeWithCompileTimeErrors,
       generateSourceMap,
-      hasIncrementalSupport,
       outputUri,
       platformConfigUri,
       preserveComments,
@@ -580,8 +569,6 @@
         generateCodeWithCompileTimeErrors: generateCodeWithCompileTimeErrors ??
             options.generateCodeWithCompileTimeErrors,
         generateSourceMap: generateSourceMap ?? options.generateSourceMap,
-        hasIncrementalSupport:
-            hasIncrementalSupport ?? options.hasIncrementalSupport,
         outputUri: outputUri ?? options.outputUri,
         platformConfigUri: platformConfigUri ?? options.platformConfigUri,
         preserveComments: preserveComments ?? options.preserveComments,
@@ -706,5 +693,3 @@
 const String _sharedPlatform = "lib/dart_shared.platform";
 
 const String _UNDETERMINED_BUILD_ID = "build number could not be determined";
-const bool _forceIncrementalSupport =
-    const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT');
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index 4798c43..464b826 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -9,7 +9,8 @@
 import 'diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
 import 'elements/elements.dart' show ClassElement;
 import 'util/util.dart' show Link, LinkBuilder;
-import 'util/util_implementation.dart' show LinkEntry;
+import 'package:front_end/src/fasta/util/link_implementation.dart'
+    show LinkEntry;
 
 /**
  * An ordered set of the supertypes of a class. The supertypes of a class are
diff --git a/pkg/compiler/lib/src/parser/class_element_parser.dart b/pkg/compiler/lib/src/parser/class_element_parser.dart
deleted file mode 100644
index 88a6fa1..0000000
--- a/pkg/compiler/lib/src/parser/class_element_parser.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.parser.classes;
-
-import '../tokens/token.dart' show Token;
-import 'listener.dart' show Listener;
-import 'partial_parser.dart' show PartialParser;
-
-class ClassElementParser extends PartialParser {
-  ClassElementParser(Listener listener) : super(listener);
-
-  Token parseClassBody(Token token) => fullParseClassBody(token);
-}
diff --git a/pkg/compiler/lib/src/parser/diet_parser_task.dart b/pkg/compiler/lib/src/parser/diet_parser_task.dart
index aa635b9..d987f57 100644
--- a/pkg/compiler/lib/src/parser/diet_parser_task.dart
+++ b/pkg/compiler/lib/src/parser/diet_parser_task.dart
@@ -5,18 +5,24 @@
 library dart2js.parser.diet.task;
 
 import '../common.dart';
-import '../common/backend_api.dart' show Backend;
 import '../common/tasks.dart' show CompilerTask, Measurer;
 import '../elements/elements.dart' show CompilationUnitElement;
+import '../js_backend/backend.dart' show JavaScriptBackend;
 import '../id_generator.dart';
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import 'element_listener.dart' show ElementListener, ScannerOptions;
-import 'listener.dart' show ParserError;
-import 'partial_parser.dart' show PartialParser;
+import 'package:front_end/src/fasta/parser.dart'
+    show Listener, ParserError, TopLevelParser;
+
+class PartialParser extends TopLevelParser {
+  PartialParser(Listener listener) : super(listener);
+
+  Token parseFormalParameters(Token token) => skipFormalParameters(token);
+}
 
 class DietParserTask extends CompilerTask {
   final IdGenerator _idGenerator;
-  final Backend _backend;
+  final JavaScriptBackend _backend;
   final DiagnosticReporter _reporter;
 
   DietParserTask(
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index 5c058ee..61975e9 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -22,14 +22,15 @@
 import '../id_generator.dart';
 import '../native/native.dart' as native;
 import '../string_validator.dart' show StringValidator;
-import '../tokens/keyword.dart' show Keyword;
-import '../tokens/precedence_constants.dart' as Precedence show BAD_INPUT_INFO;
-import '../tokens/token.dart'
-    show BeginGroupToken, ErrorToken, KeywordToken, Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
+import 'package:front_end/src/fasta/scanner.dart'
+    show Keyword, BeginGroupToken, ErrorToken, KeywordToken, StringToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
+import 'package:front_end/src/fasta/scanner/precedence.dart' as Precedence
+    show BAD_INPUT_INFO, IDENTIFIER_INFO;
 import '../tree/tree.dart';
 import '../util/util.dart' show Link, LinkBuilder;
-import 'listener.dart' show closeBraceFor, Listener, ParserError, VERBOSE;
+import 'package:front_end/src/fasta/parser.dart'
+    show ErrorKind, Listener, ParserError, optional;
 import 'partial_elements.dart'
     show
         PartialClassElement,
@@ -39,6 +40,8 @@
         PartialMetadataAnnotation,
         PartialTypedefElement;
 
+const bool VERBOSE = false;
+
 /// Options used for scanning.
 ///
 /// Use this to conditionally support special tokens.
@@ -82,6 +85,10 @@
 
   bool suppressParseErrors = false;
 
+  /// Set to true each time we parse a native function body. It is reset in
+  /// [handleInvalidFunctionBody] which is called immediately after.
+  bool lastErrorWasNativeFunctionBody = false;
+
   ElementListener(this.scannerOptions, DiagnosticReporter reporter,
       this.compilationUnitElement, this.idGenerator)
       : this.reporter = reporter,
@@ -121,12 +128,14 @@
         library.entryCompilationUnit == compilationUnitElement;
   }
 
+  @override
   void endLibraryName(Token libraryKeyword, Token semicolon) {
     Expression name = popNode();
     addLibraryTag(new LibraryName(
         libraryKeyword, name, popMetadata(compilationUnitElement)));
   }
 
+  @override
   void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
       Token semicolon) {
     NodeList combinators = popNode();
@@ -142,11 +151,13 @@
         isDeferred: isDeferred));
   }
 
+  @override
   void endDottedName(int count, Token token) {
     NodeList identifiers = makeNodeList(count, null, null, '.');
     pushNode(new DottedName(token, identifiers));
   }
 
+  @override
   void endConditionalUris(int count) {
     if (count == 0) {
       pushNode(null);
@@ -155,6 +166,7 @@
     }
   }
 
+  @override
   void endConditionalUri(Token ifToken, Token equalSign) {
     StringNode uri = popNode();
     LiteralString conditionValue = (equalSign != null) ? popNode() : null;
@@ -162,6 +174,7 @@
     pushNode(new ConditionalUri(ifToken, identifier, conditionValue, uri));
   }
 
+  @override
   void endEnum(Token enumKeyword, Token endBrace, int count) {
     NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
     Identifier name = popNode();
@@ -173,6 +186,7 @@
     rejectBuiltInIdentifier(name);
   }
 
+  @override
   void endExport(Token exportKeyword, Token semicolon) {
     NodeList combinators = popNode();
     NodeList conditionalUris = popNode();
@@ -181,6 +195,7 @@
         popMetadata(compilationUnitElement)));
   }
 
+  @override
   void endCombinators(int count) {
     if (0 == count) {
       pushNode(null);
@@ -189,8 +204,10 @@
     }
   }
 
+  @override
   void endHide(Token hideKeyword) => pushCombinator(hideKeyword);
 
+  @override
   void endShow(Token showKeyword) => pushCombinator(showKeyword);
 
   void pushCombinator(Token keywordToken) {
@@ -198,20 +215,24 @@
     pushNode(new Combinator(identifiers, keywordToken));
   }
 
+  @override
   void endIdentifierList(int count) {
     pushNode(makeNodeList(count, null, null, ","));
   }
 
+  @override
   void endTypeList(int count) {
     pushNode(makeNodeList(count, null, null, ","));
   }
 
+  @override
   void endPart(Token partKeyword, Token semicolon) {
     StringNode uri = popLiteralString();
     addLibraryTag(
         new Part(partKeyword, uri, popMetadata(compilationUnitElement)));
   }
 
+  @override
   void endPartOf(Token partKeyword, Token semicolon) {
     Expression name = popNode();
     addPartOfTag(
@@ -222,6 +243,7 @@
     compilationUnitElement.setPartOf(tag, reporter);
   }
 
+  @override
   void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
     if (periodBeforeName != null) {
       popNode(); // Discard name.
@@ -230,14 +252,17 @@
     pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
   }
 
+  @override
   void endTopLevelDeclaration(Token token) {
     if (!metadata.isEmpty) {
       MetadataAnnotationX first = metadata.first;
-      recoverableError(first.beginToken, 'Metadata not supported here.');
+      recoverableError(reporter.spanFromToken(first.beginToken),
+          'Metadata not supported here.');
       metadata.clear();
     }
   }
 
+  @override
   void endClassDeclaration(int interfacesCount, Token beginToken,
       Token extendsKeyword, Token implementsKeyword, Token endToken) {
     makeNodeList(interfacesCount, implementsKeyword, null, ","); // interfaces
@@ -260,6 +285,7 @@
     }
   }
 
+  @override
   void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
     popNode(); // TODO(karlklose): do not throw away typeVariables.
     Identifier name = popNode();
@@ -269,6 +295,7 @@
     rejectBuiltInIdentifier(name);
   }
 
+  @override
   void endNamedMixinApplication(
       Token classKeyword, Token implementsKeyword, Token endToken) {
     NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
@@ -292,16 +319,19 @@
     rejectBuiltInIdentifier(name);
   }
 
+  @override
   void endMixinApplication() {
     NodeList mixins = popNode();
     TypeAnnotation superclass = popNode();
     pushNode(new MixinApplication(superclass, mixins));
   }
 
+  @override
   void handleVoidKeyword(Token token) {
     pushNode(new TypeAnnotation(new Identifier(token), null));
   }
 
+  @override
   void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
     bool hasParseError = currentMemberHasParseError;
     memberErrors = memberErrors.tail;
@@ -315,6 +345,7 @@
     pushElement(element);
   }
 
+  @override
   void endTopLevelFields(int count, Token beginToken, Token endToken) {
     bool hasParseError = currentMemberHasParseError;
     memberErrors = memberErrors.tail;
@@ -351,20 +382,24 @@
     }
   }
 
+  @override
   void handleIdentifier(Token token) {
     pushNode(new Identifier(token));
   }
 
+  @override
   void handleQualified(Token period) {
     Identifier last = popNode();
     Expression first = popNode();
     pushNode(new Send(first, last));
   }
 
+  @override
   void handleNoType(Token token) {
     pushNode(null);
   }
 
+  @override
   void endTypeVariable(Token token, Token extendsOrSuper) {
     TypeAnnotation bound = popNode();
     Identifier name = popNode();
@@ -372,37 +407,45 @@
     rejectBuiltInIdentifier(name);
   }
 
+  @override
   void endTypeVariables(int count, Token beginToken, Token endToken) {
     pushNode(makeNodeList(count, beginToken, endToken, ','));
   }
 
+  @override
   void handleNoTypeVariables(Token token) {
     pushNode(null);
   }
 
+  @override
   void endTypeArguments(int count, Token beginToken, Token endToken) {
     pushNode(makeNodeList(count, beginToken, endToken, ','));
   }
 
+  @override
   void handleNoTypeArguments(Token token) {
     pushNode(null);
   }
 
+  @override
   void endType(Token beginToken, Token endToken) {
     NodeList typeArguments = popNode();
     Expression typeName = popNode();
     pushNode(new TypeAnnotation(typeName, typeArguments));
   }
 
+  @override
   void handleParenthesizedExpression(BeginGroupToken token) {
     Expression expression = popNode();
     pushNode(new ParenthesizedExpression(expression, token));
   }
 
+  @override
   void handleModifier(Token token) {
     pushNode(new Identifier(token));
   }
 
+  @override
   void handleModifiers(int count) {
     if (count == 0) {
       pushNode(Modifiers.EMPTY);
@@ -412,29 +455,236 @@
     }
   }
 
-  Token expected(String string, Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else if (identical(';', string)) {
-      // When a semicolon is missing, it often leads to an error on the
-      // following line. So we try to find the token preceding the semicolon
-      // and report that something is missing *after* it.
-      Token preceding = findPrecedingToken(token);
-      if (preceding == token) {
-        reportError(
-            token, MessageKind.MISSING_TOKEN_BEFORE_THIS, {'token': string});
-      } else {
-        reportError(
-            preceding, MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': string});
-      }
-      return token;
+  @override
+  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+    Token next = handleError(token, kind, arguments);
+    if (next == null &&
+        kind != ErrorKind.UnterminatedComment &&
+        kind != ErrorKind.UnterminatedString) {
+      throw new ParserError.fromTokens(token, token, kind, arguments);
     } else {
-      reportFatalError(
-          token,
-          MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
-              .message({'token': string}, true).toString());
+      return next;
     }
-    return skipToEof(token);
+  }
+
+  @override
+  void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
+    handleError(token, kind, arguments);
+  }
+
+  @override
+  void handleInvalidExpression(Token token) {
+    pushNode(new ErrorExpression(token));
+  }
+
+  @override
+  void handleInvalidFunctionBody(Token token) {
+    lastErrorWasNativeFunctionBody = false;
+  }
+
+  @override
+  void handleInvalidTypeReference(Token token) {
+    pushNode(null);
+  }
+
+  Token handleError(Token token, ErrorKind kind, Map arguments) {
+    MessageKind errorCode;
+
+    switch (kind) {
+      case ErrorKind.ExpectedButGot:
+        String expected = arguments["expected"];
+        if (identical(";", expected)) {
+          // When a semicolon is missing, it often leads to an error on the
+          // following line. So we try to find the token preceding the semicolon
+          // and report that something is missing *after* it.
+          Token preceding = findPrecedingToken(token);
+          if (preceding == token) {
+            reportErrorFromToken(token, MessageKind.MISSING_TOKEN_BEFORE_THIS,
+                {'token': expected});
+          } else {
+            reportErrorFromToken(preceding,
+                MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': expected});
+          }
+          return token;
+        } else {
+          reportFatalError(
+              reporter.spanFromToken(token),
+              MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
+                  .message({'token': expected}, true).toString());
+          return null;
+        }
+        break;
+
+      case ErrorKind.ExpectedIdentifier:
+        if (token is KeywordToken) {
+          reportErrorFromToken(
+              token,
+              MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+              {'keyword': token.value});
+        } else if (token is ErrorToken) {
+          // TODO(ahe): This is dead code.
+          return synthesizeIdentifier(token);
+        } else {
+          reportFatalError(reporter.spanFromToken(token),
+              "Expected identifier, but got '${token.value}'.");
+        }
+        return token;
+
+      case ErrorKind.ExpectedType:
+        reportFatalError(reporter.spanFromToken(token),
+            "Expected a type, but got '${token.value}'.");
+        return null;
+
+      case ErrorKind.ExpectedExpression:
+        reportFatalError(reporter.spanFromToken(token),
+            "Expected an expression, but got '${token.value}'.");
+        return null;
+
+      case ErrorKind.UnexpectedToken:
+        String message = "Unexpected token '${token.value}'.";
+        if (token.info == Precedence.BAD_INPUT_INFO) {
+          message = token.value;
+        }
+        reportFatalError(reporter.spanFromToken(token), message);
+        return null;
+
+      case ErrorKind.ExpectedBlockToSkip:
+        if (optional("native", token)) {
+          return native.handleNativeBlockToSkip(this, token);
+        } else {
+          errorCode = MessageKind.BODY_EXPECTED;
+        }
+        break;
+
+      case ErrorKind.ExpectedFunctionBody:
+        if (optional("native", token)) {
+          lastErrorWasNativeFunctionBody = true;
+          return native.handleNativeFunctionBody(this, token);
+        } else {
+          reportFatalError(reporter.spanFromToken(token),
+              "Expected a function body, but got '${token.value}'.");
+        }
+        return null;
+
+      case ErrorKind.ExpectedClassBodyToSkip:
+      case ErrorKind.ExpectedClassBody:
+        reportFatalError(reporter.spanFromToken(token),
+            "Expected a class body, but got '${token.value}'.");
+        return null;
+
+      case ErrorKind.ExpectedDeclaration:
+        reportFatalError(reporter.spanFromToken(token),
+            "Expected a declaration, but got '${token.value}'.");
+        return null;
+
+      case ErrorKind.UnmatchedToken:
+        reportErrorFromToken(token, MessageKind.UNMATCHED_TOKEN, arguments);
+        Token next = token.next;
+        while (next is ErrorToken) {
+          next = next.next;
+        }
+        return next;
+
+      case ErrorKind.EmptyNamedParameterList:
+        errorCode = MessageKind.EMPTY_NAMED_PARAMETER_LIST;
+        break;
+
+      case ErrorKind.EmptyOptionalParameterList:
+        errorCode = MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST;
+        break;
+
+      case ErrorKind.ExpectedBody:
+        errorCode = MessageKind.BODY_EXPECTED;
+        break;
+
+      case ErrorKind.ExpectedHexDigit:
+        errorCode = MessageKind.HEX_DIGIT_EXPECTED;
+        break;
+
+      case ErrorKind.ExpectedOpenParens:
+        errorCode = MessageKind.GENERIC;
+        arguments = {"text": "Expected '('."};
+        break;
+
+      case ErrorKind.ExpectedString:
+        reportFatalError(reporter.spanFromToken(token),
+            "Expected a String, but got '${token.value}'.");
+        return null;
+
+      case ErrorKind.ExtraneousModifier:
+        errorCode = MessageKind.EXTRANEOUS_MODIFIER;
+        break;
+
+      case ErrorKind.ExtraneousModifierReplace:
+        errorCode = MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
+        break;
+
+      case ErrorKind.InvalidAwaitFor:
+        errorCode = MessageKind.INVALID_AWAIT_FOR;
+        break;
+
+      case ErrorKind.AsciiControlCharacter:
+      case ErrorKind.NonAsciiIdentifier:
+      case ErrorKind.NonAsciiWhitespace:
+      case ErrorKind.Encoding:
+        errorCode = MessageKind.BAD_INPUT_CHARACTER;
+        break;
+
+      case ErrorKind.InvalidSyncModifier:
+        errorCode = MessageKind.INVALID_SYNC_MODIFIER;
+        break;
+
+      case ErrorKind.InvalidVoid:
+        errorCode = MessageKind.VOID_NOT_ALLOWED;
+        break;
+
+      case ErrorKind.UnexpectedDollarInString:
+        errorCode = MessageKind.MALFORMED_STRING_LITERAL;
+        break;
+
+      case ErrorKind.MissingExponent:
+        errorCode = MessageKind.EXPONENT_MISSING;
+        break;
+
+      case ErrorKind.PositionalParameterWithEquals:
+        errorCode = MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS;
+        break;
+
+      case ErrorKind.RequiredParameterWithDefault:
+        errorCode = MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT;
+        break;
+
+      case ErrorKind.UnmatchedToken:
+        errorCode = MessageKind.UNMATCHED_TOKEN;
+        break;
+
+      case ErrorKind.UnsupportedPrefixPlus:
+        errorCode = MessageKind.UNSUPPORTED_PREFIX_PLUS;
+        break;
+
+      case ErrorKind.UnterminatedComment:
+        errorCode = MessageKind.UNTERMINATED_COMMENT;
+        break;
+
+      case ErrorKind.UnterminatedString:
+        errorCode = MessageKind.UNTERMINATED_STRING;
+        break;
+
+      case ErrorKind.UnterminatedToken:
+        errorCode = MessageKind.UNTERMINATED_TOKEN;
+        break;
+
+      case ErrorKind.StackOverflow:
+        errorCode = MessageKind.GENERIC;
+        arguments = {"text": "Stack overflow."};
+        break;
+
+      case ErrorKind.Unspecified:
+        errorCode = MessageKind.GENERIC;
+        break;
+    }
+    SourceSpan span = reporter.spanFromToken(token);
+    reportError(span, errorCode, arguments);
   }
 
   /// Finds the preceding token via the begin token of the last AST node pushed
@@ -494,113 +744,13 @@
     return null;
   }
 
-  Token expectedIdentifier(Token token) {
-    if (token is KeywordToken) {
-      reportError(token, MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
-          {'keyword': token.value});
-    } else if (token is ErrorToken) {
-      reportErrorToken(token);
-      return synthesizeIdentifier(token);
-    } else {
-      reportFatalError(token, "Expected identifier, but got '${token.value}'.");
-    }
-    return token;
-  }
-
-  Token expectedType(Token token) {
-    pushNode(null);
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-      return synthesizeIdentifier(token);
-    } else {
-      reportFatalError(token, "Expected a type, but got '${token.value}'.");
-      return skipToEof(token);
-    }
-  }
-
-  Token expectedExpression(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-      pushNode(new ErrorExpression(token));
-      return token.next;
-    } else {
-      reportFatalError(
-          token, "Expected an expression, but got '${token.value}'.");
-      pushNode(null);
-      return skipToEof(token);
-    }
-  }
-
-  Token unexpected(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      String message = "Unexpected token '${token.value}'.";
-      if (token.info == Precedence.BAD_INPUT_INFO) {
-        message = token.value;
-      }
-      reportFatalError(token, message);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedBlockToSkip(Token token) {
-    if (identical(token.stringValue, 'native')) {
-      return native.handleNativeBlockToSkip(this, token);
-    } else {
-      return unexpected(token);
-    }
-  }
-
-  Token expectedFunctionBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      String printString = token.value;
-      reportFatalError(
-          token, "Expected a function body, but got '$printString'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      reportFatalError(
-          token, "Expected a class body, but got '${token.value}'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBodyToSkip(Token token) {
-    return unexpected(token);
-  }
-
-  Token expectedDeclaration(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      reportFatalError(
-          token, "Expected a declaration, but got '${token.value}'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token unmatched(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      String begin = token.value;
-      String end = closeBraceFor(begin);
-      reportError(
-          token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
-    }
-    Token next = token.next;
-    while (next is ErrorToken) {
-      next = next.next;
-    }
-    return next;
+  /// Finds the preceding token via the begin token of the last AST node pushed
+  /// on the [nodes] stack.
+  Token synthesizeIdentifier(Token token) {
+    Token synthesizedToken = new StringToken.fromString(
+        Precedence.IDENTIFIER_INFO, '?', token.charOffset);
+    synthesizedToken.next = token.next;
+    return synthesizedToken;
   }
 
   void recoverableError(Spannable node, String message) {
@@ -663,6 +813,7 @@
     return new NodeList(beginToken, poppedNodes, endToken, delimiter);
   }
 
+  @override
   void beginLiteralString(Token token) {
     String source = token.value;
     StringQuoting quoting = StringValidator.quotingFromString(source);
@@ -672,12 +823,14 @@
     pushNode(new LiteralString(token, null));
   }
 
+  @override
   void handleStringPart(Token token) {
     // Just push an unvalidated token now, and replace it when we know the
     // end of the interpolation.
     pushNode(new LiteralString(token, null));
   }
 
+  @override
   void endLiteralString(int count) {
     StringQuoting quoting = popQuoting();
 
@@ -711,6 +864,7 @@
     }
   }
 
+  @override
   void handleStringJuxtaposition(int stringCount) {
     assert(stringCount != 0);
     Expression accumulator = popNode();
@@ -723,14 +877,17 @@
     pushNode(accumulator);
   }
 
+  @override
   void beginMember(Token token) {
     memberErrors = memberErrors.prepend(false);
   }
 
+  @override
   void beginTopLevelMember(Token token) {
     beginMember(token);
   }
 
+  @override
   void endMember() {
     memberErrors = memberErrors.tail;
   }
@@ -740,11 +897,12 @@
   void reportFatalError(Spannable spannable, String message) {
     reportError(spannable, MessageKind.GENERIC, {'text': message});
     // Some parse errors are infeasible to recover from, so we throw an error.
-    throw new ParserError(message);
+    SourceSpan span = reporter.spanFromSpannable(spannable);
+    throw new ParserError(
+        span.begin, span.end, ErrorKind.Unspecified, {'text': message});
   }
 
-  @override
-  void reportErrorHelper(Spannable spannable, MessageKind errorCode,
+  void reportError(Spannable spannable, MessageKind errorCode,
       [Map arguments = const {}]) {
     if (currentMemberHasParseError) return; // Error already reported.
     if (suppressParseErrors) return;
@@ -753,4 +911,9 @@
     }
     reporter.reportErrorMessage(spannable, errorCode, arguments);
   }
+
+  void reportErrorFromToken(Token token, MessageKind errorCode,
+      [Map arguments = const {}]) {
+    reportError(reporter.spanFromToken(token), errorCode, arguments);
+  }
 }
diff --git a/pkg/compiler/lib/src/parser/listener.dart b/pkg/compiler/lib/src/parser/listener.dart
deleted file mode 100644
index b33bd84..0000000
--- a/pkg/compiler/lib/src/parser/listener.dart
+++ /dev/null
@@ -1,637 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.parser.listener;
-
-import '../common.dart';
-import '../diagnostics/messages.dart' show MessageTemplate;
-import '../tokens/precedence_constants.dart' as Precedence
-    show EOF_INFO, IDENTIFIER_INFO;
-import '../tokens/token.dart'
-    show
-        BadInputToken,
-        BeginGroupToken,
-        ErrorToken,
-        StringToken,
-        Token,
-        UnmatchedToken,
-        UnterminatedToken;
-import '../tree/tree.dart';
-
-const bool VERBOSE = false;
-
-/**
- * A parser event listener that does nothing except throw exceptions
- * on parser errors.
- */
-class Listener {
-  set suppressParseErrors(bool value) {}
-
-  void beginArguments(Token token) {}
-
-  void endArguments(int count, Token beginToken, Token endToken) {}
-
-  /// Handle async modifiers `async`, `async*`, `sync`.
-  void handleAsyncModifier(Token asyncToken, Token startToken) {}
-
-  void beginAwaitExpression(Token token) {}
-
-  void endAwaitExpression(Token beginToken, Token endToken) {}
-
-  void beginBlock(Token token) {}
-
-  void endBlock(int count, Token beginToken, Token endToken) {}
-
-  void beginCascade(Token token) {}
-
-  void endCascade() {}
-
-  void beginClassBody(Token token) {}
-
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {}
-
-  void beginClassDeclaration(Token token) {}
-
-  void endClassDeclaration(int interfacesCount, Token beginToken,
-      Token extendsKeyword, Token implementsKeyword, Token endToken) {}
-
-  void beginCombinators(Token token) {}
-
-  void endCombinators(int count) {}
-
-  void beginCompilationUnit(Token token) {}
-
-  void endCompilationUnit(int count, Token token) {}
-
-  void beginConstructorReference(Token start) {}
-
-  void endConstructorReference(
-      Token start, Token periodBeforeName, Token endToken) {}
-
-  void beginDoWhileStatement(Token token) {}
-
-  void endDoWhileStatement(
-      Token doKeyword, Token whileKeyword, Token endToken) {}
-
-  void beginEnum(Token enumKeyword) {}
-
-  void endEnum(Token enumKeyword, Token endBrace, int count) {}
-
-  void beginExport(Token token) {}
-
-  void endExport(Token exportKeyword, Token semicolon) {}
-
-  void beginExpressionStatement(Token token) {}
-
-  void endExpressionStatement(Token token) {}
-
-  void beginFactoryMethod(Token token) {}
-
-  void endFactoryMethod(Token beginToken, Token endToken) {}
-
-  void beginFormalParameter(Token token) {}
-
-  void endFormalParameter(Token thisKeyword) {}
-
-  void handleNoFormalParameters(Token token) {}
-
-  void beginFormalParameters(Token token) {}
-
-  void endFormalParameters(int count, Token beginToken, Token endToken) {}
-
-  void endFields(int count, Token beginToken, Token endToken) {}
-
-  void beginForStatement(Token token) {}
-
-  void endForStatement(
-      int updateExpressionCount, Token beginToken, Token endToken) {}
-
-  void endForIn(
-      Token awaitToken, Token forToken, Token inKeyword, Token endToken) {}
-
-  void beginFunction(Token token) {}
-
-  void endFunction(Token getOrSet, Token endToken) {}
-
-  void beginFunctionDeclaration(Token token) {}
-
-  void endFunctionDeclaration(Token token) {}
-
-  void beginFunctionBody(Token token) {}
-
-  void endFunctionBody(int count, Token beginToken, Token endToken) {}
-
-  void handleNoFunctionBody(Token token) {}
-
-  void skippedFunctionBody(Token token) {}
-
-  void beginFunctionName(Token token) {}
-
-  void endFunctionName(Token token) {}
-
-  void beginFunctionTypeAlias(Token token) {}
-
-  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {}
-
-  void beginMixinApplication(Token token) {}
-
-  void endMixinApplication() {}
-
-  void beginNamedMixinApplication(Token token) {}
-
-  void endNamedMixinApplication(
-      Token classKeyword, Token implementsKeyword, Token endToken) {}
-
-  void beginHide(Token hideKeyword) {}
-
-  void endHide(Token hideKeyword) {}
-
-  void beginIdentifierList(Token token) {}
-
-  void endIdentifierList(int count) {}
-
-  void beginTypeList(Token token) {}
-
-  void endTypeList(int count) {}
-
-  void beginIfStatement(Token token) {}
-
-  void endIfStatement(Token ifToken, Token elseToken) {}
-
-  void beginImport(Token importKeyword) {}
-
-  void endImport(Token importKeyword, Token DeferredKeyword, Token asKeyword,
-      Token semicolon) {}
-
-  void beginConditionalUris(Token token) {}
-
-  void endConditionalUris(int count) {}
-
-  void beginConditionalUri(Token ifKeyword) {}
-
-  void endConditionalUri(Token ifKeyword, Token equalitySign) {}
-
-  void beginDottedName(Token token) {}
-
-  void endDottedName(int count, Token firstIdentifier) {}
-
-  void beginInitializedIdentifier(Token token) {}
-
-  void endInitializedIdentifier() {}
-
-  void beginInitializer(Token token) {}
-
-  void endInitializer(Token assignmentOperator) {}
-
-  void beginInitializers(Token token) {}
-
-  void endInitializers(int count, Token beginToken, Token endToken) {}
-
-  void handleNoInitializers() {}
-
-  void handleLabel(Token token) {}
-
-  void beginLabeledStatement(Token token, int labelCount) {}
-
-  void endLabeledStatement(int labelCount) {}
-
-  void beginLibraryName(Token token) {}
-
-  void endLibraryName(Token libraryKeyword, Token semicolon) {}
-
-  void beginLiteralMapEntry(Token token) {}
-
-  void endLiteralMapEntry(Token colon, Token endToken) {}
-
-  void beginLiteralString(Token token) {}
-
-  void endLiteralString(int interpolationCount) {}
-
-  void handleStringJuxtaposition(int literalCount) {}
-
-  void beginMember(Token token) {}
-
-  void endMember() {}
-
-  void endMethod(Token getOrSet, Token beginToken, Token endToken) {}
-
-  void beginMetadataStar(Token token) {}
-
-  void endMetadataStar(int count, bool forParameter) {}
-
-  void beginMetadata(Token token) {}
-
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {}
-
-  void beginOptionalFormalParameters(Token token) {}
-
-  void endOptionalFormalParameters(
-      int count, Token beginToken, Token endToken) {}
-
-  void beginPart(Token token) {}
-
-  void endPart(Token partKeyword, Token semicolon) {}
-
-  void beginPartOf(Token token) {}
-
-  void endPartOf(Token partKeyword, Token semicolon) {}
-
-  void beginRedirectingFactoryBody(Token token) {}
-
-  void endRedirectingFactoryBody(Token beginToken, Token endToken) {}
-
-  void beginReturnStatement(Token token) {}
-
-  void endReturnStatement(
-      bool hasExpression, Token beginToken, Token endToken) {}
-
-  void beginSend(Token token) {}
-
-  void endSend(Token token) {}
-
-  void beginShow(Token showKeyword) {}
-
-  void endShow(Token showKeyword) {}
-
-  void beginSwitchStatement(Token token) {}
-
-  void endSwitchStatement(Token switchKeyword, Token endToken) {}
-
-  void beginSwitchBlock(Token token) {}
-
-  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {}
-
-  void beginLiteralSymbol(Token token) {}
-
-  void endLiteralSymbol(Token hashToken, int identifierCount) {}
-
-  void beginThrowExpression(Token token) {}
-
-  void endThrowExpression(Token throwToken, Token endToken) {}
-
-  void beginRethrowStatement(Token token) {}
-
-  void endRethrowStatement(Token throwToken, Token endToken) {}
-
-  void endTopLevelDeclaration(Token token) {}
-
-  void beginTopLevelMember(Token token) {}
-
-  void endTopLevelFields(int count, Token beginToken, Token endToken) {}
-
-  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {}
-
-  void beginTryStatement(Token token) {}
-
-  void handleCaseMatch(Token caseKeyword, Token colon) {}
-
-  void handleCatchBlock(Token onKeyword, Token catchKeyword) {}
-
-  void handleFinallyBlock(Token finallyKeyword) {}
-
-  void endTryStatement(
-      int catchCount, Token tryKeyword, Token finallyKeyword) {}
-
-  void endType(Token beginToken, Token endToken) {}
-
-  void beginTypeArguments(Token token) {}
-
-  void endTypeArguments(int count, Token beginToken, Token endToken) {}
-
-  void handleNoTypeArguments(Token token) {}
-
-  void beginTypeVariable(Token token) {}
-
-  void endTypeVariable(Token token, Token extendsOrSuper) {}
-
-  void beginTypeVariables(Token token) {}
-
-  void endTypeVariables(int count, Token beginToken, Token endToken) {}
-
-  void beginUnnamedFunction(Token token) {}
-
-  void endUnnamedFunction(Token token) {}
-
-  void beginVariablesDeclaration(Token token) {}
-
-  void endVariablesDeclaration(int count, Token endToken) {}
-
-  void beginWhileStatement(Token token) {}
-
-  void endWhileStatement(Token whileKeyword, Token endToken) {}
-
-  void handleAsOperator(Token operator, Token endToken) {}
-
-  void handleAssignmentExpression(Token token) {}
-
-  void handleBinaryExpression(Token token) {}
-
-  void handleConditionalExpression(Token question, Token colon) {}
-
-  void handleConstExpression(Token token) {}
-
-  void handleFunctionTypedFormalParameter(Token token) {}
-
-  void handleIdentifier(Token token) {}
-
-  void handleIndexedExpression(
-      Token openCurlyBracket, Token closeCurlyBracket) {}
-
-  void handleIsOperator(Token operator, Token not, Token endToken) {}
-
-  void handleLiteralBool(Token token) {}
-
-  void handleBreakStatement(
-      bool hasTarget, Token breakKeyword, Token endToken) {}
-
-  void handleContinueStatement(
-      bool hasTarget, Token continueKeyword, Token endToken) {}
-
-  void handleEmptyStatement(Token token) {}
-
-  void handleAssertStatement(
-      Token assertKeyword, Token commaToken, Token semicolonToken) {}
-
-  /** Called with either the token containing a double literal, or
-    * an immediately preceding "unary plus" token.
-    */
-  void handleLiteralDouble(Token token) {}
-
-  /** Called with either the token containing an integer literal,
-    * or an immediately preceding "unary plus" token.
-    */
-  void handleLiteralInt(Token token) {}
-
-  void handleLiteralList(
-      int count, Token beginToken, Token constKeyword, Token endToken) {}
-
-  void handleLiteralMap(
-      int count, Token beginToken, Token constKeyword, Token endToken) {}
-
-  void handleLiteralNull(Token token) {}
-
-  void handleModifier(Token token) {}
-
-  void handleModifiers(int count) {}
-
-  void handleNamedArgument(Token colon) {}
-
-  void handleNewExpression(Token token) {}
-
-  void handleNoArguments(Token token) {}
-
-  void handleNoExpression(Token token) {}
-
-  void handleNoType(Token token) {}
-
-  void handleNoTypeVariables(Token token) {}
-
-  void handleOperator(Token token) {}
-
-  void handleOperatorName(Token operatorKeyword, Token token) {}
-
-  void handleParenthesizedExpression(BeginGroupToken token) {}
-
-  void handleQualified(Token period) {}
-
-  void handleStringPart(Token token) {}
-
-  void handleSuperExpression(Token token) {}
-
-  void handleSwitchCase(
-      int labelCount,
-      int expressionCount,
-      Token defaultKeyword,
-      int statementCount,
-      Token firstToken,
-      Token endToken) {}
-
-  void handleThisExpression(Token token) {}
-
-  void handleUnaryPostfixAssignmentExpression(Token token) {}
-
-  void handleUnaryPrefixExpression(Token token) {}
-
-  void handleUnaryPrefixAssignmentExpression(Token token) {}
-
-  void handleValuedFormalParameter(Token equals, Token token) {}
-
-  void handleVoidKeyword(Token token) {}
-
-  void beginYieldStatement(Token token) {}
-
-  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {}
-
-  Token expected(String string, Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected '$string', but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token synthesizeIdentifier(Token token) {
-    Token synthesizedToken = new StringToken.fromString(
-        Precedence.IDENTIFIER_INFO, '?', token.charOffset);
-    synthesizedToken.next = token.next;
-    return synthesizedToken;
-  }
-
-  Token expectedIdentifier(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected identifier, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedType(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a type, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedExpression(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected an expression, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token unexpected(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("unexpected token '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedBlockToSkip(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a block, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedFunctionBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a function body, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a class body, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBodyToSkip(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a class body, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedDeclaration(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a declaration, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token unmatched(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("unmatched '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  skipToEof(Token token) {
-    while (!identical(token.info, Precedence.EOF_INFO)) {
-      token = token.next;
-    }
-    return token;
-  }
-
-  void recoverableError(Token token, String message) {
-    error(message, token);
-  }
-
-  void error(String message, Token token) {
-    throw new ParserError("$message @ ${token.charOffset}");
-  }
-
-  void reportError(Spannable spannable, MessageKind messageKind,
-      [Map arguments = const {}]) {
-    if (spannable is ErrorToken) {
-      reportErrorToken(spannable);
-    } else {
-      reportErrorHelper(spannable, messageKind, arguments);
-    }
-  }
-
-  void reportErrorHelper(Spannable spannable, MessageKind messageKind,
-      [Map arguments = const {}]) {
-    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
-    String message = template.message(arguments, true).toString();
-    Token token;
-    if (spannable is Token) {
-      token = spannable;
-    } else if (spannable is Node) {
-      token = spannable.getBeginToken();
-    } else {
-      throw new ParserError(message);
-    }
-    recoverableError(token, message);
-  }
-
-  void reportErrorToken(ErrorToken token) {
-    if (token is BadInputToken) {
-      String hex = token.character.toRadixString(16);
-      if (hex.length < 4) {
-        String padding = "0000".substring(hex.length);
-        hex = "$padding$hex";
-      }
-      reportErrorHelper(
-          token, MessageKind.BAD_INPUT_CHARACTER, {'characterHex': hex});
-    } else if (token is UnterminatedToken) {
-      MessageKind kind;
-      var arguments = const {};
-      switch (token.start) {
-        case '1e':
-          kind = MessageKind.EXPONENT_MISSING;
-          break;
-        case '"':
-        case "'":
-        case '"""':
-        case "'''":
-        case 'r"':
-        case "r'":
-        case 'r"""':
-        case "r'''":
-          kind = MessageKind.UNTERMINATED_STRING;
-          arguments = {'quote': token.start};
-          break;
-        case '0x':
-          kind = MessageKind.HEX_DIGIT_EXPECTED;
-          break;
-        case r'$':
-          kind = MessageKind.MALFORMED_STRING_LITERAL;
-          break;
-        case '/*':
-          kind = MessageKind.UNTERMINATED_COMMENT;
-          break;
-        default:
-          kind = MessageKind.UNTERMINATED_TOKEN;
-          break;
-      }
-      reportErrorHelper(token, kind, arguments);
-    } else if (token is UnmatchedToken) {
-      String begin = token.begin.value;
-      String end = closeBraceFor(begin);
-      reportErrorHelper(
-          token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
-    } else {
-      throw new SpannableAssertionFailure(token, token.assertionMessage);
-    }
-  }
-}
-
-String closeBraceFor(String openBrace) {
-  return const {
-    '(': ')',
-    '[': ']',
-    '{': '}',
-    '<': '>',
-    r'${': '}',
-  }[openBrace];
-}
-
-class ParserError {
-  final String reason;
-  ParserError(this.reason);
-  toString() => reason;
-}
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
index 17ecce0..4697d5b 100644
--- a/pkg/compiler/lib/src/parser/member_listener.dart
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -8,7 +8,7 @@
 import '../elements/elements.dart' show Element, ElementKind, Elements;
 import '../elements/modelx.dart'
     show ClassElementX, ElementX, FieldElementX, VariableList;
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../tree/tree.dart';
 import 'element_listener.dart' show ScannerOptions;
 import 'node_listener.dart' show NodeListener;
@@ -67,6 +67,7 @@
     }
   }
 
+  @override
   void endMethod(Token getOrSet, Token beginToken, Token endToken) {
     super.endMethod(getOrSet, beginToken, endToken);
     FunctionExpression method = popNode();
@@ -76,7 +77,7 @@
     Element memberElement;
     if (isConstructor) {
       if (getOrSet != null) {
-        recoverableError(getOrSet, 'illegal modifier');
+        recoverableError(reporter.spanFromToken(getOrSet), 'illegal modifier');
       }
       memberElement = new PartialConstructorElement(name, beginToken, endToken,
           ElementKind.GENERATIVE_CONSTRUCTOR, method.modifiers, enclosingClass);
@@ -88,6 +89,7 @@
     addMember(memberElement);
   }
 
+  @override
   void endFactoryMethod(Token beginToken, Token endToken) {
     super.endFactoryMethod(beginToken, endToken);
     FunctionExpression method = popNode();
@@ -112,6 +114,7 @@
     addMember(memberElement);
   }
 
+  @override
   void endFields(int count, Token beginToken, Token endToken) {
     bool hasParseError = memberErrors.head;
     super.endFields(count, beginToken, endToken);
@@ -127,12 +130,14 @@
         enclosingClass, buildFieldElement, beginToken, endToken, hasParseError);
   }
 
-  void endInitializer(Token assignmentOperator) {
+  @override
+  void endFieldInitializer(Token assignmentOperator) {
     pushNode(null); // Super expects an expression, but
     // ClassElementParser just skips expressions.
-    super.endInitializer(assignmentOperator);
+    super.endFieldInitializer(assignmentOperator);
   }
 
+  @override
   void endInitializers(int count, Token beginToken, Token endToken) {
     pushNode(null);
   }
@@ -146,6 +151,7 @@
     enclosingClass.addMember(memberElement, reporter);
   }
 
+  @override
   void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
     super.endMetadata(beginToken, periodBeforeName, endToken);
     pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
diff --git a/pkg/compiler/lib/src/parser/node_listener.dart b/pkg/compiler/lib/src/parser/node_listener.dart
index 4dc325c..f717c7d 100644
--- a/pkg/compiler/lib/src/parser/node_listener.dart
+++ b/pkg/compiler/lib/src/parser/node_listener.dart
@@ -6,27 +6,29 @@
 
 import '../common.dart';
 import '../elements/elements.dart' show CompilationUnitElement;
-import '../native/native.dart' as native;
-import '../tokens/precedence_constants.dart' as Precedence show INDEX_INFO;
-import '../tokens/token.dart' show ErrorToken, StringToken, Token;
+import 'package:front_end/src/fasta/scanner/precedence.dart' as Precedence
+    show INDEX_INFO;
+import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token;
 import '../tree/tree.dart';
 import '../util/util.dart' show Link;
 import 'element_listener.dart' show ElementListener, ScannerOptions;
-import 'partial_elements.dart' show PartialFunctionElement;
 
 class NodeListener extends ElementListener {
   NodeListener(ScannerOptions scannerOptions, DiagnosticReporter reporter,
       CompilationUnitElement element)
       : super(scannerOptions, reporter, element, null);
 
+  @override
   void addLibraryTag(LibraryTag tag) {
     pushNode(tag);
   }
 
+  @override
   void addPartOfTag(PartOf tag) {
     pushNode(tag);
   }
 
+  @override
   void endLibraryName(Token libraryKeyword, Token semicolon) {
     Expression name = popNode();
     pushNode(new LibraryName(
@@ -37,6 +39,7 @@
         null));
   }
 
+  @override
   void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
       Token semicolon) {
     NodeList combinators = popNode();
@@ -55,6 +58,7 @@
         isDeferred: deferredKeyword != null));
   }
 
+  @override
   void endExport(Token exportKeyword, Token semicolon) {
     NodeList combinators = popNode();
     NodeList conditionalUris = popNode();
@@ -69,6 +73,7 @@
         null));
   }
 
+  @override
   void endPart(Token partKeyword, Token semicolon) {
     StringNode uri = popLiteralString();
     pushNode(new Part(
@@ -79,6 +84,7 @@
         null));
   }
 
+  @override
   void endPartOf(Token partKeyword, Token semicolon) {
     Expression name = popNode(); // name
     pushNode(new PartOf(
@@ -89,6 +95,7 @@
         null));
   }
 
+  @override
   void endClassDeclaration(int interfacesCount, Token beginToken,
       Token extendsKeyword, Token implementsKeyword, Token endToken) {
     NodeList body = popNode();
@@ -102,6 +109,7 @@
         interfaces, beginToken, extendsKeyword, body, endToken));
   }
 
+  @override
   void endTopLevelDeclaration(Token token) {
     // TODO(sigmund): consider moving metadata into each declaration
     // element instead.
@@ -111,10 +119,12 @@
     super.endTopLevelDeclaration(token);
   }
 
+  @override
   void endCompilationUnit(int count, Token token) {
     pushNode(makeNodeList(count, null, null, '\n'));
   }
 
+  @override
   void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
     NodeList formals = popNode();
     NodeList typeParameters = popNode();
@@ -124,6 +134,7 @@
         returnType, name, typeParameters, formals, typedefKeyword, endToken));
   }
 
+  @override
   void endNamedMixinApplication(
       Token classKeyword, Token implementsKeyword, Token endToken) {
     NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
@@ -135,16 +146,19 @@
         mixinApplication, interfaces, classKeyword, endToken));
   }
 
+  @override
   void endEnum(Token enumKeyword, Token endBrace, int count) {
     NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
     Identifier name = popNode();
     pushNode(new Enum(enumKeyword, name, names));
   }
 
+  @override
   void endClassBody(int memberCount, Token beginToken, Token endToken) {
     pushNode(makeNodeList(memberCount, beginToken, endToken, null));
   }
 
+  @override
   void endTopLevelFields(int count, Token beginToken, Token endToken) {
     NodeList variables = makeNodeList(count, null, endToken, ",");
     TypeAnnotation type = popNode();
@@ -152,6 +166,7 @@
     pushNode(new VariableDefinitions(type, modifiers, variables));
   }
 
+  @override
   void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
     Statement body = popNode();
     AsyncModifier asyncModifier = popNode();
@@ -164,6 +179,7 @@
         modifiers, null, getOrSet, asyncModifier));
   }
 
+  @override
   void endFormalParameter(Token thisKeyword) {
     Expression name = popNode();
     if (thisKeyword != null) {
@@ -181,22 +197,27 @@
         metadata, type, modifiers, new NodeList.singleton(name)));
   }
 
+  @override
   void endFormalParameters(int count, Token beginToken, Token endToken) {
     pushNode(makeNodeList(count, beginToken, endToken, ","));
   }
 
+  @override
   void handleNoFormalParameters(Token token) {
     pushNode(null);
   }
 
+  @override
   void endArguments(int count, Token beginToken, Token endToken) {
     pushNode(makeNodeList(count, beginToken, endToken, ","));
   }
 
+  @override
   void handleNoArguments(Token token) {
     pushNode(null);
   }
 
+  @override
   void endConstructorReference(
       Token start, Token periodBeforeName, Token endToken) {
     Identifier name = null;
@@ -228,74 +249,61 @@
     pushNode(constructor);
   }
 
+  @override
   void endRedirectingFactoryBody(Token beginToken, Token endToken) {
     pushNode(new RedirectingFactoryBody(beginToken, endToken, popNode()));
   }
 
+  @override
   void endReturnStatement(
       bool hasExpression, Token beginToken, Token endToken) {
     Expression expression = hasExpression ? popNode() : null;
     pushNode(new Return(beginToken, endToken, expression));
   }
 
+  @override
   void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
     Expression expression = popNode();
     pushNode(new Yield(yieldToken, starToken, expression, endToken));
   }
 
+  @override
   void endExpressionStatement(Token token) {
     pushNode(new ExpressionStatement(popNode(), token));
   }
 
   void handleOnError(Token token, var errorInformation) {
-    reporter.internalError(token, "'${token.value}': ${errorInformation}");
+    reporter.internalError(
+        reporter.spanFromToken(token), "'${token.value}': ${errorInformation}");
   }
 
-  Token expectedFunctionBody(Token token) {
-    if (identical(token.stringValue, 'native')) {
-      return native.handleNativeFunctionBody(this, token);
-    } else if (token is ErrorToken) {
-      pushNode(null);
-      reportErrorToken(token);
-    } else {
-      reportFatalError(
-          token, "Expected a function body, but got '${token.value}'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-      return skipToEof(token);
-    } else {
-      reportFatalError(
-          token, "Expected a class body, but got '${token.value}'.");
-      return skipToEof(token);
-    }
-  }
-
+  @override
   void handleLiteralInt(Token token) {
     pushNode(new LiteralInt(token, (t, e) => handleOnError(t, e)));
   }
 
+  @override
   void handleLiteralDouble(Token token) {
     pushNode(new LiteralDouble(token, (t, e) => handleOnError(t, e)));
   }
 
+  @override
   void handleLiteralBool(Token token) {
     pushNode(new LiteralBool(token, (t, e) => handleOnError(t, e)));
   }
 
+  @override
   void handleLiteralNull(Token token) {
     pushNode(new LiteralNull(token));
   }
 
+  @override
   void endLiteralSymbol(Token hashToken, int identifierCount) {
     NodeList identifiers = makeNodeList(identifierCount, null, null, '.');
     pushNode(new LiteralSymbol(hashToken, identifiers));
   }
 
+  @override
   void handleBinaryExpression(Token token) {
     Node argument = popNode();
     Node receiver = popNode();
@@ -307,7 +315,8 @@
       if (argumentSend == null) {
         // TODO(ahe): The parser should diagnose this problem, not
         // this listener.
-        reportFatalError(argument, 'Expected an identifier.');
+        reportFatalError(
+            reporter.spanFromSpannable(argument), "Expected an identifier.");
       }
       if (argumentSend.receiver != null) internalError(node: argument);
       if (argument is SendSet) internalError(node: argument);
@@ -319,23 +328,28 @@
       pushNode(new Send(receiver, new Operator(token), arguments));
     }
     if (identical(tokenString, '===')) {
-      reporter.reportErrorMessage(token, MessageKind.UNSUPPORTED_EQ_EQ_EQ,
-          {'lhs': receiver, 'rhs': argument});
+      reporter.reportErrorMessage(reporter.spanFromToken(token),
+          MessageKind.UNSUPPORTED_EQ_EQ_EQ, {'lhs': receiver, 'rhs': argument});
     }
     if (identical(tokenString, '!==')) {
-      reporter.reportErrorMessage(token, MessageKind.UNSUPPORTED_BANG_EQ_EQ,
+      reporter.reportErrorMessage(
+          reporter.spanFromToken(token),
+          MessageKind.UNSUPPORTED_BANG_EQ_EQ,
           {'lhs': receiver, 'rhs': argument});
     }
   }
 
+  @override
   void beginCascade(Token token) {
     pushNode(new CascadeReceiver(popNode(), token));
   }
 
+  @override
   void endCascade() {
     pushNode(new Cascade(popNode()));
   }
 
+  @override
   void handleAsOperator(Token operator, Token endToken) {
     TypeAnnotation type = popNode();
     Expression expression = popNode();
@@ -343,6 +357,7 @@
     pushNode(new Send(expression, new Operator(operator), arguments));
   }
 
+  @override
   void handleAssignmentExpression(Token token) {
     Node arg = popNode();
     Node node = popNode();
@@ -367,9 +382,10 @@
   void reportNotAssignable(Node node) {
     // TODO(ahe): The parser should diagnose this problem, not this
     // listener.
-    reportFatalError(node, 'Not assignable.');
+    reportFatalError(reporter.spanFromSpannable(node), "Not assignable.");
   }
 
+  @override
   void handleConditionalExpression(Token question, Token colon) {
     Node elseExpression = popNode();
     Node thenExpression = popNode();
@@ -378,6 +394,7 @@
         condition, thenExpression, elseExpression, question, colon));
   }
 
+  @override
   void endSend(Token token) {
     NodeList arguments = popNode();
     NodeList typeArguments = popNode();
@@ -386,6 +403,7 @@
     pushNode(new Send(null, selector, arguments, typeArguments));
   }
 
+  @override
   void endFunctionBody(int count, Token beginToken, Token endToken) {
     if (count == 0 && beginToken == null) {
       pushNode(new EmptyStatement(endToken));
@@ -394,6 +412,7 @@
     }
   }
 
+  @override
   void handleAsyncModifier(Token asyncToken, Token starToken) {
     if (asyncToken != null) {
       pushNode(new AsyncModifier(asyncToken, starToken));
@@ -402,14 +421,17 @@
     }
   }
 
-  void skippedFunctionBody(Token token) {
+  @override
+  void handleFunctionBodySkipped(Token token) {
     pushNode(new Block(new NodeList.empty()));
   }
 
+  @override
   void handleNoFunctionBody(Token token) {
     pushNode(new EmptyStatement(token));
   }
 
+  @override
   void endFunction(Token getOrSet, Token endToken) {
     Statement body = popNode();
     AsyncModifier asyncModifier = popNode();
@@ -424,10 +446,12 @@
         modifiers, initializers, getOrSet, asyncModifier));
   }
 
+  @override
   void endFunctionDeclaration(Token endToken) {
     pushNode(new FunctionDeclaration(popNode()));
   }
 
+  @override
   void endVariablesDeclaration(int count, Token endToken) {
     // TODO(ahe): Pick one name for this concept, either
     // VariablesDeclaration or VariableDefinitions.
@@ -437,7 +461,8 @@
     pushNode(new VariableDefinitions(type, modifiers, variables));
   }
 
-  void endInitializer(Token assignmentOperator) {
+  @override
+  void endVariableInitializer(Token assignmentOperator) {
     Expression initializer = popNode();
     NodeList arguments =
         initializer == null ? null : new NodeList.singleton(initializer);
@@ -446,6 +471,12 @@
     pushNode(new SendSet(null, name, op, arguments));
   }
 
+  @override
+  void endFieldInitializer(Token assignmentOperator) {
+    endVariableInitializer(assignmentOperator);
+  }
+
+  @override
   void endIfStatement(Token ifToken, Token elseToken) {
     Statement elsePart = (elseToken == null) ? null : popNode();
     Statement thenPart = popNode();
@@ -453,6 +484,7 @@
     pushNode(new If(condition, thenPart, elsePart, ifToken, elseToken));
   }
 
+  @override
   void endForStatement(
       int updateExpressionCount, Token beginToken, Token endToken) {
     Statement body = popNode();
@@ -462,10 +494,12 @@
     pushNode(new For(initializer, condition, updates, body, beginToken));
   }
 
+  @override
   void handleNoExpression(Token token) {
     pushNode(null);
   }
 
+  @override
   void endDoWhileStatement(
       Token doKeyword, Token whileKeyword, Token endToken) {
     Expression condition = popNode();
@@ -473,42 +507,50 @@
     pushNode(new DoWhile(body, condition, doKeyword, whileKeyword, endToken));
   }
 
+  @override
   void endWhileStatement(Token whileKeyword, Token endToken) {
     Statement body = popNode();
     Expression condition = popNode();
     pushNode(new While(condition, body, whileKeyword));
   }
 
+  @override
   void endBlock(int count, Token beginToken, Token endToken) {
     pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
   }
 
+  @override
   void endThrowExpression(Token throwToken, Token endToken) {
     Expression expression = popNode();
     pushNode(new Throw(expression, throwToken, endToken));
   }
 
+  @override
   void endAwaitExpression(Token awaitToken, Token endToken) {
     Expression expression = popNode();
     pushNode(new Await(awaitToken, expression));
   }
 
+  @override
   void endRethrowStatement(Token throwToken, Token endToken) {
     pushNode(new Rethrow(throwToken, endToken));
     if (identical(throwToken.stringValue, 'throw')) {
-      reporter.reportErrorMessage(
-          throwToken, MessageKind.MISSING_EXPRESSION_IN_THROW);
+      reporter.reportErrorMessage(reporter.spanFromToken(throwToken),
+          MessageKind.MISSING_EXPRESSION_IN_THROW);
     }
   }
 
+  @override
   void handleUnaryPrefixExpression(Token token) {
     pushNode(new Send.prefix(popNode(), new Operator(token)));
   }
 
+  @override
   void handleSuperExpression(Token token) {
     pushNode(new Identifier(token));
   }
 
+  @override
   void handleThisExpression(Token token) {
     pushNode(new Identifier(token));
   }
@@ -536,22 +578,27 @@
     }
   }
 
+  @override
   void handleUnaryPostfixAssignmentExpression(Token token) {
     handleUnaryAssignmentExpression(token, false);
   }
 
+  @override
   void handleUnaryPrefixAssignmentExpression(Token token) {
     handleUnaryAssignmentExpression(token, true);
   }
 
+  @override
   void endInitializers(int count, Token beginToken, Token endToken) {
     pushNode(makeNodeList(count, beginToken, null, ','));
   }
 
+  @override
   void handleNoInitializers() {
     pushNode(null);
   }
 
+  @override
   void endMember() {
     // TODO(sigmund): consider moving metadata into each declaration
     // element instead.
@@ -561,6 +608,7 @@
     super.endMember();
   }
 
+  @override
   void endFields(int count, Token beginToken, Token endToken) {
     NodeList variables = makeNodeList(count, null, endToken, ",");
     TypeAnnotation type = popNode();
@@ -568,6 +616,7 @@
     pushNode(new VariableDefinitions(type, modifiers, variables));
   }
 
+  @override
   void endMethod(Token getOrSet, Token beginToken, Token endToken) {
     Statement body = popNode();
     AsyncModifier asyncModifier = popNode();
@@ -581,6 +630,7 @@
         returnType, modifiers, initializers, getOrSet, asyncModifier));
   }
 
+  @override
   void handleLiteralMap(
       int count, Token beginToken, Token constKeyword, Token endToken) {
     NodeList entries = makeNodeList(count, beginToken, endToken, ',');
@@ -588,18 +638,21 @@
     pushNode(new LiteralMap(typeArguments, entries, constKeyword));
   }
 
+  @override
   void endLiteralMapEntry(Token colon, Token endToken) {
     Expression value = popNode();
     Expression key = popNode();
     pushNode(new LiteralMapEntry(key, colon, value));
   }
 
+  @override
   void handleLiteralList(
       int count, Token beginToken, Token constKeyword, Token endToken) {
     NodeList elements = makeNodeList(count, beginToken, endToken, ',');
     pushNode(new LiteralList(popNode(), elements, constKeyword));
   }
 
+  @override
   void handleIndexedExpression(
       Token openSquareBracket, Token closeSquareBracket) {
     NodeList arguments =
@@ -611,38 +664,45 @@
     pushNode(new Send(receiver, selector, arguments));
   }
 
+  @override
   void handleNewExpression(Token token) {
     NodeList arguments = popNode();
     Node name = popNode();
     pushNode(new NewExpression(token, new Send(null, name, arguments)));
   }
 
+  @override
   void handleConstExpression(Token token) {
     // [token] carries the 'const' information.
     handleNewExpression(token);
   }
 
+  @override
   void handleOperator(Token token) {
     pushNode(new Operator(token));
   }
 
+  @override
   void handleOperatorName(Token operatorKeyword, Token token) {
     Operator op = new Operator(token);
     pushNode(new Send(new Identifier(operatorKeyword), op, null));
   }
 
+  @override
   void handleNamedArgument(Token colon) {
     Expression expression = popNode();
     Identifier name = popNode();
     pushNode(new NamedArgument(name, colon, expression));
   }
 
+  @override
   void endOptionalFormalParameters(
       int count, Token beginToken, Token endToken) {
     pushNode(makeNodeList(count, beginToken, endToken, ','));
   }
 
-  void handleFunctionTypedFormalParameter(Token endToken) {
+  @override
+  void endFunctionTypedFormalParameter(Token endToken) {
     NodeList formals = popNode();
     NodeList typeVariables = popNode();
     Identifier name = popNode();
@@ -652,6 +712,7 @@
         returnType, Modifiers.EMPTY, null, null, null));
   }
 
+  @override
   void handleValuedFormalParameter(Token equals, Token token) {
     Expression defaultValue = popNode();
     Expression parameterName = popNode();
@@ -659,6 +720,7 @@
         new NodeList.singleton(defaultValue)));
   }
 
+  @override
   void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
     Block finallyBlock = null;
     if (finallyKeyword != null) {
@@ -670,10 +732,12 @@
         tryBlock, catchBlocks, finallyBlock, tryKeyword, finallyKeyword));
   }
 
+  @override
   void handleCaseMatch(Token caseKeyword, Token colon) {
     pushNode(new CaseMatch(caseKeyword, popNode(), colon));
   }
 
+  @override
   void handleCatchBlock(Token onKeyword, Token catchKeyword) {
     Block block = popNode();
     NodeList formals = catchKeyword != null ? popNode() : null;
@@ -681,12 +745,14 @@
     pushNode(new CatchBlock(type, formals, block, onKeyword, catchKeyword));
   }
 
+  @override
   void endSwitchStatement(Token switchKeyword, Token endToken) {
     NodeList cases = popNode();
     ParenthesizedExpression expression = popNode();
     pushNode(new SwitchStatement(expression, cases, switchKeyword));
   }
 
+  @override
   void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
     Link<Node> caseNodes = const Link<Node>();
     while (caseCount > 0) {
@@ -697,6 +763,7 @@
     pushNode(new NodeList(beginToken, caseNodes, endToken, null));
   }
 
+  @override
   void handleSwitchCase(int labelCount, int caseCount, Token defaultKeyword,
       int statementCount, Token firstToken, Token endToken) {
     NodeList statements = makeNodeList(statementCount, null, null, null);
@@ -706,6 +773,7 @@
         new SwitchCase(labelsAndCases, defaultKeyword, statements, firstToken));
   }
 
+  @override
   void handleBreakStatement(
       bool hasTarget, Token breakKeyword, Token endToken) {
     Identifier target = null;
@@ -715,6 +783,7 @@
     pushNode(new BreakStatement(target, breakKeyword, endToken));
   }
 
+  @override
   void handleContinueStatement(
       bool hasTarget, Token continueKeyword, Token endToken) {
     Identifier target = null;
@@ -724,10 +793,12 @@
     pushNode(new ContinueStatement(target, continueKeyword, endToken));
   }
 
+  @override
   void handleEmptyStatement(Token token) {
     pushNode(new EmptyStatement(token));
   }
 
+  @override
   void endFactoryMethod(Token beginToken, Token endToken) {
     super.endFactoryMethod(beginToken, endToken);
     Statement body = popNode();
@@ -758,6 +829,7 @@
         name, null, formals, body, null, modifiers, null, null, asyncModifier));
   }
 
+  @override
   void endForIn(
       Token awaitToken, Token forToken, Token inKeyword, Token endToken) {
     Statement body = popNode();
@@ -772,6 +844,7 @@
     }
   }
 
+  @override
   void endMetadataStar(int count, bool forParameter) {
     if (0 == count) {
       pushNode(null);
@@ -780,6 +853,7 @@
     }
   }
 
+  @override
   void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
     NodeList arguments = popNode();
     if (arguments == null) {
@@ -816,6 +890,7 @@
     }
   }
 
+  @override
   void handleAssertStatement(
       Token assertKeyword, Token commaToken, Token semicolonToken) {
     Node message;
@@ -827,6 +902,7 @@
     pushNode(new Assert(assertKeyword, condition, message, semicolonToken));
   }
 
+  @override
   void endUnnamedFunction(Token token) {
     Statement body = popNode();
     AsyncModifier asyncModifier = popNode();
@@ -836,6 +912,7 @@
         Modifiers.EMPTY, null, null, asyncModifier));
   }
 
+  @override
   void handleIsOperator(Token operator, Token not, Token endToken) {
     TypeAnnotation type = popNode();
     Expression expression = popNode();
@@ -850,21 +927,32 @@
     pushNode(new Send(expression, new Operator(operator), arguments));
   }
 
+  @override
   void handleLabel(Token colon) {
     Identifier name = popNode();
     pushNode(new Label(name, colon));
   }
 
+  @override
   void endLabeledStatement(int labelCount) {
     Statement statement = popNode();
     NodeList labels = makeNodeList(labelCount, null, null, null);
     pushNode(new LabeledStatement(labels, statement));
   }
 
+  @override
   void log(message) {
     reporter.log(message);
   }
 
+  @override
+  void handleInvalidFunctionBody(Token token) {
+    if (!lastErrorWasNativeFunctionBody) {
+      pushNode(null);
+    }
+    lastErrorWasNativeFunctionBody = false;
+  }
+
   void internalError({Token token, Node node}) {
     // TODO(ahe): This should call reporter.internalError.
     Spannable spannable = (token == null) ? node : token;
diff --git a/pkg/compiler/lib/src/parser/parser.dart b/pkg/compiler/lib/src/parser/parser.dart
deleted file mode 100644
index 0ef9cb8..0000000
--- a/pkg/compiler/lib/src/parser/parser.dart
+++ /dev/null
@@ -1,3007 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.parser;
-
-import '../common.dart';
-import '../tokens/keyword.dart' show Keyword;
-import '../tokens/precedence.dart' show PrecedenceInfo;
-import '../tokens/precedence_constants.dart'
-    show
-        AS_INFO,
-        ASSIGNMENT_PRECEDENCE,
-        CASCADE_PRECEDENCE,
-        EQUALITY_PRECEDENCE,
-        GT_INFO,
-        IS_INFO,
-        MINUS_MINUS_INFO,
-        OPEN_PAREN_INFO,
-        OPEN_SQUARE_BRACKET_INFO,
-        PERIOD_INFO,
-        PLUS_PLUS_INFO,
-        POSTFIX_PRECEDENCE,
-        QUESTION_INFO,
-        QUESTION_PERIOD_INFO,
-        RELATIONAL_PRECEDENCE;
-import '../tokens/token.dart'
-    show
-        BeginGroupToken,
-        isUserDefinableOperator,
-        KeywordToken,
-        SymbolToken,
-        Token;
-import '../tokens/token_constants.dart'
-    show
-        BAD_INPUT_TOKEN,
-        COMMA_TOKEN,
-        DOUBLE_TOKEN,
-        EOF_TOKEN,
-        EQ_TOKEN,
-        FUNCTION_TOKEN,
-        GT_TOKEN,
-        GT_GT_TOKEN,
-        HASH_TOKEN,
-        HEXADECIMAL_TOKEN,
-        IDENTIFIER_TOKEN,
-        INT_TOKEN,
-        KEYWORD_TOKEN,
-        LT_TOKEN,
-        OPEN_CURLY_BRACKET_TOKEN,
-        OPEN_PAREN_TOKEN,
-        OPEN_SQUARE_BRACKET_TOKEN,
-        PERIOD_TOKEN,
-        SEMICOLON_TOKEN,
-        STRING_INTERPOLATION_IDENTIFIER_TOKEN,
-        STRING_INTERPOLATION_TOKEN,
-        STRING_TOKEN;
-import '../util/characters.dart' as Characters show $CLOSE_CURLY_BRACKET;
-import '../util/util.dart' show Link;
-import 'listener.dart' show Listener;
-
-class FormalParameterType {
-  final String type;
-  const FormalParameterType(this.type);
-  bool get isRequired => this == REQUIRED;
-  bool get isPositional => this == POSITIONAL;
-  bool get isNamed => this == NAMED;
-  static final REQUIRED = const FormalParameterType('required');
-  static final POSITIONAL = const FormalParameterType('positional');
-  static final NAMED = const FormalParameterType('named');
-}
-
-/**
- * An event generating parser of Dart programs. This parser expects
- * all tokens in a linked list (aka a token stream).
- *
- * The class [Scanner] is used to generate a token stream. See the
- * file scanner.dart.
- *
- * Subclasses of the class [Listener] are used to listen to events.
- *
- * Most methods of this class belong in one of two major categories:
- * parse metods and peek methods. Parse methods all have the prefix
- * parse, and peek methods all have the prefix peek.
- *
- * Parse methods generate events (by calling methods on [listener])
- * and return the next token to parse. Peek methods do not generate
- * events (except for errors) and may return null.
- *
- * Parse methods are generally named parseGrammarProductionSuffix. The
- * suffix can be one of "opt", or "star". "opt" means zero or one
- * matches, "star" means zero or more matches. For example,
- * [parseMetadataStar] corresponds to this grammar snippet: [:
- * metadata* :], and [parseTypeOpt] corresponds to: [: type? :].
- */
-class Parser {
-  final Listener listener;
-  bool mayParseFunctionExpressions = true;
-  bool asyncAwaitKeywordsEnabled;
-
-  Parser(this.listener, {this.asyncAwaitKeywordsEnabled: false});
-
-  Token parseUnit(Token token) {
-    listener.beginCompilationUnit(token);
-    int count = 0;
-    while (!identical(token.kind, EOF_TOKEN)) {
-      token = parseTopLevelDeclaration(token);
-      count++;
-    }
-    listener.endCompilationUnit(count, token);
-    return token;
-  }
-
-  Token parseTopLevelDeclaration(Token token) {
-    token = _parseTopLevelDeclaration(token);
-    listener.endTopLevelDeclaration(token);
-    return token;
-  }
-
-  Token _parseTopLevelDeclaration(Token token) {
-    token = parseMetadataStar(token);
-    final String value = token.stringValue;
-    if ((identical(value, 'abstract') && optional('class', token.next)) ||
-        identical(value, 'class')) {
-      return parseClassOrNamedMixinApplication(token);
-    } else if (identical(value, 'enum')) {
-      return parseEnum(token);
-    } else if (identical(value, 'typedef')) {
-      return parseTypedef(token);
-    } else if (identical(value, 'library')) {
-      return parseLibraryName(token);
-    } else if (identical(value, 'import')) {
-      return parseImport(token);
-    } else if (identical(value, 'export')) {
-      return parseExport(token);
-    } else if (identical(value, 'part')) {
-      return parsePartOrPartOf(token);
-    } else {
-      return parseTopLevelMember(token);
-    }
-  }
-
-  /// library qualified ';'
-  Token parseLibraryName(Token token) {
-    Token libraryKeyword = token;
-    listener.beginLibraryName(libraryKeyword);
-    assert(optional('library', token));
-    token = parseQualified(token.next);
-    Token semicolon = token;
-    token = expect(';', token);
-    listener.endLibraryName(libraryKeyword, semicolon);
-    return token;
-  }
-
-  /// import uri (if (test) uri)* (as identifier)? combinator* ';'
-  Token parseImport(Token token) {
-    Token importKeyword = token;
-    listener.beginImport(importKeyword);
-    assert(optional('import', token));
-    token = parseLiteralStringOrRecoverExpression(token.next);
-    token = parseConditionalUris(token);
-    Token deferredKeyword;
-    if (optional('deferred', token)) {
-      deferredKeyword = token;
-      token = token.next;
-    }
-    Token asKeyword;
-    if (optional('as', token)) {
-      asKeyword = token;
-      token = parseIdentifier(token.next);
-    }
-    token = parseCombinators(token);
-    Token semicolon = token;
-    token = expect(';', token);
-    listener.endImport(importKeyword, deferredKeyword, asKeyword, semicolon);
-    return token;
-  }
-
-  /// if (test) uri
-  Token parseConditionalUris(Token token) {
-    listener.beginConditionalUris(token);
-    int count = 0;
-    while (optional('if', token)) {
-      count++;
-      token = parseConditionalUri(token);
-    }
-    listener.endConditionalUris(count);
-    return token;
-  }
-
-  Token parseConditionalUri(Token token) {
-    listener.beginConditionalUri(token);
-    Token ifKeyword = token;
-    token = expect('if', token);
-    token = expect('(', token);
-    token = parseDottedName(token);
-    Token equalitySign;
-    if (optional('==', token)) {
-      equalitySign = token;
-      token = parseLiteralStringOrRecoverExpression(token.next);
-    }
-    token = expect(')', token);
-    token = parseLiteralStringOrRecoverExpression(token);
-    listener.endConditionalUri(ifKeyword, equalitySign);
-    return token;
-  }
-
-  Token parseDottedName(Token token) {
-    listener.beginDottedName(token);
-    Token firstIdentifier = token;
-    token = parseIdentifier(token);
-    int count = 1;
-    while (optional('.', token)) {
-      token = parseIdentifier(token.next);
-      count++;
-    }
-    listener.endDottedName(count, firstIdentifier);
-    return token;
-  }
-
-  /// export uri conditional-uris* combinator* ';'
-  Token parseExport(Token token) {
-    Token exportKeyword = token;
-    listener.beginExport(exportKeyword);
-    assert(optional('export', token));
-    token = parseLiteralStringOrRecoverExpression(token.next);
-    token = parseConditionalUris(token);
-    token = parseCombinators(token);
-    Token semicolon = token;
-    token = expect(';', token);
-    listener.endExport(exportKeyword, semicolon);
-    return token;
-  }
-
-  Token parseCombinators(Token token) {
-    listener.beginCombinators(token);
-    int count = 0;
-    while (true) {
-      String value = token.stringValue;
-      if (identical('hide', value)) {
-        token = parseHide(token);
-      } else if (identical('show', value)) {
-        token = parseShow(token);
-      } else {
-        listener.endCombinators(count);
-        break;
-      }
-      count++;
-    }
-    return token;
-  }
-
-  /// hide identifierList
-  Token parseHide(Token token) {
-    Token hideKeyword = token;
-    listener.beginHide(hideKeyword);
-    assert(optional('hide', token));
-    token = parseIdentifierList(token.next);
-    listener.endHide(hideKeyword);
-    return token;
-  }
-
-  /// show identifierList
-  Token parseShow(Token token) {
-    Token showKeyword = token;
-    listener.beginShow(showKeyword);
-    assert(optional('show', token));
-    token = parseIdentifierList(token.next);
-    listener.endShow(showKeyword);
-    return token;
-  }
-
-  /// identifier (, identifier)*
-  Token parseIdentifierList(Token token) {
-    listener.beginIdentifierList(token);
-    token = parseIdentifier(token);
-    int count = 1;
-    while (optional(',', token)) {
-      token = parseIdentifier(token.next);
-      count++;
-    }
-    listener.endIdentifierList(count);
-    return token;
-  }
-
-  /// type (, type)*
-  Token parseTypeList(Token token) {
-    listener.beginTypeList(token);
-    token = parseType(token);
-    int count = 1;
-    while (optional(',', token)) {
-      token = parseType(token.next);
-      count++;
-    }
-    listener.endTypeList(count);
-    return token;
-  }
-
-  Token parsePartOrPartOf(Token token) {
-    assert(optional('part', token));
-    if (optional('of', token.next)) {
-      return parsePartOf(token);
-    } else {
-      return parsePart(token);
-    }
-  }
-
-  Token parsePart(Token token) {
-    Token partKeyword = token;
-    listener.beginPart(token);
-    assert(optional('part', token));
-    token = parseLiteralStringOrRecoverExpression(token.next);
-    Token semicolon = token;
-    token = expect(';', token);
-    listener.endPart(partKeyword, semicolon);
-    return token;
-  }
-
-  Token parsePartOf(Token token) {
-    listener.beginPartOf(token);
-    assert(optional('part', token));
-    assert(optional('of', token.next));
-    Token partKeyword = token;
-    token = parseQualified(token.next.next);
-    Token semicolon = token;
-    token = expect(';', token);
-    listener.endPartOf(partKeyword, semicolon);
-    return token;
-  }
-
-  Token parseMetadataStar(Token token, {bool forParameter: false}) {
-    listener.beginMetadataStar(token);
-    int count = 0;
-    while (optional('@', token)) {
-      token = parseMetadata(token);
-      count++;
-    }
-    listener.endMetadataStar(count, forParameter);
-    return token;
-  }
-
-  /**
-   * Parse
-   * [: '@' qualified (‘.’ identifier)? (arguments)? :]
-   */
-  Token parseMetadata(Token token) {
-    listener.beginMetadata(token);
-    Token atToken = token;
-    assert(optional('@', token));
-    token = parseIdentifier(token.next);
-    token = parseQualifiedRestOpt(token);
-    token = parseTypeArgumentsOpt(token);
-    Token period = null;
-    if (optional('.', token)) {
-      period = token;
-      token = parseIdentifier(token.next);
-    }
-    token = parseArgumentsOpt(token);
-    listener.endMetadata(atToken, period, token);
-    return token;
-  }
-
-  Token parseTypedef(Token token) {
-    Token typedefKeyword = token;
-    listener.beginFunctionTypeAlias(token);
-    token = parseReturnTypeOpt(token.next);
-    token = parseIdentifier(token);
-    token = parseTypeVariablesOpt(token);
-    token = parseFormalParameters(token);
-    listener.endFunctionTypeAlias(typedefKeyword, token);
-    return expect(';', token);
-  }
-
-  Token parseMixinApplication(Token token) {
-    listener.beginMixinApplication(token);
-    token = parseType(token);
-    token = expect('with', token);
-    token = parseTypeList(token);
-    listener.endMixinApplication();
-    return token;
-  }
-
-  Token parseReturnTypeOpt(Token token) {
-    if (identical(token.stringValue, 'void')) {
-      listener.handleVoidKeyword(token);
-      return token.next;
-    } else {
-      return parseTypeOpt(token);
-    }
-  }
-
-  Token parseFormalParametersOpt(Token token) {
-    if (optional('(', token)) {
-      return parseFormalParameters(token);
-    } else {
-      listener.handleNoFormalParameters(token);
-      return token;
-    }
-  }
-
-  Token parseFormalParameters(Token token) {
-    Token begin = token;
-    listener.beginFormalParameters(begin);
-    expect('(', token);
-    int parameterCount = 0;
-    do {
-      token = token.next;
-      if (optional(')', token)) {
-        break;
-      }
-      ++parameterCount;
-      String value = token.stringValue;
-      if (identical(value, '[')) {
-        token = parseOptionalFormalParameters(token, false);
-        break;
-      } else if (identical(value, '{')) {
-        token = parseOptionalFormalParameters(token, true);
-        break;
-      }
-      token = parseFormalParameter(token, FormalParameterType.REQUIRED);
-    } while (optional(',', token));
-    listener.endFormalParameters(parameterCount, begin, token);
-    return expect(')', token);
-  }
-
-  Token parseFormalParameter(Token token, FormalParameterType type) {
-    token = parseMetadataStar(token, forParameter: true);
-    listener.beginFormalParameter(token);
-
-    // Skip over `covariant` token, if the next token is an identifier or
-    // modifier.
-    // This enables the case where `covariant` is the name of the parameter:
-    //    void foo(covariant);
-    if (identical(token.stringValue, 'covariant') &&
-        (token.next.isIdentifier() || isModifier(token.next))) {
-      token = token.next;
-    }
-    token = parseModifiers(token);
-    // TODO(ahe): Validate that there are formal parameters if void.
-    token = parseReturnTypeOpt(token);
-    Token thisKeyword = null;
-    if (optional('this', token)) {
-      thisKeyword = token;
-      // TODO(ahe): Validate field initializers are only used in
-      // constructors, and not for function-typed arguments.
-      token = expect('.', token.next);
-    }
-    token = parseIdentifier(token);
-    if (optional('(', token)) {
-      listener.handleNoTypeVariables(token);
-      token = parseFormalParameters(token);
-      listener.handleFunctionTypedFormalParameter(token);
-    } else if (optional('<', token)) {
-      token = parseTypeVariablesOpt(token);
-      token = parseFormalParameters(token);
-      listener.handleFunctionTypedFormalParameter(token);
-    }
-    String value = token.stringValue;
-    if ((identical('=', value)) || (identical(':', value))) {
-      // TODO(ahe): Validate that these are only used for optional parameters.
-      Token equal = token;
-      token = parseExpression(token.next);
-      listener.handleValuedFormalParameter(equal, token);
-      if (type.isRequired) {
-        listener.reportError(
-            equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT);
-      } else if (type.isPositional && identical(':', value)) {
-        listener.reportError(
-            equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS);
-      }
-    }
-    listener.endFormalParameter(thisKeyword);
-    return token;
-  }
-
-  Token parseOptionalFormalParameters(Token token, bool isNamed) {
-    Token begin = token;
-    listener.beginOptionalFormalParameters(begin);
-    assert((isNamed && optional('{', token)) || optional('[', token));
-    int parameterCount = 0;
-    do {
-      token = token.next;
-      if (isNamed && optional('}', token)) {
-        break;
-      } else if (!isNamed && optional(']', token)) {
-        break;
-      }
-      var type =
-          isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
-      token = parseFormalParameter(token, type);
-      ++parameterCount;
-    } while (optional(',', token));
-    if (parameterCount == 0) {
-      listener.reportError(
-          token,
-          isNamed
-              ? MessageKind.EMPTY_NAMED_PARAMETER_LIST
-              : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST);
-    }
-    listener.endOptionalFormalParameters(parameterCount, begin, token);
-    if (isNamed) {
-      return expect('}', token);
-    } else {
-      return expect(']', token);
-    }
-  }
-
-  Token parseTypeOpt(Token token) {
-    Token peek = peekAfterIfType(token);
-    if (peek != null && (peek.isIdentifier() || optional('this', peek))) {
-      return parseType(token);
-    }
-    listener.handleNoType(token);
-    return token;
-  }
-
-  bool isValidTypeReference(Token token) {
-    final kind = token.kind;
-    if (identical(kind, IDENTIFIER_TOKEN)) return true;
-    if (identical(kind, KEYWORD_TOKEN)) {
-      Keyword keyword = (token as KeywordToken).keyword;
-      String value = keyword.syntax;
-      return keyword.isPseudo ||
-          (identical(value, 'dynamic')) ||
-          (identical(value, 'void'));
-    }
-    return false;
-  }
-
-  /// Returns true if [token] matches '<' type (',' type)* '>' '(', and
-  /// otherwise returns false. The final '(' is not part of the grammar
-  /// construct `typeArguments`, but it is required here such that type
-  /// arguments in generic method invocations can be recognized, and as few as
-  /// possible other constructs will pass (e.g., 'a < C, D > 3').
-  bool isValidMethodTypeArguments(Token token) {
-    return tryParseMethodTypeArguments(token) != null;
-  }
-
-  /// Returns token after match if [token] matches '<' type (',' type)* '>' '(',
-  /// and otherwise returns null. Does not produce listener events. With respect
-  /// to the final '(', please see the description of
-  /// [isValidMethodTypeArguments].
-  Token tryParseMethodTypeArguments(Token token) {
-    if (!identical(token.kind, LT_TOKEN)) return null;
-    BeginGroupToken beginToken = token;
-    Token endToken = beginToken.endGroup;
-    if (endToken == null || !identical(endToken.next.kind, OPEN_PAREN_TOKEN)) {
-      return null;
-    }
-    token = tryParseType(token.next);
-    while (token != null && identical(token.kind, COMMA_TOKEN)) {
-      token = tryParseType(token.next);
-    }
-    if (token == null || !identical(token.kind, GT_TOKEN)) return null;
-    return token.next;
-  }
-
-  /// Returns token after match if [token] matches typeName typeArguments?, and
-  /// otherwise returns null. Does not produce listener events.
-  Token tryParseType(Token token) {
-    token = tryParseQualified(token);
-    if (token == null) return null;
-    Token tokenAfterQualified = token;
-    token = tryParseNestedTypeArguments(token);
-    return token == null ? tokenAfterQualified : token;
-  }
-
-  /// Returns token after match if [token] matches identifier ('.' identifier)?,
-  /// and otherwise returns null. Does not produce listener events.
-  Token tryParseQualified(Token token) {
-    if (!isValidTypeReference(token)) return null;
-    token = token.next;
-    if (!identical(token.kind, PERIOD_TOKEN)) return token;
-    token = token.next;
-    if (!identical(token.kind, IDENTIFIER_TOKEN)) return null;
-    return token.next;
-  }
-
-  /// Returns token after match if [token] matches '<' type (',' type)* '>',
-  /// and otherwise returns null. Does not produce listener events. The final
-  /// '>' may be the first character in a '>>' token, in which case a synthetic
-  /// '>' token is created and returned, representing the second '>' in the
-  /// '>>' token.
-  Token tryParseNestedTypeArguments(Token token) {
-    if (!identical(token.kind, LT_TOKEN)) return null;
-    // If the initial '<' matches the first '>' in a '>>' token, we will have
-    // `token.endGroup == null`, so we cannot rely on `token.endGroup == null`
-    // to imply that the match must fail. Hence no `token.endGroup == null`
-    // test here.
-    token = tryParseType(token.next);
-    while (token != null && identical(token.kind, COMMA_TOKEN)) {
-      token = tryParseType(token.next);
-    }
-    if (token == null) return null;
-    if (identical(token.kind, GT_TOKEN)) return token.next;
-    if (!identical(token.kind, GT_GT_TOKEN)) return null;
-    // [token] is '>>' of which the final '>' that we are parsing is the first
-    // character. In order to keep the parsing process on track we must return
-    // a synthetic '>' corresponding to the second character of that '>>'.
-    Token syntheticToken = new SymbolToken(GT_INFO, token.charOffset + 1);
-    syntheticToken.next = token.next;
-    return syntheticToken;
-  }
-
-  Token parseQualified(Token token) {
-    token = parseIdentifier(token);
-    while (optional('.', token)) {
-      token = parseQualifiedRest(token);
-    }
-    return token;
-  }
-
-  Token parseQualifiedRestOpt(Token token) {
-    if (optional('.', token)) {
-      return parseQualifiedRest(token);
-    } else {
-      return token;
-    }
-  }
-
-  Token parseQualifiedRest(Token token) {
-    assert(optional('.', token));
-    Token period = token;
-    token = parseIdentifier(token.next);
-    listener.handleQualified(period);
-    return token;
-  }
-
-  Token skipBlock(Token token) {
-    if (!optional('{', token)) {
-      return listener.expectedBlockToSkip(token);
-    }
-    BeginGroupToken beginGroupToken = token;
-    Token endGroup = beginGroupToken.endGroup;
-    if (endGroup == null) {
-      return listener.unmatched(beginGroupToken);
-    } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) {
-      return listener.unmatched(beginGroupToken);
-    }
-    return beginGroupToken.endGroup;
-  }
-
-  Token parseEnum(Token token) {
-    listener.beginEnum(token);
-    Token enumKeyword = token;
-    token = parseIdentifier(token.next);
-    token = expect('{', token);
-    int count = 0;
-    if (!optional('}', token)) {
-      token = parseIdentifier(token);
-      count++;
-      while (optional(',', token)) {
-        token = token.next;
-        if (optional('}', token)) break;
-        token = parseIdentifier(token);
-        count++;
-      }
-    }
-    Token endBrace = token;
-    token = expect('}', token);
-    listener.endEnum(enumKeyword, endBrace, count);
-    return token;
-  }
-
-  Token parseClassOrNamedMixinApplication(Token token) {
-    Token begin = token;
-    Token abstractKeyword;
-    if (optional('abstract', token)) {
-      abstractKeyword = token;
-      token = token.next;
-    }
-    Token classKeyword = token;
-    var isMixinApplication = optional('=', peekAfterType(token.next));
-    if (isMixinApplication) {
-      listener.beginNamedMixinApplication(begin);
-    } else {
-      listener.beginClassDeclaration(begin);
-    }
-
-    int modifierCount = 0;
-    if (abstractKeyword != null) {
-      parseModifier(abstractKeyword);
-      modifierCount++;
-    }
-    listener.handleModifiers(modifierCount);
-
-    if (isMixinApplication) {
-      token = parseIdentifier(token.next);
-      token = parseTypeVariablesOpt(token);
-      token = expect('=', token);
-      return parseNamedMixinApplication(token, classKeyword);
-    } else {
-      return parseClass(begin, classKeyword);
-    }
-  }
-
-  Token parseNamedMixinApplication(Token token, Token classKeyword) {
-    token = parseMixinApplication(token);
-    Token implementsKeyword = null;
-    if (optional('implements', token)) {
-      implementsKeyword = token;
-      token = parseTypeList(token.next);
-    }
-    listener.endNamedMixinApplication(classKeyword, implementsKeyword, token);
-    return expect(';', token);
-  }
-
-  Token parseClass(Token begin, Token classKeyword) {
-    Token token = parseIdentifier(classKeyword.next);
-    token = parseTypeVariablesOpt(token);
-    Token extendsKeyword;
-    if (optional('extends', token)) {
-      extendsKeyword = token;
-      if (optional('with', peekAfterType(token.next))) {
-        token = parseMixinApplication(token.next);
-      } else {
-        token = parseType(token.next);
-      }
-    } else {
-      extendsKeyword = null;
-      listener.handleNoType(token);
-    }
-    Token implementsKeyword;
-    int interfacesCount = 0;
-    if (optional('implements', token)) {
-      implementsKeyword = token;
-      do {
-        token = parseType(token.next);
-        ++interfacesCount;
-      } while (optional(',', token));
-    }
-    token = parseClassBody(token);
-    listener.endClassDeclaration(
-        interfacesCount, begin, extendsKeyword, implementsKeyword, token);
-    return token.next;
-  }
-
-  Token parseStringPart(Token token) {
-    if (identical(token.kind, STRING_TOKEN)) {
-      listener.handleStringPart(token);
-      return token.next;
-    } else {
-      return listener.expected('string', token);
-    }
-  }
-
-  Token parseIdentifier(Token token) {
-    if (!token.isIdentifier()) {
-      token = listener.expectedIdentifier(token);
-    }
-    listener.handleIdentifier(token);
-    return token.next;
-  }
-
-  Token expect(String string, Token token) {
-    if (!identical(string, token.stringValue)) {
-      return listener.expected(string, token);
-    }
-    return token.next;
-  }
-
-  Token parseTypeVariable(Token token) {
-    listener.beginTypeVariable(token);
-    token = parseIdentifier(token);
-    Token extendsOrSuper = null;
-    if (optional('extends', token) || optional('super', token)) {
-      extendsOrSuper = token;
-      token = parseType(token.next);
-    } else {
-      listener.handleNoType(token);
-    }
-    listener.endTypeVariable(token, extendsOrSuper);
-    return token;
-  }
-
-  /**
-   * Returns true if the stringValue of the [token] is [value].
-   */
-  bool optional(String value, Token token) {
-    return identical(value, token.stringValue);
-  }
-
-  /**
-   * Returns true if the stringValue of the [token] is either [value1],
-   * [value2], or [value3].
-   */
-  bool isOneOf3(Token token, String value1, String value2, String value3) {
-    String stringValue = token.stringValue;
-    return value1 == stringValue ||
-        value2 == stringValue ||
-        value3 == stringValue;
-  }
-
-  /**
-   * Returns true if the stringValue of the [token] is either [value1],
-   * [value2], [value3], or [value4].
-   */
-  bool isOneOf4(
-      Token token, String value1, String value2, String value3, String value4) {
-    String stringValue = token.stringValue;
-    return value1 == stringValue ||
-        value2 == stringValue ||
-        value3 == stringValue ||
-        value4 == stringValue;
-  }
-
-  bool notEofOrValue(String value, Token token) {
-    return !identical(token.kind, EOF_TOKEN) &&
-        !identical(value, token.stringValue);
-  }
-
-  Token parseType(Token token) {
-    Token begin = token;
-    if (isValidTypeReference(token)) {
-      token = parseIdentifier(token);
-      token = parseQualifiedRestOpt(token);
-    } else {
-      token = listener.expectedType(token);
-    }
-    token = parseTypeArgumentsOpt(token);
-    listener.endType(begin, token);
-    return token;
-  }
-
-  Token parseTypeArgumentsOpt(Token token) {
-    return parseStuff(
-        token,
-        (t) => listener.beginTypeArguments(t),
-        (t) => parseType(t),
-        (c, bt, et) => listener.endTypeArguments(c, bt, et),
-        (t) => listener.handleNoTypeArguments(t));
-  }
-
-  Token parseTypeVariablesOpt(Token token) {
-    return parseStuff(
-        token,
-        (t) => listener.beginTypeVariables(t),
-        (t) => parseTypeVariable(t),
-        (c, bt, et) => listener.endTypeVariables(c, bt, et),
-        (t) => listener.handleNoTypeVariables(t));
-  }
-
-  // TODO(ahe): Clean this up.
-  Token parseStuff(Token token, Function beginStuff, Function stuffParser,
-      Function endStuff, Function handleNoStuff) {
-    if (optional('<', token)) {
-      Token begin = token;
-      beginStuff(begin);
-      int count = 0;
-      do {
-        token = stuffParser(token.next);
-        ++count;
-      } while (optional(',', token));
-      Token next = token.next;
-      if (identical(token.stringValue, '>>')) {
-        token = new SymbolToken(GT_INFO, token.charOffset);
-        token.next = new SymbolToken(GT_INFO, token.charOffset + 1);
-        token.next.next = next;
-      }
-      endStuff(count, begin, token);
-      return expect('>', token);
-    }
-    handleNoStuff(token);
-    return token;
-  }
-
-  Token parseTopLevelMember(Token token) {
-    Token start = token;
-    listener.beginTopLevelMember(token);
-
-    Link<Token> identifiers = findMemberName(token);
-    if (identifiers.isEmpty) {
-      return listener.expectedDeclaration(start);
-    }
-    Token afterName = identifiers.head;
-    identifiers = identifiers.tail;
-
-    if (identifiers.isEmpty) {
-      return listener.expectedDeclaration(start);
-    }
-    Token name = identifiers.head;
-    identifiers = identifiers.tail;
-    Token getOrSet;
-    if (!identifiers.isEmpty) {
-      String value = identifiers.head.stringValue;
-      if ((identical(value, 'get')) || (identical(value, 'set'))) {
-        getOrSet = identifiers.head;
-        identifiers = identifiers.tail;
-      }
-    }
-    Token type;
-    if (!identifiers.isEmpty) {
-      if (isValidTypeReference(identifiers.head)) {
-        type = identifiers.head;
-        identifiers = identifiers.tail;
-      }
-    }
-
-    token = afterName;
-    bool isField;
-    while (true) {
-      // Loop to allow the listener to rewrite the token stream for
-      // error handling.
-      final String value = token.stringValue;
-      if ((identical(value, '(')) ||
-          (identical(value, '{')) ||
-          (identical(value, '=>'))) {
-        isField = false;
-        break;
-      } else if ((identical(value, '=')) || (identical(value, ','))) {
-        isField = true;
-        break;
-      } else if (identical(value, ';')) {
-        if (getOrSet != null) {
-          // If we found a "get" keyword, this must be an abstract
-          // getter.
-          isField = (!identical(getOrSet.stringValue, 'get'));
-          // TODO(ahe): This feels like a hack.
-        } else {
-          isField = true;
-        }
-        break;
-      } else {
-        token = listener.unexpected(token);
-        if (identical(token.kind, EOF_TOKEN)) return token;
-      }
-    }
-    var modifiers = identifiers.reverse();
-    return isField
-        ? parseFields(start, modifiers, type, getOrSet, name, true)
-        : parseTopLevelMethod(start, modifiers, type, getOrSet, name);
-  }
-
-  bool isVarFinalOrConst(Token token) {
-    String value = token.stringValue;
-    return identical('var', value) ||
-        identical('final', value) ||
-        identical('const', value);
-  }
-
-  Token expectVarFinalOrConst(
-      Link<Token> modifiers, bool hasType, bool allowStatic) {
-    int modifierCount = 0;
-    Token staticModifier;
-    if (allowStatic &&
-        !modifiers.isEmpty &&
-        optional('static', modifiers.head)) {
-      staticModifier = modifiers.head;
-      modifierCount++;
-      parseModifier(staticModifier);
-      modifiers = modifiers.tail;
-    }
-    if (modifiers.isEmpty) {
-      listener.handleModifiers(modifierCount);
-      return null;
-    }
-    if (modifiers.tail.isEmpty) {
-      Token modifier = modifiers.head;
-      if (isVarFinalOrConst(modifier)) {
-        modifierCount++;
-        parseModifier(modifier);
-        listener.handleModifiers(modifierCount);
-        // TODO(ahe): The caller checks for "var Type name", perhaps we should
-        // check here instead.
-        return modifier;
-      }
-    }
-
-    // Slow case to report errors.
-    List<Token> modifierList = modifiers.toList();
-    Token varFinalOrConst =
-        modifierList.firstWhere(isVarFinalOrConst, orElse: () => null);
-    if (allowStatic && staticModifier == null) {
-      staticModifier = modifierList.firstWhere(
-          (modifier) => optional('static', modifier),
-          orElse: () => null);
-      if (staticModifier != null) {
-        modifierCount++;
-        parseModifier(staticModifier);
-        modifierList.remove(staticModifier);
-      }
-    }
-    bool hasTypeOrModifier = hasType;
-    if (varFinalOrConst != null) {
-      parseModifier(varFinalOrConst);
-      modifierCount++;
-      hasTypeOrModifier = true;
-      modifierList.remove(varFinalOrConst);
-    }
-    listener.handleModifiers(modifierCount);
-    var kind = hasTypeOrModifier
-        ? MessageKind.EXTRANEOUS_MODIFIER
-        : MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
-    for (Token modifier in modifierList) {
-      listener.reportError(modifier, kind, {'modifier': modifier});
-    }
-    return null;
-  }
-
-  /// Removes the optional `covariant` token from the modifiers, if there
-  /// is no `static` in the list, and `covariant` is the first modifier.
-  Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) {
-    if (modifiers.isEmpty ||
-        !identical(modifiers.first.stringValue, 'covariant')) {
-      return modifiers;
-    }
-    for (Token modifier in modifiers.tail) {
-      if (identical(modifier.stringValue, 'static')) {
-        return modifiers;
-      }
-    }
-    return modifiers.tail;
-  }
-
-  Token parseFields(Token start, Link<Token> modifiers, Token type,
-      Token getOrSet, Token name, bool isTopLevel) {
-    bool hasType = type != null;
-
-    if (getOrSet == null && !isTopLevel) {
-      modifiers = removeOptCovariantTokenIfNotStatic(modifiers);
-    }
-
-    Token varFinalOrConst =
-        expectVarFinalOrConst(modifiers, hasType, !isTopLevel);
-    bool isVar = false;
-    bool hasModifier = false;
-    if (varFinalOrConst != null) {
-      hasModifier = true;
-      isVar = optional('var', varFinalOrConst);
-    }
-
-    if (getOrSet != null) {
-      var kind = (hasModifier || hasType)
-          ? MessageKind.EXTRANEOUS_MODIFIER
-          : MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
-      listener.reportError(getOrSet, kind, {'modifier': getOrSet});
-    }
-
-    if (!hasType) {
-      listener.handleNoType(name);
-    } else if (optional('void', type)) {
-      listener.handleNoType(name);
-      // TODO(ahe): This error is reported twice, second time is from
-      // [parseVariablesDeclarationMaybeSemicolon] via
-      // [PartialFieldListElement.parseNode].
-      listener.reportError(type, MessageKind.VOID_NOT_ALLOWED);
-    } else {
-      parseType(type);
-      if (isVar) {
-        listener.reportError(modifiers.head, MessageKind.EXTRANEOUS_MODIFIER,
-            {'modifier': modifiers.head});
-      }
-    }
-
-    Token token = parseIdentifier(name);
-
-    int fieldCount = 1;
-    token = parseVariableInitializerOpt(token);
-    while (optional(',', token)) {
-      token = parseIdentifier(token.next);
-      token = parseVariableInitializerOpt(token);
-      ++fieldCount;
-    }
-    Token semicolon = token;
-    token = expectSemicolon(token);
-    if (isTopLevel) {
-      listener.endTopLevelFields(fieldCount, start, semicolon);
-    } else {
-      listener.endFields(fieldCount, start, semicolon);
-    }
-    return token;
-  }
-
-  Token parseTopLevelMethod(Token start, Link<Token> modifiers, Token type,
-      Token getOrSet, Token name) {
-    Token externalModifier;
-    // TODO(johnniwinther): Move error reporting to resolution to give more
-    // specific error messages.
-    for (Token modifier in modifiers) {
-      if (externalModifier == null && optional('external', modifier)) {
-        externalModifier = modifier;
-      } else {
-        listener.reportError(
-            modifier, MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
-      }
-    }
-    if (externalModifier != null) {
-      parseModifier(externalModifier);
-      listener.handleModifiers(1);
-    } else {
-      listener.handleModifiers(0);
-    }
-
-    if (type == null) {
-      listener.handleNoType(name);
-    } else {
-      parseReturnTypeOpt(type);
-    }
-    Token token = parseIdentifier(name);
-
-    if (getOrSet == null) {
-      token = parseTypeVariablesOpt(token);
-    } else {
-      listener.handleNoTypeVariables(token);
-    }
-    token = parseFormalParametersOpt(token);
-    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
-    token = parseAsyncModifier(token);
-    token = parseFunctionBody(token, false, externalModifier != null);
-    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
-    Token endToken = token;
-    token = token.next;
-    if (token.kind == BAD_INPUT_TOKEN) {
-      token = listener.unexpected(token);
-    }
-    listener.endTopLevelMethod(start, getOrSet, endToken);
-    return token;
-  }
-
-  /// Looks ahead to find the name of a member. Returns a link of the modifiers,
-  /// set/get, (operator) name, and either the start of the method body or the
-  /// end of the declaration.
-  ///
-  /// Examples:
-  ///
-  ///     int get foo;
-  /// results in
-  ///     [';', 'foo', 'get', 'int']
-  ///
-  ///
-  ///     static const List<int> foo = null;
-  /// results in
-  ///     ['=', 'foo', 'List', 'const', 'static']
-  ///
-  ///
-  ///     get foo async* { return null }
-  /// results in
-  ///     ['{', 'foo', 'get']
-  ///
-  ///
-  ///     operator *(arg) => null;
-  /// results in
-  ///     ['(', '*', 'operator']
-  ///
-  Link<Token> findMemberName(Token token) {
-    Link<Token> identifiers = const Link<Token>();
-
-    // `true` if 'get' has been seen.
-    bool isGetter = false;
-    // `true` if an identifier has been seen after 'get'.
-    bool hasName = false;
-
-    while (token.kind != EOF_TOKEN) {
-      String value = token.stringValue;
-      if (value == 'get') {
-        isGetter = true;
-      } else if (hasName && (value == 'sync' || value == 'async')) {
-        // Skip.
-        token = token.next;
-        value = token.stringValue;
-        if (value == '*') {
-          // Skip.
-          token = token.next;
-        }
-        continue;
-      } else if (value == '(' || value == '{' || value == '=>') {
-        // A method.
-        identifiers = identifiers.prepend(token);
-        return identifiers;
-      } else if (value == '=' || value == ';' || value == ',') {
-        // A field or abstract getter.
-        identifiers = identifiers.prepend(token);
-        return identifiers;
-      } else if (isGetter) {
-        hasName = true;
-      }
-      identifiers = identifiers.prepend(token);
-      if (isValidTypeReference(token)) {
-        // type ...
-        if (optional('.', token.next)) {
-          // type '.' ...
-          if (token.next.next.isIdentifier()) {
-            // type '.' identifier
-            token = token.next.next;
-          }
-        }
-        if (optional('<', token.next)) {
-          if (token.next is BeginGroupToken) {
-            BeginGroupToken beginGroup = token.next;
-            if (beginGroup.endGroup == null) {
-              listener.unmatched(beginGroup);
-            }
-            token = beginGroup.endGroup;
-          }
-        }
-      }
-      token = token.next;
-    }
-    return const Link<Token>();
-  }
-
-  Token parseVariableInitializerOpt(Token token) {
-    if (optional('=', token)) {
-      Token assignment = token;
-      listener.beginInitializer(token);
-      token = parseExpression(token.next);
-      listener.endInitializer(assignment);
-    }
-    return token;
-  }
-
-  Token parseInitializersOpt(Token token) {
-    if (optional(':', token)) {
-      return parseInitializers(token);
-    } else {
-      listener.handleNoInitializers();
-      return token;
-    }
-  }
-
-  Token parseInitializers(Token token) {
-    Token begin = token;
-    listener.beginInitializers(begin);
-    expect(':', token);
-    int count = 0;
-    bool old = mayParseFunctionExpressions;
-    mayParseFunctionExpressions = false;
-    do {
-      token = parseExpression(token.next);
-      ++count;
-    } while (optional(',', token));
-    mayParseFunctionExpressions = old;
-    listener.endInitializers(count, begin, token);
-    return token;
-  }
-
-  Token parseLiteralStringOrRecoverExpression(Token token) {
-    if (identical(token.kind, STRING_TOKEN)) {
-      return parseLiteralString(token);
-    } else {
-      listener.recoverableError(token, "unexpected");
-      return parseExpression(token);
-    }
-  }
-
-  Token expectSemicolon(Token token) {
-    return expect(';', token);
-  }
-
-  bool isModifier(Token token) {
-    final String value = token.stringValue;
-    return (identical('final', value)) ||
-        (identical('var', value)) ||
-        (identical('const', value)) ||
-        (identical('abstract', value)) ||
-        (identical('static', value)) ||
-        (identical('external', value));
-  }
-
-  Token parseModifier(Token token) {
-    assert(isModifier(token));
-    listener.handleModifier(token);
-    return token.next;
-  }
-
-  void parseModifierList(Link<Token> tokens) {
-    int count = 0;
-    for (; !tokens.isEmpty; tokens = tokens.tail) {
-      Token token = tokens.head;
-      if (isModifier(token)) {
-        parseModifier(token);
-      } else {
-        listener.unexpected(token);
-        // Skip the remaining modifiers.
-        break;
-      }
-      count++;
-    }
-    listener.handleModifiers(count);
-  }
-
-  Token parseModifiers(Token token) {
-    int count = 0;
-    while (identical(token.kind, KEYWORD_TOKEN)) {
-      if (!isModifier(token)) break;
-      token = parseModifier(token);
-      count++;
-    }
-    listener.handleModifiers(count);
-    return token;
-  }
-
-  /**
-   * Returns the first token after the type starting at [token].
-   * This method assumes that [token] is an identifier (or void).
-   * Use [peekAfterIfType] if [token] isn't known to be an identifier.
-   */
-  Token peekAfterType(Token token) {
-    // We are looking at "identifier ...".
-    Token peek = token.next;
-    if (identical(peek.kind, PERIOD_TOKEN)) {
-      if (peek.next.isIdentifier()) {
-        // Look past a library prefix.
-        peek = peek.next.next;
-      }
-    }
-    // We are looking at "qualified ...".
-    if (identical(peek.kind, LT_TOKEN)) {
-      // Possibly generic type.
-      // We are looking at "qualified '<'".
-      BeginGroupToken beginGroupToken = peek;
-      Token gtToken = beginGroupToken.endGroup;
-      if (gtToken != null) {
-        // We are looking at "qualified '<' ... '>' ...".
-        return gtToken.next;
-      }
-    }
-    return peek;
-  }
-
-  /**
-   * If [token] is the start of a type, returns the token after that type.
-   * If [token] is not the start of a type, null is returned.
-   */
-  Token peekAfterIfType(Token token) {
-    if (!optional('void', token) && !token.isIdentifier()) {
-      return null;
-    }
-    return peekAfterType(token);
-  }
-
-  Token parseClassBody(Token token) {
-    Token begin = token;
-    listener.beginClassBody(token);
-    if (!optional('{', token)) {
-      token = listener.expectedClassBody(token);
-    }
-    token = token.next;
-    int count = 0;
-    while (notEofOrValue('}', token)) {
-      token = parseMember(token);
-      ++count;
-    }
-    expect('}', token);
-    listener.endClassBody(count, begin, token);
-    return token;
-  }
-
-  bool isGetOrSet(Token token) {
-    final String value = token.stringValue;
-    return (identical(value, 'get')) || (identical(value, 'set'));
-  }
-
-  bool isFactoryDeclaration(Token token) {
-    if (optional('external', token)) token = token.next;
-    if (optional('const', token)) token = token.next;
-    return optional('factory', token);
-  }
-
-  Token parseMember(Token token) {
-    token = parseMetadataStar(token);
-    Token start = token;
-    listener.beginMember(token);
-    if (isFactoryDeclaration(token)) {
-      token = parseFactoryMethod(token);
-      listener.endMember();
-      assert(token != null);
-      return token;
-    }
-
-    Link<Token> identifiers = findMemberName(token);
-    if (identifiers.isEmpty) {
-      return listener.expectedDeclaration(start);
-    }
-    Token afterName = identifiers.head;
-    identifiers = identifiers.tail;
-
-    if (identifiers.isEmpty) {
-      return listener.expectedDeclaration(start);
-    }
-    Token name = identifiers.head;
-    identifiers = identifiers.tail;
-    if (!identifiers.isEmpty) {
-      if (optional('operator', identifiers.head)) {
-        name = identifiers.head;
-        identifiers = identifiers.tail;
-      }
-    }
-    Token getOrSet;
-    if (!identifiers.isEmpty) {
-      if (isGetOrSet(identifiers.head)) {
-        getOrSet = identifiers.head;
-        identifiers = identifiers.tail;
-      }
-    }
-    Token type;
-    if (!identifiers.isEmpty) {
-      if (isValidTypeReference(identifiers.head)) {
-        type = identifiers.head;
-        identifiers = identifiers.tail;
-      }
-    }
-
-    token = afterName;
-    bool isField;
-    while (true) {
-      // Loop to allow the listener to rewrite the token stream for
-      // error handling.
-      final String value = token.stringValue;
-      if ((identical(value, '(')) ||
-          (identical(value, '.')) ||
-          (identical(value, '{')) ||
-          (identical(value, '=>')) ||
-          (identical(value, '<'))) {
-        isField = false;
-        break;
-      } else if (identical(value, ';')) {
-        if (getOrSet != null) {
-          // If we found a "get" keyword, this must be an abstract
-          // getter.
-          isField = (!identical(getOrSet.stringValue, 'get'));
-          // TODO(ahe): This feels like a hack.
-        } else {
-          isField = true;
-        }
-        break;
-      } else if ((identical(value, '=')) || (identical(value, ','))) {
-        isField = true;
-        break;
-      } else {
-        token = listener.unexpected(token);
-        if (identical(token.kind, EOF_TOKEN)) {
-          // TODO(ahe): This is a hack, see parseTopLevelMember.
-          listener.endFields(1, start, token);
-          listener.endMember();
-          return token;
-        }
-      }
-    }
-
-    var modifiers = identifiers.reverse();
-    token = isField
-        ? parseFields(start, modifiers, type, getOrSet, name, false)
-        : parseMethod(start, modifiers, type, getOrSet, name);
-    listener.endMember();
-    return token;
-  }
-
-  Token parseMethod(Token start, Link<Token> modifiers, Token type,
-      Token getOrSet, Token name) {
-    Token externalModifier;
-    Token staticModifier;
-    Token constModifier;
-    int modifierCount = 0;
-    int allowedModifierCount = 1;
-    // TODO(johnniwinther): Move error reporting to resolution to give more
-    // specific error messages.
-    for (Token modifier in modifiers) {
-      if (externalModifier == null && optional('external', modifier)) {
-        modifierCount++;
-        externalModifier = modifier;
-        if (modifierCount != allowedModifierCount) {
-          listener.reportError(modifier, MessageKind.EXTRANEOUS_MODIFIER,
-              {'modifier': modifier});
-        }
-        allowedModifierCount++;
-      } else if (staticModifier == null && optional('static', modifier)) {
-        modifierCount++;
-        staticModifier = modifier;
-        if (modifierCount != allowedModifierCount) {
-          listener.reportError(modifier, MessageKind.EXTRANEOUS_MODIFIER,
-              {'modifier': modifier});
-        }
-      } else if (constModifier == null && optional('const', modifier)) {
-        modifierCount++;
-        constModifier = modifier;
-        if (modifierCount != allowedModifierCount) {
-          listener.reportError(modifier, MessageKind.EXTRANEOUS_MODIFIER,
-              {'modifier': modifier});
-        }
-      } else {
-        listener.reportError(
-            modifier, MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
-      }
-    }
-    if (getOrSet != null && constModifier != null) {
-      listener.reportError(constModifier, MessageKind.EXTRANEOUS_MODIFIER,
-          {'modifier': constModifier});
-    }
-    parseModifierList(modifiers);
-
-    if (type == null) {
-      listener.handleNoType(name);
-    } else {
-      parseReturnTypeOpt(type);
-    }
-    Token token;
-    if (optional('operator', name)) {
-      token = parseOperatorName(name);
-      if (staticModifier != null) {
-        listener.reportError(staticModifier, MessageKind.EXTRANEOUS_MODIFIER,
-            {'modifier': staticModifier});
-      }
-    } else {
-      token = parseIdentifier(name);
-    }
-
-    token = parseQualifiedRestOpt(token);
-    if (getOrSet == null) {
-      token = parseTypeVariablesOpt(token);
-    } else {
-      listener.handleNoTypeVariables(token);
-    }
-    token = parseFormalParametersOpt(token);
-    token = parseInitializersOpt(token);
-    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
-    token = parseAsyncModifier(token);
-    if (optional('=', token)) {
-      token = parseRedirectingFactoryBody(token);
-    } else {
-      token = parseFunctionBody(
-          token, false, staticModifier == null || externalModifier != null);
-    }
-    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
-    listener.endMethod(getOrSet, start, token);
-    return token.next;
-  }
-
-  Token parseFactoryMethod(Token token) {
-    assert(isFactoryDeclaration(token));
-    Token start = token;
-    Token externalModifier;
-    if (identical(token.stringValue, 'external')) {
-      externalModifier = token;
-      token = token.next;
-    }
-    if (optional('const', token)) {
-      token = token.next; // Skip const.
-    }
-    Token factoryKeyword = token;
-    listener.beginFactoryMethod(factoryKeyword);
-    token = token.next; // Skip 'factory'.
-    token = parseConstructorReference(token);
-    token = parseFormalParameters(token);
-    token = parseAsyncModifier(token);
-    if (optional('=', token)) {
-      token = parseRedirectingFactoryBody(token);
-    } else {
-      token = parseFunctionBody(token, false, externalModifier != null);
-    }
-    listener.endFactoryMethod(start, token);
-    return token.next;
-  }
-
-  Token parseOperatorName(Token token) {
-    assert(optional('operator', token));
-    if (isUserDefinableOperator(token.next.stringValue)) {
-      Token operator = token;
-      token = token.next;
-      listener.handleOperatorName(operator, token);
-      return token.next;
-    } else {
-      return parseIdentifier(token);
-    }
-  }
-
-  Token parseFunction(Token token, Token getOrSet) {
-    listener.beginFunction(token);
-    token = parseModifiers(token);
-    if (identical(getOrSet, token)) {
-      // get <name>  => ...
-      token = token.next;
-      listener.handleNoType(token);
-      listener.beginFunctionName(token);
-      if (optional('operator', token)) {
-        token = parseOperatorName(token);
-      } else {
-        token = parseIdentifier(token);
-      }
-    } else if (optional('operator', token)) {
-      // operator <op> (...
-      listener.handleNoType(token);
-      listener.beginFunctionName(token);
-      token = parseOperatorName(token);
-    } else {
-      // <type>? <get>? <name>
-      token = parseReturnTypeOpt(token);
-      if (identical(getOrSet, token)) {
-        token = token.next;
-      }
-      listener.beginFunctionName(token);
-      if (optional('operator', token)) {
-        token = parseOperatorName(token);
-      } else {
-        token = parseIdentifier(token);
-      }
-    }
-    token = parseQualifiedRestOpt(token);
-    listener.endFunctionName(token);
-    if (getOrSet == null) {
-      token = parseTypeVariablesOpt(token);
-    } else {
-      listener.handleNoTypeVariables(token);
-    }
-    token = parseFormalParametersOpt(token);
-    token = parseInitializersOpt(token);
-    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
-    token = parseAsyncModifier(token);
-    if (optional('=', token)) {
-      token = parseRedirectingFactoryBody(token);
-    } else {
-      token = parseFunctionBody(token, false, true);
-    }
-    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
-    listener.endFunction(getOrSet, token);
-    return token.next;
-  }
-
-  Token parseUnnamedFunction(Token token) {
-    listener.beginUnnamedFunction(token);
-    token = parseFormalParameters(token);
-    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
-    token = parseAsyncModifier(token);
-    bool isBlock = optional('{', token);
-    token = parseFunctionBody(token, true, false);
-    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
-    listener.endUnnamedFunction(token);
-    return isBlock ? token.next : token;
-  }
-
-  Token parseFunctionDeclaration(Token token) {
-    listener.beginFunctionDeclaration(token);
-    token = parseFunction(token, null);
-    listener.endFunctionDeclaration(token);
-    return token;
-  }
-
-  Token parseFunctionExpression(Token token) {
-    listener.beginFunction(token);
-    listener.handleModifiers(0);
-    token = parseReturnTypeOpt(token);
-    listener.beginFunctionName(token);
-    token = parseIdentifier(token);
-    listener.endFunctionName(token);
-    token = parseTypeVariablesOpt(token);
-    token = parseFormalParameters(token);
-    listener.handleNoInitializers();
-    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
-    token = parseAsyncModifier(token);
-    bool isBlock = optional('{', token);
-    token = parseFunctionBody(token, true, false);
-    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
-    listener.endFunction(null, token);
-    return isBlock ? token.next : token;
-  }
-
-  Token parseConstructorReference(Token token) {
-    Token start = token;
-    listener.beginConstructorReference(start);
-    token = parseIdentifier(token);
-    token = parseQualifiedRestOpt(token);
-    token = parseTypeArgumentsOpt(token);
-    Token period = null;
-    if (optional('.', token)) {
-      period = token;
-      token = parseIdentifier(token.next);
-    }
-    listener.endConstructorReference(start, period, token);
-    return token;
-  }
-
-  Token parseRedirectingFactoryBody(Token token) {
-    listener.beginRedirectingFactoryBody(token);
-    assert(optional('=', token));
-    Token equals = token;
-    token = parseConstructorReference(token.next);
-    Token semicolon = token;
-    expectSemicolon(token);
-    listener.endRedirectingFactoryBody(equals, semicolon);
-    return token;
-  }
-
-  Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
-    if (optional(';', token)) {
-      if (!allowAbstract) {
-        listener.reportError(token, MessageKind.BODY_EXPECTED);
-      }
-      listener.endFunctionBody(0, null, token);
-      return token;
-    } else if (optional('=>', token)) {
-      Token begin = token;
-      token = parseExpression(token.next);
-      if (!isExpression) {
-        expectSemicolon(token);
-        listener.endReturnStatement(true, begin, token);
-      } else {
-        listener.endReturnStatement(true, begin, null);
-      }
-      return token;
-    }
-    Token begin = token;
-    int statementCount = 0;
-    if (!optional('{', token)) {
-      return listener.expectedFunctionBody(token);
-    }
-
-    listener.beginFunctionBody(begin);
-    token = token.next;
-    while (notEofOrValue('}', token)) {
-      token = parseStatement(token);
-      ++statementCount;
-    }
-    listener.endFunctionBody(statementCount, begin, token);
-    expect('}', token);
-    return token;
-  }
-
-  Token parseAsyncModifier(Token token) {
-    Token async;
-    Token star;
-    asyncAwaitKeywordsEnabled = false;
-    if (optional('async', token)) {
-      asyncAwaitKeywordsEnabled = true;
-      async = token;
-      token = token.next;
-      if (optional('*', token)) {
-        star = token;
-        token = token.next;
-      }
-    } else if (optional('sync', token)) {
-      async = token;
-      token = token.next;
-      if (optional('*', token)) {
-        asyncAwaitKeywordsEnabled = true;
-        star = token;
-        token = token.next;
-      } else {
-        listener.reportError(async, MessageKind.INVALID_SYNC_MODIFIER);
-      }
-    }
-    listener.handleAsyncModifier(async, star);
-    return token;
-  }
-
-  Token parseStatement(Token token) {
-    final value = token.stringValue;
-    if (identical(token.kind, IDENTIFIER_TOKEN)) {
-      return parseExpressionStatementOrDeclaration(token);
-    } else if (identical(value, '{')) {
-      return parseBlock(token);
-    } else if (identical(value, 'return')) {
-      return parseReturnStatement(token);
-    } else if (identical(value, 'var') || identical(value, 'final')) {
-      return parseVariablesDeclaration(token);
-    } else if (identical(value, 'if')) {
-      return parseIfStatement(token);
-    } else if (asyncAwaitKeywordsEnabled && identical(value, 'await')) {
-      if (identical(token.next.stringValue, 'for')) {
-        return parseForStatement(token, token.next);
-      } else {
-        return parseExpressionStatement(token);
-      }
-    } else if (identical(value, 'for')) {
-      return parseForStatement(null, token);
-    } else if (identical(value, 'rethrow')) {
-      return parseRethrowStatement(token);
-    } else if (identical(value, 'throw') && optional(';', token.next)) {
-      // TODO(kasperl): Stop dealing with throw here.
-      return parseRethrowStatement(token);
-    } else if (identical(value, 'void')) {
-      return parseExpressionStatementOrDeclaration(token);
-    } else if (identical(value, 'while')) {
-      return parseWhileStatement(token);
-    } else if (identical(value, 'do')) {
-      return parseDoWhileStatement(token);
-    } else if (identical(value, 'try')) {
-      return parseTryStatement(token);
-    } else if (identical(value, 'switch')) {
-      return parseSwitchStatement(token);
-    } else if (identical(value, 'break')) {
-      return parseBreakStatement(token);
-    } else if (identical(value, 'continue')) {
-      return parseContinueStatement(token);
-    } else if (identical(value, 'assert')) {
-      return parseAssertStatement(token);
-    } else if (identical(value, ';')) {
-      return parseEmptyStatement(token);
-    } else if (asyncAwaitKeywordsEnabled && identical(value, 'yield')) {
-      return parseYieldStatement(token);
-    } else if (identical(value, 'const')) {
-      return parseExpressionStatementOrConstDeclaration(token);
-    } else if (token.isIdentifier()) {
-      return parseExpressionStatementOrDeclaration(token);
-    } else {
-      return parseExpressionStatement(token);
-    }
-  }
-
-  Token parseYieldStatement(Token token) {
-    Token begin = token;
-    listener.beginYieldStatement(begin);
-    assert(identical('yield', token.stringValue));
-    token = token.next;
-    Token starToken;
-    if (optional('*', token)) {
-      starToken = token;
-      token = token.next;
-    }
-    token = parseExpression(token);
-    listener.endYieldStatement(begin, starToken, token);
-    return expectSemicolon(token);
-  }
-
-  Token parseReturnStatement(Token token) {
-    Token begin = token;
-    listener.beginReturnStatement(begin);
-    assert(identical('return', token.stringValue));
-    token = token.next;
-    if (optional(';', token)) {
-      listener.endReturnStatement(false, begin, token);
-    } else {
-      token = parseExpression(token);
-      listener.endReturnStatement(true, begin, token);
-    }
-    return expectSemicolon(token);
-  }
-
-  Token peekIdentifierAfterType(Token token) {
-    Token peek = peekAfterType(token);
-    if (peek != null && peek.isIdentifier()) {
-      // We are looking at "type identifier".
-      return peek;
-    } else {
-      return null;
-    }
-  }
-
-  Token peekIdentifierAfterOptionalType(Token token) {
-    Token peek = peekAfterIfType(token);
-    if (peek != null && peek.isIdentifier()) {
-      // We are looking at "type identifier".
-      return peek;
-    } else if (token.isIdentifier()) {
-      // We are looking at "identifier".
-      return token;
-    } else {
-      return null;
-    }
-  }
-
-  Token parseExpressionStatementOrDeclaration(Token token) {
-    assert(token.isIdentifier() || identical(token.stringValue, 'void'));
-    Token identifier = peekIdentifierAfterType(token);
-    if (identifier != null) {
-      assert(identifier.isIdentifier());
-      Token afterId = identifier.next;
-      int afterIdKind = afterId.kind;
-      if (identical(afterIdKind, EQ_TOKEN) ||
-          identical(afterIdKind, SEMICOLON_TOKEN) ||
-          identical(afterIdKind, COMMA_TOKEN)) {
-        // We are looking at "type identifier" followed by '=', ';', ','.
-        return parseVariablesDeclaration(token);
-      } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) {
-        // We are looking at "type identifier '('".
-        BeginGroupToken beginParen = afterId;
-        Token endParen = beginParen.endGroup;
-        // TODO(eernst): Check for NPE as described in issue 26252.
-        Token afterParens = endParen.next;
-        if (optional('{', afterParens) ||
-            optional('=>', afterParens) ||
-            optional('async', afterParens) ||
-            optional('sync', afterParens)) {
-          // We are looking at "type identifier '(' ... ')'" followed
-          // by '{', '=>', 'async', or 'sync'.
-          return parseFunctionDeclaration(token);
-        }
-      } else if (identical(afterIdKind, LT_TOKEN)) {
-        // We are looking at "type identifier '<'".
-        BeginGroupToken beginAngle = afterId;
-        Token endAngle = beginAngle.endGroup;
-        if (endAngle != null &&
-            identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
-          BeginGroupToken beginParen = endAngle.next;
-          Token endParen = beginParen.endGroup;
-          if (endParen != null) {
-            Token afterParens = endParen.next;
-            if (optional('{', afterParens) ||
-                optional('=>', afterParens) ||
-                optional('async', afterParens) ||
-                optional('sync', afterParens)) {
-              // We are looking at "type identifier '<' ... '>' '(' ... ')'"
-              // followed by '{', '=>', 'async', or 'sync'.
-              return parseFunctionDeclaration(token);
-            }
-          }
-        }
-      }
-      // Fall-through to expression statement.
-    } else {
-      if (optional(':', token.next)) {
-        return parseLabeledStatement(token);
-      } else if (optional('(', token.next)) {
-        BeginGroupToken begin = token.next;
-        // TODO(eernst): Check for NPE as described in issue 26252.
-        String afterParens = begin.endGroup.next.stringValue;
-        if (identical(afterParens, '{') ||
-            identical(afterParens, '=>') ||
-            identical(afterParens, 'async') ||
-            identical(afterParens, 'sync')) {
-          return parseFunctionDeclaration(token);
-        }
-      } else if (optional('<', token.next)) {
-        BeginGroupToken beginAngle = token.next;
-        Token endAngle = beginAngle.endGroup;
-        if (endAngle != null &&
-            identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
-          BeginGroupToken beginParen = endAngle.next;
-          Token endParen = beginParen.endGroup;
-          if (endParen != null) {
-            String afterParens = endParen.next.stringValue;
-            if (identical(afterParens, '{') ||
-                identical(afterParens, '=>') ||
-                identical(afterParens, 'async') ||
-                identical(afterParens, 'sync')) {
-              return parseFunctionDeclaration(token);
-            }
-          }
-        }
-        // Fall through to expression statement.
-      }
-    }
-    return parseExpressionStatement(token);
-  }
-
-  Token parseExpressionStatementOrConstDeclaration(Token token) {
-    assert(identical(token.stringValue, 'const'));
-    if (isModifier(token.next)) {
-      return parseVariablesDeclaration(token);
-    }
-    Token identifier = peekIdentifierAfterOptionalType(token.next);
-    if (identifier != null) {
-      assert(identifier.isIdentifier());
-      Token afterId = identifier.next;
-      int afterIdKind = afterId.kind;
-      if (identical(afterIdKind, EQ_TOKEN) ||
-          identical(afterIdKind, SEMICOLON_TOKEN) ||
-          identical(afterIdKind, COMMA_TOKEN)) {
-        // We are looking at "const type identifier" followed by '=', ';', or
-        // ','.
-        return parseVariablesDeclaration(token);
-      }
-      // Fall-through to expression statement.
-    }
-
-    return parseExpressionStatement(token);
-  }
-
-  Token parseLabel(Token token) {
-    token = parseIdentifier(token);
-    Token colon = token;
-    token = expect(':', token);
-    listener.handleLabel(colon);
-    return token;
-  }
-
-  Token parseLabeledStatement(Token token) {
-    int labelCount = 0;
-    do {
-      token = parseLabel(token);
-      labelCount++;
-    } while (token.isIdentifier() && optional(':', token.next));
-    listener.beginLabeledStatement(token, labelCount);
-    token = parseStatement(token);
-    listener.endLabeledStatement(labelCount);
-    return token;
-  }
-
-  Token parseExpressionStatement(Token token) {
-    listener.beginExpressionStatement(token);
-    token = parseExpression(token);
-    listener.endExpressionStatement(token);
-    return expectSemicolon(token);
-  }
-
-  Token parseExpression(Token token) {
-    return optional('throw', token)
-        ? parseThrowExpression(token, true)
-        : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true);
-  }
-
-  Token parseExpressionWithoutCascade(Token token) {
-    return optional('throw', token)
-        ? parseThrowExpression(token, false)
-        : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false);
-  }
-
-  Token parseConditionalExpressionRest(Token token) {
-    assert(optional('?', token));
-    Token question = token;
-    token = parseExpressionWithoutCascade(token.next);
-    Token colon = token;
-    token = expect(':', token);
-    token = parseExpressionWithoutCascade(token);
-    listener.handleConditionalExpression(question, colon);
-    return token;
-  }
-
-  Token parsePrecedenceExpression(
-      Token token, int precedence, bool allowCascades) {
-    assert(precedence >= 1);
-    assert(precedence <= POSTFIX_PRECEDENCE);
-    token = parseUnaryExpression(token, allowCascades);
-    PrecedenceInfo info = token.info;
-    int tokenLevel = info.precedence;
-    for (int level = tokenLevel; level >= precedence; --level) {
-      while (identical(tokenLevel, level)) {
-        Token operator = token;
-        if (identical(tokenLevel, CASCADE_PRECEDENCE)) {
-          if (!allowCascades) {
-            return token;
-          }
-          token = parseCascadeExpression(token);
-        } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) {
-          // Right associative, so we recurse at the same precedence
-          // level.
-          token = parsePrecedenceExpression(token.next, level, allowCascades);
-          listener.handleAssignmentExpression(operator);
-        } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
-          if (identical(info, PERIOD_INFO) ||
-              identical(info, QUESTION_PERIOD_INFO)) {
-            // Left associative, so we recurse at the next higher
-            // precedence level. However, POSTFIX_PRECEDENCE is the
-            // highest level, so we just call parseUnaryExpression
-            // directly.
-            token = parseUnaryExpression(token.next, allowCascades);
-            listener.handleBinaryExpression(operator);
-          } else if ((identical(info, OPEN_PAREN_INFO)) ||
-              (identical(info, OPEN_SQUARE_BRACKET_INFO))) {
-            token = parseArgumentOrIndexStar(token);
-          } else if ((identical(info, PLUS_PLUS_INFO)) ||
-              (identical(info, MINUS_MINUS_INFO))) {
-            listener.handleUnaryPostfixAssignmentExpression(token);
-            token = token.next;
-          } else {
-            token = listener.unexpected(token);
-          }
-        } else if (identical(info, IS_INFO)) {
-          token = parseIsOperatorRest(token);
-        } else if (identical(info, AS_INFO)) {
-          token = parseAsOperatorRest(token);
-        } else if (identical(info, QUESTION_INFO)) {
-          token = parseConditionalExpressionRest(token);
-        } else {
-          // Left associative, so we recurse at the next higher
-          // precedence level.
-          token =
-              parsePrecedenceExpression(token.next, level + 1, allowCascades);
-          listener.handleBinaryExpression(operator);
-        }
-        info = token.info;
-        tokenLevel = info.precedence;
-        if (level == EQUALITY_PRECEDENCE || level == RELATIONAL_PRECEDENCE) {
-          // We don't allow (a == b == c) or (a < b < c).
-          // Continue the outer loop if we have matched one equality or
-          // relational operator.
-          break;
-        }
-      }
-    }
-    return token;
-  }
-
-  Token parseCascadeExpression(Token token) {
-    listener.beginCascade(token);
-    assert(optional('..', token));
-    Token cascadeOperator = token;
-    token = token.next;
-    if (optional('[', token)) {
-      token = parseArgumentOrIndexStar(token);
-    } else if (token.isIdentifier()) {
-      token = parseSend(token);
-      listener.handleBinaryExpression(cascadeOperator);
-    } else {
-      return listener.unexpected(token);
-    }
-    Token mark;
-    do {
-      mark = token;
-      if (optional('.', token)) {
-        Token period = token;
-        token = parseSend(token.next);
-        listener.handleBinaryExpression(period);
-      }
-      token = parseArgumentOrIndexStar(token);
-    } while (!identical(mark, token));
-
-    if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) {
-      Token assignment = token;
-      token = parseExpressionWithoutCascade(token.next);
-      listener.handleAssignmentExpression(assignment);
-    }
-    listener.endCascade();
-    return token;
-  }
-
-  Token parseUnaryExpression(Token token, bool allowCascades) {
-    String value = token.stringValue;
-    // Prefix:
-    if (asyncAwaitKeywordsEnabled && optional('await', token)) {
-      return parseAwaitExpression(token, allowCascades);
-    } else if (identical(value, '+')) {
-      // Dart no longer allows prefix-plus.
-      listener.reportError(token, MessageKind.UNSUPPORTED_PREFIX_PLUS);
-      return parseUnaryExpression(token.next, allowCascades);
-    } else if ((identical(value, '!')) ||
-        (identical(value, '-')) ||
-        (identical(value, '~'))) {
-      Token operator = token;
-      // Right associative, so we recurse at the same precedence
-      // level.
-      token = parsePrecedenceExpression(
-          token.next, POSTFIX_PRECEDENCE, allowCascades);
-      listener.handleUnaryPrefixExpression(operator);
-    } else if ((identical(value, '++')) || identical(value, '--')) {
-      // TODO(ahe): Validate this is used correctly.
-      Token operator = token;
-      // Right associative, so we recurse at the same precedence
-      // level.
-      token = parsePrecedenceExpression(
-          token.next, POSTFIX_PRECEDENCE, allowCascades);
-      listener.handleUnaryPrefixAssignmentExpression(operator);
-    } else {
-      token = parsePrimary(token);
-    }
-    return token;
-  }
-
-  Token parseArgumentOrIndexStar(Token token) {
-    while (true) {
-      if (optional('[', token)) {
-        Token openSquareBracket = token;
-        bool old = mayParseFunctionExpressions;
-        mayParseFunctionExpressions = true;
-        token = parseExpression(token.next);
-        mayParseFunctionExpressions = old;
-        listener.handleIndexedExpression(openSquareBracket, token);
-        token = expect(']', token);
-      } else if (optional('(', token)) {
-        listener.handleNoTypeArguments(token);
-        token = parseArguments(token);
-        listener.endSend(token);
-      } else {
-        break;
-      }
-    }
-    return token;
-  }
-
-  Token parsePrimary(Token token) {
-    final kind = token.kind;
-    if (kind == IDENTIFIER_TOKEN) {
-      return parseSendOrFunctionLiteral(token);
-    } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) {
-      return parseLiteralInt(token);
-    } else if (kind == DOUBLE_TOKEN) {
-      return parseLiteralDouble(token);
-    } else if (kind == STRING_TOKEN) {
-      return parseLiteralString(token);
-    } else if (kind == HASH_TOKEN) {
-      return parseLiteralSymbol(token);
-    } else if (kind == KEYWORD_TOKEN) {
-      final value = token.stringValue;
-      if (value == 'true' || value == 'false') {
-        return parseLiteralBool(token);
-      } else if (value == 'null') {
-        return parseLiteralNull(token);
-      } else if (value == 'this') {
-        return parseThisExpression(token);
-      } else if (value == 'super') {
-        return parseSuperExpression(token);
-      } else if (value == 'new') {
-        return parseNewExpression(token);
-      } else if (value == 'const') {
-        return parseConstExpression(token);
-      } else if (value == 'void') {
-        return parseFunctionExpression(token);
-      } else if (asyncAwaitKeywordsEnabled &&
-          (value == 'yield' || value == 'async')) {
-        return listener.expectedExpression(token);
-      } else if (token.isIdentifier()) {
-        return parseSendOrFunctionLiteral(token);
-      } else {
-        return listener.expectedExpression(token);
-      }
-    } else if (kind == OPEN_PAREN_TOKEN) {
-      return parseParenthesizedExpressionOrFunctionLiteral(token);
-    } else if (kind == OPEN_SQUARE_BRACKET_TOKEN || token.stringValue == '[]') {
-      listener.handleNoTypeArguments(token);
-      return parseLiteralListSuffix(token, null);
-    } else if (kind == OPEN_CURLY_BRACKET_TOKEN) {
-      listener.handleNoTypeArguments(token);
-      return parseLiteralMapSuffix(token, null);
-    } else if (kind == LT_TOKEN) {
-      return parseLiteralListOrMapOrFunction(token, null);
-    } else {
-      return listener.expectedExpression(token);
-    }
-  }
-
-  Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
-    BeginGroupToken beginGroup = token;
-    // TODO(eernst): Check for NPE as described in issue 26252.
-    Token nextToken = beginGroup.endGroup.next;
-    int kind = nextToken.kind;
-    if (mayParseFunctionExpressions &&
-        (identical(kind, FUNCTION_TOKEN) ||
-            identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
-            (identical(kind, KEYWORD_TOKEN) &&
-                (nextToken.value == 'async' || nextToken.value == 'sync')))) {
-      listener.handleNoTypeVariables(token);
-      return parseUnnamedFunction(token);
-    } else {
-      bool old = mayParseFunctionExpressions;
-      mayParseFunctionExpressions = true;
-      token = parseParenthesizedExpression(token);
-      mayParseFunctionExpressions = old;
-      return token;
-    }
-  }
-
-  Token parseParenthesizedExpression(Token token) {
-    // We expect [begin] to be of type [BeginGroupToken], but we don't know for
-    // sure until after calling expect.
-    var begin = token;
-    token = expect('(', token);
-    // [begin] is now known to have type [BeginGroupToken].
-    token = parseExpression(token);
-    if (!identical(begin.endGroup, token)) {
-      listener.unexpected(token);
-      token = begin.endGroup;
-    }
-    listener.handleParenthesizedExpression(begin);
-    return expect(')', token);
-  }
-
-  Token parseThisExpression(Token token) {
-    listener.handleThisExpression(token);
-    token = token.next;
-    if (optional('(', token)) {
-      // Constructor forwarding.
-      listener.handleNoTypeArguments(token);
-      token = parseArguments(token);
-      listener.endSend(token);
-    }
-    return token;
-  }
-
-  Token parseSuperExpression(Token token) {
-    listener.handleSuperExpression(token);
-    token = token.next;
-    if (optional('(', token)) {
-      // Super constructor.
-      listener.handleNoTypeArguments(token);
-      token = parseArguments(token);
-      listener.endSend(token);
-    }
-    return token;
-  }
-
-  /// '[' (expressionList ','?)? ']'.
-  ///
-  /// Provide [constKeyword] if preceded by 'const', null if not.
-  /// This is a suffix parser because it is assumed that type arguments have
-  /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
-  Token parseLiteralListSuffix(Token token, Token constKeyword) {
-    assert(optional('[', token) || optional('[]', token));
-    Token beginToken = token;
-    int count = 0;
-    if (optional('[', token)) {
-      bool old = mayParseFunctionExpressions;
-      mayParseFunctionExpressions = true;
-      do {
-        if (optional(']', token.next)) {
-          token = token.next;
-          break;
-        }
-        token = parseExpression(token.next);
-        ++count;
-      } while (optional(',', token));
-      mayParseFunctionExpressions = old;
-      listener.handleLiteralList(count, beginToken, constKeyword, token);
-      return expect(']', token);
-    }
-    // Looking at '[]'.
-    listener.handleLiteralList(0, token, constKeyword, token);
-    return token.next;
-  }
-
-  /// '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'.
-  ///
-  /// Provide token for [constKeyword] if preceded by 'const', null if not.
-  /// This is a suffix parser because it is assumed that type arguments have
-  /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
-  Token parseLiteralMapSuffix(Token token, Token constKeyword) {
-    assert(optional('{', token));
-    Token beginToken = token;
-    int count = 0;
-    bool old = mayParseFunctionExpressions;
-    mayParseFunctionExpressions = true;
-    do {
-      if (optional('}', token.next)) {
-        token = token.next;
-        break;
-      }
-      token = parseMapLiteralEntry(token.next);
-      ++count;
-    } while (optional(',', token));
-    mayParseFunctionExpressions = old;
-    listener.handleLiteralMap(count, beginToken, constKeyword, token);
-    return expect('}', token);
-  }
-
-  /// formalParameterList functionBody.
-  ///
-  /// This is a suffix parser because it is assumed that type arguments have
-  /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
-  Token parseLiteralFunctionSuffix(Token token) {
-    assert(optional('(', token));
-    BeginGroupToken beginGroup = token;
-    if (beginGroup.endGroup != null) {
-      Token nextToken = beginGroup.endGroup.next;
-      int kind = nextToken.kind;
-      if (identical(kind, FUNCTION_TOKEN) ||
-          identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
-          (identical(kind, KEYWORD_TOKEN) &&
-              (nextToken.value == 'async' || nextToken.value == 'sync'))) {
-        return parseUnnamedFunction(token);
-      }
-      // Fall through.
-    }
-    listener.unexpected(token);
-    return null;
-  }
-
-  /// genericListLiteral | genericMapLiteral | genericFunctionLiteral.
-  ///
-  /// Where
-  ///   genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']'
-  ///   genericMapLiteral ::=
-  ///       typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
-  ///   genericFunctionLiteral ::=
-  ///       typeParameters formalParameterList functionBody
-  /// Provide token for [constKeyword] if preceded by 'const', null if not.
-  Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) {
-    assert(optional('<', token));
-    BeginGroupToken begin = token;
-    if (constKeyword == null &&
-        begin.endGroup != null &&
-        identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) {
-      token = parseTypeVariablesOpt(token);
-      return parseLiteralFunctionSuffix(token);
-    } else {
-      token = parseTypeArgumentsOpt(token);
-      if (optional('{', token)) {
-        return parseLiteralMapSuffix(token, constKeyword);
-      } else if ((optional('[', token)) || (optional('[]', token))) {
-        return parseLiteralListSuffix(token, constKeyword);
-      }
-      listener.unexpected(token);
-      return null;
-    }
-  }
-
-  Token parseMapLiteralEntry(Token token) {
-    listener.beginLiteralMapEntry(token);
-    // Assume the listener rejects non-string keys.
-    token = parseExpression(token);
-    Token colon = token;
-    token = expect(':', token);
-    token = parseExpression(token);
-    listener.endLiteralMapEntry(colon, token);
-    return token;
-  }
-
-  Token parseSendOrFunctionLiteral(Token token) {
-    if (!mayParseFunctionExpressions) return parseSend(token);
-    Token peek = peekAfterIfType(token);
-    if (peek != null &&
-        identical(peek.kind, IDENTIFIER_TOKEN) &&
-        isFunctionDeclaration(peek.next)) {
-      return parseFunctionExpression(token);
-    } else if (isFunctionDeclaration(token.next)) {
-      return parseFunctionExpression(token);
-    } else {
-      return parseSend(token);
-    }
-  }
-
-  bool isFunctionDeclaration(Token token) {
-    if (optional('<', token)) {
-      BeginGroupToken begin = token;
-      if (begin.endGroup == null) return false;
-      token = begin.endGroup.next;
-    }
-    if (optional('(', token)) {
-      BeginGroupToken begin = token;
-      // TODO(eernst): Check for NPE as described in issue 26252.
-      String afterParens = begin.endGroup.next.stringValue;
-      if (identical(afterParens, '{') ||
-          identical(afterParens, '=>') ||
-          identical(afterParens, 'async') ||
-          identical(afterParens, 'sync')) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  Token parseRequiredArguments(Token token) {
-    if (optional('(', token)) {
-      token = parseArguments(token);
-    } else {
-      listener.handleNoArguments(token);
-      token = listener.unexpected(token);
-    }
-    return token;
-  }
-
-  Token parseNewExpression(Token token) {
-    Token newKeyword = token;
-    token = expect('new', token);
-    token = parseConstructorReference(token);
-    token = parseRequiredArguments(token);
-    listener.handleNewExpression(newKeyword);
-    return token;
-  }
-
-  Token parseConstExpression(Token token) {
-    Token constKeyword = token;
-    token = expect('const', token);
-    final String value = token.stringValue;
-    if ((identical(value, '[')) || (identical(value, '[]'))) {
-      listener.handleNoTypeArguments(token);
-      return parseLiteralListSuffix(token, constKeyword);
-    }
-    if (identical(value, '{')) {
-      listener.handleNoTypeArguments(token);
-      return parseLiteralMapSuffix(token, constKeyword);
-    }
-    if (identical(value, '<')) {
-      return parseLiteralListOrMapOrFunction(token, constKeyword);
-    }
-    token = parseConstructorReference(token);
-    token = parseRequiredArguments(token);
-    listener.handleConstExpression(constKeyword);
-    return token;
-  }
-
-  Token parseLiteralInt(Token token) {
-    listener.handleLiteralInt(token);
-    return token.next;
-  }
-
-  Token parseLiteralDouble(Token token) {
-    listener.handleLiteralDouble(token);
-    return token.next;
-  }
-
-  Token parseLiteralString(Token token) {
-    bool old = mayParseFunctionExpressions;
-    mayParseFunctionExpressions = true;
-    token = parseSingleLiteralString(token);
-    int count = 1;
-    while (identical(token.kind, STRING_TOKEN)) {
-      token = parseSingleLiteralString(token);
-      count++;
-    }
-    if (count > 1) {
-      listener.handleStringJuxtaposition(count);
-    }
-    mayParseFunctionExpressions = old;
-    return token;
-  }
-
-  Token parseLiteralSymbol(Token token) {
-    Token hashToken = token;
-    listener.beginLiteralSymbol(hashToken);
-    token = token.next;
-    if (isUserDefinableOperator(token.stringValue)) {
-      listener.handleOperator(token);
-      listener.endLiteralSymbol(hashToken, 1);
-      return token.next;
-    } else {
-      int count = 1;
-      token = parseIdentifier(token);
-      while (identical(token.stringValue, '.')) {
-        count++;
-        token = parseIdentifier(token.next);
-      }
-      listener.endLiteralSymbol(hashToken, count);
-      return token;
-    }
-  }
-
-  /**
-   * Only called when [:token.kind === STRING_TOKEN:].
-   */
-  Token parseSingleLiteralString(Token token) {
-    listener.beginLiteralString(token);
-    // Parsing the prefix, for instance 'x of 'x${id}y${id}z'
-    token = token.next;
-    int interpolationCount = 0;
-    var kind = token.kind;
-    while (kind != EOF_TOKEN) {
-      if (identical(kind, STRING_INTERPOLATION_TOKEN)) {
-        // Parsing ${expression}.
-        token = token.next;
-        token = parseExpression(token);
-        token = expect('}', token);
-      } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) {
-        // Parsing $identifier.
-        token = token.next;
-        token = parseExpression(token);
-      } else {
-        break;
-      }
-      ++interpolationCount;
-      // Parsing the infix/suffix, for instance y and z' of 'x${id}y${id}z'
-      token = parseStringPart(token);
-      kind = token.kind;
-    }
-    listener.endLiteralString(interpolationCount);
-    return token;
-  }
-
-  Token parseLiteralBool(Token token) {
-    listener.handleLiteralBool(token);
-    return token.next;
-  }
-
-  Token parseLiteralNull(Token token) {
-    listener.handleLiteralNull(token);
-    return token.next;
-  }
-
-  Token parseSend(Token token) {
-    listener.beginSend(token);
-    token = parseIdentifier(token);
-    if (isValidMethodTypeArguments(token)) {
-      token = parseTypeArgumentsOpt(token);
-    } else {
-      listener.handleNoTypeArguments(token);
-    }
-    token = parseArgumentsOpt(token);
-    listener.endSend(token);
-    return token;
-  }
-
-  Token parseArgumentsOpt(Token token) {
-    if (!optional('(', token)) {
-      listener.handleNoArguments(token);
-      return token;
-    } else {
-      return parseArguments(token);
-    }
-  }
-
-  Token parseArguments(Token token) {
-    Token begin = token;
-    listener.beginArguments(begin);
-    assert(identical('(', token.stringValue));
-    int argumentCount = 0;
-    if (optional(')', token.next)) {
-      listener.endArguments(argumentCount, begin, token.next);
-      return token.next.next;
-    }
-    bool old = mayParseFunctionExpressions;
-    mayParseFunctionExpressions = true;
-    do {
-      if (optional(')', token.next)) {
-        token = token.next;
-        break;
-      }
-      Token colon = null;
-      if (optional(':', token.next.next)) {
-        token = parseIdentifier(token.next);
-        colon = token;
-      }
-      token = parseExpression(token.next);
-      if (colon != null) listener.handleNamedArgument(colon);
-      ++argumentCount;
-    } while (optional(',', token));
-    mayParseFunctionExpressions = old;
-    listener.endArguments(argumentCount, begin, token);
-    return expect(')', token);
-  }
-
-  Token parseIsOperatorRest(Token token) {
-    assert(optional('is', token));
-    Token operator = token;
-    Token not = null;
-    if (optional('!', token.next)) {
-      token = token.next;
-      not = token;
-    }
-    token = parseType(token.next);
-    listener.handleIsOperator(operator, not, token);
-    String value = token.stringValue;
-    if (identical(value, 'is') || identical(value, 'as')) {
-      // The is- and as-operators cannot be chained, but they can take part of
-      // expressions like: foo is Foo || foo is Bar.
-      listener.unexpected(token);
-    }
-    return token;
-  }
-
-  Token parseAsOperatorRest(Token token) {
-    assert(optional('as', token));
-    Token operator = token;
-    token = parseType(token.next);
-    listener.handleAsOperator(operator, token);
-    String value = token.stringValue;
-    if (identical(value, 'is') || identical(value, 'as')) {
-      // The is- and as-operators cannot be chained.
-      listener.unexpected(token);
-    }
-    return token;
-  }
-
-  Token parseVariablesDeclaration(Token token) {
-    return parseVariablesDeclarationMaybeSemicolon(token, true);
-  }
-
-  Token parseVariablesDeclarationNoSemicolon(Token token) {
-    // Only called when parsing a for loop, so this is for parsing locals.
-    return parseVariablesDeclarationMaybeSemicolon(token, false);
-  }
-
-  Token parseVariablesDeclarationMaybeSemicolon(
-      Token token, bool endWithSemicolon) {
-    int count = 1;
-    listener.beginVariablesDeclaration(token);
-    token = parseModifiers(token);
-    token = parseTypeOpt(token);
-    token = parseOptionallyInitializedIdentifier(token);
-    while (optional(',', token)) {
-      token = parseOptionallyInitializedIdentifier(token.next);
-      ++count;
-    }
-    if (endWithSemicolon) {
-      Token semicolon = token;
-      token = expectSemicolon(semicolon);
-      listener.endVariablesDeclaration(count, semicolon);
-      return token;
-    } else {
-      listener.endVariablesDeclaration(count, null);
-      return token;
-    }
-  }
-
-  Token parseOptionallyInitializedIdentifier(Token token) {
-    listener.beginInitializedIdentifier(token);
-    token = parseIdentifier(token);
-    token = parseVariableInitializerOpt(token);
-    listener.endInitializedIdentifier();
-    return token;
-  }
-
-  Token parseIfStatement(Token token) {
-    Token ifToken = token;
-    listener.beginIfStatement(ifToken);
-    token = expect('if', token);
-    token = parseParenthesizedExpression(token);
-    token = parseStatement(token);
-    Token elseToken = null;
-    if (optional('else', token)) {
-      elseToken = token;
-      token = parseStatement(token.next);
-    }
-    listener.endIfStatement(ifToken, elseToken);
-    return token;
-  }
-
-  Token parseForStatement(Token awaitToken, Token token) {
-    Token forToken = token;
-    listener.beginForStatement(forToken);
-    token = expect('for', token);
-    token = expect('(', token);
-    token = parseVariablesDeclarationOrExpressionOpt(token);
-    if (optional('in', token)) {
-      return parseForInRest(awaitToken, forToken, token);
-    } else {
-      if (awaitToken != null) {
-        listener.reportError(awaitToken, MessageKind.INVALID_AWAIT_FOR);
-      }
-      return parseForRest(forToken, token);
-    }
-  }
-
-  Token parseVariablesDeclarationOrExpressionOpt(Token token) {
-    final String value = token.stringValue;
-    if (identical(value, ';')) {
-      listener.handleNoExpression(token);
-      return token;
-    } else if (isOneOf3(token, 'var', 'final', 'const')) {
-      return parseVariablesDeclarationNoSemicolon(token);
-    }
-    Token identifier = peekIdentifierAfterType(token);
-    if (identifier != null) {
-      assert(identifier.isIdentifier());
-      if (isOneOf4(identifier.next, '=', ';', ',', 'in')) {
-        return parseVariablesDeclarationNoSemicolon(token);
-      }
-    }
-    return parseExpression(token);
-  }
-
-  Token parseForRest(Token forToken, Token token) {
-    token = expectSemicolon(token);
-    if (optional(';', token)) {
-      token = parseEmptyStatement(token);
-    } else {
-      token = parseExpressionStatement(token);
-    }
-    int expressionCount = 0;
-    while (true) {
-      if (optional(')', token)) break;
-      token = parseExpression(token);
-      ++expressionCount;
-      if (optional(',', token)) {
-        token = token.next;
-      } else {
-        break;
-      }
-    }
-    token = expect(')', token);
-    token = parseStatement(token);
-    listener.endForStatement(expressionCount, forToken, token);
-    return token;
-  }
-
-  Token parseForInRest(Token awaitToken, Token forToken, Token token) {
-    assert(optional('in', token));
-    Token inKeyword = token;
-    token = parseExpression(token.next);
-    token = expect(')', token);
-    token = parseStatement(token);
-    listener.endForIn(awaitToken, forToken, inKeyword, token);
-    return token;
-  }
-
-  Token parseWhileStatement(Token token) {
-    Token whileToken = token;
-    listener.beginWhileStatement(whileToken);
-    token = expect('while', token);
-    token = parseParenthesizedExpression(token);
-    token = parseStatement(token);
-    listener.endWhileStatement(whileToken, token);
-    return token;
-  }
-
-  Token parseDoWhileStatement(Token token) {
-    Token doToken = token;
-    listener.beginDoWhileStatement(doToken);
-    token = expect('do', token);
-    token = parseStatement(token);
-    Token whileToken = token;
-    token = expect('while', token);
-    token = parseParenthesizedExpression(token);
-    listener.endDoWhileStatement(doToken, whileToken, token);
-    return expectSemicolon(token);
-  }
-
-  Token parseBlock(Token token) {
-    Token begin = token;
-    listener.beginBlock(begin);
-    int statementCount = 0;
-    token = expect('{', token);
-    while (notEofOrValue('}', token)) {
-      token = parseStatement(token);
-      ++statementCount;
-    }
-    listener.endBlock(statementCount, begin, token);
-    return expect('}', token);
-  }
-
-  Token parseAwaitExpression(Token token, bool allowCascades) {
-    Token awaitToken = token;
-    listener.beginAwaitExpression(awaitToken);
-    token = expect('await', token);
-    token = parsePrecedenceExpression(token, POSTFIX_PRECEDENCE, allowCascades);
-    listener.endAwaitExpression(awaitToken, token);
-    return token;
-  }
-
-  Token parseThrowExpression(Token token, bool allowCascades) {
-    Token throwToken = token;
-    listener.beginThrowExpression(throwToken);
-    token = expect('throw', token);
-    token = allowCascades
-        ? parseExpression(token)
-        : parseExpressionWithoutCascade(token);
-    listener.endThrowExpression(throwToken, token);
-    return token;
-  }
-
-  Token parseRethrowStatement(Token token) {
-    Token throwToken = token;
-    listener.beginRethrowStatement(throwToken);
-    // TODO(kasperl): Disallow throw here.
-    if (identical(throwToken.stringValue, 'throw')) {
-      token = expect('throw', token);
-    } else {
-      token = expect('rethrow', token);
-    }
-    listener.endRethrowStatement(throwToken, token);
-    return expectSemicolon(token);
-  }
-
-  Token parseTryStatement(Token token) {
-    assert(optional('try', token));
-    Token tryKeyword = token;
-    listener.beginTryStatement(tryKeyword);
-    token = parseBlock(token.next);
-    int catchCount = 0;
-
-    String value = token.stringValue;
-    while (identical(value, 'catch') || identical(value, 'on')) {
-      var onKeyword = null;
-      if (identical(value, 'on')) {
-        // on qualified catchPart?
-        onKeyword = token;
-        token = parseType(token.next);
-        value = token.stringValue;
-      }
-      Token catchKeyword = null;
-      if (identical(value, 'catch')) {
-        catchKeyword = token;
-        // TODO(ahe): Validate the "parameters".
-        token = parseFormalParameters(token.next);
-      }
-      token = parseBlock(token);
-      ++catchCount;
-      listener.handleCatchBlock(onKeyword, catchKeyword);
-      value = token.stringValue; // while condition
-    }
-
-    Token finallyKeyword = null;
-    if (optional('finally', token)) {
-      finallyKeyword = token;
-      token = parseBlock(token.next);
-      listener.handleFinallyBlock(finallyKeyword);
-    }
-    listener.endTryStatement(catchCount, tryKeyword, finallyKeyword);
-    return token;
-  }
-
-  Token parseSwitchStatement(Token token) {
-    assert(optional('switch', token));
-    Token switchKeyword = token;
-    listener.beginSwitchStatement(switchKeyword);
-    token = parseParenthesizedExpression(token.next);
-    token = parseSwitchBlock(token);
-    listener.endSwitchStatement(switchKeyword, token);
-    return token.next;
-  }
-
-  Token parseSwitchBlock(Token token) {
-    Token begin = token;
-    listener.beginSwitchBlock(begin);
-    token = expect('{', token);
-    int caseCount = 0;
-    while (!identical(token.kind, EOF_TOKEN)) {
-      if (optional('}', token)) {
-        break;
-      }
-      token = parseSwitchCase(token);
-      ++caseCount;
-    }
-    listener.endSwitchBlock(caseCount, begin, token);
-    expect('}', token);
-    return token;
-  }
-
-  /**
-   * Peek after the following labels (if any). The following token
-   * is used to determine if the labels belong to a statement or a
-   * switch case.
-   */
-  Token peekPastLabels(Token token) {
-    while (token.isIdentifier() && optional(':', token.next)) {
-      token = token.next.next;
-    }
-    return token;
-  }
-
-  /**
-   * Parse a group of labels, cases and possibly a default keyword and
-   * the statements that they select.
-   */
-  Token parseSwitchCase(Token token) {
-    Token begin = token;
-    Token defaultKeyword = null;
-    int expressionCount = 0;
-    int labelCount = 0;
-    Token peek = peekPastLabels(token);
-    while (true) {
-      // Loop until we find something that can't be part of a switch case.
-      String value = peek.stringValue;
-      if (identical(value, 'default')) {
-        while (!identical(token, peek)) {
-          token = parseLabel(token);
-          labelCount++;
-        }
-        defaultKeyword = token;
-        token = expect(':', token.next);
-        peek = token;
-        break;
-      } else if (identical(value, 'case')) {
-        while (!identical(token, peek)) {
-          token = parseLabel(token);
-          labelCount++;
-        }
-        Token caseKeyword = token;
-        token = parseExpression(token.next);
-        Token colonToken = token;
-        token = expect(':', token);
-        listener.handleCaseMatch(caseKeyword, colonToken);
-        expressionCount++;
-        peek = peekPastLabels(token);
-      } else {
-        if (expressionCount == 0) {
-          listener.expected("case", token);
-        }
-        break;
-      }
-    }
-    // Finally zero or more statements.
-    int statementCount = 0;
-    while (!identical(token.kind, EOF_TOKEN)) {
-      String value = peek.stringValue;
-      if ((identical(value, 'case')) ||
-          (identical(value, 'default')) ||
-          ((identical(value, '}')) && (identical(token, peek)))) {
-        // A label just before "}" will be handled as a statement error.
-        break;
-      } else {
-        token = parseStatement(token);
-      }
-      statementCount++;
-      peek = peekPastLabels(token);
-    }
-    listener.handleSwitchCase(labelCount, expressionCount, defaultKeyword,
-        statementCount, begin, token);
-    return token;
-  }
-
-  Token parseBreakStatement(Token token) {
-    assert(optional('break', token));
-    Token breakKeyword = token;
-    token = token.next;
-    bool hasTarget = false;
-    if (token.isIdentifier()) {
-      token = parseIdentifier(token);
-      hasTarget = true;
-    }
-    listener.handleBreakStatement(hasTarget, breakKeyword, token);
-    return expectSemicolon(token);
-  }
-
-  Token parseAssertStatement(Token token) {
-    Token assertKeyword = token;
-    Token commaToken = null;
-    token = expect('assert', token);
-    token = expect('(', token);
-    bool old = mayParseFunctionExpressions;
-    mayParseFunctionExpressions = true;
-    token = parseExpression(token);
-    if (optional(',', token)) {
-      commaToken = token;
-      token = token.next;
-      token = parseExpression(token);
-    }
-    token = expect(')', token);
-    mayParseFunctionExpressions = old;
-    listener.handleAssertStatement(assertKeyword, commaToken, token);
-    return expectSemicolon(token);
-  }
-
-  Token parseContinueStatement(Token token) {
-    assert(optional('continue', token));
-    Token continueKeyword = token;
-    token = token.next;
-    bool hasTarget = false;
-    if (token.isIdentifier()) {
-      token = parseIdentifier(token);
-      hasTarget = true;
-    }
-    listener.handleContinueStatement(hasTarget, continueKeyword, token);
-    return expectSemicolon(token);
-  }
-
-  Token parseEmptyStatement(Token token) {
-    listener.handleEmptyStatement(token);
-    return expectSemicolon(token);
-  }
-}
diff --git a/pkg/compiler/lib/src/parser/parser_task.dart b/pkg/compiler/lib/src/parser/parser_task.dart
index 54219d4..8d6a807 100644
--- a/pkg/compiler/lib/src/parser/parser_task.dart
+++ b/pkg/compiler/lib/src/parser/parser_task.dart
@@ -8,12 +8,11 @@
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../elements/modelx.dart' show ElementX;
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../tree/tree.dart' show Node;
 import 'element_listener.dart' show ScannerOptions;
-import 'listener.dart' show ParserError;
+import 'package:front_end/src/fasta/parser.dart' show Parser, ParserError;
 import 'node_listener.dart' show NodeListener;
-import 'parser.dart' show Parser;
 
 class ParserTask extends CompilerTask {
   final Compiler compiler;
@@ -36,7 +35,8 @@
       try {
         parser.parseUnit(token);
       } on ParserError catch (_) {
-        assert(invariant(token, compiler.compilationFailed));
+        assert(invariant(compiler.reporter.spanFromToken(token),
+            compiler.compilationFailed));
         return listener.makeNodeList(0, null, null, '\n');
       }
       Node result = listener.popNode();
diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart
index c68e5e4..ca1ef2e 100644
--- a/pkg/compiler/lib/src/parser/partial_elements.dart
+++ b/pkg/compiler/lib/src/parser/partial_elements.dart
@@ -31,14 +31,19 @@
         TypedefElementX,
         VariableList;
 import '../elements/visitor.dart' show ElementVisitor;
-import '../tokens/token.dart' show Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
 import '../tree/tree.dart';
-import 'class_element_parser.dart' show ClassElementParser;
-import 'listener.dart' show ParserError;
+import 'package:front_end/src/fasta/parser.dart'
+    show ClassMemberParser, Listener, Parser, ParserError;
 import 'member_listener.dart' show MemberListener;
 import 'node_listener.dart' show NodeListener;
-import 'parser.dart' show Parser;
+
+class ClassElementParser extends ClassMemberParser {
+  ClassElementParser(Listener listener) : super(listener);
+
+  Token parseFormalParameters(Token token) => skipFormalParameters(token);
+}
 
 abstract class PartialElement implements DeclarationSite {
   Token beginToken;
@@ -379,7 +384,8 @@
           Token token = parser.parseTopLevelDeclaration(beginToken);
           assert(identical(token, endToken.next));
           cachedNode = listener.popNode();
-          assert(invariant(beginToken, listener.nodes.isEmpty,
+          assert(invariant(
+              reporter.spanFromToken(beginToken), listener.nodes.isEmpty,
               message: "Non-empty listener stack: ${listener.nodes}"));
         } on ParserError {
           // TODO(ahe): Often, a ParserError is thrown while parsing the class
@@ -443,7 +449,7 @@
         doParse(new Parser(listener));
       } on ParserError catch (e) {
         partial.hasParseError = true;
-        return new ErrorNode(element.position, e.reason);
+        return new ErrorNode(element.position, e.kind, e.arguments);
       }
       Node node = listener.popNode();
       assert(listener.nodes.isEmpty);
diff --git a/pkg/compiler/lib/src/parser/partial_parser.dart b/pkg/compiler/lib/src/parser/partial_parser.dart
deleted file mode 100644
index 6aaa52c..0000000
--- a/pkg/compiler/lib/src/parser/partial_parser.dart
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.parser.partial;
-
-import '../common.dart';
-import '../tokens/token.dart' show BeginGroupToken, ErrorToken, Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
-import '../util/characters.dart' as Characters show $CLOSE_CURLY_BRACKET;
-import 'listener.dart' show Listener;
-import 'parser.dart' show Parser;
-
-class PartialParser extends Parser {
-  PartialParser(Listener listener) : super(listener);
-
-  Token parseClassBody(Token token) => skipClassBody(token);
-
-  Token fullParseClassBody(Token token) => super.parseClassBody(token);
-
-  Token parseExpression(Token token) => skipExpression(token);
-
-  Token parseArgumentsOpt(Token token) {
-    // This method is overridden for two reasons:
-    // 1. Avoid generating events for arguments.
-    // 2. Avoid calling skip expression for each argument (which doesn't work).
-    listener.handleNoArguments(token);
-    if (optional('(', token)) {
-      BeginGroupToken begin = token;
-      return begin.endGroup.next;
-    } else {
-      return token;
-    }
-  }
-
-  Token skipExpression(Token token) {
-    while (true) {
-      final kind = token.kind;
-      final value = token.stringValue;
-      if ((identical(kind, Tokens.EOF_TOKEN)) ||
-          (identical(value, ';')) ||
-          (identical(value, ',')) ||
-          (identical(value, '}')) ||
-          (identical(value, ')')) ||
-          (identical(value, ']'))) {
-        break;
-      }
-      if (identical(value, '=') ||
-          identical(value, '?') ||
-          identical(value, ':') ||
-          identical(value, '??')) {
-        var nextValue = token.next.stringValue;
-        if (identical(nextValue, 'const')) {
-          token = token.next;
-          nextValue = token.next.stringValue;
-        }
-        if (identical(nextValue, '{')) {
-          // Handle cases like this:
-          // class Foo {
-          //   var map;
-          //   Foo() : map = {};
-          //   Foo.x() : map = true ? {} : {};
-          // }
-          BeginGroupToken begin = token.next;
-          token = (begin.endGroup != null) ? begin.endGroup : token;
-          token = token.next;
-          continue;
-        }
-        if (identical(nextValue, '<')) {
-          // Handle cases like this:
-          // class Foo {
-          //   var map;
-          //   Foo() : map = <String, Foo>{};
-          //   Foo.x() : map = true ? <String, Foo>{} : <String, Foo>{};
-          // }
-          BeginGroupToken begin = token.next;
-          token = (begin.endGroup != null) ? begin.endGroup : token;
-          token = token.next;
-          if (identical(token.stringValue, '{')) {
-            begin = token;
-            token = (begin.endGroup != null) ? begin.endGroup : token;
-            token = token.next;
-          }
-          continue;
-        }
-      }
-      if (!mayParseFunctionExpressions && identical(value, '{')) {
-        break;
-      }
-      if (token is BeginGroupToken) {
-        BeginGroupToken begin = token;
-        token = (begin.endGroup != null) ? begin.endGroup : token;
-      } else if (token is ErrorToken) {
-        listener.reportErrorToken(token);
-      }
-      token = token.next;
-    }
-    return token;
-  }
-
-  Token skipClassBody(Token token) {
-    if (!optional('{', token)) {
-      return listener.expectedClassBodyToSkip(token);
-    }
-    BeginGroupToken beginGroupToken = token;
-    Token endGroup = beginGroupToken.endGroup;
-    if (endGroup == null) {
-      return listener.unmatched(beginGroupToken);
-    } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) {
-      return listener.unmatched(beginGroupToken);
-    }
-    return endGroup;
-  }
-
-  Token skipAsyncModifier(Token token) {
-    String value = token.stringValue;
-    if (identical(value, 'async')) {
-      token = token.next;
-      value = token.stringValue;
-
-      if (identical(value, '*')) {
-        token = token.next;
-      }
-    } else if (identical(value, 'sync')) {
-      token = token.next;
-      value = token.stringValue;
-
-      if (identical(value, '*')) {
-        token = token.next;
-      }
-    }
-    return token;
-  }
-
-  Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
-    assert(!isExpression);
-    token = skipAsyncModifier(token);
-    String value = token.stringValue;
-    if (identical(value, ';')) {
-      if (!allowAbstract) {
-        listener.reportError(token, MessageKind.BODY_EXPECTED);
-      }
-      listener.handleNoFunctionBody(token);
-    } else {
-      if (identical(value, '=>')) {
-        token = parseExpression(token.next);
-        expectSemicolon(token);
-      } else if (value == '=') {
-        token = parseRedirectingFactoryBody(token);
-        expectSemicolon(token);
-      } else {
-        token = skipBlock(token);
-      }
-      listener.skippedFunctionBody(token);
-    }
-    return token;
-  }
-
-  Token parseFormalParameters(Token token) => skipFormals(token);
-
-  Token skipFormals(Token token) {
-    listener.beginOptionalFormalParameters(token);
-    if (!optional('(', token)) {
-      if (optional(';', token)) {
-        listener.recoverableError(token, "expected '('");
-        return token;
-      }
-      return listener.unexpected(token);
-    }
-    BeginGroupToken beginGroupToken = token;
-    Token endToken = beginGroupToken.endGroup;
-    listener.endFormalParameters(0, token, endToken);
-    return endToken.next;
-  }
-}
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index bf2ae05..45ff585 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -134,14 +134,14 @@
 import 'js_backend/js_backend.dart' show JavaScriptBackend;
 import 'library_loader.dart' show LibraryLoader;
 import 'parser/element_listener.dart' show ElementListener;
-import 'parser/listener.dart' show Listener, ParserError;
+import 'package:front_end/src/fasta/parser.dart'
+    show Listener, Parser, ParserError;
 import 'parser/member_listener.dart' show MemberListener;
-import 'parser/parser.dart' show Parser;
-import 'parser/partial_elements.dart' show PartialClassElement;
-import 'parser/partial_parser.dart' show PartialParser;
-import 'scanner/scanner.dart' show Scanner;
+import 'parser/partial_elements.dart'
+    show ClassElementParser, PartialClassElement;
 import 'script.dart';
-import 'tokens/token.dart' show StringToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token;
+import 'parser/diet_parser_task.dart' show PartialParser;
 
 class PatchParserTask extends CompilerTask {
   final String name = "Patching Parser";
@@ -178,7 +178,7 @@
     measure(() {
       // TODO(johnniwinther): Test that parts and exports are handled correctly.
       Script script = compilationUnit.script;
-      Token tokens = new Scanner(script.file).tokenize();
+      Token tokens = compiler.scanner.scanFile(script.file);
       Listener patchListener = new PatchElementListener(
           compiler, compilationUnit, compiler.idGenerator);
       try {
@@ -199,7 +199,7 @@
 
     measure(() => reporter.withCurrentElement(cls, () {
           MemberListener listener = new PatchMemberListener(compiler, cls);
-          Parser parser = new PatchClassElementParser(listener);
+          Parser parser = new ClassElementParser(listener);
           try {
             Token token = parser.parseTopLevelDeclaration(cls.beginToken);
             assert(identical(token, cls.endToken.next));
@@ -245,16 +245,6 @@
 }
 
 /**
- * Partial parser for patch files that also handles the members of class
- * declarations.
- */
-class PatchClassElementParser extends PartialParser {
-  PatchClassElementParser(Listener listener) : super(listener);
-
-  Token parseClassBody(Token token) => fullParseClassBody(token);
-}
-
-/**
  * Extension of [ElementListener] for parsing patch files.
  */
 class PatchElementListener extends ElementListener implements Listener {
@@ -431,7 +421,7 @@
     ResolutionDartType annotationType =
         constant.getType(compiler.commonElements);
     if (annotationType.element !=
-        compiler.commonElements.nativeAnnotationClass) {
+        compiler.backend.helpers.nativeAnnotationClass) {
       DiagnosticReporter reporter = compiler.reporter;
       reporter.internalError(annotation, 'Invalid @Native(...) annotation.');
     }
@@ -501,7 +491,7 @@
     ResolutionDartType annotationType =
         constant.getType(compiler.commonElements);
     if (annotationType.element !=
-        compiler.commonElements.patchAnnotationClass) {
+        compiler.backend.helpers.patchAnnotationClass) {
       DiagnosticReporter reporter = compiler.reporter;
       reporter.internalError(annotation, 'Invalid patch annotation.');
     }
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index c73a926..0186e97 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -9,10 +9,9 @@
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
 import '../elements/modelx.dart';
-import '../tokens/keyword.dart' show Keyword;
-import '../tokens/precedence.dart';
-import '../tokens/precedence_constants.dart' as Precedence;
-import '../tokens/token.dart';
+import 'package:front_end/src/fasta/scanner.dart';
+import 'package:front_end/src/fasta/scanner/precedence.dart';
+import 'package:front_end/src/fasta/scanner/precedence.dart' as Precedence;
 import '../tree/tree.dart';
 import '../util/util.dart';
 
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 13bcdd9..35b0773 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -27,7 +27,7 @@
         VariableElementX,
         VariableList;
 import '../options.dart';
-import '../tokens/token.dart' show isUserDefinableOperator;
+import 'package:front_end/src/fasta/scanner.dart' show isUserDefinableOperator;
 import '../tree/tree.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/feature.dart' show Feature;
@@ -1808,7 +1808,7 @@
         node,
         name.text,
         MessageKind.PRIVATE_ACCESS,
-        {'libraryName': member.library.libraryOrScriptName, 'name': name});
+        {'libraryName': member.library.name, 'name': name});
     // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
     // member access.
     return handleErroneousAccess(
@@ -1825,7 +1825,7 @@
         node,
         name.text,
         MessageKind.PRIVATE_ACCESS,
-        {'libraryName': member.library.libraryOrScriptName, 'name': name});
+        {'libraryName': member.library.name, 'name': name});
     // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
     // member access.
     return handleUpdate(node, name, new StaticAccess.unresolved(error));
@@ -2061,7 +2061,7 @@
       Send node, Name name, TypedefElement typdef) {
     typdef.ensureResolved(resolution);
     ResolutionDartType type = typdef.rawType;
-    ConstantExpression constant = new TypeConstantExpression(type);
+    ConstantExpression constant = new TypeConstantExpression(type, name.text);
     AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
     return handleConstantTypeLiteralAccess(node, name, typdef, type, semantics);
   }
@@ -2072,7 +2072,7 @@
       SendSet node, Name name, TypedefElement typdef) {
     typdef.ensureResolved(resolution);
     ResolutionDartType type = typdef.rawType;
-    ConstantExpression constant = new TypeConstantExpression(type);
+    ConstantExpression constant = new TypeConstantExpression(type, name.text);
     AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
     return handleConstantTypeLiteralUpdate(node, name, typdef, type, semantics);
   }
@@ -2084,7 +2084,8 @@
     ConstantExpression constant = new TypeConstantExpression(
         // TODO(johnniwinther): Use [type] when evaluation of constants is done
         // directly on the constant expressions.
-        node.isCall ? commonElements.typeType : type);
+        node.isCall ? commonElements.typeType : type,
+        'dynamic');
     AccessSemantics semantics = new ConstantAccess.dynamicTypeLiteral(constant);
     ClassElement typeClass = commonElements.typeClass;
     return handleConstantTypeLiteralAccess(
@@ -2096,7 +2097,7 @@
   ResolutionResult handleDynamicTypeLiteralUpdate(SendSet node) {
     ResolutionDartType type = const ResolutionDynamicType();
     ConstantExpression constant =
-        new TypeConstantExpression(const ResolutionDynamicType());
+        new TypeConstantExpression(const ResolutionDynamicType(), 'dynamic');
     AccessSemantics semantics = new ConstantAccess.dynamicTypeLiteral(constant);
     ClassElement typeClass = commonElements.typeClass;
     return handleConstantTypeLiteralUpdate(
@@ -2109,7 +2110,7 @@
       Send node, Name name, ClassElement cls) {
     cls.ensureResolved(resolution);
     ResolutionDartType type = cls.rawType;
-    ConstantExpression constant = new TypeConstantExpression(type);
+    ConstantExpression constant = new TypeConstantExpression(type, name.text);
     AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
     return handleConstantTypeLiteralAccess(node, name, cls, type, semantics);
   }
@@ -2120,7 +2121,7 @@
       SendSet node, Name name, ClassElement cls) {
     cls.ensureResolved(resolution);
     ResolutionDartType type = cls.rawType;
-    ConstantExpression constant = new TypeConstantExpression(type);
+    ConstantExpression constant = new TypeConstantExpression(type, name.text);
     AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
     return handleConstantTypeLiteralUpdate(node, name, cls, type, semantics);
   }
@@ -2551,8 +2552,9 @@
           break;
         case AccessKind.FINAL_LOCAL_VARIABLE:
           if (element.isConst) {
+            LocalVariableElement local = element;
             result = new ConstantResult(
-                node, new VariableConstantExpression(element),
+                node, new LocalVariableConstantExpression(local),
                 element: element);
           } else {
             result = new ElementResult(element);
@@ -2747,7 +2749,7 @@
       registry.registerSendStructure(node, new GetStructure(semantics));
       if (member.isConst) {
         FieldElement field = member;
-        result = new ConstantResult(node, new VariableConstantExpression(field),
+        result = new ConstantResult(node, new FieldConstantExpression(field),
             element: field);
       } else {
         result = new ElementResult(member);
@@ -2841,7 +2843,7 @@
       } else if (member.isFunction) {
         // `a = b`, `a++` or `a += b` where `a` is a function.
         MethodElement method = member;
-        ErroneousElement error = reportAndCreateErroneousElement(
+        reportAndCreateErroneousElement(
             node.selector, name.text, MessageKind.ASSIGNING_METHOD, const {});
         registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
         if (node.isComplex) {
@@ -2860,11 +2862,8 @@
           registry.registerStaticUse(new StaticUse.staticGet(member));
         }
         if (member.isFinal || member.isConst) {
-          ErroneousElement error = reportAndCreateErroneousElement(
-              node.selector,
-              name.text,
-              MessageKind.UNDEFINED_STATIC_SETTER_BUT_GETTER,
-              {'name': name});
+          reportAndCreateErroneousElement(node.selector, name.text,
+              MessageKind.UNDEFINED_STATIC_SETTER_BUT_GETTER, {'name': name});
           registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
           semantics = member.isTopLevel
               ? new StaticAccess.finalTopLevelField(member)
@@ -3612,8 +3611,8 @@
 
   ResolutionResult visitYield(Yield node) {
     if (!resolution.target.supportsAsyncAwait) {
-      reporter.reportErrorMessage(
-          node.yieldToken, MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
+      reporter.reportErrorMessage(reporter.spanFromToken(node.yieldToken),
+          MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
     } else {
       if (!currentAsyncMarker.isYielding) {
         reporter.reportErrorMessage(node, MessageKind.INVALID_YIELD);
@@ -3753,8 +3752,8 @@
 
   ResolutionResult visitAwait(Await node) {
     if (!resolution.target.supportsAsyncAwait) {
-      reporter.reportErrorMessage(
-          node.awaitToken, MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
+      reporter.reportErrorMessage(reporter.spanFromToken(node.awaitToken),
+          MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
     } else {
       if (!currentAsyncMarker.isAsync) {
         reporter.reportErrorMessage(node, MessageKind.INVALID_AWAIT);
@@ -3981,12 +3980,13 @@
           // TODO(johnniwinther): Remove this when all constants are computed
           // in resolution.
           !constructor.isFromEnvironmentConstructor) {
+        ResolutionInterfaceType interfaceType = type;
         CallStructure callStructure = argumentsResult.callStructure;
         List<ConstantExpression> arguments = argumentsResult.constantArguments;
 
         ConstructedConstantExpression constant =
             new ConstructedConstantExpression(
-                type, constructor, callStructure, arguments);
+                interfaceType, constructor, callStructure, arguments);
         registry.registerNewStructure(node,
             new ConstInvokeStructure(ConstantInvokeKind.CONSTRUCTED, constant));
         resolutionResult = new ConstantResult(node, constant);
@@ -4017,7 +4017,9 @@
       if (resolution.commonElements.isSymbolConstructor(constructor) &&
           !resolution.mirrorUsageAnalyzerTask
               .hasMirrorUsage(enclosingElement)) {
-        reporter.reportHintMessage(node.newToken, MessageKind.NON_CONST_BLOAT,
+        reporter.reportHintMessage(
+            reporter.spanFromToken(node.newToken),
+            MessageKind.NON_CONST_BLOAT,
             {'name': commonElements.symbolClass.name});
       }
       registry.registerNewStructure(
@@ -4288,12 +4290,12 @@
 
   ResolutionResult visitAsyncForIn(AsyncForIn node) {
     if (!resolution.target.supportsAsyncAwait) {
-      reporter.reportErrorMessage(
-          node.awaitToken, MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
+      reporter.reportErrorMessage(reporter.spanFromToken(node.awaitToken),
+          MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
     } else {
       if (!currentAsyncMarker.isAsync) {
-        reporter.reportErrorMessage(
-            node.awaitToken, MessageKind.INVALID_AWAIT_FOR_IN);
+        reporter.reportErrorMessage(reporter.spanFromToken(node.awaitToken),
+            MessageKind.INVALID_AWAIT_FOR_IN);
       }
       registry.registerFeature(Feature.ASYNC_FOR_IN);
       registry.registerDynamicUse(new DynamicUse(Selectors.current, null));
@@ -4593,6 +4595,7 @@
 
     JumpTarget breakElement = getOrDefineTarget(node);
     Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{};
+    Set<SwitchCase> switchCasesWithContinues = new Set<SwitchCase>();
     Link<Node> cases = node.cases.nodes;
     while (!cases.isEmpty) {
       SwitchCase switchCase = cases.head;
@@ -4660,12 +4663,22 @@
     node.cases.accept(this);
     statementScope.exitSwitch();
 
+    continueLabels.forEach((String key, LabelDefinition label) {
+      if (label.isContinueTarget) {
+        JumpTarget targetElement = label.target;
+        SwitchCase switchCase = targetElement.statement;
+        switchCasesWithContinues.add(switchCase);
+      }
+    });
+
     // Clean-up unused labels.
     continueLabels.forEach((String key, LabelDefinition label) {
       if (!label.isContinueTarget) {
         JumpTarget targetElement = label.target;
         SwitchCase switchCase = targetElement.statement;
-        registry.undefineTarget(switchCase);
+        if (!switchCasesWithContinues.contains(switchCase)) {
+          registry.undefineTarget(switchCase);
+        }
         registry.undefineLabel(label.label);
       }
     });
@@ -4693,7 +4706,8 @@
     visit(node.tryBlock);
     if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
       reporter.reportErrorMessage(
-          node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
+          reporter.spanFromToken(node.getEndToken().next),
+          MessageKind.NO_CATCH_NOR_FINALLY);
     }
     visit(node.catchBlocks);
     visit(node.finallyBlock);
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 83edcfe..df2f729 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -5,8 +5,7 @@
 library dart2js.resolution.registry;
 
 import '../common.dart';
-import '../common/backend_api.dart'
-    show Backend, ForeignResolver, NativeRegistry;
+import '../common/backend_api.dart' show ForeignResolver, NativeRegistry;
 import '../common/resolution.dart' show ResolutionImpact, Target;
 import '../constants/expressions.dart';
 import '../elements/resolution_types.dart';
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index b844779..5706455 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -37,7 +37,7 @@
         TypedefElementX;
 import '../enqueue.dart';
 import '../options.dart';
-import '../tokens/token.dart'
+import 'package:front_end/src/fasta/scanner.dart'
     show
         isBinaryOperator,
         isMinusOperator,
@@ -47,7 +47,7 @@
 import '../tree/tree.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/feature.dart' show Feature;
-import '../universe/use.dart' show StaticUse, TypeUse;
+import '../universe/use.dart' show StaticUse;
 import '../universe/world_impact.dart' show WorldImpact;
 import '../util/util.dart' show Link, Setlet;
 import '../world.dart';
@@ -518,7 +518,6 @@
       ResolvedAst resolvedAst = factory.resolvedAst;
       assert(invariant(node, resolvedAst != null,
           message: 'No ResolvedAst for $factory.'));
-      FunctionExpression functionNode = resolvedAst.node;
       RedirectingFactoryBody redirectionNode = resolvedAst.body;
       ResolutionDartType factoryType =
           resolvedAst.elements.getType(redirectionNode);
@@ -1083,8 +1082,8 @@
               switch (constant.kind) {
                 case ConstantExpressionKind.CONSTRUCTED:
                   ConstructedConstantExpression constructedConstant = constant;
-                  if (constructedConstant.type.isGeneric &&
-                      !constructedConstant.type.isRaw) {
+                  ResolutionInterfaceType type = constructedConstant.type;
+                  if (type.isGeneric && !type.isRaw) {
                     // Const constructor calls cannot have type arguments.
                     // TODO(24312): Remove this.
                     reporter.reportErrorMessage(
@@ -1092,7 +1091,7 @@
                     constant = new ErroneousConstantExpression();
                   }
                   break;
-                case ConstantExpressionKind.VARIABLE:
+                case ConstantExpressionKind.FIELD:
                 case ConstantExpressionKind.ERRONEOUS:
                   break;
                 default:
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 07f3bba..ac7b6d8 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -18,7 +18,6 @@
         LocalParameterElementX,
         TypeVariableElementX;
 import '../tree/tree.dart';
-import '../universe/use.dart' show TypeUse;
 import '../util/util.dart' show Link, LinkBuilder;
 import 'members.dart' show ResolverVisitor;
 import 'registry.dart' show ResolutionRegistry;
diff --git a/pkg/compiler/lib/src/resolution/variables.dart b/pkg/compiler/lib/src/resolution/variables.dart
index d6490e0..60541a5 100644
--- a/pkg/compiler/lib/src/resolution/variables.dart
+++ b/pkg/compiler/lib/src/resolution/variables.dart
@@ -8,7 +8,6 @@
 import '../common/resolution.dart';
 import '../elements/modelx.dart' show LocalVariableElementX, VariableList;
 import '../tree/tree.dart';
-import '../universe/use.dart' show TypeUse;
 import '../universe/feature.dart';
 import '../util/util.dart' show Link;
 import 'members.dart' show ResolverVisitor;
diff --git a/pkg/compiler/lib/src/resolved_uri_translator.dart b/pkg/compiler/lib/src/resolved_uri_translator.dart
index e2bf954..ecd7d0a 100644
--- a/pkg/compiler/lib/src/resolved_uri_translator.dart
+++ b/pkg/compiler/lib/src/resolved_uri_translator.dart
@@ -10,8 +10,9 @@
 /// system readable URIs.
 abstract class ResolvedUriTranslator {
   factory ResolvedUriTranslator(
-          Map<String, Uri> sdkLibraries, DiagnosticReporter reporter) =
-      _ResolvedUriTranslator;
+      Map<String, Uri> sdkLibraries,
+      DiagnosticReporter reporter,
+      Uri platformConfigUri) = _ResolvedUriTranslator;
 
   /// The set of platform libraries reported as unsupported.
   ///
@@ -76,11 +77,13 @@
 class _ResolvedUriTranslator implements ResolvedUriTranslator {
   final Map<String, Uri> _sdkLibraries;
   final DiagnosticReporter _reporter;
+  final Uri _platformConfigUri;
 
   Set<Uri> disallowedLibraryUris = new Set<Uri>();
   bool mockableLibraryUsed = false;
 
-  _ResolvedUriTranslator(this._sdkLibraries, this._reporter);
+  _ResolvedUriTranslator(
+      this._sdkLibraries, this._reporter, this._platformConfigUri);
 
   Map<String, Uri> get sdkLibraries => _sdkLibraries;
 
@@ -136,9 +139,27 @@
     }
 
     if (location.scheme == "unsupported") {
-      _reporter.reportErrorMessage(spannable, MessageKind.LIBRARY_NOT_SUPPORTED,
-          {'resolvedUri': resolvedUri});
-      registerDisallowedLibraryUse(resolvedUri);
+      if (location.path == "") {
+        _reporter.reportErrorMessage(spannable,
+            MessageKind.LIBRARY_NOT_SUPPORTED, {'resolvedUri': resolvedUri});
+        registerDisallowedLibraryUse(resolvedUri);
+      } else {
+        // If the specification includes a path, we treat it as "partially"
+        // unsupported: it is allowed to be imported unconditionally, but we
+        // will not expose it as being supported in the const variable
+        // `dart.library.name`.
+        //
+        // This is a stopgap measure to support packages like `http` that need
+        // to import `dart:io` conditionally. Once config-imports are supported
+        // in the language, we can make it an error again to import it
+        // unconditionally.
+        //
+        // The plaform configuration files contain a URI of the form
+        // `unsupported:path/to/library.dart` to indicate this partially
+        // supported mode. We resolve the path with respect to the configuration
+        // file.
+        return _platformConfigUri.resolve(location.path);
+      }
       return null;
     }
 
diff --git a/pkg/compiler/lib/src/scanner/array_based_scanner.dart b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
deleted file mode 100644
index edd22ae..0000000
--- a/pkg/compiler/lib/src/scanner/array_based_scanner.dart
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.scanner.array_based;
-
-import '../io/source_file.dart' show SourceFile;
-import '../tokens/keyword.dart' show Keyword;
-import '../tokens/precedence.dart' show PrecedenceInfo;
-import '../tokens/precedence_constants.dart' as Precedence
-    show COMMENT_INFO, EOF_INFO;
-import '../tokens/token.dart'
-    show BeginGroupToken, ErrorToken, KeywordToken, SymbolToken, Token;
-import '../tokens/token_constants.dart' as Tokens
-    show LT_TOKEN, OPEN_CURLY_BRACKET_TOKEN, STRING_INTERPOLATION_TOKEN;
-import '../util/characters.dart' show $LF, $STX;
-import '../util/util.dart' show Link;
-import 'scanner.dart' show AbstractScanner;
-
-abstract class ArrayBasedScanner extends AbstractScanner {
-  ArrayBasedScanner(SourceFile file, bool includeComments)
-      : super(file, includeComments);
-
-  /**
-   * The stack of open groups, e.g [: { ... ( .. :]
-   * Each BeginGroupToken has a pointer to the token where the group
-   * ends. This field is set when scanning the end group token.
-   */
-  Link<BeginGroupToken> groupingStack = const Link<BeginGroupToken>();
-
-  /**
-   * Appends a fixed token whose kind and content is determined by [info].
-   * Appends an *operator* token from [info].
-   *
-   * An operator token represent operators like ':', '.', ';', '&&', '==', '--',
-   * '=>', etc.
-   */
-  void appendPrecedenceToken(PrecedenceInfo info) {
-    tail.next = new SymbolToken(info, tokenStart);
-    tail = tail.next;
-  }
-
-  /**
-   * Appends a fixed token based on whether the current char is [choice] or not.
-   * If the current char is [choice] a fixed token whose kind and content
-   * is determined by [yes] is appended, otherwise a fixed token whose kind
-   * and content is determined by [no] is appended.
-   */
-  int select(int choice, PrecedenceInfo yes, PrecedenceInfo no) {
-    int next = advance();
-    if (identical(next, choice)) {
-      appendPrecedenceToken(yes);
-      return advance();
-    } else {
-      appendPrecedenceToken(no);
-      return next;
-    }
-  }
-
-  /**
-   * Appends a keyword token whose kind is determined by [keyword].
-   */
-  void appendKeywordToken(Keyword keyword) {
-    String syntax = keyword.syntax;
-    // Type parameters and arguments cannot contain 'this'.
-    if (identical(syntax, 'this')) {
-      discardOpenLt();
-    }
-    tail.next = new KeywordToken(keyword, tokenStart);
-    tail = tail.next;
-  }
-
-  void appendEofToken() {
-    beginToken();
-    discardOpenLt();
-    while (!groupingStack.isEmpty) {
-      unmatchedBeginGroup(groupingStack.head);
-      groupingStack = groupingStack.tail;
-    }
-    tail.next = new SymbolToken(Precedence.EOF_INFO, tokenStart);
-    tail = tail.next;
-    // EOF points to itself so there's always infinite look-ahead.
-    tail.next = tail;
-  }
-
-  /**
-   * Notifies scanning a whitespace character. Note that [appendWhiteSpace] is
-   * not always invoked for [$SPACE] characters.
-   *
-   * This method is used by the scanners to track line breaks and create the
-   * [lineStarts] map.
-   */
-  void appendWhiteSpace(int next) {
-    if (next == $LF && file != null) {
-      lineStarts.add(stringOffset + 1); // +1, the line starts after the $LF.
-    }
-  }
-
-  /**
-   * Notifies on [$LF] characters in multi-line comments or strings.
-   *
-   * This method is used by the scanners to track line breaks and create the
-   * [lineStarts] map.
-   */
-  void lineFeedInMultiline() {
-    if (file != null) {
-      lineStarts.add(stringOffset + 1);
-    }
-  }
-
-  /**
-   * Appends a token that begins a new group, represented by [value].
-   * Group begin tokens are '{', '(', '[' and '${'.
-   */
-  void appendBeginGroup(PrecedenceInfo info) {
-    Token token = new BeginGroupToken(info, tokenStart);
-    tail.next = token;
-    tail = tail.next;
-
-    // { (  [ ${ cannot appear inside a type parameters / arguments.
-    if (!identical(info.kind, Tokens.LT_TOKEN)) discardOpenLt();
-    groupingStack = groupingStack.prepend(token);
-  }
-
-  /**
-   * Appends a token that begins an end group, represented by [value].
-   * It handles the group end tokens '}', ')' and ']'. The tokens '>' and
-   * '>>' are handled separately bo [appendGt] and [appendGtGt].
-   */
-  int appendEndGroup(PrecedenceInfo info, int openKind) {
-    assert(!identical(openKind, Tokens.LT_TOKEN)); // openKind is < for > and >>
-    discardBeginGroupUntil(openKind);
-    appendPrecedenceToken(info);
-    Token close = tail;
-    if (groupingStack.isEmpty) {
-      return advance();
-    }
-    BeginGroupToken begin = groupingStack.head;
-    if (!identical(begin.kind, openKind)) {
-      assert(begin.kind == Tokens.STRING_INTERPOLATION_TOKEN &&
-          openKind == Tokens.OPEN_CURLY_BRACKET_TOKEN);
-      // We're ending an interpolated expression.
-      begin.endGroup = close;
-      groupingStack = groupingStack.tail;
-      // Using "start-of-text" to signal that we're back in string
-      // scanning mode.
-      return $STX;
-    }
-    begin.endGroup = close;
-    groupingStack = groupingStack.tail;
-    return advance();
-  }
-
-  /**
-   * Discards begin group tokens until a match with [openKind] is found.
-   * This recovers nicely from from a situation like "{[}".
-   */
-  void discardBeginGroupUntil(int openKind) {
-    while (!groupingStack.isEmpty) {
-      // Don't report unmatched errors for <; it is also the less-than operator.
-      discardOpenLt();
-      if (groupingStack.isEmpty) return;
-      BeginGroupToken begin = groupingStack.head;
-      if (openKind == begin.kind) return;
-      if (openKind == Tokens.OPEN_CURLY_BRACKET_TOKEN &&
-          begin.kind == Tokens.STRING_INTERPOLATION_TOKEN) return;
-      unmatchedBeginGroup(begin);
-      groupingStack = groupingStack.tail;
-    }
-  }
-
-  /**
-   * Appends a token for '>'.
-   * This method does not issue unmatched errors, because > is also the
-   * greater-than operator. It does not necessarily have to close a group.
-   */
-  void appendGt(PrecedenceInfo info) {
-    appendPrecedenceToken(info);
-    if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
-      groupingStack.head.endGroup = tail;
-      groupingStack = groupingStack.tail;
-    }
-  }
-
-  /**
-   * Appends a token for '>>'.
-   * This method does not issue unmatched errors, because >> is also the
-   * shift operator. It does not necessarily have to close a group.
-   */
-  void appendGtGt(PrecedenceInfo info) {
-    appendPrecedenceToken(info);
-    if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
-      // Don't assign endGroup: in "T<U<V>>", the '>>' token closes the outer
-      // '<', the inner '<' is left without endGroup.
-      groupingStack = groupingStack.tail;
-    }
-    if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
-      groupingStack.head.endGroup = tail;
-      groupingStack = groupingStack.tail;
-    }
-  }
-
-  void appendComment(start, bool asciiOnly) {
-    if (!includeComments) return;
-    appendSubstringToken(Precedence.COMMENT_INFO, start, asciiOnly);
-  }
-
-  void appendErrorToken(ErrorToken token) {
-    tail.next = token;
-    tail = token;
-  }
-
-  /**
-   * This method is called to discard '<' from the "grouping" stack.
-   *
-   * [PartialParser.skipExpression] relies on the fact that we do not
-   * create groups for stuff like:
-   * [:a = b < c, d = e > f:].
-   *
-   * In other words, this method is called when the scanner recognizes
-   * something which cannot possibly be part of a type parameter/argument
-   * list, like the '=' in the above example.
-   */
-  void discardOpenLt() {
-    while (!groupingStack.isEmpty &&
-        identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
-      groupingStack = groupingStack.tail;
-    }
-  }
-}
diff --git a/pkg/compiler/lib/src/scanner/scanner.dart b/pkg/compiler/lib/src/scanner/scanner.dart
deleted file mode 100644
index f069861..0000000
--- a/pkg/compiler/lib/src/scanner/scanner.dart
+++ /dev/null
@@ -1,1187 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.scanner;
-
-import '../io/source_file.dart' show SourceFile, Utf8BytesSourceFile;
-import '../tokens/keyword.dart' show Keyword, KeywordState;
-import '../tokens/precedence.dart';
-import '../tokens/precedence_constants.dart';
-import '../tokens/token.dart';
-import '../tokens/token_constants.dart';
-import '../util/characters.dart';
-import 'string_scanner.dart' show StringScanner;
-import 'utf8_bytes_scanner.dart' show Utf8BytesScanner;
-
-abstract class Scanner {
-  Token tokenize();
-
-  factory Scanner(SourceFile file, {bool includeComments: false}) {
-    if (file is Utf8BytesSourceFile) {
-      return new Utf8BytesScanner(file, includeComments: includeComments);
-    } else {
-      return new StringScanner(file, includeComments: includeComments);
-    }
-  }
-}
-
-abstract class AbstractScanner implements Scanner {
-  // TODO(ahe): Move this class to implementation.
-
-  final bool includeComments;
-
-  /**
-   * The string offset for the next token that will be created.
-   *
-   * Note that in the [Utf8BytesScanner], [stringOffset] and [scanOffset] values
-   * are different. One string character can be encoded using multiple UTF-8
-   * bytes.
-   */
-  int tokenStart = -1;
-
-  /**
-   * A pointer to the token stream created by this scanner. The first token
-   * is a special token and not part of the source file. This is an
-   * implementation detail to avoids special cases in the scanner. This token
-   * is not exposed to clients of the scanner, which are expected to invoke
-   * [firstToken] to access the token stream.
-   */
-  final Token tokens = new SymbolToken(EOF_INFO, -1);
-
-  /**
-   * A pointer to the last scanned token.
-   */
-  Token tail;
-
-  /**
-   * The source file that is being scanned. This field can be [:null:].
-   * If the source file is available, the scanner assigns its [:lineStarts:] and
-   * [:length:] fields at the end of [tokenize].
-   */
-  final SourceFile file;
-
-  final List<int> lineStarts = <int>[0];
-
-  AbstractScanner(this.file, this.includeComments) {
-    this.tail = this.tokens;
-  }
-
-  /**
-   * Advances and returns the next character.
-   *
-   * If the next character is non-ASCII, then the returned value depends on the
-   * scanner implementation. The [Utf8BytesScanner] returns a UTF-8 byte, while
-   * the [StringScanner] returns a UTF-16 code unit.
-   *
-   * The scanner ensures that [advance] is not invoked after it returned [$EOF].
-   * This allows implementations to omit bound checks if the data structure ends
-   * with '0'.
-   */
-  int advance();
-
-  /**
-   * Returns the current unicode character.
-   *
-   * If the current character is ASCII, then it is returned unchanged.
-   *
-   * The [Utf8BytesScanner] decodes the next unicode code point starting at the
-   * current position. Note that every unicode character is returned as a single
-   * code point, that is, for '\u{1d11e}' it returns 119070, and the following
-   * [advance] returns the next character.
-   *
-   * The [StringScanner] returns the current character unchanged, which might
-   * be a surrogate character. In the case of '\u{1d11e}', it returns the first
-   * code unit 55348, and the following [advance] returns the second code unit
-   * 56606.
-   *
-   * Invoking [currentAsUnicode] multiple times is safe, i.e.,
-   * [:currentAsUnicode(next) == currentAsUnicode(currentAsUnicode(next)):].
-   */
-  int currentAsUnicode(int next);
-
-  /**
-   * Returns the character at the next poisition. Like in [advance], the
-   * [Utf8BytesScanner] returns a UTF-8 byte, while the [StringScanner] returns
-   * a UTF-16 code unit.
-   */
-  int peek();
-
-  /**
-   * Notifies the scanner that unicode characters were detected in either a
-   * comment or a string literal between [startScanOffset] and the current
-   * scan offset.
-   */
-  void handleUnicode(int startScanOffset);
-
-  /**
-   * Returns the current scan offset.
-   *
-   * In the [Utf8BytesScanner] this is the offset into the byte list, in the
-   * [StringScanner] the offset in the source string.
-   */
-  int get scanOffset;
-
-  /**
-   * Returns the current string offset.
-   *
-   * In the [StringScanner] this is identical to the [scanOffset]. In the
-   * [Utf8BytesScanner] it is computed based on encountered UTF-8 characters.
-   */
-  int get stringOffset;
-
-  /**
-   * Returns the first token scanned by this [Scanner].
-   */
-  Token firstToken();
-
-  /**
-   * Returns the last token scanned by this [Scanner].
-   */
-  Token previousToken();
-
-  /**
-   * Notifies that a new token starts at current offset.
-   */
-  void beginToken() {
-    tokenStart = stringOffset;
-  }
-
-  /**
-   * Appends a substring from the scan offset [:start:] to the current
-   * [:scanOffset:] plus the [:extraOffset:]. For example, if the current
-   * scanOffset is 10, then [:appendSubstringToken(5, -1):] will append the
-   * substring string [5,9).
-   *
-   * Note that [extraOffset] can only be used if the covered character(s) are
-   * known to be ASCII.
-   */
-  void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
-      [int extraOffset]);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendPrecedenceToken(PrecedenceInfo info);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  int select(int choice, PrecedenceInfo yes, PrecedenceInfo no);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendKeywordToken(Keyword keyword);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendEofToken();
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendWhiteSpace(int next);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void lineFeedInMultiline();
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendBeginGroup(PrecedenceInfo info);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  int appendEndGroup(PrecedenceInfo info, int openKind);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendGt(PrecedenceInfo info);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendGtGt(PrecedenceInfo info);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void appendComment(start, bool asciiOnly);
-
-  /// Append [token] to the token stream.
-  void appendErrorToken(ErrorToken token);
-
-  /** Documentation in subclass [ArrayBasedScanner]. */
-  void discardOpenLt();
-
-  /// Return true when at EOF.
-  bool atEndOfFile();
-
-  Token tokenize() {
-    while (!atEndOfFile()) {
-      int next = advance();
-      while (!identical(next, $EOF)) {
-        next = bigSwitch(next);
-      }
-      if (atEndOfFile()) {
-        appendEofToken();
-      } else {
-        unexpected($EOF);
-      }
-    }
-
-    if (file != null) {
-      file.length = stringOffset;
-      // One additional line start at the end, see [SourceFile.lineStarts].
-      lineStarts.add(stringOffset + 1);
-      file.lineStarts = lineStarts;
-    }
-
-    return firstToken();
-  }
-
-  int bigSwitch(int next) {
-    beginToken();
-    if (identical(next, $SPACE) ||
-        identical(next, $TAB) ||
-        identical(next, $LF) ||
-        identical(next, $CR)) {
-      appendWhiteSpace(next);
-      next = advance();
-      // Sequences of spaces are common, so advance through them fast.
-      while (identical(next, $SPACE)) {
-        // We don't invoke [:appendWhiteSpace(next):] here for efficiency,
-        // assuming that it does not do anything for space characters.
-        next = advance();
-      }
-      return next;
-    }
-
-    if ($a <= next && next <= $z) {
-      if (identical($r, next)) {
-        return tokenizeRawStringKeywordOrIdentifier(next);
-      }
-      return tokenizeKeywordOrIdentifier(next, true);
-    }
-
-    if (($A <= next && next <= $Z) ||
-        identical(next, $_) ||
-        identical(next, $$)) {
-      return tokenizeIdentifier(next, scanOffset, true);
-    }
-
-    if (identical(next, $LT)) {
-      return tokenizeLessThan(next);
-    }
-
-    if (identical(next, $GT)) {
-      return tokenizeGreaterThan(next);
-    }
-
-    if (identical(next, $EQ)) {
-      return tokenizeEquals(next);
-    }
-
-    if (identical(next, $BANG)) {
-      return tokenizeExclamation(next);
-    }
-
-    if (identical(next, $PLUS)) {
-      return tokenizePlus(next);
-    }
-
-    if (identical(next, $MINUS)) {
-      return tokenizeMinus(next);
-    }
-
-    if (identical(next, $STAR)) {
-      return tokenizeMultiply(next);
-    }
-
-    if (identical(next, $PERCENT)) {
-      return tokenizePercent(next);
-    }
-
-    if (identical(next, $AMPERSAND)) {
-      return tokenizeAmpersand(next);
-    }
-
-    if (identical(next, $BAR)) {
-      return tokenizeBar(next);
-    }
-
-    if (identical(next, $CARET)) {
-      return tokenizeCaret(next);
-    }
-
-    if (identical(next, $OPEN_SQUARE_BRACKET)) {
-      return tokenizeOpenSquareBracket(next);
-    }
-
-    if (identical(next, $TILDE)) {
-      return tokenizeTilde(next);
-    }
-
-    if (identical(next, $BACKSLASH)) {
-      appendPrecedenceToken(BACKSLASH_INFO);
-      return advance();
-    }
-
-    if (identical(next, $HASH)) {
-      return tokenizeTag(next);
-    }
-
-    if (identical(next, $OPEN_PAREN)) {
-      appendBeginGroup(OPEN_PAREN_INFO);
-      return advance();
-    }
-
-    if (identical(next, $CLOSE_PAREN)) {
-      return appendEndGroup(CLOSE_PAREN_INFO, OPEN_PAREN_TOKEN);
-    }
-
-    if (identical(next, $COMMA)) {
-      appendPrecedenceToken(COMMA_INFO);
-      return advance();
-    }
-
-    if (identical(next, $COLON)) {
-      appendPrecedenceToken(COLON_INFO);
-      return advance();
-    }
-
-    if (identical(next, $SEMICOLON)) {
-      appendPrecedenceToken(SEMICOLON_INFO);
-      // Type parameters and arguments cannot contain semicolon.
-      discardOpenLt();
-      return advance();
-    }
-
-    if (identical(next, $QUESTION)) {
-      return tokenizeQuestion(next);
-    }
-
-    if (identical(next, $CLOSE_SQUARE_BRACKET)) {
-      return appendEndGroup(
-          CLOSE_SQUARE_BRACKET_INFO, OPEN_SQUARE_BRACKET_TOKEN);
-    }
-
-    if (identical(next, $BACKPING)) {
-      appendPrecedenceToken(BACKPING_INFO);
-      return advance();
-    }
-
-    if (identical(next, $OPEN_CURLY_BRACKET)) {
-      appendBeginGroup(OPEN_CURLY_BRACKET_INFO);
-      return advance();
-    }
-
-    if (identical(next, $CLOSE_CURLY_BRACKET)) {
-      return appendEndGroup(CLOSE_CURLY_BRACKET_INFO, OPEN_CURLY_BRACKET_TOKEN);
-    }
-
-    if (identical(next, $SLASH)) {
-      return tokenizeSlashOrComment(next);
-    }
-
-    if (identical(next, $AT)) {
-      return tokenizeAt(next);
-    }
-
-    if (identical(next, $DQ) || identical(next, $SQ)) {
-      return tokenizeString(next, scanOffset, false);
-    }
-
-    if (identical(next, $PERIOD)) {
-      return tokenizeDotsOrNumber(next);
-    }
-
-    if (identical(next, $0)) {
-      return tokenizeHexOrNumber(next);
-    }
-
-    // TODO(ahe): Would a range check be faster?
-    if (identical(next, $1) ||
-        identical(next, $2) ||
-        identical(next, $3) ||
-        identical(next, $4) ||
-        identical(next, $5) ||
-        identical(next, $6) ||
-        identical(next, $7) ||
-        identical(next, $8) ||
-        identical(next, $9)) {
-      return tokenizeNumber(next);
-    }
-
-    if (identical(next, $EOF)) {
-      return $EOF;
-    }
-    if (next < 0x1f) {
-      return unexpected(next);
-    }
-
-    next = currentAsUnicode(next);
-
-    // The following are non-ASCII characters.
-
-    if (identical(next, $NBSP)) {
-      appendWhiteSpace(next);
-      return advance();
-    }
-
-    return unexpected(next);
-  }
-
-  int tokenizeTag(int next) {
-    // # or #!.*[\n\r]
-    if (scanOffset == 0) {
-      if (identical(peek(), $BANG)) {
-        int start = scanOffset + 1;
-        bool asciiOnly = true;
-        do {
-          next = advance();
-          if (next > 127) asciiOnly = false;
-        } while (!identical(next, $LF) &&
-            !identical(next, $CR) &&
-            !identical(next, $EOF));
-        if (!asciiOnly) handleUnicode(start);
-        return next;
-      }
-    }
-    appendPrecedenceToken(HASH_INFO);
-    return advance();
-  }
-
-  int tokenizeTilde(int next) {
-    // ~ ~/ ~/=
-    next = advance();
-    if (identical(next, $SLASH)) {
-      return select($EQ, TILDE_SLASH_EQ_INFO, TILDE_SLASH_INFO);
-    } else {
-      appendPrecedenceToken(TILDE_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeOpenSquareBracket(int next) {
-    // [ [] []=
-    next = advance();
-    if (identical(next, $CLOSE_SQUARE_BRACKET)) {
-      Token token = previousToken();
-      if (token is KeywordToken && token.keyword.syntax == 'operator' ||
-          token is SymbolToken && token.info == HASH_INFO) {
-        return select($EQ, INDEX_EQ_INFO, INDEX_INFO);
-      }
-    }
-    appendBeginGroup(OPEN_SQUARE_BRACKET_INFO);
-    return next;
-  }
-
-  int tokenizeCaret(int next) {
-    // ^ ^=
-    return select($EQ, CARET_EQ_INFO, CARET_INFO);
-  }
-
-  int tokenizeQuestion(int next) {
-    // ? ?. ?? ??=
-    next = advance();
-    if (identical(next, $QUESTION)) {
-      return select($EQ, QUESTION_QUESTION_EQ_INFO, QUESTION_QUESTION_INFO);
-    } else if (identical(next, $PERIOD)) {
-      appendPrecedenceToken(QUESTION_PERIOD_INFO);
-      return advance();
-    } else {
-      appendPrecedenceToken(QUESTION_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeBar(int next) {
-    // | || |=
-    next = advance();
-    if (identical(next, $BAR)) {
-      appendPrecedenceToken(BAR_BAR_INFO);
-      return advance();
-    } else if (identical(next, $EQ)) {
-      appendPrecedenceToken(BAR_EQ_INFO);
-      return advance();
-    } else {
-      appendPrecedenceToken(BAR_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeAmpersand(int next) {
-    // && &= &
-    next = advance();
-    if (identical(next, $AMPERSAND)) {
-      appendPrecedenceToken(AMPERSAND_AMPERSAND_INFO);
-      return advance();
-    } else if (identical(next, $EQ)) {
-      appendPrecedenceToken(AMPERSAND_EQ_INFO);
-      return advance();
-    } else {
-      appendPrecedenceToken(AMPERSAND_INFO);
-      return next;
-    }
-  }
-
-  int tokenizePercent(int next) {
-    // % %=
-    return select($EQ, PERCENT_EQ_INFO, PERCENT_INFO);
-  }
-
-  int tokenizeMultiply(int next) {
-    // * *=
-    return select($EQ, STAR_EQ_INFO, STAR_INFO);
-  }
-
-  int tokenizeMinus(int next) {
-    // - -- -=
-    next = advance();
-    if (identical(next, $MINUS)) {
-      appendPrecedenceToken(MINUS_MINUS_INFO);
-      return advance();
-    } else if (identical(next, $EQ)) {
-      appendPrecedenceToken(MINUS_EQ_INFO);
-      return advance();
-    } else {
-      appendPrecedenceToken(MINUS_INFO);
-      return next;
-    }
-  }
-
-  int tokenizePlus(int next) {
-    // + ++ +=
-    next = advance();
-    if (identical($PLUS, next)) {
-      appendPrecedenceToken(PLUS_PLUS_INFO);
-      return advance();
-    } else if (identical($EQ, next)) {
-      appendPrecedenceToken(PLUS_EQ_INFO);
-      return advance();
-    } else {
-      appendPrecedenceToken(PLUS_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeExclamation(int next) {
-    // ! !=
-    // !== is kept for user-friendly error reporting.
-
-    next = advance();
-    if (identical(next, $EQ)) {
-      return select($EQ, BANG_EQ_EQ_INFO, BANG_EQ_INFO);
-    }
-    appendPrecedenceToken(BANG_INFO);
-    return next;
-  }
-
-  int tokenizeEquals(int next) {
-    // = == =>
-    // === is kept for user-friendly error reporting.
-
-    // Type parameters and arguments cannot contain any token that
-    // starts with '='.
-    discardOpenLt();
-
-    next = advance();
-    if (identical(next, $EQ)) {
-      return select($EQ, EQ_EQ_EQ_INFO, EQ_EQ_INFO);
-    } else if (identical(next, $GT)) {
-      appendPrecedenceToken(FUNCTION_INFO);
-      return advance();
-    }
-    appendPrecedenceToken(EQ_INFO);
-    return next;
-  }
-
-  int tokenizeGreaterThan(int next) {
-    // > >= >> >>=
-    next = advance();
-    if (identical($EQ, next)) {
-      appendPrecedenceToken(GT_EQ_INFO);
-      return advance();
-    } else if (identical($GT, next)) {
-      next = advance();
-      if (identical($EQ, next)) {
-        appendPrecedenceToken(GT_GT_EQ_INFO);
-        return advance();
-      } else {
-        appendGtGt(GT_GT_INFO);
-        return next;
-      }
-    } else {
-      appendGt(GT_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeLessThan(int next) {
-    // < <= << <<=
-    next = advance();
-    if (identical($EQ, next)) {
-      appendPrecedenceToken(LT_EQ_INFO);
-      return advance();
-    } else if (identical($LT, next)) {
-      return select($EQ, LT_LT_EQ_INFO, LT_LT_INFO);
-    } else {
-      appendBeginGroup(LT_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeNumber(int next) {
-    int start = scanOffset;
-    while (true) {
-      next = advance();
-      if ($0 <= next && next <= $9) {
-        continue;
-      } else if (identical(next, $e) || identical(next, $E)) {
-        return tokenizeFractionPart(next, start);
-      } else {
-        if (identical(next, $PERIOD)) {
-          int nextnext = peek();
-          if ($0 <= nextnext && nextnext <= $9) {
-            return tokenizeFractionPart(advance(), start);
-          }
-        }
-        appendSubstringToken(INT_INFO, start, true);
-        return next;
-      }
-    }
-    return null;
-  }
-
-  int tokenizeHexOrNumber(int next) {
-    int x = peek();
-    if (identical(x, $x) || identical(x, $X)) {
-      return tokenizeHex(next);
-    }
-    return tokenizeNumber(next);
-  }
-
-  int tokenizeHex(int next) {
-    int start = scanOffset;
-    next = advance(); // Advance past the $x or $X.
-    bool hasDigits = false;
-    while (true) {
-      next = advance();
-      if (($0 <= next && next <= $9) ||
-          ($A <= next && next <= $F) ||
-          ($a <= next && next <= $f)) {
-        hasDigits = true;
-      } else {
-        if (!hasDigits) {
-          unterminated('0x', shouldAdvance: false);
-          return next;
-        }
-        appendSubstringToken(HEXADECIMAL_INFO, start, true);
-        return next;
-      }
-    }
-    return null;
-  }
-
-  int tokenizeDotsOrNumber(int next) {
-    int start = scanOffset;
-    next = advance();
-    if (($0 <= next && next <= $9)) {
-      return tokenizeFractionPart(next, start);
-    } else if (identical($PERIOD, next)) {
-      return select($PERIOD, PERIOD_PERIOD_PERIOD_INFO, PERIOD_PERIOD_INFO);
-    } else {
-      appendPrecedenceToken(PERIOD_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeFractionPart(int next, int start) {
-    bool done = false;
-    bool hasDigit = false;
-    LOOP:
-    while (!done) {
-      if ($0 <= next && next <= $9) {
-        hasDigit = true;
-      } else if (identical($e, next) || identical($E, next)) {
-        hasDigit = true;
-        next = advance();
-        if (identical(next, $PLUS) || identical(next, $MINUS)) {
-          next = advance();
-        }
-        bool hasExponentDigits = false;
-        while (true) {
-          if ($0 <= next && next <= $9) {
-            hasExponentDigits = true;
-          } else {
-            if (!hasExponentDigits) {
-              unterminated('1e', shouldAdvance: false);
-              return next;
-            }
-            break;
-          }
-          next = advance();
-        }
-
-        done = true;
-        continue LOOP;
-      } else {
-        done = true;
-        continue LOOP;
-      }
-      next = advance();
-    }
-    if (!hasDigit) {
-      // Reduce offset, we already advanced to the token past the period.
-      appendSubstringToken(INT_INFO, start, true, -1);
-
-      // TODO(ahe): Wrong offset for the period. Cannot call beginToken because
-      // the scanner already advanced past the period.
-      if (identical($PERIOD, next)) {
-        return select($PERIOD, PERIOD_PERIOD_PERIOD_INFO, PERIOD_PERIOD_INFO);
-      }
-      appendPrecedenceToken(PERIOD_INFO);
-      return next;
-    }
-    appendSubstringToken(DOUBLE_INFO, start, true);
-    return next;
-  }
-
-  int tokenizeSlashOrComment(int next) {
-    int start = scanOffset;
-    next = advance();
-    if (identical($STAR, next)) {
-      return tokenizeMultiLineComment(next, start);
-    } else if (identical($SLASH, next)) {
-      return tokenizeSingleLineComment(next, start);
-    } else if (identical($EQ, next)) {
-      appendPrecedenceToken(SLASH_EQ_INFO);
-      return advance();
-    } else {
-      appendPrecedenceToken(SLASH_INFO);
-      return next;
-    }
-  }
-
-  int tokenizeSingleLineComment(int next, int start) {
-    bool asciiOnly = true;
-    while (true) {
-      next = advance();
-      if (next > 127) asciiOnly = false;
-      if (identical($LF, next) ||
-          identical($CR, next) ||
-          identical($EOF, next)) {
-        if (!asciiOnly) handleUnicode(start);
-        appendComment(start, asciiOnly);
-        return next;
-      }
-    }
-    return null;
-  }
-
-  int tokenizeMultiLineComment(int next, int start) {
-    bool asciiOnlyComment = true; // Track if the entire comment is ASCII.
-    bool asciiOnlyLines = true; // Track ASCII since the last handleUnicode.
-    int unicodeStart = start;
-    int nesting = 1;
-    next = advance();
-    while (true) {
-      if (identical($EOF, next)) {
-        if (!asciiOnlyLines) handleUnicode(unicodeStart);
-        unterminated('/*');
-        break;
-      } else if (identical($STAR, next)) {
-        next = advance();
-        if (identical($SLASH, next)) {
-          --nesting;
-          if (0 == nesting) {
-            if (!asciiOnlyLines) handleUnicode(unicodeStart);
-            next = advance();
-            appendComment(start, asciiOnlyComment);
-            break;
-          } else {
-            next = advance();
-          }
-        }
-      } else if (identical($SLASH, next)) {
-        next = advance();
-        if (identical($STAR, next)) {
-          next = advance();
-          ++nesting;
-        }
-      } else if (identical(next, $LF)) {
-        if (!asciiOnlyLines) {
-          // Synchronize the string offset in the utf8 scanner.
-          handleUnicode(unicodeStart);
-          asciiOnlyLines = true;
-          unicodeStart = scanOffset;
-        }
-        lineFeedInMultiline();
-        next = advance();
-      } else {
-        if (next > 127) {
-          asciiOnlyLines = false;
-          asciiOnlyComment = false;
-        }
-        next = advance();
-      }
-    }
-    return next;
-  }
-
-  int tokenizeRawStringKeywordOrIdentifier(int next) {
-    // [next] is $r.
-    int nextnext = peek();
-    if (identical(nextnext, $DQ) || identical(nextnext, $SQ)) {
-      int start = scanOffset;
-      next = advance();
-      return tokenizeString(next, start, true);
-    }
-    return tokenizeKeywordOrIdentifier(next, true);
-  }
-
-  int tokenizeKeywordOrIdentifier(int next, bool allowDollar) {
-    KeywordState state = KeywordState.KEYWORD_STATE;
-    int start = scanOffset;
-    while (state != null && $a <= next && next <= $z) {
-      state = state.next(next);
-      next = advance();
-    }
-    if (state == null || state.keyword == null) {
-      return tokenizeIdentifier(next, start, allowDollar);
-    }
-    if (($A <= next && next <= $Z) ||
-        ($0 <= next && next <= $9) ||
-        identical(next, $_) ||
-        identical(next, $$)) {
-      return tokenizeIdentifier(next, start, allowDollar);
-    } else {
-      appendKeywordToken(state.keyword);
-      return next;
-    }
-  }
-
-  /**
-   * [allowDollar] can exclude '$', which is not allowed as part of a string
-   * interpolation identifier.
-   */
-  int tokenizeIdentifier(int next, int start, bool allowDollar) {
-    while (true) {
-      if (($a <= next && next <= $z) ||
-          ($A <= next && next <= $Z) ||
-          ($0 <= next && next <= $9) ||
-          identical(next, $_) ||
-          (identical(next, $$) && allowDollar)) {
-        next = advance();
-      } else {
-        // Identifier ends here.
-        if (start == scanOffset) {
-          return unexpected(next);
-        } else {
-          appendSubstringToken(IDENTIFIER_INFO, start, true);
-        }
-        break;
-      }
-    }
-    return next;
-  }
-
-  int tokenizeAt(int next) {
-    appendPrecedenceToken(AT_INFO);
-    return advance();
-  }
-
-  int tokenizeString(int next, int start, bool raw) {
-    int quoteChar = next;
-    next = advance();
-    if (identical(quoteChar, next)) {
-      next = advance();
-      if (identical(quoteChar, next)) {
-        // Multiline string.
-        return tokenizeMultiLineString(quoteChar, start, raw);
-      } else {
-        // Empty string.
-        appendSubstringToken(STRING_INFO, start, true);
-        return next;
-      }
-    }
-    if (raw) {
-      return tokenizeSingleLineRawString(next, quoteChar, start);
-    } else {
-      return tokenizeSingleLineString(next, quoteChar, start);
-    }
-  }
-
-  /**
-   * [next] is the first character after the quote.
-   * [start] is the scanOffset of the quote.
-   *
-   * The token contains a substring of the source file, including the
-   * string quotes, backslashes for escaping. For interpolated strings,
-   * the parts before and after are separate tokens.
-   *
-   *   "a $b c"
-   *
-   * gives StringToken("a $), StringToken(b) and StringToken( c").
-   */
-  int tokenizeSingleLineString(int next, int quoteChar, int start) {
-    bool asciiOnly = true;
-    while (!identical(next, quoteChar)) {
-      if (identical(next, $BACKSLASH)) {
-        next = advance();
-      } else if (identical(next, $$)) {
-        if (!asciiOnly) handleUnicode(start);
-        next = tokenizeStringInterpolation(start, asciiOnly);
-        start = scanOffset;
-        asciiOnly = true;
-        continue;
-      }
-      if (next <= $CR &&
-          (identical(next, $LF) ||
-              identical(next, $CR) ||
-              identical(next, $EOF))) {
-        if (!asciiOnly) handleUnicode(start);
-        return unterminatedString(quoteChar);
-      }
-      if (next > 127) asciiOnly = false;
-      next = advance();
-    }
-    if (!asciiOnly) handleUnicode(start);
-    // Advance past the quote character.
-    next = advance();
-    appendSubstringToken(STRING_INFO, start, asciiOnly);
-    return next;
-  }
-
-  int tokenizeStringInterpolation(int start, bool asciiOnly) {
-    appendSubstringToken(STRING_INFO, start, asciiOnly);
-    beginToken(); // $ starts here.
-    int next = advance();
-    if (identical(next, $OPEN_CURLY_BRACKET)) {
-      return tokenizeInterpolatedExpression(next);
-    } else {
-      return tokenizeInterpolatedIdentifier(next);
-    }
-  }
-
-  int tokenizeInterpolatedExpression(int next) {
-    appendBeginGroup(STRING_INTERPOLATION_INFO);
-    beginToken(); // The expression starts here.
-    next = advance(); // Move past the curly bracket.
-    while (!identical(next, $EOF) && !identical(next, $STX)) {
-      next = bigSwitch(next);
-    }
-    if (identical(next, $EOF)) return next;
-    next = advance(); // Move past the $STX.
-    beginToken(); // The string interpolation suffix starts here.
-    return next;
-  }
-
-  int tokenizeInterpolatedIdentifier(int next) {
-    appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO);
-
-    if ($a <= next && next <= $z) {
-      beginToken(); // The identifier starts here.
-      next = tokenizeKeywordOrIdentifier(next, false);
-    } else if (($A <= next && next <= $Z) || identical(next, $_)) {
-      beginToken(); // The identifier starts here.
-      next = tokenizeIdentifier(next, scanOffset, false);
-    } else {
-      unterminated(r'$', shouldAdvance: false);
-    }
-    beginToken(); // The string interpolation suffix starts here.
-    return next;
-  }
-
-  int tokenizeSingleLineRawString(int next, int quoteChar, int start) {
-    bool asciiOnly = true;
-    while (next != $EOF) {
-      if (identical(next, quoteChar)) {
-        if (!asciiOnly) handleUnicode(start);
-        next = advance();
-        appendSubstringToken(STRING_INFO, start, asciiOnly);
-        return next;
-      } else if (identical(next, $LF) || identical(next, $CR)) {
-        if (!asciiOnly) handleUnicode(start);
-        return unterminatedRawString(quoteChar);
-      } else if (next > 127) {
-        asciiOnly = false;
-      }
-      next = advance();
-    }
-    if (!asciiOnly) handleUnicode(start);
-    return unterminatedRawString(quoteChar);
-  }
-
-  int tokenizeMultiLineRawString(int quoteChar, int start) {
-    bool asciiOnlyString = true;
-    bool asciiOnlyLine = true;
-    int unicodeStart = start;
-    int next = advance(); // Advance past the (last) quote (of three).
-    outer:
-    while (!identical(next, $EOF)) {
-      while (!identical(next, quoteChar)) {
-        if (identical(next, $LF)) {
-          if (!asciiOnlyLine) {
-            // Synchronize the string offset in the utf8 scanner.
-            handleUnicode(unicodeStart);
-            asciiOnlyLine = true;
-            unicodeStart = scanOffset;
-          }
-          lineFeedInMultiline();
-        } else if (next > 127) {
-          asciiOnlyLine = false;
-          asciiOnlyString = false;
-        }
-        next = advance();
-        if (identical(next, $EOF)) break outer;
-      }
-      next = advance();
-      if (identical(next, quoteChar)) {
-        next = advance();
-        if (identical(next, quoteChar)) {
-          if (!asciiOnlyLine) handleUnicode(unicodeStart);
-          next = advance();
-          appendSubstringToken(STRING_INFO, start, asciiOnlyString);
-          return next;
-        }
-      }
-    }
-    if (!asciiOnlyLine) handleUnicode(unicodeStart);
-    return unterminatedRawMultiLineString(quoteChar);
-  }
-
-  int tokenizeMultiLineString(int quoteChar, int start, bool raw) {
-    if (raw) return tokenizeMultiLineRawString(quoteChar, start);
-    bool asciiOnlyString = true;
-    bool asciiOnlyLine = true;
-    int unicodeStart = start;
-    int next = advance(); // Advance past the (last) quote (of three).
-    while (!identical(next, $EOF)) {
-      if (identical(next, $$)) {
-        if (!asciiOnlyLine) handleUnicode(unicodeStart);
-        next = tokenizeStringInterpolation(start, asciiOnlyString);
-        start = scanOffset;
-        unicodeStart = start;
-        asciiOnlyString = true; // A new string token is created for the rest.
-        asciiOnlyLine = true;
-        continue;
-      }
-      if (identical(next, quoteChar)) {
-        next = advance();
-        if (identical(next, quoteChar)) {
-          next = advance();
-          if (identical(next, quoteChar)) {
-            if (!asciiOnlyLine) handleUnicode(unicodeStart);
-            next = advance();
-            appendSubstringToken(STRING_INFO, start, asciiOnlyString);
-            return next;
-          }
-        }
-        continue;
-      }
-      if (identical(next, $BACKSLASH)) {
-        next = advance();
-        if (identical(next, $EOF)) break;
-      }
-      if (identical(next, $LF)) {
-        if (!asciiOnlyLine) {
-          // Synchronize the string offset in the utf8 scanner.
-          handleUnicode(unicodeStart);
-          asciiOnlyLine = true;
-          unicodeStart = scanOffset;
-        }
-        lineFeedInMultiline();
-      } else if (next > 127) {
-        asciiOnlyString = false;
-        asciiOnlyLine = false;
-      }
-      next = advance();
-    }
-    if (!asciiOnlyLine) handleUnicode(unicodeStart);
-    return unterminatedMultiLineString(quoteChar);
-  }
-
-  int unexpected(int character) {
-    appendErrorToken(new BadInputToken(character, tokenStart));
-    return advanceAfterError(true);
-  }
-
-  int unterminated(String prefix, {bool shouldAdvance: true}) {
-    appendErrorToken(new UnterminatedToken(prefix, tokenStart, stringOffset));
-    return advanceAfterError(shouldAdvance);
-  }
-
-  int unterminatedString(int quoteChar) {
-    return unterminated(new String.fromCharCodes([quoteChar]));
-  }
-
-  int unterminatedRawString(int quoteChar) {
-    return unterminated('r${new String.fromCharCodes([quoteChar])}');
-  }
-
-  int unterminatedMultiLineString(int quoteChar) {
-    return unterminated(
-        new String.fromCharCodes([quoteChar, quoteChar, quoteChar]));
-  }
-
-  int unterminatedRawMultiLineString(int quoteChar) {
-    return unterminated(
-        'r${new String.fromCharCodes([quoteChar, quoteChar, quoteChar])}');
-  }
-
-  int advanceAfterError(bool shouldAdvance) {
-    if (atEndOfFile()) return $EOF;
-    if (shouldAdvance) {
-      return advance(); // Ensure progress.
-    } else {
-      return -1;
-    }
-  }
-
-  void unmatchedBeginGroup(BeginGroupToken begin) {
-    // We want to ensure that unmatched BeginGroupTokens are reported as
-    // errors.  However, the diet parser assumes that groups are well-balanced
-    // and will never look at the endGroup token.  This is a nice property that
-    // allows us to skip quickly over correct code. By inserting an additional
-    // synthetic token in the stream, we can keep ignoring endGroup tokens.
-    //
-    // [begin] --next--> [tail]
-    // [begin] --endG--> [synthetic] --next--> [next] --next--> [tail]
-    //
-    // This allows the diet parser to skip from [begin] via endGroup to
-    // [synthetic] and ignore the [synthetic] token (assuming it's correct),
-    // then the error will be reported when parsing the [next] token.
-    //
-    // For example, tokenize("{[1};") produces:
-    //
-    // SymbolToken({) --endGroup-----+
-    //      |                        |
-    //     next                      |
-    //      v                        |
-    // SymbolToken([) --endGroup--+  |
-    //      |                     |  |
-    //     next                   |  |
-    //      v                     |  |
-    // StringToken(1)             |  |
-    //      |                     v  |
-    //     next       SymbolToken(]) | <- Synthetic token.
-    //      |                     |  |
-    //      |                   next |
-    //      v                     |  |
-    // UnmatchedToken([)<---------+  |
-    //      |                        |
-    //     next                      |
-    //      v                        |
-    // SymbolToken(})<---------------+
-    //      |
-    //     next
-    //      v
-    // SymbolToken(;)
-    //      |
-    //     next
-    //      v
-    //     EOF
-    Token synthetic =
-        new SymbolToken(closeBraceInfoFor(begin), begin.charOffset);
-    UnmatchedToken next = new UnmatchedToken(begin);
-    begin.endGroup = synthetic;
-    synthetic.next = next;
-    appendErrorToken(next);
-  }
-}
-
-PrecedenceInfo closeBraceInfoFor(BeginGroupToken begin) {
-  return const {
-    '(': CLOSE_PAREN_INFO,
-    '[': CLOSE_SQUARE_BRACKET_INFO,
-    '{': CLOSE_CURLY_BRACKET_INFO,
-    '<': GT_INFO,
-    r'${': CLOSE_CURLY_BRACKET_INFO,
-  }[begin.value];
-}
diff --git a/pkg/compiler/lib/src/scanner/scanner_task.dart b/pkg/compiler/lib/src/scanner/scanner_task.dart
index 1977248..c49621e 100644
--- a/pkg/compiler/lib/src/scanner/scanner_task.dart
+++ b/pkg/compiler/lib/src/scanner/scanner_task.dart
@@ -9,11 +9,12 @@
 import '../elements/elements.dart' show CompilationUnitElement, LibraryElement;
 import '../parser/diet_parser_task.dart' show DietParserTask;
 import '../script.dart' show Script;
-import '../tokens/token.dart' show Token;
-import '../tokens/token_constants.dart' as Tokens show COMMENT_TOKEN, EOF_TOKEN;
+import 'package:front_end/src/fasta/scanner.dart'
+    show Scanner, StringScanner, Token, Utf8BytesScanner;
+import 'package:front_end/src/fasta/scanner/token_constants.dart' as Tokens
+    show COMMENT_TOKEN, EOF_TOKEN;
 import '../tokens/token_map.dart' show TokenMap;
-import 'scanner.dart' show Scanner;
-import 'string_scanner.dart' show StringScanner;
+import '../io/source_file.dart';
 
 class ScannerTask extends CompilerTask {
   final DietParserTask _dietParser;
@@ -52,10 +53,17 @@
     });
   }
 
+  Token scanFile(SourceFile file, {bool includeComments: false}) {
+    Scanner scanner = file is Utf8BytesSourceFile
+        ? new Utf8BytesScanner(file.slowUtf8ZeroTerminatedBytes(),
+            includeComments: includeComments)
+        : new StringScanner(file.slowText(), includeComments: includeComments);
+    return measure(scanner.tokenize);
+  }
+
   void scanElements(CompilationUnitElement compilationUnit) {
     Script script = compilationUnit.script;
-    Token tokens =
-        new Scanner(script.file, includeComments: _preserveComments).tokenize();
+    Token tokens = scanFile(script.file, includeComments: _preserveComments);
     if (_preserveComments) {
       tokens = processAndStripComments(tokens);
     }
@@ -71,8 +79,7 @@
    */
   Token tokenize(String source) {
     return measure(() {
-      return new StringScanner.fromString(source, includeComments: false)
-          .tokenize();
+      return new StringScanner(source, includeComments: false).tokenize();
     });
   }
 
diff --git a/pkg/compiler/lib/src/scanner/string_scanner.dart b/pkg/compiler/lib/src/scanner/string_scanner.dart
deleted file mode 100644
index 7e1f995d..0000000
--- a/pkg/compiler/lib/src/scanner/string_scanner.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.scanner.string;
-
-import '../io/source_file.dart' show SourceFile;
-import '../tokens/precedence.dart' show PrecedenceInfo;
-import '../tokens/token.dart' show StringToken, Token;
-import 'array_based_scanner.dart' show ArrayBasedScanner;
-
-/**
- * Scanner that reads from a String and creates tokens that points to
- * substrings.
- */
-class StringScanner extends ArrayBasedScanner {
-  /** The file content. */
-  String string;
-
-  /** The current offset in [string]. */
-  int scanOffset = -1;
-
-  StringScanner(SourceFile file, {bool includeComments: false})
-      : string = file.slowText(),
-        super(file, includeComments) {
-    ensureZeroTermination();
-  }
-
-  StringScanner.fromString(this.string, {bool includeComments: false})
-      : super(null, includeComments) {
-    ensureZeroTermination();
-  }
-
-  void ensureZeroTermination() {
-    if (string.isEmpty || string.codeUnitAt(string.length - 1) != 0) {
-      // TODO(lry): abort instead of copying the array, or warn?
-      string = string + '\x00';
-    }
-  }
-
-  int advance() => string.codeUnitAt(++scanOffset);
-  int peek() => string.codeUnitAt(scanOffset + 1);
-
-  int get stringOffset => scanOffset;
-
-  int currentAsUnicode(int next) => next;
-
-  void handleUnicode(int startScanOffset) {}
-
-  Token firstToken() => tokens.next;
-  Token previousToken() => tail;
-
-  void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
-      [int extraOffset = 0]) {
-    tail.next = new StringToken.fromSubstring(
-        info, string, start, scanOffset + extraOffset, tokenStart,
-        canonicalize: true);
-    tail = tail.next;
-  }
-
-  bool atEndOfFile() => scanOffset >= string.length - 1;
-}
diff --git a/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart b/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
deleted file mode 100644
index ea46e35..0000000
--- a/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.scanner.utf8;
-
-import 'dart:convert' show UNICODE_BOM_CHARACTER_RUNE, UTF8;
-
-import '../io/source_file.dart' show SourceFile;
-import '../tokens/precedence.dart' show PrecedenceInfo;
-import '../tokens/token.dart' show StringToken, Token;
-import 'array_based_scanner.dart' show ArrayBasedScanner;
-
-/**
- * Scanner that reads from a UTF-8 encoded list of bytes and creates tokens
- * that points to substrings.
- */
-class Utf8BytesScanner extends ArrayBasedScanner {
-  /**
-   * The file content.
-   *
-   * The content is zero-terminated.
-   */
-  List<int> bytes;
-
-  /**
-   * Points to the offset of the last byte returned by [advance].
-   *
-   * After invoking [currentAsUnicode], the [byteOffset] points to the last
-   * byte that is part of the (unicode or ASCII) character. That way, [advance]
-   * can always increase the byte offset by 1.
-   */
-  int byteOffset = -1;
-
-  /**
-   * The getter [scanOffset] is expected to return the index where the current
-   * character *starts*. In case of a non-ascii character, after invoking
-   * [currentAsUnicode], the byte offset points to the *last* byte.
-   *
-   * This field keeps track of the number of bytes for the current unicode
-   * character. For example, if bytes 7,8,9 encode one unicode character, the
-   * [byteOffset] is 9 (after invoking [currentAsUnicode]). The [scanSlack]
-   * will be 2, so that [scanOffset] returns 7.
-   */
-  int scanSlack = 0;
-
-  /**
-   * Holds the [byteOffset] value for which the current [scanSlack] is valid.
-   */
-  int scanSlackOffset = -1;
-
-  /**
-   * Returns the byte offset of the first byte that belongs to the current
-   * character.
-   */
-  int get scanOffset {
-    if (byteOffset == scanSlackOffset) {
-      return byteOffset - scanSlack;
-    } else {
-      return byteOffset;
-    }
-  }
-
-  /**
-   * The difference between the number of bytes and the number of corresponding
-   * string characters, up to the current [byteOffset].
-   */
-  int utf8Slack = 0;
-
-  /**
-   * Creates a new Utf8BytesScanner. The source file is expected to be a
-   * [Utf8BytesSourceFile] that holds a list of UTF-8 bytes. Otherwise the
-   * string text of the source file is decoded.
-   *
-   * The list of UTF-8 bytes [file.slowUtf8Bytes()] is expected to return an
-   * array whose last element is '0' to signal the end of the file. If this
-   * is not the case, the entire array is copied before scanning.
-   */
-  Utf8BytesScanner(SourceFile file, {bool includeComments: false})
-      : bytes = file.slowUtf8ZeroTerminatedBytes(),
-        super(file, includeComments) {
-    assert(bytes.last == 0);
-    // Skip a leading BOM.
-    if (_containsBomAt(0)) byteOffset += 3;
-  }
-
-  /**
-   * Creates a new Utf8BytesScanner from a list of UTF-8 bytes.
-   *
-   * The last element of the list is expected to be '0' to signal the end of
-   * the file. If this is not the case, the entire array is copied before
-   * scanning.
-   */
-  Utf8BytesScanner.fromBytes(List<int> zeroTerminatedBytes,
-      {bool includeComments: false})
-      : this.bytes = zeroTerminatedBytes,
-        super(null, includeComments) {
-    assert(bytes.last == 0);
-  }
-
-  bool _containsBomAt(int offset) {
-    const BOM_UTF8 = const [0xEF, 0xBB, 0xBF];
-
-    return offset + 3 < bytes.length &&
-        bytes[offset] == BOM_UTF8[0] &&
-        bytes[offset + 1] == BOM_UTF8[1] &&
-        bytes[offset + 2] == BOM_UTF8[2];
-  }
-
-  int advance() => bytes[++byteOffset];
-
-  int peek() => bytes[byteOffset + 1];
-
-  /**
-   * Returns the unicode code point starting at the byte offset [startOffset]
-   * with the byte [nextByte]. If [advance] is true the current [byteOffset]
-   * is advanced to the last byte of the code point.
-   */
-  int nextCodePoint(int startOffset, int nextByte, bool advance) {
-    // The number of 1s in the first byte indicate the number of bytes, at
-    // least 2.
-    int numBytes = 2;
-    int bit = 0x20;
-    while ((nextByte & bit) != 0) {
-      numBytes++;
-      bit >>= 1;
-    }
-    int end = startOffset + numBytes;
-    if (advance) {
-      byteOffset = end - 1;
-    }
-    // TODO(lry): measurably slow, decode creates first a Utf8Decoder and a
-    // _Utf8Decoder instance. Also the sublist is eagerly allocated.
-    String codePoint = UTF8.decode(bytes.sublist(startOffset, end));
-    if (codePoint.length == 0) {
-      // The UTF-8 decoder discards leading BOM characters.
-      // TODO(floitsch): don't just assume that removed characters were the
-      // BOM.
-      assert(_containsBomAt(startOffset));
-      codePoint = new String.fromCharCode(UNICODE_BOM_CHARACTER_RUNE);
-    }
-    if (codePoint.length == 1) {
-      if (advance) {
-        utf8Slack += (numBytes - 1);
-        scanSlack = numBytes - 1;
-        scanSlackOffset = byteOffset;
-      }
-      return codePoint.codeUnitAt(0);
-    } else if (codePoint.length == 2) {
-      if (advance) {
-        utf8Slack += (numBytes - 2);
-        scanSlack = numBytes - 1;
-        scanSlackOffset = byteOffset;
-        stringOffsetSlackOffset = byteOffset;
-      }
-      // In case of a surrogate pair, return a single code point.
-      return codePoint.runes.single;
-    } else {
-      throw "Invalid UTF-8 byte sequence: ${bytes.sublist(startOffset, end)}";
-    }
-  }
-
-  int lastUnicodeOffset = -1;
-  int currentAsUnicode(int next) {
-    if (next < 128) return next;
-    // Check if currentAsUnicode was already invoked.
-    if (byteOffset == lastUnicodeOffset) return next;
-    int res = nextCodePoint(byteOffset, next, true);
-    lastUnicodeOffset = byteOffset;
-    return res;
-  }
-
-  void handleUnicode(int startScanOffset) {
-    int end = byteOffset;
-    // TODO(lry): this measurably slows down the scanner for files with unicode.
-    String s = UTF8.decode(bytes.sublist(startScanOffset, end));
-    utf8Slack += (end - startScanOffset) - s.length;
-  }
-
-  /**
-   * This field remembers the byte offset of the last character decoded with
-   * [nextCodePoint] that used two code units in UTF-16.
-   *
-   * [nextCodePoint] returns a single code point for each unicode character,
-   * even if it needs two code units in UTF-16.
-   *
-   * For example, '\u{1d11e}' uses 4 bytes in UTF-8, and two code units in
-   * UTF-16. The [utf8Slack] is therefore 2. After invoking [nextCodePoint], the
-   * [byteOffset] points to the last (of 4) bytes. The [stringOffset] should
-   * return the offset of the first one, which is one position more left than
-   * the [utf8Slack].
-   */
-  int stringOffsetSlackOffset = -1;
-
-  int get stringOffset {
-    if (stringOffsetSlackOffset == byteOffset) {
-      return byteOffset - utf8Slack - 1;
-    } else {
-      return byteOffset - utf8Slack;
-    }
-  }
-
-  Token firstToken() => tokens.next;
-  Token previousToken() => tail;
-
-  void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
-      [int extraOffset = 0]) {
-    tail.next = new StringToken.fromUtf8Bytes(
-        info, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
-    tail = tail.next;
-  }
-
-  bool atEndOfFile() => byteOffset >= bytes.length - 1;
-}
diff --git a/pkg/compiler/lib/src/serialization/constant_serialization.dart b/pkg/compiler/lib/src/serialization/constant_serialization.dart
index a3025c2..28daa36 100644
--- a/pkg/compiler/lib/src/serialization/constant_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/constant_serialization.dart
@@ -7,7 +7,8 @@
 import '../constants/constructors.dart';
 import '../constants/expressions.dart';
 import '../elements/resolution_types.dart';
-import '../elements/elements.dart' show FieldElement;
+import '../elements/elements.dart'
+    show ConstructorElement, FieldElement, LocalVariableElement, MethodElement;
 import '../resolution/operators.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import 'keys.dart';
@@ -48,15 +49,18 @@
   @override
   void visitConstructed(
       ConstructedConstantExpression exp, ObjectEncoder encoder) {
-    encoder.setElement(Key.ELEMENT, exp.target);
-    encoder.setType(Key.TYPE, exp.type);
+    ConstructorElement constructor = exp.target;
+    ResolutionInterfaceType type = exp.type;
+    encoder.setElement(Key.ELEMENT, constructor);
+    encoder.setType(Key.TYPE, type);
     encoder.setStrings(Key.NAMES, exp.callStructure.namedArguments);
     encoder.setConstants(Key.ARGUMENTS, exp.arguments);
   }
 
   @override
   void visitFunction(FunctionConstantExpression exp, ObjectEncoder encoder) {
-    encoder.setElement(Key.ELEMENT, exp.element);
+    MethodElement function = exp.element;
+    encoder.setElement(Key.ELEMENT, function);
   }
 
   @override
@@ -67,13 +71,15 @@
 
   @override
   void visitList(ListConstantExpression exp, ObjectEncoder encoder) {
-    encoder.setType(Key.TYPE, exp.type);
+    ResolutionInterfaceType type = exp.type;
+    encoder.setType(Key.TYPE, type);
     encoder.setConstants(Key.VALUES, exp.values);
   }
 
   @override
   void visitMap(MapConstantExpression exp, ObjectEncoder encoder) {
-    encoder.setType(Key.TYPE, exp.type);
+    ResolutionInterfaceType type = exp.type;
+    encoder.setType(Key.TYPE, type);
     encoder.setConstants(Key.KEYS, exp.keys);
     encoder.setConstants(Key.VALUES, exp.values);
   }
@@ -111,6 +117,7 @@
   @override
   void visitType(TypeConstantExpression exp, ObjectEncoder encoder) {
     encoder.setType(Key.TYPE, exp.type);
+    encoder.setString(Key.NAME, exp.name);
   }
 
   @override
@@ -120,8 +127,16 @@
   }
 
   @override
-  void visitVariable(VariableConstantExpression exp, ObjectEncoder encoder) {
-    encoder.setElement(Key.ELEMENT, exp.element);
+  void visitField(FieldConstantExpression exp, ObjectEncoder encoder) {
+    FieldElement field = exp.element;
+    encoder.setElement(Key.ELEMENT, field);
+  }
+
+  @override
+  void visitLocalVariable(
+      LocalVariableConstantExpression exp, ObjectEncoder encoder) {
+    LocalVariableElement local = exp.element;
+    encoder.setElement(Key.ELEMENT, local);
   }
 
   @override
@@ -208,20 +223,20 @@
             decoder.getConstant(Key.TRUE),
             decoder.getConstant(Key.FALSE));
       case ConstantExpressionKind.CONSTRUCTED:
+        ResolutionInterfaceType type = decoder.getType(Key.TYPE);
+        ConstructorElement constructor = decoder.getElement(Key.ELEMENT);
         List<String> names = decoder.getStrings(Key.NAMES, isOptional: true);
         List<ConstantExpression> arguments =
             decoder.getConstants(Key.ARGUMENTS, isOptional: true);
-        return new ConstructedConstantExpression(
-            decoder.getType(Key.TYPE),
-            decoder.getElement(Key.ELEMENT),
-            new CallStructure(arguments.length, names),
-            arguments);
+        return new ConstructedConstantExpression(type, constructor,
+            new CallStructure(arguments.length, names), arguments);
       case ConstantExpressionKind.DOUBLE:
         return new DoubleConstantExpression(decoder.getDouble(Key.VALUE));
       case ConstantExpressionKind.ERRONEOUS:
         break;
       case ConstantExpressionKind.FUNCTION:
-        return new FunctionConstantExpression(decoder.getElement(Key.ELEMENT));
+        MethodElement function = decoder.getElement(Key.ELEMENT);
+        return new FunctionConstantExpression(function, function.type);
       case ConstantExpressionKind.IDENTICAL:
         return new IdenticalConstantExpression(
             decoder.getConstant(Key.LEFT), decoder.getConstant(Key.RIGHT));
@@ -232,11 +247,13 @@
             decoder.getConstant(Key.NAME),
             decoder.getConstant(Key.DEFAULT, isOptional: true));
       case ConstantExpressionKind.LIST:
-        return new ListConstantExpression(decoder.getType(Key.TYPE),
-            decoder.getConstants(Key.VALUES, isOptional: true));
+        ResolutionInterfaceType type = decoder.getType(Key.TYPE);
+        return new ListConstantExpression(
+            type, decoder.getConstants(Key.VALUES, isOptional: true));
       case ConstantExpressionKind.MAP:
+        ResolutionInterfaceType type = decoder.getType(Key.TYPE);
         return new MapConstantExpression(
-            decoder.getType(Key.TYPE),
+            type,
             decoder.getConstants(Key.KEYS, isOptional: true),
             decoder.getConstants(Key.VALUES, isOptional: true));
       case ConstantExpressionKind.NULL:
@@ -253,14 +270,19 @@
       case ConstantExpressionKind.SYMBOL:
         return new SymbolConstantExpression(decoder.getString(Key.NAME));
       case ConstantExpressionKind.TYPE:
-        return new TypeConstantExpression(decoder.getType(Key.TYPE));
+        return new TypeConstantExpression(
+            decoder.getType(Key.TYPE), decoder.getString(Key.NAME));
       case ConstantExpressionKind.UNARY:
         UnaryOperator operator = UnaryOperator
             .fromKind(decoder.getEnum(Key.OPERATOR, UnaryOperatorKind.values));
         return new UnaryConstantExpression(
             operator, decoder.getConstant(Key.EXPRESSION));
-      case ConstantExpressionKind.VARIABLE:
-        return new VariableConstantExpression(decoder.getElement(Key.ELEMENT));
+      case ConstantExpressionKind.FIELD:
+        FieldElement field = decoder.getElement(Key.ELEMENT);
+        return new FieldConstantExpression(field);
+      case ConstantExpressionKind.LOCAL_VARIABLE:
+        LocalVariableElement local = decoder.getElement(Key.ELEMENT);
+        return new LocalVariableConstantExpression(local);
 
       case ConstantExpressionKind.POSITIONAL_REFERENCE:
         return new PositionalArgumentReference(decoder.getInt(Key.INDEX));
@@ -296,7 +318,8 @@
   @override
   void visitGenerative(
       GenerativeConstantConstructor constructor, ObjectEncoder encoder) {
-    encoder.setType(Key.TYPE, constructor.type);
+    ResolutionInterfaceType type = constructor.type;
+    encoder.setType(Key.TYPE, type);
     MapEncoder defaults = encoder.createMap(Key.DEFAULTS);
     constructor.defaultValues.forEach((key, e) {
       defaults.setConstant('$key', e);
@@ -389,8 +412,9 @@
 
     switch (kind) {
       case ConstantConstructorKind.GENERATIVE:
-        return new GenerativeConstantConstructor(readType(), readDefaults(),
-            readFields(), readConstructorInvocation());
+        ResolutionInterfaceType type = readType();
+        return new GenerativeConstantConstructor(
+            type, readDefaults(), readFields(), readConstructorInvocation());
       case ConstantConstructorKind.REDIRECTING_GENERATIVE:
         return new RedirectingGenerativeConstantConstructor(
             readDefaults(), readConstructorInvocation());
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index f3fc4f1..3fd3f45 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -12,6 +12,8 @@
 import '../constants/values.dart';
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
+import '../elements/types.dart';
 import '../elements/visitor.dart';
 import '../js_backend/backend_serialization.dart'
     show NativeBehaviorSerialization;
@@ -19,7 +21,7 @@
 import '../resolution/access_semantics.dart';
 import '../resolution/send_structure.dart';
 import '../resolution/tree_elements.dart';
-import '../tokens/token.dart';
+import 'package:front_end/src/fasta/scanner.dart';
 import '../tree/nodes.dart';
 import '../universe/selector.dart';
 import '../universe/feature.dart';
@@ -27,6 +29,8 @@
 import '../util/util.dart';
 import 'resolved_ast_serialization.dart';
 
+typedef bool Equivalence<E>(E a, E b, {TestStrategy strategy});
+
 /// Equality based equivalence function.
 bool equality(a, b) => a == b;
 
@@ -90,31 +94,36 @@
 }
 
 /// Returns `true` if elements [a] and [b] are equivalent.
-bool areElementsEquivalent(Element a, Element b) {
+bool areElementsEquivalent(Element a, Element b, {TestStrategy strategy}) {
   if (identical(a, b)) return true;
   if (a == null || b == null) return false;
-  return const ElementIdentityEquivalence().visit(a, b);
+  return new ElementIdentityEquivalence(strategy ?? const TestStrategy())
+      .visit(a, b);
 }
 
 /// Returns `true` if types [a] and [b] are equivalent.
-bool areTypesEquivalent(ResolutionDartType a, ResolutionDartType b) {
+bool areTypesEquivalent(DartType a, DartType b, {TestStrategy strategy}) {
   if (identical(a, b)) return true;
   if (a == null || b == null) return false;
-  return const TypeEquivalence().visit(a, b);
+  return new TypeEquivalence(strategy ?? const TestStrategy()).visit(a, b);
 }
 
 /// Returns `true` if constants [exp1] and [exp2] are equivalent.
-bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2) {
+bool areConstantsEquivalent(ConstantExpression exp1, ConstantExpression exp2,
+    {TestStrategy strategy}) {
   if (identical(exp1, exp2)) return true;
   if (exp1 == null || exp2 == null) return false;
-  return const ConstantEquivalence().visit(exp1, exp2);
+  return new ConstantEquivalence(strategy ?? const TestStrategy())
+      .visit(exp1, exp2);
 }
 
 /// Returns `true` if constant values [value1] and [value2] are equivalent.
-bool areConstantValuesEquivalent(ConstantValue value1, ConstantValue value2) {
+bool areConstantValuesEquivalent(ConstantValue value1, ConstantValue value2,
+    {TestStrategy strategy}) {
   if (identical(value1, value2)) return true;
   if (value1 == null || value2 == null) return false;
-  return const ConstantValueEquivalence().visit(value1, value2);
+  return new ConstantValueEquivalence(strategy ?? const TestStrategy())
+      .visit(value1, value2);
 }
 
 /// Returns `true` if the lists of elements, [a] and [b], are equivalent.
@@ -141,48 +150,54 @@
 }
 
 /// Returns `true` if the selectors [a] and [b] are equivalent.
-bool areSelectorsEquivalent(Selector a, Selector b) {
+bool areSelectorsEquivalent(Selector a, Selector b,
+    {TestStrategy strategy: const TestStrategy()}) {
   if (identical(a, b)) return true;
   if (a == null || b == null) return false;
   return a.kind == b.kind &&
       a.callStructure == b.callStructure &&
-      areNamesEquivalent(a.memberName, b.memberName);
+      areNamesEquivalent(a.memberName, b.memberName, strategy: strategy);
 }
 
 /// Returns `true` if the names [a] and [b] are equivalent.
-bool areNamesEquivalent(Name a, Name b) {
-  LibraryElement library1 = a.library;
-  LibraryElement library2 = b.library;
+bool areNamesEquivalent(Name a, Name b,
+    {TestStrategy strategy: const TestStrategy()}) {
   return a.text == b.text &&
       a.isSetter == b.isSetter &&
-      areElementsEquivalent(library1, library2);
+      strategy.testElements(a, b, 'library', a.library, b.library);
 }
 
 /// Returns `true` if the dynamic uses [a] and [b] are equivalent.
-bool areDynamicUsesEquivalent(DynamicUse a, DynamicUse b) {
-  return areSelectorsEquivalent(a.selector, b.selector);
+bool areDynamicUsesEquivalent(DynamicUse a, DynamicUse b,
+    {TestStrategy strategy: const TestStrategy()}) {
+  return areSelectorsEquivalent(a.selector, b.selector, strategy: strategy);
 }
 
 /// Returns `true` if the static uses [a] and [b] are equivalent.
-bool areStaticUsesEquivalent(StaticUse a, StaticUse b) {
-  return a.kind == b.kind && areElementsEquivalent(a.element, b.element);
+bool areStaticUsesEquivalent(StaticUse a, StaticUse b,
+    {TestStrategy strategy: const TestStrategy()}) {
+  return a.kind == b.kind &&
+      strategy.testElements(a, b, 'element', a.element, b.element);
 }
 
 /// Returns `true` if the type uses [a] and [b] are equivalent.
-bool areTypeUsesEquivalent(TypeUse a, TypeUse b) {
-  return a.kind == b.kind && areTypesEquivalent(a.type, b.type);
+bool areTypeUsesEquivalent(TypeUse a, TypeUse b,
+    {TestStrategy strategy: const TestStrategy()}) {
+  return a.kind == b.kind && strategy.testTypes(a, b, 'type', a.type, b.type);
 }
 
 /// Returns `true` if the list literal uses [a] and [b] are equivalent.
-bool areListLiteralUsesEquivalent(ListLiteralUse a, ListLiteralUse b) {
-  return areTypesEquivalent(a.type, b.type) &&
+bool areListLiteralUsesEquivalent(ListLiteralUse a, ListLiteralUse b,
+    {TestStrategy strategy: const TestStrategy()}) {
+  return strategy.testTypes(a, b, 'type', a.type, b.type) &&
       a.isConstant == b.isConstant &&
       a.isEmpty == b.isEmpty;
 }
 
 /// Returns `true` if the map literal uses [a] and [b] are equivalent.
-bool areMapLiteralUsesEquivalent(MapLiteralUse a, MapLiteralUse b) {
-  return areTypesEquivalent(a.type, b.type) &&
+bool areMapLiteralUsesEquivalent(MapLiteralUse a, MapLiteralUse b,
+    {TestStrategy strategy: const TestStrategy()}) {
+  return strategy.testTypes(a, b, 'type', a.type, b.type) &&
       a.isConstant == b.isConstant &&
       a.isEmpty == b.isEmpty;
 }
@@ -331,7 +346,19 @@
 ///
 /// Use this strategy to determine equivalence without failing on inequivalence.
 class TestStrategy {
-  const TestStrategy();
+  final Equivalence<Entity> elementEquivalence;
+  final Equivalence<DartType> typeEquivalence;
+  final Equivalence<ConstantExpression> constantEquivalence;
+  final Equivalence<ConstantValue> constantValueEquivalence;
+
+  const TestStrategy(
+      {this.elementEquivalence: areElementsEquivalent,
+      this.typeEquivalence: areTypesEquivalent,
+      this.constantEquivalence: areConstantsEquivalent,
+      this.constantValueEquivalence: areConstantValuesEquivalent});
+
+  /// An equivalence [TestStrategy] that doesn't throw on inequivalence.
+  TestStrategy get testOnly => this;
 
   bool test(var object1, var object2, String property, var value1, var value2,
       [bool equivalence(a, b) = equality]) {
@@ -357,38 +384,45 @@
   }
 
   bool testElements(Object object1, Object object2, String property,
-      Element element1, Element element2) {
-    return areElementsEquivalent(element1, element2);
+      Entity element1, Entity element2) {
+    return test(object1, object2, property, element1, element2,
+        (a, b) => elementEquivalence(a, b, strategy: this));
   }
 
   bool testTypes(Object object1, Object object2, String property,
-      ResolutionDartType type1, ResolutionDartType type2) {
-    return areTypesEquivalent(type1, type2);
+      DartType type1, DartType type2) {
+    return test(object1, object2, property, type1, type2,
+        (a, b) => typeEquivalence(a, b, strategy: this));
   }
 
   bool testConstants(Object object1, Object object2, String property,
       ConstantExpression exp1, ConstantExpression exp2) {
-    return areConstantsEquivalent(exp1, exp2);
+    return test(object1, object2, property, exp1, exp2,
+        (a, b) => constantEquivalence(a, b, strategy: this));
   }
 
   bool testConstantValues(Object object1, Object object2, String property,
       ConstantValue value1, ConstantValue value2) {
-    return areConstantValuesEquivalent(value1, value2);
+    return test(object1, object2, property, value1, value2,
+        (a, b) => constantValueEquivalence(a, b, strategy: this));
   }
 
   bool testTypeLists(Object object1, Object object2, String property,
-      List<ResolutionDartType> list1, List<ResolutionDartType> list2) {
-    return areTypeListsEquivalent(list1, list2);
+      List<DartType> list1, List<DartType> list2) {
+    return testLists(object1, object2, property, list1, list2,
+        (a, b) => typeEquivalence(a, b, strategy: this));
   }
 
   bool testConstantLists(Object object1, Object object2, String property,
       List<ConstantExpression> list1, List<ConstantExpression> list2) {
-    return areConstantListsEquivalent(list1, list2);
+    return testLists(object1, object2, property, list1, list2,
+        (a, b) => constantEquivalence(a, b, strategy: this));
   }
 
   bool testConstantValueLists(Object object1, Object object2, String property,
       List<ConstantValue> list1, List<ConstantValue> list2) {
-    return areConstantValueListsEquivalent(list1, list2);
+    return testLists(object1, object2, property, list1, list2,
+        (a, b) => constantValueEquivalence(a, b, strategy: this));
   }
 
   bool testNodes(
@@ -519,9 +553,11 @@
   bool visitLocalFunctionElement(
       LocalFunctionElement element1, LocalFunctionElement element2) {
     // TODO(johnniwinther): Define an equivalence on locals.
+    MemberElement member1 = element1.memberContext;
+    MemberElement member2 = element2.memberContext;
     return strategy.test(
             element1, element2, 'name', element1.name, element2.name) &&
-        checkMembers(element1.memberContext, element2.memberContext);
+        checkMembers(member1, member2);
   }
 
   @override
@@ -774,8 +810,14 @@
   }
 
   @override
-  bool visitVariable(
-      VariableConstantExpression exp1, VariableConstantExpression exp2) {
+  bool visitField(FieldConstantExpression exp1, FieldConstantExpression exp2) {
+    return strategy.testElements(
+        exp1, exp2, 'element', exp1.element, exp2.element);
+  }
+
+  @override
+  bool visitLocalVariable(LocalVariableConstantExpression exp1,
+      LocalVariableConstantExpression exp2) {
     return strategy.testElements(
         exp1, exp2, 'element', exp1.element, exp2.element);
   }
@@ -981,7 +1023,7 @@
 /// Tests the equivalence of [impact1] and [impact2] using [strategy].
 bool testResolutionImpactEquivalence(
     ResolutionImpact impact1, ResolutionImpact impact2,
-    [TestStrategy strategy = const TestStrategy()]) {
+    {TestStrategy strategy = const TestStrategy()}) {
   return strategy.testSets(impact1, impact2, 'constSymbolNames',
           impact1.constSymbolNames, impact2.constSymbolNames) &&
       strategy.testSets(
@@ -991,20 +1033,54 @@
           impact1.constantLiterals,
           impact2.constantLiterals,
           areConstantsEquivalent) &&
-      strategy.testSets(impact1, impact2, 'dynamicUses', impact1.dynamicUses,
-          impact2.dynamicUses, areDynamicUsesEquivalent) &&
+      strategy.testSets(
+          impact1,
+          impact2,
+          'dynamicUses',
+          impact1.dynamicUses,
+          impact2.dynamicUses,
+          (a, b) =>
+              areDynamicUsesEquivalent(a, b, strategy: strategy.testOnly)) &&
       strategy.testSets(
           impact1, impact2, 'features', impact1.features, impact2.features) &&
-      strategy.testSets(impact1, impact2, 'listLiterals', impact1.listLiterals,
-          impact2.listLiterals, areListLiteralUsesEquivalent) &&
-      strategy.testSets(impact1, impact2, 'mapLiterals', impact1.mapLiterals,
-          impact2.mapLiterals, areMapLiteralUsesEquivalent) &&
-      strategy.testSets(impact1, impact2, 'staticUses', impact1.staticUses,
-          impact2.staticUses, areStaticUsesEquivalent) &&
-      strategy.testSets(impact1, impact2, 'typeUses', impact1.typeUses,
-          impact2.typeUses, areTypeUsesEquivalent) &&
-      strategy.testSets(impact1, impact2, 'nativeData', impact1.nativeData,
-          impact2.nativeData, testNativeBehavior);
+      strategy.testSets(
+          impact1,
+          impact2,
+          'listLiterals',
+          impact1.listLiterals,
+          impact2.listLiterals,
+          (a, b) => areListLiteralUsesEquivalent(a, b,
+              strategy: strategy.testOnly)) &&
+      strategy.testSets(
+          impact1,
+          impact2,
+          'mapLiterals',
+          impact1.mapLiterals,
+          impact2.mapLiterals,
+          (a, b) =>
+              areMapLiteralUsesEquivalent(a, b, strategy: strategy.testOnly)) &&
+      strategy.testSets(
+          impact1,
+          impact2,
+          'staticUses',
+          impact1.staticUses,
+          impact2.staticUses,
+          (a, b) =>
+              areStaticUsesEquivalent(a, b, strategy: strategy.testOnly)) &&
+      strategy.testSets(
+          impact1,
+          impact2,
+          'typeUses',
+          impact1.typeUses,
+          impact2.typeUses,
+          (a, b) => areTypeUsesEquivalent(a, b, strategy: strategy.testOnly)) &&
+      strategy.testSets(
+          impact1,
+          impact2,
+          'nativeData',
+          impact1.nativeData,
+          impact2.nativeData,
+          (a, b) => testNativeBehavior(a, b, strategy: strategy));
 }
 
 /// Tests the equivalence of [resolvedAst1] and [resolvedAst2] using [strategy].
@@ -1072,7 +1148,7 @@
 }
 
 bool testNativeBehavior(NativeBehavior a, NativeBehavior b,
-    [TestStrategy strategy = const TestStrategy()]) {
+    {TestStrategy strategy = const TestStrategy()}) {
   if (identical(a, b)) return true;
   if (a == null || b == null) return false;
   return strategy.test(
@@ -1159,7 +1235,7 @@
     if (identical(a, b)) return true;
     if (a == null || b == null) return false;
     if (a is NativeBehavior && b is NativeBehavior) {
-      return testNativeBehavior(a, b, strategy);
+      return testNativeBehavior(a, b, strategy: strategy);
     }
     return true;
   }
@@ -1367,7 +1443,10 @@
         (Token t1, Token t2) {
       if (t1 == t2) return true;
       if (t1 == null || t2 == null) return false;
-      return strategy.test(t1, t2, 'hashCode', t1.hashCode, t2.hashCode);
+      return strategy.test(
+              t1, t2, 'charOffset', t1.charOffset, t2.charOffset) &&
+          strategy.test(t1, t2, 'info', t1.info, t2.info) &&
+          strategy.test(t1, t2, 'value', t1.value, t2.value);
     });
   }
 
diff --git a/pkg/compiler/lib/src/serialization/impact_serialization.dart b/pkg/compiler/lib/src/serialization/impact_serialization.dart
index 3b8e4b1..a83d308 100644
--- a/pkg/compiler/lib/src/serialization/impact_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/impact_serialization.dart
@@ -44,7 +44,8 @@
       ListEncoder encoder = objectEncoder.createList(Key.LISTS);
       for (ListLiteralUse use in resolutionImpact.listLiterals) {
         ObjectEncoder useEncoder = encoder.createObject();
-        useEncoder.setType(Key.TYPE, use.type);
+        ResolutionInterfaceType type = use.type;
+        useEncoder.setType(Key.TYPE, type);
         useEncoder.setBool(Key.IS_CONST, use.isConstant);
         useEncoder.setBool(Key.IS_EMPTY, use.isEmpty);
       }
@@ -53,7 +54,8 @@
       ListEncoder encoder = objectEncoder.createList(Key.MAPS);
       for (MapLiteralUse use in resolutionImpact.mapLiterals) {
         ObjectEncoder useEncoder = encoder.createObject();
-        useEncoder.setType(Key.TYPE, use.type);
+        ResolutionInterfaceType type = use.type;
+        useEncoder.setType(Key.TYPE, type);
         useEncoder.setBool(Key.IS_CONST, use.isConstant);
         useEncoder.setBool(Key.IS_EMPTY, use.isEmpty);
       }
@@ -174,7 +176,7 @@
       listLiterals = <ListLiteralUse>[];
       for (int i = 0; i < listLiteralDecoder.length; i++) {
         ObjectDecoder useDecoder = listLiteralDecoder.getObject(i);
-        ResolutionDartType type = useDecoder.getType(Key.TYPE);
+        ResolutionInterfaceType type = useDecoder.getType(Key.TYPE);
         bool isConstant = useDecoder.getBool(Key.IS_CONST);
         bool isEmpty = useDecoder.getBool(Key.IS_EMPTY);
         listLiterals.add(
@@ -189,7 +191,7 @@
       mapLiterals = <MapLiteralUse>[];
       for (int i = 0; i < mapLiteralDecoder.length; i++) {
         ObjectDecoder useDecoder = mapLiteralDecoder.getObject(i);
-        ResolutionDartType type = useDecoder.getType(Key.TYPE);
+        ResolutionInterfaceType type = useDecoder.getType(Key.TYPE);
         bool isConstant = useDecoder.getBool(Key.IS_CONST);
         bool isEmpty = useDecoder.getBool(Key.IS_EMPTY);
         mapLiterals.add(
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index e1fb5d0..40d57ee 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -25,7 +25,7 @@
 import '../resolution/tree_elements.dart' show TreeElements;
 import '../script.dart';
 import '../serialization/constant_serialization.dart';
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../tree/tree.dart';
 import '../util/util.dart' show Link, LinkBuilder;
 import 'keys.dart';
@@ -418,9 +418,6 @@
   Element get enclosingElement => null;
 
   @override
-  String get name => entryCompilationUnit.name;
-
-  @override
   SourceSpan get sourcePosition => entryCompilationUnit.sourcePosition;
 
   @override
@@ -1571,11 +1568,6 @@
 
   @override
   bool get isInjected => _decoder.getBool(Key.IS_INJECTED);
-
-  @override
-  void forgetElement() {
-    nestedClosures.clear();
-  }
 }
 
 abstract class FieldElementZ extends DeserializedElementZ
diff --git a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
index 85044fb..c81aec5 100644
--- a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
@@ -11,16 +11,14 @@
 import '../diagnostics/diagnostic_listener.dart';
 import '../elements/elements.dart';
 import '../elements/modelx.dart';
-import '../parser/listener.dart' show ParserError;
+import 'package:front_end/src/fasta/parser.dart' show Parser, ParserError;
 import '../parser/node_listener.dart' show NodeListener;
-import '../parser/parser.dart' show Parser;
 import '../resolution/enum_creator.dart';
 import '../resolution/send_structure.dart';
 import '../resolution/tree_elements.dart';
-import '../tokens/token.dart';
+import 'package:front_end/src/fasta/scanner.dart';
 import '../tree/tree.dart';
 import '../universe/selector.dart';
-import '../util/util.dart';
 import 'keys.dart';
 import 'modelz.dart';
 import 'serialization.dart';
@@ -374,7 +372,6 @@
       ParsingContext parsing,
       Token getBeginToken(Uri uri, int charOffset),
       DeserializerPlugin nativeDataDeserializer) {
-    CompilationUnitElement compilationUnit = element.compilationUnit;
     DiagnosticReporter reporter = parsing.reporter;
     Uri uri = objectDecoder.getUri(Key.URI);
 
@@ -395,7 +392,6 @@
     Node doParse(parse(Parser parser)) {
       return parsing.measure(() {
         return reporter.withCurrentElement(element, () {
-          CompilationUnitElement unit = element.compilationUnit;
           NodeListener listener = new NodeListener(
               parsing.getScannerOptionsFor(element), reporter, null);
           listener.memberErrors = listener.memberErrors.prepend(false);
@@ -424,7 +420,6 @@
         case AstKind.ENUM_VALUES_FIELD:
           EnumClassElement enumClass = element.enclosingClass;
           AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
-          List<FieldElement> enumValues = <FieldElement>[];
           List<Node> valueReferences = <Node>[];
           for (EnumConstantElement enumConstant in enumClass.enumValues) {
             AstBuilder valueBuilder =
@@ -532,7 +527,6 @@
     Node root = computeNode(kind);
     TreeElementMapping elements = new TreeElementMapping(element);
     AstIndexComputer indexComputer = new AstIndexComputer();
-    Map<Node, int> nodeIndices = indexComputer.nodeIndices;
     List<Node> nodeList = indexComputer.nodeList;
     root.accept(indexComputer);
     elements.containsTryStatement = objectDecoder.getBool(Key.CONTAINS_TRY);
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index ff18e36..9bbfb8d 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -659,7 +659,6 @@
 class Serializer {
   List<SerializerPlugin> plugins = <SerializerPlugin>[];
 
-  Map<Uri, dynamic> _dependencyMap = <Uri, dynamic>{};
   Map<Element, DataObject> _elementMap = <Element, DataObject>{};
   Map<ConstantExpression, DataObject> _constantMap =
       <ConstantExpression, DataObject>{};
diff --git a/pkg/compiler/lib/src/serialization/serialization_util.dart b/pkg/compiler/lib/src/serialization/serialization_util.dart
index 9c7d1a8..8816cbd 100644
--- a/pkg/compiler/lib/src/serialization/serialization_util.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_util.dart
@@ -52,9 +52,6 @@
   int argumentCount = decoder.getInt(Key.ARGUMENTS);
   List<String> namedArguments =
       decoder.getStrings(Key.NAMED_ARGUMENTS, isOptional: true);
-  String name = decoder.getString(Key.NAME);
-  bool isSetter = decoder.getBool(Key.IS_SETTER);
-  LibraryElement library = decoder.getElement(Key.LIBRARY, isOptional: true);
   return new Selector(kind, deserializeName(decoder),
       new CallStructure(argumentCount, namedArguments));
 }
diff --git a/pkg/compiler/lib/src/serialization/system.dart b/pkg/compiler/lib/src/serialization/system.dart
index 12b4adb..b250712 100644
--- a/pkg/compiler/lib/src/serialization/system.dart
+++ b/pkg/compiler/lib/src/serialization/system.dart
@@ -11,10 +11,9 @@
 import '../compiler.dart';
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
-import '../scanner/scanner.dart';
 import '../script.dart';
 import '../serialization/impact_serialization.dart';
-import '../tokens/token.dart';
+import 'package:front_end/src/fasta/scanner.dart';
 import '../universe/call_structure.dart';
 import '../universe/use.dart';
 import '../universe/world_impact.dart';
@@ -315,7 +314,7 @@
             'No source file found for $uri in:\n ${scripts.keys.join('\n ')}');
       }
       if (script.isSynthesized) return null;
-      return new Scanner(script.file).tokenize();
+      return parsingContext.scanner.scanFile(script.file);
     });
     if (beginToken == null) return null;
     return ResolvedAstDeserializer.findTokenInStream(beginToken, offset);
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index acad224..886aac4 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -10,7 +10,6 @@
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../elements/elements.dart';
-import '../enqueue.dart' show ResolutionEnqueuer;
 import '../universe/world_impact.dart' show WorldImpact;
 import 'json_serializer.dart';
 import 'serialization.dart';
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index b49d87e6..9bde50e 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -462,7 +462,7 @@
       // Generative constructors of native classes should not be called directly
       // and have an extra argument that causes problems with inlining.
       if (function.isGenerativeConstructor &&
-          backend.isNativeOrExtendsNative(function.enclosingClass)) {
+          backend.nativeData.isNativeOrExtendsNative(function.enclosingClass)) {
         return false;
       }
 
@@ -1140,12 +1140,11 @@
       if (compiler.elementHasCompileTimeError(member)) return;
       reporter.withCurrentElement(member, () {
         ResolvedAst fieldResolvedAst = member.resolvedAst;
-        ast.Node node = fieldResolvedAst.node;
         ast.Expression initializer = fieldResolvedAst.body;
         if (initializer == null) {
           // Unassigned fields of native classes are not initialized to
           // prevent overwriting pre-initialized native properties.
-          if (!backend.isNativeOrExtendsNative(classElement)) {
+          if (!backend.nativeData.isNativeOrExtendsNative(classElement)) {
             fieldValues[member] = graph.addConstantNull(closedWorld);
           }
         } else {
@@ -1180,7 +1179,7 @@
     functionElement = functionElement.implementation;
     ClassElement classElement = functionElement.enclosingClass.implementation;
     bool isNativeUpgradeFactory =
-        backend.isNativeOrExtendsNative(classElement) &&
+        backend.nativeData.isNativeOrExtendsNative(classElement) &&
             !backend.isJsInterop(classElement);
     ast.FunctionExpression function;
     if (resolvedAst.kind == ResolvedAstKind.PARSED) {
@@ -2055,7 +2054,7 @@
     HInstruction loadIdConstant = addConstantString(loadId);
     String uri = prefixElement.deferredImport.uri.toString();
     HInstruction uriConstant = addConstantString(uri);
-    Element helper = helpers.checkDeferredIsLoaded;
+    MethodElement helper = helpers.checkDeferredIsLoaded;
     pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]);
     pop();
   }
@@ -2426,14 +2425,14 @@
     } else if (type.isTypeVariable) {
       HInstruction runtimeType =
           typeBuilder.addTypeVariableReference(type, sourceElement);
-      Element helper = helpers.checkSubtypeOfRuntimeType;
+      MethodElement helper = helpers.checkSubtypeOfRuntimeType;
       List<HInstruction> inputs = <HInstruction>[expression, runtimeType];
       pushInvokeStatic(null, helper, inputs, typeMask: commonMasks.boolType);
       HInstruction call = pop();
       return new HIs.variable(type, expression, call, commonMasks.boolType);
     } else if (RuntimeTypes.hasTypeArguments(type)) {
       ClassElement element = type.element;
-      Element helper = helpers.checkSubtype;
+      MethodElement helper = helpers.checkSubtype;
       HInstruction representations =
           typeBuilder.buildTypeArgumentRepresentations(type, sourceElement);
       add(representations);
@@ -2697,7 +2696,7 @@
       // Call a helper method from the isolate library. The isolate
       // library uses its own isolate structure, that encapsulates
       // Leg's isolate.
-      Element element = helpers.currentIsolate;
+      MethodElement element = helpers.currentIsolate;
       if (element == null) {
         reporter.internalError(node, 'Isolate library and compiler mismatch.');
       }
@@ -2891,7 +2890,7 @@
           <HInstruction>[pop()], commonMasks.dynamicType));
     } else {
       // Call a helper method from the isolate library.
-      Element element = helpers.callInIsolate;
+      MethodElement element = helpers.callInIsolate;
       if (element == null) {
         reporter.internalError(node, 'Isolate library and compiler mismatch.');
       }
@@ -3041,7 +3040,7 @@
 
     js.Name internalName = backend.namer.invocationName(selector);
 
-    Element createInvocationMirror = helpers.createInvocationMirror;
+    MethodElement createInvocationMirror = helpers.createInvocationMirror;
     var argumentsInstruction = buildLiteralList(arguments);
     add(argumentsInstruction);
 
@@ -3270,7 +3269,7 @@
   HInstruction callSetRuntimeTypeInfo(
       HInstruction typeInfo, HInstruction newObject) {
     // Set the runtime type information on the object.
-    Element typeInfoSetterElement = helpers.setRuntimeTypeInfo;
+    MethodElement typeInfoSetterElement = helpers.setRuntimeTypeInfo;
     pushInvokeStatic(
         null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo],
         typeMask: commonMasks.dynamicType,
@@ -3292,14 +3291,15 @@
     ast.Send send = node.send;
     generateIsDeferredLoadedCheckOfSend(send);
 
+    ConstructorElement constructor = elements[send];
     bool isFixedList = false;
     bool isFixedListConstructorCall = Elements.isFixedListConstructorCall(
-        elements[send], send, closedWorld.commonElements);
+        constructor, send, closedWorld.commonElements);
     bool isGrowableListConstructorCall = Elements.isGrowableListConstructorCall(
-        elements[send], send, closedWorld.commonElements);
+        constructor, send, closedWorld.commonElements);
 
     TypeMask computeType(element) {
-      Element originalElement = elements[send];
+      ConstructorElement originalElement = elements[send];
       if (isFixedListConstructorCall ||
           Elements.isFilledListConstructorCall(
               originalElement, send, closedWorld.commonElements)) {
@@ -3336,7 +3336,6 @@
       }
     }
 
-    Element constructor = elements[send];
     CallStructure callStructure = elements.getSelector(send).callStructure;
     ConstructorElement constructorDeclaration = constructor;
     ConstructorElement constructorImplementation = constructor.implementation;
@@ -3407,7 +3406,8 @@
 
     List<HInstruction> inputs = <HInstruction>[];
     if (constructor.isGenerativeConstructor &&
-        backend.isNativeOrExtendsNative(constructor.enclosingClass) &&
+        backend.nativeData
+            .isNativeOrExtendsNative(constructor.enclosingClass) &&
         !backend.isJsInterop(constructor)) {
       // Native class generative constructors take a pre-constructed object.
       inputs.add(graph.addConstantNull(closedWorld));
@@ -3820,15 +3820,18 @@
   }
 
   void generateRuntimeError(ast.Node node, String message) {
-    generateError(node, message, helpers.throwRuntimeError);
+    MethodElement helper = helpers.throwRuntimeError;
+    generateError(node, message, helper);
   }
 
   void generateTypeError(ast.Node node, String message) {
-    generateError(node, message, helpers.throwTypeError);
+    MethodElement helper = helpers.throwTypeError;
+    generateError(node, message, helper);
   }
 
   void generateAbstractClassInstantiationError(ast.Node node, String message) {
-    generateError(node, message, helpers.throwAbstractClassInstantiationError);
+    MethodElement helper = helpers.throwAbstractClassInstantiationError;
+    generateError(node, message, helper);
   }
 
   void generateThrowNoSuchMethod(ast.Node diagnosticNode, String methodName,
@@ -3836,7 +3839,7 @@
       List<HInstruction> argumentValues,
       List<String> existingArguments,
       SourceInformation sourceInformation}) {
-    Element helper = helpers.throwNoSuchMethod;
+    MethodElement helper = helpers.throwNoSuchMethod;
     ConstantValue receiverConstant =
         constantSystem.createString(new ast.DartString.empty());
     HInstruction receiver = graph.addConstant(receiverConstant, closedWorld);
@@ -3963,7 +3966,8 @@
     bool isOptimizableOperation(Selector selector, Element element) {
       ClassElement cls = element.enclosingClass;
       if (isOptimizableOperationOnIndexable(selector, element)) return true;
-      if (!backend.interceptedClasses.contains(cls)) return false;
+      if (!backend.interceptorData.interceptedClasses.contains(cls))
+        return false;
       if (selector.isOperator) return true;
       if (selector.isSetter) return true;
       if (selector.isIndex) return true;
@@ -3989,7 +3993,8 @@
 
     HInstruction receiver = arguments[0];
     List<HInstruction> inputs = <HInstruction>[];
-    bool isIntercepted = backend.isInterceptedSelector(selector);
+    bool isIntercepted =
+        backend.interceptorData.isInterceptedSelector(selector);
     if (isIntercepted) {
       inputs.add(invokeInterceptor(receiver));
     }
@@ -4088,8 +4093,8 @@
     if (!compiler.options.trustJSInteropTypeAnnotations ||
         type.isObject ||
         type.isDynamic) {
-      nativeBehavior.typesInstantiated
-          .add(backend.helpers.jsJavaScriptObjectClass.thisType);
+      ClassElement cls = backend.helpers.jsJavaScriptObjectClass;
+      nativeBehavior.typesInstantiated.add(cls.thisType);
     }
 
     String code;
@@ -4155,7 +4160,7 @@
     // TODO(5346): Try to avoid the need for calling [declaration] before
     // creating an [HStatic].
     List<HInstruction> inputs = <HInstruction>[];
-    if (backend.isInterceptedSelector(selector) &&
+    if (backend.interceptorData.isInterceptedSelector(selector) &&
         // Fields don't need an interceptor; consider generating HFieldGet/Set
         // instead.
         element.kind != ElementKind.FIELD) {
@@ -4167,9 +4172,11 @@
     if (!element.isGetter && selector.isGetter) {
       type = TypeMaskFactory.inferredTypeForElement(
           element, globalInferenceResults);
-    } else {
+    } else if (element.isFunction) {
       type = TypeMaskFactory.inferredReturnTypeForElement(
           element, globalInferenceResults);
+    } else {
+      type = closedWorld.commonMasks.dynamicType;
     }
     HInstruction instruction = new HInvokeSuper(element, currentNonClosureClass,
         selector, inputs, type, sourceInformation,
@@ -4737,21 +4744,21 @@
   @override
   void visitClassTypeLiteralSet(
       ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
-    generateThrowNoSuchMethod(node, constant.type.name,
+    generateThrowNoSuchMethod(node, constant.name,
         argumentNodes: node.arguments);
   }
 
   @override
   void visitTypedefTypeLiteralSet(
       ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
-    generateThrowNoSuchMethod(node, constant.type.name,
+    generateThrowNoSuchMethod(node, constant.name,
         argumentNodes: node.arguments);
   }
 
   @override
   void visitDynamicTypeLiteralSet(
       ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
-    generateThrowNoSuchMethod(node, constant.type.name,
+    generateThrowNoSuchMethod(node, constant.name,
         argumentNodes: node.arguments);
   }
 
@@ -5331,8 +5338,9 @@
 
     visit(node.expression);
     HInstruction expression = pop();
-    pushInvokeStatic(node, helpers.streamIteratorConstructor,
-        [expression, graph.addConstantNull(closedWorld)]);
+    ConstructorElement constructor = helpers.streamIteratorConstructor;
+    pushInvokeStatic(
+        node, constructor, [expression, graph.addConstantNull(closedWorld)]);
     streamIterator = pop();
 
     void buildInitializer() {}
@@ -5483,9 +5491,7 @@
     HInstruction originalLength = null; // Set for growable lists.
 
     HInstruction buildGetLength() {
-      MemberElement lengthElement = helpers.jsIndexableLength;
-      HFieldGet result = new HFieldGet(
-          lengthElement, array, commonMasks.positiveIntType,
+      HInstruction result = new HGetLength(array, commonMasks.positiveIntType,
           isAssignable: !isFixed);
       add(result);
       return result;
@@ -5625,30 +5631,31 @@
       listInputs.add(pop());
     }
 
-    Element constructor;
+    ConstructorElement listConstructor;
     List<HInstruction> inputs = <HInstruction>[];
 
     if (listInputs.isEmpty) {
-      constructor = helpers.mapLiteralConstructorEmpty;
+      listConstructor = helpers.mapLiteralConstructorEmpty;
     } else {
-      constructor = helpers.mapLiteralConstructor;
+      listConstructor = helpers.mapLiteralConstructor;
       HLiteralList keyValuePairs = buildLiteralList(listInputs);
       add(keyValuePairs);
       inputs.add(keyValuePairs);
     }
 
-    assert(constructor.isFactoryConstructor);
+    assert(listConstructor.isFactoryConstructor);
 
-    ConstructorElement functionElement = constructor;
-    constructor = functionElement.effectiveTarget;
+    ConstructorElement constructorElement = listConstructor;
+    listConstructor = constructorElement.effectiveTarget;
 
     ResolutionInterfaceType type = elements.getType(node);
     ResolutionInterfaceType expectedType =
-        functionElement.computeEffectiveTargetType(type);
+        constructorElement.computeEffectiveTargetType(type);
     expectedType = localsHandler.substInContext(expectedType);
 
-    ClassElement cls = constructor.enclosingClass;
+    ClassElement cls = listConstructor.enclosingClass;
 
+    MethodElement createFunction = listConstructor;
     if (backend.classNeedsRti(cls)) {
       List<HInstruction> typeInputs = <HInstruction>[];
       expectedType.typeArguments.forEach((ResolutionDartType argument) {
@@ -5660,9 +5667,9 @@
       // in the output.
       if (typeInputs.every((HInstruction input) => input.isNull())) {
         if (listInputs.isEmpty) {
-          constructor = helpers.mapLiteralUntypedEmptyMaker;
+          createFunction = helpers.mapLiteralUntypedEmptyMaker;
         } else {
-          constructor = helpers.mapLiteralUntypedMaker;
+          createFunction = helpers.mapLiteralUntypedMaker;
         }
       } else {
         inputs.addAll(typeInputs);
@@ -5672,7 +5679,8 @@
     // If rti is needed and the map literal has no type parameters,
     // 'constructor' is a static function that forwards the call to the factory
     // constructor without type parameters.
-    assert(constructor is ConstructorElement || constructor is FunctionElement);
+    assert(createFunction is ConstructorElement ||
+        createFunction is FunctionElement);
 
     // The instruction type will always be a subtype of the mapLiteralClass, but
     // type inference might discover a more specific type, or find nothing (in
@@ -5680,12 +5688,12 @@
     TypeMask mapType =
         new TypeMask.nonNullSubtype(helpers.mapLiteralClass, closedWorld);
     TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement(
-        constructor, globalInferenceResults);
+        createFunction, globalInferenceResults);
     TypeMask instructionType =
         mapType.intersection(returnTypeMask, closedWorld);
 
     addInlinedInstantiation(expectedType);
-    pushInvokeStatic(node, constructor, inputs,
+    pushInvokeStatic(node, createFunction, inputs,
         typeMask: instructionType, instanceType: expectedType);
     removeInlinedInstantiation(expectedType);
   }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 84ae3a5..974f561 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -16,9 +16,9 @@
         InterceptorConstantValue,
         StringConstantValue,
         TypeConstantValue;
-import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
-import '../elements/entities.dart' show MemberEntity;
+import '../elements/entities.dart';
+import '../elements/resolution_types.dart';
 import '../io/source_information.dart';
 import '../js/js.dart' as js;
 import '../js_backend/backend.dart' show JavaScriptBackend;
@@ -26,12 +26,12 @@
 import '../native/native.dart' as native;
 import '../resolution/tree_elements.dart';
 import '../tree/dartstring.dart';
-import '../tree/nodes.dart' show Node, BreakStatement;
+import '../tree/nodes.dart' show Node;
 import '../types/masks.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/selector.dart';
 import '../universe/side_effects.dart' show SideEffects;
-import '../universe/use.dart' show StaticUse;
+import '../universe/use.dart' show DynamicUse, StaticUse;
 import '../world.dart';
 import 'graph_builder.dart';
 import 'jump_handler.dart';
@@ -663,7 +663,6 @@
       returnStatement.expression.accept(this);
       value = pop();
       if (_targetFunction.asyncMarker == ir.AsyncMarker.Async) {
-        var returnType = astAdapter.getDartType(_targetFunction.returnType);
         if (compiler.options.enableTypeAssertions &&
             !isValidAsyncReturnType(_targetFunction.returnType)) {
           generateTypeError(
@@ -755,8 +754,7 @@
     HInstruction originalLength = null; // Set for growable lists.
 
     HInstruction buildGetLength() {
-      HFieldGet result = new HFieldGet(
-          astAdapter.jsIndexableLength, array, commonMasks.positiveIntType,
+      HGetLength result = new HGetLength(array, commonMasks.positiveIntType,
           isAssignable: !isFixed);
       add(result);
       return result;
@@ -813,8 +811,12 @@
       HInstruction value = new HIndex(array, index, null, type);
       add(value);
 
-      localsHandler.updateLocal(
-          astAdapter.getLocal(forInStatement.variable), value);
+      Local loopVariableLocal = astAdapter.getLocal(forInStatement.variable);
+      localsHandler.updateLocal(loopVariableLocal, value);
+      // Hint to name loop value after name of loop variable.
+      if (loopVariableLocal is! SyntheticLocal) {
+        value.sourceElement ??= loopVariableLocal;
+      }
 
       forInStatement.body.accept(this);
     }
@@ -870,8 +872,13 @@
       TypeMask mask = astAdapter.typeOfIteratorCurrent(forInStatement);
       _pushDynamicInvocation(forInStatement, mask, [iterator],
           selector: Selectors.current);
-      localsHandler.updateLocal(
-          astAdapter.getLocal(forInStatement.variable), pop());
+      Local loopVariableLocal = astAdapter.getLocal(forInStatement.variable);
+      HInstruction value = pop();
+      localsHandler.updateLocal(loopVariableLocal, value);
+      // Hint to name loop value after name of loop variable.
+      if (loopVariableLocal is! SyntheticLocal) {
+        value.sourceElement ??= loopVariableLocal;
+      }
       forInStatement.body.accept(this);
     }
 
@@ -1309,12 +1316,12 @@
     int switchIndex = 1;
     bool hasDefault = false;
     for (ir.SwitchCase switchCase in switchStatement.cases) {
+      if (_isDefaultCase(switchCase)) {
+        hasDefault = true;
+      }
       if (SwitchContinueAnalysis.containsContinue(switchCase.body)) {
         hasContinue = true;
       }
-      if (switchCase.isDefault) {
-        hasDefault = true;
-      }
       caseIndex[switchCase] = switchIndex;
       switchIndex++;
     }
@@ -1412,7 +1419,7 @@
     // This is because JS does not have this same "continue label" semantics so
     // we encode it in the form of a state machine.
 
-    JumpTarget switchTarget = astAdapter.getJumpTarget(switchStatement.parent);
+    JumpTarget switchTarget = astAdapter.getJumpTarget(switchStatement);
     localsHandler.updateLocal(switchTarget, graph.addConstantNull(closedWorld));
 
     var switchCases = switchStatement.cases;
@@ -1901,6 +1908,25 @@
   }
 
   @override
+  void visitSuperPropertySet(ir.SuperPropertySet propertySet) {
+    propertySet.value.accept(this);
+    HInstruction value = pop();
+
+    if (propertySet.interfaceTarget == null) {
+      _generateSuperNoSuchMethod(
+          propertySet,
+          astAdapter.getSelector(propertySet).name + "=",
+          <HInstruction>[value]);
+    } else {
+      _buildInvokeSuper(
+          astAdapter.getSelector(propertySet),
+          _containingClass(propertySet),
+          propertySet.interfaceTarget,
+          <HInstruction>[value]);
+    }
+  }
+
+  @override
   void visitVariableSet(ir.VariableSet variableSet) {
     variableSet.value.accept(this);
     HInstruction value = pop();
@@ -2627,32 +2653,143 @@
     return null;
   }
 
-  @override
-  void visitSuperMethodInvocation(ir.SuperMethodInvocation invocation) {
+  /// Find the applicable NoSuchMethod method for an object of this particular
+  /// class.
+  ir.Procedure _findNoSuchMethodInClass(ir.Class cls) {
+    // TODO(efortuna): If we find ourselves doing this sort of calculation
+    // often, rewrite what is done with the original element class where we call
+    // lookupSuperMember.
+    ir.Procedure noSuchMethod = null;
+    while (cls != null && cls != astAdapter.objectClass) {
+      for (ir.Procedure procedure in cls.procedures) {
+        // TODO(efortuna): Do we need to check mixin classes as well?
+        if (procedure.name.name == Identifiers.noSuchMethod_ &&
+            Selectors.noSuchMethod_
+                .signatureApplies(astAdapter.getElement(procedure))) {
+          noSuchMethod = procedure;
+        }
+      }
+      cls = cls.superclass;
+    }
+
+    if (noSuchMethod == null) {
+      // There is no matching overloaded NoSuchMethod function in the containing
+      // class. Look on the Object class itself.
+      for (ir.Procedure procedure in astAdapter.objectClass.procedures) {
+        if (procedure.name.name == Identifiers.noSuchMethod_) {
+          noSuchMethod = procedure;
+        }
+      }
+    }
+    assert(noSuchMethod != null);
+    return noSuchMethod;
+  }
+
+  void _generateSuperNoSuchMethod(ir.Expression invocation, String publicName,
+      List<HInstruction> arguments) {
     Selector selector = astAdapter.getSelector(invocation);
-    List<HInstruction> arguments = _visitArgumentsForStaticTarget(
-        invocation.interfaceTarget.function, invocation.arguments);
+    ir.Class cls = _containingClass(invocation).superclass;
+    assert(cls != null);
+    ir.Procedure noSuchMethod = _findNoSuchMethodInClass(cls);
+    if (backend.hasInvokeOnSupport &&
+        _containingClass(noSuchMethod) != astAdapter.objectClass) {
+      // Register the call as dynamic if [noSuchMethod] on the super
+      // class is _not_ the default implementation from [Object] (it might be
+      // overridden in the super class, but it might have a different number of
+      // arguments), in case the [noSuchMethod] implementation calls
+      // [JSInvocationMirror._invokeOn].
+      // TODO(johnniwinther): Register this more precisely.
+      registry?.registerDynamicUse(new DynamicUse(selector, null));
+    }
+
+    ConstantValue nameConstant =
+        backend.constantSystem.createString(new DartString.literal(publicName));
+
+    js.Name internalName = backend.namer.invocationName(selector);
+
+    var argumentsInstruction =
+        new HLiteralList(arguments, commonMasks.extendableArrayType);
+    add(argumentsInstruction);
+
+    var argumentNames = new List<HInstruction>();
+    for (String argumentName in selector.namedArguments) {
+      ConstantValue argumentNameConstant = backend.constantSystem
+          .createString(new DartString.literal(argumentName));
+      argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld));
+    }
+    var argumentNamesInstruction =
+        new HLiteralList(argumentNames, commonMasks.extendableArrayType);
+    add(argumentNamesInstruction);
+
+    ConstantValue kindConstant =
+        backend.constantSystem.createInt(selector.invocationMirrorKind);
+
+    _pushStaticInvocation(
+        astAdapter.createInvocationMirror,
+        [
+          graph.addConstant(nameConstant, closedWorld),
+          graph.addConstantStringFromName(internalName, closedWorld),
+          graph.addConstant(kindConstant, closedWorld),
+          argumentsInstruction,
+          argumentNamesInstruction
+        ],
+        commonMasks.dynamicType);
+
+    _buildInvokeSuper(Selectors.noSuchMethod_, _containingClass(invocation),
+        noSuchMethod, <HInstruction>[pop()]);
+  }
+
+  HInstruction _buildInvokeSuper(Selector selector, ir.Class containingClass,
+      ir.Member interfaceTarget, List<HInstruction> arguments) {
+    // TODO(efortuna): Add source information.
     HInstruction receiver = localsHandler.readThis();
-    ir.Class surroundingClass = _containingClass(invocation);
 
     List<HInstruction> inputs = <HInstruction>[];
-    if (astAdapter.isIntercepted(invocation)) {
+    if (astAdapter.isInterceptedSelector(selector)) {
       inputs.add(_interceptorFor(receiver));
     }
     inputs.add(receiver);
     inputs.addAll(arguments);
 
+    TypeMask typeMask;
+    if (interfaceTarget is ir.Procedure) {
+      typeMask = astAdapter.returnTypeOf(interfaceTarget);
+    } else {
+      typeMask = closedWorld.commonMasks.dynamicType;
+    }
     HInstruction instruction = new HInvokeSuper(
-        astAdapter.getMethod(invocation.interfaceTarget),
-        astAdapter.getClass(surroundingClass),
+        astAdapter.getMember(interfaceTarget),
+        astAdapter.getClass(containingClass),
         selector,
         inputs,
-        astAdapter.returnTypeOf(invocation.interfaceTarget),
+        typeMask,
         null,
         isSetter: selector.isSetter || selector.isIndexSet);
     instruction.sideEffects =
         closedWorld.getSideEffectsOfSelector(selector, null);
     push(instruction);
+    return instruction;
+  }
+
+  @override
+  void visitSuperPropertyGet(ir.SuperPropertyGet propertyGet) {
+    if (propertyGet.interfaceTarget == null) {
+      _generateSuperNoSuchMethod(propertyGet,
+          astAdapter.getSelector(propertyGet).name, const <HInstruction>[]);
+    } else {
+      _buildInvokeSuper(
+          astAdapter.getSelector(propertyGet),
+          _containingClass(propertyGet),
+          propertyGet.interfaceTarget, const <HInstruction>[]);
+    }
+  }
+
+  @override
+  void visitSuperMethodInvocation(ir.SuperMethodInvocation invocation) {
+    List<HInstruction> arguments = _visitArgumentsForStaticTarget(
+        invocation.interfaceTarget.function, invocation.arguments);
+    _buildInvokeSuper(astAdapter.getSelector(invocation),
+        _containingClass(invocation), invocation.interfaceTarget, arguments);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 7709a20..7e45b9b 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -12,7 +12,6 @@
 import '../core_types.dart' show CommonElements;
 import '../elements/elements.dart'
     show
-        Entity,
         JumpTarget,
         LabelDefinition,
         Name,
@@ -1638,7 +1637,7 @@
       js.Name name =
           backend.namer.nameForGetInterceptor(node.interceptedClasses);
       var isolate = new js.VariableUse(
-          backend.namer.globalObjectFor(helpers.interceptorsLibrary));
+          backend.namer.globalObjectForLibrary(helpers.interceptorsLibrary));
       use(node.receiver);
       List<js.Expression> arguments = <js.Expression>[pop()];
       push(js
@@ -1703,9 +1702,10 @@
   void visitOneShotInterceptor(HOneShotInterceptor node) {
     List<js.Expression> arguments = visitArguments(node.inputs);
     var isolate = new js.VariableUse(
-        backend.namer.globalObjectFor(helpers.interceptorsLibrary));
+        backend.namer.globalObjectForLibrary(helpers.interceptorsLibrary));
     Selector selector = node.selector;
-    js.Name methodName = backend.registerOneShotInterceptor(selector);
+    js.Name methodName = backend.interceptorData
+        .registerOneShotInterceptor(selector, backend.namer);
     push(js
         .propertyCall(isolate, methodName, arguments)
         .withSourceInformation(node.sourceInformation));
@@ -1937,21 +1937,14 @@
 
   visitFieldGet(HFieldGet node) {
     use(node.receiver);
-    MemberEntity element = node.element;
     if (node.isNullCheck) {
       // We access a JavaScript member we know all objects besides
       // null and undefined have: V8 does not like accessing a member
       // that does not exist.
       push(new js.PropertyAccess.field(pop(), 'toString')
           .withSourceInformation(node.sourceInformation));
-    } else if (element == helpers.jsIndexableLength) {
-      // We're accessing a native JavaScript property called 'length'
-      // on a JS String or a JS array. Therefore, the name of that
-      // property should not be mangled.
-      push(new js.PropertyAccess.field(pop(), 'length')
-          .withSourceInformation(node.sourceInformation));
     } else {
-      FieldEntity field = element;
+      FieldEntity field = node.element;
       js.Name name = backend.namer.instanceFieldPropertyName(field);
       push(new js.PropertyAccess(pop(), name)
           .withSourceInformation(node.sourceInformation));
@@ -1960,7 +1953,7 @@
   }
 
   visitFieldSet(HFieldSet node) {
-    MemberEntity element = node.element;
+    FieldEntity element = node.element;
     registry.registerStaticUse(new StaticUse.fieldSet(element));
     js.Name name = backend.namer.instanceFieldPropertyName(element);
     use(node.receiver);
@@ -1970,6 +1963,12 @@
         .withSourceInformation(node.sourceInformation));
   }
 
+  visitGetLength(HGetLength node) {
+    use(node.receiver);
+    push(new js.PropertyAccess.field(pop(), 'length')
+        .withSourceInformation(node.sourceInformation));
+  }
+
   visitReadModifyWrite(HReadModifyWrite node) {
     FieldEntity element = node.element;
     registry.registerStaticUse(new StaticUse.fieldGet(element));
@@ -2809,15 +2808,17 @@
         negative: negative);
   }
 
-  js.Expression generateReceiverOrArgumentTypeTest(
-      HInstruction input, TypeMask checkedType) {
-    TypeMask inputType = input.instructionType;
+  js.Expression generateReceiverOrArgumentTypeTest(HTypeConversion node) {
+    HInstruction input = node.checkedInput;
+    TypeMask inputType = node.inputType ?? input.instructionType;
+    TypeMask checkedType = node.checkedType;
     // Figure out if it is beneficial to turn this into a null check.
     // V8 generally prefers 'typeof' checks, but for integers and
     // indexable primitives we cannot compile this test into a single
     // typeof check so the null check is cheaper.
     bool isIntCheck = checkedType.containsOnlyInt(closedWorld);
-    bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(closedWorld);
+    bool turnIntoNumCheck =
+        isIntCheck && inputType.containsOnlyInt(closedWorld);
     bool turnIntoNullCheck = !turnIntoNumCheck &&
         (checkedType.nullable() == inputType) &&
         (isIntCheck ||
@@ -2850,13 +2851,7 @@
 
   void visitTypeConversion(HTypeConversion node) {
     if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) {
-      // An int check if the input is not int or null, is not
-      // sufficient for doing an argument or receiver check.
-      assert(compiler.options.trustTypeAnnotations ||
-          !node.checkedType.containsOnlyInt(closedWorld) ||
-          node.checkedInput.isIntegerOrNull(closedWorld));
-      js.Expression test = generateReceiverOrArgumentTypeTest(
-          node.checkedInput, node.checkedType);
+      js.Expression test = generateReceiverOrArgumentTypeTest(node);
       js.Block oldContainer = currentContainer;
       js.Statement body = new js.Block.empty();
       currentContainer = body;
@@ -3061,7 +3056,7 @@
 
     use(node.inputs[0]);
     if (node.hasReceiver) {
-      if (backend.isInterceptorClass(element.typeDeclaration)) {
+      if (backend.interceptorData.isInterceptorClass(element.typeDeclaration)) {
         int index = element.index;
         js.Expression receiver = pop();
         js.Expression helper =
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 9773af6..71ade2c 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -142,8 +142,8 @@
     HInstruction receiverArgument = node.inputs[1];
 
     if (interceptor.nonCheck() == receiverArgument.nonCheck()) {
-      if (backend.isInterceptedSelector(selector) &&
-          !backend.isInterceptedMixinSelector(selector, mask)) {
+      if (backend.interceptorData.isInterceptedSelector(selector) &&
+          !backend.interceptorData.isInterceptedMixinSelector(selector, mask)) {
         ConstantValue constant = new SyntheticConstantValue(
             SyntheticConstantKind.DUMMY_INTERCEPTOR,
             receiverArgument.instructionType);
@@ -283,6 +283,11 @@
   }
 
   void visitTypeKnown(HTypeKnown instruction) {
+    for (HInstruction user in instruction.usedBy) {
+      if (user is HTypeConversion) {
+        user.inputType = instruction.instructionType;
+      }
+    }
     instruction.block.rewrite(instruction, instruction.checkedInput);
     instruction.block.remove(instruction);
   }
diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart
index a426b34..9dbab93 100644
--- a/pkg/compiler/lib/src/ssa/graph_builder.dart
+++ b/pkg/compiler/lib/src/ssa/graph_builder.dart
@@ -2,25 +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 '../closure.dart';
-import '../common.dart';
 import '../common/codegen.dart' show CodegenRegistry;
 import '../compiler.dart';
-import '../constants/constant_system.dart';
-import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
-import '../io/source_information.dart';
+import '../elements/entities.dart' show Entity, Local;
+import '../elements/resolution_types.dart';
 import '../js_backend/js_backend.dart';
 import '../resolution/tree_elements.dart';
 import '../tree/tree.dart' as ast;
 import '../types/types.dart';
-import '../universe/call_structure.dart' show CallStructure;
-import '../universe/use.dart' show TypeUse;
 import '../world.dart' show ClosedWorld;
 import 'jump_handler.dart';
 import 'locals_handler.dart';
 import 'nodes.dart';
-import 'ssa_branch_builder.dart';
 import 'type_builder.dart';
 
 /// Base class for objects that build up an SSA graph.
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 86d436e..d04dfe8 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -101,7 +101,7 @@
       return false;
     }
     if (receiver.canBeNull() &&
-        interceptedClasses.contains(backendClasses.nullImplementation)) {
+        interceptedClasses.contains(backendClasses.nullClass)) {
       // Need the JSNull interceptor.
       return false;
     }
@@ -142,25 +142,25 @@
       TypeMask type, Set<ClassEntity> interceptedClasses) {
     if (type.isNullable) {
       if (type.isNull) {
-        return backendClasses.nullImplementation;
+        return backendClasses.nullClass;
       }
     } else if (type.containsOnlyInt(closedWorld)) {
-      return backendClasses.intImplementation;
+      return backendClasses.intClass;
     } else if (type.containsOnlyDouble(closedWorld)) {
-      return backendClasses.doubleImplementation;
+      return backendClasses.doubleClass;
     } else if (type.containsOnlyBool(closedWorld)) {
-      return backendClasses.boolImplementation;
+      return backendClasses.boolClass;
     } else if (type.containsOnlyString(closedWorld)) {
-      return backendClasses.stringImplementation;
-    } else if (type.satisfies(backendClasses.listImplementation, closedWorld)) {
-      return backendClasses.listImplementation;
+      return backendClasses.stringClass;
+    } else if (type.satisfies(backendClasses.listClass, closedWorld)) {
+      return backendClasses.listClass;
     } else if (type.containsOnlyNum(closedWorld) &&
-        !interceptedClasses.contains(backendClasses.intImplementation) &&
-        !interceptedClasses.contains(backendClasses.doubleImplementation)) {
+        !interceptedClasses.contains(backendClasses.intClass) &&
+        !interceptedClasses.contains(backendClasses.doubleClass)) {
       // If the method being intercepted is not defined in [int] or [double] we
       // can safely use the number interceptor.  This is because none of the
       // [int] or [double] methods are called from a method defined on [num].
-      return backendClasses.numImplementation;
+      return backendClasses.numClass;
     } else {
       // Try to find constant interceptor for a native class.  If the receiver
       // is constrained to a leaf native class, we can use the class's
@@ -224,30 +224,30 @@
         dominator.isCallOnInterceptor(closedWorld) &&
         node == dominator.receiver &&
         useCount(dominator, node) == 1) {
-      interceptedClasses =
-          backend.getInterceptedClassesOn(dominator.selector.name);
+      interceptedClasses = backend.interceptorData
+          .getInterceptedClassesOn(dominator.selector.name);
 
       // If we found that we need number, we must still go through all
       // uses to check if they require int, or double.
-      if (interceptedClasses.contains(backendClasses.numImplementation) &&
-          !(interceptedClasses.contains(backendClasses.doubleImplementation) ||
-              interceptedClasses.contains(backendClasses.intImplementation))) {
+      if (interceptedClasses.contains(backendClasses.numClass) &&
+          !(interceptedClasses.contains(backendClasses.doubleClass) ||
+              interceptedClasses.contains(backendClasses.intClass))) {
         Set<ClassEntity> required;
         for (HInstruction user in node.usedBy) {
           if (user is! HInvoke) continue;
-          Set<ClassEntity> intercepted =
-              backend.getInterceptedClassesOn(user.selector.name);
-          if (intercepted.contains(backendClasses.intImplementation)) {
+          Set<ClassEntity> intercepted = backend.interceptorData
+              .getInterceptedClassesOn(user.selector.name);
+          if (intercepted.contains(backendClasses.intClass)) {
             // TODO(johnniwinther): Use type argument when all uses of
             // intercepted classes expect entities instead of elements.
             required ??= new Set/*<ClassEntity>*/();
-            required.add(backendClasses.intImplementation);
+            required.add(backendClasses.intClass);
           }
-          if (intercepted.contains(backendClasses.doubleImplementation)) {
+          if (intercepted.contains(backendClasses.doubleClass)) {
             // TODO(johnniwinther): Use type argument when all uses of
             // intercepted classes expect entities instead of elements.
             required ??= new Set/*<ClassEntity>*/();
-            required.add(backendClasses.doubleImplementation);
+            required.add(backendClasses.doubleClass);
           }
         }
         // Don't modify the result of [backend.getInterceptedClassesOn].
@@ -264,18 +264,18 @@
             user.isCallOnInterceptor(closedWorld) &&
             node == user.receiver &&
             useCount(user, node) == 1) {
-          interceptedClasses
-              .addAll(backend.getInterceptedClassesOn(user.selector.name));
+          interceptedClasses.addAll(backend.interceptorData
+              .getInterceptedClassesOn(user.selector.name));
         } else if (user is HInvokeSuper &&
             user.isCallOnInterceptor(closedWorld) &&
             node == user.receiver &&
             useCount(user, node) == 1) {
-          interceptedClasses
-              .addAll(backend.getInterceptedClassesOn(user.selector.name));
+          interceptedClasses.addAll(backend.interceptorData
+              .getInterceptedClassesOn(user.selector.name));
         } else {
           // Use a most general interceptor for other instructions, example,
           // is-checks and escaping interceptors.
-          interceptedClasses.addAll(backend.interceptedClasses);
+          interceptedClasses.addAll(backend.interceptorData.interceptedClasses);
           break;
         }
       }
@@ -315,7 +315,7 @@
     // constant interceptor `C`.  Then we can use `(receiver && C)` for the
     // interceptor.
     if (receiver.canBeNull()) {
-      if (!interceptedClasses.contains(backendClasses.nullImplementation)) {
+      if (!interceptedClasses.contains(backendClasses.nullClass)) {
         // Can use `(receiver && C)` only if receiver is either null or truthy.
         if (!(receiver.canBePrimitiveNumber(closedWorld) ||
             receiver.canBePrimitiveBoolean(closedWorld) ||
@@ -334,7 +334,6 @@
     }
 
     // Try creating a one-shot interceptor or optimized is-check
-    if (compiler.options.hasIncrementalSupport) return false;
     if (node.usedBy.length != 1) return false;
     HInstruction user = node.usedBy.single;
 
diff --git a/pkg/compiler/lib/src/ssa/jump_handler.dart b/pkg/compiler/lib/src/ssa/jump_handler.dart
index c3d1528..50628f8 100644
--- a/pkg/compiler/lib/src/ssa/jump_handler.dart
+++ b/pkg/compiler/lib/src/ssa/jump_handler.dart
@@ -6,7 +6,6 @@
 import '../elements/elements.dart';
 import '../tree/tree.dart' as ast;
 
-import 'builder.dart';
 import 'graph_builder.dart';
 import 'locals_handler.dart';
 import 'nodes.dart';
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index ea8dedb..e0f85cc 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -6,18 +6,18 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../common.dart';
-import '../common/names.dart';
 import '../compiler.dart';
 import '../constants/expressions.dart';
 import '../constants/values.dart';
+import '../core_types.dart';
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
 import '../elements/entities.dart';
 import '../elements/modelx.dart';
 import '../elements/types.dart';
 import '../js/js.dart' as js;
-import '../js_backend/backend_helpers.dart';
 import '../js_backend/js_backend.dart';
+import '../kernel/element_adapter.dart';
 import '../kernel/kernel.dart';
 import '../kernel/kernel_debug.dart';
 import '../native/native.dart' as native;
@@ -25,7 +25,6 @@
 import '../tree/tree.dart' as ast;
 import '../types/masks.dart';
 import '../types/types.dart';
-import '../universe/call_structure.dart';
 import '../universe/selector.dart';
 import '../universe/side_effects.dart';
 import '../world.dart';
@@ -34,92 +33,10 @@
 import 'locals_handler.dart';
 import 'types.dart';
 
-/// Interface that translates between Kernel IR nodes and entities.
-abstract class KernelWorldBuilder {
-  /// Returns the [DartType] corresponding to [type].
-  DartType getDartType(ir.DartType type);
-
-  /// Returns the list of [DartType]s corresponding to [types].
-  List<DartType> getDartTypes(List<ir.DartType> types);
-
-  /// Returns the [InterfaceType] corresponding to [type].
-  InterfaceType getInterfaceType(ir.InterfaceType type);
-
-  /// Return the [InterfaceType] corresponding to the [cls] with the given
-  /// [typeArguments].
-  InterfaceType createInterfaceType(
-      ir.Class cls, List<ir.DartType> typeArguments);
-
-  /// Returns the [CallStructure] corresponding to the [arguments].
-  CallStructure getCallStructure(ir.Arguments arguments);
-
-  /// Returns the [Selector] corresponding to the invocation or getter/setter
-  /// access of [node].
-  Selector getSelector(ir.Expression node);
-
-  /// Returns the [FunctionEntity] corresponding to the generative or factory
-  /// constructor [node].
-  FunctionEntity getConstructor(ir.Member node);
-
-  /// Returns the [MemberEntity] corresponding to the member [node].
-  MemberEntity getMember(ir.Member node);
-
-  /// Returns the [FunctionEntity] corresponding to the procedure [node].
-  FunctionEntity getMethod(ir.Procedure node);
-
-  /// Returns the [FieldEntity] corresponding to the field [node].
-  FieldEntity getField(ir.Field node);
-
-  /// Returns the [ClassEntity] corresponding to the class [node].
-  ClassEntity getClass(ir.Class node);
-
-  /// Returns the [Local] corresponding to the [node]. The node must be either
-  /// a [ir.FunctionDeclaration] or [ir.FunctionExpression].
-  Local getLocalFunction(ir.Node node);
-
-  /// Returns the [Name] corresponding to [name].
-  Name getName(ir.Name name);
-
-  /// Returns `true` is [node] has a `@Native(...)` annotation.
-  bool isNativeClass(ir.Class node);
-
-  /// Return `true` if [node] is the `dart:_foreign_helper` library.
-  bool isForeignLibrary(ir.Library node);
-
-  /// Computes the native behavior for reading the native [field].
-  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field);
-
-  /// Computes the native behavior for writing to the native [field].
-  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);
-
-  /// Computes the native behavior for calling [procedure].
-  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure);
-
-  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
-  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
-
-  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
-  /// function.
-  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
-      ir.StaticInvocation node);
-
-  /// Computes the [native.NativeBehavior] for a call to the
-  /// [JS_EMBEDDED_GLOBAL] function.
-  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
-      ir.StaticInvocation node);
-
-  /// Compute the kind of foreign helper function called by [node], if any.
-  ForeignKind getForeignKind(ir.StaticInvocation node);
-
-  /// Computes the [InterfaceType] referenced by a call to the
-  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
-  InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node);
-}
-
 /// A helper class that abstracts all accesses of the AST from Kernel nodes.
 ///
 /// The goal is to remove all need for the AST from the Kernel SSA builder.
-class KernelAstAdapter implements KernelWorldBuilder {
+class KernelAstAdapter extends KernelElementAdapterMixin {
   final Kernel kernel;
   final JavaScriptBackend _backend;
   final Map<ir.Node, ast.Node> _nodeToAst;
@@ -140,8 +57,12 @@
   /// constructing the field values). We keep track of this with a stack.
   final List<ResolvedAst> _resolvedAstStack = <ResolvedAst>[];
 
+  final native.BehaviorBuilder nativeBehaviorBuilder;
+
   KernelAstAdapter(this.kernel, this._backend, this._resolvedAst,
-      this._nodeToAst, this._nodeToElement) {
+      this._nodeToAst, this._nodeToElement)
+      : nativeBehaviorBuilder =
+            new native.ResolverBehaviorBuilder(_backend.compiler) {
     KernelJumpTarget.index = 0;
     // TODO(het): Maybe just use all of the kernel maps directly?
     for (FieldElement fieldElement in kernel.fields.keys) {
@@ -165,6 +86,12 @@
     _typeConverter = new DartTypeConverter(this);
   }
 
+  @override
+  CommonElements get commonElements => _compiler.commonElements;
+
+  @override
+  ElementEnvironment get elementEnvironment => _compiler.elementEnvironment;
+
   /// Push the existing resolved AST on the stack and shift the current resolved
   /// AST to the AST that this kernel node points to.
   void pushResolvedAst(ir.Node node) {
@@ -192,7 +119,8 @@
 
   ConstantValue getConstantForSymbol(ir.SymbolLiteral node) {
     if (kernel.syntheticNodes.contains(node)) {
-      return _backend.constantSystem.createSymbol(_compiler, node.value);
+      return _backend.constantSystem.createSymbol(
+          _compiler.commonElements, _backend.backendClasses, node.value);
     }
     ast.Node astNode = getNode(node);
     ConstantValue constantValue = _backend.constants
@@ -221,7 +149,9 @@
 
   ClassElement getClass(ir.Class node) => getElement(node).declaration;
 
-  LocalFunctionElement getLocalFunction(ir.Node node) => getElement(node);
+  LibraryElement getLibrary(ir.Library node) => getElement(node).declaration;
+
+  LocalFunctionElement getLocalFunction(ir.TreeNode node) => getElement(node);
 
   ast.Node getNode(ir.Node node) {
     ast.Node result = _nodeToAst[node];
@@ -254,74 +184,23 @@
     return !closedWorld.getCannotThrow(function);
   }
 
-  TypeMask returnTypeOf(ir.Member node) {
+  TypeMask returnTypeOf(ir.Procedure node) {
     return TypeMaskFactory.inferredReturnTypeForElement(
-        getElement(node), _globalInferenceResults);
+        getMethod(node), _globalInferenceResults);
   }
 
   SideEffects getSideEffects(ir.Node node, ClosedWorld closedWorld) {
     return closedWorld.getSideEffectsOfElement(getElement(node));
   }
 
-  CallStructure getCallStructure(ir.Arguments arguments) {
-    int argumentCount = arguments.positional.length + arguments.named.length;
-    List<String> namedArguments = arguments.named.map((e) => e.name).toList();
-    return new CallStructure(argumentCount, namedArguments);
-  }
-
   FunctionSignature getFunctionSignature(ir.FunctionNode function) {
     return getElement(function).asFunctionElement().functionSignature;
   }
 
-  Name getName(ir.Name name) {
-    return new Name(
-        name.name, name.isPrivate ? getElement(name.library) : null);
-  }
-
   ir.Field getFieldFromElement(FieldElement field) {
     return kernel.fields[field];
   }
 
-  Selector getSelector(ir.Expression node) {
-    if (node is ir.PropertyGet) return getGetterSelector(node);
-    if (node is ir.PropertySet) return getSetterSelector(node);
-    if (node is ir.InvocationExpression) return getInvocationSelector(node);
-    _compiler.reporter.internalError(getNode(node),
-        "Can only get the selector for a property get or an invocation.");
-    return null;
-  }
-
-  Selector getInvocationSelector(ir.InvocationExpression invocation) {
-    Name name = getName(invocation.name);
-    SelectorKind kind;
-    if (Elements.isOperatorName(invocation.name.name)) {
-      if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
-        kind = SelectorKind.INDEX;
-      } else {
-        kind = SelectorKind.OPERATOR;
-      }
-    } else {
-      kind = SelectorKind.CALL;
-    }
-
-    CallStructure callStructure = getCallStructure(invocation.arguments);
-    return new Selector(kind, name, callStructure);
-  }
-
-  Selector getGetterSelector(ir.PropertyGet getter) {
-    ir.Name irName = getter.name;
-    Name name = new Name(
-        irName.name, irName.isPrivate ? getElement(irName.library) : null);
-    return new Selector.getter(name);
-  }
-
-  Selector getSetterSelector(ir.PropertySet setter) {
-    ir.Name irName = setter.name;
-    Name name = new Name(
-        irName.name, irName.isPrivate ? getElement(irName.library) : null);
-    return new Selector.setter(name);
-  }
-
   TypeMask typeOfInvocation(ir.MethodInvocation send, ClosedWorld closedWorld) {
     ast.Node operatorNode = kernel.nodeToAstOperator[send];
     if (operatorNode != null) {
@@ -384,8 +263,8 @@
       return true;
     }
     // TODO(sra): Recognize any combination of fixed length indexables.
-    if (mask.containsOnly(closedWorld.backendClasses.fixedListImplementation) ||
-        mask.containsOnly(closedWorld.backendClasses.constListImplementation) ||
+    if (mask.containsOnly(closedWorld.backendClasses.fixedListClass) ||
+        mask.containsOnly(closedWorld.backendClasses.constListClass) ||
         mask.containsOnlyString(closedWorld) ||
         closedWorld.commonMasks.isTypedArray(mask)) {
       return true;
@@ -440,16 +319,17 @@
 
   ConstantValue getConstantForType(ir.DartType irType) {
     ResolutionDartType type = getDartType(irType);
-    return _backend.constantSystem.createType(_compiler, type.asRaw());
+    return _backend.constantSystem.createType(
+        _compiler.commonElements, _backend.backendClasses, type.asRaw());
   }
 
   bool isIntercepted(ir.Node node) {
     Selector selector = getSelector(node);
-    return _backend.isInterceptedSelector(selector);
+    return _backend.interceptorData.isInterceptedSelector(selector);
   }
 
   bool isInterceptedSelector(Selector selector) {
-    return _backend.isInterceptedSelector(selector);
+    return _backend.interceptorData.isInterceptedSelector(selector);
   }
 
   // Is the member a lazy initialized static or top-level member?
@@ -475,6 +355,9 @@
     });
   }
 
+  ir.Procedure get createInvocationMirror =>
+      kernel.functions[_backend.helpers.createInvocationMirror];
+
   ir.Class get mapLiteralClass =>
       kernel.classes[_backend.helpers.mapLiteralClass];
 
@@ -506,7 +389,8 @@
 
   TypeMask get streamIteratorConstructorType =>
       TypeMaskFactory.inferredReturnTypeForElement(
-          _backend.helpers.streamIteratorConstructor, _globalInferenceResults);
+          _backend.helpers.streamIteratorConstructor as FunctionEntity,
+          _globalInferenceResults);
 
   ir.Procedure get fallThroughError =>
       kernel.functions[_backend.helpers.fallThroughError];
@@ -518,8 +402,6 @@
   ir.Procedure get mapLiteralUntypedMaker =>
       kernel.functions[_backend.helpers.mapLiteralUntypedMaker];
 
-  MemberElement get jsIndexableLength => _backend.helpers.jsIndexableLength;
-
   ir.Procedure get checkConcurrentModificationError =>
       kernel.functions[_backend.helpers.checkConcurrentModificationError];
 
@@ -612,7 +494,7 @@
   }
 
   int _extractEnumIndexFromConstantValue(
-      ConstantValue constant, Element classElement) {
+      ConstantValue constant, ClassEntity classElement) {
     if (constant is ConstructedConstantValue) {
       if (constant.type.element == classElement) {
         assert(constant.fields.length == 1);
@@ -691,229 +573,9 @@
         getClass(cls), getDartTypes(typeArguments));
   }
 
-  /// Converts [annotations] into a list of [ConstantExpression]s.
-  List<ConstantExpression> getMetadata(List<ir.Expression> annotations) {
-    List<ConstantExpression> metadata = <ConstantExpression>[];
-    annotations.forEach((ir.Expression node) {
-      ConstantExpression constant = node.accept(new Constantifier(this));
-      if (constant == null) {
-        throw new UnsupportedError(
-            'No constant for ${DebugPrinter.prettyPrint(node)}');
-      }
-      metadata.add(constant);
-    });
-    return metadata;
-  }
-
-  /// Compute the kind of foreign helper function called by [node], if any.
-  ForeignKind getForeignKind(ir.StaticInvocation node) {
-    if (isForeignLibrary(node.target.enclosingLibrary)) {
-      switch (node.target.name.name) {
-        case BackendHelpers.JS:
-          return ForeignKind.JS;
-        case BackendHelpers.JS_BUILTIN:
-          return ForeignKind.JS_BUILTIN;
-        case BackendHelpers.JS_EMBEDDED_GLOBAL:
-          return ForeignKind.JS_EMBEDDED_GLOBAL;
-        case BackendHelpers.JS_INTERCEPTOR_CONSTANT:
-          return ForeignKind.JS_INTERCEPTOR_CONSTANT;
-      }
-    }
-    return ForeignKind.NONE;
-  }
-
-  /// Return `true` if [node] is the `dart:_foreign_helper` library.
-  bool isForeignLibrary(ir.Library node) {
-    return node.importUri == BackendHelpers.DART_FOREIGN_HELPER;
-  }
-
-  /// Looks up [typeName] for use in the spec-string of a `JS` called.
-  // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
-  // the `ForeignResolver`.
-  // TODO(johnniwinther): Cache the result to avoid redundant lookups?
-  native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
-    return (String typeName) {
-      ResolutionDartType findIn(Uri uri) {
-        LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri);
-        if (library != null) {
-          Element element = library.find(typeName);
-          if (element != null && element.isClass) {
-            ClassElement cls = element;
-            // TODO(johnniwinther): Align semantics.
-            return resolveAsRaw ? cls.rawType : cls.thisType;
-          }
-        }
-        return null;
-      }
-
-      ResolutionDartType type = findIn(Uris.dart_core);
-      type ??= findIn(BackendHelpers.DART_JS_HELPER);
-      type ??= findIn(BackendHelpers.DART_INTERCEPTORS);
-      type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER);
-      type ??= findIn(Uris.dart_collection);
-      type ??= findIn(Uris.dart_html);
-      type ??= findIn(Uris.dart_svg);
-      type ??= findIn(Uris.dart_web_audio);
-      type ??= findIn(Uris.dart_web_gl);
-      return type;
-    };
-  }
-
-  String _getStringArgument(ir.StaticInvocation node, int index) {
-    return node.arguments.positional[index].accept(new Stringifier());
-  }
-
-  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
-  // TODO(johnniwinther): Cache this for later use.
-  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
-    if (node.arguments.positional.length < 2 ||
-        node.arguments.named.isNotEmpty) {
-      reporter.reportErrorMessage(
-          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
-      return new native.NativeBehavior();
-    }
-    String specString = _getStringArgument(node, 0);
-    if (specString == null) {
-      reporter.reportErrorMessage(
-          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
-      return new native.NativeBehavior();
-    }
-
-    String codeString = _getStringArgument(node, 1);
-    if (codeString == null) {
-      reporter.reportErrorMessage(
-          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
-      return new native.NativeBehavior();
-    }
-
-    return native.NativeBehavior.ofJsCall(
-        specString,
-        codeString,
-        _typeLookup(resolveAsRaw: true),
-        CURRENT_ELEMENT_SPANNABLE,
-        reporter,
-        _compiler.commonElements);
-  }
-
-  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
-  /// function.
-  // TODO(johnniwinther): Cache this for later use.
-  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
-      ir.StaticInvocation node) {
-    if (node.arguments.positional.length < 1) {
-      reporter.internalError(
-          CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
-      return new native.NativeBehavior();
-    }
-    if (node.arguments.positional.length < 2) {
-      reporter.internalError(
-          CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
-      return new native.NativeBehavior();
-    }
-    String specString = _getStringArgument(node, 0);
-    if (specString == null) {
-      reporter.internalError(
-          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
-      return new native.NativeBehavior();
-    }
-    return native.NativeBehavior.ofJsBuiltinCall(
-        specString,
-        _typeLookup(resolveAsRaw: true),
-        CURRENT_ELEMENT_SPANNABLE,
-        reporter,
-        _compiler.commonElements);
-  }
-
-  /// Computes the [native.NativeBehavior] for a call to the
-  /// [JS_EMBEDDED_GLOBAL] function.
-  // TODO(johnniwinther): Cache this for later use.
-  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
-      ir.StaticInvocation node) {
-    if (node.arguments.positional.length < 1) {
-      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
-          "JS embedded global expression has no type.");
-      return new native.NativeBehavior();
-    }
-    if (node.arguments.positional.length < 2) {
-      reporter.internalError(
-          CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
-      return new native.NativeBehavior();
-    }
-    if (node.arguments.positional.length > 2 ||
-        node.arguments.named.isNotEmpty) {
-      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
-          "JS embedded global has more than 2 arguments.");
-      return new native.NativeBehavior();
-    }
-    String specString = _getStringArgument(node, 0);
-    if (specString == null) {
-      reporter.internalError(
-          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
-      return new native.NativeBehavior();
-    }
-    return native.NativeBehavior.ofJsEmbeddedGlobalCall(
-        specString,
-        _typeLookup(resolveAsRaw: true),
-        CURRENT_ELEMENT_SPANNABLE,
-        reporter,
-        _compiler.commonElements);
-  }
-
-  /// Computes the [InterfaceType] referenced by a call to the
-  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
-  InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
-    if (node.arguments.positional.length != 1 ||
-        node.arguments.named.isNotEmpty) {
-      reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
-          MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
-    }
-    ir.Node argument = node.arguments.positional.first;
-    if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
-      return getInterfaceType(argument.type);
-    }
-    return null;
-  }
-
-  /// Returns `true` is [node] has a `@Native(...)` annotation.
-  // TODO(johnniwinther): Cache this for later use.
-  bool isNativeClass(ir.Class node) {
-    for (ir.Expression annotation in node.annotations) {
-      if (annotation is ir.ConstructorInvocation) {
-        ConstructorElement target = getElement(annotation.target).declaration;
-        if (target.enclosingClass ==
-            _compiler.commonElements.nativeAnnotationClass) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  /// Computes the native behavior for reading the native [field].
-  // TODO(johnniwinther): Cache this for later use.
-  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
-    ResolutionDartType type = getDartType(field.type);
-    List<ConstantExpression> metadata = getMetadata(field.annotations);
-    return native.NativeBehavior.ofFieldLoad(CURRENT_ELEMENT_SPANNABLE, type,
-        metadata, _typeLookup(resolveAsRaw: false), _compiler,
-        isJsInterop: false);
-  }
-
-  /// Computes the native behavior for writing to the native [field].
-  // TODO(johnniwinther): Cache this for later use.
-  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
-    ResolutionDartType type = getDartType(field.type);
-    return native.NativeBehavior.ofFieldStore(type, _compiler.resolution);
-  }
-
-  /// Computes the native behavior for calling [procedure].
-  // TODO(johnniwinther): Cache this for later use.
-  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
-    ResolutionDartType type = getFunctionType(procedure.function);
-    List<ConstantExpression> metadata = getMetadata(procedure.annotations);
-    return native.NativeBehavior.ofMethod(CURRENT_ELEMENT_SPANNABLE, type,
-        metadata, _typeLookup(resolveAsRaw: false), _compiler,
-        isJsInterop: false);
+  @override
+  InterfaceType getThisType(ir.Class cls) {
+    return getClass(cls).thisType;
   }
 
   MemberEntity getConstructorBodyEntity(ir.Constructor constructor) {
@@ -925,15 +587,6 @@
   }
 }
 
-/// Kinds of foreign functions.
-enum ForeignKind {
-  JS,
-  JS_BUILTIN,
-  JS_EMBEDDED_GLOBAL,
-  JS_INTERCEPTOR_CONSTANT,
-  NONE,
-}
-
 /// Visitor that converts kernel dart types into [ResolutionDartType].
 class DartTypeConverter extends ir.DartTypeVisitor<ResolutionDartType> {
   final KernelAstAdapter astAdapter;
@@ -996,7 +649,7 @@
 
   @override
   ResolutionDartType visitInterfaceType(ir.InterfaceType node) {
-    ClassElement cls = astAdapter.getElement(node.classNode);
+    ClassElement cls = astAdapter.getClass(node.classNode);
     return new ResolutionInterfaceType(cls, visitTypes(node.typeArguments));
   }
 
@@ -1021,95 +674,25 @@
   }
 }
 
-/// Visitor that converts string literals and concatenations of string literals
-/// into the string value.
-class Stringifier extends ir.ExpressionVisitor<String> {
-  @override
-  String visitStringLiteral(ir.StringLiteral node) => node.value;
-
-  @override
-  String visitStringConcatenation(ir.StringConcatenation node) {
-    StringBuffer sb = new StringBuffer();
-    for (ir.Expression expression in node.expressions) {
-      String value = expression.accept(this);
-      if (value == null) return null;
-      sb.write(value);
-    }
-    return sb.toString();
-  }
-}
-
-/// Visitor that converts a kernel constant expression into a
-/// [ConstantExpression].
-class Constantifier extends ir.ExpressionVisitor<ConstantExpression> {
-  final KernelAstAdapter astAdapter;
-
-  Constantifier(this.astAdapter);
-
-  @override
-  ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) {
-    ConstructorElement constructor =
-        astAdapter.getElement(node.target).declaration;
-    List<ResolutionDartType> typeArguments = <ResolutionDartType>[];
-    for (ir.DartType type in node.arguments.types) {
-      typeArguments.add(astAdapter.getDartType(type));
-    }
-    List<ConstantExpression> arguments = <ConstantExpression>[];
-    List<String> argumentNames = <String>[];
-    for (ir.Expression argument in node.arguments.positional) {
-      ConstantExpression constant = argument.accept(this);
-      if (constant == null) return null;
-      arguments.add(constant);
-    }
-    for (ir.NamedExpression argument in node.arguments.named) {
-      argumentNames.add(argument.name);
-      ConstantExpression constant = argument.value.accept(this);
-      if (constant == null) return null;
-      arguments.add(constant);
-    }
-    return new ConstructedConstantExpression(
-        constructor.enclosingClass.thisType.createInstantiation(typeArguments),
-        constructor,
-        new CallStructure(
-            node.arguments.positional.length + argumentNames.length,
-            argumentNames),
-        arguments);
-  }
-
-  @override
-  ConstantExpression visitStaticGet(ir.StaticGet node) {
-    Element element = astAdapter.getMember(node.target);
-    if (element.isField) {
-      return new VariableConstantExpression(element);
-    }
-    astAdapter.reporter.internalError(
-        CURRENT_ELEMENT_SPANNABLE, "Unexpected constant target: $element.");
-    return null;
-  }
-
-  @override
-  ConstantExpression visitStringLiteral(ir.StringLiteral node) {
-    return new StringConstantExpression(node.value);
-  }
-}
-
 class KernelJumpTarget extends JumpTarget {
   static int index = 0;
 
   /// Pointer to the actual executable statements that a jump target refers to.
   /// If this jump target was not initially constructed with a LabeledStatement,
-  /// this value is identical to originalStatement.
-  // TODO(efortuna): In an ideal world the Node should be some common
-  // interface we create for both ir.Statements and ir.SwitchCase (the
-  // ContinueSwitchStatement's target is a SwitchCase) rather than general
-  // Node. Talking to Asger about this.
+  /// this value is identical to originalStatement. This Node is actually of
+  /// type either ir.Statement or ir.SwitchCase.
   ir.Node targetStatement;
 
   /// The original statement used to construct this jump target.
   /// If this jump target was not initially constructed with a LabeledStatement,
-  /// this value is identical to targetStatement.
+  /// this value is identical to targetStatement. This Node is actually of
+  /// type either ir.Statement or ir.SwitchCase.
   ir.Node originalStatement;
 
+  /// Used to provide unique numbers to labels that would otherwise be duplicate
+  /// if one JumpTarget is inside another.
+  int nestingLevel;
+
   @override
   bool isBreakTarget = false;
 
@@ -1139,6 +722,13 @@
           new LabelDefinitionX(null, 'L${index++}', this)..setBreakTarget());
       isBreakTarget = true;
     }
+    var originalNode = adapter.getNode(originalStatement);
+    var originalTarget = adapter.elements.getTargetDefinition(originalNode);
+    if (originalTarget != null) {
+      nestingLevel = originalTarget.nestingLevel;
+    } else {
+      nestingLevel = 0;
+    }
 
     if (makeContinueLabel) {
       labels.add(
@@ -1158,6 +748,9 @@
   ExecutableElement get executableContext => null;
 
   @override
+  MemberElement get memberContext => null;
+
+  @override
   bool get isSwitch => targetStatement is ir.SwitchStatement;
 
   @override
@@ -1169,14 +762,6 @@
   @override
   String get name => 'target';
 
-  // TODO(efortuna): In the original version, this nesting level is specified at
-  // jump target construction time, by the resolver. Because these are
-  // instantiated later, we don't have that information. When we move fully over
-  // to the kernel model, we can pass the nesting level in KernelJumpTarget's
-  // constructor.
-  @override
-  int get nestingLevel => 0;
-
   @override
   ast.Node get statement => null;
 
diff --git a/pkg/compiler/lib/src/ssa/kernel_impact.dart b/pkg/compiler/lib/src/ssa/kernel_impact.dart
index 54d2686..0eb95a6 100644
--- a/pkg/compiler/lib/src/ssa/kernel_impact.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_impact.dart
@@ -13,6 +13,7 @@
 import '../elements/elements.dart' show AstElement, ResolvedAst;
 import '../elements/entities.dart';
 import '../js_backend/backend.dart' show JavaScriptBackend;
+import '../kernel/element_adapter.dart';
 import '../kernel/kernel.dart';
 import '../kernel/kernel_debug.dart';
 import '../resolution/registry.dart' show ResolutionWorldImpactBuilder;
@@ -32,49 +33,61 @@
     Kernel kernel = backend.kernelTask.kernel;
     KernelAstAdapter astAdapter = new KernelAstAdapter(kernel, compiler.backend,
         resolvedAst, kernel.nodeToAst, kernel.nodeToElement);
-    KernelImpactBuilder builder = new KernelImpactBuilder(
-        '${resolvedAst.element}', astAdapter, compiler.commonElements);
-    if (element.isFunction ||
-        element.isGetter ||
-        element.isSetter ||
-        element.isFactoryConstructor) {
-      ir.Procedure function = kernel.functions[element];
-      if (function == null) {
-        throw "FOUND NULL FUNCTION: $element";
-      } else {
-        return builder.buildProcedure(function);
-      }
-    } else if (element.isGenerativeConstructor) {
-      ir.Constructor constructor = kernel.functions[element];
-      if (constructor == null) {
-        throw "FOUND NULL CONSTRUCTOR: $element";
-      } else {
-        return builder.buildConstructor(constructor);
-      }
-    } else if (element.isField) {
-      ir.Field field = kernel.fields[element];
-      if (field == null) {
-        throw "FOUND NULL FIELD: $element";
-      } else {
-        return builder.buildField(field);
-      }
-    } else {
-      throw new UnsupportedError("Unsupported element: $element");
-    }
+    ir.Member member = getIrMember(compiler, resolvedAst);
+    return buildKernelImpact(member, astAdapter);
   });
 }
 
+ir.Member getIrMember(Compiler compiler, ResolvedAst resolvedAst) {
+  AstElement element = resolvedAst.element;
+  JavaScriptBackend backend = compiler.backend;
+  Kernel kernel = backend.kernelTask.kernel;
+  ir.Member member;
+  if (element.isFunction ||
+      element.isGetter ||
+      element.isSetter ||
+      element.isConstructor) {
+    member = kernel.functions[element];
+    if (member == null) {
+      throw "FOUND NULL FUNCTION: $element";
+    }
+  } else if (element.isField) {
+    member = kernel.fields[element];
+    if (member == null) {
+      throw "FOUND NULL FIELD: $element";
+    }
+  } else {
+    throw new UnsupportedError("Unsupported element: $element");
+  }
+  return member;
+}
+
+ResolutionImpact buildKernelImpact(
+    ir.Member member, KernelElementAdapter elementAdapter) {
+  KernelImpactBuilder builder =
+      new KernelImpactBuilder('${member.name}', elementAdapter);
+  if (member is ir.Procedure) {
+    return builder.buildProcedure(member);
+  } else if (member is ir.Constructor) {
+    return builder.buildConstructor(member);
+  } else if (member is ir.Field) {
+    return builder.buildField(member);
+  }
+  throw new UnsupportedError("Unsupported member: $member");
+}
+
 class KernelImpactBuilder extends ir.Visitor {
   final ResolutionWorldImpactBuilder impactBuilder;
-  final KernelWorldBuilder astAdapter;
-  final CommonElements commonElements;
+  final KernelElementAdapter elementAdapter;
 
-  KernelImpactBuilder(String name, this.astAdapter, this.commonElements)
+  KernelImpactBuilder(String name, this.elementAdapter)
       : this.impactBuilder = new ResolutionWorldImpactBuilder(name);
 
+  CommonElements get commonElements => elementAdapter.commonElements;
+
   /// Add a checked-mode type use of [type] if it is not `dynamic`.
   DartType checkType(ir.DartType irType) {
-    DartType type = astAdapter.getDartType(irType);
+    DartType type = elementAdapter.getDartType(irType);
     if (!type.isDynamic) {
       impactBuilder.registerTypeUse(new TypeUse.checkedModeCheck(type));
     }
@@ -109,11 +122,11 @@
       }
     }
     if (field.isInstanceMember &&
-        astAdapter.isNativeClass(field.enclosingClass)) {
-      impactBuilder
-          .registerNativeData(astAdapter.getNativeBehaviorForFieldLoad(field));
-      impactBuilder
-          .registerNativeData(astAdapter.getNativeBehaviorForFieldStore(field));
+        elementAdapter.isNativeClass(field.enclosingClass)) {
+      impactBuilder.registerNativeData(
+          elementAdapter.getNativeBehaviorForFieldLoad(field));
+      impactBuilder.registerNativeData(
+          elementAdapter.getNativeBehaviorForFieldStore(field));
     }
     return impactBuilder;
   }
@@ -145,9 +158,9 @@
             "Unexpected async marker: ${procedure.function.asyncMarker}");
     }
     if (procedure.isExternal &&
-        !astAdapter.isForeignLibrary(procedure.enclosingLibrary)) {
-      impactBuilder
-          .registerNativeData(astAdapter.getNativeBehaviorForMethod(procedure));
+        !elementAdapter.isForeignLibrary(procedure.enclosingLibrary)) {
+      impactBuilder.registerNativeData(
+          elementAdapter.getNativeBehaviorForMethod(procedure));
     }
     return impactBuilder;
   }
@@ -252,10 +265,11 @@
   void handleNew(ir.InvocationExpression node, ir.Member target,
       {bool isConst: false}) {
     _visitArguments(node.arguments);
-    FunctionEntity constructor = astAdapter.getConstructor(target);
-    InterfaceType type = astAdapter.createInterfaceType(
+    ConstructorEntity constructor = elementAdapter.getConstructor(target);
+    InterfaceType type = elementAdapter.createInterfaceType(
         target.enclosingClass, node.arguments.types);
-    CallStructure callStructure = astAdapter.getCallStructure(node.arguments);
+    CallStructure callStructure =
+        elementAdapter.getCallStructure(node.arguments);
     impactBuilder.registerStaticUse(isConst
         ? new StaticUse.constConstructorInvoke(constructor, callStructure, type)
         : new StaticUse.typedConstructorInvoke(
@@ -267,15 +281,14 @@
 
   @override
   void visitSuperInitializer(ir.SuperInitializer node) {
-    FunctionEntity target = astAdapter.getConstructor(node.target);
+    ConstructorEntity target = elementAdapter.getConstructor(node.target);
     _visitArguments(node.arguments);
     impactBuilder.registerStaticUse(new StaticUse.superConstructorInvoke(
-        target, astAdapter.getCallStructure(node.arguments)));
+        target, elementAdapter.getCallStructure(node.arguments)));
   }
 
   @override
   void visitStaticInvocation(ir.StaticInvocation node) {
-    FunctionEntity target = astAdapter.getMethod(node.target);
     if (node.target.kind == ir.ProcedureKind.Factory) {
       // TODO(johnniwinther): We should not mark the type as instantiated but
       // rather follow the type arguments directly.
@@ -301,26 +314,27 @@
       // instantiated as int and String.
       handleNew(node, node.target, isConst: node.isConst);
     } else {
+      FunctionEntity target = elementAdapter.getMethod(node.target);
       _visitArguments(node.arguments);
       impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
-          target, astAdapter.getCallStructure(node.arguments)));
+          target, elementAdapter.getCallStructure(node.arguments)));
     }
-    switch (astAdapter.getForeignKind(node)) {
+    switch (elementAdapter.getForeignKind(node)) {
       case ForeignKind.JS:
-        impactBuilder
-            .registerNativeData(astAdapter.getNativeBehaviorForJsCall(node));
+        impactBuilder.registerNativeData(
+            elementAdapter.getNativeBehaviorForJsCall(node));
         break;
       case ForeignKind.JS_BUILTIN:
         impactBuilder.registerNativeData(
-            astAdapter.getNativeBehaviorForJsBuiltinCall(node));
+            elementAdapter.getNativeBehaviorForJsBuiltinCall(node));
         break;
       case ForeignKind.JS_EMBEDDED_GLOBAL:
         impactBuilder.registerNativeData(
-            astAdapter.getNativeBehaviorForJsEmbeddedGlobalCall(node));
+            elementAdapter.getNativeBehaviorForJsEmbeddedGlobalCall(node));
         break;
       case ForeignKind.JS_INTERCEPTOR_CONSTANT:
         InterfaceType type =
-            astAdapter.getInterfaceTypeForJsInterceptorCall(node);
+            elementAdapter.getInterfaceTypeForJsInterceptorCall(node);
         if (type != null) {
           impactBuilder.registerTypeUse(new TypeUse.instantiation(type));
         }
@@ -334,10 +348,10 @@
   void visitStaticGet(ir.StaticGet node) {
     ir.Member target = node.target;
     if (target is ir.Procedure && target.kind == ir.ProcedureKind.Method) {
-      FunctionEntity method = astAdapter.getMethod(target);
+      FunctionEntity method = elementAdapter.getMethod(target);
       impactBuilder.registerStaticUse(new StaticUse.staticTearOff(method));
     } else {
-      MemberEntity member = astAdapter.getMember(target);
+      MemberEntity member = elementAdapter.getMember(target);
       impactBuilder.registerStaticUse(new StaticUse.staticGet(member));
     }
   }
@@ -345,15 +359,15 @@
   @override
   void visitStaticSet(ir.StaticSet node) {
     visitNode(node.value);
-    MemberEntity member = astAdapter.getMember(node.target);
+    MemberEntity member = elementAdapter.getMember(node.target);
     impactBuilder.registerStaticUse(new StaticUse.staticSet(member));
   }
 
   void handleSuperInvocation(ir.Node target, ir.Node arguments) {
-    FunctionEntity method = astAdapter.getMethod(target);
+    FunctionEntity method = elementAdapter.getMethod(target);
     _visitArguments(arguments);
     impactBuilder.registerStaticUse(new StaticUse.superInvoke(
-        method, astAdapter.getCallStructure(arguments)));
+        method, elementAdapter.getCallStructure(arguments)));
   }
 
   @override
@@ -370,10 +384,10 @@
 
   void handleSuperGet(ir.Member target) {
     if (target is ir.Procedure && target.kind == ir.ProcedureKind.Method) {
-      FunctionEntity method = astAdapter.getMethod(target);
+      FunctionEntity method = elementAdapter.getMethod(target);
       impactBuilder.registerStaticUse(new StaticUse.superTearOff(method));
     } else {
-      MemberEntity member = astAdapter.getMember(target);
+      MemberEntity member = elementAdapter.getMember(target);
       impactBuilder.registerStaticUse(new StaticUse.superGet(member));
     }
   }
@@ -391,10 +405,10 @@
   void handleSuperSet(ir.Node target, ir.Node value) {
     visitNode(value);
     if (target is ir.Field) {
-      FieldEntity field = astAdapter.getField(target);
+      FieldEntity field = elementAdapter.getField(target);
       impactBuilder.registerStaticUse(new StaticUse.superFieldSet(field));
     } else {
-      FunctionEntity method = astAdapter.getMethod(target);
+      FunctionEntity method = elementAdapter.getMethod(target);
       impactBuilder.registerStaticUse(new StaticUse.superSetterSet(method));
     }
   }
@@ -419,7 +433,7 @@
     } else {
       visitNode(invocation.receiver);
       impactBuilder.registerDynamicUse(
-          new DynamicUse(astAdapter.getSelector(invocation), null));
+          new DynamicUse(elementAdapter.getSelector(invocation), null));
     }
     _visitArguments(invocation.arguments);
   }
@@ -428,7 +442,7 @@
   void visitPropertyGet(ir.PropertyGet node) {
     visitNode(node.receiver);
     impactBuilder.registerDynamicUse(new DynamicUse(
-        new Selector.getter(astAdapter.getName(node.name)), null));
+        new Selector.getter(elementAdapter.getName(node.name)), null));
   }
 
   @override
@@ -436,7 +450,7 @@
     visitNode(node.receiver);
     visitNode(node.value);
     impactBuilder.registerDynamicUse(new DynamicUse(
-        new Selector.setter(astAdapter.getName(node.name)), null));
+        new Selector.setter(elementAdapter.getName(node.name)), null));
   }
 
   @override
@@ -457,7 +471,7 @@
   @override
   void visitFunctionDeclaration(ir.FunctionDeclaration node) {
     impactBuilder.registerStaticUse(
-        new StaticUse.closure(astAdapter.getLocalFunction(node)));
+        new StaticUse.closure(elementAdapter.getLocalFunction(node)));
     handleSignature(node.function);
     visitNode(node.function.body);
   }
@@ -465,7 +479,7 @@
   @override
   void visitFunctionExpression(ir.FunctionExpression node) {
     impactBuilder.registerStaticUse(
-        new StaticUse.closure(astAdapter.getLocalFunction(node)));
+        new StaticUse.closure(elementAdapter.getLocalFunction(node)));
     handleSignature(node.function);
     visitNode(node.function.body);
   }
@@ -483,14 +497,14 @@
   @override
   void visitIsExpression(ir.IsExpression node) {
     impactBuilder.registerTypeUse(
-        new TypeUse.isCheck(astAdapter.getDartType(node.type)));
+        new TypeUse.isCheck(elementAdapter.getDartType(node.type)));
     visitNode(node.operand);
   }
 
   @override
   void visitAsExpression(ir.AsExpression node) {
-    impactBuilder
-        .registerTypeUse(new TypeUse.asCast(astAdapter.getDartType(node.type)));
+    impactBuilder.registerTypeUse(
+        new TypeUse.asCast(elementAdapter.getDartType(node.type)));
     visitNode(node.operand);
   }
 
@@ -530,7 +544,7 @@
     }
     if (node.guard is! ir.DynamicType) {
       impactBuilder.registerTypeUse(
-          new TypeUse.catchType(astAdapter.getDartType(node.guard)));
+          new TypeUse.catchType(elementAdapter.getDartType(node.guard)));
     }
     visitNode(node.body);
   }
@@ -544,22 +558,22 @@
   @override
   void visitTypeLiteral(ir.TypeLiteral node) {
     impactBuilder.registerTypeUse(
-        new TypeUse.typeLiteral(astAdapter.getDartType(node.type)));
+        new TypeUse.typeLiteral(elementAdapter.getDartType(node.type)));
   }
 
   @override
   void visitFieldInitializer(ir.FieldInitializer node) {
     impactBuilder.registerStaticUse(
-        new StaticUse.fieldInit(astAdapter.getField(node.field)));
+        new StaticUse.fieldInit(elementAdapter.getField(node.field)));
     visitNode(node.value);
   }
 
   @override
   void visitRedirectingInitializer(ir.RedirectingInitializer node) {
     _visitArguments(node.arguments);
-    FunctionEntity target = astAdapter.getConstructor(node.target);
+    ConstructorEntity target = elementAdapter.getConstructor(node.target);
     impactBuilder.registerStaticUse(new StaticUse.superConstructorInvoke(
-        target, astAdapter.getCallStructure(node.arguments)));
+        target, elementAdapter.getCallStructure(node.arguments)));
   }
 
   // TODO(johnniwinther): Make this throw and visit child nodes explicitly
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index 70d9522..618c78b 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -7,6 +7,7 @@
 import '../compiler.dart' show Compiler;
 import '../elements/resolution_types.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../io/source_information.dart';
 import '../js/js.dart' as js;
 import '../js_backend/js_backend.dart';
@@ -250,10 +251,11 @@
     // and passed to the generative constructor factory function as a parameter.
     // Instead of allocating and initializing the object, the constructor
     // 'upgrades' the native subclass object by initializing the Dart fields.
-    bool isNativeUpgradeFactory =
-        element.isGenerativeConstructor && backend.isNativeOrExtendsNative(cls);
-    if (backend.isInterceptedMethod(element)) {
-      bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
+    bool isNativeUpgradeFactory = element.isGenerativeConstructor &&
+        backend.nativeData.isNativeOrExtendsNative(cls);
+    if (backend.interceptorData.isInterceptedMethod(element)) {
+      bool isInterceptorClass =
+          backend.interceptorData.isInterceptorClass(cls.declaration);
       String name = isInterceptorClass ? 'receiver' : '_';
       SyntheticLocal parameter = new SyntheticLocal(name, executableContext);
       HParameterValue value = new HParameterValue(parameter, getTypeOfThis());
@@ -486,7 +488,6 @@
     Map<Local, HInstruction> savedDirectLocals =
         new Map<Local, HInstruction>.from(directLocals);
 
-    JavaScriptBackend backend = _compiler.backend;
     // Create phis for all elements in the definitions environment.
     savedDirectLocals.forEach((Local local, HInstruction instruction) {
       if (isAccessedDirectly(local)) {
@@ -671,5 +672,8 @@
 
   SyntheticLocal(this.name, this.executableContext);
 
+  @override
+  MemberElement get memberContext => executableContext.memberContext;
+
   toString() => 'SyntheticLocal($name)';
 }
diff --git a/pkg/compiler/lib/src/ssa/loop_handler.dart b/pkg/compiler/lib/src/ssa/loop_handler.dart
index 3b59a5f..6e7ad54 100644
--- a/pkg/compiler/lib/src/ssa/loop_handler.dart
+++ b/pkg/compiler/lib/src/ssa/loop_handler.dart
@@ -368,7 +368,7 @@
 
   @override
   JumpTarget getTargetDefinition(ir.TreeNode node) =>
-      astAdapter.getJumpTarget(node.parent);
+      astAdapter.getJumpTarget(node);
 
   @override
   int loopKind(ir.TreeNode node) => node.accept(new _KernelLoopTypeVisitor());
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 1852bce..48d1a23 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -8,8 +8,7 @@
 import '../compiler.dart' show Compiler;
 import '../constants/constant_system.dart';
 import '../constants/values.dart';
-import '../elements/elements.dart'
-    show Entity, JumpTarget, LabelDefinition, Local;
+import '../elements/elements.dart' show JumpTarget, LabelDefinition;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../io/source_information.dart';
@@ -45,6 +44,7 @@
   R visitFieldGet(HFieldGet node);
   R visitFieldSet(HFieldSet node);
   R visitForeignCode(HForeignCode node);
+  R visitGetLength(HGetLength node);
   R visitGoto(HGoto node);
   R visitGreater(HGreater node);
   R visitGreaterEqual(HGreaterEqual node);
@@ -358,6 +358,7 @@
   visitFieldGet(HFieldGet node) => visitFieldAccess(node);
   visitFieldSet(HFieldSet node) => visitFieldAccess(node);
   visitForeignCode(HForeignCode node) => visitInstruction(node);
+  visitGetLength(HGetLength node) => visitInstruction(node);
   visitGoto(HGoto node) => visitControlFlow(node);
   visitGreater(HGreater node) => visitRelational(node);
   visitGreaterEqual(HGreaterEqual node) => visitRelational(node);
@@ -893,6 +894,7 @@
 
   static const int FOREIGN_CODE_TYPECODE = 41;
   static const int REMAINDER_TYPECODE = 42;
+  static const int GET_LENGTH_TYPECODE = 43;
 
   HInstruction(this.inputs, this.instructionType)
       : id = idCounter++,
@@ -978,76 +980,74 @@
     // TODO(sra): It should be possible to test only jsDoubleClass and
     // jsUInt31Class, since all others are superclasses of these two.
     return containsType(
-            instructionType, backendClasses.numImplementation, closedWorld) ||
+            instructionType, backendClasses.numClass, closedWorld) ||
+        containsType(instructionType, backendClasses.intClass, closedWorld) ||
         containsType(
-            instructionType, backendClasses.intImplementation, closedWorld) ||
-        containsType(instructionType, backendClasses.positiveIntImplementation,
-            closedWorld) ||
-        containsType(instructionType, backendClasses.uint32Implementation,
-            closedWorld) ||
-        containsType(instructionType, backendClasses.uint31Implementation,
-            closedWorld) ||
+            instructionType, backendClasses.positiveIntClass, closedWorld) ||
         containsType(
-            instructionType, backendClasses.doubleImplementation, closedWorld);
+            instructionType, backendClasses.uint32Class, closedWorld) ||
+        containsType(
+            instructionType, backendClasses.uint31Class, closedWorld) ||
+        containsType(instructionType, backendClasses.doubleClass, closedWorld);
   }
 
   bool canBePrimitiveBoolean(ClosedWorld closedWorld) {
-    return containsType(instructionType,
-        closedWorld.backendClasses.boolImplementation, closedWorld);
+    return containsType(
+        instructionType, closedWorld.backendClasses.boolClass, closedWorld);
   }
 
   bool canBePrimitiveArray(ClosedWorld closedWorld) {
     BackendClasses backendClasses = closedWorld.backendClasses;
     return containsType(
-            instructionType, backendClasses.listImplementation, closedWorld) ||
-        containsType(instructionType, backendClasses.fixedListImplementation,
-            closedWorld) ||
-        containsType(instructionType, backendClasses.growableListImplementation,
-            closedWorld) ||
-        containsType(instructionType, backendClasses.constListImplementation,
-            closedWorld);
+            instructionType, backendClasses.listClass, closedWorld) ||
+        containsType(
+            instructionType, backendClasses.fixedListClass, closedWorld) ||
+        containsType(
+            instructionType, backendClasses.growableListClass, closedWorld) ||
+        containsType(
+            instructionType, backendClasses.constListClass, closedWorld);
   }
 
   bool isIndexablePrimitive(ClosedWorld closedWorld) {
     return instructionType.containsOnlyString(closedWorld) ||
-        isInstanceOf(instructionType,
-            closedWorld.backendClasses.indexableImplementation, closedWorld);
+        isInstanceOf(instructionType, closedWorld.backendClasses.indexableClass,
+            closedWorld);
   }
 
   bool isFixedArray(ClosedWorld closedWorld) {
     BackendClasses backendClasses = closedWorld.backendClasses;
     // TODO(sra): Recognize the union of these types as well.
-    return containsOnlyType(instructionType,
-            backendClasses.fixedListImplementation, closedWorld) ||
-        containsOnlyType(instructionType,
-            backendClasses.constListImplementation, closedWorld);
+    return containsOnlyType(
+            instructionType, backendClasses.fixedListClass, closedWorld) ||
+        containsOnlyType(
+            instructionType, backendClasses.constListClass, closedWorld);
   }
 
   bool isExtendableArray(ClosedWorld closedWorld) {
     return containsOnlyType(instructionType,
-        closedWorld.backendClasses.growableListImplementation, closedWorld);
+        closedWorld.backendClasses.growableListClass, closedWorld);
   }
 
   bool isMutableArray(ClosedWorld closedWorld) {
     return isInstanceOf(instructionType,
-        closedWorld.backendClasses.mutableListImplementation, closedWorld);
+        closedWorld.backendClasses.mutableListClass, closedWorld);
   }
 
   bool isReadableArray(ClosedWorld closedWorld) {
-    return isInstanceOf(instructionType,
-        closedWorld.backendClasses.listImplementation, closedWorld);
+    return isInstanceOf(
+        instructionType, closedWorld.backendClasses.listClass, closedWorld);
   }
 
   bool isMutableIndexable(ClosedWorld closedWorld) {
     return isInstanceOf(instructionType,
-        closedWorld.backendClasses.mutableIndexableImplementation, closedWorld);
+        closedWorld.backendClasses.mutableIndexableClass, closedWorld);
   }
 
   bool isArray(ClosedWorld closedWorld) => isReadableArray(closedWorld);
 
   bool canBePrimitiveString(ClosedWorld closedWorld) {
-    return containsType(instructionType,
-        closedWorld.backendClasses.stringImplementation, closedWorld);
+    return containsType(
+        instructionType, closedWorld.backendClasses.stringClass, closedWorld);
   }
 
   bool isInteger(ClosedWorld closedWorld) {
@@ -1057,25 +1057,25 @@
 
   bool isUInt32(ClosedWorld closedWorld) {
     return !instructionType.isNullable &&
-        isInstanceOf(instructionType,
-            closedWorld.backendClasses.uint32Implementation, closedWorld);
+        isInstanceOf(instructionType, closedWorld.backendClasses.uint32Class,
+            closedWorld);
   }
 
   bool isUInt31(ClosedWorld closedWorld) {
     return !instructionType.isNullable &&
-        isInstanceOf(instructionType,
-            closedWorld.backendClasses.uint31Implementation, closedWorld);
+        isInstanceOf(instructionType, closedWorld.backendClasses.uint31Class,
+            closedWorld);
   }
 
   bool isPositiveInteger(ClosedWorld closedWorld) {
     return !instructionType.isNullable &&
         isInstanceOf(instructionType,
-            closedWorld.backendClasses.positiveIntImplementation, closedWorld);
+            closedWorld.backendClasses.positiveIntClass, closedWorld);
   }
 
   bool isPositiveIntegerOrNull(ClosedWorld closedWorld) {
     return isInstanceOf(instructionType,
-        closedWorld.backendClasses.positiveIntImplementation, closedWorld);
+        closedWorld.backendClasses.positiveIntClass, closedWorld);
   }
 
   bool isIntegerOrNull(ClosedWorld closedWorld) {
@@ -1354,7 +1354,7 @@
     assert(!type.isTypeVariable);
     assert(type.treatAsRaw || type.isFunctionType);
     if (type.isDynamic) return this;
-    if (type.isObject) return this;
+    if (type == closedWorld.commonElements.objectType) return this;
     if (type.isVoid || type.isFunctionType || type.isMalformed) {
       return new HTypeConversion(
           type, kind, closedWorld.commonMasks.dynamicType, this);
@@ -1697,9 +1697,7 @@
 }
 
 abstract class HFieldAccess extends HInstruction {
-  // TODO(johnniwinther): This should be a [FieldLike] but JSIndexable.length is
-  // encoded using a [HFieldGet].
-  final MemberEntity element;
+  final FieldEntity element;
 
   HFieldAccess(this.element, List<HInstruction> inputs, TypeMask type)
       : super(inputs, type);
@@ -1710,7 +1708,7 @@
 class HFieldGet extends HFieldAccess {
   final bool isAssignable;
 
-  HFieldGet(MemberEntity element, HInstruction receiver, TypeMask type,
+  HFieldGet(FieldEntity element, HInstruction receiver, TypeMask type,
       {bool isAssignable})
       : this.isAssignable =
             (isAssignable != null) ? isAssignable : element.isAssignable,
@@ -1751,7 +1749,7 @@
 }
 
 class HFieldSet extends HFieldAccess {
-  HFieldSet(MemberEntity element, HInstruction receiver, HInstruction value)
+  HFieldSet(FieldEntity element, HInstruction receiver, HInstruction value)
       : super(element, <HInstruction>[receiver, value],
             const TypeMask.nonNullEmpty()) {
     sideEffects.clearAllSideEffects();
@@ -1771,6 +1769,34 @@
   String toString() => "FieldSet $element";
 }
 
+class HGetLength extends HInstruction {
+  final bool isAssignable;
+  HGetLength(HInstruction receiver, TypeMask type, {bool this.isAssignable})
+      : super(<HInstruction>[receiver], type) {
+    assert(isAssignable != null);
+    sideEffects.clearAllSideEffects();
+    sideEffects.clearAllDependencies();
+    setUseGvn();
+    if (this.isAssignable) {
+      sideEffects.setDependsOnInstancePropertyStore();
+    }
+  }
+
+  HInstruction get receiver => inputs.single;
+
+  bool canThrow() => receiver.canBeNull();
+
+  HInstruction getDartReceiver(ClosedWorld closedWorld) => receiver;
+  bool onlyThrowsNSM() => true;
+
+  accept(HVisitor visitor) => visitor.visitGetLength(this);
+
+  int typeCode() => HInstruction.GET_LENGTH_TYPECODE;
+  bool typeEquals(other) => other is HGetLength;
+  bool dataEquals(HGetLength other) => true;
+  String toString() => "GetLength()";
+}
+
 /**
  * HReadModifyWrite is a late stage instruction for a field (property) update
  * via an assignment operation or pre- or post-increment.
@@ -2813,6 +2839,7 @@
   final Selector receiverTypeCheckSelector;
 
   TypeMask checkedType; // Not final because we refine it.
+  TypeMask inputType; // Holds input type for codegen after HTypeKnown removal.
 
   HTypeConversion(
       this.typeExpression, this.kind, TypeMask type, HInstruction input,
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index b7b0c0a..2ac63da 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -10,7 +10,7 @@
 import '../constants/values.dart';
 import '../core_types.dart' show CommonElements;
 import '../elements/elements.dart'
-    show ClassElement, Entity, FieldElement, MethodElement;
+    show ClassElement, FieldElement, MethodElement;
 import '../elements/entities.dart';
 import '../elements/resolution_types.dart';
 import '../js/js.dart' as js;
@@ -85,9 +85,13 @@
         // updated because they now have different inputs.
         new SsaTypePropagator(compiler, closedWorld),
         codeMotion = new SsaCodeMotion(),
-        new SsaLoadElimination(compiler, closedWorld),
+        new SsaLoadElimination(backend, compiler, closedWorld),
         new SsaRedundantPhiEliminator(),
         new SsaDeadPhiEliminator(),
+        // After GVN and load elimination the same value may be used in code
+        // controlled by a test on the value, so redo 'conversion insertion' to
+        // learn from the refined type.
+        new SsaTypeConversionInserter(closedWorld),
         new SsaTypePropagator(compiler, closedWorld),
         new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this),
         // Previous optimizations may have generated new
@@ -142,8 +146,8 @@
     return true;
   }
   // TODO(sra): Recognize any combination of fixed length indexables.
-  if (mask.containsOnly(closedWorld.backendClasses.fixedListImplementation) ||
-      mask.containsOnly(closedWorld.backendClasses.constListImplementation) ||
+  if (mask.containsOnly(closedWorld.backendClasses.fixedListClass) ||
+      mask.containsOnly(closedWorld.backendClasses.constListClass) ||
       mask.containsOnlyString(closedWorld) ||
       closedWorld.commonMasks.isTypedArray(mask)) {
     return true;
@@ -345,7 +349,6 @@
         ListConstantValue constant = constantInput.constant;
         return graph.addConstantInt(constant.length, closedWorld);
       }
-      MemberEntity element = helpers.jsIndexableLength;
       bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld);
       TypeMask actualType = node.instructionType;
       TypeMask resultType = closedWorld.commonMasks.positiveIntType;
@@ -357,8 +360,8 @@
           actualType, helpers.jsUInt32Class, closedWorld)) {
         resultType = closedWorld.commonMasks.uint32Type;
       }
-      HFieldGet result = new HFieldGet(element, actualReceiver, resultType,
-          isAssignable: !isFixed);
+      HGetLength result =
+          new HGetLength(actualReceiver, resultType, isAssignable: !isFixed);
       return result;
     } else if (actualReceiver.isConstantMap()) {
       HConstant constantInput = actualReceiver;
@@ -865,35 +868,6 @@
   HInstruction visitFieldGet(HFieldGet node) {
     if (node.isNullCheck) return node;
     var receiver = node.receiver;
-    if (node.element == helpers.jsIndexableLength) {
-      if (graph.allocatedFixedLists.contains(receiver)) {
-        // TODO(ngeoffray): checking if the second input is an integer
-        // should not be necessary but it currently makes it easier for
-        // other optimizations to reason about a fixed length constructor
-        // that we know takes an int.
-        if (receiver.inputs[0].isInteger(closedWorld)) {
-          return receiver.inputs[0];
-        }
-      } else if (receiver.isConstantList() || receiver.isConstantString()) {
-        return graph.addConstantInt(receiver.constant.length, closedWorld);
-      } else {
-        var type = receiver.instructionType;
-        if (type.isContainer && type.length != null) {
-          HInstruction constant =
-              graph.addConstantInt(type.length, closedWorld);
-          if (type.isNullable) {
-            // If the container can be null, we update all uses of the
-            // length access to use the constant instead, but keep the
-            // length access in the graph, to ensure we still have a
-            // null check.
-            node.block.rewrite(node, constant);
-            return node;
-          } else {
-            return constant;
-          }
-        }
-      }
-    }
 
     // HFieldGet of a constructed constant can be replaced with the constant's
     // field.
@@ -912,6 +886,37 @@
     return node;
   }
 
+  HInstruction visitGetLength(HGetLength node) {
+    var receiver = node.receiver;
+    if (graph.allocatedFixedLists.contains(receiver)) {
+      // TODO(ngeoffray): checking if the second input is an integer
+      // should not be necessary but it currently makes it easier for
+      // other optimizations to reason about a fixed length constructor
+      // that we know takes an int.
+      if (receiver.inputs[0].isInteger(closedWorld)) {
+        return receiver.inputs[0];
+      }
+    } else if (receiver.isConstantList() || receiver.isConstantString()) {
+      return graph.addConstantInt(receiver.constant.length, closedWorld);
+    } else {
+      var type = receiver.instructionType;
+      if (type.isContainer && type.length != null) {
+        HInstruction constant = graph.addConstantInt(type.length, closedWorld);
+        if (type.isNullable) {
+          // If the container can be null, we update all uses of the
+          // length access to use the constant instead, but keep the
+          // length access in the graph, to ensure we still have a
+          // null check.
+          node.block.rewrite(node, constant);
+          return node;
+        } else {
+          return constant;
+        }
+      }
+    }
+    return node;
+  }
+
   HInstruction visitIndex(HIndex node) {
     if (node.receiver.isConstantList() && node.index.isConstantInteger()) {
       var instruction = node.receiver;
@@ -1344,8 +1349,8 @@
 
   HBoundsCheck insertBoundsCheck(
       HInstruction indexNode, HInstruction array, HInstruction indexArgument) {
-    HFieldGet length = new HFieldGet(helpers.jsIndexableLength, array,
-        closedWorld.commonMasks.positiveIntType,
+    HGetLength length = new HGetLength(
+        array, closedWorld.commonMasks.positiveIntType,
         isAssignable: !isFixedLength(array.instructionType, closedWorld));
     indexNode.block.addBefore(indexNode, length);
 
@@ -2241,13 +2246,14 @@
  * location.
  */
 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
+  final JavaScriptBackend backend;
   final Compiler compiler;
   final ClosedWorld closedWorld;
   final String name = "SsaLoadElimination";
   MemorySet memorySet;
   List<MemorySet> memories;
 
-  SsaLoadElimination(this.compiler, this.closedWorld);
+  SsaLoadElimination(this.backend, this.compiler, this.closedWorld);
 
   void visitGraph(HGraph graph) {
     memories = new List<MemorySet>(graph.blocks.length);
@@ -2302,8 +2308,18 @@
 
   void visitFieldGet(HFieldGet instruction) {
     if (instruction.isNullCheck) return;
-    MemberEntity element = instruction.element;
+    FieldEntity element = instruction.element;
     HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck();
+    _visitFieldGet(element, receiver, instruction);
+  }
+
+  void visitGetLength(HGetLength instruction) {
+    _visitFieldGet(backend.helpers.jsIndexableLength,
+        instruction.receiver.nonCheck(), instruction);
+  }
+
+  void _visitFieldGet(
+      MemberEntity element, HInstruction receiver, HInstruction instruction) {
     HInstruction existing = memorySet.lookupFieldValue(element, receiver);
     if (existing != null) {
       instruction.block.rewriteWithBetterUser(instruction, existing);
@@ -2460,6 +2476,10 @@
   /**
    * Maps a field to a map of receiver to value.
    */
+  // The key is [MemberEntity] rather than [FieldEntity] so that HGetLength can
+  // be modeled as the JSIndexable.length abstract getter.
+  // TODO(25544): Split length effects from other effects and model lengths
+  // separately.
   final Map<MemberEntity, Map<HInstruction, HInstruction>> fieldValues =
       <MemberEntity, Map<HInstruction, HInstruction>>{};
 
diff --git a/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart b/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
index 8c1fa21..7493d30 100644
--- a/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
@@ -4,7 +4,6 @@
 
 import '../compiler.dart';
 import '../io/source_information.dart';
-import '../js_backend/js_backend.dart';
 import '../tree/tree.dart' as ast;
 
 import 'graph_builder.dart';
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index c76b592..d06c00e 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -238,6 +238,10 @@
     }
   }
 
+  String visitGetLength(HGetLength node) {
+    return 'GetLength: ${temporaryId(node.receiver)}';
+  }
+
   String visitLocalGet(HLocalGet node) {
     String localName = node.variable.name;
     return 'LocalGet: ${temporaryId(node.local)}.$localName';
diff --git a/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart b/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart
index ea06f8b..e11b8f4 100644
--- a/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart
+++ b/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart
@@ -57,12 +57,8 @@
   }
 
   bool visitIfStatement(ir.IfStatement ifStatement) {
-    if (ifStatement.then.accept(this)) {
-      if (ifStatement.otherwise != null) {
-        return ifStatement.otherwise.accept(this);
-      }
-    }
-    return false;
+    return ifStatement.then.accept(this) ||
+        (ifStatement.otherwise != null && ifStatement.otherwise.accept(this));
   }
 
   bool visitTryCatch(ir.TryCatch tryCatch) {
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
index a624e13..44eb5bc 100644
--- a/pkg/compiler/lib/src/ssa/type_builder.dart
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -6,9 +6,10 @@
 import 'nodes.dart';
 import '../closure.dart';
 import '../common.dart';
-import '../elements/resolution_types.dart';
 import '../types/types.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
+import '../elements/resolution_types.dart';
 import '../io/source_information.dart';
 import '../universe/use.dart' show TypeUse;
 
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 07e99b3..13d417a 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -11,7 +11,7 @@
 
 class TypeMaskFactory {
   static TypeMask inferredReturnTypeForElement(
-      Element element, GlobalTypeInferenceResults results) {
+      MethodElement element, GlobalTypeInferenceResults results) {
     return results.resultOf(element).returnType ??
         results.closedWorld.commonMasks.dynamicType;
   }
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index 23d5087..b4a9d55 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -698,12 +698,11 @@
   }
 
   Range visitFieldGet(HFieldGet fieldGet) {
-    if (!fieldGet.isInteger(closedWorld)) return info.newUnboundRange();
-    if (!fieldGet.receiver.isIndexablePrimitive(closedWorld)) {
-      return visitInstruction(fieldGet);
-    }
-    assert(fieldGet.element == backendHelpers.jsIndexableLength);
-    PositiveValue value = info.newPositiveValue(fieldGet);
+    return visitInstruction(fieldGet);
+  }
+
+  Range visitGetLength(HGetLength node) {
+    PositiveValue value = info.newPositiveValue(node);
     // We know this range is above zero. To simplify the analysis, we
     // put the zero value as the lower bound of this range. This
     // allows to easily remove the second bound check in the following
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index b81661a..2834a28 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -9,10 +9,10 @@
 import 'dart:collection';
 
 import 'common.dart';
-import 'tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import 'tree/dartstring.dart' show DartString;
 import 'tree/nodes.dart' show StringQuoting;
-import 'util/characters.dart';
+import 'package:front_end/src/fasta/scanner/characters.dart';
 
 class StringValidator {
   final DiagnosticReporter reporter;
@@ -99,8 +99,8 @@
   }
 
   void stringParseError(String message, Token token, int offset) {
-    reporter.reportErrorMessage(
-        token, MessageKind.GENERIC, {'text': "$message @ $offset"});
+    reporter.reportErrorMessage(reporter.spanFromToken(token),
+        MessageKind.GENERIC, {'text': "$message @ $offset"});
   }
 
   /**
diff --git a/pkg/compiler/lib/src/tokens/keyword.dart b/pkg/compiler/lib/src/tokens/keyword.dart
deleted file mode 100644
index 607c4e8..0000000
--- a/pkg/compiler/lib/src/tokens/keyword.dart
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.tokens.keywords;
-
-import '../util/characters.dart' as Characters show $a;
-import 'precedence.dart' show PrecedenceInfo;
-import 'precedence_constants.dart' as Precedence
-    show AS_INFO, IS_INFO, KEYWORD_INFO;
-
-/**
- * A keyword in the Dart programming language.
- */
-class Keyword {
-  static const List<Keyword> values = const <Keyword>[
-    const Keyword("assert"),
-    const Keyword("break"),
-    const Keyword("case"),
-    const Keyword("catch"),
-    const Keyword("class"),
-    const Keyword("const"),
-    const Keyword("continue"),
-    const Keyword("default"),
-    const Keyword("do"),
-    const Keyword("else"),
-    const Keyword("enum"),
-    const Keyword("extends"),
-    const Keyword("false"),
-    const Keyword("final"),
-    const Keyword("finally"),
-    const Keyword("for"),
-    const Keyword("if"),
-    const Keyword("in"),
-    const Keyword("new"),
-    const Keyword("null"),
-    const Keyword("rethrow"),
-    const Keyword("return"),
-    const Keyword("super"),
-    const Keyword("switch"),
-    const Keyword("this"),
-    const Keyword("throw"),
-    const Keyword("true"),
-    const Keyword("try"),
-    const Keyword("var"),
-    const Keyword("void"),
-    const Keyword("while"),
-    const Keyword("with"),
-
-    // TODO(ahe): Don't think this is a reserved word.
-    // See: http://dartbug.com/5579
-    const Keyword("is", info: Precedence.IS_INFO),
-
-    const Keyword("abstract", isBuiltIn: true),
-    const Keyword("as", info: Precedence.AS_INFO, isBuiltIn: true),
-    const Keyword("covariant", isBuiltIn: true),
-    const Keyword("dynamic", isBuiltIn: true),
-    const Keyword("export", isBuiltIn: true),
-    const Keyword("external", isBuiltIn: true),
-    const Keyword("factory", isBuiltIn: true),
-    const Keyword("get", isBuiltIn: true),
-    const Keyword("implements", isBuiltIn: true),
-    const Keyword("import", isBuiltIn: true),
-    const Keyword("library", isBuiltIn: true),
-    const Keyword("operator", isBuiltIn: true),
-    const Keyword("part", isBuiltIn: true),
-    const Keyword("set", isBuiltIn: true),
-    const Keyword("static", isBuiltIn: true),
-    const Keyword("typedef", isBuiltIn: true),
-
-    const Keyword("hide", isPseudo: true),
-    const Keyword("native", isPseudo: true),
-    const Keyword("of", isPseudo: true),
-    const Keyword("on", isPseudo: true),
-    const Keyword("show", isPseudo: true),
-    const Keyword("source", isPseudo: true),
-    const Keyword("deferred", isPseudo: true),
-    const Keyword("async", isPseudo: true),
-    const Keyword("sync", isPseudo: true),
-    const Keyword("await", isPseudo: true),
-    const Keyword("yield", isPseudo: true),
-  ];
-
-  final String syntax;
-  final bool isPseudo;
-  final bool isBuiltIn;
-  final PrecedenceInfo info;
-
-  static Map<String, Keyword> _keywords;
-  static Map<String, Keyword> get keywords {
-    if (_keywords == null) {
-      _keywords = computeKeywordMap();
-    }
-    return _keywords;
-  }
-
-  const Keyword(this.syntax,
-      {this.isPseudo: false,
-      this.isBuiltIn: false,
-      this.info: Precedence.KEYWORD_INFO});
-
-  static Map<String, Keyword> computeKeywordMap() {
-    Map<String, Keyword> result = new Map<String, Keyword>();
-    for (Keyword keyword in values) {
-      result[keyword.syntax] = keyword;
-    }
-    return result;
-  }
-
-  String toString() => syntax;
-}
-
-/**
- * Abstract state in a state machine for scanning keywords.
- */
-abstract class KeywordState {
-  KeywordState(this.keyword);
-
-  KeywordState next(int c);
-  final Keyword keyword;
-
-  static KeywordState _KEYWORD_STATE;
-  static KeywordState get KEYWORD_STATE {
-    if (_KEYWORD_STATE == null) {
-      List<String> strings = new List<String>(Keyword.values.length);
-      for (int i = 0; i < Keyword.values.length; i++) {
-        strings[i] = Keyword.values[i].syntax;
-      }
-      strings.sort((a, b) => a.compareTo(b));
-      _KEYWORD_STATE = computeKeywordStateTable(0, strings, 0, strings.length);
-    }
-    return _KEYWORD_STATE;
-  }
-
-  static KeywordState computeKeywordStateTable(
-      int start, List<String> strings, int offset, int length) {
-    List<KeywordState> result = new List<KeywordState>(26);
-    assert(length != 0);
-    int chunk = 0;
-    int chunkStart = -1;
-    bool isLeaf = false;
-    for (int i = offset; i < offset + length; i++) {
-      if (strings[i].length == start) {
-        isLeaf = true;
-      }
-      if (strings[i].length > start) {
-        int c = strings[i].codeUnitAt(start);
-        if (chunk != c) {
-          if (chunkStart != -1) {
-            assert(result[chunk - Characters.$a] == null);
-            result[chunk - Characters.$a] = computeKeywordStateTable(
-                start + 1, strings, chunkStart, i - chunkStart);
-          }
-          chunkStart = i;
-          chunk = c;
-        }
-      }
-    }
-    if (chunkStart != -1) {
-      assert(result[chunk - Characters.$a] == null);
-      result[chunk - Characters.$a] = computeKeywordStateTable(
-          start + 1, strings, chunkStart, offset + length - chunkStart);
-    } else {
-      assert(length == 1);
-      return new LeafKeywordState(strings[offset]);
-    }
-    if (isLeaf) {
-      return new ArrayKeywordState(result, strings[offset]);
-    } else {
-      return new ArrayKeywordState(result, null);
-    }
-  }
-}
-
-/**
- * A state with multiple outgoing transitions.
- */
-class ArrayKeywordState extends KeywordState {
-  final List<KeywordState> table;
-
-  ArrayKeywordState(List<KeywordState> this.table, String syntax)
-      : super((syntax == null) ? null : Keyword.keywords[syntax]);
-
-  KeywordState next(int c) => table[c - Characters.$a];
-
-  String toString() {
-    StringBuffer sb = new StringBuffer();
-    sb.write("[");
-    if (keyword != null) {
-      sb.write("*");
-      sb.write(keyword);
-      sb.write(" ");
-    }
-    List<KeywordState> foo = table;
-    for (int i = 0; i < foo.length; i++) {
-      if (foo[i] != null) {
-        sb.write("${new String.fromCharCodes([i + Characters.$a])}: "
-            "${foo[i]}; ");
-      }
-    }
-    sb.write("]");
-    return sb.toString();
-  }
-}
-
-/**
- * A state that has no outgoing transitions.
- */
-class LeafKeywordState extends KeywordState {
-  LeafKeywordState(String syntax) : super(Keyword.keywords[syntax]);
-
-  KeywordState next(int c) => null;
-
-  String toString() => keyword.syntax;
-}
diff --git a/pkg/compiler/lib/src/tokens/precedence.dart b/pkg/compiler/lib/src/tokens/precedence.dart
deleted file mode 100644
index c3f4906..0000000
--- a/pkg/compiler/lib/src/tokens/precedence.dart
+++ /dev/null
@@ -1,19 +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.
-
-library dart2js.tokens.precedence;
-
-import '../util/util.dart' show computeHashCode;
-
-class PrecedenceInfo {
-  final String value;
-  final int precedence;
-  final int kind;
-
-  const PrecedenceInfo(this.value, this.precedence, this.kind);
-
-  toString() => 'PrecedenceInfo($value, $precedence, $kind)';
-
-  int get hashCode => computeHashCode(value, precedence, kind);
-}
diff --git a/pkg/compiler/lib/src/tokens/precedence_constants.dart b/pkg/compiler/lib/src/tokens/precedence_constants.dart
deleted file mode 100644
index 08475ec..0000000
--- a/pkg/compiler/lib/src/tokens/precedence_constants.dart
+++ /dev/null
@@ -1,189 +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.
-
-library dart2js.tokens.precedence.constants;
-
-import 'precedence.dart' show PrecedenceInfo;
-import 'token_constants.dart';
-
-// TODO(ahe): The following are not tokens in Dart.
-const PrecedenceInfo BACKPING_INFO =
-    const PrecedenceInfo('`', 0, BACKPING_TOKEN);
-const PrecedenceInfo BACKSLASH_INFO =
-    const PrecedenceInfo('\\', 0, BACKSLASH_TOKEN);
-const PrecedenceInfo PERIOD_PERIOD_PERIOD_INFO =
-    const PrecedenceInfo('...', 0, PERIOD_PERIOD_PERIOD_TOKEN);
-
-/**
- * The cascade operator has the lowest precedence of any operator
- * except assignment.
- */
-const int CASCADE_PRECEDENCE = 2;
-const PrecedenceInfo PERIOD_PERIOD_INFO =
-    const PrecedenceInfo('..', CASCADE_PRECEDENCE, PERIOD_PERIOD_TOKEN);
-
-const PrecedenceInfo BANG_INFO = const PrecedenceInfo('!', 0, BANG_TOKEN);
-const PrecedenceInfo COLON_INFO = const PrecedenceInfo(':', 0, COLON_TOKEN);
-const PrecedenceInfo INDEX_INFO = const PrecedenceInfo('[]', 0, INDEX_TOKEN);
-const PrecedenceInfo MINUS_MINUS_INFO =
-    const PrecedenceInfo('--', POSTFIX_PRECEDENCE, MINUS_MINUS_TOKEN);
-const PrecedenceInfo PLUS_PLUS_INFO =
-    const PrecedenceInfo('++', POSTFIX_PRECEDENCE, PLUS_PLUS_TOKEN);
-const PrecedenceInfo TILDE_INFO = const PrecedenceInfo('~', 0, TILDE_TOKEN);
-
-const PrecedenceInfo FUNCTION_INFO =
-    const PrecedenceInfo('=>', 0, FUNCTION_TOKEN);
-const PrecedenceInfo HASH_INFO = const PrecedenceInfo('#', 0, HASH_TOKEN);
-const PrecedenceInfo INDEX_EQ_INFO =
-    const PrecedenceInfo('[]=', 0, INDEX_EQ_TOKEN);
-const PrecedenceInfo SEMICOLON_INFO =
-    const PrecedenceInfo(';', 0, SEMICOLON_TOKEN);
-const PrecedenceInfo COMMA_INFO = const PrecedenceInfo(',', 0, COMMA_TOKEN);
-
-const PrecedenceInfo AT_INFO = const PrecedenceInfo('@', 0, AT_TOKEN);
-
-// Assignment operators.
-const int ASSIGNMENT_PRECEDENCE = 1;
-const PrecedenceInfo AMPERSAND_EQ_INFO =
-    const PrecedenceInfo('&=', ASSIGNMENT_PRECEDENCE, AMPERSAND_EQ_TOKEN);
-const PrecedenceInfo BAR_EQ_INFO =
-    const PrecedenceInfo('|=', ASSIGNMENT_PRECEDENCE, BAR_EQ_TOKEN);
-const PrecedenceInfo CARET_EQ_INFO =
-    const PrecedenceInfo('^=', ASSIGNMENT_PRECEDENCE, CARET_EQ_TOKEN);
-const PrecedenceInfo EQ_INFO =
-    const PrecedenceInfo('=', ASSIGNMENT_PRECEDENCE, EQ_TOKEN);
-const PrecedenceInfo GT_GT_EQ_INFO =
-    const PrecedenceInfo('>>=', ASSIGNMENT_PRECEDENCE, GT_GT_EQ_TOKEN);
-const PrecedenceInfo LT_LT_EQ_INFO =
-    const PrecedenceInfo('<<=', ASSIGNMENT_PRECEDENCE, LT_LT_EQ_TOKEN);
-const PrecedenceInfo MINUS_EQ_INFO =
-    const PrecedenceInfo('-=', ASSIGNMENT_PRECEDENCE, MINUS_EQ_TOKEN);
-const PrecedenceInfo PERCENT_EQ_INFO =
-    const PrecedenceInfo('%=', ASSIGNMENT_PRECEDENCE, PERCENT_EQ_TOKEN);
-const PrecedenceInfo PLUS_EQ_INFO =
-    const PrecedenceInfo('+=', ASSIGNMENT_PRECEDENCE, PLUS_EQ_TOKEN);
-const PrecedenceInfo SLASH_EQ_INFO =
-    const PrecedenceInfo('/=', ASSIGNMENT_PRECEDENCE, SLASH_EQ_TOKEN);
-const PrecedenceInfo STAR_EQ_INFO =
-    const PrecedenceInfo('*=', ASSIGNMENT_PRECEDENCE, STAR_EQ_TOKEN);
-const PrecedenceInfo TILDE_SLASH_EQ_INFO =
-    const PrecedenceInfo('~/=', ASSIGNMENT_PRECEDENCE, TILDE_SLASH_EQ_TOKEN);
-const PrecedenceInfo QUESTION_QUESTION_EQ_INFO = const PrecedenceInfo(
-    '??=', ASSIGNMENT_PRECEDENCE, QUESTION_QUESTION_EQ_TOKEN);
-
-const PrecedenceInfo QUESTION_INFO =
-    const PrecedenceInfo('?', 3, QUESTION_TOKEN);
-
-const PrecedenceInfo QUESTION_QUESTION_INFO =
-    const PrecedenceInfo('??', 4, QUESTION_QUESTION_TOKEN);
-
-const PrecedenceInfo BAR_BAR_INFO =
-    const PrecedenceInfo('||', 5, BAR_BAR_TOKEN);
-
-const PrecedenceInfo AMPERSAND_AMPERSAND_INFO =
-    const PrecedenceInfo('&&', 6, AMPERSAND_AMPERSAND_TOKEN);
-
-const PrecedenceInfo BAR_INFO = const PrecedenceInfo('|', 9, BAR_TOKEN);
-
-const PrecedenceInfo CARET_INFO = const PrecedenceInfo('^', 10, CARET_TOKEN);
-
-const PrecedenceInfo AMPERSAND_INFO =
-    const PrecedenceInfo('&', 11, AMPERSAND_TOKEN);
-
-// Equality operators.
-const int EQUALITY_PRECEDENCE = 7;
-const PrecedenceInfo BANG_EQ_EQ_INFO =
-    const PrecedenceInfo('!==', EQUALITY_PRECEDENCE, BANG_EQ_EQ_TOKEN);
-const PrecedenceInfo BANG_EQ_INFO =
-    const PrecedenceInfo('!=', EQUALITY_PRECEDENCE, BANG_EQ_TOKEN);
-const PrecedenceInfo EQ_EQ_EQ_INFO =
-    const PrecedenceInfo('===', EQUALITY_PRECEDENCE, EQ_EQ_EQ_TOKEN);
-const PrecedenceInfo EQ_EQ_INFO =
-    const PrecedenceInfo('==', EQUALITY_PRECEDENCE, EQ_EQ_TOKEN);
-
-// Relational operators.
-const int RELATIONAL_PRECEDENCE = 8;
-const PrecedenceInfo GT_EQ_INFO =
-    const PrecedenceInfo('>=', RELATIONAL_PRECEDENCE, GT_EQ_TOKEN);
-const PrecedenceInfo GT_INFO =
-    const PrecedenceInfo('>', RELATIONAL_PRECEDENCE, GT_TOKEN);
-const PrecedenceInfo IS_INFO =
-    const PrecedenceInfo('is', RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
-const PrecedenceInfo AS_INFO =
-    const PrecedenceInfo('as', RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
-const PrecedenceInfo LT_EQ_INFO =
-    const PrecedenceInfo('<=', RELATIONAL_PRECEDENCE, LT_EQ_TOKEN);
-const PrecedenceInfo LT_INFO =
-    const PrecedenceInfo('<', RELATIONAL_PRECEDENCE, LT_TOKEN);
-
-// Shift operators.
-const PrecedenceInfo GT_GT_INFO = const PrecedenceInfo('>>', 12, GT_GT_TOKEN);
-const PrecedenceInfo LT_LT_INFO = const PrecedenceInfo('<<', 12, LT_LT_TOKEN);
-
-// Additive operators.
-const PrecedenceInfo MINUS_INFO = const PrecedenceInfo('-', 13, MINUS_TOKEN);
-const PrecedenceInfo PLUS_INFO = const PrecedenceInfo('+', 13, PLUS_TOKEN);
-
-// Multiplicative operators.
-const PrecedenceInfo PERCENT_INFO =
-    const PrecedenceInfo('%', 14, PERCENT_TOKEN);
-const PrecedenceInfo SLASH_INFO = const PrecedenceInfo('/', 14, SLASH_TOKEN);
-const PrecedenceInfo STAR_INFO = const PrecedenceInfo('*', 14, STAR_TOKEN);
-const PrecedenceInfo TILDE_SLASH_INFO =
-    const PrecedenceInfo('~/', 14, TILDE_SLASH_TOKEN);
-
-const int POSTFIX_PRECEDENCE = 15;
-const PrecedenceInfo PERIOD_INFO =
-    const PrecedenceInfo('.', POSTFIX_PRECEDENCE, PERIOD_TOKEN);
-const PrecedenceInfo QUESTION_PERIOD_INFO =
-    const PrecedenceInfo('?.', POSTFIX_PRECEDENCE, QUESTION_PERIOD_TOKEN);
-
-const PrecedenceInfo KEYWORD_INFO =
-    const PrecedenceInfo('keyword', 0, KEYWORD_TOKEN);
-
-const PrecedenceInfo EOF_INFO = const PrecedenceInfo('EOF', 0, EOF_TOKEN);
-
-const PrecedenceInfo IDENTIFIER_INFO =
-    const PrecedenceInfo('identifier', 0, IDENTIFIER_TOKEN);
-
-const PrecedenceInfo BAD_INPUT_INFO =
-    const PrecedenceInfo('malformed input', 0, BAD_INPUT_TOKEN);
-
-const PrecedenceInfo OPEN_PAREN_INFO =
-    const PrecedenceInfo('(', POSTFIX_PRECEDENCE, OPEN_PAREN_TOKEN);
-
-const PrecedenceInfo CLOSE_PAREN_INFO =
-    const PrecedenceInfo(')', 0, CLOSE_PAREN_TOKEN);
-
-const PrecedenceInfo OPEN_CURLY_BRACKET_INFO =
-    const PrecedenceInfo('{', 0, OPEN_CURLY_BRACKET_TOKEN);
-
-const PrecedenceInfo CLOSE_CURLY_BRACKET_INFO =
-    const PrecedenceInfo('}', 0, CLOSE_CURLY_BRACKET_TOKEN);
-
-const PrecedenceInfo INT_INFO = const PrecedenceInfo('int', 0, INT_TOKEN);
-
-const PrecedenceInfo STRING_INFO =
-    const PrecedenceInfo('string', 0, STRING_TOKEN);
-
-const PrecedenceInfo OPEN_SQUARE_BRACKET_INFO =
-    const PrecedenceInfo('[', POSTFIX_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN);
-
-const PrecedenceInfo CLOSE_SQUARE_BRACKET_INFO =
-    const PrecedenceInfo(']', 0, CLOSE_SQUARE_BRACKET_TOKEN);
-
-const PrecedenceInfo DOUBLE_INFO =
-    const PrecedenceInfo('double', 0, DOUBLE_TOKEN);
-
-const PrecedenceInfo STRING_INTERPOLATION_INFO =
-    const PrecedenceInfo('\${', 0, STRING_INTERPOLATION_TOKEN);
-
-const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO =
-    const PrecedenceInfo('\$', 0, STRING_INTERPOLATION_IDENTIFIER_TOKEN);
-
-const PrecedenceInfo HEXADECIMAL_INFO =
-    const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN);
-
-const PrecedenceInfo COMMENT_INFO =
-    const PrecedenceInfo('comment', 0, COMMENT_TOKEN);
diff --git a/pkg/compiler/lib/src/tokens/token.dart b/pkg/compiler/lib/src/tokens/token.dart
deleted file mode 100644
index af31142..0000000
--- a/pkg/compiler/lib/src/tokens/token.dart
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.tokens;
-
-import 'dart:collection' show HashSet;
-import 'dart:convert' show UTF8;
-
-import '../common.dart';
-import '../util/util.dart' show computeHashCode;
-import 'keyword.dart' show Keyword;
-import 'precedence.dart' show PrecedenceInfo;
-import 'precedence_constants.dart' as Precedence show BAD_INPUT_INFO;
-import 'token_constants.dart' as Tokens show IDENTIFIER_TOKEN;
-
-/**
- * A token that doubles as a linked list.
- */
-abstract class Token implements Spannable {
-  /**
-   * The character offset of the start of this token within the source text.
-   */
-  final int charOffset;
-
-  Token(this.charOffset);
-
-  /**
-   * The next token in the token stream.
-   */
-  Token next;
-
-  /**
-   * The precedence info for this token. [info] determines the kind and the
-   * precedence level of this token.
-   *
-   * Defined as getter to save a field in the [KeywordToken] subclass.
-   */
-  PrecedenceInfo get info;
-
-  /**
-   * The string represented by this token, a substring of the source code.
-   *
-   * For [StringToken]s the [value] includes the quotes, explicit escapes, etc.
-   */
-  String get value;
-
-  /**
-   * For symbol and keyword tokens, returns the string value represented by this
-   * token. For [StringToken]s this method returns [:null:].
-   *
-   * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time
-   * constant originating in the [PrecedenceInfo] or in the [Keyword] instance.
-   * This allows testing for keywords and symbols using [:identical:], e.g.,
-   * [:identical('class', token.value):].
-   *
-   * Note that returning [:null:] for string tokens is important to identify
-   * symbols and keywords, we cannot use [value] instead. The string literal
-   *   "$a($b"
-   * produces ..., SymbolToken($), StringToken(a), StringToken((), ...
-   *
-   * After parsing the identifier 'a', the parser tests for a function
-   * declaration using [:identical(next.stringValue, '('):], which (rightfully)
-   * returns false because stringValue returns [:null:].
-   */
-  String get stringValue;
-
-  /**
-   * The kind enum of this token as determined by its [info].
-   */
-  int get kind => info.kind;
-
-  /**
-   * The precedence level for this token.
-   */
-  int get precedence => info.precedence;
-
-  /**
-   * True if this token is an identifier. Some keywords allowed as identifiers,
-   * see implementation in [KeywordToken].
-   */
-  bool isIdentifier();
-
-  /**
-   * Returns a textual representation of this token to be used for debugging
-   * purposes. The resulting string might contain information about the
-   * structure of the token, for example 'StringToken(foo)' for the identifier
-   * token 'foo'.
-   *
-   * Use [value] for the text actually parsed by the token.
-   */
-  String toString();
-
-  /**
-   * The number of characters parsed by this token.
-   */
-  int get charCount {
-    if (info == Precedence.BAD_INPUT_INFO) {
-      // This is a token that wraps around an error message. Return 1
-      // instead of the size of the length of the error message.
-      return 1;
-    } else {
-      return value.length;
-    }
-  }
-
-  /// The character offset of the end of this token within the source text.
-  int get charEnd => charOffset + charCount;
-
-  int get hashCode => computeHashCode(charOffset, info, value);
-}
-
-/// A pair of tokens marking the beginning and the end of a span. Use for error
-/// reporting.
-class TokenPair implements Spannable {
-  final Token begin;
-  final Token end;
-
-  TokenPair(this.begin, this.end);
-}
-
-/**
- * A [SymbolToken] represents the symbol in its precendence info.
- * Also used for end of file with EOF_INFO.
- */
-class SymbolToken extends Token {
-  final PrecedenceInfo info;
-
-  SymbolToken(this.info, int charOffset) : super(charOffset);
-
-  String get value => info.value;
-
-  String get stringValue => info.value;
-
-  bool isIdentifier() => false;
-
-  String toString() => "SymbolToken($value)";
-}
-
-/**
- * A [BeginGroupToken] represents a symbol that may be the beginning of
- * a pair of brackets, i.e., ( { [ < or ${
- * The [endGroup] token points to the matching closing bracked in case
- * it can be identified during scanning.
- */
-class BeginGroupToken extends SymbolToken {
-  Token endGroup;
-
-  BeginGroupToken(PrecedenceInfo info, int charOffset)
-      : super(info, charOffset);
-}
-
-/**
- * A keyword token.
- */
-class KeywordToken extends Token {
-  final Keyword keyword;
-
-  KeywordToken(this.keyword, int charOffset) : super(charOffset);
-
-  PrecedenceInfo get info => keyword.info;
-
-  String get value => keyword.syntax;
-
-  String get stringValue => keyword.syntax;
-
-  bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn;
-
-  String toString() => "KeywordToken($value)";
-}
-
-abstract class ErrorToken extends Token {
-  ErrorToken(int charOffset) : super(charOffset);
-
-  PrecedenceInfo get info => Precedence.BAD_INPUT_INFO;
-
-  String get value {
-    throw new SpannableAssertionFailure(this, assertionMessage);
-  }
-
-  String get stringValue => null;
-
-  bool isIdentifier() => false;
-
-  String get assertionMessage;
-}
-
-class BadInputToken extends ErrorToken {
-  final int character;
-
-  BadInputToken(this.character, int charOffset) : super(charOffset);
-
-  String toString() => "BadInputToken($character)";
-
-  String get assertionMessage {
-    return 'Character U+${character.toRadixString(16)} not allowed here.';
-  }
-}
-
-class UnterminatedToken extends ErrorToken {
-  final String start;
-  final int endOffset;
-
-  UnterminatedToken(this.start, int charOffset, this.endOffset)
-      : super(charOffset);
-
-  String toString() => "UnterminatedToken($start)";
-
-  String get assertionMessage => "'$start' isn't terminated.";
-
-  int get charCount => endOffset - charOffset;
-}
-
-class UnmatchedToken extends ErrorToken {
-  final BeginGroupToken begin;
-
-  UnmatchedToken(BeginGroupToken begin)
-      : this.begin = begin,
-        super(begin.charOffset);
-
-  String toString() => "UnmatchedToken(${begin.value})";
-
-  String get assertionMessage => "'$begin' isn't closed.";
-}
-
-/**
- * A String-valued token. Represents identifiers, string literals,
- * number literals, comments, and error tokens, using the corresponding
- * precedence info.
- */
-class StringToken extends Token {
-  /**
-   * The length threshold above which substring tokens are computed lazily.
-   *
-   * For string tokens that are substrings of the program source, the actual
-   * substring extraction is performed lazily. This is beneficial because
-   * not all scanned code is actually used. For unused parts, the substrings
-   * are never computed and allocated.
-   */
-  static const int LAZY_THRESHOLD = 4;
-
-  var /* String | LazySubtring */ valueOrLazySubstring;
-
-  final PrecedenceInfo info;
-
-  /**
-   * Creates a non-lazy string token. If [canonicalize] is true, the string
-   * is canonicalized before the token is created.
-   */
-  StringToken.fromString(this.info, String value, int charOffset,
-      {bool canonicalize: false})
-      : valueOrLazySubstring = canonicalizedString(value, canonicalize),
-        super(charOffset);
-
-  /**
-   * Creates a lazy string token. If [canonicalize] is true, the string
-   * is canonicalized before the token is created.
-   */
-  StringToken.fromSubstring(
-      this.info, String data, int start, int end, int charOffset,
-      {bool canonicalize: false})
-      : super(charOffset) {
-    int length = end - start;
-    if (length <= LAZY_THRESHOLD) {
-      valueOrLazySubstring =
-          canonicalizedString(data.substring(start, end), canonicalize);
-    } else {
-      valueOrLazySubstring =
-          new LazySubstring(data, start, length, canonicalize);
-    }
-  }
-
-  /**
-   * Creates a lazy string token. If [asciiOnly] is false, the byte array
-   * is passed through a UTF-8 decoder.
-   */
-  StringToken.fromUtf8Bytes(this.info, List<int> data, int start, int end,
-      bool asciiOnly, int charOffset)
-      : super(charOffset) {
-    int length = end - start;
-    if (length <= LAZY_THRESHOLD) {
-      valueOrLazySubstring = decodeUtf8(data, start, end, asciiOnly);
-    } else {
-      valueOrLazySubstring = new LazySubstring(data, start, length, asciiOnly);
-    }
-  }
-
-  String get value {
-    if (valueOrLazySubstring is String) {
-      return valueOrLazySubstring;
-    } else {
-      assert(valueOrLazySubstring is LazySubstring);
-      var data = valueOrLazySubstring.data;
-      int start = valueOrLazySubstring.start;
-      int end = start + valueOrLazySubstring.length;
-      if (data is String) {
-        valueOrLazySubstring = canonicalizedString(
-            data.substring(start, end), valueOrLazySubstring.boolValue);
-      } else {
-        valueOrLazySubstring =
-            decodeUtf8(data, start, end, valueOrLazySubstring.boolValue);
-      }
-      return valueOrLazySubstring;
-    }
-  }
-
-  /// See [Token.stringValue] for an explanation.
-  String get stringValue => null;
-
-  bool isIdentifier() => identical(kind, Tokens.IDENTIFIER_TOKEN);
-
-  String toString() => "StringToken($value)";
-
-  static final HashSet<String> canonicalizedSubstrings = new HashSet<String>();
-
-  static String canonicalizedString(String s, bool canonicalize) {
-    if (!canonicalize) return s;
-    var result = canonicalizedSubstrings.lookup(s);
-    if (result != null) return result;
-    canonicalizedSubstrings.add(s);
-    return s;
-  }
-
-  static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) {
-    var s;
-    if (asciiOnly) {
-      s = new String.fromCharCodes(data, start, end);
-    } else {
-      s = UTF8.decoder.convert(data, start, end);
-    }
-    return canonicalizedString(s, true);
-  }
-}
-
-/**
- * This class represents the necessary information to compute a substring
- * lazily. The substring can either originate from a string or from
- * a [:List<int>:] of UTF-8 bytes.
- */
-abstract class LazySubstring {
-  /** The original data, either a string or a List<int> */
-  get data;
-
-  int get start;
-  int get length;
-
-  /**
-   * If this substring is based on a String, the [boolValue] indicates wheter
-   * the resulting substring should be canonicalized.
-   *
-   * For substrings based on a byte array, the [boolValue] is true if the
-   * array only holds ASCII characters. The resulting substring will be
-   * canonicalized after decoding.
-   */
-  bool get boolValue;
-
-  LazySubstring.internal();
-
-  factory LazySubstring(data, int start, int length, bool b) {
-    // See comment on [CompactLazySubstring].
-    if (start < 0x100000 && length < 0x200) {
-      int fields = (start << 9);
-      fields = fields | length;
-      fields = fields << 1;
-      if (b) fields |= 1;
-      return new CompactLazySubstring(data, fields);
-    } else {
-      return new FullLazySubstring(data, start, length, b);
-    }
-  }
-}
-
-/**
- * This class encodes [start], [length] and [boolValue] in a single
- * 30 bit integer. It uses 20 bits for [start], which covers source files
- * of 1MB. [length] has 9 bits, which covers 512 characters.
- *
- * The file html_dart2js.dart is currently around 1MB.
- */
-class CompactLazySubstring extends LazySubstring {
-  final data;
-  final int fields;
-
-  CompactLazySubstring(this.data, this.fields) : super.internal();
-
-  int get start => fields >> 10;
-  int get length => (fields >> 1) & 0x1ff;
-  bool get boolValue => (fields & 1) == 1;
-}
-
-class FullLazySubstring extends LazySubstring {
-  final data;
-  final int start;
-  final int length;
-  final bool boolValue;
-  FullLazySubstring(this.data, this.start, this.length, this.boolValue)
-      : super.internal();
-}
-
-bool isUserDefinableOperator(String value) {
-  return isBinaryOperator(value) ||
-      isMinusOperator(value) ||
-      isTernaryOperator(value) ||
-      isUnaryOperator(value);
-}
-
-bool isUnaryOperator(String value) => value == '~';
-
-bool isBinaryOperator(String value) {
-  return value == '==' ||
-      value == '[]' ||
-      value == '*' ||
-      value == '/' ||
-      value == '%' ||
-      value == '~/' ||
-      value == '+' ||
-      value == '<<' ||
-      value == '>>' ||
-      value == '>=' ||
-      value == '>' ||
-      value == '<=' ||
-      value == '<' ||
-      value == '&' ||
-      value == '^' ||
-      value == '|';
-}
-
-bool isTernaryOperator(String value) => value == '[]=';
-
-bool isMinusOperator(String value) => value == '-';
diff --git a/pkg/compiler/lib/src/tokens/token_constants.dart b/pkg/compiler/lib/src/tokens/token_constants.dart
deleted file mode 100644
index c1078f0..0000000
--- a/pkg/compiler/lib/src/tokens/token_constants.dart
+++ /dev/null
@@ -1,82 +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.
-
-library dart2js.tokens.constants;
-
-import '../util/characters.dart';
-
-const int EOF_TOKEN = 0;
-
-const int KEYWORD_TOKEN = $k;
-const int IDENTIFIER_TOKEN = $a;
-const int BAD_INPUT_TOKEN = $X;
-const int DOUBLE_TOKEN = $d;
-const int INT_TOKEN = $i;
-const int HEXADECIMAL_TOKEN = $x;
-const int STRING_TOKEN = $SQ;
-
-const int AMPERSAND_TOKEN = $AMPERSAND;
-const int BACKPING_TOKEN = $BACKPING;
-const int BACKSLASH_TOKEN = $BACKSLASH;
-const int BANG_TOKEN = $BANG;
-const int BAR_TOKEN = $BAR;
-const int COLON_TOKEN = $COLON;
-const int COMMA_TOKEN = $COMMA;
-const int EQ_TOKEN = $EQ;
-const int GT_TOKEN = $GT;
-const int HASH_TOKEN = $HASH;
-const int OPEN_CURLY_BRACKET_TOKEN = $OPEN_CURLY_BRACKET;
-const int OPEN_SQUARE_BRACKET_TOKEN = $OPEN_SQUARE_BRACKET;
-const int OPEN_PAREN_TOKEN = $OPEN_PAREN;
-const int LT_TOKEN = $LT;
-const int MINUS_TOKEN = $MINUS;
-const int PERIOD_TOKEN = $PERIOD;
-const int PLUS_TOKEN = $PLUS;
-const int QUESTION_TOKEN = $QUESTION;
-const int AT_TOKEN = $AT;
-const int CLOSE_CURLY_BRACKET_TOKEN = $CLOSE_CURLY_BRACKET;
-const int CLOSE_SQUARE_BRACKET_TOKEN = $CLOSE_SQUARE_BRACKET;
-const int CLOSE_PAREN_TOKEN = $CLOSE_PAREN;
-const int SEMICOLON_TOKEN = $SEMICOLON;
-const int SLASH_TOKEN = $SLASH;
-const int TILDE_TOKEN = $TILDE;
-const int STAR_TOKEN = $STAR;
-const int PERCENT_TOKEN = $PERCENT;
-const int CARET_TOKEN = $CARET;
-
-const int STRING_INTERPOLATION_TOKEN = 128;
-const int LT_EQ_TOKEN = STRING_INTERPOLATION_TOKEN + 1;
-const int FUNCTION_TOKEN = LT_EQ_TOKEN + 1;
-const int SLASH_EQ_TOKEN = FUNCTION_TOKEN + 1;
-const int PERIOD_PERIOD_PERIOD_TOKEN = SLASH_EQ_TOKEN + 1;
-const int PERIOD_PERIOD_TOKEN = PERIOD_PERIOD_PERIOD_TOKEN + 1;
-const int EQ_EQ_EQ_TOKEN = PERIOD_PERIOD_TOKEN + 1;
-const int EQ_EQ_TOKEN = EQ_EQ_EQ_TOKEN + 1;
-const int LT_LT_EQ_TOKEN = EQ_EQ_TOKEN + 1;
-const int LT_LT_TOKEN = LT_LT_EQ_TOKEN + 1;
-const int GT_EQ_TOKEN = LT_LT_TOKEN + 1;
-const int GT_GT_EQ_TOKEN = GT_EQ_TOKEN + 1;
-const int INDEX_EQ_TOKEN = GT_GT_EQ_TOKEN + 1;
-const int INDEX_TOKEN = INDEX_EQ_TOKEN + 1;
-const int BANG_EQ_EQ_TOKEN = INDEX_TOKEN + 1;
-const int BANG_EQ_TOKEN = BANG_EQ_EQ_TOKEN + 1;
-const int AMPERSAND_AMPERSAND_TOKEN = BANG_EQ_TOKEN + 1;
-const int AMPERSAND_EQ_TOKEN = AMPERSAND_AMPERSAND_TOKEN + 1;
-const int BAR_BAR_TOKEN = AMPERSAND_EQ_TOKEN + 1;
-const int BAR_EQ_TOKEN = BAR_BAR_TOKEN + 1;
-const int STAR_EQ_TOKEN = BAR_EQ_TOKEN + 1;
-const int PLUS_PLUS_TOKEN = STAR_EQ_TOKEN + 1;
-const int PLUS_EQ_TOKEN = PLUS_PLUS_TOKEN + 1;
-const int MINUS_MINUS_TOKEN = PLUS_EQ_TOKEN + 1;
-const int MINUS_EQ_TOKEN = MINUS_MINUS_TOKEN + 1;
-const int TILDE_SLASH_EQ_TOKEN = MINUS_EQ_TOKEN + 1;
-const int TILDE_SLASH_TOKEN = TILDE_SLASH_EQ_TOKEN + 1;
-const int PERCENT_EQ_TOKEN = TILDE_SLASH_TOKEN + 1;
-const int GT_GT_TOKEN = PERCENT_EQ_TOKEN + 1;
-const int CARET_EQ_TOKEN = GT_GT_TOKEN + 1;
-const int COMMENT_TOKEN = CARET_EQ_TOKEN + 1;
-const int STRING_INTERPOLATION_IDENTIFIER_TOKEN = COMMENT_TOKEN + 1;
-const int QUESTION_PERIOD_TOKEN = STRING_INTERPOLATION_IDENTIFIER_TOKEN + 1;
-const int QUESTION_QUESTION_TOKEN = QUESTION_PERIOD_TOKEN + 1;
-const int QUESTION_QUESTION_EQ_TOKEN = QUESTION_QUESTION_TOKEN + 1;
diff --git a/pkg/compiler/lib/src/tokens/token_map.dart b/pkg/compiler/lib/src/tokens/token_map.dart
index e7fc3b5..4d5da67 100644
--- a/pkg/compiler/lib/src/tokens/token_map.dart
+++ b/pkg/compiler/lib/src/tokens/token_map.dart
@@ -4,7 +4,7 @@
 
 library dart2js.tokens.token_map;
 
-import 'token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 
 /**
  * Key class used in [TokenMap] in which the hash code for a token is based
diff --git a/pkg/compiler/lib/src/tree/dartstring.dart b/pkg/compiler/lib/src/tree/dartstring.dart
index 4ec773c..6df4af8 100644
--- a/pkg/compiler/lib/src/tree/dartstring.dart
+++ b/pkg/compiler/lib/src/tree/dartstring.dart
@@ -4,7 +4,7 @@
 
 import 'dart:collection';
 
-import '../util/characters.dart';
+import 'package:front_end/src/fasta/scanner/characters.dart';
 
 /**
  * The [DartString] type represents a Dart string value as a sequence of Unicode
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index 1e5f9dd..a5b20d0 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -8,14 +8,17 @@
 import '../elements/elements.dart' show MetadataAnnotation;
 import '../resolution/secret_tree_element.dart'
     show NullTreeElementMixin, StoredTreeElementMixin;
-import '../tokens/precedence_constants.dart' as Precedence show FUNCTION_INFO;
-import '../tokens/token.dart' show BeginGroupToken, Token;
-import '../tokens/token_constants.dart' as Tokens show PLUS_TOKEN;
-import '../util/characters.dart';
+import 'package:front_end/src/fasta/scanner/precedence.dart' as Precedence
+    show FUNCTION_INFO;
+import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
+import 'package:front_end/src/fasta/scanner/token_constants.dart' as Tokens
+    show PLUS_TOKEN;
+import 'package:front_end/src/fasta/scanner/characters.dart';
 import '../util/util.dart';
 import 'dartstring.dart';
 import 'prettyprint.dart';
 import 'unparser.dart';
+import 'package:front_end/src/fasta/parser.dart' show ErrorKind;
 
 abstract class Visitor<R> {
   const Visitor();
@@ -478,7 +481,7 @@
     if (token == null) {
       token = name.getEndToken();
     }
-    assert(invariant(beginToken, token != null));
+    assert(token != null);
     return token;
   }
 
@@ -3086,17 +3089,19 @@
 class ErrorNode extends Node
     implements FunctionExpression, VariableDefinitions, Typedef {
   final Token token;
-  final String reason;
+  final ErrorKind kind;
+  final Map arguments;
   final Identifier name;
   final NodeList definitions;
 
-  ErrorNode.internal(this.token, this.reason, this.name, this.definitions);
+  ErrorNode.internal(
+      this.token, this.kind, this.arguments, this.name, this.definitions);
 
-  factory ErrorNode(Token token, String reason) {
+  factory ErrorNode(Token token, ErrorKind kind, Map arguments) {
     Identifier name = new Identifier(token);
     NodeList definitions =
         new NodeList(null, const Link<Node>().prepend(name), null, null);
-    return new ErrorNode.internal(token, reason, name, definitions);
+    return new ErrorNode.internal(token, kind, arguments, name, definitions);
   }
 
   Token get beginToken => token;
diff --git a/pkg/compiler/lib/src/tree/prettyprint.dart b/pkg/compiler/lib/src/tree/prettyprint.dart
index 837db37..6056a3d 100644
--- a/pkg/compiler/lib/src/tree/prettyprint.dart
+++ b/pkg/compiler/lib/src/tree/prettyprint.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import '../tokens/token.dart' show Token;
+import 'package:front_end/src/fasta/scanner.dart' show Token;
 import '../util/util.dart';
 import 'nodes.dart';
 
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index 5d1d154..1aa5eb7 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.dart
@@ -2,8 +2,8 @@
 // for 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 '../tokens/token.dart' show Token;
-import '../tokens/token_constants.dart' as Tokens
+import 'package:front_end/src/fasta/scanner.dart' show Token;
+import 'package:front_end/src/fasta/scanner/token_constants.dart' as Tokens
     show IDENTIFIER_TOKEN, KEYWORD_TOKEN, PLUS_TOKEN;
 import '../util/util.dart';
 import 'nodes.dart';
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index e7d66ce..3507c24 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -716,7 +716,7 @@
         Name.isPrivateName(name) &&
         element.library != currentLibrary) {
       reportTypeWarning(node, MessageKind.PRIVATE_ACCESS,
-          {'name': name, 'libraryName': element.library.libraryOrScriptName});
+          {'name': name, 'libraryName': element.library.name});
     }
   }
 
@@ -812,7 +812,7 @@
             PrivateName privateName = member.name;
             LibraryElement library = privateName.library;
             reportMessage(node, MessageKind.PRIVATE_ACCESS,
-                {'name': name, 'libraryName': library.libraryOrScriptName},
+                {'name': name, 'libraryName': library.name},
                 isHint: isHint);
             foundPrivateMember = true;
           }
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index c6cc7b8..d62a216 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -5,11 +5,8 @@
 library types.constants;
 
 import '../common.dart';
-import '../constants/constant_system.dart' show ConstantSystem;
-import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
-import '../js_backend/js_backend.dart'
-    show JavaScriptBackend, SyntheticConstantKind;
+import '../js_backend/js_backend.dart' show SyntheticConstantKind;
 import '../world.dart' show ClosedWorld;
 import 'masks.dart';
 
diff --git a/pkg/compiler/lib/src/types/flat_type_mask.dart b/pkg/compiler/lib/src/types/flat_type_mask.dart
index 5b93e4d..5758746 100644
--- a/pkg/compiler/lib/src/types/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/types/flat_type_mask.dart
@@ -117,22 +117,22 @@
     BackendClasses backendClasses = closedWorld.backendClasses;
     if (containsOnlyString(closedWorld)) {
       return cls == closedWorld.commonElements.stringClass ||
-          cls == backendClasses.stringImplementation;
+          cls == backendClasses.stringClass;
     }
     if (containsOnlyBool(closedWorld)) {
       return cls == closedWorld.commonElements.boolClass ||
-          cls == backendClasses.boolImplementation;
+          cls == backendClasses.boolClass;
     }
     if (containsOnlyInt(closedWorld)) {
       return cls == closedWorld.commonElements.intClass ||
-          cls == backendClasses.intImplementation ||
-          cls == backendClasses.positiveIntImplementation ||
-          cls == backendClasses.uint32Implementation ||
-          cls == backendClasses.uint31Implementation;
+          cls == backendClasses.intClass ||
+          cls == backendClasses.positiveIntClass ||
+          cls == backendClasses.uint32Class ||
+          cls == backendClasses.uint31Class;
     }
     if (containsOnlyDouble(closedWorld)) {
       return cls == closedWorld.commonElements.doubleClass ||
-          cls == backendClasses.doubleImplementation;
+          cls == backendClasses.doubleClass;
     }
     return false;
   }
@@ -177,16 +177,16 @@
   bool containsOnlyInt(ClosedWorld closedWorld) {
     BackendClasses backendClasses = closedWorld.backendClasses;
     return base == closedWorld.commonElements.intClass ||
-        base == backendClasses.intImplementation ||
-        base == backendClasses.positiveIntImplementation ||
-        base == backendClasses.uint31Implementation ||
-        base == backendClasses.uint32Implementation;
+        base == backendClasses.intClass ||
+        base == backendClasses.positiveIntClass ||
+        base == backendClasses.uint31Class ||
+        base == backendClasses.uint32Class;
   }
 
   bool containsOnlyDouble(ClosedWorld closedWorld) {
     BackendClasses backendClasses = closedWorld.backendClasses;
     return base == closedWorld.commonElements.doubleClass ||
-        base == backendClasses.doubleImplementation;
+        base == backendClasses.doubleClass;
   }
 
   bool containsOnlyNum(ClosedWorld closedWorld) {
@@ -194,19 +194,19 @@
     return containsOnlyInt(closedWorld) ||
         containsOnlyDouble(closedWorld) ||
         base == closedWorld.commonElements.numClass ||
-        base == backendClasses.numImplementation;
+        base == backendClasses.numClass;
   }
 
   bool containsOnlyBool(ClosedWorld closedWorld) {
     BackendClasses backendClasses = closedWorld.backendClasses;
     return base == closedWorld.commonElements.boolClass ||
-        base == backendClasses.boolImplementation;
+        base == backendClasses.boolClass;
   }
 
   bool containsOnlyString(ClosedWorld closedWorld) {
     BackendClasses backendClasses = closedWorld.backendClasses;
     return base == closedWorld.commonElements.stringClass ||
-        base == backendClasses.stringImplementation;
+        base == backendClasses.stringClass;
   }
 
   bool containsOnly(ClassEntity cls) {
@@ -501,11 +501,11 @@
     if (isEmpty) return false;
     if (isNull) {
       return closedWorld.hasElementIn(
-          backendClasses.nullImplementation, selector, element);
+          backendClasses.nullClass, selector, element);
     }
 
     ClassEntity other = element.enclosingClass;
-    if (other == backendClasses.nullImplementation) {
+    if (other == backendClasses.nullClass) {
       return isNullable;
     } else if (isExact) {
       return closedWorld.hasElementIn(base, selector, element);
diff --git a/pkg/compiler/lib/src/types/map_type_mask.dart b/pkg/compiler/lib/src/types/map_type_mask.dart
index 148fdbf..a519996 100644
--- a/pkg/compiler/lib/src/types/map_type_mask.dart
+++ b/pkg/compiler/lib/src/types/map_type_mask.dart
@@ -81,7 +81,7 @@
       // doesn't need the compiler.
       assert(other.keyType ==
           new TypeMask.nonNullExact(
-              closedWorld.backendClasses.stringImplementation, closedWorld));
+              closedWorld.backendClasses.stringClass, closedWorld));
       TypeMask newKeyType = keyType.union(other.keyType, closedWorld);
       TypeMask newValueType =
           other.typeMap.values.fold(keyType, (p, n) => p.union(n, closedWorld));
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index 827e3f4..0f8fc76 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -7,7 +7,6 @@
 import '../common.dart';
 import '../common/backend_api.dart' show BackendClasses;
 import '../constants/values.dart' show PrimitiveConstantValue;
-import '../elements/elements.dart' show Entity;
 import '../elements/entities.dart';
 import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
 import '../tree/tree.dart';
@@ -75,99 +74,93 @@
   TypeMask get nonNullType => _nonNullType ??= new TypeMask.nonNullSubclass(
       closedWorld.commonElements.objectClass, closedWorld);
 
-  TypeMask get intType => _intType ??= new TypeMask.nonNullSubclass(
-      backendClasses.intImplementation, closedWorld);
+  TypeMask get intType => _intType ??=
+      new TypeMask.nonNullSubclass(backendClasses.intClass, closedWorld);
 
-  TypeMask get uint32Type => _uint32Type ??= new TypeMask.nonNullSubclass(
-      backendClasses.uint32Implementation, closedWorld);
+  TypeMask get uint32Type => _uint32Type ??=
+      new TypeMask.nonNullSubclass(backendClasses.uint32Class, closedWorld);
 
-  TypeMask get uint31Type => _uint31Type ??= new TypeMask.nonNullExact(
-      backendClasses.uint31Implementation, closedWorld);
+  TypeMask get uint31Type => _uint31Type ??=
+      new TypeMask.nonNullExact(backendClasses.uint31Class, closedWorld);
 
   TypeMask get positiveIntType =>
       _positiveIntType ??= new TypeMask.nonNullSubclass(
-          backendClasses.positiveIntImplementation, closedWorld);
+          backendClasses.positiveIntClass, closedWorld);
 
-  TypeMask get doubleType => _doubleType ??= new TypeMask.nonNullExact(
-      backendClasses.doubleImplementation, closedWorld);
+  TypeMask get doubleType => _doubleType ??=
+      new TypeMask.nonNullExact(backendClasses.doubleClass, closedWorld);
 
-  TypeMask get numType => _numType ??= new TypeMask.nonNullSubclass(
-      backendClasses.numImplementation, closedWorld);
+  TypeMask get numType => _numType ??=
+      new TypeMask.nonNullSubclass(backendClasses.numClass, closedWorld);
 
   TypeMask get boolType => _boolType ??=
-      new TypeMask.nonNullExact(backendClasses.boolImplementation, closedWorld);
+      new TypeMask.nonNullExact(backendClasses.boolClass, closedWorld);
 
-  TypeMask get functionType => _functionType ??= new TypeMask.nonNullSubtype(
-      backendClasses.functionImplementation, closedWorld);
+  TypeMask get functionType => _functionType ??=
+      new TypeMask.nonNullSubtype(backendClasses.functionClass, closedWorld);
 
   TypeMask get listType => _listType ??=
-      new TypeMask.nonNullExact(backendClasses.listImplementation, closedWorld);
+      new TypeMask.nonNullExact(backendClasses.listClass, closedWorld);
 
-  TypeMask get constListType => _constListType ??= new TypeMask.nonNullExact(
-      backendClasses.constListImplementation, closedWorld);
+  TypeMask get constListType => _constListType ??=
+      new TypeMask.nonNullExact(backendClasses.constListClass, closedWorld);
 
-  TypeMask get fixedListType => _fixedListType ??= new TypeMask.nonNullExact(
-      backendClasses.fixedListImplementation, closedWorld);
+  TypeMask get fixedListType => _fixedListType ??=
+      new TypeMask.nonNullExact(backendClasses.fixedListClass, closedWorld);
 
-  TypeMask get growableListType =>
-      _growableListType ??= new TypeMask.nonNullExact(
-          backendClasses.growableListImplementation, closedWorld);
+  TypeMask get growableListType => _growableListType ??=
+      new TypeMask.nonNullExact(backendClasses.growableListClass, closedWorld);
 
-  TypeMask get mapType => _mapType ??= new TypeMask.nonNullSubtype(
-      backendClasses.mapImplementation, closedWorld);
+  TypeMask get mapType => _mapType ??=
+      new TypeMask.nonNullSubtype(backendClasses.mapClass, closedWorld);
 
-  TypeMask get constMapType => _constMapType ??= new TypeMask.nonNullSubtype(
-      backendClasses.constMapImplementation, closedWorld);
+  TypeMask get constMapType => _constMapType ??=
+      new TypeMask.nonNullSubtype(backendClasses.constMapClass, closedWorld);
 
-  TypeMask get stringType => _stringType ??= new TypeMask.nonNullExact(
-      backendClasses.stringImplementation, closedWorld);
+  TypeMask get stringType => _stringType ??=
+      new TypeMask.nonNullExact(backendClasses.stringClass, closedWorld);
 
   TypeMask get typeType => _typeType ??=
-      new TypeMask.nonNullExact(backendClasses.typeImplementation, closedWorld);
+      new TypeMask.nonNullExact(backendClasses.typeClass, closedWorld);
 
   TypeMask get syncStarIterableType =>
       _syncStarIterableType ??= new TypeMask.nonNullExact(
-          backendClasses.syncStarIterableImplementation, closedWorld);
+          backendClasses.syncStarIterableClass, closedWorld);
 
-  TypeMask get asyncFutureType =>
-      _asyncFutureType ??= new TypeMask.nonNullExact(
-          backendClasses.asyncFutureImplementation, closedWorld);
+  TypeMask get asyncFutureType => _asyncFutureType ??=
+      new TypeMask.nonNullExact(backendClasses.asyncFutureClass, closedWorld);
 
   TypeMask get asyncStarStreamType =>
       _asyncStarStreamType ??= new TypeMask.nonNullExact(
-          backendClasses.asyncStarStreamImplementation, closedWorld);
+          backendClasses.asyncStarStreamClass, closedWorld);
 
   // TODO(johnniwinther): Assert that the null type has been resolved.
   TypeMask get nullType => _nullType ??= const TypeMask.empty();
 
   TypeMask get emptyType => const TypeMask.nonNullEmpty();
 
-  TypeMask get indexablePrimitiveType =>
-      _indexablePrimitiveType ??= new TypeMask.nonNullSubtype(
-          backendClasses.indexableImplementation, closedWorld);
+  TypeMask get indexablePrimitiveType => _indexablePrimitiveType ??=
+      new TypeMask.nonNullSubtype(backendClasses.indexableClass, closedWorld);
 
-  TypeMask get readableArrayType =>
-      _readableArrayType ??= new TypeMask.nonNullSubclass(
-          backendClasses.listImplementation, closedWorld);
+  TypeMask get readableArrayType => _readableArrayType ??=
+      new TypeMask.nonNullSubclass(backendClasses.listClass, closedWorld);
 
   TypeMask get mutableArrayType =>
       _mutableArrayType ??= new TypeMask.nonNullSubclass(
-          backendClasses.mutableListImplementation, closedWorld);
+          backendClasses.mutableListClass, closedWorld);
 
-  TypeMask get fixedArrayType => _fixedArrayType ??= new TypeMask.nonNullExact(
-      backendClasses.fixedListImplementation, closedWorld);
+  TypeMask get fixedArrayType => _fixedArrayType ??=
+      new TypeMask.nonNullExact(backendClasses.fixedListClass, closedWorld);
 
-  TypeMask get extendableArrayType =>
-      _extendableArrayType ??= new TypeMask.nonNullExact(
-          backendClasses.growableListImplementation, closedWorld);
+  TypeMask get extendableArrayType => _extendableArrayType ??=
+      new TypeMask.nonNullExact(backendClasses.growableListClass, closedWorld);
 
-  TypeMask get unmodifiableArrayType =>
-      _unmodifiableArrayType ??= new TypeMask.nonNullExact(
-          backendClasses.constListImplementation, closedWorld);
+  TypeMask get unmodifiableArrayType => _unmodifiableArrayType ??=
+      new TypeMask.nonNullExact(backendClasses.constListClass, closedWorld);
 
   TypeMask get interceptorType =>
       _interceptorType ??= new TypeMask.nonNullSubclass(
-          backendClasses.interceptorImplementation, closedWorld);
+          backendClasses.interceptorClass, closedWorld);
 
   bool isTypedArray(TypeMask mask) {
     // Just checking for [:TypedData:] is not sufficient, as it is an
@@ -178,8 +171,7 @@
         closedWorld.isInstantiated(typedDataClass) &&
         mask.satisfies(typedDataClass, closedWorld) &&
         mask.satisfies(
-            closedWorld.backendClasses.indexingBehaviorImplementation,
-            closedWorld);
+            closedWorld.backendClasses.indexingBehaviorClass, closedWorld);
   }
 
   bool couldBeTypedArray(TypeMask mask) {
@@ -194,8 +186,7 @@
         intersects(
             mask,
             new TypeMask.subtype(
-                closedWorld.backendClasses.indexingBehaviorImplementation,
-                closedWorld));
+                closedWorld.backendClasses.indexingBehaviorClass, closedWorld));
   }
 
   TypeMask createNonNullExact(ClassEntity cls) {
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index 7386238..8e6c3b9 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -4,7 +4,6 @@
 
 library dart2js.call_structure;
 
-import '../common.dart';
 import '../common/names.dart' show Names;
 import '../elements/types.dart' show FunctionType;
 import '../util/util.dart';
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 39f507a..e004c98 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -6,7 +6,6 @@
 
 import 'dart:collection' show IterableBase;
 
-import '../common.dart';
 import '../elements/elements.dart' show ClassElement;
 import '../util/enumset.dart' show EnumSet;
 import '../util/util.dart' show Link;
diff --git a/pkg/compiler/lib/src/universe/feature.dart b/pkg/compiler/lib/src/universe/feature.dart
index d3d8dfa..03315f0 100644
--- a/pkg/compiler/lib/src/universe/feature.dart
+++ b/pkg/compiler/lib/src/universe/feature.dart
@@ -8,7 +8,7 @@
 /// compilation pipeline, for example during resolution.
 library compiler.universe.feature;
 
-import '../elements/resolution_types.dart' show ResolutionInterfaceType;
+import '../elements/types.dart' show InterfaceType;
 
 /// A language feature that may be seen in the program.
 // TODO(johnniwinther): Should mirror usage be part of this?
@@ -88,7 +88,7 @@
 
 /// Describes a use of a map literal in the program.
 class MapLiteralUse {
-  final ResolutionInterfaceType type;
+  final InterfaceType type;
   final bool isConstant;
   final bool isEmpty;
 
@@ -115,7 +115,7 @@
 
 /// Describes the use of a list literal in the program.
 class ListLiteralUse {
-  final ResolutionInterfaceType type;
+  final InterfaceType type;
   final bool isConstant;
   final bool isEmpty;
 
diff --git a/pkg/compiler/lib/src/universe/function_set.dart b/pkg/compiler/lib/src/universe/function_set.dart
index 3dc566a..90970db 100644
--- a/pkg/compiler/lib/src/universe/function_set.dart
+++ b/pkg/compiler/lib/src/universe/function_set.dart
@@ -298,7 +298,7 @@
           ClassEntity cls = element.enclosingClass;
           return [cls]..addAll(closedWorld.mixinUsesOf(cls));
         }).map((cls) {
-          if (closedWorld.backendClasses.nullImplementation == cls) {
+          if (closedWorld.backendClasses.nullClass == cls) {
             return const TypeMask.empty();
           } else if (closedWorld.isInstantiated(cls)) {
             return new TypeMask.nonNullSubclass(cls, closedWorld);
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 0595e8d..57d27e5 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -19,13 +19,7 @@
 import '../closure.dart' show BoxFieldElement;
 import '../common.dart';
 import '../elements/types.dart';
-import '../elements/elements.dart'
-    show
-        ConstructorElement,
-        ConstructorBodyElement,
-        Element,
-        Entity,
-        LocalFunctionElement;
+import '../elements/elements.dart' show ConstructorBodyElement, Element;
 import '../elements/entities.dart';
 import '../util/util.dart' show Hashing;
 import '../world.dart' show World;
@@ -204,7 +198,7 @@
   /// Invocation of a constructor [element] through a this or super
   /// constructor call with the given [callStructure].
   factory StaticUse.superConstructorInvoke(
-      ConstructorElement element, CallStructure callStructure) {
+      ConstructorEntity element, CallStructure callStructure) {
     // TODO(johnniwinther): Use the [callStructure].
     assert(invariant(element, element.isGenerativeConstructor,
         message: "Constructor invoke element $element must be a "
@@ -251,7 +245,7 @@
 
   /// Constructor invocation of [element] with the given [callStructure].
   factory StaticUse.constructorInvoke(
-      FunctionEntity element, CallStructure callStructure) {
+      ConstructorEntity element, CallStructure callStructure) {
     assert(invariant(element, element.isConstructor,
         message: "Constructor invocation element $element "
             "must be a constructor."));
@@ -262,7 +256,7 @@
   /// Constructor invocation of [element] with the given [callStructure] on
   /// [type].
   factory StaticUse.typedConstructorInvoke(
-      FunctionEntity element, CallStructure callStructure, DartType type) {
+      ConstructorEntity element, CallStructure callStructure, DartType type) {
     assert(invariant(element, type != null,
         message: "No type provided for constructor invocation."));
     assert(invariant(element, element.isConstructor,
@@ -276,7 +270,7 @@
   /// Constant constructor invocation of [element] with the given
   /// [callStructure] on [type].
   factory StaticUse.constConstructorInvoke(
-      FunctionEntity element, CallStructure callStructure, DartType type) {
+      ConstructorEntity element, CallStructure callStructure, DartType type) {
     assert(invariant(element, type != null,
         message: "No type provided for constructor invocation."));
     assert(invariant(element, element.isConstructor,
@@ -289,7 +283,7 @@
 
   /// Constructor redirection to [element] on [type].
   factory StaticUse.constructorRedirect(
-      FunctionEntity element, InterfaceType type) {
+      ConstructorEntity element, InterfaceType type) {
     assert(invariant(element, type != null,
         message: "No type provided for constructor redirection."));
     assert(invariant(element, element.isConstructor,
@@ -324,7 +318,7 @@
   }
 
   /// Read of a local function [element].
-  factory StaticUse.closure(LocalFunctionElement element) {
+  factory StaticUse.closure(Local element) {
     return new StaticUse.internal(element, StaticUseKind.CLOSURE);
   }
 
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index a201a73..04ac8bf 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -6,23 +6,20 @@
 
 import 'dart:collection';
 
-import '../cache_strategy.dart';
 import '../common.dart';
-import '../common/backend_api.dart' show Backend;
 import '../common/names.dart' show Identifiers;
 import '../common/resolution.dart' show Resolution;
-import '../compiler.dart' show Compiler;
 import '../core_types.dart';
 import '../elements/elements.dart';
 import '../elements/entities.dart';
 import '../elements/resolution_types.dart';
 import '../elements/types.dart';
+import '../js_backend/backend.dart' show JavaScriptBackend;
 import '../universe/class_set.dart';
 import '../universe/function_set.dart' show FunctionSetBuilder;
 import '../util/enumset.dart';
 import '../util/util.dart';
 import '../world.dart' show World, ClosedWorld, ClosedWorldImpl, OpenWorld;
-import 'call_structure.dart' show CallStructure;
 import 'selector.dart' show Selector;
 import 'use.dart' show DynamicUse, DynamicUseKind, StaticUse, StaticUseKind;
 
@@ -463,7 +460,7 @@
   /// and classes.
   bool useInstantiationMap = false;
 
-  final Backend _backend;
+  final JavaScriptBackend _backend;
   final Resolution _resolution;
   bool _closed = false;
   ClosedWorld _closedWorldCache;
@@ -480,18 +477,10 @@
       <ClassElement, ClassHierarchyNode>{};
   final Map<ClassElement, ClassSet> _classSets = <ClassElement, ClassSet>{};
 
-  final Set<Element> alreadyPopulated;
-
-  final CacheStrategy cacheStrategy;
-
   bool get isClosed => _closed;
 
-  ResolutionWorldBuilderImpl(Backend backend, Resolution resolution,
-      CacheStrategy cacheStrategy, this.selectorConstraintsStrategy)
-      : this._backend = backend,
-        this._resolution = resolution,
-        this.cacheStrategy = cacheStrategy,
-        alreadyPopulated = cacheStrategy.newSet() {
+  ResolutionWorldBuilderImpl(
+      this._backend, this._resolution, this.selectorConstraintsStrategy) {
     _allFunctions = new FunctionSetBuilder();
   }
 
@@ -797,24 +786,6 @@
     }
   }
 
-  void forgetEntity(Entity entity, Compiler compiler) {
-    allClosures.remove(entity);
-    slowDirectlyNestedClosures(entity).forEach(compiler.forgetElement);
-    closurizedMembers.remove(entity);
-    fieldSetters.remove(entity);
-    _instantiationInfo.remove(entity);
-
-    void removeUsage(Set<_MemberUsage> set, Entity entity) {
-      if (set == null) return;
-      set.removeAll(
-          set.where((_MemberUsage usage) => usage.entity == entity).toList());
-    }
-
-    _processedClasses.remove(entity);
-    removeUsage(_instanceMembersByName[entity.name], entity);
-    removeUsage(_instanceFunctionsByName[entity.name], entity);
-  }
-
   // TODO(ahe): Replace this method with something that is O(1), for example,
   // by using a map.
   List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) {
@@ -1034,9 +1005,6 @@
       if (!info.hasInstantiation) {
         return;
       }
-      if (cacheStrategy.hasIncrementalSupport && !alreadyPopulated.add(cls)) {
-        return;
-      }
       assert(cls.isDeclaration);
       if (!cls.isResolved) {
         reporter.internalError(cls, 'Class "${cls.name}" is not resolved.');
@@ -1149,7 +1117,7 @@
 }
 
 class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
-  final Backend _backend;
+  final JavaScriptBackend _backend;
   ClosedWorld __world;
 
   /// The set of all directly instantiated classes, that is, classes with a
@@ -1505,24 +1473,6 @@
     memberUsed(usage.entity, useSet);
   }
 
-  void forgetElement(Element element, Compiler compiler) {
-    _processedClasses.remove(element);
-    _directlyInstantiatedClasses.remove(element);
-    if (element is ClassElement) {
-      assert(invariant(element, element.thisType.isRaw,
-          message: 'Generic classes not supported (${element.thisType}).'));
-      _instantiatedTypes..remove(element.rawType)..remove(element.thisType);
-    }
-    removeFromSet(_instanceMembersByName, element);
-    removeFromSet(_instanceFunctionsByName, element);
-    if (element is MemberElement) {
-      for (Element closure in element.nestedClosures) {
-        removeFromSet(_instanceMembersByName, closure);
-        removeFromSet(_instanceFunctionsByName, closure);
-      }
-    }
-  }
-
   void processClassMembers(ClassElement cls, MemberUsedCallback memberUsed) {
     cls.implementation.forEachMember((_, MemberElement member) {
       assert(invariant(member, member.isDeclaration));
@@ -1982,10 +1932,3 @@
   @override
   EnumSet<MemberUse> get _originalUse => MemberUses.ALL_STATIC;
 }
-
-void removeFromSet(Map<String, Set<_MemberUsage>> map, Element element) {
-  Set<_MemberUsage> set = map[element.name];
-  if (set == null) return;
-  set.removeAll(
-      set.where((_MemberUsage usage) => usage.entity == element).toList());
-}
diff --git a/pkg/compiler/lib/src/universe/world_impact.dart b/pkg/compiler/lib/src/universe/world_impact.dart
index 4d4f3f9..0c708a2 100644
--- a/pkg/compiler/lib/src/universe/world_impact.dart
+++ b/pkg/compiler/lib/src/universe/world_impact.dart
@@ -4,7 +4,6 @@
 
 library dart2js.universe.world_impact;
 
-import '../elements/elements.dart' show Element;
 import '../util/util.dart' show Setlet;
 import 'use.dart' show DynamicUse, StaticUse, TypeUse;
 
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index de79fb6..45fa490 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -70,9 +70,7 @@
   useElements();
   useCompiler(null);
   useTypes();
-  useCodeEmitterTask(null);
   useScript(null);
-  useProgramBuilder(null);
   useSemanticVisitor();
   useDeferred();
 }
@@ -104,8 +102,8 @@
     constants.Environment env]) {
   constant.isObject;
   cs.isBool(constant);
-  constructedConstant.computeInstanceType();
-  constructedConstant.computeInstanceFields();
+  constructedConstant.computeInstanceType(null);
+  constructedConstant.computeInstanceFields(null);
   expression.evaluate(null, null);
   new NullConstantConstructorVisitor()
     ..visit(null, null)
@@ -283,28 +281,16 @@
     ..reset()
     ..resetAsync(null)
     ..lookupLibrary(null);
-  c.forgetElement(null);
   c.backend.constantCompilerTask.copyConstantValues(null);
   c.currentlyInUserCode();
 }
 
 useTypes() {}
 
-useCodeEmitterTask(js_emitter.CodeEmitterTask codeEmitterTask) {
-  full.Emitter fullEmitter = codeEmitterTask.emitter;
-  fullEmitter.clearCspPrecompiledNodes();
-  fullEmitter.buildLazilyInitializedStaticField(null, isolateProperties: null);
-}
-
 useScript(Script script) {
   script.copyWithFile(null);
 }
 
-useProgramBuilder(program_builder.ProgramBuilder builder) {
-  builder.buildMethodHackForIncrementalCompilation(null);
-  builder.buildFieldsHackForIncrementalCompilation(null);
-}
-
 useSemanticVisitor() {
   operators.UnaryOperator.fromKind(null);
   operators.BinaryOperator.fromKind(null);
diff --git a/pkg/compiler/lib/src/util/characters.dart b/pkg/compiler/lib/src/util/characters.dart
deleted file mode 100644
index 60fe4e1..0000000
--- a/pkg/compiler/lib/src/util/characters.dart
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library characters;
-
-const int $EOF = 0;
-const int $STX = 2;
-const int $BS = 8;
-const int $TAB = 9;
-const int $LF = 10;
-const int $VTAB = 11;
-const int $FF = 12;
-const int $CR = 13;
-const int $SPACE = 32;
-const int $BANG = 33;
-const int $DQ = 34;
-const int $HASH = 35;
-const int $$ = 36;
-const int $PERCENT = 37;
-const int $AMPERSAND = 38;
-const int $SQ = 39;
-const int $OPEN_PAREN = 40;
-const int $CLOSE_PAREN = 41;
-const int $STAR = 42;
-const int $PLUS = 43;
-const int $COMMA = 44;
-const int $MINUS = 45;
-const int $PERIOD = 46;
-const int $SLASH = 47;
-const int $0 = 48;
-const int $1 = 49;
-const int $2 = 50;
-const int $3 = 51;
-const int $4 = 52;
-const int $5 = 53;
-const int $6 = 54;
-const int $7 = 55;
-const int $8 = 56;
-const int $9 = 57;
-const int $COLON = 58;
-const int $SEMICOLON = 59;
-const int $LT = 60;
-const int $EQ = 61;
-const int $GT = 62;
-const int $QUESTION = 63;
-const int $AT = 64;
-const int $A = 65;
-const int $B = 66;
-const int $C = 67;
-const int $D = 68;
-const int $E = 69;
-const int $F = 70;
-const int $G = 71;
-const int $H = 72;
-const int $I = 73;
-const int $J = 74;
-const int $K = 75;
-const int $L = 76;
-const int $M = 77;
-const int $N = 78;
-const int $O = 79;
-const int $P = 80;
-const int $Q = 81;
-const int $R = 82;
-const int $S = 83;
-const int $T = 84;
-const int $U = 85;
-const int $V = 86;
-const int $W = 87;
-const int $X = 88;
-const int $Y = 89;
-const int $Z = 90;
-const int $OPEN_SQUARE_BRACKET = 91;
-const int $BACKSLASH = 92;
-const int $CLOSE_SQUARE_BRACKET = 93;
-const int $CARET = 94;
-const int $_ = 95;
-const int $BACKPING = 96;
-const int $a = 97;
-const int $b = 98;
-const int $c = 99;
-const int $d = 100;
-const int $e = 101;
-const int $f = 102;
-const int $g = 103;
-const int $h = 104;
-const int $i = 105;
-const int $j = 106;
-const int $k = 107;
-const int $l = 108;
-const int $m = 109;
-const int $n = 110;
-const int $o = 111;
-const int $p = 112;
-const int $q = 113;
-const int $r = 114;
-const int $s = 115;
-const int $t = 116;
-const int $u = 117;
-const int $v = 118;
-const int $w = 119;
-const int $x = 120;
-const int $y = 121;
-const int $z = 122;
-const int $OPEN_CURLY_BRACKET = 123;
-const int $BAR = 124;
-const int $CLOSE_CURLY_BRACKET = 125;
-const int $TILDE = 126;
-const int $DEL = 127;
-const int $NBSP = 160;
-const int $LS = 0x2028;
-const int $PS = 0x2029;
-
-const int $FIRST_SURROGATE = 0xd800;
-const int $LAST_SURROGATE = 0xdfff;
-const int $LAST_CODE_POINT = 0x10ffff;
-
-bool isHexDigit(int characterCode) {
-  if (characterCode <= $9) return $0 <= characterCode;
-  characterCode |= $a ^ $A;
-  return ($a <= characterCode && characterCode <= $f);
-}
-
-int hexDigitValue(int hexDigit) {
-  assert(isHexDigit(hexDigit));
-  // hexDigit is one of '0'..'9', 'A'..'F' and 'a'..'f'.
-  if (hexDigit <= $9) return hexDigit - $0;
-  return (hexDigit | ($a ^ $A)) - ($a - 10);
-}
-
-bool isUnicodeScalarValue(int value) {
-  return value < $FIRST_SURROGATE ||
-      (value > $LAST_SURROGATE && value <= $LAST_CODE_POINT);
-}
-
-bool isUtf16LeadSurrogate(int value) {
-  return value >= 0xd800 && value <= 0xdbff;
-}
-
-bool isUtf16TrailSurrogate(int value) {
-  return value >= 0xdc00 && value <= 0xdfff;
-}
diff --git a/pkg/compiler/lib/src/util/link.dart b/pkg/compiler/lib/src/util/link.dart
deleted file mode 100644
index 58d2cb9..0000000
--- a/pkg/compiler/lib/src/util/link.dart
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart2js.util;
-
-class Link<T> implements Iterable<T> {
-  T get head => throw new StateError("no elements");
-  Link<T> get tail => null;
-
-  const Link();
-
-  Link<T> prepend(T element) {
-    return new LinkEntry<T>(element, this);
-  }
-
-  Iterator<T> get iterator => new LinkIterator<T>(this);
-
-  void printOn(StringBuffer buffer, [separatedBy]) {}
-
-  List<T> toList({bool growable: true}) {
-    List<T> result;
-    if (!growable) {
-      result = new List<T>(slowLength());
-    } else {
-      result = new List<T>();
-      result.length = slowLength();
-    }
-    int i = 0;
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
-      result[i++] = link.head;
-    }
-    return result;
-  }
-
-  /// Lazily maps over this linked list, returning an [Iterable].
-  Iterable map(dynamic fn(T item)) {
-    return new MappedLinkIterable<T, dynamic>(this, fn);
-  }
-
-  /// Invokes `fn` for every item in the linked list and returns the results
-  /// in a [List].
-  List mapToList(dynamic fn(T item), {bool growable: true}) {
-    List result;
-    if (!growable) {
-      result = new List(slowLength());
-    } else {
-      result = new List();
-      result.length = slowLength();
-    }
-    int i = 0;
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
-      result[i++] = fn(link.head);
-    }
-    return result;
-  }
-
-  bool get isEmpty => true;
-  bool get isNotEmpty => false;
-
-  Link<T> reverse() => this;
-
-  Link<T> reversePrependAll(Link<T> from) {
-    if (from.isEmpty) return this;
-    return this.prepend(from.head).reversePrependAll(from.tail);
-  }
-
-  Link<T> skip(int n) {
-    if (n == 0) return this;
-    throw new RangeError('Index $n out of range');
-  }
-
-  void forEach(void f(T element)) {}
-
-  bool operator ==(other) {
-    if (other is! Link<T>) return false;
-    return other.isEmpty;
-  }
-
-  int get hashCode => throw new UnsupportedError('Link.hashCode');
-
-  String toString() => "[]";
-
-  get length {
-    throw new UnsupportedError('get:length');
-  }
-
-  int slowLength() => 0;
-
-  // TODO(ahe): Remove this method?
-  bool contains(T element) {
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
-      if (link.head == element) return true;
-    }
-    return false;
-  }
-
-  // TODO(ahe): Remove this method?
-  T get single {
-    if (isEmpty) throw new StateError('No elements');
-    if (!tail.isEmpty) throw new StateError('More than one element');
-    return head;
-  }
-
-  // TODO(ahe): Remove this method?
-  T get first {
-    if (isEmpty) throw new StateError('No elements');
-    return head;
-  }
-
-  /// Returns true if f returns true for all elements of this list.
-  ///
-  /// Returns true for the empty list.
-  bool every(bool f(T)) {
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
-      if (!f(link.head)) return false;
-    }
-    return true;
-  }
-
-  Link copyWithout(e) => this;
-
-  //
-  // Unsupported Iterable<T> methods.
-  //
-  bool any(bool f(T e)) => _unsupported('any');
-  T elementAt(int i) => _unsupported('elementAt');
-  Iterable expand(Iterable f(T e)) => _unsupported('expand');
-  T firstWhere(bool f(T e), {T orElse()}) => _unsupported('firstWhere');
-  fold(initialValue, combine(value, T element)) => _unsupported('fold');
-  T get last => _unsupported('get:last');
-  T lastWhere(bool f(T e), {T orElse()}) => _unsupported('lastWhere');
-  String join([separator = '']) => _unsupported('join');
-  T reduce(T combine(T a, T b)) => _unsupported('reduce');
-  T singleWhere(bool f(T e)) => _unsupported('singleWhere');
-  Iterable<T> skipWhile(bool f(T e)) => _unsupported('skipWhile');
-  Iterable<T> take(int n) => _unsupported('take');
-  Iterable<T> takeWhile(bool f(T e)) => _unsupported('takeWhile');
-  Set<T> toSet() => _unsupported('toSet');
-  Iterable<T> where(bool f(T e)) => _unsupported('where');
-
-  _unsupported(String method) => throw new UnsupportedError(method);
-}
-
-/// Builder object for creating linked lists using [Link] or fixed-length [List]
-/// objects.
-abstract class LinkBuilder<T> {
-  factory LinkBuilder() = LinkBuilderImplementation;
-
-  /// Prepends all elements added to the builder to [tail]. The resulting list
-  /// is returned and the builder is cleared.
-  Link<T> toLink([Link<T> tail = const Link()]);
-
-  /// Creates a new fixed length containing all added elements. The
-  /// resulting list is returned and the builder is cleared.
-  List<T> toList();
-
-  /// Adds the element [t] to the end of the list being built.
-  Link<T> addLast(T t);
-
-  /// Returns the first element in the list being built.
-  T get first;
-
-  /// Returns the number of elements in the list being built.
-  final int length;
-
-  /// Returns `true` if the list being built is empty.
-  final bool isEmpty;
-
-  /// Removes all added elements and resets the builder.
-  void clear();
-}
diff --git a/pkg/compiler/lib/src/util/link_implementation.dart b/pkg/compiler/lib/src/util/link_implementation.dart
deleted file mode 100644
index 186bfff..0000000
--- a/pkg/compiler/lib/src/util/link_implementation.dart
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of util_implementation;
-
-class LinkIterator<T> implements Iterator<T> {
-  T _current;
-  Link<T> _link;
-
-  LinkIterator(Link<T> this._link);
-
-  T get current => _current;
-
-  bool moveNext() {
-    if (_link.isEmpty) {
-      _current = null;
-      return false;
-    }
-    _current = _link.head;
-    _link = _link.tail;
-    return true;
-  }
-}
-
-typedef T Transformation<S, T>(S input);
-
-class MappedLinkIterator<S, T> extends Iterator<T> {
-  Transformation<S, T> _transformation;
-  Link<S> _link;
-  T _current;
-
-  MappedLinkIterator(this._link, this._transformation);
-
-  T get current => _current;
-
-  bool moveNext() {
-    if (_link.isEmpty) {
-      _current = null;
-      return false;
-    }
-    _current = _transformation(_link.head);
-    _link = _link.tail;
-    return true;
-  }
-}
-
-class MappedLinkIterable<S, T> extends IterableBase<T> {
-  Transformation<S, T> _transformation;
-  Link<S> _link;
-
-  MappedLinkIterable(this._link, this._transformation);
-
-  Iterator<T> get iterator {
-    return new MappedLinkIterator<S, T>(_link, _transformation);
-  }
-}
-
-class LinkEntry<T> extends Link<T> {
-  final T head;
-  Link<T> tail;
-
-  LinkEntry(T this.head, [Link<T> tail])
-      : this.tail = ((tail == null) ? const Link() : tail);
-
-  Link<T> prepend(T element) {
-    // TODO(ahe): Use new Link<T>, but this cost 8% performance on VM.
-    return new LinkEntry<T>(element, this);
-  }
-
-  void printOn(StringBuffer buffer, [separatedBy]) {
-    buffer.write(head);
-    if (separatedBy == null) separatedBy = '';
-    for (Link link = tail; link.isNotEmpty; link = link.tail) {
-      buffer.write(separatedBy);
-      buffer.write(link.head);
-    }
-  }
-
-  String toString() {
-    StringBuffer buffer = new StringBuffer();
-    buffer.write('[ ');
-    printOn(buffer, ', ');
-    buffer.write(' ]');
-    return buffer.toString();
-  }
-
-  Link<T> reverse() {
-    Link<T> result = const Link();
-    for (Link<T> link = this; link.isNotEmpty; link = link.tail) {
-      result = result.prepend(link.head);
-    }
-    return result;
-  }
-
-  Link<T> reversePrependAll(Link<T> from) {
-    Link<T> result;
-    for (result = this; from.isNotEmpty; from = from.tail) {
-      result = result.prepend(from.head);
-    }
-    return result;
-  }
-
-  Link<T> skip(int n) {
-    Link<T> link = this;
-    for (int i = 0; i < n; i++) {
-      if (link.isEmpty) {
-        throw new RangeError('Index $n out of range');
-      }
-      link = link.tail;
-    }
-    return link;
-  }
-
-  bool get isEmpty => false;
-  bool get isNotEmpty => true;
-
-  void forEach(void f(T element)) {
-    for (Link<T> link = this; link.isNotEmpty; link = link.tail) {
-      f(link.head);
-    }
-  }
-
-  bool operator ==(other) {
-    if (other is! Link<T>) return false;
-    Link<T> myElements = this;
-    while (myElements.isNotEmpty && other.isNotEmpty) {
-      if (myElements.head != other.head) {
-        return false;
-      }
-      myElements = myElements.tail;
-      other = other.tail;
-    }
-    return myElements.isEmpty && other.isEmpty;
-  }
-
-  int get hashCode => throw new UnsupportedError('LinkEntry.hashCode');
-
-  int slowLength() {
-    int length = 0;
-    for (Link current = this; current.isNotEmpty; current = current.tail) {
-      ++length;
-    }
-    return length;
-  }
-
-  Link copyWithout(e) {
-    LinkBuilder copy = new LinkBuilder();
-    Link link = this;
-    for (; link.isNotEmpty; link = link.tail) {
-      if (link.head != e) {
-        copy.addLast(link.head);
-      }
-    }
-    return copy.toLink(link);
-  }
-}
-
-class LinkBuilderImplementation<T> implements LinkBuilder<T> {
-  LinkEntry<T> head = null;
-  LinkEntry<T> lastLink = null;
-  int length = 0;
-
-  LinkBuilderImplementation();
-
-  Link<T> toLink([Link<T> tail = const Link()]) {
-    if (head == null) return tail;
-    lastLink.tail = tail;
-    Link<T> link = head;
-    lastLink = null;
-    head = null;
-    length = 0;
-    return link;
-  }
-
-  List<T> toList() {
-    if (length == 0) return new List<T>(0);
-    List<T> list = new List<T>(length);
-    int index = 0;
-    Link<T> link = head;
-    while (link.isNotEmpty) {
-      list[index] = link.head;
-      link = link.tail;
-      index++;
-    }
-    lastLink = null;
-    head = null;
-    length = 0;
-    return list;
-  }
-
-  Link<T> addLast(T t) {
-    length++;
-    LinkEntry<T> entry = new LinkEntry<T>(t, null);
-    if (head == null) {
-      head = entry;
-    } else {
-      lastLink.tail = entry;
-    }
-    lastLink = entry;
-    return entry;
-  }
-
-  bool get isEmpty => length == 0;
-
-  T get first {
-    if (head != null) {
-      return head.head;
-    }
-    throw new StateError("no elements");
-  }
-
-  void clear() {
-    head = null;
-    lastLink = null;
-    length = 0;
-  }
-}
diff --git a/pkg/compiler/lib/src/util/util.dart b/pkg/compiler/lib/src/util/util.dart
index dbcc7d3..4573778 100644
--- a/pkg/compiler/lib/src/util/util.dart
+++ b/pkg/compiler/lib/src/util/util.dart
@@ -4,15 +4,15 @@
 
 library dart2js.util;
 
-import 'characters.dart';
-import 'util_implementation.dart';
+import 'package:front_end/src/fasta/scanner/characters.dart';
+import 'package:front_end/src/fasta/util/link.dart';
 
 export 'emptyset.dart';
 export 'maplet.dart';
 export 'setlet.dart';
+export 'package:front_end/src/fasta/util/link.dart';
 
 part 'indentation.dart';
-part 'link.dart';
 
 /// Helper functions for creating hash codes.
 class Hashing {
diff --git a/pkg/compiler/lib/src/util/util_implementation.dart b/pkg/compiler/lib/src/util/util_implementation.dart
deleted file mode 100644
index bdb6b90..0000000
--- a/pkg/compiler/lib/src/util/util_implementation.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library util_implementation;
-
-import 'dart:collection';
-
-import 'util.dart';
-
-part 'link_implementation.dart';
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 7f5039d..6e774c4 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -14,7 +14,6 @@
     show
         ClassElement,
         Element,
-        Entity,
         FunctionElement,
         MemberElement,
         MixinApplicationElement,
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index e0f3df7d..da400c1 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -19,6 +19,13 @@
     path: ../../third_party/pkg/dart2js_info
   lookup_map:
     path: ../lookup_map
+  front_end:
+    path: ../front_end
+dependency_overrides:
+  front_end:
+    path: ../front_end
+  analyzer:
+    path: ../analyzer
 
 # Uncomment if running gclient, so you can depend directly on the downloaded
 # versions of dart2js's transitive dependencies:
diff --git a/pkg/compiler/tool/perf.dart b/pkg/compiler/tool/perf.dart
index 194c392..febe590 100644
--- a/pkg/compiler/tool/perf.dart
+++ b/pkg/compiler/tool/perf.dart
@@ -19,15 +19,13 @@
 import 'package:compiler/src/io/source_file.dart';
 import 'package:compiler/src/options.dart';
 import 'package:compiler/src/parser/element_listener.dart' show ScannerOptions;
-import 'package:compiler/src/parser/listener.dart';
 import 'package:compiler/src/parser/node_listener.dart' show NodeListener;
-import 'package:compiler/src/parser/parser.dart' show Parser;
-import 'package:compiler/src/parser/partial_parser.dart';
+import 'package:compiler/src/parser/diet_parser_task.dart' show PartialParser;
 import 'package:compiler/src/platform_configuration.dart' as platform;
-import 'package:compiler/src/scanner/scanner.dart';
 import 'package:compiler/src/source_file_provider.dart';
-import 'package:compiler/src/tokens/token.dart' show Token;
 import 'package:compiler/src/universe/world_impact.dart' show WorldImpact;
+import 'package:front_end/src/fasta/parser.dart' show Listener, Parser;
+import 'package:front_end/src/fasta/scanner.dart' show Token, scan;
 import 'package:package_config/discovery.dart' show findPackages;
 import 'package:package_config/packages.dart' show Packages;
 import 'package:package_config/src/util.dart' show checkValidPackageUri;
@@ -175,7 +173,7 @@
 /// Scan [source] and return the first token produced by the scanner.
 Token tokenize(SourceFile source) {
   scanTimer.start();
-  var token = new Scanner(source).tokenize();
+  var token = scan(source.slowUtf8ZeroTerminatedBytes()).tokens;
   scanTimer.stop();
   return token;
 }
@@ -234,6 +232,7 @@
   log(m) => print(m);
   internalError(_, m) => print(m);
   spanFromSpannable(_) => null;
+  spanFromToken(_) => null;
 
   void reportError(DiagnosticMessage message,
       [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
diff --git a/pkg/dart2js_incremental/lib/caching_compiler.dart b/pkg/dart2js_incremental/lib/caching_compiler.dart
deleted file mode 100644
index 4b530c8..0000000
--- a/pkg/dart2js_incremental/lib/caching_compiler.dart
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart2js_incremental;
-
-/// Do not call this method directly. It will be made private.
-// TODO(ahe): Make this method private.
-Future<CompilerImpl> reuseCompiler(
-    {CompilerDiagnostics diagnosticHandler,
-     CompilerInput inputProvider,
-     CompilerOutput outputProvider,
-     List<String> options: const [],
-     CompilerImpl cachedCompiler,
-     Uri libraryRoot,
-     Uri packageRoot,
-     Uri packageConfig,
-     bool packagesAreImmutable: false,
-     Map<String, dynamic> environment,
-     Future<bool> reuseLibrary(LibraryElement library)}) {
-  UserTag oldTag = new UserTag('_reuseCompiler').makeCurrent();
-  if (libraryRoot == null) {
-    throw 'Missing libraryRoot';
-  }
-  if (inputProvider == null) {
-    throw 'Missing inputProvider';
-  }
-  if (diagnosticHandler == null) {
-    throw 'Missing diagnosticHandler';
-  }
-  if (outputProvider == null) {
-    outputProvider = const NullCompilerOutput();
-  }
-  if (environment == null) {
-    environment = {};
-  }
-  CompilerImpl compiler = cachedCompiler;
-  JavaScriptBackend backend = compiler?.backend;
-  if (compiler == null ||
-      compiler.libraryRoot != libraryRoot ||
-      !compiler.options.hasIncrementalSupport ||
-      compiler.hasCrashed ||
-      backend.mirrorsAnalysis.resolutionHandler.hasEnqueuedReflectiveElements ||
-      compiler.deferredLoadTask.isProgramSplit) {
-    if (compiler != null && compiler.options.hasIncrementalSupport) {
-      print('***FLUSH***');
-      if (compiler.hasCrashed) {
-        print('Unable to reuse compiler due to crash.');
-      } else if (backend.mirrorsAnalysis.resolutionHandler
-                     .hasEnqueuedReflectiveElements) {
-        print('Unable to reuse compiler due to dart:mirrors.');
-      } else if (compiler.deferredLoadTask.isProgramSplit) {
-        print('Unable to reuse compiler due to deferred loading.');
-      } else {
-        print('Unable to reuse compiler.');
-      }
-    }
-    oldTag.makeCurrent();
-    compiler = new CompilerImpl(
-        inputProvider,
-        outputProvider,
-        diagnosticHandler,
-        new CompilerOptions.parse(
-            libraryRoot: libraryRoot,
-            packageRoot: packageRoot,
-            packageConfig: packageConfig,
-            options: options,
-            environment: environment));
-    backend = compiler.backend;
-
-    Uri core = Uri.parse("dart:core");
-
-    return compiler.setupSdk().then((_) {
-      return compiler.libraryLoader.loadLibrary(core).then((_) {
-        // Likewise, always be prepared for runtimeType support.
-        // TODO(johnniwinther): Add global switch to force RTI.
-        compiler.resolutionWorldBuilder.hasRuntimeTypeSupport = true;
-        compiler.enqueuer.resolution.applyImpact(backend.registerRuntimeType());
-        return compiler;
-      });
-    });
-  } else {
-    compiler.tasks.forEach((t) => t.clearMeasurements());
-    compiler
-        ..userOutputProvider = outputProvider
-        ..provider = inputProvider
-        ..handler = diagnosticHandler
-        ..enqueuer.resolution.queueIsClosed = false
-        ..enqueuer.resolution.hasEnqueuedReflectiveElements = false
-        ..enqueuer.resolution.hasEnqueuedReflectiveStaticFields = false
-        ..enqueuer.codegen.queueIsClosed = false
-        ..enqueuer.codegen.hasEnqueuedReflectiveElements = false
-        ..enqueuer.codegen.hasEnqueuedReflectiveStaticFields = false
-        ..compilationFailed = false;
-    JavaScriptBackend backend = compiler.backend;
-    full.Emitter emitter = backend.emitter.emitter;
-
-    // TODO(ahe): Seems this cache only serves to tell
-    // [emitter.invalidateCaches] if it was invoked on a full compile (in
-    // which case nothing should be invalidated), or if it is an incremental
-    // compilation (in which case, holders/owners of newly compiled methods
-    // must be invalidated).
-    emitter.cachedElements.add(null);
-
-    compiler.enqueuer.codegen
-        ..newlyEnqueuedElements.clear()
-        ..newlySeenSelectors.clear();
-
-    emitter.nsmEmitter
-        ..trivialNsmHandlers.clear();
-
-    backend.emitter.typeTestRegistry
-        ..checkedClasses = null
-        ..checkedFunctionTypes = null
-        ..rtiNeededClasses.clear()
-        ..cachedClassesUsingTypeVariableTests = null;
-
-    emitter.interceptorEmitter
-        ..interceptorInvocationNames.clear();
-
-    backend.emitter.nativeEmitter
-        ..hasNativeClasses = false
-        ..nativeMethods.clear();
-
-    backend.emitter.readTypeVariables.clear();
-
-    emitter
-        ..outputBuffers.clear()
-        ..classesCollector = null
-        ..mangledFieldNames.clear()
-        ..mangledGlobalFieldNames.clear()
-        ..recordedMangledNames.clear()
-        ..clearCspPrecompiledNodes()
-        ..elementDescriptors.clear();
-
-    backend
-        ..preMirrorsMethodCount = 0;
-
-    if (reuseLibrary == null) {
-      reuseLibrary = (LibraryElement library) {
-        return new Future.value(
-            library.isPlatformLibrary ||
-            (packagesAreImmutable && library.isPackageLibrary));
-      };
-    }
-    return compiler.libraryLoader.resetAsync(reuseLibrary).then((_) {
-      oldTag.makeCurrent();
-      return compiler;
-    });
-  }
-}
-
-/// Helper class to collect sources.
-class StringEventSink implements EventSink<String> {
-  List<String> data = <String>[];
-
-  final Function onClose;
-
-  StringEventSink(this.onClose);
-
-  void add(String event) {
-    if (data == null) throw 'StringEventSink is closed.';
-    data.add(event);
-  }
-
-  void addError(errorEvent, [StackTrace stackTrace]) {
-    throw 'addError($errorEvent, $stackTrace)';
-  }
-
-  void close() {
-    if (data != null) {
-      onClose(data.join());
-      data = null;
-    }
-  }
-}
-
-/// Output provider which collect output in [output].
-class OutputProvider implements CompilerOutput {
-  final Map<String, String> output = new Map<String, String>();
-
-  EventSink<String> createEventSink(String name, String extension) {
-    return new StringEventSink((String data) {
-      output['$name.$extension'] = data;
-    });
-  }
-
-  String operator[] (String key) => output[key];
-}
diff --git a/pkg/dart2js_incremental/lib/compiler.dart b/pkg/dart2js_incremental/lib/compiler.dart
deleted file mode 100644
index f0a195e..0000000
--- a/pkg/dart2js_incremental/lib/compiler.dart
+++ /dev/null
@@ -1,211 +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:io';
-
-import 'dart:async' show
-    EventSink,
-    Future,
-    Stream,
-    StreamController,
-    StreamSubscription;
-
-import 'package:dart2js_incremental/dart2js_incremental.dart' show
-    IncrementalCompilationFailed,
-    IncrementalCompiler;
-
-import 'package:compiler/compiler_new.dart' show
-    CompilerOutput;
-
-import 'package:compiler/src/old_to_new_api.dart' show
-    LegacyCompilerDiagnostics,
-    LegacyCompilerInput;
-
-import 'package:compiler/src/source_file_provider.dart' show
-    FormattingDiagnosticHandler;
-
-import 'watcher.dart';
-
-main(List<String> arguments) {
-  int updateCount = 0;
-  StreamSubscription<CompilerEvent> subscription =
-      compile(Uri.base.resolve(arguments.first)).listen(null);
-  subscription.onData((CompilerEvent event) {
-    switch (event.kind) {
-      case IncrementalKind.FULL:
-        updateCount = 0;
-        print('// Compiled JavaScript:');
-        print(event['.js']);
-        break;
-
-      case IncrementalKind.INCREMENTAL:
-        Stopwatch sw = event.stopwatch..start();
-        String updates = '${event.compiler.allUpdates()}';
-        sw.stop();
-
-        print('// Patch after ${++updateCount} updates,');
-        print('// computed in ${sw.elapsedMicroseconds/1000000} seconds:');
-        print(updates);
-        break;
-
-      case IncrementalKind.ERROR:
-        updateCount = 0;
-        print("Compilation failed");
-        break;
-
-      default:
-        throw "Unknown kind: ${event.kind}";
-    }
-  });
-  subscription.onError((error, StackTrace trace) {
-    if (error is IncrementalCompilationFailed) {
-      print("Incremental compilation failed due to:\n${error.reason}");
-    } else {
-      throw error;
-    }
-  });
-}
-
-Stream<CompilerEvent> compile(Uri originalInput) {
-  StreamController<CompilerEvent> controller =
-      new StreamController<CompilerEvent>();
-  compileToStream(originalInput, controller);
-  return controller.stream;
-}
-
-compileToStream(
-    Uri originalInput,
-    StreamController<CompilerEvent> controller) async {
-  var watcher = new Watcher();
-
-  Uri libraryRoot = Uri.base.resolve('sdk/');
-  Uri packageRoot = Uri.base.resolve('packages/');
-
-  FormattingDiagnosticHandler diagnosticHandler =
-      new FormattingDiagnosticHandler();
-
-  OutputProvider outputProvider = new OutputProvider();
-
-  void resilientDiagnosticHandler(
-      Uri uri, int begin, int end, String message, kind) {
-    try {
-      diagnosticHandler(uri, begin, end, message, kind);
-    } catch (e) {
-      String name = diagnosticHandler.provider.relativizeUri(uri);
-      print('$name@$begin+${end - begin}: [$kind] $message}');
-    }
-  }
-
-  Future inputProvider(Uri uri) {
-    if (uri.scheme == "file") {
-      if (!'$uri'.startsWith('$libraryRoot')) {
-        watcher.watchFile(uri);
-      }
-    }
-    return diagnosticHandler.provider(uri);
-  }
-
-  while (true) {
-    Stopwatch sw = new Stopwatch()..start();
-    IncrementalCompiler compiler = new IncrementalCompiler(
-        libraryRoot: libraryRoot,
-        packageRoot: packageRoot,
-        inputProvider: new LegacyCompilerInput(inputProvider),
-        diagnosticHandler:
-            new LegacyCompilerDiagnostics(resilientDiagnosticHandler),
-        outputProvider: outputProvider);
-
-    bool success = await compiler.compile(originalInput);
-    sw.stop();
-    if (success) {
-      controller.add(
-          new CompilerEvent(
-              IncrementalKind.FULL, compiler, outputProvider.output, sw));
-    } else {
-      controller.add(
-          new CompilerEvent(
-              IncrementalKind.ERROR, compiler, outputProvider.output, sw));
-    }
-
-    while (await watcher.hasChanges()) {
-      try {
-        Map<Uri, Uri> changes = watcher.readChanges();
-
-        sw = new Stopwatch()..start();
-        String updates = await compiler.compileUpdates(changes);
-        sw.stop();
-
-        controller.add(
-            new CompilerEvent(
-                IncrementalKind.INCREMENTAL, compiler, outputProvider.output,
-                sw, updates: updates));
-
-      } on IncrementalCompilationFailed catch (error, trace) {
-        controller.addError(error, trace);
-        break;
-      }
-    }
-  }
-}
-
-/// Output provider which collects output in [output].
-class OutputProvider implements CompilerOutput {
-  final Map<String, String> output = new Map<String, String>();
-
-  EventSink<String> createEventSink(String name, String extension) {
-    return new StringEventSink((String data) {
-      output['$name.$extension'] = data;
-    });
-  }
-
-  String operator[](String key) => output[key];
-}
-
-/// Helper class to collect sources.
-class StringEventSink implements EventSink<String> {
-  List<String> data = <String>[];
-
-  final Function onClose;
-
-  StringEventSink(this.onClose);
-
-  void add(String event) {
-    if (data == null) throw 'StringEventSink is closed.';
-    data.add(event);
-  }
-
-  void addError(errorEvent, [StackTrace stackTrace]) {
-    throw 'addError($errorEvent, $stackTrace)';
-  }
-
-  void close() {
-    if (data != null) {
-      onClose(data.join());
-      data = null;
-    }
-  }
-}
-
-enum IncrementalKind {
-  FULL,
-  INCREMENTAL,
-  ERROR,
-}
-
-class CompilerEvent {
-  final IncrementalKind kind;
-
-  final IncrementalCompiler compiler;
-
-  final Map<String, String> _output;
-
-  final Stopwatch stopwatch;
-
-  final String updates;
-
-  CompilerEvent(
-      this.kind, this.compiler, this._output, this.stopwatch, {this.updates});
-
-  String operator[](String key) => _output[key];
-}
diff --git a/pkg/dart2js_incremental/lib/dart2js_incremental.dart b/pkg/dart2js_incremental/lib/dart2js_incremental.dart
deleted file mode 100644
index e62c7c3..0000000
--- a/pkg/dart2js_incremental/lib/dart2js_incremental.dart
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js_incremental;
-
-import 'dart:async' show
-    EventSink,
-    Future;
-
-import 'dart:developer' show
-    UserTag;
-
-import 'package:compiler/src/apiimpl.dart' show
-    CompilerImpl;
-
-import 'package:compiler/compiler_new.dart' show
-    CompilerDiagnostics,
-    CompilerInput,
-    CompilerOutput,
-    Diagnostic;
-
-import 'package:compiler/src/options.dart' show
-    CompilerOptions;
-
-import 'package:compiler/src/null_compiler_output.dart' show
-    NullCompilerOutput;
-
-import 'package:compiler/src/js_backend/js_backend.dart' show
-    JavaScriptBackend;
-
-import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
-    as full show Emitter;
-
-import 'package:compiler/src/elements/elements.dart' show
-    LibraryElement;
-
-import 'library_updater.dart' show
-    IncrementalCompilerContext,
-    LibraryUpdater,
-    Logger;
-
-import 'package:compiler/src/js/js.dart' as jsAst;
-
-part 'caching_compiler.dart';
-
-const List<String> INCREMENTAL_OPTIONS = const <String>[
-    '--disable-type-inference',
-    '--incremental-support',
-    '--generate-code-with-compile-time-errors',
-    '--no-source-maps', // TODO(ahe): Remove this.
-];
-
-class IncrementalCompiler {
-  final Uri libraryRoot;
-  final Uri packageRoot;
-  final Uri packageConfig;
-  final CompilerInput inputProvider;
-  final CompilerDiagnostics diagnosticHandler;
-  final List<String> options;
-  final CompilerOutput outputProvider;
-  final Map<String, dynamic> environment;
-  final List<String> _updates = <String>[];
-  final IncrementalCompilerContext _context = new IncrementalCompilerContext();
-
-  CompilerImpl _compiler;
-
-  IncrementalCompiler({
-      this.libraryRoot,
-      this.packageRoot,
-      this.packageConfig,
-      this.inputProvider,
-      this.diagnosticHandler,
-      this.options,
-      this.outputProvider,
-      this.environment}) {
-    if (libraryRoot == null) {
-      throw new ArgumentError('libraryRoot is null.');
-    }
-    if (inputProvider == null) {
-      throw new ArgumentError('inputProvider is null.');
-    }
-    if (outputProvider == null) {
-      throw new ArgumentError('outputProvider is null.');
-    }
-    if (diagnosticHandler == null) {
-      throw new ArgumentError('diagnosticHandler is null.');
-    }
-    _context.incrementalCompiler = this;
-  }
-
-  LibraryElement get mainApp => _compiler.mainApp;
-
-  CompilerImpl get compiler => _compiler;
-
-  Future<bool> compile(Uri script) {
-    return _reuseCompiler(null).then((CompilerImpl compiler) {
-      _compiler = compiler;
-      return compiler.run(script);
-    });
-  }
-
-  Future<CompilerImpl> _reuseCompiler(
-      Future<bool> reuseLibrary(LibraryElement library)) {
-    List<String> options = this.options == null
-        ? <String> [] : new List<String>.from(this.options);
-    options.addAll(INCREMENTAL_OPTIONS);
-    return reuseCompiler(
-        cachedCompiler: _compiler,
-        libraryRoot: libraryRoot,
-        packageRoot: packageRoot,
-        packageConfig: packageConfig,
-        inputProvider: inputProvider,
-        diagnosticHandler: diagnosticHandler,
-        options: options,
-        outputProvider: outputProvider,
-        environment: environment,
-        reuseLibrary: reuseLibrary);
-  }
-
-  Future<String> compileUpdates(
-      Map<Uri, Uri> updatedFiles,
-      {Logger logTime,
-       Logger logVerbose}) {
-    if (logTime == null) {
-      logTime = (_) {};
-    }
-    if (logVerbose == null) {
-      logVerbose = (_) {};
-    }
-    Future mappingInputProvider(Uri uri) {
-      Uri updatedFile = updatedFiles[uri];
-      return inputProvider.readFromUri(updatedFile == null ? uri : updatedFile);
-    }
-    LibraryUpdater updater = new LibraryUpdater(
-        _compiler,
-        mappingInputProvider,
-        logTime,
-        logVerbose,
-        _context);
-    _context.registerUriWithUpdates(updatedFiles.keys);
-    Future<CompilerImpl> future = _reuseCompiler(updater.reuseLibrary);
-    return future.then((CompilerImpl compiler) {
-      _compiler = compiler;
-      if (compiler.compilationFailed) {
-        return null;
-      } else {
-        String update = updater.computeUpdateJs();
-        _updates.add(update);
-        return update;
-      }
-    });
-  }
-
-  String allUpdates() {
-    jsAst.Node updates = jsAst.js.escapedString(_updates.join(""));
-
-    JavaScriptBackend backend = _compiler.backend;
-
-    jsAst.FunctionDeclaration mainRunner = jsAst.js.statement(r"""
-function dartMainRunner(main, args) {
-  #helper.patch(#updates + "\n//# sourceURL=initial_patch.js\n");
-  return main(args);
-}""", {'updates': updates, 'helper': backend.namer.accessIncrementalHelper});
-
-    return jsAst.prettyPrint(mainRunner, _compiler).getText();
-  }
-}
-
-class IncrementalCompilationFailed {
-  final String reason;
-
-  const IncrementalCompilationFailed(this.reason);
-
-  String toString() => "Can't incrementally compile program.\n\n$reason";
-}
diff --git a/pkg/dart2js_incremental/lib/diff.dart b/pkg/dart2js_incremental/lib/diff.dart
deleted file mode 100644
index b0569d1..0000000
--- a/pkg/dart2js_incremental/lib/diff.dart
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library trydart.poi.diff;
-
-import 'package:compiler/src/elements/elements.dart' show
-    AbstractFieldElement,
-    ClassElement,
-    CompilationUnitElement,
-    Element,
-    ElementCategory,
-    FunctionElement,
-    LibraryElement,
-    ScopeContainerElement;
-
-import 'package:compiler/src/elements/modelx.dart' as modelx;
-
-import 'package:compiler/src/elements/modelx.dart' show
-    DeclarationSite;
-
-import 'package:compiler/src/parser/partial_elements.dart' show
-    PartialClassElement,
-    PartialElement;
-
-import 'package:compiler/src/tokens/token.dart' show
-    ErrorToken,
-    Token;
-
-import 'package:compiler/src/tokens/token_constants.dart' show
-    EOF_TOKEN,
-    IDENTIFIER_TOKEN,
-    KEYWORD_TOKEN;
-
-class Difference {
-  final DeclarationSite before;
-  final DeclarationSite after;
-
-  /// Records the position of first difference between [before] and [after]. If
-  /// either [before] or [after] are null, [token] is null.
-  Token token;
-
-  Difference(this.before, this.after) {
-    if (before == after) {
-      throw '[before] and [after] are the same.';
-    }
-  }
-
-  String toString() {
-    if (before == null) return 'Added($after)';
-    if (after == null) return 'Removed($before)';
-    return 'Modified($after -> $before)';
-  }
-}
-
-List<Difference> computeDifference(
-    ScopeContainerElement before,
-    ScopeContainerElement after) {
-  Map<String, DeclarationSite> beforeMap = <String, DeclarationSite>{};
-  before.forEachLocalMember((modelx.ElementX element) {
-    DeclarationSite site = element.declarationSite;
-    assert(site != null || element.isSynthesized);
-    if (!element.isSynthesized) {
-      beforeMap[element.name] = site;
-    }
-  });
-  List<Difference> modifications = <Difference>[];
-  List<Difference> potentiallyChanged = <Difference>[];
-  after.forEachLocalMember((modelx.ElementX element) {
-    DeclarationSite existing = beforeMap.remove(element.name);
-    if (existing == null) {
-      modifications.add(new Difference(null, element.declarationSite));
-    } else {
-      potentiallyChanged.add(new Difference(existing, element.declarationSite));
-    }
-  });
-
-  modifications.addAll(
-      beforeMap.values.map(
-          (DeclarationSite site) => new Difference(site, null)));
-
-  modifications.addAll(
-      potentiallyChanged.where(areDifferentElements));
-
-  return modifications;
-}
-
-bool areDifferentElements(Difference diff) {
-  DeclarationSite before = diff.before;
-  DeclarationSite after = diff.after;
-  if (before is PartialElement && after is PartialElement) {
-    Token beforeToken = before.beginToken;
-    Token afterToken = after.beginToken;
-    Token stop = before.endToken;
-    int beforeKind = beforeToken.kind;
-    int afterKind = afterToken.kind;
-    while (beforeKind != EOF_TOKEN && afterKind != EOF_TOKEN) {
-
-      if (beforeKind != afterKind) {
-        diff.token = afterToken;
-        return true;
-      }
-
-      if (beforeToken is! ErrorToken && afterToken is! ErrorToken) {
-        if (beforeToken.value != afterToken.value) {
-          diff.token = afterToken;
-          return true;
-        }
-      }
-
-      if (beforeToken == stop) return false;
-
-      beforeToken = beforeToken.next;
-      afterToken = afterToken.next;
-      beforeKind = beforeToken.kind;
-      afterKind = afterToken.kind;
-    }
-    return beforeKind != afterKind;
-  }
-  print("$before isn't a PartialElement");
-  return true;
-}
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
deleted file mode 100644
index 7994891..0000000
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ /dev/null
@@ -1,1521 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js_incremental.library_updater;
-
-import 'dart:async' show
-    Future;
-
-import 'package:compiler/compiler.dart' as api;
-
-import 'package:compiler/src/compiler.dart' show
-    Compiler;
-
-import 'package:compiler/src/diagnostics/messages.dart' show
-    MessageKind;
-
-import 'package:compiler/src/elements/elements.dart' show
-    ClassElement,
-    CompilationUnitElement,
-    Element,
-    FunctionElement,
-    LibraryElement,
-    STATE_NOT_STARTED,
-    ScopeContainerElement;
-
-import 'package:compiler/src/enqueue.dart' show
-    EnqueueTask;
-
-import 'package:compiler/src/parser/listener.dart' show
-    Listener;
-
-import 'package:compiler/src/parser/node_listener.dart' show
-    NodeListener;
-
-import 'package:compiler/src/parser/partial_elements.dart' show
-    PartialClassElement,
-    PartialElement,
-    PartialFieldList,
-    PartialFunctionElement;
-
-import 'package:compiler/src/parser/parser.dart' show
-    Parser;
-
-import 'package:compiler/src/scanner/scanner.dart' show
-    Scanner;
-
-import 'package:compiler/src/tokens/token.dart' show
-    Token;
-
-import 'package:compiler/src/tokens/token_constants.dart' show
-    EOF_TOKEN;
-
-import 'package:compiler/src/script.dart' show
-    Script;
-
-import 'package:compiler/src/io/source_file.dart' show
-    CachingUtf8BytesSourceFile,
-    SourceFile,
-    StringSourceFile;
-
-import 'package:compiler/src/tree/tree.dart' show
-    ClassNode,
-    FunctionExpression,
-    LibraryTag,
-    NodeList,
-    Part,
-    StringNode,
-    unparse;
-
-import 'package:compiler/src/js/js.dart' show
-    js;
-
-import 'package:compiler/src/js/js.dart' as jsAst;
-
-import 'package:compiler/src/js_emitter/js_emitter.dart' show
-    CodeEmitterTask,
-    computeMixinClass;
-
-import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
-    as full show Emitter;
-
-import 'package:compiler/src/js_emitter/model.dart' show
-    Class,
-    Method;
-
-import 'package:compiler/src/js_emitter/program_builder/program_builder.dart'
-    show ProgramBuilder;
-
-import 'package:js_runtime/shared/embedded_names.dart'
-    as embeddedNames;
-
-import 'package:compiler/src/js_backend/js_backend.dart' show
-    JavaScriptBackend,
-    Namer;
-
-import 'package:compiler/src/util/util.dart' show
-    Link,
-    LinkBuilder;
-
-import 'package:compiler/src/elements/modelx.dart' show
-    ClassElementX,
-    CompilationUnitElementX,
-    DeclarationSite,
-    ElementX,
-    FieldElementX,
-    LibraryElementX;
-
-import 'package:compiler/src/universe/selector.dart' show
-    Selector;
-
-import 'package:compiler/src/constants/values.dart' show
-    ConstantValue;
-
-import 'package:compiler/src/library_loader.dart' show
-    TagState;
-
-import 'diff.dart' show
-    Difference,
-    computeDifference;
-
-import 'dart2js_incremental.dart' show
-    IncrementalCompilationFailed,
-    IncrementalCompiler;
-
-typedef void Logger(message);
-
-typedef bool Reuser(
-    Token diffToken,
-    PartialElement before,
-    PartialElement after);
-
-class FailedUpdate {
-  /// Either an [Element] or a [Difference].
-  final context;
-  final String message;
-
-  FailedUpdate(this.context, this.message);
-
-  String toString() {
-    if (context == null) return '$message';
-    return 'In $context:\n  $message';
-  }
-}
-
-abstract class _IncrementalCompilerContext {
-  IncrementalCompiler incrementalCompiler;
-
-  Set<ClassElementX> _emittedClasses;
-
-  Set<ClassElementX> _directlyInstantiatedClasses;
-
-  Set<ConstantValue> _compiledConstants;
-}
-
-class IncrementalCompilerContext extends _IncrementalCompilerContext {
-  final Set<Uri> _uriWithUpdates = new Set<Uri>();
-
-  void set incrementalCompiler(IncrementalCompiler value) {
-    if (super.incrementalCompiler != null) {
-      throw new StateError("Can't set [incrementalCompiler] more than once.");
-    }
-    super.incrementalCompiler = value;
-  }
-
-  void registerUriWithUpdates(Iterable<Uri> uris) {
-    _uriWithUpdates.addAll(uris);
-  }
-
-  void _captureState(Compiler compiler) {
-    JavaScriptBackend backend = compiler.backend;
-    Set neededClasses = backend.emitter.neededClasses;
-    if (neededClasses == null) {
-      neededClasses = new Set();
-    }
-    _emittedClasses = new Set.from(neededClasses);
-
-    _directlyInstantiatedClasses =
-        new Set.from(compiler.codegenWorld.directlyInstantiatedClasses);
-
-    // This breaks constant tracking of the incremental compiler. It would need
-    // to capture the emitted constants.
-    List<ConstantValue> constants = null;
-    if (constants == null) constants = <ConstantValue>[];
-    _compiledConstants = new Set<ConstantValue>.identity()..addAll(constants);
-  }
-
-  bool _uriHasUpdate(Uri uri) => _uriWithUpdates.contains(uri);
-}
-
-class LibraryUpdater extends JsFeatures {
-  final Compiler compiler;
-
-  final api.CompilerInputProvider inputProvider;
-
-  final Logger logTime;
-
-  final Logger logVerbose;
-
-  final List<Update> updates = <Update>[];
-
-  final List<FailedUpdate> _failedUpdates = <FailedUpdate>[];
-
-  final Set<ElementX> _elementsToInvalidate = new Set<ElementX>();
-
-  final Set<ElementX> _removedElements = new Set<ElementX>();
-
-  final Set<ClassElementX> _classesWithSchemaChanges =
-      new Set<ClassElementX>();
-
-  final IncrementalCompilerContext _context;
-
-  final Map<Uri, Future> _sources = <Uri, Future>{};
-
-  /// Cached tokens of entry compilation units.
-  final Map<LibraryElementX, Token> _entryUnitTokens =
-      <LibraryElementX, Token>{};
-
-  /// Cached source files for entry compilation units.
-  final Map<LibraryElementX, SourceFile> _entrySourceFiles =
-      <LibraryElementX, SourceFile>{};
-
-  bool _hasComputedNeeds = false;
-
-  bool _hasCapturedCompilerState = false;
-
-  LibraryUpdater(
-      this.compiler,
-      this.inputProvider,
-      this.logTime,
-      this.logVerbose,
-      this._context) {
-    // TODO(ahe): Would like to remove this from the constructor. However, the
-    // state must be captured before calling [reuseCompiler].
-    // Proper solution might be: [reuseCompiler] should not clear the sets that
-    // are captured in [IncrementalCompilerContext._captureState].
-    _ensureCompilerStateCaptured();
-  }
-
-  /// Returns the classes emitted by [compiler].
-  Set<ClassElementX> get _emittedClasses => _context._emittedClasses;
-
-  /// Returns the directly instantantiated classes seen by [compiler] (this
-  /// includes interfaces and may be different from [_emittedClasses] that only
-  /// includes interfaces used in type tests).
-  Set<ClassElementX> get _directlyInstantiatedClasses {
-    return _context._directlyInstantiatedClasses;
-  }
-
-  /// Returns the constants emitted by [compiler].
-  Set<ConstantValue> get _compiledConstants => _context._compiledConstants;
-
-  /// When [true], updates must be applied (using [applyUpdates]) before the
-  /// [compiler]'s state correctly reflects the updated program.
-  bool get hasPendingUpdates => !updates.isEmpty;
-
-  bool get failed => !_failedUpdates.isEmpty;
-
-  /// Used as tear-off passed to [LibraryLoaderTask.resetAsync].
-  Future<bool> reuseLibrary(LibraryElement library) {
-    _ensureCompilerStateCaptured();
-    assert(compiler != null);
-    if (library.isPlatformLibrary) {
-      logTime('Reusing $library (assumed read-only).');
-      return new Future.value(true);
-    }
-    return _haveTagsChanged(library).then((bool haveTagsChanged) {
-      if (haveTagsChanged) {
-        cannotReuse(
-            library,
-            "Changes to library, import, export, or part declarations not"
-            " supported.");
-        return true;
-      }
-
-      bool isChanged = false;
-      List<Future<Script>> futureScripts = <Future<Script>>[];
-
-      for (CompilationUnitElementX unit in library.compilationUnits) {
-        Uri uri = unit.script.resourceUri;
-        if (_context._uriHasUpdate(uri)) {
-          isChanged = true;
-          futureScripts.add(_updatedScript(unit.script, library));
-        } else {
-          futureScripts.add(new Future.value(unit.script));
-        }
-      }
-
-      if (!isChanged) {
-        logTime("Reusing $library, source didn't change.");
-        return true;
-      }
-
-      return Future.wait(futureScripts).then(
-          (List<Script> scripts) => canReuseLibrary(library, scripts));
-    }).whenComplete(() => _cleanUp(library));
-  }
-
-  void _cleanUp(LibraryElementX library) {
-    _entryUnitTokens.remove(library);
-    _entrySourceFiles.remove(library);
-  }
-
-  Future<Script> _updatedScript(Script before, LibraryElementX library) {
-    if (before == library.entryCompilationUnit.script &&
-        _entrySourceFiles.containsKey(library)) {
-      return new Future.value(before.copyWithFile(_entrySourceFiles[library]));
-    }
-
-    return _readUri(before.resourceUri).then((bytes) {
-      Uri uri = before.file.uri;
-      String filename = before.file.filename;
-      SourceFile sourceFile = bytes is String
-          ? new StringSourceFile(uri, filename, bytes)
-          : new CachingUtf8BytesSourceFile(uri, filename, bytes);
-      return before.copyWithFile(sourceFile);
-    });
-  }
-
-  Future<bool> _haveTagsChanged(LibraryElement library) {
-    Script before = library.entryCompilationUnit.script;
-    if (!_context._uriHasUpdate(before.resourceUri)) {
-      // The entry compilation unit hasn't been updated. So the tags aren't
-      // changed.
-      return new Future<bool>.value(false);
-    }
-
-    return _updatedScript(before, library).then((Script script) {
-      _entrySourceFiles[library] = script.file;
-      Token token = new Scanner(_entrySourceFiles[library]).tokenize();
-      _entryUnitTokens[library] = token;
-      // Using two parsers to only create the nodes we want ([LibraryTag]).
-      Parser parser = new Parser(new Listener(), compiler.options);
-      NodeListener listener = new NodeListener(
-          compiler, library.entryCompilationUnit);
-      Parser nodeParser = new Parser(listener, compiler.options);
-      Iterator<LibraryTag> tags = library.tags.iterator;
-      while (token.kind != EOF_TOKEN) {
-        token = parser.parseMetadataStar(token);
-        if (parser.optional('library', token) ||
-            parser.optional('import', token) ||
-            parser.optional('export', token) ||
-            parser.optional('part', token)) {
-          if (!tags.moveNext()) return true;
-          token = nodeParser.parseTopLevelDeclaration(token);
-          LibraryTag tag = listener.popNode();
-          assert(listener.nodes.isEmpty);
-          if (unparse(tags.current) != unparse(tag)) {
-            return true;
-          }
-        } else {
-          break;
-        }
-      }
-      return tags.moveNext();
-    });
-  }
-
-  Future _readUri(Uri uri) {
-    return _sources.putIfAbsent(uri, () => inputProvider(uri));
-  }
-
-  void _ensureCompilerStateCaptured() {
-    // TODO(ahe): [compiler] shouldn't be null, remove the following line.
-    if (compiler == null) return;
-
-    if (_hasCapturedCompilerState) return;
-    _context._captureState(compiler);
-    _hasCapturedCompilerState = true;
-  }
-
-  /// Returns true if [library] can be reused.
-  ///
-  /// This methods also computes the [updates] (patches) needed to have
-  /// [library] reflect the modifications in [scripts].
-  bool canReuseLibrary(LibraryElement library, List<Script> scripts) {
-    logTime('Attempting to reuse ${library}.');
-
-    Uri entryUri = library.entryCompilationUnit.script.resourceUri;
-    Script entryScript =
-        scripts.singleWhere((Script script) => script.resourceUri == entryUri);
-    LibraryElement newLibrary =
-        new LibraryElementX(entryScript, library.canonicalUri);
-    if (_entryUnitTokens.containsKey(library)) {
-      compiler.dietParser.dietParse(
-          newLibrary.entryCompilationUnit, _entryUnitTokens[library]);
-    } else {
-      compiler.scanner.scanLibrary(newLibrary);
-    }
-
-    TagState tagState = new TagState();
-    for (LibraryTag tag in newLibrary.tags) {
-      if (tag.isImport) {
-        tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler);
-      } else if (tag.isExport) {
-        tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler);
-      } else if (tag.isLibraryName) {
-        tagState.checkTag(TagState.LIBRARY, tag, compiler);
-        if (newLibrary.libraryTag == null) {
-          // Use the first if there are multiple (which is reported as an
-          // error in [TagState.checkTag]).
-          newLibrary.libraryTag = tag;
-        }
-      } else if (tag.isPart) {
-        tagState.checkTag(TagState.PART, tag, compiler);
-      }
-    }
-
-    // TODO(ahe): Process tags using TagState, not
-    // LibraryLoaderTask.processLibraryTags.
-    Link<CompilationUnitElement> units = library.compilationUnits;
-    for (Script script in scripts) {
-      CompilationUnitElementX unit = units.head;
-      units = units.tail;
-      if (script != entryScript) {
-        // TODO(ahe): Copied from library_loader.
-        CompilationUnitElement newUnit =
-            new CompilationUnitElementX(script, newLibrary);
-        compiler.withCurrentElement(newUnit, () {
-          compiler.scanner.scan(newUnit);
-          if (unit.partTag == null) {
-            compiler.reportError(unit, MessageKind.MISSING_PART_OF_TAG);
-          }
-        });
-      }
-    }
-
-    logTime('New library synthesized.');
-    return canReuseScopeContainerElement(library, newLibrary);
-  }
-
-  bool cannotReuse(context, String message) {
-    _failedUpdates.add(new FailedUpdate(context, message));
-    logVerbose(message);
-    return false;
-  }
-
-  bool canReuseScopeContainerElement(
-      ScopeContainerElement element,
-      ScopeContainerElement newElement) {
-    List<Difference> differences = computeDifference(element, newElement);
-    logTime('Differences computed.');
-    for (Difference difference in differences) {
-      logTime('Looking at difference: $difference');
-
-      if (difference.before == null && difference.after is PartialElement) {
-        canReuseAddedElement(difference.after, element, newElement);
-        continue;
-      }
-      if (difference.after == null && difference.before is PartialElement) {
-        canReuseRemovedElement(difference.before, element);
-        continue;
-      }
-      Token diffToken = difference.token;
-      if (diffToken == null) {
-        cannotReuse(difference, "No difference token.");
-        continue;
-      }
-      if (difference.after is! PartialElement &&
-          difference.before is! PartialElement) {
-        cannotReuse(difference, "Don't know how to recompile.");
-        continue;
-      }
-      PartialElement before = difference.before;
-      PartialElement after = difference.after;
-
-      Reuser reuser;
-
-      if (before is PartialFunctionElement && after is PartialFunctionElement) {
-        reuser = canReuseFunction;
-      } else if (before is PartialClassElement &&
-                 after is PartialClassElement) {
-        reuser = canReuseClass;
-      } else {
-        reuser = unableToReuse;
-      }
-      if (!reuser(diffToken, before, after)) {
-        assert(!_failedUpdates.isEmpty);
-        continue;
-      }
-    }
-
-    return _failedUpdates.isEmpty;
-  }
-
-  bool canReuseAddedElement(
-      PartialElement element,
-      ScopeContainerElement container,
-      ScopeContainerElement syntheticContainer) {
-    if (element is PartialFunctionElement) {
-      addFunction(element, container);
-      return true;
-    } else if (element is PartialClassElement) {
-      addClass(element, container);
-      return true;
-    } else if (element is PartialFieldList) {
-      addFields(element, container, syntheticContainer);
-      return true;
-    }
-    return cannotReuse(element, "Adding ${element.runtimeType} not supported.");
-  }
-
-  void addFunction(
-      PartialFunctionElement element,
-      /* ScopeContainerElement */ container) {
-    invalidateScopesAffectedBy(element, container);
-
-    updates.add(new AddedFunctionUpdate(compiler, element, container));
-  }
-
-  void addClass(
-      PartialClassElement element,
-      LibraryElementX library) {
-    invalidateScopesAffectedBy(element, library);
-
-    updates.add(new AddedClassUpdate(compiler, element, library));
-  }
-
-  /// Called when a field in [definition] has changed.
-  ///
-  /// There's no direct link from a [PartialFieldList] to its implied
-  /// [FieldElementX], so instead we use [syntheticContainer], the (synthetic)
-  /// container created by [canReuseLibrary], or [canReuseClass] (through
-  /// [PartialClassElement.parseNode]). This container is scanned looking for
-  /// fields whose declaration site is [definition].
-  // TODO(ahe): It would be nice if [computeDifference] returned this
-  // information directly.
-  void addFields(
-      PartialFieldList definition,
-      ScopeContainerElement container,
-      ScopeContainerElement syntheticContainer) {
-    List<FieldElementX> fields = <FieldElementX>[];
-    syntheticContainer.forEachLocalMember((ElementX member) {
-      if (member.declarationSite == definition) {
-        fields.add(member);
-      }
-    });
-    for (FieldElementX field in fields) {
-      // TODO(ahe): This only works when there's one field per
-      // PartialFieldList.
-      addField(field, container);
-    }
-  }
-
-  void addField(FieldElementX element, ScopeContainerElement container) {
-    invalidateScopesAffectedBy(element, container);
-    if (element.isInstanceMember) {
-      _classesWithSchemaChanges.add(container);
-    }
-    updates.add(new AddedFieldUpdate(compiler, element, container));
-  }
-
-  bool canReuseRemovedElement(
-      PartialElement element,
-      ScopeContainerElement container) {
-    if (element is PartialFunctionElement) {
-      removeFunction(element);
-      return true;
-    } else if (element is PartialClassElement) {
-      removeClass(element);
-      return true;
-    } else if (element is PartialFieldList) {
-      removeFields(element, container);
-      return true;
-    }
-    return cannotReuse(
-        element, "Removing ${element.runtimeType} not supported.");
-  }
-
-  void removeFunction(PartialFunctionElement element) {
-    logVerbose("Removed method $element.");
-
-    invalidateScopesAffectedBy(element, element.enclosingElement);
-
-    _removedElements.add(element);
-
-    updates.add(new RemovedFunctionUpdate(compiler, element));
-  }
-
-  void removeClass(PartialClassElement element) {
-    logVerbose("Removed class $element.");
-
-    invalidateScopesAffectedBy(element, element.library);
-
-    _removedElements.add(element);
-    element.forEachLocalMember((ElementX member) {
-      _removedElements.add(member);
-    });
-
-    updates.add(new RemovedClassUpdate(compiler, element));
-  }
-
-  void removeFields(
-      PartialFieldList definition,
-      ScopeContainerElement container) {
-    List<FieldElementX> fields = <FieldElementX>[];
-    container.forEachLocalMember((ElementX member) {
-      if (member.declarationSite == definition) {
-        fields.add(member);
-      }
-    });
-    for (FieldElementX field in fields) {
-      // TODO(ahe): This only works when there's one field per
-      // PartialFieldList.
-      removeField(field);
-    }
-  }
-
-  void removeField(FieldElementX element) {
-    logVerbose("Removed field $element.");
-    if (!element.isInstanceMember) {
-      cannotReuse(element, "Not an instance field.");
-    } else {
-      removeInstanceField(element);
-    }
-  }
-
-  void removeInstanceField(FieldElementX element) {
-    PartialClassElement cls = element.enclosingClass;
-
-    _classesWithSchemaChanges.add(cls);
-    invalidateScopesAffectedBy(element, cls);
-
-    _removedElements.add(element);
-
-    updates.add(new RemovedFieldUpdate(compiler, element));
-  }
-
-  void invalidateScopesAffectedBy(
-      ElementX element,
-      /* ScopeContainerElement */ container) {
-    for (ScopeContainerElement scope in scopesAffectedBy(element, container)) {
-      scanSites(scope, (Element member, DeclarationSite site) {
-        // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
-        Set<String> names = qualifiedNamesIn(site);
-        if (canNamesResolveStaticallyTo(names, element, container)) {
-          _elementsToInvalidate.add(member);
-        }
-      });
-    }
-  }
-
-  /// Invoke [f] on each [DeclarationSite] in [element]. If [element] is a
-  /// [ScopeContainerElement], invoke f on all local members as well.
-  void scanSites(
-      Element element,
-      void f(ElementX element, DeclarationSite site)) {
-    DeclarationSite site = declarationSite(element);
-    if (site != null) {
-      f(element, site);
-    }
-    if (element is ScopeContainerElement) {
-      element.forEachLocalMember((member) { scanSites(member, f); });
-    }
-  }
-
-  /// Assume [element] is either removed from or added to [container], and
-  /// return all [ScopeContainerElement] that can see this change.
-  List<ScopeContainerElement> scopesAffectedBy(
-      Element element,
-      /* ScopeContainerElement */ container) {
-    // TODO(ahe): Use library export graph to compute this.
-    // TODO(ahe): Should return all user-defined libraries and packages.
-    LibraryElement library = container.library;
-    List<ScopeContainerElement> result = <ScopeContainerElement>[library];
-
-    if (!container.isClass) return result;
-
-    ClassElement cls = container;
-
-    var externalSubtypes =
-        compiler.world.subtypesOf(cls).where((e) => e.library != library);
-
-    return result..addAll(externalSubtypes);
-  }
-
-  /// Returns true if function [before] can be reused to reflect the changes in
-  /// [after].
-  ///
-  /// If [before] can be reused, an update (patch) is added to [updates].
-  bool canReuseFunction(
-      Token diffToken,
-      PartialFunctionElement before,
-      PartialFunctionElement after) {
-    FunctionExpression node =
-        after.parseNode(compiler.parsingContext).asFunctionExpression();
-    if (node == null) {
-      return cannotReuse(after, "Not a function expression: '$node'");
-    }
-    Token last = after.endToken;
-    if (node.body != null) {
-      last = node.body.getBeginToken();
-    }
-    if (isTokenBetween(diffToken, after.beginToken, last)) {
-      removeFunction(before);
-      addFunction(after, before.enclosingElement);
-      return true;
-    }
-    logVerbose('Simple modification of ${after} detected');
-    updates.add(new FunctionUpdate(compiler, before, after));
-    return true;
-  }
-
-  bool canReuseClass(
-      Token diffToken,
-      PartialClassElement before,
-      PartialClassElement after) {
-    ClassNode node = after.parseNode(compiler.parsingContext).asClassNode();
-    if (node == null) {
-      return cannotReuse(after, "Not a ClassNode: '$node'");
-    }
-    NodeList body = node.body;
-    if (body == null) {
-      return cannotReuse(after, "Class has no body.");
-    }
-    if (isTokenBetween(diffToken, node.beginToken, body.beginToken)) {
-      logVerbose('Class header modified in ${after}');
-      updates.add(new ClassUpdate(compiler, before, after));
-      before.forEachLocalMember((ElementX member) {
-        // TODO(ahe): Quadratic.
-        invalidateScopesAffectedBy(member, before);
-      });
-    }
-    return canReuseScopeContainerElement(before, after);
-  }
-
-  bool isTokenBetween(Token token, Token first, Token last) {
-    Token current = first;
-    while (current != last && current.kind != EOF_TOKEN) {
-      if (current == token) {
-        return true;
-      }
-      current = current.next;
-    }
-    return false;
-  }
-
-  bool unableToReuse(
-      Token diffToken,
-      PartialElement before,
-      PartialElement after) {
-    return cannotReuse(
-        after,
-        'Unhandled change:'
-        ' ${before} (${before.runtimeType} -> ${after.runtimeType}).');
-  }
-
-  /// Apply the collected [updates]. Return a list of elements that needs to be
-  /// recompiled after applying the updates. Any elements removed as a
-  /// consequence of applying the patches are added to [removals] if provided.
-  List<Element> applyUpdates([List<Update> removals]) {
-    for (Update update in updates) {
-      update.captureState();
-    }
-    if (!_failedUpdates.isEmpty) {
-      throw new IncrementalCompilationFailed(_failedUpdates.join('\n\n'));
-    }
-    for (ElementX element in _elementsToInvalidate) {
-      compiler.forgetElement(element);
-      element.reuseElement();
-    }
-    List<Element> elementsToInvalidate = <Element>[];
-    for (ElementX element in _elementsToInvalidate) {
-      if (!_removedElements.contains(element)) {
-        elementsToInvalidate.add(element);
-      }
-    }
-    for (Update update in updates) {
-      Element element = update.apply();
-      if (update.isRemoval) {
-        if (removals != null) {
-          removals.add(update);
-        }
-      } else {
-        elementsToInvalidate.add(element);
-      }
-    }
-    return elementsToInvalidate;
-  }
-
-  String computeUpdateJs() {
-    List<Update> removals = <Update>[];
-    List<Element> updatedElements = applyUpdates(removals);
-    if (compiler.progress != null) {
-      compiler.progress.reset();
-    }
-    for (Element element in updatedElements) {
-      if (!element.isClass) {
-        enqueuer.resolution.addToWorkList(element);
-      } else {
-        NO_WARN(element).ensureResolved(compiler);
-      }
-    }
-    compiler.processQueue(enqueuer.resolution, null);
-
-    compiler.phase = Compiler.PHASE_DONE_RESOLVING;
-
-    // TODO(ahe): Clean this up. Don't call this method in analyze-only mode.
-    if (compiler.options.analyzeOnly) return "/* analyze only */";
-
-    Set<ClassElementX> changedClasses =
-        new Set<ClassElementX>.from(_classesWithSchemaChanges);
-    for (Element element in updatedElements) {
-      if (!element.isClass) {
-        enqueuer.codegen.addToWorkList(element);
-      } else {
-        changedClasses.add(element);
-      }
-    }
-    compiler.processQueue(enqueuer.codegen, null);
-
-    // Run through all compiled methods and see if they may apply to
-    // newlySeenSelectors.
-    for (Element e in enqueuer.codegen.generatedCode.keys) {
-      if (e.isFunction && !e.isConstructor &&
-          e.functionSignature.hasOptionalParameters) {
-        for (Selector selector in enqueuer.codegen.newlySeenSelectors) {
-          // TODO(ahe): Group selectors by name at this point for improved
-          // performance.
-          if (e.isInstanceMember && selector.applies(e, compiler.world)) {
-            // TODO(ahe): Don't use
-            // enqueuer.codegen.newlyEnqueuedElements directly like
-            // this, make a copy.
-            enqueuer.codegen.newlyEnqueuedElements.add(e);
-          }
-          if (selector.name == namer.closureInvocationSelectorName) {
-            selector = new Selector.call(
-                e.name, e.library,
-                selector.argumentCount, selector.namedArguments);
-            if (selector.appliesUnnamed(e, compiler.world)) {
-              // TODO(ahe): Also make a copy here.
-              enqueuer.codegen.newlyEnqueuedElements.add(e);
-            }
-          }
-        }
-      }
-    }
-
-    List<jsAst.Statement> updates = <jsAst.Statement>[];
-
-    Set<ClassElementX> newClasses = new Set.from(
-        compiler.codegenWorld.directlyInstantiatedClasses);
-    newClasses.removeAll(_directlyInstantiatedClasses);
-
-    if (!newClasses.isEmpty) {
-      // Ask the emitter to compute "needs" (only) if new classes were
-      // instantiated.
-      _ensureAllNeededEntitiesComputed();
-      newClasses = new Set.from(emitter.neededClasses);
-      newClasses.removeAll(_emittedClasses);
-    } else {
-      // Make sure that the set of emitted classes is preserved for subsequent
-      // updates.
-      // TODO(ahe): This is a bit convoluted, find a better approach.
-      emitter.neededClasses
-          ..clear()
-          ..addAll(_emittedClasses);
-    }
-
-    List<jsAst.Statement> inherits = <jsAst.Statement>[];
-
-    for (ClassElementX cls in newClasses) {
-      jsAst.Node classAccess = emitter.constructorAccess(cls);
-      String name = namer.className(cls);
-
-      updates.add(
-          js.statement(
-              r'# = #', [classAccess, invokeDefineClass(cls)]));
-
-      ClassElement superclass = cls.superclass;
-      if (superclass != null) {
-        jsAst.Node superAccess = emitter.constructorAccess(superclass);
-        inherits.add(
-            js.statement(
-                r'this.inheritFrom(#, #)', [classAccess, superAccess]));
-      }
-    }
-
-    // Call inheritFrom after all classes have been created. This way we don't
-    // need to sort the classes by having superclasses defined before their
-    // subclasses.
-    updates.addAll(inherits);
-
-    for (ClassElementX cls in changedClasses) {
-      ClassElement superclass = cls.superclass;
-      jsAst.Node superAccess =
-          superclass == null ? js('null')
-              : emitter.constructorAccess(superclass);
-      jsAst.Node classAccess = emitter.constructorAccess(cls);
-      updates.add(
-          js.statement(
-              r'# = this.schemaChange(#, #, #)',
-              [classAccess, invokeDefineClass(cls), classAccess, superAccess]));
-    }
-
-    for (RemovalUpdate update in removals) {
-      update.writeUpdateJsOn(updates);
-    }
-    for (Element element in enqueuer.codegen.newlyEnqueuedElements) {
-      if (element.isField) {
-        updates.addAll(computeFieldUpdateJs(element));
-      } else {
-        updates.add(computeMethodUpdateJs(element));
-      }
-    }
-
-    Set<ConstantValue> newConstants = new Set<ConstantValue>.identity()..addAll(
-        compiler.backend.constants.compiledConstants);
-    newConstants.removeAll(_compiledConstants);
-
-    if (!newConstants.isEmpty) {
-      _ensureAllNeededEntitiesComputed();
-      List<ConstantValue> constants =
-          emitter.outputConstantLists[compiler.deferredLoadTask.mainOutputUnit];
-      if (constants != null) {
-        for (ConstantValue constant in constants) {
-          if (!_compiledConstants.contains(constant)) {
-            full.Emitter fullEmitter = emitter.emitter;
-            jsAst.Statement constantInitializer =
-                fullEmitter.buildConstantInitializer(constant).toStatement();
-            updates.add(constantInitializer);
-          }
-        }
-      }
-    }
-
-    updates.add(js.statement(r'''
-if (this.pendingStubs) {
-  this.pendingStubs.map(function(e) { return e(); });
-  this.pendingStubs = void 0;
-}
-'''));
-
-    if (updates.length == 1) {
-      return prettyPrintJs(updates.single);
-    } else {
-      return prettyPrintJs(js.statement('{#}', [updates]));
-    }
-  }
-
-  jsAst.Expression invokeDefineClass(ClassElementX cls) {
-    String name = namer.className(cls);
-    var descriptor = js('Object.create(null)');
-    return js(
-        r'''
-(new Function(
-    "$collectedClasses", "$desc",
-    this.defineClass(#name, #computeFields) +"\n;return " + #name))(
-        {#name: [,#descriptor]})''',
-        {'name': js.string(name),
-         'computeFields': js.stringArray(computeFields(cls)),
-         'descriptor': descriptor});
-  }
-
-  jsAst.Node computeMethodUpdateJs(Element element) {
-    Method member = new ProgramBuilder(compiler, namer, emitter)
-        .buildMethodHackForIncrementalCompilation(element);
-    if (member == null) {
-      compiler.internalError(element, '${element.runtimeType}');
-    }
-    ClassBuilder builder = new ClassBuilder(element, namer);
-    containerBuilder.addMemberMethod(member, builder);
-    jsAst.Node partialDescriptor =
-        builder.toObjectInitializer(emitClassDescriptor: false);
-
-    String name = member.name;
-    jsAst.Node function = member.code;
-    bool isStatic = !element.isInstanceMember;
-
-    /// Either a global object (non-instance members) or a prototype (instance
-    /// members).
-    jsAst.Node holder;
-
-    if (element.isInstanceMember) {
-      holder = emitter.prototypeAccess(element.enclosingClass);
-    } else {
-      holder = js('#', namer.globalObjectFor(element));
-    }
-
-    jsAst.Expression globalFunctionsAccess =
-        emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS);
-
-    return js.statement(
-        r'this.addMethod(#, #, #, #, #)',
-        [partialDescriptor, js.string(name), holder,
-         new jsAst.LiteralBool(isStatic), globalFunctionsAccess]);
-  }
-
-  List<jsAst.Statement> computeFieldUpdateJs(FieldElementX element) {
-    if (element.isInstanceMember) {
-      // Any initializers are inlined in factory methods, and the field is
-      // declared by adding its class to [_classesWithSchemaChanges].
-      return const <jsAst.Statement>[];
-    }
-    // A static (or top-level) field.
-    if (backend.constants.lazyStatics.contains(element)) {
-      full.Emitter fullEmitter = emitter.emitter;
-      jsAst.Expression init =
-          fullEmitter.buildLazilyInitializedStaticField(
-              element, isolateProperties: namer.staticStateHolder);
-      if (init == null) {
-        throw new StateError("Initializer optimized away for $element");
-      }
-      return <jsAst.Statement>[init.toStatement()];
-    } else {
-      // TODO(ahe): When a field is referenced it is enqueued. If the field has
-      // no initializer, it will not have any associated code, so it will
-      // appear as if it was newly enqueued.
-      if (element.initializer == null) {
-        return const <jsAst.Statement>[];
-      } else {
-        throw new StateError("Don't know how to compile $element");
-      }
-    }
-  }
-
-  String prettyPrintJs(jsAst.Node node) {
-    jsAst.JavaScriptPrintingOptions options =
-        new jsAst.JavaScriptPrintingOptions();
-    jsAst.JavaScriptPrintingContext context =
-        new jsAst.Dart2JSJavaScriptPrintingContext(compiler, null);
-    jsAst.Printer printer = new jsAst.Printer(options, context);
-    printer.blockOutWithoutBraces(node);
-    return context.outBuffer.getText();
-  }
-
-  String callNameFor(FunctionElement element) {
-    // TODO(ahe): Call a method in the compiler to obtain this name.
-    String callPrefix = namer.callPrefix;
-    int parameterCount = element.functionSignature.parameterCount;
-    return '$callPrefix\$$parameterCount';
-  }
-
-  List<String> computeFields(ClassElement cls) {
-    return new EmitterHelper(compiler).computeFields(cls);
-  }
-
-  void _ensureAllNeededEntitiesComputed() {
-    if (_hasComputedNeeds) return;
-    emitter.computeAllNeededEntities();
-    _hasComputedNeeds = true;
-  }
-}
-
-/// Represents an update (aka patch) of [before] to [after]. We use the word
-/// "update" to avoid confusion with the compiler feature of "patch" methods.
-abstract class Update {
-  final Compiler compiler;
-
-  PartialElement get before;
-
-  PartialElement get after;
-
-  Update(this.compiler);
-
-  /// Applies the update to [before] and returns that element.
-  Element apply();
-
-  bool get isRemoval => false;
-
-  /// Called before any patches are applied to capture any state that is needed
-  /// later.
-  void captureState() {
-  }
-}
-
-/// Represents an update of a function element.
-class FunctionUpdate extends Update with ReuseFunction {
-  final PartialFunctionElement before;
-
-  final PartialFunctionElement after;
-
-  FunctionUpdate(Compiler compiler, this.before, this.after)
-      : super(compiler);
-
-  PartialFunctionElement apply() {
-    patchElement();
-    reuseElement();
-    return before;
-  }
-
-  /// Destructively change the tokens in [before] to match those of [after].
-  void patchElement() {
-    before.beginToken = after.beginToken;
-    before.endToken = after.endToken;
-    before.getOrSet = after.getOrSet;
-  }
-}
-
-abstract class ReuseFunction {
-  Compiler get compiler;
-
-  PartialFunctionElement get before;
-
-  /// Reset various caches and remove this element from the compiler's internal
-  /// state.
-  void reuseElement() {
-    compiler.forgetElement(before);
-    before.reuseElement();
-  }
-}
-
-abstract class RemovalUpdate extends Update {
-  ElementX get element;
-
-  RemovalUpdate(Compiler compiler)
-      : super(compiler);
-
-  bool get isRemoval => true;
-
-  void writeUpdateJsOn(List<jsAst.Statement> updates);
-
-  void removeFromEnclosing() {
-    // TODO(ahe): Need to recompute duplicated elements logic again. Simplest
-    // solution is probably to remove all elements from enclosing scope and add
-    // them back.
-    if (element.isTopLevel) {
-      removeFromLibrary(element.library);
-    } else {
-      removeFromEnclosingClass(element.enclosingClass);
-    }
-  }
-
-  void removeFromEnclosingClass(PartialClassElement cls) {
-    cls.localMembersCache = null;
-    cls.localMembersReversed = cls.localMembersReversed.copyWithout(element);
-    cls.localScope.contents.remove(element.name);
-  }
-
-  void removeFromLibrary(LibraryElementX library) {
-    library.localMembers = library.localMembers.copyWithout(element);
-    library.localScope.contents.remove(element.name);
-  }
-}
-
-class RemovedFunctionUpdate extends RemovalUpdate
-    with JsFeatures, ReuseFunction {
-  final PartialFunctionElement element;
-
-  /// Name of property to remove using JavaScript "delete". Null for
-  /// non-instance methods.
-  String name;
-
-  /// For instance methods, access to class object. Otherwise, access to the
-  /// method itself.
-  jsAst.Node elementAccess;
-
-  bool wasStateCaptured = false;
-
-  RemovedFunctionUpdate(Compiler compiler, this.element)
-      : super(compiler);
-
-  PartialFunctionElement get before => element;
-
-  PartialFunctionElement get after => null;
-
-  void captureState() {
-    if (wasStateCaptured) throw "captureState was called twice.";
-    wasStateCaptured = true;
-
-    if (element.isInstanceMember) {
-      elementAccess = emitter.constructorAccess(element.enclosingClass);
-      name = namer.instanceMethodName(element);
-    } else {
-      elementAccess = emitter.staticFunctionAccess(element);
-    }
-  }
-
-  PartialFunctionElement apply() {
-    if (!wasStateCaptured) throw "captureState must be called before apply.";
-    removeFromEnclosing();
-    reuseElement();
-    return null;
-  }
-
-  void writeUpdateJsOn(List<jsAst.Statement> updates) {
-    if (elementAccess == null) {
-      compiler.internalError(
-          element, 'No elementAccess for ${element.runtimeType}');
-    }
-    if (element.isInstanceMember) {
-      if (name == null) {
-        compiler.internalError(element, 'No name for ${element.runtimeType}');
-      }
-      updates.add(
-          js.statement('delete #.prototype.#', [elementAccess, name]));
-    } else {
-      updates.add(js.statement('delete #', [elementAccess]));
-    }
-  }
-}
-
-class RemovedClassUpdate extends RemovalUpdate with JsFeatures {
-  final PartialClassElement element;
-
-  bool wasStateCaptured = false;
-
-  final List<jsAst.Node> accessToStatics = <jsAst.Node>[];
-
-  RemovedClassUpdate(Compiler compiler, this.element)
-      : super(compiler);
-
-  PartialClassElement get before => element;
-
-  PartialClassElement get after => null;
-
-  void captureState() {
-    if (wasStateCaptured) throw "captureState was called twice.";
-    wasStateCaptured = true;
-    accessToStatics.add(emitter.constructorAccess(element));
-
-    element.forEachLocalMember((ElementX member) {
-      if (!member.isInstanceMember) {
-        accessToStatics.add(emitter.staticFunctionAccess(member));
-      }
-    });
-  }
-
-  PartialClassElement apply() {
-    if (!wasStateCaptured) {
-      throw new StateError("captureState must be called before apply.");
-    }
-
-    removeFromEnclosing();
-
-    element.forEachLocalMember((ElementX member) {
-      compiler.forgetElement(member);
-      member.reuseElement();
-    });
-
-    compiler.forgetElement(element);
-    element.reuseElement();
-
-    return null;
-  }
-
-  void writeUpdateJsOn(List<jsAst.Statement> updates) {
-    if (accessToStatics.isEmpty) {
-      throw
-          new StateError("captureState must be called before writeUpdateJsOn.");
-    }
-
-    for (jsAst.Node access in accessToStatics) {
-      updates.add(js.statement('delete #', [access]));
-    }
-  }
-}
-
-class RemovedFieldUpdate extends RemovalUpdate with JsFeatures {
-  final FieldElementX element;
-
-  bool wasStateCaptured = false;
-
-  jsAst.Node prototypeAccess;
-
-  String getterName;
-
-  String setterName;
-
-  RemovedFieldUpdate(Compiler compiler, this.element)
-      : super(compiler);
-
-  PartialFieldList get before => element.declarationSite;
-
-  PartialFieldList get after => null;
-
-  void captureState() {
-    if (wasStateCaptured) throw "captureState was called twice.";
-    wasStateCaptured = true;
-
-    prototypeAccess = emitter.prototypeAccess(element.enclosingClass);
-    getterName = namer.getterForElement(element);
-    setterName = namer.setterForElement(element);
-  }
-
-  FieldElementX apply() {
-    if (!wasStateCaptured) {
-      throw new StateError("captureState must be called before apply.");
-    }
-
-    removeFromEnclosing();
-
-    return element;
-  }
-
-  void writeUpdateJsOn(List<jsAst.Statement> updates) {
-    if (!wasStateCaptured) {
-      throw new StateError(
-          "captureState must be called before writeUpdateJsOn.");
-    }
-
-    updates.add(
-        js.statement('delete #.#', [prototypeAccess, getterName]));
-    updates.add(
-        js.statement('delete #.#', [prototypeAccess, setterName]));
-  }
-}
-
-class AddedFunctionUpdate extends Update with JsFeatures {
-  final PartialFunctionElement element;
-
-  final /* ScopeContainerElement */ container;
-
-  AddedFunctionUpdate(Compiler compiler, this.element, this.container)
-      : super(compiler) {
-    if (container == null) {
-      throw "container is null";
-    }
-  }
-
-  PartialFunctionElement get before => null;
-
-  PartialFunctionElement get after => element;
-
-  PartialFunctionElement apply() {
-    Element enclosing = container;
-    if (enclosing.isLibrary) {
-      // TODO(ahe): Reuse compilation unit of element instead?
-      enclosing = enclosing.compilationUnit;
-    }
-    PartialFunctionElement copy = element.copyWithEnclosing(enclosing);
-    NO_WARN(container).addMember(copy, compiler);
-    return copy;
-  }
-}
-
-class AddedClassUpdate extends Update with JsFeatures {
-  final PartialClassElement element;
-
-  final LibraryElementX library;
-
-  AddedClassUpdate(Compiler compiler, this.element, this.library)
-      : super(compiler);
-
-  PartialClassElement get before => null;
-
-  PartialClassElement get after => element;
-
-  PartialClassElement apply() {
-    // TODO(ahe): Reuse compilation unit of element instead?
-    CompilationUnitElementX compilationUnit = library.compilationUnit;
-    PartialClassElement copy = element.copyWithEnclosing(compilationUnit);
-    compilationUnit.addMember(copy, compiler);
-    return copy;
-  }
-}
-
-class AddedFieldUpdate extends Update with JsFeatures {
-  final FieldElementX element;
-
-  final ScopeContainerElement container;
-
-  AddedFieldUpdate(Compiler compiler, this.element, this.container)
-      : super(compiler);
-
-  PartialFieldList get before => null;
-
-  PartialFieldList get after => element.declarationSite;
-
-  FieldElementX apply() {
-    Element enclosing = container;
-    if (enclosing.isLibrary) {
-      // TODO(ahe): Reuse compilation unit of element instead?
-      enclosing = enclosing.compilationUnit;
-    }
-    FieldElementX copy = element.copyWithEnclosing(enclosing);
-    NO_WARN(container).addMember(copy, compiler);
-    return copy;
-  }
-}
-
-
-class ClassUpdate extends Update with JsFeatures {
-  final PartialClassElement before;
-
-  final PartialClassElement after;
-
-  ClassUpdate(Compiler compiler, this.before, this.after)
-      : super(compiler);
-
-  PartialClassElement apply() {
-    patchElement();
-    reuseElement();
-    return before;
-  }
-
-  /// Destructively change the tokens in [before] to match those of [after].
-  void patchElement() {
-    before.cachedNode = after.cachedNode;
-    before.beginToken = after.beginToken;
-    before.endToken = after.endToken;
-  }
-
-  void reuseElement() {
-    before.supertype = null;
-    before.interfaces = null;
-    before.nativeTagInfo = null;
-    before.supertypeLoadState = STATE_NOT_STARTED;
-    before.resolutionState = STATE_NOT_STARTED;
-    before.isProxy = false;
-    before.hasIncompleteHierarchy = false;
-    before.backendMembers = const Link<Element>();
-    before.allSupertypesAndSelf = null;
-  }
-}
-
-/// Returns all qualified names in [element] with less than four identifiers. A
-/// qualified name is an identifier followed by a sequence of dots and
-/// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the
-/// fourth identifier).
-///
-/// The longest possible name that can be resolved is three identifiers, for
-/// example, "prefix.MyClass.staticMethod". Since four or more identifiers
-/// cannot resolve to anything statically, they're not included in the returned
-/// value of this method.
-Set<String> qualifiedNamesIn(PartialElement element) {
-  Token beginToken = element.beginToken;
-  Token endToken = element.endToken;
-  Token token = beginToken;
-  if (element is PartialClassElement) {
-    ClassNode node = element.cachedNode;
-    if (node != null) {
-      NodeList body = node.body;
-      if (body != null) {
-        endToken = body.beginToken;
-      }
-    }
-  }
-  Set<String> names = new Set<String>();
-  do {
-    if (token.isIdentifier()) {
-      String name = token.value;
-      // [name] is a single "identifier".
-      names.add(name);
-      if (identical('.', token.next.stringValue) &&
-          token.next.next.isIdentifier()) {
-        token = token.next.next;
-        name += '.${token.value}';
-        // [name] is "idenfifier.idenfifier".
-        names.add(name);
-
-        if (identical('.', token.next.stringValue) &&
-            token.next.next.isIdentifier()) {
-          token = token.next.next;
-          name += '.${token.value}';
-          // [name] is "idenfifier.idenfifier.idenfifier".
-          names.add(name);
-
-          while (identical('.', token.next.stringValue) &&
-                 token.next.next.isIdentifier()) {
-            // Skip remaining identifiers, they cannot statically resolve to
-            // anything, and must be dynamic sends.
-            token = token.next.next;
-          }
-        }
-      }
-    }
-    token = token.next;
-  } while (token.kind != EOF_TOKEN && token != endToken);
-  return names;
-}
-
-/// Returns true if one of the qualified names in names (as computed by
-/// [qualifiedNamesIn]) could be a static reference to [element].
-bool canNamesResolveStaticallyTo(
-    Set<String> names,
-    Element element,
-    /* ScopeContainerElement */ container) {
-  if (names.contains(element.name)) return true;
-  if (container != null && container.isClass) {
-    // [names] contains C.m, where C is the name of [container], and m is the
-    // name of [element].
-    if (names.contains("${container.name}.${element.name}")) return true;
-  }
-  // TODO(ahe): Check for prefixes as well.
-  return false;
-}
-
-DeclarationSite declarationSite(Element element) {
-  return element is ElementX ? element.declarationSite : null;
-}
-
-abstract class JsFeatures {
-  Compiler get compiler;
-
-  JavaScriptBackend get backend => compiler.backend;
-
-  Namer get namer => backend.namer;
-
-  CodeEmitterTask get emitter => backend.emitter;
-
-  ContainerBuilder get containerBuilder {
-    full.Emitter fullEmitter = emitter.emitter;
-    return fullEmitter.containerBuilder;
-  }
-
-  EnqueueTask get enqueuer => compiler.enqueuer;
-}
-
-class EmitterHelper extends JsFeatures {
-  final Compiler compiler;
-
-  EmitterHelper(this.compiler);
-
-  ClassEmitter get classEmitter {
-    full.Emitter fullEmitter = emitter.emitter;
-    return fullEmitter.classEmitter;
-  }
-
-  List<String> computeFields(ClassElement classElement) {
-    Class cls = new ProgramBuilder(compiler, namer, emitter)
-        .buildFieldsHackForIncrementalCompilation(classElement);
-    // TODO(ahe): Rewrite for new emitter.
-    ClassBuilder builder = new ClassBuilder(classElement, namer);
-    classEmitter.emitFields(cls, builder);
-    return builder.fields;
-  }
-}
-
-// TODO(ahe): Remove this method.
-NO_WARN(x) => x;
diff --git a/pkg/dart2js_incremental/lib/server.dart b/pkg/dart2js_incremental/lib/server.dart
deleted file mode 100644
index d2dc9a2..0000000
--- a/pkg/dart2js_incremental/lib/server.dart
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js_incremental.server;
-
-import 'dart:io';
-
-import 'dart:async' show
-    Completer,
-    Future,
-    Stream,
-    StreamController,
-    StreamSubscription;
-
-import 'dart:convert' show
-    HtmlEscape,
-    JSON,
-    UTF8;
-
-import 'src/options.dart';
-
-import 'compiler.dart' show
-    CompilerEvent,
-    IncrementalKind,
-    compile;
-
-class Conversation {
-  HttpRequest request;
-  HttpResponse response;
-
-  static const String PACKAGES_PATH = '/packages';
-
-  static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE;
-
-  static Uri documentRoot = Uri.base;
-
-  static Uri packageRoot = Uri.base.resolve('packages/');
-
-  static Map<Uri, Future<String>> generatedFiles =
-      new Map<Uri, Future<String>>();
-
-  static Map<Uri, StreamController<String>> updateControllers =
-      new Map<Uri, StreamController<String>>();
-
-  Conversation(this.request, this.response);
-
-  onClosed(_) {
-    if (response.statusCode == HttpStatus.OK) return;
-    print('Request for ${request.uri} ${response.statusCode}');
-  }
-
-  Future notFound(Uri uri) {
-    response
-        ..headers.set(CONTENT_TYPE, 'text/html')
-        ..statusCode = HttpStatus.NOT_FOUND
-        ..write(htmlInfo("Not Found", "The file '$uri' could not be found."));
-    return response.close();
-  }
-
-  Future badRequest(String problem) {
-    response
-        ..headers.set(CONTENT_TYPE, 'text/html')
-        ..statusCode = HttpStatus.BAD_REQUEST
-        ..write(
-            htmlInfo("Bad request", "Bad request '${request.uri}': $problem"));
-    return response.close();
-  }
-
-  Future handleSocket() async {
-    StreamController<String> controller = updateControllers[request.uri];
-    if (controller != null) {
-      WebSocket socket = await WebSocketTransformer.upgrade(request);
-      print(
-          "Patches to ${request.uri} will be pushed to "
-          "${request.connectionInfo.remoteAddress.host}:"
-          "${request.connectionInfo.remotePort}.");
-      controller.stream.pipe(socket);
-    } else {
-      response.done
-          .then(onClosed)
-          .catchError(onError);
-      return await notFound(request.uri);
-    }
-  }
-
-  Future handle() {
-    response.done
-        .then(onClosed)
-        .catchError(onError);
-
-    Uri uri = request.uri;
-    if (uri.path.endsWith('/')) {
-      uri = uri.resolve('index.html');
-    }
-    if (uri.path.contains('..') || uri.path.contains('%')) {
-      return notFound(uri);
-    }
-    String path = uri.path;
-    Uri root = documentRoot;
-    if (path.startsWith('${PACKAGES_PATH}/')) {
-      root = packageRoot;
-      path = path.substring(PACKAGES_PATH.length);
-    }
-
-    Uri resolvedRequest = root.resolve('.$path');
-    switch (request.method) {
-      case 'GET':
-        return handleGet(resolvedRequest);
-      default:
-        String method = const HtmlEscape().convert(request.method);
-        return badRequest("Unsupported method: '$method'");
-    }
-  }
-
-  Future handleGet(Uri uri) async {
-    String path = uri.path;
-    var f = new File.fromUri(uri);
-    if (!await f.exists()) {
-      return await handleNonExistingFile(uri);
-    } else {
-      setContentType(path);
-    }
-    return await f.openRead().pipe(response);
-  }
-
-  void setContentType(String path) {
-    if (path.endsWith('.html')) {
-      response.headers.set(CONTENT_TYPE, 'text/html');
-    } else if (path.endsWith('.dart')) {
-      response.headers.set(CONTENT_TYPE, 'application/dart');
-    } else if (path.endsWith('.js')) {
-      response.headers.set(CONTENT_TYPE, 'application/javascript');
-    } else if (path.endsWith('.ico')) {
-      response.headers.set(CONTENT_TYPE, 'image/x-icon');
-    } else if (path.endsWith('.appcache')) {
-      response.headers.set(CONTENT_TYPE, 'text/cache-manifest');
-    } else if (path.endsWith('.css')) {
-      response.headers.set(CONTENT_TYPE, 'text/css');
-    } else if (path.endsWith('.png')) {
-      response.headers.set(CONTENT_TYPE, 'image/png');
-    }
-  }
-
-  Future handleNonExistingFile(Uri uri) async {
-    String path = uri.path;
-    String generated = await generatedFiles[request.uri];
-    if (generated != null) {
-      print("Serving ${request.uri} from memory.");
-      setContentType(path);
-      response.write(generated);
-      return await response.close();
-    }
-    if (path.endsWith('.dart.js')) {
-      Uri dartScript = uri.resolve(path.substring(0, path.length - 3));
-      if (await new File.fromUri(dartScript).exists()) {
-        return await compileToJavaScript(dartScript);
-      }
-    }
-    return await notFound(request.uri);
-  }
-
-  compileToJavaScript(Uri dartScript) {
-    Uri outputUri = request.uri;
-    Completer<String> completer = new Completer<String>();
-    generatedFiles[outputUri] = completer.future;
-    StreamController controller = updateControllers[outputUri];
-    if (controller != null) {
-      controller.close();
-    }
-    updateControllers[outputUri] = new StreamController<String>.broadcast();
-    print("Compiling $dartScript to $outputUri.");
-    StreamSubscription<CompilerEvent> subscription;
-    subscription = compile(dartScript).listen((CompilerEvent event) {
-      subscription.onData(
-          (CompilerEvent event) => onCompilerEvent(completer, event));
-      if (event.kind != IncrementalKind.FULL) {
-        notFound(request.uri);
-        // TODO(ahe): Do something about this situation.
-      } else {
-        print("Done compiling $dartScript to $outputUri.");
-        completer.complete(event['.js']);
-        setContentType(outputUri.path);
-        response.write(event['.js']);
-        response.close();
-      }
-    });
-  }
-
-  onCompilerEvent(Completer completer, CompilerEvent event) {
-    Uri outputUri = request.uri;
-    print("Got ${event.kind} for $outputUri");
-
-    switch (event.kind) {
-      case IncrementalKind.FULL:
-        generatedFiles[outputUri] = new Future.value(event['.js']);
-        break;
-
-      case IncrementalKind.INCREMENTAL:
-        generatedFiles[outputUri] = completer.future.then(
-            (String full) => '$full\n\n${event.compiler.allUpdates()}');
-        pushUpdates(event.updates);
-        break;
-
-      case IncrementalKind.ERROR:
-        generatedFiles.removeKey(outputUri);
-        break;
-    }
-  }
-
-  void pushUpdates(String updates) {
-    if (updates == null) return;
-    StreamController<String> controller = updateControllers[request.uri];
-    if (controller == null) return;
-    print("Adding updates to controller");
-    controller.add(updates);
-  }
-
-  Future dispatch() async {
-    try {
-      return await WebSocketTransformer.isUpgradeRequest(request)
-          ? handleSocket()
-          : handle();
-    } catch (e, s) {
-      onError(e, s);
-    }
-  }
-
-  static Future onRequest(HttpRequest request) async {
-    HttpResponse response = request.response;
-    try {
-      return await new Conversation(request, response).dispatch();
-    } catch (e, s) {
-      try {
-        onStaticError(e, s);
-        return await response.close();
-      } catch (e, s) {
-        onStaticError(e, s);
-      }
-    }
-  }
-
-  Future onError(error, [stack]) async {
-    try {
-      onStaticError(error, stack);
-      return await response.close();
-    } catch (e, s) {
-      onStaticError(e, s);
-    }
-  }
-
-  static void onStaticError(error, [stack]) {
-    if (error is HttpException) {
-      print('Error: ${error.message}');
-    } else {
-      print('Error: ${error}');
-    }
-    if (stack != null) {
-      print(stack);
-    }
-  }
-
-  String htmlInfo(String title, String text) {
-    // No script injection, please.
-    title = const HtmlEscape().convert(title);
-    text = const HtmlEscape().convert(text);
-    return """
-<!DOCTYPE html>
-<html lang='en'>
-<head>
-<title>$title</title>
-</head>
-<body>
-<h1>$title</h1>
-<p style='white-space:pre'>$text</p>
-</body>
-</html>
-""";
-  }
-}
-
-main(List<String> arguments) async {
-  Options options = Options.parse(arguments);
-  if (options == null) {
-    exit(1);
-  }
-  if (!options.arguments.isEmpty) {
-    Conversation.documentRoot = Uri.base.resolve(options.arguments.single);
-  }
-  Conversation.packageRoot = options.packageRoot;
-  String host = options.host;
-  int port = options.port;
-  try {
-    HttpServer server = await HttpServer.bind(host, port);
-    print('HTTP server started on http://$host:${server.port}/');
-    server.listen(Conversation.onRequest, onError: Conversation.onStaticError);
-  } catch (e) {
-    print("HttpServer.bind error: $e");
-    exit(1);
-  };
-}
diff --git a/pkg/dart2js_incremental/lib/src/options.dart b/pkg/dart2js_incremental/lib/src/options.dart
deleted file mode 100644
index ba1260f..0000000
--- a/pkg/dart2js_incremental/lib/src/options.dart
+++ /dev/null
@@ -1,134 +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.
-
-library dart2js_incremental.options;
-
-class Options {
-  final List<String> arguments;
-  final Uri packageRoot;
-  final String host;
-  final int port;
-
-  Options({this.arguments, this.packageRoot, this.host, this.port});
-
-  static String extractArgument(String option, String short, {String long}) {
-    if (option.startsWith(short)) {
-      return option.substring(short.length);
-    }
-    if (long != null && option.startsWith(long)) {
-      return option.substring(long.length);
-    }
-    return null;
-  }
-
-  static Options parse(List<String> commandLine) {
-    Iterator<String> iterator = commandLine.iterator;
-    List<String> arguments = <String>[];
-    Uri packageRoot;
-    String host = "127.0.0.1";
-    int port = 0;
-    bool showHelp = false;
-    List<String> unknownOptions = <String>[];
-
-    LOOP: while (iterator.moveNext()) {
-      String option = iterator.current;
-      switch (option) {
-        case "-p":
-          iterator.moveNext();
-          packageRoot = Uri.base.resolve(iterator.current);
-          continue;
-
-        case "-h":
-          iterator.moveNext();
-          host = iterator.current;
-          continue;
-
-        case "-n":
-          iterator.moveNext();
-          port = int.parse(iterator.current);
-          continue;
-
-        case "--help":
-          showHelp = true;
-          continue;
-
-        case "--":
-          break LOOP;
-
-        default:
-          String argument;
-
-          argument = extractArgument(option, "-p", long: "--package-root");
-          if (argument != null) {
-            packageRoot = Uri.base.resolve(argument);
-            continue;
-          }
-
-          argument = extractArgument(option, "-h", long: "--host");
-          if (argument != null) {
-            host = argument;
-            continue;
-          }
-
-          argument = extractArgument(option, "-n", long: "--port");
-          if (argument != null) {
-            port = int.parse(option);
-            continue;
-          }
-
-          if (option.startsWith("-")) {
-            unknownOptions.add(option);
-            continue;
-          }
-
-          arguments.add(option);
-          break;
-      }
-    }
-    if (showHelp) {
-      print(USAGE);
-    }
-    if (!unknownOptions.isEmpty) {
-      print(USAGE);
-      print("Unknown options: '${unknownOptions.join('\', \'')}'");
-      return null;
-    }
-    while (iterator.moveNext()) {
-      arguments.add(iterator.current);
-    }
-    if (arguments.length > 1) {
-      print(USAGE);
-      print("Extra arguments: '${arguments.skip(1).join('\', \'')}'");
-      return null;
-    }
-    if (packageRoot == null) {
-      packageRoot = Uri.base.resolve('packages/');
-    }
-    return new Options(
-        arguments: arguments, packageRoot: packageRoot, host: host, port: port);
-  }
-}
-
-const String USAGE = """
-Usage: server.dart [options] [--] documentroot
-
-Development web server which serves files relative to [documentroot]. If a file
-is missing, and the requested file name ends with '.dart.js', the server will
-look for a file with the same name save '.js', compile it to JavaScript, and
-serve that file instead.
-
-Supported options:
-
-  -p<path>, --package-root=<path>
-    Where to find packages, that is, "package:..." imports.
-
-  -h<name>, --host=<name>
-    Host name to bind the web server to (default 127.0.0.1).
-
-  -n<port>, --port=<port>
-    Port number to bind the web server to.
-
-  --help
-    Show this message.
-""";
diff --git a/pkg/dart2js_incremental/lib/watcher.dart b/pkg/dart2js_incremental/lib/watcher.dart
deleted file mode 100644
index a212f6d..0000000
--- a/pkg/dart2js_incremental/lib/watcher.dart
+++ /dev/null
@@ -1,62 +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.
-
-library dart2js_incremental.watcher;
-
-import 'dart:io';
-
-import 'dart:async';
-
-class Watcher {
-  final Set<String> _watchedDirectories = new Set<String>();
-
-  final Map<String, Set<Uri>> _watchedFiles = new Map<String, Set<Uri>>();
-
-  final Set<Uri> _changes = new Set<Uri>();
-
-  bool _hasEarlyChanges = false;
-
-  Completer<bool> _changesCompleter;
-
-  Future<bool> hasChanges() {
-    if (_changesCompleter == null && _hasEarlyChanges) {
-      return new Future.value(true);
-    }
-    _changesCompleter = new Completer<bool>();
-    return _changesCompleter.future;
-  }
-
-  void _onFileSystemEvent(FileSystemEvent event) {
-    Set<Uri> uris = _watchedFiles[event.path];
-    if (uris == null) return;
-    _changes.addAll(uris);
-    if (_changesCompleter == null) {
-      _hasEarlyChanges = true;
-    } else if (!_changesCompleter.isCompleted) {
-      _changesCompleter.complete(true);
-    }
-  }
-
-  Map<Uri, Uri> readChanges() {
-    if (_changes.isEmpty) {
-      throw new StateError("No changes");
-    }
-    Map<Uri, Uri> result = new Map<Uri, Uri>();
-    for (Uri uri in _changes) {
-      result[uri] = uri;
-    }
-    _changes.clear();
-    return result;
-  }
-
-  void watchFile(Uri uri) {
-    String realpath = new File.fromUri(uri).resolveSymbolicLinksSync();
-    _watchedFiles.putIfAbsent(realpath, () => new Set<Uri>()).add(uri);
-    Directory directory = new File(realpath).parent;
-    if (_watchedDirectories.add(directory.path)) {
-      print("Watching ${directory.path}");
-      directory.watch().listen(_onFileSystemEvent);
-    }
-  }
-}
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index 152b38d..b6da6fe 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -1988,6 +1988,9 @@
     return dart.noSuchMethod(obj, new dart.InvocationImpl(field, [value], {isSetter: true}));
   };
   dart._checkApply = function(type, actuals) {
+    if (type instanceof Array) {
+      type = type[0];
+    }
     if (actuals.length < type.args.length) return false;
     let index = 0;
     for (let i = 0; i < type.args.length; ++i) {
@@ -25730,13 +25733,13 @@
         this[_modifications$] = modifications;
         this[_cell$] = null;
         this[_current$2] = null;
-        this[_cell$] = collection._LinkedHashSetCell._check(dart.dload(this[_set], _first$));
+        this[_cell$] = this[_set][_first$];
       }
       get current() {
         return this[_current$2];
       }
       moveNext() {
-        if (!dart.equals(this[_modifications$], dart.dload(this[_set], _modifications$))) {
+        if (this[_modifications$] != this[_set][_modifications$]) {
           dart.throw(new core.ConcurrentModificationError(this[_set]));
         } else if (this[_cell$] == null) {
           this[_current$2] = null;
@@ -25751,9 +25754,9 @@
     dart.addTypeTests(_LinkedHashSetIterator);
     _LinkedHashSetIterator[dart.implements] = () => [IteratorOfE()];
     dart.setSignature(_LinkedHashSetIterator, {
-      constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [dart.dynamic, core.int])}),
+      constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [collection._LinkedHashSet, core.int])}),
       fields: () => ({
-        [_set]: dart.dynamic,
+        [_set]: collection._LinkedHashSet,
         [_modifications$]: core.int,
         [_cell$]: collection._LinkedHashSetCell,
         [_current$2]: E
@@ -99198,7 +99201,7 @@
       let copy = this.newJsList(length);
       this.writeSlot(slot, copy);
       for (; i < dart.notNull(length); i++) {
-        dart.dsetindex(copy, i, this.walk(e[dartx._get](i)));
+        copy[dartx._set](i, this.walk(e[dartx._get](i)));
       }
       return copy;
     }
@@ -99219,7 +99222,7 @@
       writeSlot: dart.definiteFunctionType(dart.dynamic, [core.int, dart.dynamic]),
       cleanupSlots: dart.definiteFunctionType(dart.dynamic, []),
       walk: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-      copyList: dart.definiteFunctionType(dart.dynamic, [core.List, core.int]),
+      copyList: dart.definiteFunctionType(core.List, [core.List, core.int]),
       convertDartToNative_PrepareForStructuredClone: dart.definiteFunctionType(dart.dynamic, [dart.dynamic])
     })
   });
@@ -99268,14 +99271,15 @@
         return copy;
       }
       if (dart.test(html_common.isJavaScriptArray(e))) {
-        let slot = this.findSlot(e);
+        let l = e;
+        let slot = this.findSlot(l);
         let copy = this.readSlot(slot);
         if (copy != null) return copy;
-        let length = core.int._check(dart.dload(e, 'length'));
-        copy = dart.test(this.mustCopy) ? this.newDartList(length) : e;
+        let length = l[dartx.length];
+        copy = dart.test(this.mustCopy) ? this.newDartList(length) : l;
         this.writeSlot(slot, copy);
         for (let i = 0; i < dart.notNull(length); i++) {
-          dart.dsetindex(copy, i, this.walk(dart.dindex(e, i)));
+          copy[dartx._set](i, this.walk(l[dartx._get](i)));
         }
         return copy;
       }
@@ -99436,7 +99440,7 @@
     methods: () => ({
       newJsMap: dart.definiteFunctionType(dart.dynamic, []),
       putIntoMap: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic, dart.dynamic]),
-      newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+      newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
       cloneNotRequired: dart.definiteFunctionType(core.bool, [dart.dynamic])
     })
   });
@@ -99461,10 +99465,10 @@
   };
   dart.setSignature(html_common._AcceptStructuredCloneDart2Js, {
     methods: () => ({
-      newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-      newDartList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+      newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
+      newDartList: dart.definiteFunctionType(core.List, [dart.dynamic]),
       identicalInJs: dart.definiteFunctionType(core.bool, [dart.dynamic, dart.dynamic]),
-      forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic])
+      forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dynamicAnddynamicTodynamic()])
     })
   });
   html_common.isJavaScriptDate = function(value) {
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index 6e91b7b..674993a 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -1988,6 +1988,9 @@
     return dart.noSuchMethod(obj, new dart.InvocationImpl(field, [value], {isSetter: true}));
   };
   dart._checkApply = function(type, actuals) {
+    if (type instanceof Array) {
+      type = type[0];
+    }
     if (actuals.length < type.args.length) return false;
     let index = 0;
     for (let i = 0; i < type.args.length; ++i) {
@@ -25730,13 +25733,13 @@
         this[_modifications$] = modifications;
         this[_cell$] = null;
         this[_current$2] = null;
-        this[_cell$] = collection._LinkedHashSetCell._check(dart.dload(this[_set], _first$));
+        this[_cell$] = this[_set][_first$];
       }
       get current() {
         return this[_current$2];
       }
       moveNext() {
-        if (!dart.equals(this[_modifications$], dart.dload(this[_set], _modifications$))) {
+        if (this[_modifications$] != this[_set][_modifications$]) {
           dart.throw(new core.ConcurrentModificationError(this[_set]));
         } else if (this[_cell$] == null) {
           this[_current$2] = null;
@@ -25751,9 +25754,9 @@
     dart.addTypeTests(_LinkedHashSetIterator);
     _LinkedHashSetIterator[dart.implements] = () => [IteratorOfE()];
     dart.setSignature(_LinkedHashSetIterator, {
-      constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [dart.dynamic, core.int])}),
+      constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [collection._LinkedHashSet, core.int])}),
       fields: () => ({
-        [_set]: dart.dynamic,
+        [_set]: collection._LinkedHashSet,
         [_modifications$]: core.int,
         [_cell$]: collection._LinkedHashSetCell,
         [_current$2]: E
@@ -99198,7 +99201,7 @@
       let copy = this.newJsList(length);
       this.writeSlot(slot, copy);
       for (; i < dart.notNull(length); i++) {
-        dart.dsetindex(copy, i, this.walk(e[dartx._get](i)));
+        copy[dartx._set](i, this.walk(e[dartx._get](i)));
       }
       return copy;
     }
@@ -99219,7 +99222,7 @@
       writeSlot: dart.definiteFunctionType(dart.dynamic, [core.int, dart.dynamic]),
       cleanupSlots: dart.definiteFunctionType(dart.dynamic, []),
       walk: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-      copyList: dart.definiteFunctionType(dart.dynamic, [core.List, core.int]),
+      copyList: dart.definiteFunctionType(core.List, [core.List, core.int]),
       convertDartToNative_PrepareForStructuredClone: dart.definiteFunctionType(dart.dynamic, [dart.dynamic])
     })
   });
@@ -99268,14 +99271,15 @@
         return copy;
       }
       if (dart.test(html_common.isJavaScriptArray(e))) {
-        let slot = this.findSlot(e);
+        let l = e;
+        let slot = this.findSlot(l);
         let copy = this.readSlot(slot);
         if (copy != null) return copy;
-        let length = core.int._check(dart.dload(e, 'length'));
-        copy = dart.test(this.mustCopy) ? this.newDartList(length) : e;
+        let length = l[dartx.length];
+        copy = dart.test(this.mustCopy) ? this.newDartList(length) : l;
         this.writeSlot(slot, copy);
         for (let i = 0; i < dart.notNull(length); i++) {
-          dart.dsetindex(copy, i, this.walk(dart.dindex(e, i)));
+          copy[dartx._set](i, this.walk(l[dartx._get](i)));
         }
         return copy;
       }
@@ -99436,7 +99440,7 @@
     methods: () => ({
       newJsMap: dart.definiteFunctionType(dart.dynamic, []),
       putIntoMap: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic, dart.dynamic]),
-      newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+      newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
       cloneNotRequired: dart.definiteFunctionType(core.bool, [dart.dynamic])
     })
   });
@@ -99461,10 +99465,10 @@
   };
   dart.setSignature(html_common._AcceptStructuredCloneDart2Js, {
     methods: () => ({
-      newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-      newDartList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+      newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
+      newDartList: dart.definiteFunctionType(core.List, [dart.dynamic]),
       identicalInJs: dart.definiteFunctionType(core.bool, [dart.dynamic, dart.dynamic]),
-      forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic])
+      forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dynamicAnddynamicTodynamic()])
     })
   });
   html_common.isJavaScriptDate = function(value) {
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index 9f9e9f3..8e04bfc 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -1986,6 +1986,9 @@
   return dart.noSuchMethod(obj, new dart.InvocationImpl(field, [value], {isSetter: true}));
 };
 dart._checkApply = function(type, actuals) {
+  if (type instanceof Array) {
+    type = type[0];
+  }
   if (actuals.length < type.args.length) return false;
   let index = 0;
   for (let i = 0; i < type.args.length; ++i) {
@@ -25728,13 +25731,13 @@
       this[_modifications] = modifications;
       this[_cell] = null;
       this[_current] = null;
-      this[_cell] = collection._LinkedHashSetCell._check(dart.dload(this[_set], _first));
+      this[_cell] = this[_set][_first];
     }
     get current() {
       return this[_current];
     }
     moveNext() {
-      if (!dart.equals(this[_modifications], dart.dload(this[_set], _modifications))) {
+      if (this[_modifications] != this[_set][_modifications]) {
         dart.throw(new core.ConcurrentModificationError(this[_set]));
       } else if (this[_cell] == null) {
         this[_current] = null;
@@ -25749,9 +25752,9 @@
   dart.addTypeTests(_LinkedHashSetIterator);
   _LinkedHashSetIterator[dart.implements] = () => [IteratorOfE()];
   dart.setSignature(_LinkedHashSetIterator, {
-    constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [dart.dynamic, core.int])}),
+    constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [collection._LinkedHashSet, core.int])}),
     fields: () => ({
-      [_set]: dart.dynamic,
+      [_set]: collection._LinkedHashSet,
       [_modifications]: core.int,
       [_cell]: collection._LinkedHashSetCell,
       [_current]: E
@@ -99196,7 +99199,7 @@
     let copy = this.newJsList(length);
     this.writeSlot(slot, copy);
     for (; i < dart.notNull(length); i++) {
-      dart.dsetindex(copy, i, this.walk(e[dartx._get](i)));
+      copy[dartx._set](i, this.walk(e[dartx._get](i)));
     }
     return copy;
   }
@@ -99217,7 +99220,7 @@
     writeSlot: dart.definiteFunctionType(dart.dynamic, [core.int, dart.dynamic]),
     cleanupSlots: dart.definiteFunctionType(dart.dynamic, []),
     walk: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-    copyList: dart.definiteFunctionType(dart.dynamic, [core.List, core.int]),
+    copyList: dart.definiteFunctionType(core.List, [core.List, core.int]),
     convertDartToNative_PrepareForStructuredClone: dart.definiteFunctionType(dart.dynamic, [dart.dynamic])
   })
 });
@@ -99266,14 +99269,15 @@
       return copy;
     }
     if (dart.test(html_common.isJavaScriptArray(e))) {
-      let slot = this.findSlot(e);
+      let l = e;
+      let slot = this.findSlot(l);
       let copy = this.readSlot(slot);
       if (copy != null) return copy;
-      let length = core.int._check(dart.dload(e, 'length'));
-      copy = dart.test(this.mustCopy) ? this.newDartList(length) : e;
+      let length = l[dartx.length];
+      copy = dart.test(this.mustCopy) ? this.newDartList(length) : l;
       this.writeSlot(slot, copy);
       for (let i = 0; i < dart.notNull(length); i++) {
-        dart.dsetindex(copy, i, this.walk(dart.dindex(e, i)));
+        copy[dartx._set](i, this.walk(l[dartx._get](i)));
       }
       return copy;
     }
@@ -99434,7 +99438,7 @@
   methods: () => ({
     newJsMap: dart.definiteFunctionType(dart.dynamic, []),
     putIntoMap: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic, dart.dynamic]),
-    newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+    newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
     cloneNotRequired: dart.definiteFunctionType(core.bool, [dart.dynamic])
   })
 });
@@ -99459,10 +99463,10 @@
 };
 dart.setSignature(html_common._AcceptStructuredCloneDart2Js, {
   methods: () => ({
-    newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-    newDartList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+    newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
+    newDartList: dart.definiteFunctionType(core.List, [dart.dynamic]),
     identicalInJs: dart.definiteFunctionType(core.bool, [dart.dynamic, dart.dynamic]),
-    forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic])
+    forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dynamicAnddynamicTodynamic()])
   })
 });
 html_common.isJavaScriptDate = function(value) {
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index 5d65992..295dd7f 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -1989,6 +1989,9 @@
     return dart.noSuchMethod(obj, new dart.InvocationImpl(field, [value], {isSetter: true}));
   };
   dart._checkApply = function(type, actuals) {
+    if (type instanceof Array) {
+      type = type[0];
+    }
     if (actuals.length < type.args.length) return false;
     let index = 0;
     for (let i = 0; i < type.args.length; ++i) {
@@ -25731,13 +25734,13 @@
         this[_modifications$] = modifications;
         this[_cell$] = null;
         this[_current$2] = null;
-        this[_cell$] = collection._LinkedHashSetCell._check(dart.dload(this[_set], _first$));
+        this[_cell$] = this[_set][_first$];
       }
       get current() {
         return this[_current$2];
       }
       moveNext() {
-        if (!dart.equals(this[_modifications$], dart.dload(this[_set], _modifications$))) {
+        if (this[_modifications$] != this[_set][_modifications$]) {
           dart.throw(new core.ConcurrentModificationError(this[_set]));
         } else if (this[_cell$] == null) {
           this[_current$2] = null;
@@ -25752,9 +25755,9 @@
     dart.addTypeTests(_LinkedHashSetIterator);
     _LinkedHashSetIterator[dart.implements] = () => [IteratorOfE()];
     dart.setSignature(_LinkedHashSetIterator, {
-      constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [dart.dynamic, core.int])}),
+      constructors: () => ({new: dart.definiteFunctionType(collection._LinkedHashSetIterator$(E), [collection._LinkedHashSet, core.int])}),
       fields: () => ({
-        [_set]: dart.dynamic,
+        [_set]: collection._LinkedHashSet,
         [_modifications$]: core.int,
         [_cell$]: collection._LinkedHashSetCell,
         [_current$2]: E
@@ -99199,7 +99202,7 @@
       let copy = this.newJsList(length);
       this.writeSlot(slot, copy);
       for (; i < dart.notNull(length); i++) {
-        dart.dsetindex(copy, i, this.walk(e[dartx._get](i)));
+        copy[dartx._set](i, this.walk(e[dartx._get](i)));
       }
       return copy;
     }
@@ -99220,7 +99223,7 @@
       writeSlot: dart.definiteFunctionType(dart.dynamic, [core.int, dart.dynamic]),
       cleanupSlots: dart.definiteFunctionType(dart.dynamic, []),
       walk: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-      copyList: dart.definiteFunctionType(dart.dynamic, [core.List, core.int]),
+      copyList: dart.definiteFunctionType(core.List, [core.List, core.int]),
       convertDartToNative_PrepareForStructuredClone: dart.definiteFunctionType(dart.dynamic, [dart.dynamic])
     })
   });
@@ -99269,14 +99272,15 @@
         return copy;
       }
       if (dart.test(html_common.isJavaScriptArray(e))) {
-        let slot = this.findSlot(e);
+        let l = e;
+        let slot = this.findSlot(l);
         let copy = this.readSlot(slot);
         if (copy != null) return copy;
-        let length = core.int._check(dart.dload(e, 'length'));
-        copy = dart.test(this.mustCopy) ? this.newDartList(length) : e;
+        let length = l[dartx.length];
+        copy = dart.test(this.mustCopy) ? this.newDartList(length) : l;
         this.writeSlot(slot, copy);
         for (let i = 0; i < dart.notNull(length); i++) {
-          dart.dsetindex(copy, i, this.walk(dart.dindex(e, i)));
+          copy[dartx._set](i, this.walk(l[dartx._get](i)));
         }
         return copy;
       }
@@ -99437,7 +99441,7 @@
     methods: () => ({
       newJsMap: dart.definiteFunctionType(dart.dynamic, []),
       putIntoMap: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic, dart.dynamic]),
-      newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+      newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
       cloneNotRequired: dart.definiteFunctionType(core.bool, [dart.dynamic])
     })
   });
@@ -99462,10 +99466,10 @@
   };
   dart.setSignature(html_common._AcceptStructuredCloneDart2Js, {
     methods: () => ({
-      newJsList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
-      newDartList: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
+      newJsList: dart.definiteFunctionType(core.List, [dart.dynamic]),
+      newDartList: dart.definiteFunctionType(core.List, [dart.dynamic]),
       identicalInJs: dart.definiteFunctionType(core.bool, [dart.dynamic, dart.dynamic]),
-      forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dart.dynamic])
+      forEachJsField: dart.definiteFunctionType(dart.void, [dart.dynamic, dynamicAnddynamicTodynamic()])
     })
   });
   html_common.isJavaScriptDate = function(value) {
diff --git a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
index 0c71c33..8afc764 100644
--- a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
+++ b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
Binary files differ
diff --git a/pkg/dev_compiler/lib/src/compiler/ast_builder.dart b/pkg/dev_compiler/lib/src/compiler/ast_builder.dart
index 2cbfdbf..352efdb 100644
--- a/pkg/dev_compiler/lib/src/compiler/ast_builder.dart
+++ b/pkg/dev_compiler/lib/src/compiler/ast_builder.dart
@@ -167,8 +167,6 @@
         return TokenType.INDEX;
       case "[]=":
         return TokenType.INDEX_EQ;
-      case "is":
-        return TokenType.IS;
       case "<":
         return TokenType.LT;
       case "<=":
diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
index 76292e4..a23e3e3 100644
--- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
@@ -4448,7 +4448,7 @@
       Element staticElement = identifier.staticElement;
       if (staticElement is PropertyAccessorElement && staticElement.isGetter) {
         PropertyInducingElement variable = staticElement.variable;
-        int value = variable?.constantValue?.toIntValue();
+        int value = variable?.computeConstantValue()?.toIntValue();
         if (value != null && value >= low && value <= high) return value;
       }
       return null;
diff --git a/pkg/dev_compiler/lib/src/compiler/nullable_type_inference.dart b/pkg/dev_compiler/lib/src/compiler/nullable_type_inference.dart
index 3934503..7968113 100644
--- a/pkg/dev_compiler/lib/src/compiler/nullable_type_inference.dart
+++ b/pkg/dev_compiler/lib/src/compiler/nullable_type_inference.dart
@@ -81,7 +81,8 @@
 
       if (element is PropertyAccessorElement && element.isGetter) {
         PropertyInducingElement variable = element.variable;
-        return variable.constantValue?.isNull ?? true;
+        var isVirtual = variable is FieldElement && variable.isVirtual;
+        return isVirtual || (variable.computeConstantValue()?.isNull ?? true);
       }
 
       // Other types of identifiers are nullable (parameters, fields).
diff --git a/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart b/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart
index 499cb86..c273228 100644
--- a/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart
+++ b/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart
@@ -124,7 +124,7 @@
   DartObject computeConstant(VariableDeclaration field) {
     // If the constant is already computed by ConstantEvaluator, just return it.
     VariableElement element = field.element;
-    var result = element.constantValue;
+    var result = element.computeConstantValue();
     if (result != null) return result;
 
     // ConstantEvaluator will not compute constants for non-const fields,
diff --git a/pkg/dev_compiler/test-main.js b/pkg/dev_compiler/test-main.js
index bcb70fe..829ca47 100644
--- a/pkg/dev_compiler/test-main.js
+++ b/pkg/dev_compiler/test-main.js
@@ -52,6 +52,7 @@
     expect: 'gen/codegen_output/pkg/expect',
     js: 'gen/codegen_output/pkg/js',
     matcher: 'gen/codegen_output/pkg/matcher',
+    meta: 'gen/codegen_output/pkg/meta',
     minitest: 'gen/codegen_output/pkg/minitest',
     path: 'gen/codegen_output/pkg/path',
     stack_trace: 'gen/codegen_output/pkg/stack_trace',
diff --git a/pkg/dev_compiler/test/browser/language_tests.js b/pkg/dev_compiler/test/browser/language_tests.js
index 1bf0b53..d2ad2b2 100644
--- a/pkg/dev_compiler/test/browser/language_tests.js
+++ b/pkg/dev_compiler/test/browser/language_tests.js
@@ -185,6 +185,7 @@
       'generic_instanceof2_test': fail,
       'generic_is_check_test': fail,
       'getter_closure_execution_order_test': fail,
+      'gc_test': 'slow',
       'hash_code_mangling_test': fail,
       'identical_closure2_test': fail,
       'infinite_switch_label_test': fail,
@@ -205,7 +206,7 @@
       'many_generic_instanceof_test': fail,
       'map_literal10_test': fail,
       'map_literal7_test': fail,
-      'memory_swap_test': is.firefox() ? skip_timeout : pass,
+      'memory_swap_test': skip_timeout,
       'method_invocation_test': fail,
       'mint_arithmetic_test': fail,
       'mixin_forwarding_constructor3_test': fail,
@@ -353,6 +354,9 @@
     },
 
     'lib/convert': {
+      'base64_test_01_multi': 'slow',
+      'chunked_conversion_utf85_test': 'slow',
+
       'encoding_test': skip_timeout,
 
       'json_utf8_chunk_test': skip_timeout,
@@ -690,8 +694,9 @@
         }
       };
 
-      test(name, function(done) { // 'function' to allow `this.timeout`.
-        console.debug('Running test:  ' + name);
+      var fullName = status_group + '/' + name;
+      test(fullName, function(done) { // 'function' to allow `this.timeout`.
+        console.debug('Running test:  ' + fullName);
 
         // Many tests are async.  Currently, tests can indicate this in
         // two different ways.  First, `main` can call (in Dart)
diff --git a/pkg/dev_compiler/test/not_yet_strong_tests.dart b/pkg/dev_compiler/test/not_yet_strong_tests.dart
index 715f099..c73580e 100644
--- a/pkg/dev_compiler/test/not_yet_strong_tests.dart
+++ b/pkg/dev_compiler/test/not_yet_strong_tests.dart
@@ -784,6 +784,7 @@
   'language/generic_field_mixin6_test_01_multi',
   'language/generic_field_mixin6_test_none_multi',
   'language/generic_list_checked_test',
+  'language/generic_tearoff_test',
   'language/generic_test',
   'language/generics_test',
   'language/get_set_syntax_test_00_multi',
diff --git a/pkg/dev_compiler/tool/analyze.sh b/pkg/dev_compiler/tool/analyze.sh
index cd457fc..7786289 100755
--- a/pkg/dev_compiler/tool/analyze.sh
+++ b/pkg/dev_compiler/tool/analyze.sh
@@ -15,6 +15,6 @@
 # TODO(jmesserly): ideally we could do test/all_tests.dart, but
 # dart_runtime_test.dart creates invalid generic type instantiation AA.
 echo "Running dartanalyzer to check for errors/warnings..."
-dartanalyzer --strong --package-warnings \
+dart ../analyzer_cli/bin/analyzer.dart --strong --package-warnings \
     bin/dartdevc.dart web/main.dart \
     | grep -v "\[info\]" | grep -v "\[hint\]" | (! grep $PWD) || fail
diff --git a/pkg/dev_compiler/tool/build_pkgs.dart b/pkg/dev_compiler/tool/build_pkgs.dart
index a6e2b6b..04be68b 100755
--- a/pkg/dev_compiler/tool/build_pkgs.dart
+++ b/pkg/dev_compiler/tool/build_pkgs.dart
@@ -22,9 +22,9 @@
   compileModule('async_helper');
   compileModule('expect', libs: ['minitest']);
   compileModule('js', libs: ['js_util']);
+  compileModule('meta');
   if (!test) {
     compileModule('lookup_map');
-    compileModule('meta');
     compileModule('microlytics', libs: ['html_channels']);
     compileModule('typed_mock');
   }
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/async/stream.dart b/pkg/dev_compiler/tool/input_sdk/lib/async/stream.dart
index eca6c34..d0b0d0b 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/async/stream.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/async/stream.dart
@@ -1607,7 +1607,7 @@
    * Returns the same future as [done].
    *
    * The stream sink may close before the [close] method is called, either due
-   * to an error or because it is itself provding events to someone who has
+   * to an error or because it is itself providing events to someone who has
    * stopped listening. In that case, the [done] future is completed first,
    * and the `close` method will return the `done` future when called.
    *
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions.dart b/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions.dart
index de0d423..4b2cff3 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions.dart
@@ -76,7 +76,7 @@
   cleanupSlots() {}  // Will be needed if we mark objects with a property.
   bool cloneNotRequired(object);
   newJsMap();
-  newJsList(length);
+  List newJsList(length);
   void putIntoMap(map, key, value);
 
   // Returns the input, or a clone of the input.
@@ -127,7 +127,7 @@
       // non-native properties or methods from interceptors and such, e.g.
       // an immutability marker. So we  had to stop doing that.
       var slot = findSlot(e);
-      var copy = readSlot(slot);
+      var copy = JS('List', '#', readSlot(slot));
       if (copy != null) return copy;
       copy = copyList(e, slot);
       return copy;
@@ -136,7 +136,7 @@
     throw new UnimplementedError('structured clone of other type');
   }
 
-  copyList(List e, int slot) {
+  List copyList(List e, int slot) {
     int i = 0;
     int length = e.length;
     var copy = newJsList(length);
@@ -196,11 +196,11 @@
   writeSlot(int i, x) { copies[i] = x; }
 
   /// Iterate over the JS properties.
-  forEachJsField(object, action);
+  forEachJsField(object, action(key, value));
 
   /// Create a new Dart list of the given length. May create a native List or
   /// a JsArray, depending if we're in Dartium or dart2js.
-  newDartList(length);
+  List newDartList(length);
 
   walk(e) {
     if (e == null) return e;
@@ -235,18 +235,19 @@
     }
 
     if (isJavaScriptArray(e)) {
-      var slot = findSlot(e);
-      var copy = readSlot(slot);
+      var l = JS('List', '#', e);
+      var slot = findSlot(l);
+      var copy = JS('List', '#', readSlot(slot));
       if (copy != null) return copy;
 
-      int length = e.length;
+      int length = l.length;
       // Since a JavaScript Array is an instance of Dart List, we can modify it
       // in-place unless we must copy.
-      copy = mustCopy ? newDartList(length) : e;
+      copy = mustCopy ? newDartList(length) : l;
       writeSlot(slot, copy);
 
       for (int i = 0; i < length; i++) {
-        copy[i] = walk(e[i]);
+        copy[i] = walk(l[i]);
       }
       return copy;
     }
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions_dart2js.dart b/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions_dart2js.dart
index b5a1064..3cab380 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/html/html_common/conversions_dart2js.dart
@@ -60,11 +60,11 @@
 
 class _AcceptStructuredCloneDart2Js extends _AcceptStructuredClone {
 
-  newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length);
-  newDartList(length) => newJsList(length);
-  identicalInJs(a, b) => identical(a, b);
+  List newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length);
+  List newDartList(length) => newJsList(length);
+  bool identicalInJs(a, b) => identical(a, b);
 
-  void forEachJsField(object, action) {
+  void forEachJsField(object, action(key, value)) {
       for (final key in JS('JSExtendableArray', 'Object.keys(#)', object)) {
         action(key, JS('var', '#[#]', object, key));
       }
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/io/file.dart b/pkg/dev_compiler/tool/input_sdk/lib/io/file.dart
index 4ac4486..de526ed 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/io/file.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/io/file.dart
@@ -582,7 +582,7 @@
    * bytes will be filled into [buffer] from at index [start], otherwise index
    * 0. If [end] is present, the [end] - [start] bytes will be read into
    * [buffer], otherwise up to [buffer.length]. If [end] == [start] nothing
-   * happends.
+   * happens.
    *
    * Returns a [:Future<int>:] that completes with the number of bytes read.
    */
@@ -593,7 +593,7 @@
    * present, the bytes will be filled into [buffer] from at index [start],
    * otherwise index 0.  If [end] is present, the [end] - [start] bytes will be
    * read into [buffer], otherwise up to [buffer.length]. If [end] == [start]
-   * nothing happends.
+   * nothing happens.
    *
    * Throws a [FileSystemException] if the operation fails.
    */
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/io/file_system_entity.dart b/pkg/dev_compiler/tool/input_sdk/lib/io/file_system_entity.dart
index f39eafd..d197949 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/io/file_system_entity.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/io/file_system_entity.dart
@@ -433,7 +433,7 @@
    * being listened to, not when the call to [watch] is issued.
    *
    * The returned value is an endless broadcast [Stream], that only stops when
-   * one of the following happends:
+   * one of the following happens:
    *
    *   * The [Stream] is canceled, e.g. by calling `cancel` on the
    *      [StreamSubscription].
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart b/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart
index 5eb96ce..adef61f 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/io/http_parser.dart
@@ -1038,7 +1038,7 @@
   }
 
   void _closeIncoming([bool closing = false]) {
-    // Ignore multiple close (can happend in re-entrance).
+    // Ignore multiple close (can happen in re-entrance).
     if (_incoming == null) return;
     var tmp = _incoming;
     tmp.close(closing);
diff --git a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
index c8a2c7e..7fccdc3 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
@@ -1606,7 +1606,7 @@
 
 // TODO(kasperl): Share this code with LinkedHashMapKeyIterator<E>?
 class _LinkedHashSetIterator<E> implements Iterator<E> {
-  final _set;
+  final _LinkedHashSet _set;
   final int _modifications;
   _LinkedHashSetCell _cell;
   E _current;
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index 68d8fd0..6f4236c 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -137,6 +137,11 @@
 _checkApply(type, actuals) => JS(
     '',
     '''(() => {
+  // TODO(vsm): Remove when we no longer need mirrors metadata.
+  // An array is used to encode annotations attached to the type.
+  if ($type instanceof Array) {
+    $type = type[0];
+  }
   if ($actuals.length < $type.args.length) return false;
   let index = 0;
   for(let i = 0; i < $type.args.length; ++i) {
diff --git a/pkg/front_end/.analysis_options b/pkg/front_end/.analysis_options
index f0ac32f..61936d8 100644
--- a/pkg/front_end/.analysis_options
+++ b/pkg/front_end/.analysis_options
@@ -2,3 +2,22 @@
   strong-mode: true
   language:
     enableSuperMixins: true
+  exclude:
+    # TODO(devoncarew): Without this exclude I see ~400 analysis errors.
+    - test/fasta/**
+  errors:
+    # Omits warnings due to missing `@virtual`
+    # TODO(sigmund): enable once #28601 is fixed
+    strong_mode_invalid_field_override: ignore
+
+    # Omits warnings for implicit casts with generics like `List<T> x = list;`,
+    # also removes warnings due to a bad interaction between inference of
+    # guarded type arguments and downward cast warnings (see #28646).
+    strong_mode_down_cast_composite: ignore
+
+    # Allow having TODOs in the code
+    todo: ignore
+
+    # Allow deprecated calls (although it would be nice to have a distinction
+    # between internal and external deprecated calls).
+    deprecated_member_use: ignore
diff --git a/pkg/front_end/front_end.iml b/pkg/front_end/front_end.iml
new file mode 100644
index 0000000..58263b3
--- /dev/null
+++ b/pkg/front_end/front_end.iml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.pub" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/fasta/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/fasta/parser/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/fasta/rasta/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/fasta/scanner/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/base/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/test/src/packages" />
+      <excludeFolder url="file://$MODULE_DIR$/tool/packages" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Dart SDK" level="application" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/pkg/front_end/lib/compiler_options.dart b/pkg/front_end/lib/compiler_options.dart
index 731344c..8653baa 100644
--- a/pkg/front_end/lib/compiler_options.dart
+++ b/pkg/front_end/lib/compiler_options.dart
@@ -8,7 +8,7 @@
 import 'file_system.dart';
 import 'physical_file_system.dart';
 
-/// Default error handler used by [CompielerOptions.onError].
+/// Default error handler used by [CompilerOptions.onError].
 void defaultErrorHandler(CompilationError error) => throw error;
 
 /// Callback used to report errors encountered during compilation.
@@ -85,14 +85,6 @@
   /// generated files.
   List<Uri> multiRoots = [];
 
-  /// Sets the platform bit, which determines which patch files should be
-  /// applied to the SDK.
-  ///
-  /// The value should be a power of two, and should match the `PLATFORM` bit
-  /// flags in sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart.  If
-  /// zero, no patch files will be applied.
-  int platformBit;
-
   /// The declared variables for use by configurable imports and constant
   /// evaluation.
   Map<String, String> declaredVariables;
@@ -120,6 +112,25 @@
   /// not described in a summary as if it was explictly listed as an input.
   bool chaseDependencies = false;
 
-  /// Whether to intepret Dart sources in strong-mode.
+  /// Whether to interpret Dart sources in strong-mode.
   bool strongMode = true;
+
+  // All options below are target-specific options.
+  //
+  // TODO(sigmund): revisit the right layout for these options. We might want to
+  // split them out into a separate bag of options or provide factories for
+  // common combinations of these options.
+
+  /// Patch files to apply on the core libraries for a specific target platform.
+  ///
+  /// Keys on this map are expected to be `dart:*` URIs. The values can be
+  /// either absolute or relative URIs. Absolute URIs are read directly, while
+  /// relative URIs are resolved from the [sdkRoot].
+  Map<Uri, List<Uri>> targetPatches = {};
+
+  /// Additional core libraries to be loaded when building a program.
+  // TODO(sigmund): delete. Ideally building a program only needs what's
+  // reachable and we can use kernelForBuildUnit when creating a snapshot of the
+  // SDK itself.
+  List<Uri> additionalLibraries = [];
 }
diff --git a/pkg/front_end/lib/incremental_resolved_ast_generator.dart b/pkg/front_end/lib/incremental_resolved_ast_generator.dart
index dd5e4c7..daeb8c1 100644
--- a/pkg/front_end/lib/incremental_resolved_ast_generator.dart
+++ b/pkg/front_end/lib/incremental_resolved_ast_generator.dart
@@ -4,9 +4,9 @@
 
 import 'dart:async';
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:front_end/src/base/processed_options.dart';
 import 'package:front_end/src/incremental_resolved_ast_generator_impl.dart';
-import 'package:analyzer/dart/ast/ast.dart';
 
 import 'compiler_options.dart';
 
@@ -14,27 +14,19 @@
 ///
 /// Not intended to be implemented or extended by clients.
 class DeltaLibraries {
-  /// The new state of the program, as a map from Uri to [ResolvedLibrary].
+  /// The new state of the program, as a two-layer map.
+  ///
+  /// The outer map key is the library URI.  The inner map key is the
+  /// compilation unit (part) URI.  The map values are the resolved compilation
+  /// units.
   ///
   /// Libraries whose resolved AST is known to be unchanged since the last
   /// [DeltaLibraries] are not included.
-  final Map<Uri, ResolvedLibrary> newState;
+  final Map<Uri, Map<Uri, CompilationUnit>> newState;
 
   DeltaLibraries(this.newState);
 
-/// TODO(paulberry): add information about libraries that were removed.
-}
-
-/// Represents the resolved ASTs for all the compilation units in a single
-/// library.
-///
-/// Not intended to be implemented or extended by clients.
-class ResolvedLibrary {
-  final CompilationUnit definingCompilationUnit;
-
-  final Map<Uri, CompilationUnit> partUnits;
-
-  ResolvedLibrary(this.definingCompilationUnit, this.partUnits);
+  /// TODO(paulberry): add information about libraries that were removed.
 }
 
 /// Interface for generating an initial resolved representation of a program and
@@ -67,8 +59,10 @@
   /// "previous program state" is an empty program containing no code, and the
   /// initial set of valid sources is empty.  To obtain a resolved AST
   /// representation of the program, call [computeDelta].
-  factory IncrementalResolvedAstGenerator(Uri source, CompilerOptions options) =>
-      new IncrementalResolvedAstGeneratorImpl(source, new ProcessedOptions(options));
+  factory IncrementalResolvedAstGenerator(
+          Uri source, CompilerOptions options) =>
+      new IncrementalResolvedAstGeneratorImpl(
+          source, new ProcessedOptions(options));
 
   /// Generates a resolved AST representation of the changes to the program,
   /// assuming that all valid sources are unchanged since the last call to
diff --git a/pkg/front_end/lib/kernel_generator.dart b/pkg/front_end/lib/kernel_generator.dart
index 348d1f9..b76b54a 100644
--- a/pkg/front_end/lib/kernel_generator.dart
+++ b/pkg/front_end/lib/kernel_generator.dart
@@ -10,6 +10,7 @@
 import 'dart:async';
 
 import 'package:analyzer/src/generated/source.dart' show SourceKind;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/summary/package_bundle_reader.dart'
     show InSummarySource;
 // TODO(sigmund): move loader logic under front_end/lib/src/kernel/
@@ -37,6 +38,11 @@
 /// needed to access the contents of method bodies).
 Future<Program> kernelForProgram(Uri source, CompilerOptions options) async {
   var loader = await _createLoader(options, entry: source);
+
+  if (options.compileSdk) {
+    options.additionalLibraries.forEach(loader.loadLibrary);
+  }
+
   // TODO(sigmund): merge what we have in loadEverything and the logic below in
   // kernelForBuildUnit so there is a single place where we crawl for
   // dependencies.
@@ -131,8 +137,21 @@
   var packages = await createPackages(
       _uriToPath(options.packagesFileUri, options),
       discoveryPath: entry?.path);
-  return new DartLoader(
+  var loader = new DartLoader(
       repository ?? new Repository(), kernelOptions, packages);
+  var patchPaths = <String, List<String>>{};
+
+  // TODO(sigmund,paulberry): use ProcessedOptions so that we can resolve the
+  // URIs correctly even if sdkRoot is inferred and not specified explicitly.
+  String resolve(Uri patch) =>
+    options.fileSystem.context.fromUri(options.sdkRoot.resolveUri(patch));
+
+  options.targetPatches.forEach((uri, patches) {
+    patchPaths['$uri'] = patches.map(resolve).toList();
+  });
+  AnalysisOptionsImpl analysisOptions = loader.context.analysisOptions;
+  analysisOptions.patchPaths = patchPaths;
+  return loader;
 }
 
 DartOptions _convertOptions(CompilerOptions options) {
@@ -144,6 +163,7 @@
       sdkSummary:
           options.compileSdk ? null : _uriToPath(options.sdkSummary, options),
       packagePath: _uriToPath(options.packagesFileUri, options),
+      customUriMappings: options.uriOverride,
       declaredVariables: options.declaredVariables);
 }
 
@@ -157,7 +177,7 @@
 String _uriToPath(Uri uri, CompilerOptions options) {
   if (uri == null) return null;
   if (uri.scheme != 'file') {
-    throw new StateError('Only file URIs are supported');
+    throw new StateError('Only file URIs are supported: $uri');
   }
   return options.fileSystem.context.fromUri(uri);
 }
diff --git a/pkg/front_end/lib/src/base/resolve_relative_uri.dart b/pkg/front_end/lib/src/base/resolve_relative_uri.dart
new file mode 100644
index 0000000..cafcbf2
--- /dev/null
+++ b/pkg/front_end/lib/src/base/resolve_relative_uri.dart
@@ -0,0 +1,27 @@
+// 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.
+
+/**
+ * Resolve the [containedUri] against [baseUri] using Dart rules.
+ *
+ * This function behaves similarly to [Uri.resolveUri], except that it properly
+ * handles situations like the following:
+ *
+ *     resolveRelativeUri(dart:core, bool.dart) -> dart:core/bool.dart
+ *     resolveRelativeUri(package:a/b.dart, ../c.dart) -> package:a/c.dart
+ */
+Uri resolveRelativeUri(Uri baseUri, Uri containedUri) {
+  if (containedUri.isAbsolute) {
+    return containedUri;
+  }
+  String scheme = baseUri.scheme;
+  // dart:core => dart:core/core.dart
+  if (scheme == 'dart') {
+    String part = baseUri.path;
+    if (part.indexOf('/') < 0) {
+      baseUri = Uri.parse('$scheme:$part/$part.dart');
+    }
+  }
+  return baseUri.resolveUri(containedUri);
+}
diff --git a/pkg/front_end/lib/src/fasta/README.md b/pkg/front_end/lib/src/fasta/README.md
new file mode 100644
index 0000000..35bfd22
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/README.md
@@ -0,0 +1,108 @@
+<!--
+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.
+-->
+# Fasta -- Fully-resolved AST, Accelerated.
+
+Fasta is a compiler framework for compiling Dart sources to Kernel IR. When Fasta works well, you won't even know you're using it, as it will be transparently integrated in tools like *dart*, *dartanalyzer*, *dart2js*, etc.
+
+Hopefully, you'll notice that Fasta-based tools are fast, with good error messages. If not, please let us [know](https://github.com/dart-lang/sdk/issues/new).
+
+Fasta sounds like faster, and that's a promise we intend to keep.
+
+## Getting Started
+
+1. [Build](https://github.com/dart-lang/sdk/wiki/Building#building) the VM and patched SDK. Note: you only need to build the target `runtime`, so you only need to run this command:
+
+```bash
+./tools/build.py --mode release --arch x64 runtime
+```
+
+Make sure to define these environment variables, for example, by adding them to `~/.bashrc`:
+
+```bash
+# Linux
+DART_SDK=<Location of Dart SDK source check out>
+export DART_AOT_VM=${DART_SDK}/out/ReleaseIA32/dart
+export DART_AOT_SDK=${DART_SDK}/out/ReleaseIA32/patched_sdk
+```
+
+```bash
+# Mac OS X
+DART_SDK=<Location of Dart SDK source check out>
+export DART_AOT_VM=${DART_SDK}/xcodebuild/ReleaseIA32/dart
+export DART_AOT_SDK=${DART_SDK}/xcodebuild/ReleaseIA32/patched_sdk
+```
+
+If you want to help us translate these instructions to another OS, please let us [know](https://github.com/dart-lang/sdk/issues/new).
+
+## Create an Outline File
+
+1. Run `dart pkg/front_end/lib/src/fasta/bin/outline.dart pkg/compiler/lib/src/dart2js.dart`
+
+2. Optionally, run `dart pkg/kernel/bin/dartk.dart pkg/compiler/lib/src/dart2js.dart.dill` to view the generated outline.
+
+This will generate a file named `pkg/compiler/lib/src/dart2js.dart.dill` which contains a serialized reprsentation of the input program excluding method bodies. This is similar to an analyzer summary.
+
+
+## Create a Platform Dill File
+
+A `platform.dill` is a dill file that contains the Dart SDK platform libraries. For now, this is generated with dartk until fasta reaches a higher rate of test passes.
+
+```bash
+dart pkg/front_end/lib/src/fasta/bin/compile_platform.dart platform.dill
+```
+
+Make sure to define `$DART_AOT_SDK` as described [above](#Building-The-Dart-SDK).
+
+## Compiling a Program
+
+```bash
+dart pkg/front_end/lib/src/fasta/bin/compile.dart pkg/front_end/test/fasta/hello.dart
+```
+
+This will generate `pkg/front_end/test/fasta/hello.dart.dill` which can be run this way:
+
+```bash
+$DART_AOT_VM pkg/front_end/test/fasta/hello.dart.dill
+```
+
+Where `$DART_AOT_VM` is defined as described [above](#Building-The-Dart-SDK).
+
+### Using dartk and the Analyzer AST
+
+```bash
+dart pkg/front_end/lib/src/fasta/bin/kompile.dart pkg/front_end/test/fasta/hello.dart
+```
+
+This will generate `pkg/front_end/test/fasta/hello.dart.dill` which can be run this way:
+
+```bash
+$DART_AOT_VM pkg/front_end/test/fasta/hello.dart.dill
+```
+
+Where `$DART_AOT_VM` is defined as described [above](#Building-The-Dart-SDK).
+
+## Running Tests
+
+Run:
+
+```bash
+dart -c pkg/testing/bin/testing.dart --config=pkg/front_end/test/fasta/testing.json
+```
+
+## Running dart2js
+
+```bash
+dart pkg/front_end/lib/src/fasta/bin/compile.dart pkg/compiler/lib/src/dart2js.dart
+$DART_AOT_VM pkg/compiler/lib/src/dart2js.dart.dill pkg/front_end/test/fasta/hello.dart
+```
+
+The output of dart2js will be `out.js`, and it can be run on any Javascript engine, for example, d8 which is included with the Dart SDK sources:
+
+```
+./third_party/d8/<OS>/d8 out.js
+```
+
+Where `<OS>` is one of `linux`, `macos`, or `windows`.
diff --git a/pkg/front_end/lib/src/fasta/analyzer/README.md b/pkg/front_end/lib/src/fasta/analyzer/README.md
new file mode 100644
index 0000000..5dcf867
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/README.md
@@ -0,0 +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 file.
+-->
+# Analyzer Integration
+
+Generates [Analyzer](https://pub.dartlang.org/packages/analyzer) abstract syntax trees (AST) and element model.
diff --git a/pkg/front_end/lib/src/fasta/analyzer/analyzer.dart b/pkg/front_end/lib/src/fasta/analyzer/analyzer.dart
new file mode 100644
index 0000000..c673913
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/analyzer.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer;
+
+import 'package:analyzer/analyzer.dart' show
+    AstNode;
+
+import 'package:analyzer/dart/element/element.dart' show
+    LocalElement;
+
+import 'package:kernel/analyzer/ast_from_analyzer.dart' show
+    ExpressionScope;
+
+import 'package:kernel/ast.dart' show
+    Library,
+    TreeNode;
+
+import '../builder/scope.dart' show
+    Scope;
+
+import '../kernel/kernel_builder.dart' show
+    Builder,
+    KernelFormalParameterBuilder;
+
+import 'element_store.dart' show
+    ElementStore;
+
+export 'ast_builder.dart' show
+    AstBuilder;
+
+export 'element_store.dart' show
+    ElementStore;
+
+TreeNode toKernel(AstNode node, ElementStore store, Library library,
+    Scope scope) {
+  ExpressionScope expressionScope = new ExpressionScope(store, library);
+  scope.local.forEach((String name, Builder builder) {
+    if (builder is KernelFormalParameterBuilder) {
+      LocalElement local = store[builder];
+      assert(local != null);
+      assert(builder.declaration != null);
+      expressionScope.localVariables[local] = builder.declaration;
+    }
+  });
+  return expressionScope.buildStatement(node);
+}
diff --git a/pkg/front_end/lib/src/fasta/analyzer/ast_builder.dart b/pkg/front_end/lib/src/fasta/analyzer/ast_builder.dart
new file mode 100644
index 0000000..505af9f
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/ast_builder.dart
@@ -0,0 +1,597 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer.ast_builder;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    BeginGroupToken,
+    Token;
+
+import 'package:analyzer/analyzer.dart';
+
+import 'package:analyzer/dart/ast/token.dart' as analyzer show
+    Token;
+
+import 'package:analyzer/dart/element/element.dart' show
+    Element;
+
+import 'package:analyzer/dart/ast/ast_factory.dart' show
+    AstFactory;
+
+import 'package:analyzer/dart/ast/standard_ast_factory.dart' as standard;
+
+import '../errors.dart' show
+    internalError;
+
+import '../source/scope_listener.dart' show
+    JumpTargetKind,
+    NullValue,
+    Scope,
+    ScopeListener;
+
+import '../kernel/kernel_builder.dart' show
+    Builder,
+    KernelLibraryBuilder,
+    ProcedureBuilder;
+
+import '../quote.dart';
+
+import '../source/outline_builder.dart' show
+    asyncMarkerFromTokens;
+
+import 'element_store.dart' show
+    AnalyzerLocalVariableElemment,
+    AnalyzerParameterElement,
+    ElementStore,
+    KernelClassElement;
+
+import 'token_utils.dart' show
+    toAnalyzerToken;
+
+import 'analyzer.dart' show
+    toKernel;
+
+class AstBuilder extends ScopeListener {
+  final AstFactory ast = standard.astFactory;
+
+  final KernelLibraryBuilder library;
+
+  final Builder member;
+
+  final ElementStore elementStore;
+
+  bool isFirstIdentifier = false;
+
+  AstBuilder(this.library, this.member, this.elementStore, Scope scope)
+      : super(scope);
+
+  Uri get uri => library.fileUri ?? library.uri;
+
+  createJumpTarget(JumpTargetKind kind, int charOffset) {
+    // TODO(ahe): Implement jump targets.
+    return null;
+  }
+
+  void beginLiteralString(Token token) {
+    debugEvent("beginLiteralString");
+    push(token);
+  }
+
+  void handleStringPart(Token token) {
+    debugEvent("StringPart");
+    push(token);
+  }
+
+  void doStringPart(Token token) {
+    push(ast.simpleStringLiteral(toAnalyzerToken(token), token.value));
+  }
+
+  void endLiteralString(int interpolationCount) {
+    debugEvent("endLiteralString");
+    if (interpolationCount == 0) {
+      Token token = pop();
+      String value = unescapeString(token.value);
+      push(ast.simpleStringLiteral(toAnalyzerToken(token), value));
+    } else {
+      List parts = popList(1 + interpolationCount * 2);
+      Token first = parts.first;
+      Token last = parts.last;
+      Quote quote = analyzeQuote(first.value);
+      List<InterpolationElement> elements = <InterpolationElement>[];
+      elements.add(ast.interpolationString(
+              toAnalyzerToken(first),
+              unescapeFirstStringPart(first.value, quote)));
+      for (int i = 1; i < parts.length - 1; i++) {
+        var part = parts[i];
+        if (part is Token) {
+          elements.add(ast.interpolationString(
+                  toAnalyzerToken(part), part.value));
+        } else if (part is Expression) {
+          elements.add(ast.interpolationExpression(null, part, null));
+        } else {
+          internalError(
+              "Unexpected part in string interpolation: ${part.runtimeType}");
+        }
+      }
+      elements.add(ast.interpolationString(toAnalyzerToken(last),
+              unescapeLastStringPart(last.value, quote)));
+      push(ast.stringInterpolation(elements));
+    }
+  }
+
+  void handleStringJuxtaposition(int literalCount) {
+    debugEvent("StringJuxtaposition");
+    push(ast.adjacentStrings(popList(literalCount)));
+  }
+
+  void endArguments(int count, Token beginToken, Token endToken) {
+    debugEvent("Arguments");
+    List expressions = popList(count);
+    ArgumentList arguments = ast.argumentList(toAnalyzerToken(beginToken),
+        expressions, toAnalyzerToken(endToken));
+    push(ast.methodInvocation(null, null, null, null, arguments));
+  }
+
+  void beginExpression(Token token) {
+    isFirstIdentifier = true;
+  }
+
+  void handleIdentifier(Token token) {
+    debugEvent("handleIdentifier");
+    String name = token.value;
+    SimpleIdentifier identifier = ast.simpleIdentifier(toAnalyzerToken(token));
+    if (isFirstIdentifier) {
+      Builder builder = scope.lookup(name, token.charOffset, uri);
+      if (builder != null) {
+        Element element = elementStore[builder];
+        assert(element != null);
+        identifier.staticElement = element;
+      }
+    }
+    push(identifier);
+    isFirstIdentifier = false;
+  }
+
+  void endSend(Token token) {
+    debugEvent("Send");
+    MethodInvocation arguments = pop();
+    TypeArgumentList typeArguments = pop();
+    if (arguments != null) {
+      if (typeArguments != null) {
+        arguments.typeArguments = typeArguments;
+      }
+      doInvocation(token, arguments);
+    } else {
+      doPropertyGet(token);
+    }
+  }
+
+  void doInvocation(Token token, MethodInvocation arguments) {
+    Expression receiver = pop();
+    if (receiver is SimpleIdentifier) {
+      arguments.methodName = receiver;
+      push(arguments);
+    } else {
+      internalError("Unhandled receiver in send: ${receiver.runtimeType}");
+    }
+  }
+
+  void doPropertyGet(Token token) {
+  }
+
+  void endExpressionStatement(Token token) {
+    debugEvent("ExpressionStatement");
+    push(ast.expressionStatement(pop(), toAnalyzerToken(token)));
+  }
+
+  void endFunctionBody(int count, Token beginToken, Token endToken) {
+    debugEvent("FunctionBody");
+    List statements = popList(count);
+    if (beginToken != null) {
+      exitLocalScope();
+    }
+    push(ast.block(toAnalyzerToken(beginToken), statements,
+            toAnalyzerToken(endToken)));
+  }
+
+  void finishFunction(formals, asyncModifier, Statement body) {
+    debugEvent("finishFunction");
+    var kernel = toKernel(body, elementStore, library.library, scope);
+    if (member is ProcedureBuilder) {
+      ProcedureBuilder builder = member;
+      builder.body = kernel;
+    } else {
+      internalError("Internal error: expected procedure, but got: $member");
+    }
+  }
+
+  void beginCascade(Token token) {
+    debugEvent("beginCascade");
+    Expression expression = pop();
+    push(token);
+    if (expression is CascadeExpression) {
+      push(expression);
+    } else {
+      push(ast.cascadeExpression(expression, <Expression>[]));
+    }
+    push(NullValue.CascadeReceiver);
+  }
+
+  void endCascade() {
+    debugEvent("Cascade");
+    Expression expression = pop();
+    CascadeExpression receiver = pop();
+    pop(); // Token.
+    receiver.cascadeSections.add(expression);
+    push(receiver);
+  }
+
+  void handleBinaryExpression(Token token) {
+    debugEvent("BinaryExpression");
+    if (identical(".", token.stringValue) ||
+        identical("..", token.stringValue)) {
+      doDotExpression(token);
+    } else {
+      Expression right = pop();
+      Expression left = pop();
+      push(ast.binaryExpression(left, toAnalyzerToken(token), right));
+    }
+  }
+
+  void doDotExpression(Token token) {
+    Expression identifierOrInvoke = pop();
+    Expression receiver = pop();
+    if (identifierOrInvoke is SimpleIdentifier) {
+      push(ast.propertyAccess(receiver, toAnalyzerToken(token),
+              identifierOrInvoke));
+    } else if (identifierOrInvoke is MethodInvocation) {
+      assert(identifierOrInvoke.target == null);
+      identifierOrInvoke
+          ..target = receiver
+          ..operator = toAnalyzerToken(token);
+      push(identifierOrInvoke);
+    } else {
+      internalError(
+          "Unhandled property access: ${identifierOrInvoke.runtimeType}");
+    }
+  }
+
+  void handleLiteralInt(Token token) {
+    debugEvent("LiteralInt");
+    push(ast.integerLiteral(toAnalyzerToken(token), int.parse(token.value)));
+  }
+
+  void endReturnStatement(
+      bool hasExpression, Token beginToken, Token endToken) {
+    debugEvent("ReturnStatement");
+    Expression expression = hasExpression ? pop() : null;
+    push(ast.returnStatement(toAnalyzerToken(beginToken), expression,
+            toAnalyzerToken(endToken)));
+  }
+
+  void endIfStatement(Token ifToken, Token elseToken) {
+    Statement elsePart = popIfNotNull(elseToken);
+    Statement thenPart = pop();
+    Expression condition = pop();
+    BeginGroupToken leftParenthesis = ifToken.next;
+    push(ast.ifStatement(
+            toAnalyzerToken(ifToken), toAnalyzerToken(ifToken.next), condition,
+            toAnalyzerToken(leftParenthesis.endGroup), thenPart,
+            toAnalyzerToken(elseToken), elsePart));
+  }
+
+  void prepareInitializers() {
+    debugEvent("prepareInitializers");
+  }
+
+  void handleNoInitializers() {
+    debugEvent("NoInitializers");
+  }
+
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    debugEvent("Initializers");
+    popList(count);
+  }
+
+  void endVariableInitializer(Token assignmentOperator) {
+    debugEvent("VariableInitializer");
+    assert(assignmentOperator.stringValue == "=");
+    Expression initializer = pop();
+    Identifier identifier = pop();
+    // TODO(ahe): Don't push initializers, instead install them.
+    push(ast.variableDeclaration(
+            identifier, toAnalyzerToken(assignmentOperator), initializer));
+  }
+
+  void endInitializedIdentifier() {
+    debugEvent("InitializedIdentifier");
+    AstNode node = pop();
+    VariableDeclaration variable;
+    if (node is VariableDeclaration) {
+      variable = node;
+    } else if (node is SimpleIdentifier) {
+      variable = ast.variableDeclaration(node, null, null);
+    } else {
+      internalError("unhandled identifier: ${node.runtimeType}");
+    }
+    push(variable);
+    scope[variable.name.name] = variable.name.staticElement =
+        new AnalyzerLocalVariableElemment(variable);
+  }
+
+  void endVariablesDeclaration(int count, Token endToken) {
+    debugEvent("VariablesDeclaration");
+    List<VariableDeclaration> variables = popList(count);
+    TypeName type = pop();
+    pop(); // Modifiers.
+    push(ast.variableDeclarationStatement(
+            ast.variableDeclarationList(null, null, null, type, variables),
+            toAnalyzerToken(endToken)));
+  }
+
+  void handleAssignmentExpression(Token token) {
+    debugEvent("AssignmentExpression");
+    Expression rhs = pop();
+    Expression lhs = pop();
+    push(ast.assignmentExpression(lhs, toAnalyzerToken(token), rhs));
+  }
+
+  void endBlock(int count, Token beginToken, Token endToken) {
+    debugEvent("Block");
+    List<Statement> statements = popList(count) ?? <Statement>[];
+    exitLocalScope();
+    push(ast.block(toAnalyzerToken(beginToken), statements,
+            toAnalyzerToken(endToken)));
+  }
+
+  void endForStatement(
+      int updateExpressionCount, Token beginToken, Token endToken) {
+    debugEvent("ForStatement");
+    Statement body = pop();
+    List<Expression> updates = popList(updateExpressionCount);
+    ExpressionStatement condition = pop();
+    VariableDeclarationStatement variables = pop();
+    exitContinueTarget();
+    exitBreakTarget();
+    exitLocalScope();
+    BeginGroupToken leftParenthesis = beginToken.next;
+    push(ast.forStatement(
+            toAnalyzerToken(beginToken),
+            toAnalyzerToken(leftParenthesis),
+            variables?.variables,
+            null, // initialization.
+            variables?.semicolon,
+            condition.expression,
+            condition.semicolon,
+            updates,
+            toAnalyzerToken(leftParenthesis.endGroup),
+            body));
+  }
+
+  void handleLiteralList(
+      int count, Token beginToken, Token constKeyword, Token endToken) {
+    debugEvent("LiteralList");
+    List<Expression> expressions = popList(count);
+    TypeArgumentList typeArguments = pop();
+    push(ast.listLiteral(
+            toAnalyzerToken(constKeyword),
+            typeArguments,
+            toAnalyzerToken(beginToken),
+            expressions,
+            toAnalyzerToken(endToken)));
+  }
+
+  void handleAsyncModifier(Token asyncToken, Token starToken) {
+    debugEvent("AsyncModifier");
+    push(asyncMarkerFromTokens(asyncToken, starToken));
+  }
+
+  void endAwaitExpression(Token beginToken, Token endToken) {
+    debugEvent("AwaitExpression");
+    push(ast.awaitExpression(toAnalyzerToken(beginToken), pop()));
+  }
+
+  void beginLiteralSymbol(Token token) {
+    isFirstIdentifier = false;
+  }
+
+  void handleLiteralBool(Token token) {
+    debugEvent("LiteralBool");
+    bool value = identical(token.stringValue, "true");
+    assert(value || identical(token.stringValue, "false"));
+    push(ast.booleanLiteral(toAnalyzerToken(token), value));
+  }
+
+  void handleLiteralDouble(Token token) {
+    debugEvent("LiteralDouble");
+    push(ast.doubleLiteral(toAnalyzerToken(token), double.parse(token.value)));
+  }
+
+  void handleLiteralNull(Token token) {
+    debugEvent("LiteralNull");
+    push(ast.nullLiteral(toAnalyzerToken(token)));
+  }
+
+  void handleLiteralMap(
+      int count, Token beginToken, Token constKeyword, Token endToken) {
+    debugEvent("LiteralMap");
+    List<MapLiteralEntry> entries = popList(count) ?? <MapLiteralEntry>[];
+    TypeArgumentList typeArguments = pop();
+    push(ast.mapLiteral(toAnalyzerToken(constKeyword), typeArguments,
+            toAnalyzerToken(beginToken), entries, toAnalyzerToken(endToken)));
+  }
+
+  void endLiteralMapEntry(Token colon, Token endToken) {
+    debugEvent("LiteralMapEntry");
+    Expression value = pop();
+    Expression key = pop();
+    push(ast.mapLiteralEntry(key, toAnalyzerToken(colon), value));
+  }
+
+  void endLiteralSymbol(Token hashToken, int identifierCount) {
+    debugEvent("LiteralSymbol");
+    List<analyzer.Token> components = new List<analyzer.Token>(identifierCount);
+    for (int i = identifierCount - 1; i >= 0; i--) {
+      SimpleIdentifier identifier = pop();
+      components[i] = identifier.token;
+    }
+    push(ast.symbolLiteral(toAnalyzerToken(hashToken), components));
+  }
+
+  void endType(Token beginToken, Token endToken) {
+    debugEvent("Type");
+    TypeArgumentList arguments = pop();
+    SimpleIdentifier name = pop();
+    KernelClassElement cls = name.staticElement;
+    if (cls == null) {
+      Builder builder = scope.lookup(name.name, beginToken.charOffset, uri);
+      if (builder == null) {
+        internalError("Undefined name: $name");
+      }
+      // TODO(paulberry,ahe): what if the type doesn't resolve to a class
+      // element?
+      cls = elementStore[builder];
+      assert(cls != null);
+      name.staticElement = cls;
+    }
+    push(ast.typeName(name, arguments)..type = cls.rawType);
+  }
+
+  void handleAsOperator(Token operator, Token endToken) {
+    debugEvent("AsOperator");
+    TypeName type = pop();
+    Expression expression = pop();
+    push(ast.asExpression(expression, toAnalyzerToken(operator), type));
+  }
+
+  void handleIsOperator(Token operator, Token not, Token endToken) {
+    debugEvent("IsOperator");
+    TypeName type = pop();
+    Expression expression = pop();
+    push(ast.isExpression(expression, toAnalyzerToken(operator),
+            toAnalyzerToken(not), type));
+  }
+
+  void handleConditionalExpression(Token question, Token colon) {
+    debugEvent("ConditionalExpression");
+    Expression elseExpression = pop();
+    Expression thenExpression = pop();
+    Expression condition = pop();
+    push(ast.conditionalExpression(condition, toAnalyzerToken(question),
+            thenExpression, toAnalyzerToken(colon), elseExpression));
+  }
+
+  void endThrowExpression(Token throwToken, Token endToken) {
+    debugEvent("ThrowExpression");
+    push(ast.throwExpression(toAnalyzerToken(throwToken), pop()));
+  }
+
+  void endFormalParameter(Token thisKeyword) {
+    debugEvent("FormalParameter");
+    if (thisKeyword != null) {
+      internalError("'this' can't be used here.");
+    }
+    SimpleIdentifier name = pop();
+    TypeName type = pop();
+    pop(); // Modifiers.
+    pop(); // Metadata.
+    SimpleFormalParameter node = ast.simpleFormalParameter(null, null,
+        toAnalyzerToken(thisKeyword), type, name);
+    scope[name.name] = name.staticElement = new AnalyzerParameterElement(node);
+    push(node);
+  }
+
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+    debugEvent("FormalParameters");
+    List<FormalParameter> parameters = popList(count) ?? <FormalParameter>[];
+    push(ast.formalParameterList(toAnalyzerToken(beginToken), parameters,
+            null, null, toAnalyzerToken(endToken)));
+  }
+
+  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+    debugEvent("CatchBlock");
+    Block body = pop();
+    FormalParameterList catchParameters = popIfNotNull(catchKeyword);
+    if (catchKeyword != null) {
+      exitLocalScope();
+    }
+    TypeName type = popIfNotNull(onKeyword);
+    SimpleIdentifier exception;
+    SimpleIdentifier stackTrace;
+    if (catchParameters != null) {
+      if (catchParameters.length > 0) {
+        exception = catchParameters.parameters[0].identifier;
+      }
+      if (catchParameters.length > 1) {
+        stackTrace = catchParameters.parameters[1].identifier;
+      }
+    }
+    BeginGroupToken leftParenthesis = catchKeyword.next;
+    push(ast.catchClause(toAnalyzerToken(onKeyword), type,
+            toAnalyzerToken(catchKeyword), toAnalyzerToken(leftParenthesis),
+            exception, null, stackTrace,
+            toAnalyzerToken(leftParenthesis.endGroup), body));
+  }
+
+  void endTryStatement(
+      int catchCount, Token tryKeyword, Token finallyKeyword) {
+    Block finallyBlock = popIfNotNull(finallyKeyword);
+    List<CatchClause> catchClauses = popList(catchCount);
+    Block body = pop();
+    push(ast.tryStatement(toAnalyzerToken(tryKeyword), body, catchClauses,
+            toAnalyzerToken(finallyKeyword), finallyBlock));
+  }
+
+  void handleNoExpression(Token token) {
+    debugEvent("NoExpression");
+    push(NullValue.Expression);
+  }
+
+  void handleIndexedExpression(
+      Token openCurlyBracket, Token closeCurlyBracket) {
+    debugEvent("IndexedExpression");
+    Expression index = pop();
+    Expression target = pop();
+    if (target == null) {
+      CascadeExpression receiver = pop();
+      Token token = peek();
+      push(receiver);
+      IndexExpression expression = ast.indexExpressionForCascade(
+          toAnalyzerToken(token), toAnalyzerToken(openCurlyBracket), index,
+          toAnalyzerToken(closeCurlyBracket));
+      assert(expression.isCascaded);
+      push(expression);
+    } else {
+      push(ast.indexExpressionForTarget(target,
+              toAnalyzerToken(openCurlyBracket), index,
+              toAnalyzerToken(closeCurlyBracket)));
+    }
+  }
+
+  void handleUnaryPrefixExpression(Token token) {
+    debugEvent("UnaryPrefixExpression");
+    push(ast.prefixExpression(toAnalyzerToken(token), pop()));
+  }
+
+  void handleUnaryPrefixAssignmentExpression(Token token) {
+    debugEvent("UnaryPrefixAssignmentExpression");
+    push(ast.prefixExpression(toAnalyzerToken(token), pop()));
+  }
+
+  void handleUnaryPostfixAssignmentExpression(Token token) {
+    debugEvent("UnaryPostfixAssignmentExpression");
+    push(ast.postfixExpression(pop(), toAnalyzerToken(token)));
+  }
+
+  void handleModifier(Token token) {
+    debugEvent("Modifier");
+    // TODO(ahe): Don't ignore modifiers.
+  }
+
+  void handleModifiers(int count) {
+    debugEvent("Modifiers");
+    // TODO(ahe): Don't ignore modifiers.
+    push(NullValue.Modifiers);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/analyzer/element_store.dart b/pkg/front_end/lib/src/fasta/analyzer/element_store.dart
new file mode 100644
index 0000000..ab60c94
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/element_store.dart
@@ -0,0 +1,301 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer.element_store;
+
+import 'package:kernel/analyzer/loader.dart' show
+    ReferenceLevelLoader;
+
+import 'package:kernel/ast.dart';
+
+import 'package:analyzer/analyzer.dart' show
+    ParameterKind;
+
+import 'package:analyzer/analyzer.dart' as analyzer;
+
+import 'package:analyzer/dart/element/element.dart';
+
+import 'package:analyzer/dart/element/type.dart' as analyzer;
+
+import '../errors.dart' show
+    internalError;
+
+import '../kernel/kernel_builder.dart';
+
+import '../dill/dill_member_builder.dart';
+
+import 'mock_element.dart';
+
+import 'mock_type.dart';
+
+abstract class ElementStore implements ReferenceLevelLoader {
+  Element operator[] (Builder builder);
+
+  factory ElementStore(
+      LibraryBuilder coreLibrary, Map<Uri, LibraryBuilder> builders) =
+      ElementStoreImplementation;
+}
+
+// ClassElement,
+// ClassMemberElement,
+// CompilationUnitElement,
+// ConstructorElement,
+// Element,
+// FieldElement,
+// FieldFormalParameterElement,
+// FunctionElement,
+// FunctionTypedElement,
+// LibraryElement,
+// LocalElement,
+// LocalVariableElement,
+// MethodElement,
+// ParameterElement,
+// PrefixElement,
+// PropertyAccessorElement,
+// TopLevelVariableElement,
+// TypeParameterElement,
+// VariableElement;
+class ElementStoreImplementation implements ElementStore {
+  final LibraryBuilder coreLibrary;
+
+  final Map<Builder, Element> elements;
+
+  ElementStoreImplementation.internal(this.coreLibrary, this.elements);
+
+  Element operator[] (Builder builder) {
+    // Avoid storing local elements in the element store to reduce memory
+    // usage. So they both implement [Element] and [Builder].
+    return builder is Element ? builder : elements[builder];
+  }
+
+  factory ElementStoreImplementation(
+      LibraryBuilder coreLibrary, Map<Uri, LibraryBuilder> libraries) {
+    Map<Builder, Element> elements = <Builder, Element>{};
+    libraries.forEach((Uri uri, LibraryBuilder library) {
+      KernelCompilationUnitElement unit =
+          new KernelCompilationUnitElement(library);
+      KernelLibraryElement element = new KernelLibraryElement(unit);
+      elements[library] = element;
+      unit.library = element;
+      library.members.forEach((String name, Builder builder) {
+        do {
+          if (builder is ClassBuilder) {
+            elements[builder] = new KernelClassElement(builder);
+          } else if (builder is DillMemberBuilder) {
+            Member member = builder.member;
+            if (member is Field) {
+            } else if (member is Procedure) {
+              buildDillFunctionElement(builder, unit, elements);
+            } else {
+              internalError("Unhandled $name ${member.runtimeType} in $uri");
+            }
+          } else if (builder is KernelProcedureBuilder) {
+            buildKernelFunctionElement(builder, unit, elements);
+          } else {
+            internalError("Unhandled $name ${builder.runtimeType} in $uri");
+          }
+          builder = builder.next;
+        } while (builder != null);
+      });
+    });
+    return new ElementStoreImplementation.internal(coreLibrary, elements);
+  }
+
+  bool get ignoreRedirectingFactories => false;
+
+  Constructor getCoreClassConstructorReference(String className,
+      {String constructorName, String library}) {
+    assert(library == null);
+    KernelClassBuilder cls = coreLibrary.members[className];
+    Constructor constructor = constructorName == null
+        ? cls.cls.constructors.first
+        : cls.cls.constructors.firstWhere(
+            (Constructor c) => c.name.name == constructorName);
+    return constructor;
+  }
+
+  Library getLibraryReference(LibraryElement element) {
+    return internalError("not supported.");
+  }
+
+  Class getClassReference(covariant KernelClassElement cls) => cls.builder.cls;
+
+  Member getMemberReference(Element element) {
+    if (element is KernelFunctionElement) {
+      return element.procedure;
+    } else {
+      return internalError("getMemberReference(${element.runtimeType})");
+    }
+  }
+
+  Class getRootClassReference() => internalError("not supported.");
+
+  Constructor getRootClassConstructorReference() {
+    return internalError("not supported.");
+  }
+
+  Class getCoreClassReference(String className) {
+    return internalError("not supported.");
+  }
+
+  TypeParameter tryGetClassTypeParameter(TypeParameterElement element) {
+    return internalError("not supported.");
+  }
+
+  Class getSharedMixinApplicationClass(
+      Library library, Class supertype, Class mixin) {
+    return internalError("not supported.");
+  }
+
+  bool get strongMode => false;
+
+  static void buildDillFunctionElement(DillMemberBuilder builder,
+      KernelCompilationUnitElement unit, Map<Builder, Element> elements) {
+    Procedure procedure = builder.member;
+    List<VariableDeclaration> positionalParameters =
+        procedure.function.positionalParameters;
+    List<VariableDeclaration> namedParameters =
+        procedure.function.namedParameters;
+    int requiredParameterCount = procedure.function.requiredParameterCount;
+    List<KernelParameterElement> parameters = new List<KernelParameterElement>(
+        positionalParameters.length + namedParameters.length);
+    int i = 0;
+    for (VariableDeclaration parameter in positionalParameters) {
+      parameters[i] = buildFormalParameter(
+          parameter, isOptional: i >= requiredParameterCount);
+      i++;
+    }
+    for (VariableDeclaration parameter in namedParameters) {
+      parameters[i++] = buildFormalParameter(parameter, isNamed: true);
+    }
+    elements[builder] = new KernelFunctionElement(procedure, unit, parameters);
+  }
+
+  static void buildKernelFunctionElement(KernelProcedureBuilder builder,
+      KernelCompilationUnitElement unit, Map<Builder, Element> elements) {
+    assert(builder.procedure != null);
+    List<KernelParameterElement> parameters;
+    int i = 0;
+    if (builder.formals != null) {
+      parameters = new List<KernelParameterElement>(builder.formals.length);
+      for (KernelFormalParameterBuilder parameter in builder.formals) {
+        assert(parameter.declaration != null);
+        elements[parameter] = parameters[i++] = buildFormalParameter(
+            parameter.declaration, isOptional: parameter.isOptional,
+            isNamed: parameter.isNamed);
+      }
+    } else {
+      parameters = new List<KernelParameterElement>(0);
+    }
+    elements[builder] = new KernelFunctionElement(
+        builder.procedure, unit, parameters);
+  }
+
+  static KernelParameterElement buildFormalParameter(
+      VariableDeclaration parameter,
+      {bool isOptional: true, bool isNamed: false}) {
+    ParameterKind kind = isOptional
+        ? (isNamed ? ParameterKind.NAMED : ParameterKind.POSITIONAL)
+        : ParameterKind.REQUIRED;
+    return new KernelParameterElement(parameter, kind);
+  }
+}
+
+class KernelLibraryElement extends MockLibraryElement {
+  final KernelCompilationUnitElement definingCompilationUnit;
+
+  KernelLibraryElement(this.definingCompilationUnit);
+
+  FunctionElement get loadLibraryFunction => null;
+}
+
+class KernelCompilationUnitElement extends MockCompilationUnitElement {
+  final LibraryBuilder builder;
+
+  KernelLibraryElement library;
+
+  KernelCompilationUnitElement(this.builder);
+
+  KernelLibraryElement get enclosingElement => library;
+
+  String get uri => "${builder.uri}";
+}
+
+class KernelFunctionElement extends MockFunctionElement {
+  final Procedure procedure;
+
+  final KernelCompilationUnitElement enclosingElement;
+
+  final List<KernelParameterElement> parameters;
+
+  KernelFunctionElement(this.procedure, this.enclosingElement, this.parameters);
+
+  KernelLibraryElement get library => enclosingElement.library;
+}
+
+class KernelParameterElement extends MockParameterElement {
+  final VariableDeclaration declaration;
+
+  final ParameterKind parameterKind;
+
+  KernelParameterElement(this.declaration, this.parameterKind);
+}
+
+/// Both an [Element] and [Builder] to using memory to store local elements in
+/// [ElementStore].
+class AnalyzerLocalVariableElemment extends MockElement
+    implements LocalVariableElement {
+  final analyzer.VariableDeclaration variable;
+
+  AnalyzerLocalVariableElemment(this.variable)
+      : super(ElementKind.LOCAL_VARIABLE);
+
+  String get name => variable.name.name;
+
+  bool get isFinal => false; // TODO(ahe): implement this.
+
+  bool get isConst => false; // TODO(ahe): implement this.
+
+  analyzer.VariableDeclaration get target => variable;
+
+  get type => null;
+
+  get constantValue => internalError("not supported.");
+
+  computeConstantValue() => internalError("not supported.");
+}
+
+/// Both an [Element] and [Builder] to using memory to store local elements in
+/// [ElementStore].
+class AnalyzerParameterElement extends MockParameterElement {
+  final analyzer.FormalParameter parameter;
+
+  AnalyzerParameterElement(this.parameter);
+
+  String get name => parameter.identifier.name;
+
+  bool get isFinal => false; // TODO(ahe): implement this.
+
+  bool get isConst => false; // TODO(ahe): implement this.
+
+  analyzer.FormalParameter get target => parameter;
+}
+
+class KernelClassElement extends MockClassElement {
+  final KernelClassBuilder builder;
+
+  KernelInterfaceType rawType;
+
+  KernelClassElement(this.builder) {
+    rawType = new KernelInterfaceType(this);
+  }
+}
+
+class KernelInterfaceType extends MockInterfaceType {
+  final KernelClassElement element;
+
+  KernelInterfaceType(this.element);
+
+  List<analyzer.DartType> get typeArguments => const <analyzer.DartType>[];
+}
diff --git a/pkg/front_end/lib/src/fasta/analyzer/mock_element.dart b/pkg/front_end/lib/src/fasta/analyzer/mock_element.dart
new file mode 100644
index 0000000..e9ed649
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/mock_element.dart
@@ -0,0 +1,380 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer.mock_element;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+
+import '../builder/builder.dart' show
+    Builder;
+
+import '../errors.dart' show
+    internalError;
+
+abstract class MockElement extends Builder
+    implements Element, LocalElement {
+  final ElementKind kind;
+
+  MockElement(this.kind)
+      : super(null, -1, null);
+
+  get librarySource => internalError("not supported.");
+
+  get source => internalError("not supported.");
+
+  get context => internalError("not supported.");
+
+  String get displayName => internalError("not supported.");
+
+  String get documentationComment => internalError("not supported.");
+
+  Element get enclosingElement => internalError("not supported.");
+
+  int get id => internalError("not supported.");
+
+  bool get isDeprecated => internalError("not supported.");
+
+  bool get isFactory => internalError("not supported.");
+
+  bool get isJS => internalError("not supported.");
+
+  bool get isOverride => internalError("not supported.");
+
+  bool get isPrivate => internalError("not supported.");
+
+  bool get isProtected => internalError("not supported.");
+
+  bool get isPublic => internalError("not supported.");
+
+  bool get isRequired => internalError("not supported.");
+
+  bool get isSynthetic => internalError("not supported.");
+
+  LibraryElement get library => internalError("not supported.");
+
+  get location => internalError("not supported.");
+
+  get metadata => internalError("not supported.");
+
+  String get name => internalError("not supported.");
+
+  int get nameLength => internalError("not supported.");
+
+  int get nameOffset => -1;
+
+  get unit => internalError("not supported.");
+
+  accept<T>(visitor) => internalError("not supported.");
+
+  String computeDocumentationComment() => internalError("not supported.");
+
+  computeNode() => internalError("not supported.");
+
+  getAncestor<E>(predicate) => internalError("not supported.");
+
+  String getExtendedDisplayName(String shortName) {
+    return internalError("not supported.");
+  }
+
+  bool isAccessibleIn(LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  void visitChildren(visitor) => internalError("not supported.");
+
+  String get uri => internalError("not supported.");
+
+  int get uriEnd => internalError("not supported.");
+
+  int get uriOffset => internalError("not supported.");
+
+  List<ParameterElement> get parameters => internalError("not supported.");
+
+  List<FunctionElement> get functions => internalError("not supported.");
+
+  bool get hasImplicitReturnType => internalError("not supported.");
+
+  bool get isAbstract => internalError("not supported.");
+
+  bool get isAsynchronous => internalError("not supported.");
+
+  bool get isExternal => internalError("not supported.");
+
+  bool get isGenerator => internalError("not supported.");
+
+  bool get isOperator => internalError("not supported.");
+
+  bool get isStatic => internalError("not supported.");
+
+  bool get isSynchronous => internalError("not supported.");
+
+  List<LabelElement> get labels => internalError("not supported.");
+
+  List<LocalVariableElement> get localVariables {
+    return internalError("not supported.");
+  }
+
+  get visibleRange => internalError("not supported.");
+
+  bool get hasImplicitType => internalError("not supported.");
+
+  FunctionElement get initializer => internalError("not supported.");
+
+  bool get isConst => internalError("not supported.");
+
+  bool get isFinal => internalError("not supported.");
+
+  bool get isPotentiallyMutatedInClosure => internalError("not supported.");
+
+  bool get isPotentiallyMutatedInScope => internalError("not supported.");
+}
+
+abstract class MockLibraryElement extends MockElement
+    implements LibraryElement {
+  MockLibraryElement()
+      : super(ElementKind.LIBRARY);
+
+  CompilationUnitElement get definingCompilationUnit {
+    return internalError("not supported.");
+  }
+
+  FunctionElement get entryPoint => internalError("not supported.");
+
+  List<LibraryElement> get exportedLibraries {
+    return internalError("not supported.");
+  }
+
+  get exportNamespace => internalError("not supported.");
+
+  get exports => internalError("not supported.");
+
+  bool get hasExtUri => internalError("not supported.");
+
+  bool get hasLoadLibraryFunction => internalError("not supported.");
+
+  String get identifier => internalError("not supported.");
+
+  List<LibraryElement> get importedLibraries {
+    return internalError("not supported.");
+  }
+
+  get imports => internalError("not supported.");
+
+  bool get isBrowserApplication => internalError("not supported.");
+
+  bool get isDartAsync => internalError("not supported.");
+
+  bool get isDartCore => internalError("not supported.");
+
+  bool get isInSdk => internalError("not supported.");
+
+  List<LibraryElement> get libraryCycle => internalError("not supported.");
+
+  FunctionElement get loadLibraryFunction => internalError("not supported.");
+
+  List<CompilationUnitElement> get parts => internalError("not supported.");
+
+  List<PrefixElement> get prefixes => internalError("not supported.");
+
+  get publicNamespace => internalError("not supported.");
+
+  List<CompilationUnitElement> get units => internalError("not supported.");
+
+  getImportsWithPrefix(PrefixElement prefix) {
+    return internalError("not supported.");
+  }
+
+  ClassElement getType(String className) => internalError("not supported.");
+}
+
+abstract class MockCompilationUnitElement extends MockElement
+    implements CompilationUnitElement {
+  MockCompilationUnitElement()
+      : super(ElementKind.COMPILATION_UNIT);
+
+  List<PropertyAccessorElement> get accessors {
+    return internalError("not supported.");
+  }
+
+  LibraryElement get enclosingElement => internalError("not supported.");
+
+  List<ClassElement> get enums => internalError("not supported.");
+
+  List<FunctionElement> get functions => internalError("not supported.");
+
+  List<FunctionTypeAliasElement> get functionTypeAliases {
+    return internalError("not supported.");
+  }
+
+  bool get hasLoadLibraryFunction => internalError("not supported.");
+
+  List<TopLevelVariableElement> get topLevelVariables {
+    return internalError("not supported.");
+  }
+
+  List<ClassElement> get types => internalError("not supported.");
+
+  Element getElementAt(int offset) => internalError("not supported.");
+
+  ClassElement getEnum(String name) => internalError("not supported.");
+
+  ClassElement getType(String name) => internalError("not supported.");
+
+  CompilationUnit computeNode() => internalError("not supported.");
+}
+
+abstract class MockClassElement extends MockElement implements ClassElement {
+  MockClassElement()
+      : super(ElementKind.CLASS);
+
+  List<PropertyAccessorElement> get accessors {
+    return internalError("not supported.");
+  }
+
+  get allSupertypes => internalError("not supported.");
+
+  List<ConstructorElement> get constructors => internalError("not supported.");
+
+  List<FieldElement> get fields => internalError("not supported.");
+
+  bool get hasNonFinalField => internalError("not supported.");
+
+  bool get hasReferenceToSuper => internalError("not supported.");
+
+  bool get hasStaticMember => internalError("not supported.");
+
+  get interfaces => internalError("not supported.");
+
+  bool get isAbstract => internalError("not supported.");
+
+  bool get isEnum => internalError("not supported.");
+
+  bool get isMixinApplication => internalError("not supported.");
+
+  bool get isOrInheritsProxy => internalError("not supported.");
+
+  bool get isProxy => internalError("not supported.");
+
+  bool get isValidMixin => internalError("not supported.");
+
+  get typeParameters => internalError("not supported.");
+
+  List<MethodElement> get methods => internalError("not supported.");
+
+  get mixins => internalError("not supported.");
+
+  get supertype => internalError("not supported.");
+
+  ConstructorElement get unnamedConstructor => internalError("not supported.");
+
+  FieldElement getField(String name) => internalError("not supported.");
+
+  PropertyAccessorElement getGetter(String name) {
+    return internalError("not supported.");
+  }
+
+  MethodElement getMethod(String name) => internalError("not supported.");
+
+  ConstructorElement getNamedConstructor(String name) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement getSetter(String name) {
+    return internalError("not supported.");
+  }
+
+  bool isSuperConstructorAccessible(ConstructorElement constructor) {
+    return internalError("not supported.");
+  }
+
+  MethodElement lookUpConcreteMethod(
+      String methodName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpGetter(
+      String getterName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpInheritedConcreteGetter(
+      String getterName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  MethodElement lookUpInheritedConcreteMethod(
+      String methodName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpInheritedConcreteSetter(
+      String setterName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  MethodElement lookUpInheritedMethod(
+      String methodName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  MethodElement lookUpMethod(String methodName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpSetter(
+      String setterName, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  NamedCompilationUnitMember computeNode() => internalError("not supported.");
+
+  InterfaceType get type => internalError("not supported.");
+}
+
+abstract class MockFunctionElement extends MockElement
+    implements FunctionElement {
+  MockFunctionElement()
+      : super(ElementKind.FUNCTION);
+
+  bool get isEntryPoint => internalError("not supported.");
+
+  get typeParameters => internalError("not supported.");
+
+  FunctionType get type => internalError("not supported.");
+  DartType get returnType => internalError("not supported.");
+
+  FunctionDeclaration computeNode() => internalError("not supported.");
+}
+
+abstract class MockParameterElement extends MockElement
+    implements ParameterElement {
+  MockParameterElement()
+      : super(ElementKind.PARAMETER);
+
+  String get defaultValueCode => internalError("not supported.");
+
+  bool get isCovariant => internalError("not supported.");
+
+  bool get isInitializingFormal => internalError("not supported.");
+
+  get parameterKind => internalError("not supported.");
+
+  List<ParameterElement> get parameters => internalError("not supported.");
+
+  get type => null;
+
+  get typeParameters => internalError("not supported.");
+
+  get constantValue => internalError("not supported.");
+
+  computeConstantValue() => internalError("not supported.");
+
+  void appendToWithoutDelimiters(StringBuffer buffer) {
+    return internalError("not supported.");
+  }
+
+  FormalParameter computeNode() => internalError("not supported.");
+}
diff --git a/pkg/front_end/lib/src/fasta/analyzer/mock_type.dart b/pkg/front_end/lib/src/fasta/analyzer/mock_type.dart
new file mode 100644
index 0000000..bf55d37
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/mock_type.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer.mock_type;
+
+import 'package:analyzer/dart/element/element.dart';
+
+import 'package:analyzer/dart/element/type.dart';
+
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystem;
+
+import '../errors.dart' show
+    internalError;
+
+abstract class MockType extends DartType {
+  String get displayName => internalError("not supported.");
+
+  Element get element => internalError("not supported.");
+
+  bool get isBottom => internalError("not supported.");
+
+  bool get isDartAsyncFuture => internalError("not supported.");
+
+  bool get isDartAsyncFutureOr => internalError("not supported.");
+
+  bool get isDartCoreFunction => internalError("not supported.");
+
+  bool get isDynamic => internalError("not supported.");
+
+  bool get isObject => internalError("not supported.");
+
+  bool get isUndefined => internalError("not supported.");
+
+  bool get isVoid => internalError("not supported.");
+
+  String get name => internalError("not supported.");
+
+  DartType flattenFutures(TypeSystem typeSystem) {
+    return internalError("not supported.");
+  }
+
+  bool isAssignableTo(DartType type) => internalError("not supported.");
+
+  bool isMoreSpecificThan(DartType type) => internalError("not supported.");
+
+  bool isSubtypeOf(DartType type) => internalError("not supported.");
+
+  bool isSupertypeOf(DartType type) => internalError("not supported.");
+
+  DartType resolveToBound(DartType objectType) {
+    return internalError("not supported.");
+  }
+
+  DartType substitute2(
+      List<DartType> argumentTypes, List<DartType> parameterTypes) {
+    return internalError("not supported.");
+  }
+
+  List<DartType> get typeArguments => internalError("not supported.");
+
+  List<TypeParameterElement> get typeParameters {
+    return internalError("not supported.");
+  }
+
+  ParameterizedType instantiate(List<DartType> argumentTypes) {
+    return internalError("not supported.");
+  }
+}
+
+abstract class MockInterfaceType extends MockType implements InterfaceType {
+  ClassElement get element => internalError("not supported.");
+
+  List<PropertyAccessorElement> get accessors {
+    return internalError("not supported.");
+  }
+
+  List<ConstructorElement> get constructors => internalError("not supported.");
+
+  List<InterfaceType> get interfaces => internalError("not supported.");
+
+  List<MethodElement> get methods => internalError("not supported.");
+
+  List<InterfaceType> get mixins => internalError("not supported.");
+
+  InterfaceType get superclass => internalError("not supported.");
+
+  PropertyAccessorElement getGetter(String name) {
+    return internalError("not supported.");
+  }
+
+  MethodElement getMethod(String name) => internalError("not supported.");
+
+  PropertyAccessorElement getSetter(String name) {
+    return internalError("not supported.");
+  }
+
+  bool isDirectSupertypeOf(InterfaceType type) {
+    return internalError("not supported.");
+  }
+
+
+  ConstructorElement lookUpConstructor(String name, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpGetter(String name, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpGetterInSuperclass(
+      String name, LibraryElement library) => internalError("not supported.");
+
+  PropertyAccessorElement lookUpInheritedGetter(String name,
+      {LibraryElement library, bool thisType: true}) {
+    return internalError("not supported.");
+  }
+
+  ExecutableElement lookUpInheritedGetterOrMethod(String name,
+      {LibraryElement library}) => internalError("not supported.");
+
+  MethodElement lookUpInheritedMethod(String name,
+      {LibraryElement library, bool thisType: true}) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpInheritedSetter(String name,
+      {LibraryElement library, bool thisType: true}) {
+    return internalError("not supported.");
+  }
+
+  MethodElement lookUpMethod(String name, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  MethodElement lookUpMethodInSuperclass(String name, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpSetter(String name, LibraryElement library) {
+    return internalError("not supported.");
+  }
+
+  PropertyAccessorElement lookUpSetterInSuperclass(
+      String name, LibraryElement library) => internalError("not supported.");
+
+  InterfaceType instantiate(List<DartType> argumentTypes) {
+    return internalError("not supported.");
+  }
+
+  InterfaceType substitute2(
+      List<DartType> argumentTypes, List<DartType> parameterTypes) {
+    return internalError("not supported.");
+  }
+
+  InterfaceType substitute4(List<DartType> argumentTypes) {
+    return internalError("not supported.");
+  }
+
+  get isDartCoreNull => internalError("not supported.");
+}
diff --git a/pkg/front_end/lib/src/fasta/analyzer/token_utils.dart b/pkg/front_end/lib/src/fasta/analyzer/token_utils.dart
new file mode 100644
index 0000000..ed5a9ea
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/analyzer/token_utils.dart
@@ -0,0 +1,657 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer.token_utils;
+
+import 'package:front_end/src/fasta/parser/error_kind.dart' show
+    ErrorKind;
+
+import 'package:front_end/src/fasta/scanner/error_token.dart' show
+    ErrorToken;
+
+import 'package:front_end/src/fasta/scanner/keyword.dart' show
+    Keyword;
+
+import 'package:front_end/src/fasta/scanner/precedence.dart';
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    BeginGroupToken,
+    KeywordToken,
+    StringToken,
+    SymbolToken,
+    Token;
+
+import 'package:front_end/src/fasta/scanner/token_constants.dart';
+
+import 'package:front_end/src/scanner/token.dart' as analyzer show
+    BeginToken,
+    BeginTokenWithComment,
+    CommentToken,
+    Keyword,
+    KeywordToken,
+    KeywordTokenWithComment,
+    StringToken,
+    StringTokenWithComment,
+    Token,
+    TokenWithComment;
+
+import 'package:front_end/src/scanner/errors.dart' as analyzer show
+    ScannerErrorCode;
+
+import 'package:analyzer/dart/ast/token.dart' show
+    TokenType;
+
+import '../errors.dart' show
+    internalError;
+
+/// Converts a stream of Fasta tokens (starting with [token] and continuing to
+/// EOF) to a stream of analyzer tokens.
+///
+/// If any error tokens are found in the stream, they are reported using the
+/// [reportError] callback.
+analyzer.Token toAnalyzerTokenStream(
+    Token token,
+    void reportError(analyzer.ScannerErrorCode errorCode, int offset,
+        List<Object> arguments)) {
+  var analyzerTokenHead = new analyzer.Token(null, 0);
+  analyzerTokenHead.previous = analyzerTokenHead;
+  var analyzerTokenTail = analyzerTokenHead;
+  // TODO(paulberry,ahe): Fasta includes comments directly in the token
+  // stream, rather than pointing to them via a "precedingComment" pointer, as
+  // analyzer does.  This seems like it will complicate parsing and other
+  // operations.
+  analyzer.CommentToken currentCommentHead;
+  analyzer.CommentToken currentCommentTail;
+  // Note: beginTokenStack and endTokenStack are seeded with a sentinel value
+  // so that we don't have to check if they're empty.
+  var beginTokenStack = <analyzer.BeginToken>[null];
+  var endTokenStack = <Token>[null];
+  void matchGroups(Token token, analyzer.Token translatedToken) {
+    // If this token closes a group, set the corresponding opener token
+    // to point to it.
+    if (identical(endTokenStack.last, token)) {
+      beginTokenStack.last.endToken = translatedToken;
+      beginTokenStack.removeLast();
+      endTokenStack.removeLast();
+    }
+    // If this token opens a group, and there is a matching closer that's not
+    // synthetic, put it on the stack.  The easiest way to tell whether the
+    // closer is synthetic is to see if it has the same offset as the opener.
+    if (translatedToken is analyzer.BeginToken &&
+        token is BeginGroupToken &&
+        token.endGroup != null &&
+        token.endGroup.charOffset != token.charOffset) {
+      beginTokenStack.add(translatedToken);
+      endTokenStack.add(token.endGroup);
+    }
+  }
+
+  while (true) {
+    if (token.info.kind == BAD_INPUT_TOKEN) {
+      ErrorToken errorToken = token;
+      _translateErrorToken(errorToken, reportError);
+    } else if (token.info.kind == COMMENT_TOKEN) {
+      // TODO(paulberry,ahe): It would be nice if the scanner gave us an
+      // easier way to distinguish between the two types of comment.
+      var type = token.value.startsWith('/*')
+          ? TokenType.MULTI_LINE_COMMENT
+          : TokenType.SINGLE_LINE_COMMENT;
+      var translatedToken =
+          new analyzer.CommentToken(type, token.value, token.charOffset);
+      if (currentCommentHead == null) {
+        currentCommentHead = currentCommentTail = translatedToken;
+      } else {
+        currentCommentTail.setNext(translatedToken);
+        currentCommentTail = translatedToken;
+      }
+    } else {
+      var translatedToken = toAnalyzerToken(token, currentCommentHead);
+      matchGroups(token, translatedToken);
+      translatedToken.setNext(translatedToken);
+      currentCommentHead = currentCommentTail = null;
+      analyzerTokenTail.setNext(translatedToken);
+      translatedToken.previous = analyzerTokenTail;
+      analyzerTokenTail = translatedToken;
+    }
+    if (token.isEof) {
+      return analyzerTokenHead.next;
+    }
+    token = token.next;
+  }
+}
+
+/// Converts a stream of Analyzer tokens (starting with [token] and continuing
+/// to EOF) to a stream of Fasta tokens.
+///
+/// TODO(paulberry): Analyzer tokens do not record error conditions, so a round
+/// trip through this function and [toAnalyzerTokenStream] will lose error
+/// information.
+Token fromAnalyzerTokenStream(analyzer.Token analyzerToken) {
+  Token tokenHead = new SymbolToken(EOF_INFO, -1);
+  Token tokenTail = tokenHead;
+  // Note: beginTokenStack and endTokenStack are seeded with a sentinel value
+  // so that we don't have to check if they're empty.
+  var beginTokenStack = <BeginGroupToken>[null];
+  var endTokenStack = <analyzer.Token>[null];
+  var angleBracketStack = <BeginGroupToken>[];
+  void matchGroups(analyzer.Token analyzerToken, Token translatedToken) {
+    // If this token closes a group, set the corresponding opener token to point
+    // to it.
+    if (identical(endTokenStack.last, analyzerToken)) {
+      angleBracketStack.clear();
+      beginTokenStack.last.endGroup = translatedToken;
+      beginTokenStack.removeLast();
+      endTokenStack.removeLast();
+    } else if (translatedToken.info.kind == LT_TOKEN) {
+      BeginGroupToken beginGroupToken = translatedToken;
+      angleBracketStack.add(beginGroupToken);
+    } else if (translatedToken.info.kind == GT_TOKEN &&
+        angleBracketStack.isNotEmpty) {
+      angleBracketStack.removeLast().endGroup = translatedToken;
+    } else if (translatedToken.info.kind == GT_GT_TOKEN &&
+        angleBracketStack.isNotEmpty) {
+      angleBracketStack.removeLast();
+      if (angleBracketStack.isNotEmpty) {
+        angleBracketStack.removeLast().endGroup = translatedToken;
+      }
+    }
+    // If this token opens a group, and there is a matching closer, put it on
+    // the stack.
+    // TODO(paulberry): generate synthetic closer tokens and "UnmatchedToken"
+    // tokens as appropriate.
+    if (translatedToken is BeginGroupToken &&
+        analyzerToken is analyzer.BeginToken &&
+        analyzerToken.endToken != null) {
+      angleBracketStack.clear();
+      beginTokenStack.add(translatedToken);
+      endTokenStack.add(analyzerToken.endToken);
+    }
+  }
+
+  analyzer.Token translateAndAppend(analyzer.Token analyzerToken) {
+    var token = fromAnalyzerToken(analyzerToken);
+    tokenTail.next = token;
+    tokenTail = token;
+    matchGroups(analyzerToken, token);
+    return analyzerToken.next;
+  }
+
+  while (true) {
+    analyzer.Token commentToken = analyzerToken.precedingComments;
+    while (commentToken != null) {
+      commentToken = translateAndAppend(commentToken);
+    }
+    // TODO(paulberry): join up begingroup/endgroup.
+    if (analyzerToken.type == TokenType.EOF) {
+      tokenTail.next = new SymbolToken(EOF_INFO, analyzerToken.offset);
+      return tokenHead.next;
+    }
+    analyzerToken = translateAndAppend(analyzerToken);
+  }
+}
+
+/// Converts a single analyzer token into a Fasta token.
+Token fromAnalyzerToken(analyzer.Token token) {
+  Token beginGroup(PrecedenceInfo info) =>
+      new BeginGroupToken(info, token.offset);
+  Token string(PrecedenceInfo info) =>
+      new StringToken.fromString(info, token.lexeme, token.offset);
+  Token symbol(PrecedenceInfo info) => new SymbolToken(info, token.offset);
+  switch (token.type) {
+    case TokenType.DOUBLE:
+      return string(DOUBLE_INFO);
+    case TokenType.HEXADECIMAL:
+      return string(HEXADECIMAL_INFO);
+    case TokenType.IDENTIFIER:
+      // Certain identifiers have special grammatical meanings even though they
+      // are neither keywords nor built-in identifiers (e.g. "async").  Analyzer
+      // represents these as identifiers.  Fasta represents them as keywords
+      // with the "isPseudo" property.
+      var keyword = Keyword.keywords[token.lexeme];
+      if (keyword != null) {
+        assert(keyword.isPseudo);
+        return new KeywordToken(keyword, token.offset);
+      } else {
+        return string(IDENTIFIER_INFO);
+      }
+      break;
+    case TokenType.INT:
+      return string(INT_INFO);
+    case TokenType.KEYWORD:
+      var keyword = Keyword.keywords[token.lexeme];
+      if (keyword != null) {
+        return new KeywordToken(keyword, token.offset);
+      } else {
+        return internalError("Unrecognized keyword: '${token.lexeme}'.");
+      }
+      break;
+    case TokenType.MULTI_LINE_COMMENT:
+      return string(COMMENT_INFO);
+    // case TokenType.SCRIPT_TAG
+    case TokenType.SINGLE_LINE_COMMENT:
+      return string(COMMENT_INFO);
+    case TokenType.STRING:
+      return string(STRING_INFO);
+    case TokenType.AMPERSAND:
+      return symbol(AMPERSAND_INFO);
+    case TokenType.AMPERSAND_AMPERSAND:
+      return symbol(AMPERSAND_AMPERSAND_INFO);
+    // case TokenType.AMPERSAND_AMPERSAND_EQ
+    case TokenType.AMPERSAND_EQ:
+      return symbol(AMPERSAND_EQ_INFO);
+    case TokenType.AT:
+      return symbol(AT_INFO);
+    case TokenType.BANG:
+      return symbol(BANG_INFO);
+    case TokenType.BANG_EQ:
+      return symbol(BANG_EQ_INFO);
+    case TokenType.BAR:
+      return symbol(BAR_INFO);
+    case TokenType.BAR_BAR:
+      return symbol(BAR_BAR_INFO);
+    // case TokenType.BAR_BAR_EQ
+    case TokenType.BAR_EQ:
+      return symbol(BAR_EQ_INFO);
+    case TokenType.COLON:
+      return symbol(COLON_INFO);
+    case TokenType.COMMA:
+      return symbol(COMMA_INFO);
+    case TokenType.CARET:
+      return symbol(CARET_INFO);
+    case TokenType.CARET_EQ:
+      return symbol(CARET_EQ_INFO);
+    case TokenType.CLOSE_CURLY_BRACKET:
+      return symbol(CLOSE_CURLY_BRACKET_INFO);
+    case TokenType.CLOSE_PAREN:
+      return symbol(CLOSE_PAREN_INFO);
+    case TokenType.CLOSE_SQUARE_BRACKET:
+      return symbol(CLOSE_SQUARE_BRACKET_INFO);
+    case TokenType.EQ:
+      return symbol(EQ_INFO);
+    case TokenType.EQ_EQ:
+      return symbol(EQ_EQ_INFO);
+    case TokenType.FUNCTION:
+      return symbol(FUNCTION_INFO);
+    case TokenType.GT:
+      return symbol(GT_INFO);
+    case TokenType.GT_EQ:
+      return symbol(GT_EQ_INFO);
+    case TokenType.GT_GT:
+      return symbol(GT_GT_INFO);
+    case TokenType.GT_GT_EQ:
+      return symbol(GT_GT_EQ_INFO);
+    case TokenType.HASH:
+      return symbol(HASH_INFO);
+    case TokenType.INDEX:
+      return symbol(INDEX_INFO);
+    case TokenType.INDEX_EQ:
+      return symbol(INDEX_EQ_INFO);
+    case TokenType.LT:
+      return beginGroup(LT_INFO);
+    case TokenType.LT_EQ:
+      return symbol(LT_EQ_INFO);
+    case TokenType.LT_LT:
+      return symbol(LT_LT_INFO);
+    case TokenType.LT_LT_EQ:
+      return symbol(LT_LT_EQ_INFO);
+    case TokenType.MINUS:
+      return symbol(MINUS_INFO);
+    case TokenType.MINUS_EQ:
+      return symbol(MINUS_EQ_INFO);
+    case TokenType.MINUS_MINUS:
+      return symbol(MINUS_MINUS_INFO);
+    case TokenType.OPEN_CURLY_BRACKET:
+      return beginGroup(OPEN_CURLY_BRACKET_INFO);
+    case TokenType.OPEN_PAREN:
+      return beginGroup(OPEN_PAREN_INFO);
+    case TokenType.OPEN_SQUARE_BRACKET:
+      return beginGroup(OPEN_SQUARE_BRACKET_INFO);
+    case TokenType.PERCENT:
+      return symbol(PERCENT_INFO);
+    case TokenType.PERCENT_EQ:
+      return symbol(PERCENT_EQ_INFO);
+    case TokenType.PERIOD:
+      return symbol(PERIOD_INFO);
+    case TokenType.PERIOD_PERIOD:
+      return symbol(PERIOD_PERIOD_INFO);
+    case TokenType.PLUS:
+      return symbol(PLUS_INFO);
+    case TokenType.PLUS_EQ:
+      return symbol(PLUS_EQ_INFO);
+    case TokenType.PLUS_PLUS:
+      return symbol(PLUS_PLUS_INFO);
+    case TokenType.QUESTION:
+      return symbol(QUESTION_INFO);
+    case TokenType.QUESTION_PERIOD:
+      return symbol(QUESTION_PERIOD_INFO);
+    case TokenType.QUESTION_QUESTION:
+      return symbol(QUESTION_QUESTION_INFO);
+    case TokenType.QUESTION_QUESTION_EQ:
+      return symbol(QUESTION_QUESTION_EQ_INFO);
+    case TokenType.SEMICOLON:
+      return symbol(SEMICOLON_INFO);
+    case TokenType.SLASH:
+      return symbol(SLASH_INFO);
+    case TokenType.SLASH_EQ:
+      return symbol(SLASH_EQ_INFO);
+    case TokenType.STAR:
+      return symbol(STAR_INFO);
+    case TokenType.STAR_EQ:
+      return symbol(STAR_EQ_INFO);
+    case TokenType.STRING_INTERPOLATION_EXPRESSION:
+      return beginGroup(STRING_INTERPOLATION_INFO);
+    case TokenType.STRING_INTERPOLATION_IDENTIFIER:
+      return symbol(STRING_INTERPOLATION_IDENTIFIER_INFO);
+    case TokenType.TILDE:
+      return symbol(TILDE_INFO);
+    case TokenType.TILDE_SLASH:
+      return symbol(TILDE_SLASH_INFO);
+    case TokenType.TILDE_SLASH_EQ:
+      return symbol(TILDE_SLASH_EQ_INFO);
+    case TokenType.BACKPING:
+      return symbol(BACKPING_INFO);
+    case TokenType.BACKSLASH:
+      return symbol(BACKSLASH_INFO);
+    case TokenType.PERIOD_PERIOD_PERIOD:
+      return symbol(PERIOD_PERIOD_PERIOD_INFO);
+    // case TokenType.GENERIC_METHOD_TYPE_ASSIGN
+    // case TokenType.GENERIC_METHOD_TYPE_LIST
+    default:
+      return internalError('Unhandled token type ${token.type}');
+  }
+}
+
+/// Determines whether the given [charOffset], which came from the non-EOF token
+/// [token], represents the end of the input.
+bool _isAtEnd(Token token, int charOffset) {
+  while (true) {
+    // Skip to the next token.
+    token = token.next;
+    // If we've found an EOF token, its charOffset indicates where the end of
+    // the input is.
+    if (token.isEof) return token.charOffset == charOffset;
+    // If we've found a non-error token, then we know there is additional input
+    // text after [charOffset].
+    if (token.info.kind != BAD_INPUT_TOKEN) return false;
+    // Otherwise keep looking.
+  }
+}
+
+/// Translates the given error [token] into an analyzer error and reports it
+/// using [reportError].
+void _translateErrorToken(
+    ErrorToken token,
+    void reportError(analyzer.ScannerErrorCode errorCode, int offset,
+        List<Object> arguments)) {
+  int charOffset = token.charOffset;
+  // TODO(paulberry,ahe): why is endOffset sometimes null?
+  int endOffset = token.endOffset ?? charOffset;
+  void _makeError(analyzer.ScannerErrorCode errorCode, List<Object> arguments) {
+    if (_isAtEnd(token, charOffset)) {
+      // Analyzer never generates an error message past the end of the input,
+      // since such an error would not be visible in an editor.
+      // TODO(paulberry,ahe): would it make sense to replicate this behavior
+      // in fasta, or move it elsewhere in analyzer?
+      charOffset--;
+    }
+    reportError(errorCode, charOffset, arguments);
+  }
+
+  var errorCode = token.errorCode;
+  switch (errorCode) {
+    case ErrorKind.UnterminatedString:
+      // TODO(paulberry,ahe): Fasta reports the error location as the entire
+      // string; analyzer expects the end of the string.
+      charOffset = endOffset;
+      return _makeError(
+          analyzer.ScannerErrorCode.UNTERMINATED_STRING_LITERAL, null);
+    case ErrorKind.UnmatchedToken:
+      return null;
+    case ErrorKind.UnterminatedComment:
+      // TODO(paulberry,ahe): Fasta reports the error location as the entire
+      // comment; analyzer expects the end of the comment.
+      charOffset = endOffset;
+      return _makeError(
+          analyzer.ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT, null);
+    case ErrorKind.MissingExponent:
+      // TODO(paulberry,ahe): Fasta reports the error location as the entire
+      // number; analyzer expects the end of the number.
+      charOffset = endOffset;
+      return _makeError(analyzer.ScannerErrorCode.MISSING_DIGIT, null);
+    case ErrorKind.ExpectedHexDigit:
+      // TODO(paulberry,ahe): Fasta reports the error location as the entire
+      // number; analyzer expects the end of the number.
+      charOffset = endOffset;
+      return _makeError(analyzer.ScannerErrorCode.MISSING_HEX_DIGIT, null);
+    case ErrorKind.NonAsciiIdentifier:
+    case ErrorKind.NonAsciiWhitespace:
+      return _makeError(
+          analyzer.ScannerErrorCode.ILLEGAL_CHARACTER, [token.character]);
+    case ErrorKind.UnexpectedDollarInString:
+      return null;
+    default:
+      throw new UnimplementedError('$errorCode');
+  }
+}
+
+analyzer.Token toAnalyzerToken(Token token,
+    [analyzer.CommentToken commentToken]) {
+  if (token == null) return null;
+  analyzer.Token makeStringToken(TokenType tokenType) {
+    if (commentToken == null) {
+      return new analyzer.StringToken(tokenType, token.value, token.charOffset);
+    } else {
+      return new analyzer.StringTokenWithComment(
+          tokenType, token.value, token.charOffset, commentToken);
+    }
+  }
+
+  analyzer.Token makeBeginToken(TokenType tokenType) {
+    if (commentToken == null) {
+      return new analyzer.BeginToken(tokenType, token.charOffset);
+    } else {
+      return new analyzer.BeginTokenWithComment(
+          tokenType, token.charOffset, commentToken);
+    }
+  }
+
+  switch (token.kind) {
+    case DOUBLE_TOKEN:
+      return makeStringToken(TokenType.DOUBLE);
+
+    case HEXADECIMAL_TOKEN:
+      return makeStringToken(TokenType.HEXADECIMAL);
+
+    case IDENTIFIER_TOKEN:
+      return makeStringToken(TokenType.IDENTIFIER);
+
+    case INT_TOKEN:
+      return makeStringToken(TokenType.INT);
+
+    case KEYWORD_TOKEN:
+      KeywordToken keywordToken = token;
+      var syntax = keywordToken.keyword.syntax;
+      if (keywordToken.keyword.isPseudo) {
+        // TODO(paulberry,ahe): Fasta considers "deferred" be a "pseudo-keyword"
+        // (ordinary identifier which has special meaning under circumstances),
+        // but analyzer and the spec consider it to be a built-in identifier
+        // (identifier which can't be used in type names).
+        if (!identical(syntax, 'deferred')) {
+          return makeStringToken(TokenType.IDENTIFIER);
+        }
+      }
+      // TODO(paulberry): if the map lookup proves to be too slow, consider
+      // using a switch statement, or perhaps a string of
+      // "if (identical(syntax, "foo"))" checks.  (Note that identical checks
+      // should be safe because the Fasta scanner uses string literals for
+      // the values of keyword.syntax.)
+      var keyword =
+          _keywordMap[syntax] ?? internalError('Unknown keyword: $syntax');
+      if (commentToken == null) {
+        return new analyzer.KeywordToken(keyword, token.charOffset);
+      } else {
+        return new analyzer.KeywordTokenWithComment(
+            keyword, token.charOffset, commentToken);
+      }
+      break;
+
+    case STRING_TOKEN:
+      return makeStringToken(TokenType.STRING);
+
+    case OPEN_CURLY_BRACKET_TOKEN:
+    case OPEN_SQUARE_BRACKET_TOKEN:
+    case OPEN_PAREN_TOKEN:
+    case STRING_INTERPOLATION_TOKEN:
+      return makeBeginToken(getTokenType(token));
+
+    default:
+      if (commentToken == null) {
+        return new analyzer.Token(getTokenType(token), token.charOffset);
+      } else {
+        return new analyzer.TokenWithComment(
+            getTokenType(token), token.charOffset, commentToken);
+      }
+      break;
+  }
+}
+
+final _keywordMap = {
+  "assert": analyzer.Keyword.ASSERT,
+  "break": analyzer.Keyword.BREAK,
+  "case": analyzer.Keyword.CASE,
+  "catch": analyzer.Keyword.CATCH,
+  "class": analyzer.Keyword.CLASS,
+  "const": analyzer.Keyword.CONST,
+  "continue": analyzer.Keyword.CONTINUE,
+  "default": analyzer.Keyword.DEFAULT,
+  "do": analyzer.Keyword.DO,
+  "else": analyzer.Keyword.ELSE,
+  "enum": analyzer.Keyword.ENUM,
+  "extends": analyzer.Keyword.EXTENDS,
+  "false": analyzer.Keyword.FALSE,
+  "final": analyzer.Keyword.FINAL,
+  "finally": analyzer.Keyword.FINALLY,
+  "for": analyzer.Keyword.FOR,
+  "if": analyzer.Keyword.IF,
+  "in": analyzer.Keyword.IN,
+  "new": analyzer.Keyword.NEW,
+  "null": analyzer.Keyword.NULL,
+  "rethrow": analyzer.Keyword.RETHROW,
+  "return": analyzer.Keyword.RETURN,
+  "super": analyzer.Keyword.SUPER,
+  "switch": analyzer.Keyword.SWITCH,
+  "this": analyzer.Keyword.THIS,
+  "throw": analyzer.Keyword.THROW,
+  "true": analyzer.Keyword.TRUE,
+  "try": analyzer.Keyword.TRY,
+  "var": analyzer.Keyword.VAR,
+  "void": analyzer.Keyword.VOID,
+  "while": analyzer.Keyword.WHILE,
+  "with": analyzer.Keyword.WITH,
+  "is": analyzer.Keyword.IS,
+  "abstract": analyzer.Keyword.ABSTRACT,
+  "as": analyzer.Keyword.AS,
+  "covariant": analyzer.Keyword.COVARIANT,
+  "dynamic": analyzer.Keyword.DYNAMIC,
+  "export": analyzer.Keyword.EXPORT,
+  "external": analyzer.Keyword.EXTERNAL,
+  "factory": analyzer.Keyword.FACTORY,
+  "get": analyzer.Keyword.GET,
+  "implements": analyzer.Keyword.IMPLEMENTS,
+  "import": analyzer.Keyword.IMPORT,
+  "library": analyzer.Keyword.LIBRARY,
+  "operator": analyzer.Keyword.OPERATOR,
+  "part": analyzer.Keyword.PART,
+  "set": analyzer.Keyword.SET,
+  "static": analyzer.Keyword.STATIC,
+  "typedef": analyzer.Keyword.TYPEDEF,
+  "deferred": analyzer.Keyword.DEFERRED,
+};
+
+TokenType getTokenType(Token token) {
+  switch (token.kind) {
+    case EOF_TOKEN: return TokenType.EOF;
+    case DOUBLE_TOKEN: return TokenType.DOUBLE;
+    case HEXADECIMAL_TOKEN: return TokenType.HEXADECIMAL;
+    case IDENTIFIER_TOKEN: return TokenType.IDENTIFIER;
+    case INT_TOKEN: return TokenType.INT;
+    case KEYWORD_TOKEN: return TokenType.KEYWORD;
+    // case MULTI_LINE_COMMENT_TOKEN: return TokenType.MULTI_LINE_COMMENT;
+    // case SCRIPT_TAG_TOKEN: return TokenType.SCRIPT_TAG;
+    // case SINGLE_LINE_COMMENT_TOKEN: return TokenType.SINGLE_LINE_COMMENT;
+    case STRING_TOKEN: return TokenType.STRING;
+    case AMPERSAND_TOKEN: return TokenType.AMPERSAND;
+    case AMPERSAND_AMPERSAND_TOKEN: return TokenType.AMPERSAND_AMPERSAND;
+    // case AMPERSAND_AMPERSAND_EQ_TOKEN:
+    //   return TokenType.AMPERSAND_AMPERSAND_EQ;
+    case AMPERSAND_EQ_TOKEN: return TokenType.AMPERSAND_EQ;
+    case AT_TOKEN: return TokenType.AT;
+    case BANG_TOKEN: return TokenType.BANG;
+    case BANG_EQ_TOKEN: return TokenType.BANG_EQ;
+    case BAR_TOKEN: return TokenType.BAR;
+    case BAR_BAR_TOKEN: return TokenType.BAR_BAR;
+    // case BAR_BAR_EQ_TOKEN: return TokenType.BAR_BAR_EQ;
+    case BAR_EQ_TOKEN: return TokenType.BAR_EQ;
+    case COLON_TOKEN: return TokenType.COLON;
+    case COMMA_TOKEN: return TokenType.COMMA;
+    case CARET_TOKEN: return TokenType.CARET;
+    case CARET_EQ_TOKEN: return TokenType.CARET_EQ;
+    case CLOSE_CURLY_BRACKET_TOKEN: return TokenType.CLOSE_CURLY_BRACKET;
+    case CLOSE_PAREN_TOKEN: return TokenType.CLOSE_PAREN;
+    case CLOSE_SQUARE_BRACKET_TOKEN: return TokenType.CLOSE_SQUARE_BRACKET;
+    case EQ_TOKEN: return TokenType.EQ;
+    case EQ_EQ_TOKEN: return TokenType.EQ_EQ;
+    case FUNCTION_TOKEN: return TokenType.FUNCTION;
+    case GT_TOKEN: return TokenType.GT;
+    case GT_EQ_TOKEN: return TokenType.GT_EQ;
+    case GT_GT_TOKEN: return TokenType.GT_GT;
+    case GT_GT_EQ_TOKEN: return TokenType.GT_GT_EQ;
+    case HASH_TOKEN: return TokenType.HASH;
+    case INDEX_TOKEN: return TokenType.INDEX;
+    case INDEX_EQ_TOKEN: return TokenType.INDEX_EQ;
+    // case IS_TOKEN: return TokenType.IS;
+    case LT_TOKEN: return TokenType.LT;
+    case LT_EQ_TOKEN: return TokenType.LT_EQ;
+    case LT_LT_TOKEN: return TokenType.LT_LT;
+    case LT_LT_EQ_TOKEN: return TokenType.LT_LT_EQ;
+    case MINUS_TOKEN: return TokenType.MINUS;
+    case MINUS_EQ_TOKEN: return TokenType.MINUS_EQ;
+    case MINUS_MINUS_TOKEN: return TokenType.MINUS_MINUS;
+    case OPEN_CURLY_BRACKET_TOKEN: return TokenType.OPEN_CURLY_BRACKET;
+    case OPEN_PAREN_TOKEN: return TokenType.OPEN_PAREN;
+    case OPEN_SQUARE_BRACKET_TOKEN: return TokenType.OPEN_SQUARE_BRACKET;
+    case PERCENT_TOKEN: return TokenType.PERCENT;
+    case PERCENT_EQ_TOKEN: return TokenType.PERCENT_EQ;
+    case PERIOD_TOKEN: return TokenType.PERIOD;
+    case PERIOD_PERIOD_TOKEN: return TokenType.PERIOD_PERIOD;
+    case PLUS_TOKEN: return TokenType.PLUS;
+    case PLUS_EQ_TOKEN: return TokenType.PLUS_EQ;
+    case PLUS_PLUS_TOKEN: return TokenType.PLUS_PLUS;
+    case QUESTION_TOKEN: return TokenType.QUESTION;
+    case QUESTION_PERIOD_TOKEN: return TokenType.QUESTION_PERIOD;
+    case QUESTION_QUESTION_TOKEN: return TokenType.QUESTION_QUESTION;
+    case QUESTION_QUESTION_EQ_TOKEN: return TokenType.QUESTION_QUESTION_EQ;
+    case SEMICOLON_TOKEN: return TokenType.SEMICOLON;
+    case SLASH_TOKEN: return TokenType.SLASH;
+    case SLASH_EQ_TOKEN: return TokenType.SLASH_EQ;
+    case STAR_TOKEN: return TokenType.STAR;
+    case STAR_EQ_TOKEN: return TokenType.STAR_EQ;
+    case STRING_INTERPOLATION_TOKEN:
+      return TokenType.STRING_INTERPOLATION_EXPRESSION;
+    case STRING_INTERPOLATION_IDENTIFIER_TOKEN:
+      return TokenType.STRING_INTERPOLATION_IDENTIFIER;
+    case TILDE_TOKEN: return TokenType.TILDE;
+    case TILDE_SLASH_TOKEN: return TokenType.TILDE_SLASH;
+    case TILDE_SLASH_EQ_TOKEN: return TokenType.TILDE_SLASH_EQ;
+    case BACKPING_TOKEN: return TokenType.BACKPING;
+    case BACKSLASH_TOKEN: return TokenType.BACKSLASH;
+    case PERIOD_PERIOD_PERIOD_TOKEN: return TokenType.PERIOD_PERIOD_PERIOD;
+    // case GENERIC_METHOD_TYPE_LIST_TOKEN:
+    //   return TokenType.GENERIC_METHOD_TYPE_LIST;
+    // case GENERIC_METHOD_TYPE_ASSIGN_TOKEN:
+    //   return TokenType.GENERIC_METHOD_TYPE_ASSIGN;
+    default:
+      return internalError("Unhandled token ${token.info}");
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/ast_kind.dart b/pkg/front_end/lib/src/fasta/ast_kind.dart
new file mode 100644
index 0000000..e636942
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/ast_kind.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.ast_kind;
+
+enum AstKind {
+  Analyzer,
+  Kernel,
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/compile.dart b/pkg/front_end/lib/src/fasta/bin/compile.dart
new file mode 100644
index 0000000..65b2373
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/compile.dart
@@ -0,0 +1,16 @@
+// 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:front_end/src/fasta/outline.dart' as outline;
+
+const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
+
+main(List<String> arguments) async {
+  for (int i = 0; i < iterations; i++) {
+    if (i > 0) {
+      print("\n");
+    }
+    await outline.compile(arguments);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/compile_platform.dart b/pkg/front_end/lib/src/fasta/bin/compile_platform.dart
new file mode 100644
index 0000000..93205c4
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/compile_platform.dart
@@ -0,0 +1,16 @@
+// 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:front_end/src/fasta/compile_platform.dart' as compile_platform;
+
+const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
+
+main(List<String> arguments) async {
+  for (int i = 0; i < iterations; i++) {
+    if (i > 0) {
+      print("\n");
+    }
+    await compile_platform.main(arguments);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/generate_dart_libraries.dart b/pkg/front_end/lib/src/fasta/bin/generate_dart_libraries.dart
new file mode 100644
index 0000000..6071707
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/generate_dart_libraries.dart
@@ -0,0 +1,15 @@
+// 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:sdk_library_metadata/libraries.dart' show
+    LibraryInfo,
+    libraries;
+
+void main(_) {
+  libraries.forEach((String name, LibraryInfo info) {
+    if (info.isVmLibrary) {
+      print('"$name": sdk.resolve("lib/${info.path}"),');
+    }
+  });
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/kompile.dart b/pkg/front_end/lib/src/fasta/bin/kompile.dart
new file mode 100644
index 0000000..96e09a6
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/kompile.dart
@@ -0,0 +1,16 @@
+// 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:front_end/src/fasta/outline.dart' as outline;
+
+const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
+
+main(List<String> arguments) async {
+  for (int i = 0; i < iterations; i++) {
+    if (i > 0) {
+      print("\n");
+    }
+    await outline.kompile(arguments);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/log_analyzer.dart b/pkg/front_end/lib/src/fasta/bin/log_analyzer.dart
new file mode 100644
index 0000000..c9dba29
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/log_analyzer.dart
@@ -0,0 +1,38 @@
+// 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:convert' show
+    JSON;
+
+import 'dart:io';
+
+import 'package:testing/src/run_tests.dart' show
+    CommandLine;
+
+main(List<String> arguments) async {
+  CommandLine cl = CommandLine.parse(arguments);
+  Set<String> fields = cl.commaSeparated("--fields=");
+  if (fields.isEmpty) {
+    fields.addAll(["uri", "offset", "json:error"]);
+  }
+  for (String filename in cl.arguments) {
+    String json = await new File(filename).readAsString();
+    Map<String, dynamic> data = JSON.decode(json) as Map<String, dynamic>;
+    StringBuffer sb = new StringBuffer();
+    bool isFirst = true;
+    for (String field in fields) {
+      if (!isFirst) {
+        sb.write(":");
+      }
+      if (field.startsWith("json:")) {
+        field = field.substring(5);
+        sb.write(JSON.encode(data[field]));
+      } else {
+        sb.write(data[field]);
+      }
+      isFirst = false;
+    }
+    print("$sb");
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/log_collector.dart b/pkg/front_end/lib/src/fasta/bin/log_collector.dart
new file mode 100644
index 0000000..50d4a76
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/log_collector.dart
@@ -0,0 +1,114 @@
+// 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:convert' show
+    JSON,
+    UTF8;
+
+import 'dart:isolate' show
+    RawReceivePort;
+
+import 'dart:io';
+
+import 'package:front_end/src/fasta/errors.dart' show
+    defaultServerAddress;
+
+badRequest(HttpRequest request, int status, String message) {
+  request.response.statusCode = status;
+  request.response.write('''
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>$message</title>
+  </head>
+  <body>
+    <h1>$message</h1>
+  </body>
+</html>
+''');
+  request.response.close().catchError((e, s) {
+    print("Request error: $e.");
+  });
+  print("${request.uri}: $message");
+}
+
+collectLog(DateTime time, HttpRequest request) async {
+  String json = await request.transform(UTF8.decoder).join();
+  var data;
+  try {
+    data = JSON.decode(json);
+  } on FormatException catch (e) {
+    print(e);
+    return badRequest(request, HttpStatus.BAD_REQUEST,
+        "Malformed JSON data: ${e.message}.");
+  }
+  if (data is! Map) {
+    return badRequest(request, HttpStatus.BAD_REQUEST,
+        "Malformed JSON data: not a map.");
+  }
+  if (data["type"] != "crash") {
+    return badRequest(request, HttpStatus.BAD_REQUEST,
+        "Malformed JSON data: type should be 'crash'.");
+  }
+  request.response.close();
+  String year = "${time.year}".padLeft(4, "0");
+  String month = "${time.month}".padLeft(2, "0");
+  String day = "${time.day}".padLeft(2, "0");
+  String us = "${time.microsecondsSinceEpoch}".padLeft(19, '0');
+  Uri uri = Uri.base.resolve(
+      "crash_logs/${data['client']}/$year-$month-$day/$us.log");
+  File file = new File.fromUri(uri);
+  await file.parent.create(recursive: true);
+  await file.writeAsString(json);
+  print("Wrote ${uri.toFilePath()}");
+
+  String type = data["type"];
+  String text = data["uri"];
+  uri = text == null ? null : Uri.parse(text);
+  int charOffset = data["offset"];
+  var error = data["error"];
+  text = data["trace"];
+  StackTrace trace = text == null ? null : new StackTrace.fromString(text);
+  String client = data["client"];
+  print("""
+date: ${time}
+type: $type
+client: $client
+uri: $uri
+offset: $charOffset
+error:
+$error
+trace:
+$trace
+""");
+}
+
+main(List<String> arguments) async {
+  RawReceivePort keepAlive = new RawReceivePort();
+  Uri uri;
+  if (arguments.length == 1) {
+    uri = Uri.base.resolve(arguments.single);
+  } else if (arguments.length == 0) {
+    uri = Uri.parse(defaultServerAddress);
+  } else {
+    throw "Unexpected arguments: ${arguments.join(' ')}.";
+  }
+  int port = uri.hasPort ? uri.port : 0;
+  var host = uri.host.isEmpty ? InternetAddress.LOOPBACK_IP_V4 : uri.host;
+  HttpServer server = await HttpServer.bind(host, port);
+  print("Listening on http://${server.address.host}:${server.port}/");
+  await for (HttpRequest request in server) {
+    if (request.method != "POST") {
+      badRequest(request, HttpStatus.METHOD_NOT_ALLOWED, "Not allowed.");
+      continue;
+    }
+    if (request.uri.path != "/") {
+      badRequest(request, HttpStatus.NOT_FOUND, "Not found.");
+      continue;
+    }
+    collectLog(new DateTime.now(), request);
+  }
+  keepAlive.close();
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/outline.dart b/pkg/front_end/lib/src/fasta/bin/outline.dart
new file mode 100644
index 0000000..faa54a7
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/outline.dart
@@ -0,0 +1,16 @@
+// 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:front_end/src/fasta/outline.dart' as outline;
+
+const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
+
+main(List<String> arguments) async {
+  for (int i = 0; i < iterations; i++) {
+    if (i > 0) {
+      print("\n");
+    }
+    await outline.outline(arguments);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/bin/run.dart b/pkg/front_end/lib/src/fasta/bin/run.dart
new file mode 100644
index 0000000..94bcc91
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/bin/run.dart
@@ -0,0 +1,48 @@
+// 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:io' show
+    exit,
+    exitCode;
+
+import 'package:front_end/src/fasta/ast_kind.dart' show
+    AstKind;
+
+import 'package:front_end/src/fasta/compiler_command_line.dart' show
+    CompilerCommandLine;
+
+import 'package:front_end/src/fasta/outline.dart' show
+    doCompile,
+    parseArguments;
+
+import 'package:front_end/src/fasta/errors.dart' show
+    InputError;
+
+import 'package:front_end/src/fasta/run.dart' show
+    run;
+
+import 'package:front_end/src/fasta/ticker.dart' show
+    Ticker;
+
+const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
+
+main(List<String> arguments) async {
+  Uri uri;
+  CompilerCommandLine cl;
+  for (int i = 0; i < iterations; i++) {
+    if (i > 0) {
+      print("\n");
+    }
+    try {
+      cl = parseArguments("run", arguments);
+      uri =
+          await doCompile(cl, new Ticker(isVerbose:cl.verbose), AstKind.Kernel);
+    } on InputError catch (e) {
+      print(e.format());
+      exit(1);
+    }
+    if (exitCode != 0) exit(exitCode);
+  }
+  exit(await run(uri, cl));
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/README.md b/pkg/front_end/lib/src/fasta/builder/README.md
new file mode 100644
index 0000000..970ec46
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/README.md
@@ -0,0 +1,12 @@
+<!--
+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.
+-->
+# Builder
+
+A program element is any part of a program excluding method bodies (but including local variables). Examples of program elements includes classes, methods, typedefs, etc.
+
+A builder is a representation of a program element that is being constructed, either from source or dill file.
+
+The builders in this directory are supposed to capture the common behavior shared between builders specific for source or dill.
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
new file mode 100644
index 0000000..322179a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.builder;
+
+import '../errors.dart' show
+    internalError;
+
+export 'class_builder.dart' show
+    ClassBuilder;
+
+export 'field_builder.dart' show
+    FieldBuilder;
+
+export 'library_builder.dart' show
+    LibraryBuilder;
+
+export 'procedure_builder.dart' show
+    ProcedureBuilder;
+
+export 'type_builder.dart' show
+    TypeBuilder;
+
+export 'formal_parameter_builder.dart' show
+    FormalParameterBuilder;
+
+export 'metadata_builder.dart' show
+    MetadataBuilder;
+
+export 'type_variable_builder.dart' show
+    TypeVariableBuilder;
+
+export 'function_type_alias_builder.dart' show
+    FunctionTypeAliasBuilder;
+
+export 'named_mixin_application_builder.dart' show
+    NamedMixinApplicationBuilder;
+
+export 'mixin_application_builder.dart' show
+    MixinApplicationBuilder;
+
+export 'enum_builder.dart' show
+    EnumBuilder;
+
+export 'type_declaration_builder.dart' show
+    TypeDeclarationBuilder;
+
+export 'named_type_builder.dart' show
+    NamedTypeBuilder;
+
+export 'constructor_reference_builder.dart' show
+    ConstructorReferenceBuilder;
+
+export '../source/unhandled_listener.dart' show
+    Unhandled;
+
+export 'member_builder.dart' show
+    MemberBuilder;
+
+export 'modifier_builder.dart' show
+    ModifierBuilder;
+
+export 'prefix_builder.dart' show
+    PrefixBuilder;
+
+export 'invalid_type_builder.dart' show
+    InvalidTypeBuilder;
+
+export 'mixed_accessor.dart' show
+    MixedAccessor;
+
+export 'scope.dart' show
+    AccessErrorBuilder;
+
+export 'dynamic_type_builder.dart' show
+    DynamicTypeBuilder;
+
+import 'library_builder.dart' show
+    LibraryBuilder;
+
+abstract class Builder {
+  /// Used when multiple things with the same name are declared within the same
+  /// parent. Only used for declarations, not for scopes.
+  ///
+  // TODO(ahe): Move to member builder or something. Then we can make
+  // this a const class.
+  Builder next;
+
+  /// The values of [parent], [charOffset], and [fileUri] aren't stored. We
+  /// need to evaluate the memory impact of doing so, but want to ensure the
+  /// information is always provided.
+  Builder(Builder parent, int charOffset, Uri fileUri);
+
+  int get charOffset => -1;
+
+  Uri get fileUri => null;
+
+  /// Resolve types (lookup names in scope) recorded in this builder and return
+  /// the number of types resolved.
+  int resolveTypes(covariant Builder parent) => 0;
+
+  /// Resolve constructors (lookup names in scope) recorded in this builder and
+  /// return the number of constructors resolved.
+  int resolveConstructors(covariant Builder parent) => 0;
+
+  /// This builder and [other] has been imported into [library] using [name].
+  ///
+  /// This method handles this case according to the Dart language
+  /// specification.
+  Builder combineAmbiguousImport(String name, Builder other,
+      LibraryBuilder library) {
+    if (other == this) return this;
+    bool isLocal = false;
+    Builder preferred;
+    Builder hidden;
+    if (library.members[name] == this) {
+      isLocal = true;
+      preferred = this;
+      hidden = other;
+    } else if (getUri(other)?.scheme == "dart" &&
+        getUri(this)?.scheme != "dart") {
+      preferred = this;
+      hidden = other;
+    } else if (getUri(this)?.scheme == "dart" &&
+        getUri(other)?.scheme != "dart") {
+      preferred = other;
+      hidden = this;
+    } else {
+      print("${library.uri}: Note: '$name' is imported from both "
+          "'${getUri(this)}' and '${getUri(other)}'.");
+      return library.buildAmbiguousBuilder(name, this, other, charOffset);
+    }
+    if (isLocal) {
+      print("${library.uri}: Note: local definition of '$name' hides imported "
+          "version from '${getUri(other)}'.");
+    } else {
+      print("${library.uri}: import of '$name' (from '${getUri(preferred)}') "
+          "hides imported version from '${getUri(hidden)}'.");
+    }
+    return preferred;
+  }
+
+  Builder get parent => null;
+
+  bool get isFinal => false;
+
+  bool get isField => false;
+
+  bool get isRegularMethod => false;
+
+  bool get isGetter => false;
+
+  bool get isSetter => false;
+
+  bool get isInstanceMember => false;
+
+  bool get isStatic => false;
+
+  bool get isTopLevel => false;
+
+  bool get isTypeDeclaration => false;
+
+  bool get isConstructor => false;
+
+  bool get isFactory => false;
+
+  bool get isLocal => false;
+
+  get target => internalError("Unsupported operation $runtimeType.");
+
+  bool get hasProblem => false;
+
+  static Uri getUri(Builder builder) {
+    if (builder == null) return internalError("Builder is null.");
+    while (builder != null) {
+      if (builder is LibraryBuilder) return builder.uri;
+      builder = builder.parent;
+    }
+    return internalError("No library parent.");
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
new file mode 100644
index 0000000..926a708
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.class_builder;
+
+import 'builder.dart' show
+    Builder,
+    ConstructorReferenceBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder,
+    TypeVariableBuilder;
+
+import 'scope.dart' show
+    AmbiguousBuilder,
+    Scope;
+
+abstract class ClassBuilder<T extends TypeBuilder, R>
+    extends TypeDeclarationBuilder<T, R> {
+  final List<TypeVariableBuilder> typeVariables;
+
+  T supertype;
+
+  List<T> interfaces;
+
+  final Map<String, Builder> members;
+
+  ClassBuilder(
+      List<MetadataBuilder> metadata, int modifiers,
+      String name, this.typeVariables, this.supertype, this.interfaces,
+      this.members, LibraryBuilder parent, int charOffset)
+      : super(metadata, modifiers, name, parent, charOffset);
+
+  List<ConstructorReferenceBuilder> get constructorReferences => null;
+
+  Map<String, Builder> get constructors;
+
+  Map<String, Builder> get membersInScope => members;
+
+  int resolveConstructors(LibraryBuilder library) {
+    if (constructorReferences == null) return 0;
+    Scope scope = computeInstanceScope(library.scope);
+    for (ConstructorReferenceBuilder ref in constructorReferences) {
+      ref.resolveIn(scope);
+    }
+    return constructorReferences.length;
+  }
+
+  Scope computeInstanceScope(Scope parent) {
+    if (typeVariables != null) {
+      Map<String, Builder> local = <String, Builder>{};
+      for (TypeVariableBuilder t in typeVariables) {
+        local[t.name] = t;
+      }
+      parent = new Scope(local, parent, isModifiable: false);
+    }
+    return new Scope(membersInScope, parent, isModifiable: false);
+  }
+
+  /// Used to lookup a static member of this class.
+  Builder findStaticBuilder(String name, int charOffset, Uri fileUri,
+      {bool isSetter: false}) {
+    Builder builder = members[name];
+    if (builder?.next != null) {
+      Builder getterBuilder;
+      Builder setterBuilder;
+      Builder current = builder;
+      while (current != null) {
+        if (current.isGetter && getterBuilder == null) {
+          getterBuilder = current;
+        } else if (current.isSetter && setterBuilder == null) {
+          setterBuilder = current;
+        } else {
+          return new AmbiguousBuilder(builder, charOffset, fileUri);
+        }
+        current = current.next;
+      }
+      builder = isSetter ? setterBuilder : getterBuilder;
+    }
+    if (builder == null) {
+      return null;
+    } else if (isSetter && builder.isGetter) {
+      return null;
+    } else {
+      return builder.isInstanceMember ? null : builder;
+    }
+  }
+
+  Builder findConstructorOrFactory(String name);
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
new file mode 100644
index 0000000..019fb4c
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.constructor_reference_builder;
+
+import 'builder.dart' show
+    PrefixBuilder,
+    ClassBuilder,
+    Builder,
+    TypeBuilder;
+
+import 'scope.dart' show
+    Scope;
+
+class ConstructorReferenceBuilder extends Builder {
+  final String name;
+
+  final List<TypeBuilder> typeArguments;
+
+  /// This is the name of a named constructor. As `bar` in `new Foo<T>.bar()`.
+  final String suffix;
+
+  Builder target;
+
+  ConstructorReferenceBuilder(this.name, this.typeArguments, this.suffix,
+      Builder parent, int charOffset)
+      : super(parent, charOffset, parent.fileUri);
+
+  String get fullNameForErrors => "$name${suffix == null ? '' : '.$suffix'}";
+
+  void resolveIn(Scope scope) {
+    int index = name.indexOf(".");
+    Builder builder;
+    if (index == -1) {
+      builder = scope.lookup(name, charOffset, fileUri);
+    } else {
+      String prefix = name.substring(0, index);
+      String middle = name.substring(index + 1);
+      builder = scope.lookup(prefix, charOffset, fileUri);
+      if (builder is PrefixBuilder) {
+        PrefixBuilder prefix = builder;
+        builder = prefix.exports[middle];
+      } else if (builder is ClassBuilder) {
+        ClassBuilder cls = builder;
+        builder = cls.constructors[middle];
+        if (suffix == null) {
+          target = builder;
+          return;
+        }
+      }
+    }
+    if (builder is ClassBuilder) {
+      target = builder.constructors[suffix ?? ""];
+    }
+    if (target == null) {
+      print("Couldn't find constructor $fullNameForErrors.");
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart
new file mode 100644
index 0000000..630a412
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart
@@ -0,0 +1,22 @@
+// 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 fasta.dynamic_type_builder;
+
+import 'builder.dart' show
+    LibraryBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder;
+
+class DynamicTypeBuilder<T extends TypeBuilder, R>
+    extends TypeDeclarationBuilder<T, R> {
+  final R type;
+
+  DynamicTypeBuilder(this.type, LibraryBuilder compilationUnit, int charOffset)
+      : super(null, 0, "dynamic", compilationUnit, charOffset);
+
+  R buildType(List<T> arguments) => type;
+
+  R buildTypesWithBuiltArguments(List<R> arguments) => type;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
new file mode 100644
index 0000000..eca03a2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.enum_builder;
+
+import 'builder.dart' show
+    ClassBuilder,
+    TypeBuilder;
+
+abstract class EnumBuilder<T extends TypeBuilder, R>
+    implements ClassBuilder<T, R> {
+  List<String> get constants;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
new file mode 100644
index 0000000..1fdd6e6
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.field_builder;
+
+import 'builder.dart' show
+    LibraryBuilder,
+    MemberBuilder;
+
+abstract class FieldBuilder<T> extends MemberBuilder {
+  final String name;
+
+  final int modifiers;
+
+  FieldBuilder(this.name, this.modifiers, LibraryBuilder compilationUnit,
+      int charOffset)
+      : super(compilationUnit, charOffset);
+
+  void set initializer(T value);
+
+  bool get isField => true;
+}
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
new file mode 100644
index 0000000..df8cf94
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.formal_parameter_builder;
+
+import 'package:front_end/src/fasta/parser/parser.dart' show
+    FormalParameterType;
+
+import 'builder.dart' show
+    LibraryBuilder,
+    MetadataBuilder,
+    ModifierBuilder,
+    TypeBuilder;
+
+abstract class FormalParameterBuilder<T extends TypeBuilder>
+    extends ModifierBuilder {
+  final List<MetadataBuilder> metadata;
+
+  final int modifiers;
+
+  final T type;
+
+  final String name;
+
+  /// True if this parameter is on the form `this.name`.
+  final bool hasThis;
+
+  FormalParameterType kind = FormalParameterType.REQUIRED;
+
+  FormalParameterBuilder(this.metadata, this.modifiers, this.type, this.name,
+      this.hasThis, LibraryBuilder compilationUnit, int charOffset)
+      : super(compilationUnit, charOffset);
+
+  bool get isRequired => kind.isRequired;
+
+  bool get isPositional => kind.isPositional || kind.isRequired;
+
+  bool get isNamed => kind.isNamed;
+
+  bool get isOptional => !isRequired;
+
+  bool get isLocal => true;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/function_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_type_alias_builder.dart
new file mode 100644
index 0000000..6f5c794
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/function_type_alias_builder.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.function_type_alias_builder;
+
+import 'builder.dart' show
+    FormalParameterBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder,
+    TypeVariableBuilder;
+
+abstract class FunctionTypeAliasBuilder<T extends TypeBuilder, R>
+    extends TypeDeclarationBuilder<T, R> {
+  final T returnType;
+
+  final List<TypeVariableBuilder> typeVariables;
+
+  final List<FormalParameterBuilder> formals;
+
+  FunctionTypeAliasBuilder(
+      List<MetadataBuilder> metadata, this.returnType,
+      String name, this.typeVariables, this.formals,
+      LibraryBuilder parent, int charOffset)
+      : super(metadata, null, name, parent, charOffset);
+
+  LibraryBuilder get parent => super.parent;
+}
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
new file mode 100644
index 0000000..e232eca
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.invalid_type_builder;
+
+import 'builder.dart' show
+    Builder,
+    TypeBuilder,
+    TypeDeclarationBuilder;
+
+abstract class InvalidTypeBuilder<T extends TypeBuilder, R>
+    extends TypeDeclarationBuilder<T, R> {
+  InvalidTypeBuilder(String name, Builder parent, int charOffset, [Uri fileUri])
+      : super(null, 0, name, parent, charOffset, fileUri);
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
new file mode 100644
index 0000000..bf2eb92
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.library_builder;
+
+import '../combinator.dart' show
+    Combinator;
+
+import '../errors.dart' show
+    InputError,
+    internalError;
+
+import '../export.dart' show
+    Export;
+
+import '../loader.dart' show
+    Loader;
+
+import 'builder.dart' show
+    Builder,
+    ClassBuilder,
+    TypeBuilder;
+
+import 'scope.dart' show
+   Scope;
+
+abstract class LibraryBuilder<T extends TypeBuilder, R> extends Builder {
+  final List<Export> exporters = <Export>[];
+
+  final List<InputError> compileTimeErrors = <InputError>[];
+
+  LibraryBuilder partOfLibrary;
+
+  Loader get loader;
+
+  Uri get uri;
+
+  Uri get fileUri;
+
+  Map<String, Builder> get members;
+
+  // TODO(ahe): Move this to SourceLibraryBuilder.
+  Scope get scope;
+
+  Map<String, Builder> get exports;
+
+  LibraryBuilder(Uri fileUri)
+      : super(null, -1, fileUri);
+
+  Builder addBuilder(String name, Builder builder, int charOffset);
+
+  void addExporter(LibraryBuilder exporter, List<Combinator> combinators,
+      int charOffset) {
+    exporters.add(new Export(exporter, this, combinators, charOffset));
+  }
+
+  void addCompileTimeError(int charOffset, Object message, [Uri fileUri]) {
+    fileUri ??= this.fileUri;
+    InputError error = new InputError(fileUri, charOffset, message);
+    compileTimeErrors.add(error);
+    print(error.format());
+  }
+
+  bool addToExportScope(String name, Builder member);
+
+  void addToScope(String name, Builder member);
+
+  Builder buildAmbiguousBuilder(
+      String name, Builder builder, Builder other, int charOffset);
+
+  int finishStaticInvocations() => 0;
+
+  int finishNativeMethods() => 0;
+
+  /// Looks up [constructorName] in the class named [className]. It's an error
+  /// if no such class is exported by this library, or if the class doesn't
+  /// have a matching constructor (or factory).
+  ///
+  /// If [constructorName] is null or the empty string, it's assumed to be an
+  /// unnamed constructor.
+  Builder getConstructor(String className,
+      {String constructorName, bool isPrivate: false}) {
+    constructorName ??= "";
+    Builder cls = (isPrivate ? members : exports)[className];
+    if (cls is ClassBuilder) {
+      // TODO(ahe): This code is similar to code in `handleNewExpression` in
+      // `body_builder.dart`, try to share it.
+      Builder constructor = cls.findConstructorOrFactory(constructorName);
+      if (constructor == null) {
+        // Fall-through to internal error below.
+      } else if (constructor.isConstructor) {
+        if (!cls.isAbstract) {
+          return constructor;
+        }
+      } else if (constructor.isFactory) {
+        return constructor;
+      }
+    }
+    throw internalError("Internal error: No constructor named"
+        " '$className::$constructorName' in '$uri'.");
+  }
+
+  int finishTypeVariables(ClassBuilder object) => 0;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
new file mode 100644
index 0000000..608fe2d
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.member_builder;
+
+import 'builder.dart' show
+    Builder,
+    ClassBuilder,
+    ModifierBuilder;
+
+abstract class MemberBuilder extends ModifierBuilder {
+  /// For top-level members, the parent is set correctly during
+  /// construction. However, for class members, the parent is initially the
+  /// library and updated later.
+  Builder parent;
+
+  String get name;
+
+  MemberBuilder(Builder parent, int charOffset)
+      : parent = parent, super(parent, charOffset);
+
+  bool get isInstanceMember => isClassMember && !isStatic;
+
+  bool get isClassMember => parent is ClassBuilder;
+
+  bool get isTopLevel => !isClassMember;
+
+  bool get isNative => false;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
new file mode 100644
index 0000000..a060d2e
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.metadata_builder;
+
+import 'builder.dart' show
+    Builder,
+    TypeBuilder;
+
+import 'constructor_reference_builder.dart' show
+    ConstructorReferenceBuilder;
+
+abstract class MetadataBuilder<T extends TypeBuilder> extends Builder {
+  MetadataBuilder(Builder parent, int charOffset)
+      : super(parent, -1, parent.fileUri);
+
+  factory MetadataBuilder.fromConstructor(
+      ConstructorReferenceBuilder constructorReference, List arguments,
+      Builder parent, int charOffset) {
+    return new ConstructorMetadataBuilder(constructorReference, arguments,
+        parent, charOffset);
+  }
+
+  factory MetadataBuilder.fromExpression(String expression, String postfix,
+      Builder parent, int charOffset) {
+    return new ExpressionMetadataBuilder(
+        expression, postfix, parent, charOffset);
+  }
+}
+
+class ConstructorMetadataBuilder<T extends TypeBuilder>
+    extends MetadataBuilder<T> {
+  final ConstructorReferenceBuilder constructorReference;
+
+  final List arguments;
+
+  ConstructorMetadataBuilder(this.constructorReference, this.arguments,
+      Builder parent, int charOffset)
+      : super(parent, charOffset);
+}
+
+/// Expression metadata (without arguments).
+///
+/// Matches this grammar rule:
+///
+///    '@' qualified (‘.’ identifier)?
+class ExpressionMetadataBuilder<T extends TypeBuilder>
+    extends MetadataBuilder<T> {
+  final String qualified;
+
+  final String identifier;
+
+  ExpressionMetadataBuilder(this.qualified, this.identifier, Builder parent,
+      int charOffset)
+      : super(parent, charOffset);
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/mixed_accessor.dart b/pkg/front_end/lib/src/fasta/builder/mixed_accessor.dart
new file mode 100644
index 0000000..42297a6
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/mixed_accessor.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.mixed_accessor;
+
+import 'builder.dart' show
+    Builder,
+    LibraryBuilder;
+
+/// Represents the import of a getter and setter from two different libraries.
+class MixedAccessor extends Builder {
+  final Builder getter;
+  final Builder setter;
+
+  MixedAccessor(this.getter, this.setter, LibraryBuilder parent)
+      : super(parent, -1, // Synthetic element has no charOffset.
+          parent.fileUri) {
+    next = getter;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart b/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
new file mode 100644
index 0000000..e7b319693
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.mixin_application_builder;
+
+import '../errors.dart' show
+    internalError;
+
+import 'builder.dart' show
+    TypeBuilder,
+    TypeDeclarationBuilder;
+
+import 'scope.dart' show
+    Scope;
+
+abstract class MixinApplicationBuilder<T extends TypeBuilder>
+    extends TypeBuilder {
+  final T supertype;
+  final List<T> mixins;
+
+  MixinApplicationBuilder(this.supertype, this.mixins, int charOffset,
+      Uri fileUri)
+      : super(charOffset, fileUri);
+
+  String get name => null;
+
+  void resolveIn(Scope scope) {
+    supertype.resolveIn(scope);
+    for (T t in mixins) {
+      t.resolveIn(scope);
+    }
+  }
+
+  void bind(TypeDeclarationBuilder builder) {
+    internalError("Internal error: can't bind a mixin application.");
+  }
+
+  String get debugName => "MixinApplicationBuilder";
+
+  StringBuffer printOn(StringBuffer buffer) {
+    buffer.write(supertype);
+    buffer.write(" with ");
+    bool first = true;
+    for (T t in mixins) {
+      if (!first) buffer.write(", ");
+      first = false;
+      t.printOn(buffer);
+    }
+    return buffer;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
new file mode 100644
index 0000000..c60c0b3
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.modifier_builder;
+
+import '../modifier.dart' show
+    abstractMask,
+    constMask,
+    externalMask,
+    finalMask,
+    staticMask;
+
+import 'builder.dart' show
+    Builder;
+
+abstract class ModifierBuilder extends Builder {
+  ModifierBuilder(Builder parent, int charOffset, [Uri fileUri])
+      : super(parent, charOffset, fileUri ?? parent?.fileUri);
+
+  int get modifiers;
+
+  bool get isAbstract => (modifiers & abstractMask) != 0;
+
+  bool get isConst => (modifiers & constMask) != 0;
+
+  bool get isExternal => (modifiers & externalMask) != 0;
+
+  bool get isFinal => (modifiers & finalMask) != 0;
+
+  bool get isStatic => (modifiers & staticMask) != 0;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/named_mixin_application_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_mixin_application_builder.dart
new file mode 100644
index 0000000..4096fa7
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/named_mixin_application_builder.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.named_mixin_application_builder;
+
+import 'builder.dart' show
+    Builder,
+    ClassBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    TypeBuilder,
+    TypeVariableBuilder;
+
+abstract class NamedMixinApplicationBuilder<T extends TypeBuilder, R>
+    extends ClassBuilder<T, R> {
+  NamedMixinApplicationBuilder(
+      List<MetadataBuilder> metadata, String name,
+      List<TypeVariableBuilder> typeVariables, int modifiers, T supertype,
+      List<T> interfaces, LibraryBuilder parent, int charOffset)
+      : super(metadata, modifiers, name, typeVariables, supertype, interfaces,
+          <String, Builder>{}, parent, charOffset);
+
+  T get mixinApplication => supertype;
+}
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
new file mode 100644
index 0000000..deea9a8
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.interface_type_builder;
+
+import 'scope.dart' show
+    Scope;
+
+import 'builder.dart' show
+    Builder,
+    InvalidTypeBuilder,
+    PrefixBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder;
+
+abstract class NamedTypeBuilder<T extends TypeBuilder> extends TypeBuilder {
+  final String name;
+
+  final List<T> arguments;
+
+  TypeDeclarationBuilder get builder;
+
+  void set builder(covariant TypeDeclarationBuilder b);
+
+  NamedTypeBuilder(this.name, this.arguments, int charOffset, Uri fileUri)
+      : super(charOffset, fileUri);
+
+  InvalidTypeBuilder buildInvalidType(String name);
+
+  void bind(TypeDeclarationBuilder builder) {
+    this.builder = builder;
+  }
+
+  void resolveIn(Scope scope) {
+    Builder member = scope.lookup(name, charOffset, fileUri);
+    if (member is TypeDeclarationBuilder) {
+      builder = member;
+      return;
+    }
+    if (name.contains(".")) {
+      int index = name.lastIndexOf(".");
+      String first = name.substring(0, index);
+      String last = name.substring(name.lastIndexOf(".") + 1);
+      var prefix = scope.lookup(first, charOffset, fileUri);
+      if (prefix is PrefixBuilder) {
+        member = prefix.exports[last];
+      }
+      if (member is TypeDeclarationBuilder) {
+        builder = member;
+        return;
+      }
+    }
+    builder = buildInvalidType(name);
+  }
+
+  String get debugName => "NamedTypeBuilder";
+
+  StringBuffer printOn(StringBuffer buffer) {
+    buffer.write(name);
+    if (arguments == null) return buffer;
+    buffer.write("<");
+    bool first = true;
+    for (T t in arguments) {
+      if (!first) buffer.write(", ");
+      first = false;
+      t.printOn(buffer);
+    }
+    buffer.write(">");
+    return buffer;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart b/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
new file mode 100644
index 0000000..ffd32be
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.prefix_builder;
+
+import 'builder.dart' show
+    Builder,
+    LibraryBuilder,
+    MemberBuilder;
+
+import 'package:kernel/ast.dart' show
+    Member;
+
+import '../dill/dill_member_builder.dart' show
+    DillMemberBuilder;
+
+import '../errors.dart' show
+    internalError;
+
+class PrefixBuilder extends Builder {
+  final String name;
+
+  final Map<String, Builder> exports;
+
+  final LibraryBuilder parent;
+
+  PrefixBuilder(this.name, this.exports, LibraryBuilder parent, int charOffset)
+      : parent = parent, super(parent, charOffset, parent.fileUri);
+
+  Member findTopLevelMember(String name) {
+    // TODO(ahe): Move this to KernelPrefixBuilder.
+    Builder builder = exports[name];
+    if (builder == null) {
+      // TODO(ahe): Report error?
+      print("${this.name} has no member named $name");
+    }
+    if (builder is DillMemberBuilder) {
+      return builder.member.isInstanceMember
+          ? internalError("Unexpected instance member in export scope")
+          : builder.member;
+    } else if (builder is MemberBuilder) {
+      return builder.target;
+    } else {
+      return null;
+    }
+  }
+
+  Builder combineAmbiguousImport(String name, Builder other,
+      LibraryBuilder library) {
+    if (other is PrefixBuilder) {
+      /// Handles the case where the same prefix is used for different imports.
+      other.exports.forEach((String name, Builder member) {
+        Builder existing = exports[name];
+        if (existing != null) {
+          member = existing.combineAmbiguousImport(name, member, library);
+        }
+        exports[name] = member;
+      });
+      return this;
+    }
+    return super.combineAmbiguousImport(name, other, library);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
new file mode 100644
index 0000000..2d670a2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.procedure_builder;
+
+// 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;
+
+import 'builder.dart' show
+    Builder,
+    FormalParameterBuilder,
+    LibraryBuilder,
+    MemberBuilder,
+    MetadataBuilder,
+    TypeBuilder,
+    TypeVariableBuilder;
+
+import 'scope.dart' show
+    Scope;
+
+abstract class ProcedureBuilder<T extends TypeBuilder> extends MemberBuilder {
+  final List<MetadataBuilder> metadata;
+
+  final int modifiers;
+
+  final T returnType;
+
+  final String name;
+
+  final List<TypeVariableBuilder> typeVariables;
+
+  final List<FormalParameterBuilder> formals;
+
+  ProcedureBuilder(this.metadata, this.modifiers, this.returnType, this.name,
+      this.typeVariables, this.formals, LibraryBuilder compilationUnit,
+      int charOffset)
+      : super(compilationUnit, charOffset);
+
+  AsyncMarker get asyncModifier;
+
+  ProcedureKind get kind;
+
+  bool get isConstructor => false;
+
+  bool get isRegularMethod => identical(ProcedureKind.Method, kind);
+
+  bool get isGetter => identical(ProcedureKind.Getter, kind);
+
+  bool get isSetter => identical(ProcedureKind.Setter, kind);
+
+  bool get isOperator => identical(ProcedureKind.Operator, kind);
+
+  bool get isFactory => identical(ProcedureKind.Factory, kind);
+
+  void set body(covariant statement);
+
+  /// This is the formal parameter scope as specified in the Dart Programming
+  /// Language Specifiction, 4th ed, section 9.2.
+  Scope computeFormalParameterScope(Scope parent) {
+    if (formals == null) return parent;
+    Map<String, Builder> local = <String, Builder>{};
+    for (FormalParameterBuilder formal in formals) {
+      if (!formal.hasThis) {
+        local[formal.name] = formal;
+      }
+    }
+    return new Scope(local, parent, isModifiable: false);
+  }
+
+  /// This scope doesn't correspond to any scope specified in the Dart
+  /// Programming Language Specifiction, 4th ed. It's an unspecified extension
+  /// to support generic methods.
+  Scope computeTypeParameterScope(Scope parent) {
+    if (typeVariables == null) return parent;
+    Map<String, Builder> local = <String, Builder>{};
+    for (TypeVariableBuilder variable in typeVariables) {
+      local[variable.name] = variable;
+    }
+    return new Scope(local, parent, isModifiable: false);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/scope.dart b/pkg/front_end/lib/src/fasta/builder/scope.dart
new file mode 100644
index 0000000..10999a7
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/scope.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scope;
+
+import 'builder.dart' show
+    Builder,
+    MixedAccessor;
+
+import '../errors.dart' show
+    internalError;
+
+class Scope {
+  /// Names declared in this scope.
+  final Map<String, Builder> local;
+
+  /// The scope that this scope is nested within, or `null` if this is the top
+  /// level scope.
+  final Scope parent;
+
+  /// Indicates whether an attempt to declare new names in this scope should
+  /// succeed.
+  final bool isModifiable;
+
+  Scope(this.local, this.parent, {this.isModifiable: true});
+
+  Scope createNestedScope({bool isModifiable: true}) {
+    return new Scope(<String, Builder>{}, this, isModifiable: isModifiable);
+  }
+
+  Builder lookup(String name, int charOffset, Uri fileUri) {
+    Builder builder = local[name];
+    if (builder != null) {
+      if (builder.next != null) {
+        return lookupAmbiguous(name, builder, false, charOffset, fileUri);
+      }
+      return builder.isSetter
+          ? new AccessErrorBuilder(builder, charOffset, fileUri)
+          : builder;
+    } else {
+      return parent?.lookup(name, charOffset, fileUri);
+    }
+  }
+
+  Builder lookupSetter(String name, int charOffset, Uri fileUri) {
+    Builder builder = local[name];
+    if (builder != null) {
+      if (builder.next != null) {
+        return lookupAmbiguous(name, builder, true, charOffset, fileUri);
+      }
+      if (builder.isField) {
+        if (builder.isFinal) {
+          return new AccessErrorBuilder(builder, charOffset, fileUri);
+        } else {
+          return builder;
+        }
+      } else if (builder.isSetter) {
+        return builder;
+      } else {
+        return new AccessErrorBuilder(builder, charOffset, fileUri);
+      }
+    } else {
+      return parent?.lookupSetter(name, charOffset, fileUri);
+    }
+  }
+
+  Builder lookupAmbiguous(String name, Builder builder, bool setter,
+      int charOffset, Uri fileUri) {
+    assert(builder.next != null);
+    if (builder is MixedAccessor) {
+      return setter ? builder.setter : builder.getter;
+    }
+    Builder setterBuilder;
+    Builder getterBuilder;
+    Builder current = builder;
+    while (current != null) {
+      if (current.isGetter && getterBuilder == null) {
+        getterBuilder = current;
+      } else if (current.isSetter && setterBuilder == null) {
+        setterBuilder = current;
+      } else {
+        return new AmbiguousBuilder(builder, charOffset, fileUri);
+      }
+      current = current.next;
+    }
+    assert(getterBuilder != null);
+    assert(setterBuilder != null);
+    return setter ? setterBuilder : getterBuilder;
+  }
+
+  // TODO(ahe): Rename to extend or something.
+  void operator[]= (String name, Builder member) {
+    if (isModifiable) {
+      local[name] = member;
+    } else {
+      internalError("Can't extend an unmodifiable scope.");
+    }
+  }
+}
+
+class AccessErrorBuilder extends Builder {
+  final Builder builder;
+
+  AccessErrorBuilder(this.builder, int charOffset, Uri fileUri)
+      : super(null, charOffset, fileUri);
+
+  Builder get parent => builder;
+
+  get target => null;
+
+  bool get isFinal => builder.isFinal;
+
+  bool get isField => builder.isField;
+
+  bool get isRegularMethod => builder.isRegularMethod;
+
+  bool get isGetter => !builder.isGetter;
+
+  bool get isSetter => !builder.isSetter;
+
+  bool get isInstanceMember => builder.isInstanceMember;
+
+  bool get isStatic => builder.isStatic;
+
+  bool get isTopLevel => builder.isTopLevel;
+
+  bool get isTypeDeclaration => builder.isTypeDeclaration;
+
+  bool get isLocal => builder.isLocal;
+
+  bool get hasProblem => true;
+}
+
+class AmbiguousBuilder extends Builder {
+  final Builder builder;
+
+  AmbiguousBuilder(this.builder, int charOffset, Uri fileUri)
+      : super(null, charOffset, fileUri);
+
+  get target => null;
+
+  bool get hasProblem => true;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/type_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
new file mode 100644
index 0000000..0421ff2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.type_builder;
+
+import 'builder.dart' show
+    Builder,
+    TypeDeclarationBuilder,
+    TypeVariableBuilder;
+
+import 'scope.dart' show
+    Scope;
+
+// TODO(ahe): Make const class.
+abstract class TypeBuilder extends Builder {
+  TypeBuilder(int charOffset, Uri fileUri)
+      : super(null, charOffset, fileUri);
+
+  void resolveIn(Scope scope);
+
+  void bind(TypeDeclarationBuilder builder);
+
+  /// May return null, for example, for mixin applications.
+  String get name;
+
+  String get debugName;
+
+  StringBuffer printOn(StringBuffer buffer);
+
+  String toString() => "$debugName(${printOn(new StringBuffer())})";
+
+  TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) => this;
+
+  build();
+}
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
new file mode 100644
index 0000000..bb3ceb2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.type_declaration_builder;
+
+import 'builder.dart' show
+    Builder,
+    MetadataBuilder,
+    ModifierBuilder,
+    TypeBuilder;
+
+abstract class TypeDeclarationBuilder<T extends TypeBuilder, R>
+    extends ModifierBuilder {
+  final List<MetadataBuilder> metadata;
+
+  final int modifiers;
+
+  final String name;
+
+  Builder parent;
+
+  TypeDeclarationBuilder(this.metadata, this.modifiers, this.name,
+      Builder parent, int charOffset, [Uri fileUri])
+      : parent = parent, super(parent, charOffset, fileUri ?? parent?.fileUri);
+
+  bool get isTypeDeclaration => true;
+
+  R buildType(List<T> arguments);
+
+  /// [arguments] have already been built.
+  R buildTypesWithBuiltArguments(List<R> 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
new file mode 100644
index 0000000..ae843db
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.type_variable_builder;
+
+import 'builder.dart' show
+    LibraryBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder;
+
+abstract class TypeVariableBuilder<T extends TypeBuilder, R>
+    extends TypeDeclarationBuilder<T, R> {
+  T bound;
+
+  TypeVariableBuilder(String name, this.bound, LibraryBuilder compilationUnit,
+      int charOffset)
+      : super(null, null, name, compilationUnit, charOffset);
+
+  String get debugName => "TypeVariableBuilder";
+
+  StringBuffer printOn(StringBuffer buffer) {
+    buffer.write(name);
+    if (bound != null) {
+      buffer.write(" extends ");
+      bound.printOn(buffer);
+    }
+    return buffer;
+  }
+
+  String toString() => "${printOn(new StringBuffer())}";
+
+  T asTypeBuilder();
+}
diff --git a/pkg/front_end/lib/src/fasta/codereview.settings b/pkg/front_end/lib/src/fasta/codereview.settings
new file mode 100644
index 0000000..d2b97ff
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/codereview.settings
@@ -0,0 +1,9 @@
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+# This file is used by gcl to get repository specific information.
+CODE_REVIEW_SERVER: http://codereview.chromium.org
+VIEW_VC: https://github.com/dart-lang/sdk/commit/
+CC_LIST: reviews@dartlang.org,dart-fe-team+reviews@google.com
+PROJECT: Fasta
diff --git a/pkg/front_end/lib/src/fasta/colors.dart b/pkg/front_end/lib/src/fasta/colors.dart
new file mode 100644
index 0000000..906ac37
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/colors.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(ahe): Copied from sdk/pkg/compiler/lib/src/colors.dart.
+library colors;
+
+// See http://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes
+const String RESET = '\u001b[0m';
+
+// See http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+const String BLACK_COLOR = '\u001b[30m';
+const String RED_COLOR = '\u001b[31m';
+const String GREEN_COLOR = '\u001b[32m';
+const String YELLOW_COLOR = '\u001b[33m';
+const String BLUE_COLOR = '\u001b[34m';
+const String MAGENTA_COLOR = '\u001b[35m';
+const String CYAN_COLOR = '\u001b[36m';
+const String WHITE_COLOR = '\u001b[37m';
+
+String wrap(String string, String color) => "${color}$string${RESET}";
+
+String black(String string) => wrap(string, BLACK_COLOR);
+String red(String string) => wrap(string, RED_COLOR);
+String green(String string) => wrap(string, GREEN_COLOR);
+String yellow(String string) => wrap(string, YELLOW_COLOR);
+String blue(String string) => wrap(string, BLUE_COLOR);
+String magenta(String string) => wrap(string, MAGENTA_COLOR);
+String cyan(String string) => wrap(string, CYAN_COLOR);
+String white(String string) => wrap(string, WHITE_COLOR);
diff --git a/pkg/front_end/lib/src/fasta/combinator.dart b/pkg/front_end/lib/src/fasta/combinator.dart
new file mode 100644
index 0000000..a0062c1
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/combinator.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.combinator;
+
+class Combinator {
+  final bool isShow;
+
+  final Set<String> names;
+
+  Combinator(this.isShow, this.names, int charOffset, Uri fileUri);
+
+  Combinator.show(Iterable <String> names, int charOffset, Uri fileUri)
+      : this(true, new Set<String>.from(names), charOffset, fileUri);
+
+  Combinator.hide(Iterable <String> names, int charOffset, Uri fileUri)
+      : this(false, new Set<String>.from(names), charOffset, fileUri);
+
+  bool get isHide => !isShow;
+}
diff --git a/pkg/front_end/lib/src/fasta/command_line.dart b/pkg/front_end/lib/src/fasta/command_line.dart
new file mode 100644
index 0000000..0ef4bd9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/command_line.dart
@@ -0,0 +1,174 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.command_line;
+
+import 'errors.dart' show
+    inputError,
+    internalError;
+
+argumentError(String usage, String message) {
+  if (usage != null) print(usage);
+  inputError(null, null, message);
+}
+
+class ParsedArguments {
+  final Map<String, dynamic> options = <String, dynamic>{};
+  final List<String> arguments = <String>[];
+
+  toString() => "ParsedArguments($options, $arguments)";
+}
+
+class CommandLine {
+  final Map<String, dynamic> options;
+
+  final List<String> arguments;
+
+  final String usage;
+
+  CommandLine.parsed(ParsedArguments p, this.usage)
+      : this.options = p.options,
+        this.arguments = p.arguments {
+    validate();
+    if (verbose) {
+      print(p);
+    }
+  }
+
+  CommandLine(List<String> arguments,
+      {Map<String, dynamic> specification, String usage})
+      : this.parsed(parse(arguments, specification, usage), usage);
+
+  bool get verbose {
+    return options.containsKey("-v") || options.containsKey("--verbose");
+  }
+
+  /// Override to validate arguments and options.
+  void validate() {
+  }
+
+  /// Parses a list of command-line [arguments] into options and arguments.
+  ///
+  /// An /option/ is something that, normally, starts with `-` or `--` (one or
+  /// two dashes). However, as a special case `/?` and `/h` are also recognized
+  /// as options for increased compatibility with Windows. An option can have a
+  /// value.
+  ///
+  /// An /argument/ is something that isn't an option, for example, a file name.
+  ///
+  /// The specification is a map of options to one of the type literals `Uri`,
+  /// `int`, `bool`, or `String`, or a comma (`","`) that represents option
+  /// values of type [Uri], [int], [bool], [String], or a comma-separated list
+  /// of [String], respectively.
+  ///
+  /// If [arguments] contains `"--"`, anything before is parsed as options, and
+  /// arguments; anything following is treated as arguments (even if starting
+  /// with, for example, a `-`).
+  ///
+  /// Anything that looks like an option is assumed to be a `bool` option set
+  /// to true, unless it's mentioned in [specification] in which case the
+  /// option requires a value, either on the form `--option value` or
+  /// `--option=value`.
+  ///
+  /// This method performs only a limited amount of validation, but if an error
+  /// occurs, it will print [usage] along with a specific error message.
+  static ParsedArguments parse(List<String> arguments,
+      Map<String, dynamic> specification, String usage) {
+    specification ??= const <String, dynamic>{};
+    ParsedArguments result = new ParsedArguments();
+    int index = arguments.indexOf("--");
+    Iterable<String> nonOptions = const <String>[];
+    Iterator<String> iterator = arguments.iterator;
+    if (index != -1) {
+      nonOptions = arguments.skip(index + 1);
+      iterator = arguments.take(index).iterator;
+    }
+    while (iterator.moveNext()) {
+      String argument = iterator.current;
+      if (argument.startsWith("-")) {
+        var valueSpecification = specification[argument];
+        String value;
+        if (valueSpecification != null) {
+          if (!iterator.moveNext()) {
+            return argumentError(usage, "Expected value after '$argument'.");
+          }
+          value = iterator.current;
+        } else {
+          index = argument.indexOf("=");
+          if (index != -1) {
+            value = argument.substring(index + 1);
+            argument = argument.substring(0, index);
+            valueSpecification = specification[argument];
+          }
+        }
+        if (valueSpecification == null) {
+          if (value != null) {
+            return argumentError(usage,
+                "Argument '$argument' doesn't take a value: '$value'.");
+          }
+          result.options[argument] = true;
+        } else {
+          if (valueSpecification is! String && valueSpecification is! Type) {
+            return argumentError(usage, "Unrecognized type of value "
+                "specification: ${valueSpecification.runtimeType}.");
+          }
+          switch ("$valueSpecification") {
+            case ",":
+              result.options.putIfAbsent(argument, () => <String>[])
+                  .addAll(value.split(","));
+              break;
+
+            case "int":
+            case "bool":
+            case "String":
+            case "Uri":
+              if (result.options.containsKey(argument)) {
+                return argumentError(usage, "Multiple values for '$argument': "
+                    "'${result.options[argument]}' and '$value'.");
+              }
+              var parsedValue;
+              if (valueSpecification == int) {
+                parsedValue = int.parse(value, onError: (_) {
+                  return argumentError(usage,
+                      "Value for '$argument', '$value', isn't an int.");
+                });
+              } else if (valueSpecification == bool) {
+                if (value == "true" || value == "yes") {
+                  parsedValue = true;
+                } else if (value == "false" || value == "no") {
+                  parsedValue = false;
+                } else {
+                  return argumentError(usage,
+                      "Value for '$argument' is '$value', "
+                      "but expected one of: 'true', 'false', 'yes', or 'no'.");
+                }
+              } else if (valueSpecification == Uri) {
+                parsedValue = Uri.base.resolve(value);
+              } else if (valueSpecification == String) {
+                parsedValue = value;
+              } else if (valueSpecification is String) {
+                return argumentError(usage, "Unrecognized value specification: "
+                    "'$valueSpecification', try using a type literal instead.");
+              } else {
+                // All possible cases should have been handled above.
+                return internalError("assertion failure");
+              }
+              result.options[argument] = parsedValue;
+              break;
+
+            default:
+              return argumentError(usage,
+                  "Unrecognized value specification: '$valueSpecification'.");
+          }
+        }
+      } else if (argument == "/?" || argument == "/h") {
+        result.options[argument] = true;
+      } else {
+        result.arguments.add(argument);
+      }
+    }
+    result.arguments.addAll(nonOptions);
+    return result;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/compile_platform.dart b/pkg/front_end/lib/src/fasta/compile_platform.dart
new file mode 100644
index 0000000..09880e3
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/compile_platform.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.compile_platform;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    File,
+    IOSink;
+
+import 'package:analyzer/src/generated/source.dart' show
+    Source;
+
+import 'package:analyzer/dart/element/element.dart' show
+    ExportElement,
+    LibraryElement;
+
+import 'package:kernel/kernel.dart' show
+    Repository;
+
+import 'package:kernel/ast.dart' show
+    Field,
+    Library,
+    Name,
+    Program,
+    StringLiteral;
+
+import 'package:kernel/binary/ast_to_binary.dart' show
+    BinaryPrinter;
+
+import 'package:kernel/analyzer/loader.dart' show
+    DartLoader,
+    DartOptions,
+    createDartSdk;
+
+import 'package:kernel/target/targets.dart' show
+    Target,
+    TargetFlags,
+    getTarget;
+
+import 'package:kernel/repository.dart' show
+    Repository;
+
+import 'package:kernel/ast.dart' show
+    Program;
+
+import 'environment_variable.dart' show
+    EnvironmentVariableDirectory,
+    fileExists;
+
+import 'errors.dart' show
+    inputError;
+
+const EnvironmentVariableSdk dartAotSdk = const EnvironmentVariableSdk(
+    "DART_AOT_SDK",
+    "The environment variable 'DART_AOT_SDK' should point to a patched SDK.");
+
+class EnvironmentVariableSdk extends EnvironmentVariableDirectory {
+  const EnvironmentVariableSdk(String name, String what)
+      : super(name, what);
+
+  Future<Null> validate(String value) async {
+    Uri sdk = Uri.base.resolveUri(new Uri.directory(value));
+    const String asyncDart = "lib/async/async.dart";
+    if (!await fileExists(sdk, asyncDart)) {
+      inputError(null, null,
+          "The environment variable '$name' has the value '$value', "
+          "that's a directory that doesn't contain '$asyncDart'. $what");
+    }
+    const String asyncSources = "lib/async/async_sources.gypi";
+    if (await fileExists(sdk, asyncSources)) {
+      inputError(null, null,
+          "The environment variable '$name' has the value '$value', "
+          "that's a directory that contains '$asyncSources', so it isn't a "
+          "patched SDK. $what");
+    }
+    return null;
+  }
+}
+
+main(List<String> arguments) async {
+  Uri output = Uri.base.resolveUri(new Uri.file(arguments.single));
+  DartOptions options = new DartOptions(
+      strongMode: false, sdk: await dartAotSdk.value, packagePath: null);
+  Repository repository = new Repository();
+  DartLoader loader = new DartLoader(repository, options, null,
+      ignoreRedirectingFactories: false,
+      dartSdk: createDartSdk(options.sdk, strongMode: options.strongMode));
+  Target target = getTarget(
+      "vm", new TargetFlags(strongMode: options.strongMode));
+  Program program = loader.loadProgram(
+      Uri.base.resolve("pkg/fasta/test/platform.dart"), target: target);
+  if (loader.errors.isNotEmpty) {
+    inputError(null, null, loader.errors.join("\n"));
+  }
+  Library mainLibrary = program.mainMethod.enclosingLibrary;
+  program.uriToSource.remove(mainLibrary.fileUri);
+  program = new Program(
+      program.libraries.where(
+          (Library l) => l.importUri.scheme == "dart").toList(),
+      program.uriToSource);
+  target.performModularTransformations(program);
+  target.performGlobalTransformations(program);
+  for (LibraryElement analyzerLibrary in loader.libraryElements) {
+    Library library = loader.getLibraryReference(analyzerLibrary);
+    StringBuffer sb = new StringBuffer();
+    if (analyzerLibrary.exports.isNotEmpty) {
+      Source source;
+      int offset;
+      for (ExportElement export in analyzerLibrary.exports) {
+        source ??= export.source;
+        offset ??= export.nameOffset;
+        Uri uri = export.exportedLibrary.source.uri;
+        sb.write("export '");
+        sb.write(uri);
+        sb.write("'");
+        if (export.combinators.isNotEmpty) {
+          sb.write(" ");
+          sb.writeAll(export.combinators, " ");
+        }
+        sb.write(";");
+      }
+      Name exports = new Name("_exports#", library);
+      StringLiteral literal = new StringLiteral("$sb")
+          ..fileOffset = offset;
+      library.addMember(new Field(exports, isStatic: true, isConst: true,
+              initializer: literal, fileUri: "${new Uri.file(source.fullName)}")
+          ..fileOffset = offset);
+    }
+  }
+
+  IOSink sink = new File.fromUri(output).openWrite();
+  new BinaryPrinter(sink).writeProgramFile(program);
+  await sink.close();
+}
diff --git a/pkg/front_end/lib/src/fasta/compiler_command_line.dart b/pkg/front_end/lib/src/fasta/compiler_command_line.dart
new file mode 100644
index 0000000..2413488
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/compiler_command_line.dart
@@ -0,0 +1,143 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.compiler_command_line;
+
+import 'dart:io' show
+    exit;
+
+import 'command_line.dart' show
+    CommandLine,
+    argumentError;
+
+const Map<String, dynamic> optionSpecification = const <String, dynamic>{
+  "-o": Uri,
+  "--output": Uri,
+  "--platform": Uri,
+  "--packages": Uri,
+};
+
+class CompilerCommandLine extends CommandLine {
+  final String programName;
+
+  CompilerCommandLine(String programName, List<String> arguments)
+      : programName = programName,
+        super(arguments, specification: optionSpecification,
+            usage: computeUsage(programName, false));
+
+  bool get verify => options.containsKey("--verify");
+
+  bool get dumpIr => options.containsKey("--dump-ir");
+
+  bool get help {
+    return options.containsKey("--help") ||
+        options.containsKey("-h") ||
+        options.containsKey("/h") ||
+        options.containsKey("/?");
+  }
+
+  void validate() {
+    if (help) {
+      print(computeUsage(programName, verbose));
+      exit(0);
+    }
+
+    if (options.containsKey("-o") && options.containsKey("--output")) {
+      return argumentError(usage, "Can't specify both '-o' and '--output'.");
+    }
+    if (options.containsKey("--packages")) {
+      return argumentError(usage, "Option '--packages' isn't supported yet.");
+    }
+    if (arguments.isEmpty) {
+      return argumentError(usage, "No Dart file specified.");
+    }
+  }
+
+  Uri get output {
+    return options["-o"] ?? options["--output"] ?? defaultOutput;
+  }
+
+  Uri get defaultOutput => Uri.base.resolve("${arguments.first}.dill");
+
+  Uri get platform {
+    return options.containsKey("--compile-sdk")
+        ? null
+        : options["--platform"] ?? Uri.base.resolve("platform.dill");
+  }
+}
+
+String computeUsage(String programName, bool verbose) {
+  String basicUsage = "Usage: $programName [options] dartfile\n";
+  String summary;
+  String options = (verbose ? allOptions : frequentOptions).trim();
+  switch (programName) {
+    case "outline":
+      summary =
+          "Creates an outline of a Dart program in the Dill/Kernel IR format.";
+      break;
+
+    case "compile":
+      summary = "Compiles a Dart program to the Dill/Kernel IR format.";
+      break;
+
+    case "kompile":
+      summary =
+          "Compiles a Dart program to the Dill/Kernel IR format via dartk.";
+      break;
+
+    case "run":
+      summary = "Runs a Dart program.";
+      break;
+  }
+  StringBuffer sb = new StringBuffer(basicUsage);
+  if (summary != null) {
+    sb.writeln();
+    sb.writeln(summary);
+    sb.writeln();
+  }
+  sb.write(options);
+  return "$sb";
+}
+
+const String frequentOptions = """
+Frequently used options:
+
+  -o <file> Generate the output into <file>.
+  -h        Display this message (add -v for information about all options).
+""";
+
+const String allOptions = """
+Supported options:
+
+  -o <file>, --out=<file>
+    Generate the output into <file>.
+
+  -h, /h, /?, --help
+    Display this message (add -v for information about all options).
+
+  -v, --verbose
+    Display verbose information.
+
+  --
+    Stop option parsing, the rest of the command line is assumed to be
+    file names or arguments to the Dart program.
+
+  --packages=<file>
+    Use package resolution configuration <file>, which should contain a mapping
+    of package names to paths.
+
+  --platform=<file>
+    Read the SDK platform from <file>, which should be in Dill/Kernel IR format
+    and contain the Dart SDK.
+
+  --verify
+    Check that the generated output is free of various problems. This is mostly
+    useful for developers of this compiler or Kernel transformations.
+
+  --dump-ir
+    Print compiled libraries in Kernel source notation.
+
+  --compile-sdk
+    Compile the SDK from scratch instead of reading it from 'platform.dill'.
+""";
diff --git a/pkg/front_end/lib/src/fasta/dill/README.md b/pkg/front_end/lib/src/fasta/dill/README.md
new file mode 100644
index 0000000..1726bb5
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/README.md
@@ -0,0 +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 file.
+-->
+# Kernel from Binary (.dill)
+
+Builders for representing the serialized form of Kernel IR nodes from .dill files.
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
new file mode 100644
index 0000000..4c97dd2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.dill_class_builder;
+
+import 'package:kernel/ast.dart' show
+    Class,
+    Constructor,
+    Member,
+    Procedure,
+    ProcedureKind;
+
+import '../kernel/kernel_builder.dart' show
+    Builder,
+    KernelClassBuilder;
+
+import '../modifier.dart' show
+    abstractMask;
+
+import 'dill_member_builder.dart' show
+    DillMemberBuilder;
+
+import 'dill_library_builder.dart' show
+    DillLibraryBuilder;
+
+class DillClassBuilder extends KernelClassBuilder {
+  final Class cls;
+
+  final Map<String, Builder> constructors = <String, Builder>{};
+
+  DillClassBuilder(Class cls, DillLibraryBuilder parent)
+      : cls = cls,
+        super(null, computeModifiers(cls), cls.name, null, null, null,
+            <String, Builder>{}, parent, cls.fileOffset);
+
+  void addMember(Member member) {
+    DillMemberBuilder builder = new DillMemberBuilder(member, this);
+    String name = member.name.name;
+    if (member is Constructor ||
+        (member is Procedure && member.kind == ProcedureKind.Factory)) {
+      constructors[name] = builder;
+    } else {
+      DillMemberBuilder existing = members[name];
+      if (existing == null) {
+        members[name] = builder;
+      } else {
+        existing.next = builder;
+      }
+    }
+  }
+
+  Builder findConstructorOrFactory(String name) => constructors[name];
+}
+
+int computeModifiers(Class cls) {
+  return cls.isAbstract ? abstractMask : 0;
+}
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
new file mode 100644
index 0000000..22445ee
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.dill_library_builder;
+
+import 'package:kernel/ast.dart' show
+    Class,
+    ExpressionStatement,
+    Field,
+    FunctionNode,
+    Let,
+    Library,
+    ListLiteral,
+    Member,
+    Procedure,
+    StaticGet;
+
+import '../errors.dart' show
+    internalError;
+
+import '../kernel/kernel_builder.dart' show
+    Builder,
+    KernelInvalidTypeBuilder,
+    KernelTypeBuilder,
+    LibraryBuilder;
+
+import '../kernel/redirecting_factory_body.dart' show
+    RedirectingFactoryBody;
+
+import 'dill_class_builder.dart' show
+    DillClassBuilder;
+
+import 'dill_member_builder.dart' show
+    DillMemberBuilder;
+
+import 'dill_loader.dart' show
+    DillLoader;
+
+class DillLibraryBuilder extends LibraryBuilder<KernelTypeBuilder, Library> {
+  final Uri uri;
+
+  final Map<String, Builder> members = <String, Builder>{};
+
+  // TODO(ahe): Some export information needs to be serialized.
+  final Map<String, Builder> exports = <String, Builder>{};
+
+  final DillLoader loader;
+
+  Library library;
+
+  DillLibraryBuilder(Uri uri, this.loader)
+      : uri = uri, super(uri);
+
+  get scope => internalError("Scope not supported");
+
+  Uri get fileUri => uri;
+
+  void addClass(Class cls) {
+    DillClassBuilder classBulder = new DillClassBuilder(cls, this);
+    addBuilder(cls.name, classBulder, cls.fileOffset);
+    cls.procedures.forEach(classBulder.addMember);
+    cls.constructors.forEach(classBulder.addMember);
+    for (Field field in cls.fields) {
+      if (field.name.name == "_redirecting#") {
+        // This is a hack / work around for storing redirecting constructors in
+        // dill files. See `buildFactoryConstructor` in
+        // [package:kernel/analyzer/ast_from_analyzer.dart]
+        // (../../../../kernel/lib/analyzer/ast_from_analyzer.dart).
+        ListLiteral initializer = field.initializer;
+        for (StaticGet get in initializer.expressions) {
+          Procedure factory = get.target;
+          FunctionNode function = factory.function;
+          ExpressionStatement statement = function.body;
+          Let let = statement.expression;
+          StaticGet getTarget = let.variable.initializer;
+          function.body = new RedirectingFactoryBody(getTarget.target)
+              ..parent = function;
+        }
+        initializer.expressions.clear();
+      } else {
+        classBulder.addMember(field);
+      }
+    }
+  }
+
+  void addMember(Member member) {
+    String name = member.name.name;
+    if (name == "_exports#") {
+      // This is a hack / work around for storing exports in dill files. See
+      // [compile_platform.dart](../compile_platform.dart).
+    } else {
+      addBuilder(name, new DillMemberBuilder(member, this), member.fileOffset);
+    }
+  }
+
+  Builder addBuilder(String name, Builder builder, int charOffset) {
+    if (name == null || name.isEmpty) return null;
+    members[name] = builder;
+    if (!name.startsWith("_")) {
+      exports[name] = builder;
+    }
+    return builder;
+  }
+
+  bool addToExportScope(String name, Builder member) {
+    return internalError("Not implemented yet.");
+  }
+
+  void addToScope(String name, Builder member) {
+    internalError("Not implemented yet.");
+  }
+
+  KernelInvalidTypeBuilder buildAmbiguousBuilder(
+      String name, Builder builder, Builder other, int charOffset) {
+    return new KernelInvalidTypeBuilder(name, charOffset, fileUri);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
new file mode 100644
index 0000000..da0fcf9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.dill_loader;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    File;
+
+import 'package:kernel/kernel.dart' show
+    loadProgramFromBinary;
+
+import 'package:kernel/ast.dart' show
+    Library,
+    Program;
+
+import '../loader.dart' show
+    Loader;
+
+import '../target_implementation.dart' show
+    TargetImplementation;
+
+import 'dill_library_builder.dart' show
+    DillLibraryBuilder;
+
+class DillLoader extends Loader<Library> {
+  Uri input;
+
+  Program program;
+
+  DillLoader(TargetImplementation target)
+      : super(target);
+
+  DillLibraryBuilder read(Uri uri, [Uri fileUri]) => super.read(uri, fileUri);
+
+  Future<Null> buildOutline(DillLibraryBuilder builder) async {
+    if (program == null) {
+      byteCount = await new File.fromUri(input).length();
+      setProgram(await loadProgramFromBinary(input.toFilePath()));
+    }
+    builder.library.classes.forEach(builder.addClass);
+    builder.library.procedures.forEach(builder.addMember);
+    builder.library.fields.forEach(builder.addMember);
+  }
+
+  Future<Null> buildBody(DillLibraryBuilder builder, _) {
+    return buildOutline(builder);
+  }
+
+  void setProgram(Program program) {
+    assert(input != null);
+    this.program = program;
+    for (Library library in program.libraries) {
+      read(library.importUri).library = library;
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
new file mode 100644
index 0000000..23eee58
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.dill_member_builder;
+
+import 'package:kernel/ast.dart' show
+    Constructor,
+    Field,
+    Member,
+    Procedure,
+    ProcedureKind;
+
+import '../errors.dart' show
+    internalError;
+
+import '../kernel/kernel_builder.dart' show
+    Builder,
+    MemberBuilder;
+
+import '../modifier.dart' show
+    abstractMask,
+    constMask,
+    externalMask,
+    finalMask,
+    staticMask;
+
+class DillMemberBuilder extends MemberBuilder {
+  final int modifiers;
+
+  final Member member;
+
+  DillMemberBuilder(Member member, Builder parent)
+      : modifiers = computeModifiers(member),
+        member = member,
+        super(parent, member.fileOffset);
+
+  Member get target => member;
+
+  String get name => member.name.name;
+
+  bool get isConstructor => member is Constructor;
+
+  bool get isFactory {
+    if (member is Procedure) {
+      Procedure procedure = member;
+      return procedure.kind == ProcedureKind.Factory;
+    } else {
+      return false;
+    }
+  }
+}
+
+int computeModifiers(Member member) {
+  int modifier = member.isAbstract ? abstractMask : 0;
+  modifier |= member.isExternal ? externalMask : 0;
+  if (member is Field) {
+    modifier |= member.isConst ? constMask : 0;
+    modifier |= member.isFinal ? finalMask : 0;
+    modifier |= member.isStatic ? staticMask : 0;
+  } else if (member is Procedure) {
+    modifier |= member.isConst ? constMask : 0;
+    modifier |= member.isStatic ? staticMask : 0;
+  } else if (member is Constructor) {
+    modifier |= member.isConst ? constMask : 0;
+  } else {
+    internalError("Unhandled: ${member.runtimeType}");
+  }
+  return modifier;
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_target.dart b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
new file mode 100644
index 0000000..b1ad970
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.dill_target;
+
+import 'dart:async' show
+    Future;
+
+import 'package:kernel/ast.dart' show
+    Class;
+
+import 'dill_loader.dart' show
+    DillLoader;
+
+import '../errors.dart' show
+    inputError,
+    internalError;
+
+import '../target_implementation.dart' show
+    TargetImplementation;
+
+import '../ticker.dart' show
+    Ticker;
+
+import '../translate_uri.dart' show
+    TranslateUri;
+
+import '../ast_kind.dart' show
+    AstKind;
+
+import '../kernel/kernel_builder.dart' show
+    ClassBuilder,
+    KernelClassBuilder;
+
+import 'dill_library_builder.dart' show
+    DillLibraryBuilder;
+
+class DillTarget extends TargetImplementation {
+  bool isLoaded = false;
+  DillLoader loader;
+
+  DillTarget(Ticker ticker, TranslateUri uriTranslator)
+      : super(ticker, uriTranslator) {
+    loader = new DillLoader(this);
+  }
+
+  void read(Uri uri) {
+    if (loader.input == null) {
+      loader.input = uri;
+    } else {
+      inputError(uri, -1, "Can only read one dill file.");
+    }
+  }
+
+  Future<Null> writeProgram(Uri uri, AstKind kind) {
+    return internalError("not implemented.");
+  }
+
+  Future<Null> writeOutline(Uri uri) async {
+    if (loader.input == null) return null;
+    await loader.buildOutlines();
+    isLoaded = true;
+    return null;
+  }
+
+  DillLibraryBuilder createLibraryBuilder(Uri uri, Uri fileUri) {
+    return new DillLibraryBuilder(uri, loader);
+  }
+
+  void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set) {
+  }
+
+  List<ClassBuilder> collectAllClasses() {
+    return null;
+  }
+
+  void breakCycle(ClassBuilder cls) {
+  }
+
+  Class get objectClass {
+    KernelClassBuilder builder = loader.coreLibrary.exports["Object"];
+    return builder.cls;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/environment_variable.dart b/pkg/front_end/lib/src/fasta/environment_variable.dart
new file mode 100644
index 0000000..c58ab17
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/environment_variable.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.environment_variable;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    Directory,
+    File,
+    Platform;
+
+import 'errors.dart' show
+    inputError;
+
+class EnvironmentVariable {
+  final String name;
+
+  final String what;
+
+  const EnvironmentVariable(this.name, this.what);
+
+  Future<String> get value async {
+    String value = Platform.environment[name];
+    if (value == null) return variableNotDefined();
+    await validate(value);
+    return value;
+  }
+
+  Future<Null> validate(String value) => new Future<Null>.value();
+
+  variableNotDefined() {
+    inputError(null, null,
+        "The environment variable '$name' isn't defined. $what");
+  }
+}
+
+class EnvironmentVariableFile extends EnvironmentVariable {
+  const EnvironmentVariableFile(String name, String what)
+      : super(name, what);
+
+  Future<Null> validate(String value) async {
+    if (!await new File(value).exists()) notFound(value);
+    return null;
+  }
+
+  notFound(String value) {
+    inputError(null, null,"The environment variable '$name' has the value "
+        "'$value', that isn't a file. $what");
+  }
+}
+
+class EnvironmentVariableDirectory extends EnvironmentVariable {
+  const EnvironmentVariableDirectory(String name, String what)
+      : super(name, what);
+
+  Future<Null> validate(String value) async {
+    if (!await new Directory(value).exists()) notFound(value);
+    return null;
+  }
+
+  notFound(String value) {
+    inputError(null, null, "The environment variable '$name' has the value "
+        "'$value', that isn't a directory. $what");
+  }
+}
+
+Future<bool> fileExists(Uri base, String path) async {
+  return await new File.fromUri(base.resolve(path)).exists();
+}
diff --git a/pkg/front_end/lib/src/fasta/errors.dart b/pkg/front_end/lib/src/fasta/errors.dart
new file mode 100644
index 0000000..077f160
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/errors.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.errors;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:convert' show
+    JSON;
+
+import 'dart:io' show
+    ContentType,
+    HttpClient,
+    HttpClientRequest,
+    SocketException,
+    stderr;
+
+import 'colors.dart' show
+    red;
+
+import 'util/relativize.dart' show
+    relativizeUri;
+
+const String defaultServerAddress = "http://127.0.0.1:59410/";
+
+/// Tracks if there has been a crash reported through [reportCrash]. Should be
+/// reset between each compilation by calling [resetCrashReporting].
+bool hasCrashed = false;
+
+/// Tracks the first source URI that has been read and is used as a fall-back
+/// for [reportCrash]. Should be reset between each compilation by calling
+/// [resetCrashReporting].
+Uri firstSourceUri;
+
+/// Used to report an internal error.
+///
+/// Internal errors should be avoided as best as possible, but are preferred
+/// over assertion failures. Favor error messages that starts with "Internal
+/// error: " and a short description that may help a developer debug the issue.
+/// This method should be called instead of using `throw`, as this allows us to
+/// ensure that there are no throws anywhere in the codebase.
+dynamic internalError(Object error) {
+  throw error;
+}
+
+/// Used to report an error in input.
+///
+/// Avoid using this for reporting compile-time errors, instead use
+/// `LibraryBuilder.addCompileTimeError` for those.
+///
+/// An input error is any error that isn't an internal error. We use the term
+/// "input error" in favor of "user error". This way, if an input error isn't
+/// handled correctly, the user will never see a stack trace that says "user
+/// error".
+dynamic inputError(Uri uri, int charOffset, Object error) {
+  throw new InputError(uri, charOffset, error);
+}
+
+class InputError {
+  final Uri uri;
+
+  final int charOffset;
+
+  final Object error;
+
+  InputError(this.uri, int charOffset, this.error)
+      : this.charOffset = charOffset ?? -1;
+
+  toString() => "InputError: $error";
+
+  String format() {
+    // TODO(ahe): Colors need to be optional. Doesn't work well in Emacs or on
+    // Windows.
+    String message = red("Error: ${safeToString(error)}");
+    if (uri != null) {
+      String position = charOffset == -1 ? "" : "$charOffset:";
+      return "${relativizeUri(uri)}:$position $message";
+    } else {
+      return message;
+    }
+  }
+}
+
+class Crash {
+  final Uri uri;
+
+  final int charOffset;
+
+  final Object error;
+
+  final StackTrace trace;
+
+  Crash(this.uri, this.charOffset, this.error, this.trace);
+
+  String toString() {
+    return """
+Crash when compiling $uri,
+at character offset $charOffset:
+$error${trace == null ? '' : '\n$trace'}
+""";
+  }
+}
+
+void resetCrashReporting() {
+  firstSourceUri = null;
+  hasCrashed = false;
+}
+
+Future reportCrash(error, StackTrace trace, [Uri uri, int charOffset]) async {
+  note(String note) async {
+    stderr.write(note);
+    await stderr.flush();
+  }
+  if (hasCrashed) return new Future.error(error, trace);
+  if (error is Crash) {
+    trace = error.trace ?? trace;
+    uri = error.uri ?? uri;
+    charOffset = error.charOffset ?? charOffset;
+    error = error.error;
+  }
+  uri ??= firstSourceUri;
+  hasCrashed = true;
+  Map<String, dynamic> data = <String, dynamic>{};
+  data["type"] = "crash";
+  data["client"] = "package:fasta";
+  if (uri != null) data["uri"] = "$uri";
+  if (charOffset != null) data["offset"] = charOffset;
+  data["error"] = safeToString(error);
+  data["trace"] = "$trace";
+  String json = JSON.encode(data);
+  HttpClient client = new HttpClient();
+  try {
+    Uri uri = Uri.parse(defaultServerAddress);
+    HttpClientRequest request;
+    try {
+      request = await client.postUrl(uri);
+    } on SocketException {
+      // Assume the crash logger isn't running.
+      await client.close(force: true);
+      return new Future.error(error, trace);
+    }
+    if (request != null) {
+      await note("\nSending crash report data");
+      request.persistentConnection = false;
+      request.bufferOutput = false;
+      String host = request?.connectionInfo?.remoteAddress?.host;
+      int port = request?.connectionInfo?.remotePort;
+      await note(" to $host:$port");
+      await request
+          ..headers.contentType = ContentType.JSON
+          ..write(json);
+      await request.close();
+      await note(".");
+    }
+  } catch (e, s) {
+    await note("\n${safeToString(e)}\n$s\n");
+    await note("\n\n\nFE::ERROR::$json\n\n\n");
+  }
+  await client.close(force: true);
+  await note("\n");
+  return new Future.error(error, trace);
+}
+
+String safeToString(Object object) {
+  try {
+    return "$object";
+  } catch (e) {
+    return "Error when converting ${object.runtimeType} to string.";
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/export.dart b/pkg/front_end/lib/src/fasta/export.dart
new file mode 100644
index 0000000..a31a5c0
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/export.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.export;
+
+import 'builder/builder.dart' show
+    Builder,
+    LibraryBuilder;
+
+import 'combinator.dart' show
+    Combinator;
+
+class Export {
+  /// The library that is exporting [exported];
+  final LibraryBuilder exporter;
+
+  /// The library being exported.
+  final LibraryBuilder exported;
+
+  final List<Combinator> combinators;
+
+  Export(this.exporter, this.exported, this.combinators, int charOffset);
+
+  Uri get fileUri => exporter.fileUri;
+
+  bool addToExportScope(String name, Builder member) {
+    if (combinators != null) {
+      for (Combinator combinator in combinators) {
+        if (combinator.isShow && !combinator.names.contains(name)) return false;
+        if (combinator.isHide && combinator.names.contains(name)) return false;
+      }
+    }
+    return exporter.addToExportScope(name, member);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/import.dart b/pkg/front_end/lib/src/fasta/import.dart
new file mode 100644
index 0000000..4b873d9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/import.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.import;
+
+import 'builder/builder.dart' show
+    Builder,
+    LibraryBuilder,
+    PrefixBuilder;
+
+import 'combinator.dart' show
+    Combinator;
+
+typedef void AddToScope(String name, Builder member);
+
+class Import {
+  /// The library that is importing [imported];
+  final LibraryBuilder importer;
+
+  /// The library being imported.
+  final LibraryBuilder imported;
+
+  final String prefix;
+
+  final List<Combinator> combinators;
+
+  final int charOffset;
+
+  final int prefixCharOffset;
+
+  Import(this.importer, this.imported, this.prefix, this.combinators,
+      this.charOffset, this.prefixCharOffset);
+
+  Uri get fileUri => importer.fileUri;
+
+  void finalizeImports(LibraryBuilder importer) {
+    AddToScope add;
+    PrefixBuilder prefix;
+    if (this.prefix == null) {
+      add = importer.addToScope;
+    } else {
+      prefix = new PrefixBuilder(
+          this.prefix, <String, Builder>{}, importer, prefixCharOffset);
+      add = (String name, Builder member) {
+        prefix.exports[name] = member;
+      };
+    }
+    imported.exports.forEach((String name, Builder member) {
+      if (combinators != null) {
+        for (Combinator combinator in combinators) {
+          if (combinator.isShow && !combinator.names.contains(name)) return;
+          if (combinator.isHide && combinator.names.contains(name)) return;
+        }
+      }
+      add(name, member);
+    });
+    if (prefix != null) {
+      Builder existing = importer.addBuilder(prefix.name, prefix, charOffset);
+      if (existing == prefix) {
+        importer.addToScope(prefix.name, prefix);
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/README.md b/pkg/front_end/lib/src/fasta/kernel/README.md
new file mode 100644
index 0000000..c7a992b
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/README.md
@@ -0,0 +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 file.
+-->
+# Kernel from Source
+
+Builders for creating Kernel IR nodes (AST) from Dart sources.
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
new file mode 100644
index 0000000..15534ce
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -0,0 +1,2695 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.body_builder;
+
+import 'package:front_end/src/fasta/parser/parser.dart' show
+    FormalParameterType,
+    optional;
+
+import 'package:front_end/src/fasta/parser/error_kind.dart' show
+    ErrorKind;
+
+import 'package:kernel/ast.dart';
+
+import 'package:kernel/clone.dart' show
+    CloneVisitor;
+
+import 'package:kernel/transformations/flags.dart' show
+    TransformerFlag;
+
+import 'package:kernel/class_hierarchy.dart' show
+    ClassHierarchy;
+
+import 'package:kernel/core_types.dart' show
+    CoreTypes;
+
+import '../parser/dart_vm_native.dart' show
+    skipNativeClause;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    BeginGroupToken,
+    Token,
+    isBinaryOperator,
+    isMinusOperator;
+
+import '../errors.dart' show
+    InputError,
+    internalError;
+
+import '../source/scope_listener.dart' show
+    JumpTargetKind,
+    NullValue,
+    ScopeListener;
+
+import '../builder/scope.dart' show
+    AccessErrorBuilder,
+    AmbiguousBuilder,
+    Scope;
+
+import '../source/outline_builder.dart' show
+    asyncMarkerFromTokens;
+
+import 'builder_accessors.dart';
+
+import 'frontend_accessors.dart' show
+    buildIsNull,
+    makeBinary,
+    makeLet;
+
+import 'builder_accessors.dart' as builder_accessors show
+    throwNoSuchMethodError;
+
+import '../quote.dart' show
+    Quote,
+    analyzeQuote,
+    unescape,
+    unescapeFirstStringPart,
+    unescapeLastStringPart,
+    unescapeString;
+
+import '../modifier.dart' show
+    Modifier,
+    constMask,
+    finalMask;
+
+import 'redirecting_factory_body.dart' show
+    getRedirectionTarget;
+
+import 'kernel_builder.dart';
+
+const bool showNits = false;
+
+final Name callName = new Name("call");
+
+final Name plusName = new Name("+");
+
+final Name minusName = new Name("-");
+
+final Name multiplyName = new Name("*");
+
+final Name divisionName = new Name("/");
+
+final Name percentName = new Name("%");
+
+final Name ampersandName = new Name("&");
+
+final Name leftShiftName = new Name("<<");
+
+final Name rightShiftName = new Name(">>");
+
+final Name caretName = new Name("^");
+
+final Name barName = new Name("|");
+
+final Name mustacheName = new Name("~/");
+
+class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
+  final KernelLibraryBuilder library;
+
+  final MemberBuilder member;
+
+  final KernelClassBuilder classBuilder;
+
+  final ClassHierarchy hierarchy;
+
+  @override
+  final CoreTypes coreTypes;
+
+  final bool isInstanceMember;
+
+  final Map<String, FieldInitializer> fieldInitializers =
+      <String, FieldInitializer>{};
+
+  final Scope enclosingScope;
+
+  final bool isDartLibrary;
+
+  Scope formalParameterScope;
+
+  bool isFirstIdentifier = false;
+
+  bool hasParserError = false;
+
+  bool inInitializer = false;
+
+  bool inCatchClause = false;
+
+  int functionNestingLevel = 0;
+
+  Statement compileTimeErrorInTry;
+
+  Statement compileTimeErrorInLoopOrSwitch;
+
+  Scope switchScope;
+
+  CloneVisitor cloner;
+
+  BodyBuilder(KernelLibraryBuilder library, this.member, Scope scope,
+      this.formalParameterScope, this.hierarchy, this.coreTypes,
+      this.classBuilder, this.isInstanceMember)
+      : enclosingScope = scope,
+        library = library,
+        isDartLibrary = library.uri.scheme == "dart",
+        super(scope);
+
+  bool get inConstructor {
+    return functionNestingLevel == 0 && member is KernelConstructorBuilder;
+  }
+
+  bool get isInstanceContext {
+    return isInstanceMember || member is KernelConstructorBuilder;
+  }
+
+  @override
+  void push(Object node) {
+    isFirstIdentifier = false;
+    inInitializer = false;
+    super.push(node);
+  }
+
+  Expression popForValue() => toValue(pop());
+
+  Expression popForEffect() => toEffect(pop());
+
+  Expression popForValueIfNotNull(Object value) {
+    return value == null ? null : popForValue();
+  }
+
+  @override
+  Expression toValue(Object node) {
+    if (node is UnresolvedIdentifier) {
+      return throwNoSuchMethodError(node.name.name, new Arguments.empty(),
+          node.fileOffset, isGetter: true);
+    } else if (node is BuilderAccessor) {
+      return node.buildSimpleRead();
+    } else if (node is TypeVariableBuilder) {
+      TypeParameterType type = node.buildTypesWithBuiltArguments(null);
+      if (!isInstanceContext && type.parameter.parent is Class) {
+        return buildCompileTimeError(
+            "Type variables can only be used in instance methods.");
+      } else {
+        return new TypeLiteral(type);
+      }
+    } else if (node is TypeDeclarationBuilder) {
+      return new TypeLiteral(node.buildTypesWithBuiltArguments(null));
+    } else if (node is KernelTypeBuilder) {
+      return new TypeLiteral(node.build());
+    } else if (node is Expression) {
+      return node;
+    } else if (node is PrefixBuilder) {
+      return buildCompileTimeError("A library can't be used as an expression.");
+    } else {
+      return internalError("Unhandled: ${node.runtimeType}");
+    }
+  }
+
+  Expression toEffect(Object node) {
+    if (node is BuilderAccessor) return node.buildForEffect();
+    return toValue(node);
+  }
+
+  List<Expression> popListForValue(int n) {
+    List<Expression> list =
+        new List<Expression>.filled(n, null, growable: true);
+    for (int i = n - 1; i >= 0; i--) {
+      list[i] = popForValue();
+    }
+    return list;
+  }
+
+  List<Expression> popListForEffect(int n) {
+    List<Expression> list =
+        new List<Expression>.filled(n, null, growable: true);
+    for (int i = n - 1; i >= 0; i--) {
+      list[i] = popForEffect();
+    }
+    return list;
+  }
+
+  Block popBlock(int count) {
+    List<dynamic /*Statement | List<Statement>*/> statements =
+      popList(count) ?? <Statement>[];
+    List<Statement> copy;
+    for (int i = 0; i < statements.length; i++) {
+      var statement = statements[i];
+      if (statement is List) {
+        copy ??= new List<Statement>.from(statements.getRange(0, i));
+        // TODO(sigmund): remove this assignment (issue #28651)
+        Iterable subStatements = statement;
+        copy.addAll(subStatements);
+      } else if (copy != null) {
+        copy.add(statement);
+      }
+    }
+    return new Block(copy ?? statements);
+  }
+
+  Statement popStatementIfNotNull(Object value) {
+    return value == null ? null : popStatement();
+  }
+
+  Statement popStatement() {
+    var statement = pop();
+    if (statement is List) {
+      return new Block(new List<Statement>.from(statement));
+    } else {
+      return statement;
+    }
+  }
+
+  void ignore(Unhandled value) {
+    pop();
+  }
+
+  void enterSwitchScope() {
+    push(switchScope ?? NullValue.SwitchScope);
+    switchScope = scope;
+  }
+
+  void exitSwitchScope() {
+    switchScope = pop();
+  }
+
+  @override
+  Uri get uri => library.fileUri ?? library.uri;
+
+  @override
+  JumpTarget createJumpTarget(JumpTargetKind kind, int charOffset) {
+    return new JumpTarget(kind, member, charOffset);
+  }
+
+  @override
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    debugEvent("Metadata");
+    pop(); // Arguments.
+    popIfNotNull(periodBeforeName); // Postfix.
+    pop(); // Type arguments.
+    pop(); // Expression or type name (depends on arguments).
+    // TODO(ahe): Implement metadata on local declarations.
+  }
+
+  @override
+  void endMetadataStar(int count, bool forParameter) {
+    debugEvent("MetadataStar");
+    push(NullValue.Metadata);
+  }
+
+  @override
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+    debugEvent("TopLevelFields");
+    doFields(count);
+    // There's no metadata here because of a slight assymetry between
+    // [parseTopLevelMember] and [parseMember]. This assymetry leads to
+    // DietListener discarding top-level member metadata.
+  }
+
+  @override
+  void endFields(int count, Token beginToken, Token endToken) {
+    debugEvent("Fields");
+    doFields(count);
+    pop(); // Metadata.
+  }
+
+  void doFields(int count) {
+    for (int i = 0; i < count; i++) {
+      Expression initializer = pop();
+      Identifier identifier = pop();
+      if (initializer != null) {
+        String name = identifier.name;
+        FieldBuilder field;
+        if (classBuilder != null) {
+          field = classBuilder.members[name];
+        } else {
+          field = library.members[name];
+        }
+        if (field.next != null) {
+          // TODO(ahe): This can happen, for example, if a final field is
+          // combined with a setter.
+          internalError(
+              "Unhandled: '${field.name}' has more than one declaration.");
+        }
+        field.initializer = initializer;
+      }
+    }
+    pop(); // Type.
+    pop(); // Modifiers.
+  }
+
+  @override
+  void endMember() {
+    debugEvent("Member");
+    checkEmpty();
+  }
+
+  @override
+  void endFunctionBody(int count, Token beginToken, Token endToken) {
+    debugEvent("FunctionBody");
+    if (beginToken == null) {
+      assert(count == 0);
+      push(NullValue.Block);
+    } else {
+      Block block = popBlock(count);
+      exitLocalScope();
+      push(block);
+    }
+  }
+
+  @override
+  void prepareInitializers() {
+    scope = formalParameterScope;
+    assert(fieldInitializers.isEmpty);
+    final member = this.member;
+    if (member is KernelConstructorBuilder) {
+      Constructor constructor = member.constructor;
+      classBuilder.members.forEach((String name, Builder builder) {
+        if (builder is KernelFieldBuilder && builder.isInstanceMember) {
+          // TODO(ahe): Compute initializers (as in `field = initializer`).
+          fieldInitializers[name] = new FieldInitializer(builder.field, null)
+              ..parent = constructor;
+        }
+      });
+      if (member.formals != null) {
+        for (KernelFormalParameterBuilder formal in member.formals) {
+          if (formal.hasThis) {
+            FieldInitializer initializer = fieldInitializers[formal.name];
+            if (initializer != null) {
+              fieldInitializers.remove(formal.name);
+              initializer.value = new VariableGet(formal.declaration)
+                  ..parent = initializer;
+              member.addInitializer(initializer);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  @override
+  void beginInitializer(Token token) {
+    debugEvent("beginInitializer");
+    inInitializer = true;
+  }
+
+  @override
+  void endInitializer(Token token) {
+    debugEvent("endInitializer");
+    assert(!inInitializer);
+    final member = this.member;
+    var node = pop();
+    Initializer initializer;
+    if (node is Initializer) {
+      initializer = node;
+    } else if (node is BuilderAccessor) {
+      initializer = node.buildFieldInitializer(fieldInitializers);
+    } else if (node is ConstructorInvocation) {
+      initializer = new SuperInitializer(node.target, node.arguments);
+    } else {
+      if (node is !Throw) {
+        node = wrapInvalid(node);
+      }
+      initializer =
+          new LocalInitializer(new VariableDeclaration.forValue(node));
+    }
+    if (member is KernelConstructorBuilder) {
+      member.addInitializer(initializer);
+    } else {
+      addCompileTimeError(token.charOffset,
+          "Can't have initializers: ${member.name}");
+    }
+  }
+
+  @override
+  void handleNoInitializers() {
+    debugEvent("NoInitializers");
+  }
+
+  @override
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    debugEvent("Initializers");
+  }
+
+  @override
+  void finishFunction(FormalParameters formals,
+      AsyncMarker asyncModifier, Statement body) {
+    debugEvent("finishFunction");
+    KernelFunctionBuilder builder = member;
+    if (builder is KernelConstructorBuilder) {
+      if (asyncModifier != AsyncMarker.Sync) {
+        // TODO(ahe): Change this to a null check.
+        addCompileTimeError(body?.fileOffset,
+            "Can't be marked as ${asyncModifier}: ${builder.name}");
+      }
+    } else if (builder is KernelProcedureBuilder) {
+      builder.asyncModifier = asyncModifier;
+    } else {
+      internalError("Unhandled: ${builder.runtimeType}");
+    }
+    builder.body = body;
+    if (formals?.optional != null) {
+      Iterator<FormalParameterBuilder> formalBuilders =
+          builder.formals.skip(formals.required.length).iterator;
+      for (VariableDeclaration parameter in formals.optional.formals) {
+        bool hasMore = formalBuilders.moveNext();
+        assert(hasMore);
+        VariableDeclaration realParameter = formalBuilders.current.target;
+        Expression initializer = parameter.initializer ?? new NullLiteral();
+        realParameter.initializer = initializer
+              ..parent = realParameter;
+      }
+    }
+  }
+
+  @override
+  void endExpressionStatement(Token token) {
+    debugEvent("ExpressionStatement");
+    push(new ExpressionStatement(popForEffect()));
+  }
+
+  @override
+  void endArguments(int count, Token beginToken, Token endToken) {
+    debugEvent("Arguments");
+    List arguments = popList(count) ?? <Expression>[];
+    int firstNamedArgument = arguments.length;
+    for (int i = 0; i < arguments.length; i++) {
+      var node = arguments[i];
+      if (node is NamedExpression) {
+        firstNamedArgument = i < firstNamedArgument ? i : firstNamedArgument;
+      } else {
+        arguments[i] = node = toValue(node);
+        if (i > firstNamedArgument) {
+          internalError("Expected named argument: $node");
+        }
+      }
+    }
+    if (firstNamedArgument < arguments.length) {
+      List<Expression> positional = new List<Expression>.from(
+          arguments.getRange(0, firstNamedArgument));
+      List<NamedExpression> named = new List<NamedExpression>.from(
+          arguments.getRange(firstNamedArgument,arguments.length));
+      push(new Arguments(positional, named: named));
+    } else {
+      push(new Arguments(arguments));
+    }
+  }
+
+  @override
+  void handleParenthesizedExpression(BeginGroupToken token) {
+    debugEvent("ParenthesizedExpression");
+    push(popForValue());
+  }
+
+  @override
+  void endSend(Token token) {
+    debugEvent("Send");
+    Arguments arguments = pop();
+    List<DartType> typeArguments = pop();
+    Object receiver = pop();
+    if (arguments != null && typeArguments != null) {
+      arguments.types.addAll(typeArguments);
+    } else {
+      assert(typeArguments == null);
+    }
+    if (receiver is Identifier) {
+      Name name = new Name(receiver.name, library.library);
+      if (arguments == null) {
+        push(new IncompletePropertyAccessor(this, token.charOffset, name));
+      } else {
+        push(new SendAccessor(this, token.charOffset, name, arguments));
+      }
+    } else if (arguments == null) {
+      push(receiver);
+    } else {
+      push(finishSend(receiver, arguments, token.charOffset));
+    }
+  }
+
+  @override
+  finishSend(Object receiver, Arguments arguments, int charOffset) {
+    if (receiver is BuilderAccessor) {
+      return receiver.doInvocation(charOffset, arguments);
+    } else if (receiver is UnresolvedIdentifier) {
+      return throwNoSuchMethodError(receiver.name.name, arguments,
+          receiver.fileOffset);
+    } else {
+      return buildMethodInvocation(toValue(receiver), callName,
+          arguments, charOffset);
+    }
+  }
+
+  @override
+  void beginCascade(Token token) {
+    debugEvent("beginCascade");
+    Expression expression = popForValue();
+    if (expression is CascadeReceiver) {
+      push(expression);
+      push(new VariableAccessor(
+              this, expression.fileOffset, expression.variable));
+      expression.extend();
+    } else {
+      VariableDeclaration variable =
+          new VariableDeclaration.forValue(expression);
+      push(new CascadeReceiver(variable));
+      push(new VariableAccessor(this, expression.fileOffset, variable));
+    }
+  }
+
+  @override
+  void endCascade() {
+    debugEvent("endCascade");
+    Expression expression = popForEffect();
+    CascadeReceiver cascadeReceiver = pop();
+    cascadeReceiver.finalize(expression);
+    push(cascadeReceiver);
+  }
+
+  @override
+  void handleBinaryExpression(Token token) {
+    debugEvent("BinaryExpression");
+    if (optional(".", token) || optional("..", token)) {
+      return doDotOrCascadeExpression(token);
+    }
+    if (optional("&&", token) || optional("||", token)) {
+      return doLogicalExpression(token);
+    }
+    if (optional("??", token)) return doIfNull(token);
+    if (optional("?.", token)) return doIfNotNull(token);
+    Expression argument = popForValue();
+    var receiver = pop();
+    bool isSuper = false;
+    if (receiver is ThisAccessor && receiver.isSuper) {
+      isSuper = true;
+      receiver = new ThisExpression();
+    }
+    push(buildBinaryOperator(toValue(receiver), token, argument, isSuper));
+  }
+
+  Expression buildBinaryOperator(Expression a, Token token, Expression b,
+      bool isSuper) {
+    bool negate = false;
+    String operator = token.stringValue;
+    if (identical("!=", operator)) {
+      operator = "==";
+      negate = true;
+    }
+    if (!isBinaryOperator(operator) && !isMinusOperator(operator)) {
+      return buildCompileTimeError("Not an operator: '$operator'.",
+          token.charOffset);
+    } else {
+      Expression result = makeBinary(a, new Name(operator), null, b);
+      if (isSuper) {
+        result = toSuperMethodInvocation(result);
+      }
+      return negate ? new Not(result) : result;
+    }
+  }
+
+  void doLogicalExpression(Token token) {
+    Expression argument = popForValue();
+    Expression receiver = popForValue();
+    push(new LogicalExpression(receiver, token.stringValue, argument));
+  }
+
+  /// Handle `a ?? b`.
+  void doIfNull(Token token) {
+    Expression b = popForValue();
+    Expression a = popForValue();
+    VariableDeclaration variable = new VariableDeclaration.forValue(a);
+    push(makeLet(variable,
+            new ConditionalExpression(buildIsNull(new VariableGet(variable)),
+                b, new VariableGet(variable), const DynamicType())));
+  }
+
+  /// Handle `a?.b(...)`.
+  void doIfNotNull(Token token) {
+    IncompleteSend send = pop();
+    push(send.withReceiver(pop(), isNullAware: true));
+  }
+
+  void doDotOrCascadeExpression(Token token) {
+    // TODO(ahe): Handle null-aware.
+    IncompleteSend send = pop();
+    Object receiver = optional(".", token) ? pop() : popForValue();
+    push(send.withReceiver(receiver));
+  }
+
+  @override
+  Expression toSuperMethodInvocation(MethodInvocation node) {
+    Member target = lookupSuperMember(node.name);
+    bool isNoSuchMethod = target == null;
+    if (target is Procedure) {
+      if (!target.isAccessor) {
+        if (areArgumentsCompatible(target.function, node.arguments)) {
+          // TODO(ahe): Use [DirectMethodInvocation] when possible.
+          Expression result = new DirectMethodInvocation(new ThisExpression(),
+              target, node.arguments);
+          result = new SuperMethodInvocation(node.name, node.arguments, null);
+          return result;
+        } else {
+          isNoSuchMethod = true;
+        }
+      }
+    }
+    if (isNoSuchMethod) {
+      return throwNoSuchMethodError(
+          node.name.name, node.arguments, node.fileOffset, isSuper: true);
+    }
+    // TODO(ahe): Use [DirectPropertyGet] when possible.
+    Expression receiver = new DirectPropertyGet(new ThisExpression(), target);
+    receiver = new SuperPropertyGet(node.name, target);
+    return buildMethodInvocation(receiver, callName, node.arguments,
+        node.fileOffset);
+  }
+
+  bool areArgumentsCompatible(FunctionNode function, Arguments arguments) {
+    // TODO(ahe): Implement this.
+    return true;
+  }
+
+  Expression throwNoSuchMethodError(String name, Arguments arguments,
+      int charOffset, {bool isSuper: false, isGetter: false, isSetter: false}) {
+    return builder_accessors.throwNoSuchMethodError(name, arguments, uri,
+        charOffset, coreTypes, isSuper: isSuper, isGetter: isGetter,
+        isSetter: isSetter);
+  }
+
+  @override
+  Member lookupSuperMember(Name name, {bool isSetter: false}) {
+    Class superclass = classBuilder.cls.superclass;
+    return superclass == null
+        ? null
+        : hierarchy.getDispatchTarget(superclass, name, setter: isSetter);
+  }
+
+  @override
+  Constructor lookupConstructor(Name name, {bool isSuper}) {
+    Class cls = classBuilder.cls;
+    if (isSuper) {
+      cls = cls.superclass;
+      while (cls.isMixinApplication) {
+        cls = cls.superclass;
+      }
+    }
+    if (cls != null) {
+      for (Constructor constructor in cls.constructors) {
+        if (constructor.name == name) return constructor;
+      }
+    }
+    return null;
+  }
+
+  @override
+  void beginExpression(Token token) {
+    debugEvent("beginExpression");
+    isFirstIdentifier = true;
+  }
+
+  Builder computeSetter(
+      Builder builder, Scope scope, String name, int charOffset) {
+    if (builder.isSetter) return builder;
+    if (builder.isGetter) return scope.lookupSetter(name, charOffset, uri);
+    return builder.isField ? (builder.isFinal ? null : builder) : null;
+  }
+
+  @override
+  void handleIdentifier(Token token) {
+    debugEvent("handleIdentifier");
+    String name = token.value;
+    if (isFirstIdentifier) {
+      assert(!inInitializer || this.scope == enclosingScope ||
+          this.scope.parent == enclosingScope);
+      // This deals with this kind of initializer: `C(a) : a = a;`
+      Scope scope = inInitializer ? enclosingScope : this.scope;
+      Builder builder = scope.lookup(name, token.charOffset, uri);
+      push(builderToFirstExpression(builder, name, token.charOffset));
+    } else {
+      push(new Identifier(name)..fileOffset = token.charOffset);
+    }
+  }
+
+  @override
+  builderToFirstExpression(Builder builder, String name, int charOffset,
+      {bool isPrefix: false}) {
+    if (builder == null || (!isInstanceContext && builder.isInstanceMember)) {
+      if (!isPrefix && identical(name, "dynamic") && builder == null) {
+        return new KernelNamedTypeBuilder(name, null, charOffset, uri);
+      }
+      Name n = new Name(name, library.library);
+      if (!isPrefix && isInstanceContext) {
+        assert(builder == null);
+        return new ThisPropertyAccessor(this, charOffset, n, null, null);
+      } else {
+        return new UnresolvedIdentifier(n)
+            ..fileOffset = charOffset;
+      }
+    } else if (builder.isTypeDeclaration) {
+      return builder;
+    } else if (builder.isLocal) {
+      return new VariableAccessor(this, charOffset, builder.target);
+    } else if (builder.isInstanceMember) {
+      return new ThisPropertyAccessor(this, charOffset,
+          new Name(name, library.library), null, null);
+    } else if (builder.isRegularMethod) {
+      assert(builder.isStatic || builder.isTopLevel);
+      return new StaticAccessor(this, charOffset, builder.target, null);
+    } else if (builder is PrefixBuilder) {
+      return builder;
+    } else if (builder is MixedAccessor) {
+      return new StaticAccessor(this, charOffset, builder.getter.target,
+          builder.setter.target);
+    } else {
+      if (builder is AccessErrorBuilder) {
+        AccessErrorBuilder error = builder;
+        builder = error.builder;
+      }
+      if (builder.target == null) {
+        return internalError("Unhandled: ${builder}");
+      }
+      Member getter = builder.target.hasGetter ? builder.target : null;
+      Member setter = builder.target.hasSetter ? builder.target : null;
+      setter ??= computeSetter(builder, scope, name, charOffset)?.target;
+      return
+          new StaticAccessor(this, charOffset, getter, setter);
+    }
+  }
+
+  @override
+  void handleQualified(Token period) {
+    debugEvent("Qualified");
+    Identifier name = pop();
+    var receiver = pop();
+    push([receiver, name]);
+  }
+
+  @override
+  void beginLiteralString(Token token) {
+    debugEvent("beginLiteralString");
+    push(token);
+  }
+
+  @override
+  void handleStringPart(Token token) {
+    debugEvent("StringPart");
+    push(token);
+  }
+
+  @override
+  void endLiteralString(int interpolationCount) {
+    debugEvent("endLiteralString");
+    if (interpolationCount == 0) {
+      Token token = pop();
+      push(new StringLiteral(unescapeString(token.value)));
+    } else {
+      List parts = popList(1 + interpolationCount * 2);
+      Token first = parts.first;
+      Token last = parts.last;
+      Quote quote = analyzeQuote(first.value);
+      List<Expression> expressions = <Expression>[];
+      expressions.add(new StringLiteral(unescapeFirstStringPart(
+                  first.value, quote)));
+      for (int i = 1; i < parts.length - 1; i++) {
+        var part = parts[i];
+        if (part is Token) {
+          expressions.add(new StringLiteral(unescape(part.value, quote)));
+        } else {
+          expressions.add(toValue(part));
+        }
+      }
+      expressions.add(
+          new StringLiteral(unescapeLastStringPart(last.value, quote)));
+      push(new StringConcatenation(expressions));
+    }
+  }
+
+  @override
+  void handleStringJuxtaposition(int literalCount) {
+    debugEvent("StringJuxtaposition");
+    List<Expression> parts = popListForValue(literalCount);
+    List<Expression> expressions;
+    // Flatten string juxtapositions of string interpolation.
+    for (int i = 0; i < parts.length; i++) {
+      Expression part = parts[i];
+      if (part is StringConcatenation) {
+        if (expressions == null) {
+          expressions = parts.sublist(0, i);
+        }
+        expressions.addAll(part.expressions);
+      } else {
+        if (expressions != null) {
+          expressions.add(part);
+        }
+      }
+    }
+    push(new StringConcatenation(expressions ?? parts));
+  }
+
+  @override
+  void handleLiteralInt(Token token) {
+    debugEvent("LiteralInt");
+    push(new IntLiteral(int.parse(token.value)));
+  }
+
+  @override
+  void endReturnStatement(
+      bool hasExpression, Token beginToken, Token endToken) {
+    debugEvent("ReturnStatement");
+    Expression expression = hasExpression ? popForValue() : null;
+    if (expression != null && inConstructor) {
+      push(buildCompileTimeErrorStatement("Can't return from a constructor.",
+              beginToken.charOffset));
+    } else {
+      push(new ReturnStatement(expression));
+    }
+  }
+
+  @override
+  void endIfStatement(Token ifToken, Token elseToken) {
+    Statement elsePart = popStatementIfNotNull(elseToken);
+    Statement thenPart = popStatement();
+    Expression condition = popForValue();
+    push(new IfStatement(condition, thenPart, elsePart));
+  }
+
+  @override
+  void endVariableInitializer(Token assignmentOperator) {
+    debugEvent("VariableInitializer");
+    assert(assignmentOperator.stringValue == "=");
+    Expression initializer = popForValue();
+    Identifier identifier = pop();
+    push(new VariableDeclaration(identifier.name, initializer: initializer));
+  }
+
+  @override
+  void endFieldInitializer(Token assignmentOperator) {
+    debugEvent("FieldInitializer");
+    assert(assignmentOperator.stringValue == "=");
+    push(popForValue());
+  }
+
+  @override
+  void handleNoFieldInitializer(Token token) {
+    debugEvent("NoFieldInitializer");
+    push(NullValue.FieldInitializer);
+  }
+
+  @override
+  void endInitializedIdentifier() {
+    // TODO(ahe): Use [InitializedIdentifier] here?
+    debugEvent("InitializedIdentifier");
+    TreeNode node = pop();
+    VariableDeclaration variable;
+    if (node is VariableDeclaration) {
+      variable = node;
+    } else if (node is Identifier) {
+      variable = new VariableDeclaration(node.name);
+    } else {
+      internalError("unhandled identifier: ${node.runtimeType}");
+    }
+    push(variable);
+    scope[variable.name] = new KernelVariableBuilder(variable,
+        // TODO(ahe): This should be `member ?? classBuilder ?? part`, but we
+        // don't have an object representing the current part.
+        member ?? classBuilder);
+  }
+
+  @override
+  void endVariablesDeclaration(int count, Token endToken) {
+    debugEvent("VariablesDeclaration");
+    List<VariableDeclaration> variables = popList(count);
+    DartType type = pop();
+    int modifiers = Modifier.validate(pop());
+    bool isConst = (modifiers & constMask) != 0;
+    bool isFinal = (modifiers & finalMask) != 0;
+    if (type != null || isConst || isFinal) {
+      type ??= const DynamicType();
+      for (VariableDeclaration variable in variables) {
+        variable
+            ..type = type
+            ..isConst = isConst
+            ..isFinal = isFinal;
+      }
+    }
+    if (variables.length != 1) {
+      push(variables);
+    } else {
+      push(variables.single);
+    }
+  }
+
+  @override
+  void endBlock(int count, Token beginToken, Token endToken) {
+    debugEvent("Block");
+    Block block = popBlock(count);
+    exitLocalScope();
+    push(block);
+  }
+
+  @override
+  void handleAssignmentExpression(Token token) {
+    debugEvent("AssignmentExpression");
+    Expression value = popForValue();
+    var accessor = pop();
+    if (accessor is TypeDeclarationBuilder) {
+      push(wrapInvalid(
+              new TypeLiteral(accessor.buildTypesWithBuiltArguments(null))));
+    } else if (accessor is! BuilderAccessor) {
+      push(buildCompileTimeError("Can't assign to this.", token.charOffset));
+    } else {
+      push(new DelayedAssignment(this, token.charOffset, accessor, value,
+              token.stringValue));
+    }
+  }
+
+  @override
+  void enterLoop(int charOffset) {
+    if (peek() is LabelTarget) {
+      LabelTarget target = peek();
+      enterBreakTarget(charOffset, target.breakTarget);
+      enterContinueTarget(charOffset, target.continueTarget);
+    } else{
+      enterBreakTarget(charOffset);
+      enterContinueTarget(charOffset);
+    }
+  }
+
+  void exitLoopOrSwitch(Statement statement) {
+    if (compileTimeErrorInLoopOrSwitch != null) {
+      push(compileTimeErrorInLoopOrSwitch);
+      compileTimeErrorInLoopOrSwitch = null;
+    } else {
+      push(statement);
+    }
+  }
+
+  @override
+  void endForStatement(
+      int updateExpressionCount, Token beginToken, Token endToken) {
+    debugEvent("ForStatement");
+    Statement body = popStatement();
+    List<Expression> updates = popListForEffect(updateExpressionCount);
+    Statement conditionStatement = popStatement();
+    Expression condition = null;
+    if (conditionStatement is ExpressionStatement) {
+      condition = conditionStatement.expression;
+    } else {
+      assert(conditionStatement is EmptyStatement);
+    }
+    List<VariableDeclaration> variables = <VariableDeclaration>[];
+    dynamic variableOrExpression = pop();
+    Statement begin;
+    if (variableOrExpression is BuilderAccessor) {
+      variableOrExpression = variableOrExpression.buildForEffect();
+    }
+    if (variableOrExpression is VariableDeclaration) {
+      variables.add(variableOrExpression);
+    } else if (variableOrExpression is List) {
+      // TODO(sigmund): remove this assignment (see issue #28651)
+      Iterable vars = variableOrExpression;
+      variables.addAll(vars);
+    } else if (variableOrExpression == null) {
+      // Do nothing.
+    } else if (variableOrExpression is Expression) {
+      begin = new ExpressionStatement(variableOrExpression);
+    } else {
+      return internalError("Unhandled: ${variableOrExpression.runtimeType}");
+    }
+    exitLocalScope();
+    JumpTarget continueTarget = exitContinueTarget();
+    JumpTarget breakTarget = exitBreakTarget();
+    if (continueTarget.hasUsers) {
+      body = new LabeledStatement(body);
+      continueTarget.resolveContinues(body);
+    }
+    Statement result = new ForStatement(variables, condition, updates, body);
+    if (begin != null) {
+      result = new Block(<Statement>[begin, result]);
+    }
+    if (breakTarget.hasUsers) {
+      result = new LabeledStatement(result);
+      breakTarget.resolveBreaks(result);
+    }
+    exitLoopOrSwitch(result);
+  }
+
+  @override
+  void endAwaitExpression(Token beginToken, Token endToken) {
+    debugEvent("AwaitExpression");
+    push(new AwaitExpression(popForValue()));
+  }
+
+  @override
+  void handleAsyncModifier(Token asyncToken, Token starToken) {
+    debugEvent("AsyncModifier");
+    push(asyncMarkerFromTokens(asyncToken, starToken));
+  }
+
+  @override
+  void handleLiteralList(
+      int count, Token beginToken, Token constKeyword, Token endToken) {
+    debugEvent("LiteralList");
+    List<Expression> expressions = popListForValue(count);
+    List<DartType> typeArguments = pop();
+    DartType typeArgument = const DynamicType();
+    if (typeArguments != null) {
+      typeArgument = typeArguments.first;
+      if (typeArguments.length > 1) {
+        typeArgument = const DynamicType();
+        warning("Too many type arguments on List literal.",
+            beginToken.charOffset);
+      }
+    }
+    push(new ListLiteral(expressions, typeArgument: typeArgument,
+            isConst: constKeyword != null));
+  }
+
+  @override
+  void handleLiteralBool(Token token) {
+    debugEvent("LiteralBool");
+    bool value = optional("true", token);
+    assert(value || optional("false", token));
+    push(new BoolLiteral(value));
+  }
+
+  @override
+  void handleLiteralDouble(Token token) {
+    debugEvent("LiteralDouble");
+    push(new DoubleLiteral(double.parse(token.value)));
+  }
+
+  @override
+  void handleLiteralNull(Token token) {
+    debugEvent("LiteralNull");
+    push(new NullLiteral());
+  }
+
+  @override
+  void handleLiteralMap(
+      int count, Token beginToken, Token constKeyword, Token endToken) {
+    debugEvent("LiteralMap");
+    List<MapEntry> entries = popList(count) ?? <MapEntry>[];
+    List<DartType> typeArguments = pop();
+    DartType keyType = const DynamicType();
+    DartType valueType =  const DynamicType();
+    if (typeArguments != null) {
+      if (typeArguments.length != 2) {
+        keyType = const DynamicType();
+        valueType = const DynamicType();
+        warning("Map literal requires two type arguments.",
+            beginToken.charOffset);
+      } else {
+        keyType = typeArguments[0];
+        valueType = typeArguments[1];
+      }
+    }
+    push(new MapLiteral(entries, keyType: keyType, valueType: valueType,
+            isConst: constKeyword != null));
+  }
+
+  @override
+  void endLiteralMapEntry(Token colon, Token endToken) {
+    debugEvent("LiteralMapEntry");
+    Expression value = popForValue();
+    Expression key = popForValue();
+    push(new MapEntry(key, value));
+  }
+
+  @override
+  void beginLiteralSymbol(Token token) {
+    isFirstIdentifier = false;
+  }
+
+  String symbolPartToString(name) {
+    if (name is Identifier) {
+      return name.name;
+    } else if (name is Operator) {
+      return name.name;
+    } else {
+      return internalError("Unhandled: ${name.runtimeType}");
+    }
+  }
+
+  @override
+  void endLiteralSymbol(Token hashToken, int identifierCount) {
+    debugEvent("LiteralSymbol");
+    String value;
+    if (identifierCount == 1) {
+      value = symbolPartToString(popForValue());
+    } else {
+      List parts = popList(identifierCount);
+      value = symbolPartToString(parts.first);
+      for (int i = 1; i < parts.length; i++) {
+        value += ".${symbolPartToString(parts[i])}";
+      }
+    }
+    push(new SymbolLiteral(value));
+  }
+
+  DartType toKernelType(String name, List<DartType> arguments, int charOffset) {
+    if (identical(name, "void")) return const VoidType();
+    if (identical(name, "dynamic")) return const DynamicType();
+    Builder builder = scope.lookup(name, charOffset, uri);
+    if (builder is TypeDeclarationBuilder) {
+      return builder.buildTypesWithBuiltArguments(arguments);
+    }
+    if (builder == null)  {
+      print("$uri: Type not found: $name");
+    } else {
+      print("$uri: Not a type: $name");
+    }
+    // TODO(ahe): Create an error somehow.
+    return const DynamicType();
+  }
+
+  @override
+  void endType(Token beginToken, Token endToken) {
+    // TODO(ahe): The scope is wrong for return types of generic functions.
+    debugEvent("Type");
+    List<DartType> arguments = pop();
+    dynamic name = pop();
+    if (name is List) {
+      if (name.length != 2) {
+        internalError("Unexpected: $name.length");
+      }
+      var prefix = name[0];
+      if (prefix is Identifier) {
+        prefix = prefix.name;
+      }
+      var suffix = name[1];
+      if (suffix is Identifier) {
+        suffix = suffix.name;
+      }
+      Builder builder;
+      if (prefix is Builder) {
+        builder = prefix;
+      } else {
+        builder = scope.lookup(prefix, beginToken.charOffset, uri);
+      }
+      if (builder is PrefixBuilder) {
+        name = builder.exports[suffix];
+      } else {
+        push(const DynamicType());
+        addCompileTimeError(beginToken.charOffset,
+            "Can't be used as a type: '${debugName(prefix, suffix)}'.");
+        return;
+      }
+    }
+    if (name is Identifier) {
+      name = name.name;
+    }
+    if (name is BuilderAccessor) {
+      warning("'${beginToken.value}' isn't a type.", beginToken.charOffset);
+      push(const DynamicType());
+    } else if (name is UnresolvedIdentifier) {
+      warning("'${name.name}' isn't a type.", beginToken.charOffset);
+      push(const DynamicType());
+    } else if (name is TypeVariableBuilder) {
+      push(name.buildTypesWithBuiltArguments(arguments));
+    } else if (name is TypeDeclarationBuilder) {
+      push(name.buildTypesWithBuiltArguments(arguments));
+    } else if (name is TypeBuilder) {
+      push(name.build());
+    } else {
+      push(toKernelType(name, arguments, beginToken.charOffset));
+    }
+    if (peek() is TypeParameterType) {
+      TypeParameterType type = peek();
+      if (!isInstanceContext && type.parameter.parent is Class) {
+        pop();
+        warning("Type variables can only be used in instance methods.",
+            beginToken.charOffset);
+        push(const DynamicType());
+      }
+    }
+  }
+
+  @override
+  void handleVoidKeyword(Token token) {
+    debugEvent("VoidKeyword");
+    push(const VoidType());
+  }
+
+  @override
+  void handleAsOperator(Token operator, Token endToken) {
+    debugEvent("AsOperator");
+    DartType type = pop();
+    Expression expression = popForValue();
+    push(new AsExpression(expression, type));
+  }
+
+  @override
+  void handleIsOperator(Token operator, Token not, Token endToken) {
+    debugEvent("IsOperator");
+    DartType type = pop();
+    Expression expression = popForValue();
+    expression = new IsExpression(expression, type);
+    if (not != null) {
+      expression = new Not(expression);
+    }
+    push(expression);
+  }
+
+  @override
+  void handleConditionalExpression(Token question, Token colon) {
+    debugEvent("ConditionalExpression");
+    Expression elseExpression = popForValue();
+    Expression thenExpression = popForValue();
+    Expression condition = popForValue();
+    push(new ConditionalExpression(
+            condition, thenExpression, elseExpression, const DynamicType()));
+  }
+
+  @override
+  void endThrowExpression(Token throwToken, Token endToken) {
+    debugEvent("ThrowExpression");
+    Expression expression = popForValue();
+    push(new Throw(expression));
+  }
+
+  @override
+  void endFormalParameter(Token thisKeyword) {
+    debugEvent("FormalParameter");
+    // TODO(ahe): Need beginToken here.
+    int charOffset = thisKeyword?.charOffset;
+    if (thisKeyword != null) {
+      if (!inConstructor) {
+        addCompileTimeError(thisKeyword.charOffset,
+            "'this' parameters can only be used on constructors.");
+        thisKeyword = null;
+      }
+    }
+    Identifier name = pop();
+    DartType type = pop();
+    pop(); // Modifiers.
+    ignore(Unhandled.Metadata);
+    VariableDeclaration variable;
+    if (!inCatchClause && functionNestingLevel == 0) {
+      dynamic builder = formalParameterScope.lookup(name.name, charOffset, uri);
+      if (builder == null) {
+        if (thisKeyword == null) {
+          internalError("Internal error: formal missing for '${name.name}'");
+        } else {
+          addCompileTimeError(thisKeyword.charOffset,
+              "'${name.name}' isn't a field in this class.");
+          thisKeyword = null;
+        }
+      } else if (thisKeyword == null) {
+        variable = builder.build();
+        variable.initializer = name.initializer;
+      } else if (builder.isField && builder.parent == classBuilder) {
+        FieldBuilder field = builder;
+        if (type != null) {
+          nit("Ignoring type on 'this' parameter '${name.name}'.",
+              name.fileOffset);
+        }
+        type = field.target.type ?? const DynamicType();
+        variable = new VariableDeclaration(name.name, type: type,
+            initializer: name.initializer);
+      } else {
+        addCompileTimeError(name.fileOffset,
+            "'${name.name}' isn't a field in this class.");
+      }
+    }
+    variable ??= new VariableDeclaration(name.name,
+        type: type ?? const DynamicType(), initializer: name.initializer);
+    push(variable);
+  }
+
+  @override
+  void endOptionalFormalParameters(
+      int count, Token beginToken, Token endToken) {
+    debugEvent("OptionalFormalParameters");
+    FormalParameterType kind = optional("{", beginToken)
+        ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
+    push(new OptionalFormals(kind, popList(count)));
+  }
+
+  @override
+  void beginFunctionTypedFormalParameter(Token token) {
+    debugEvent("beginFunctionTypedFormalParameter");
+    functionNestingLevel++;
+  }
+
+  @override
+  void endFunctionTypedFormalParameter(Token token) {
+    debugEvent("FunctionTypedFormalParameter");
+    if (inCatchClause || functionNestingLevel != 0) {
+      exitLocalScope();
+    }
+    FormalParameters formals = pop();
+    ignore(Unhandled.TypeVariables);
+    Identifier name = pop();
+    DartType returnType = pop();
+    push(formals.toFunctionType(returnType));
+    push(name);
+    functionNestingLevel--;
+  }
+
+  @override
+  void handleValuedFormalParameter(Token equals, Token token) {
+    debugEvent("ValuedFormalParameter");
+    Expression initializer = popForValue();
+    Identifier name = pop();
+    push(new InitializedIdentifier(name.name, initializer));
+  }
+
+  @override
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+    debugEvent("FormalParameters");
+    OptionalFormals optional;
+    if (count > 0 && peek() is OptionalFormals) {
+      optional = pop();
+      count--;
+    }
+    FormalParameters formals = new FormalParameters(
+        popList(count) ?? <VariableDeclaration>[], optional);
+    push(formals);
+    if (inCatchClause || functionNestingLevel != 0) {
+      enterLocalScope(formals.computeFormalParameterScope(
+              scope, member ?? classBuilder ?? library));
+    }
+  }
+
+  @override
+  void beginCatchClause(Token token) {
+    debugEvent("beginCatchClause");
+    inCatchClause = true;
+  }
+
+  @override
+  void endCatchClause(Token token) {
+    debugEvent("CatchClause");
+    inCatchClause = false;
+  }
+
+  @override
+  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+    debugEvent("CatchBlock");
+    Block body = pop();
+    if (catchKeyword != null) {
+      exitLocalScope();
+    }
+    FormalParameters catchParameters = popIfNotNull(catchKeyword);
+    DartType type = popIfNotNull(onKeyword) ?? const DynamicType();
+    VariableDeclaration exception;
+    VariableDeclaration stackTrace;
+    if (catchParameters != null) {
+      if (catchParameters.required.length > 0) {
+        exception = catchParameters.required[0];
+      }
+      if (catchParameters.required.length > 1) {
+        stackTrace = catchParameters.required[1];
+      }
+      if (catchParameters.required.length > 2 ||
+          catchParameters.optional != null) {
+        body = new Block(<Statement>[new InvalidStatement()]);
+        compileTimeErrorInTry ??= buildCompileTimeErrorStatement(
+            "Invalid catch arguments.", catchKeyword.next.charOffset);
+      }
+    }
+    push(new Catch(exception, body, guard: type, stackTrace: stackTrace));
+  }
+
+  @override
+  void endTryStatement(
+      int catchCount, Token tryKeyword, Token finallyKeyword) {
+    Statement finallyBlock = popStatementIfNotNull(finallyKeyword);
+    List<Catch> catches = popList(catchCount);
+    Statement tryBlock = popStatement();
+    if (compileTimeErrorInTry == null) {
+      if (catches != null) {
+        tryBlock = new TryCatch(tryBlock, catches);
+      }
+      if (finallyBlock != null) {
+        tryBlock = new TryFinally(tryBlock, finallyBlock);
+      }
+      push(tryBlock);
+    } else {
+      push(compileTimeErrorInTry);
+      compileTimeErrorInTry = null;
+    }
+  }
+
+  @override
+  void handleNoExpression(Token token) {
+    debugEvent("NoExpression");
+    push(NullValue.Expression);
+  }
+
+  @override
+  void handleIndexedExpression(
+      Token openCurlyBracket, Token closeCurlyBracket) {
+    debugEvent("IndexedExpression");
+    Expression index = popForValue();
+    Expression receiver = popForValue();
+    push(IndexAccessor.make(this, openCurlyBracket.charOffset, receiver, index,
+            null, null));
+  }
+
+  @override
+  void handleUnaryPrefixExpression(Token token) {
+    debugEvent("UnaryPrefixExpression");
+    Expression expression = popForValue();
+    if (optional("!", token)) {
+      push(new Not(expression));
+    } else {
+      String operator = token.stringValue;
+      if (optional("-", token)) {
+        operator = "unary-";
+      }
+      push(buildMethodInvocation(expression, new Name(operator),
+              new Arguments.empty(), token.charOffset));
+    }
+  }
+
+  Name incrementOperator(Token token) {
+    if (optional("++", token)) return plusName;
+    if (optional("--", token)) return minusName;
+    return internalError("Unknown increment operator: ${token.value}");
+  }
+
+  @override
+  void handleUnaryPrefixAssignmentExpression(Token token) {
+    debugEvent("UnaryPrefixAssignmentExpression");
+    var accessor = pop();
+    if (accessor is BuilderAccessor) {
+      push(accessor.buildPrefixIncrement(incrementOperator(token)));
+    } else {
+      push(wrapInvalid(toValue(accessor)));
+    }
+  }
+
+  @override
+  void handleUnaryPostfixAssignmentExpression(Token token) {
+    debugEvent("UnaryPostfixAssignmentExpression");
+    var accessor = pop();
+    if (accessor is BuilderAccessor) {
+      push(new DelayedPostfixIncrement(this, token.charOffset, accessor,
+              incrementOperator(token), null));
+    } else {
+      push(wrapInvalid(toValue(accessor)));
+    }
+  }
+
+  @override
+  void endConstructorReference(
+      Token start, Token periodBeforeName, Token endToken) {
+    debugEvent("ConstructorReference");
+    // A constructor reference can contain up to three identifiers:
+    //
+    //     a) type <type-arguments>?
+    //     b) type <type-arguments>? . name
+    //     c) prefix . type <type-arguments>?
+    //     d) prefix . type <type-arguments>? . name
+    //
+    // This isn't a legal constructor reference:
+    //
+    //     type . name <type-arguments>
+    //
+    // But the parser can't tell this from type c) above.
+    //
+    // This method pops 2 (or 3 if periodBeforeName != null) values from the
+    // stack and pushes 3 values: a type, a list of type arguments, and a name.
+    //
+    // If the constructor reference can be resolved, type is either a
+    // ClassBuilder, or a ThisPropertyAccessor. Otherwise, it's an error that
+    // should be handled later.
+    Identifier suffix = popIfNotNull(periodBeforeName);
+    Identifier identifier;
+    List<DartType> typeArguments = pop();
+    dynamic type = pop();
+    if (type is List) {
+      var prefix = type[0];
+      identifier = type[1];
+      if (prefix is PrefixBuilder) {
+        // TODO(ahe): Handle privacy in prefix.exports.
+        type = builderToFirstExpression(
+            prefix.exports[identifier.name], identifier.name, start.charOffset);
+        identifier = null;
+      } else if (prefix is ClassBuilder) {
+        type = prefix;
+      } else {
+        type = new Identifier(start.value)..fileOffset = start.charOffset;
+      }
+    }
+    String name;
+    if (identifier != null && suffix != null) {
+      name = "${identifier.name}.${suffix.name}";
+    } else if (identifier != null) {
+      name = identifier.name;
+    } else if (suffix != null) {
+      name = suffix.name;
+    } else {
+      name = "";
+    }
+    push(type);
+    push(typeArguments ?? NullValue.TypeArguments);
+    push(name);
+  }
+
+  @override
+  Expression buildStaticInvocation(Member target, Arguments arguments,
+      {bool isConst: false}) {
+    List<TypeParameter> typeParameters = target.function.typeParameters;
+    if (target is Constructor) {
+      typeParameters = target.enclosingClass.typeParameters;
+    }
+    if (!addDefaultArguments(target.function, arguments, typeParameters)) {
+      return throwNoSuchMethodError(target.name.name, arguments, -1);
+    }
+    if (target is Constructor) {
+      return new ConstructorInvocation(target, arguments)
+          ..isConst = isConst;
+    } else {
+      return new StaticInvocation(target, arguments)
+          ..isConst = isConst;
+    }
+  }
+
+  bool addDefaultArguments(FunctionNode function, Arguments arguments,
+      List<TypeParameter> typeParameters) {
+    bool missingInitializers = false;
+
+    Expression defaultArgumentFrom(Expression expression) {
+      if (expression == null) {
+        missingInitializers = true;
+        return null;
+      }
+      cloner ??= new CloneVisitor();
+      return cloner.clone(expression);
+    }
+
+    if (arguments.positional.length < function.requiredParameterCount ||
+        arguments.positional.length > function.positionalParameters.length) {
+      return false;
+    }
+    for (int i = arguments.positional.length;
+         i < function.positionalParameters.length;
+         i++) {
+      var expression =
+          defaultArgumentFrom(function.positionalParameters[i].initializer);
+      expression?.parent = arguments;
+      arguments.positional.add(expression);
+    }
+    Map<String, VariableDeclaration> names;
+    if (function.namedParameters.isNotEmpty) {
+      names = <String, VariableDeclaration>{};
+      for (VariableDeclaration parameter in function.namedParameters) {
+        names[parameter.name] = parameter;
+      }
+    }
+    if (arguments.named.isNotEmpty) {
+      if (names == null) return false;
+      for (NamedExpression argument in arguments.named) {
+        VariableDeclaration parameter = names.remove(argument.name);
+        if (parameter == null) {
+          return false;
+        }
+      }
+    }
+    if (names != null) {
+      for (String name in names.keys) {
+        VariableDeclaration parameter = names[name];
+        arguments.named.add(
+            new NamedExpression(
+                name, defaultArgumentFrom(parameter.initializer))
+            ..parent = arguments);
+      }
+    }
+    if (typeParameters.length != arguments.types.length) {
+      arguments.types.clear();
+      for (int i = 0; i < typeParameters.length; i++) {
+        arguments.types.add(const DynamicType());
+      }
+    }
+
+    if (missingInitializers) {
+      library.addArgumentsWithMissingDefaultValues(arguments, function);
+    }
+    return true;
+  }
+
+  @override
+  void handleNewExpression(Token token) {
+    debugEvent("NewExpression");
+    Arguments arguments = pop();
+    String name = pop();
+    List<DartType> typeArguments = pop();
+    var type = pop();
+
+    if (typeArguments != null) {
+      assert(arguments.types.isEmpty);
+      arguments.types.addAll(typeArguments);
+    }
+
+    String errorName;
+    if (type is ClassBuilder) {
+      Builder b = type.findConstructorOrFactory(name);
+      Member target;
+      if (b == null) {
+        // Not found. Reported below.
+      } else if (b.isConstructor) {
+        if (type.isAbstract) {
+          // TODO(ahe): Generate abstract instantiation error.
+        } else {
+          target = b.target;
+        }
+      } else if (b.isFactory) {
+        target = getRedirectionTarget(b.target);
+        if (target == null) {
+          push(buildCompileTimeError(
+                  "Cyclic definition of factory '${name}'.",
+                  token.charOffset));
+          return;
+        }
+      }
+      if (target is Constructor ||
+          (target is Procedure && target.kind == ProcedureKind.Factory)) {
+        push(buildStaticInvocation(
+                target, arguments, isConst: optional("const", token)));
+        return;
+      } else {
+        errorName = debugName(type.name, name);
+      }
+    } else {
+      errorName = debugName(getNodeName(type), name);
+    }
+    errorName ??= name;
+    push(throwNoSuchMethodError(errorName, arguments, token.charOffset));
+  }
+
+  @override
+  void handleConstExpression(Token token) {
+    debugEvent("ConstExpression");
+    handleNewExpression(token);
+  }
+
+  @override
+  void endTypeArguments(int count, Token beginToken, Token endToken) {
+    debugEvent("TypeArguments");
+    push(popList(count));
+  }
+
+  @override
+  void handleThisExpression(Token token) {
+    debugEvent("ThisExpression");
+    if (isFirstIdentifier && isInstanceContext) {
+      push(new ThisAccessor(this, token.charOffset, inInitializer));
+    } else {
+      push(new IncompleteError(
+              this, token.charOffset, "Expected identifier, but got 'this'."));
+    }
+  }
+
+  @override
+  void handleSuperExpression(Token token) {
+    debugEvent("SuperExpression");
+    if (isFirstIdentifier && isInstanceContext) {
+      Member member = this.member.target;
+      member.transformerFlags |= TransformerFlag.superCalls;
+      push(new ThisAccessor(this, token.charOffset, inInitializer,
+              isSuper: true));
+    } else {
+      push(new IncompleteError(
+              this, token.charOffset, "Expected identifier, but got 'super'."));
+    }
+  }
+
+  @override
+  void handleNamedArgument(Token colon) {
+    debugEvent("NamedArgument");
+    Expression value = popForValue();
+    Identifier identifier = pop();
+    push(new NamedExpression(identifier.name, value));
+  }
+
+  @override
+  void endFunctionName(Token token) {
+    debugEvent("FunctionName");
+    Identifier name = pop();
+    VariableDeclaration variable = new VariableDeclaration(
+        name.name, isFinal: true);
+    push(new FunctionDeclaration(variable,
+            new FunctionNode(new InvalidStatement())));
+    scope[variable.name] = new KernelVariableBuilder(variable,
+        // TODO(ahe): This should be `member ?? classBuilder ?? part`, but we
+        // don't have an object representing the current part.
+        member ?? classBuilder);
+    enterLocalScope();
+  }
+
+  @override
+  void beginFunction(Token token) {
+    debugEvent("beginFunction");
+    functionNestingLevel++;
+  }
+
+  @override
+  void beginUnnamedFunction(Token token) {
+    debugEvent("beginUnnamedFunction");
+    functionNestingLevel++;
+  }
+
+  @override
+  void endFunction(Token getOrSet, Token endToken) {
+    debugEvent("Function");
+    Statement body = popStatement();
+    AsyncMarker asyncModifier = pop();
+    if (functionNestingLevel != 0) {
+      exitLocalScope();
+    }
+    FormalParameters formals = pop();
+    List<TypeParameter> typeParameters = pop();
+    push(formals.addToFunction(new FunctionNode(body,
+                typeParameters: typeParameters, asyncMarker: asyncModifier)));
+    functionNestingLevel--;
+  }
+
+  @override
+  void endFunctionDeclaration(Token token) {
+    debugEvent("FunctionDeclaration");
+    FunctionNode function = pop();
+    exitLocalScope();
+    FunctionDeclaration declaration = pop();
+    function.returnType = pop() ?? const DynamicType();
+    pop(); // Modifiers.
+    declaration.function = function;
+    function.parent = declaration;
+    push(declaration);
+  }
+
+  @override
+  void endUnnamedFunction(Token token) {
+    debugEvent("UnnamedFunction");
+    Statement body = popStatement();
+    AsyncMarker asyncModifier = pop();
+    exitLocalScope();
+    FormalParameters formals = pop();
+    List<TypeParameter> typeParameters = pop();
+    FunctionNode function = formals.addToFunction(new FunctionNode(body,
+            typeParameters: typeParameters, asyncMarker: asyncModifier));
+    push(new FunctionExpression(function));
+    functionNestingLevel--;
+  }
+
+  @override
+  void endDoWhileStatement(
+      Token doKeyword, Token whileKeyword, Token endToken) {
+    debugEvent("DoWhileStatement");
+    Expression condition = popForValue();
+    Statement body = popStatement();
+    JumpTarget continueTarget = exitContinueTarget();
+    JumpTarget breakTarget = exitBreakTarget();
+    if (continueTarget.hasUsers) {
+      body = new LabeledStatement(body);
+      continueTarget.resolveContinues(body);
+    }
+    Statement result = new DoStatement(body, condition);
+    if (breakTarget.hasUsers) {
+      result = new LabeledStatement(result);
+      breakTarget.resolveBreaks(result);
+    }
+    exitLoopOrSwitch(result);
+  }
+
+  @override
+  void beginForInExpression(Token token) {
+    enterLocalScope(scope.parent);
+  }
+
+  @override
+  void endForInExpression(Token token) {
+    debugEvent("ForInExpression");
+    Expression expression = popForValue();
+    exitLocalScope();
+    push(expression ?? NullValue.Expression);
+  }
+
+  @override
+  void endForIn(
+      Token awaitToken, Token forToken, Token inKeyword, Token endToken) {
+    debugEvent("ForIn");
+    Statement body = popStatement();
+    Expression expression = popForValue();
+    var lvalue = pop();
+    exitLocalScope();
+    JumpTarget continueTarget = exitContinueTarget();
+    JumpTarget breakTarget = exitBreakTarget();
+    if (continueTarget.hasUsers) {
+      body = new LabeledStatement(body);
+      continueTarget.resolveContinues(body);
+    }
+    VariableDeclaration variable;
+    if (lvalue is VariableDeclaration) {
+      variable = lvalue;
+    } else if (lvalue is BuilderAccessor) {
+      /// We are in this case, where `lvalue` isn't a [VariableDeclaration]:
+      ///
+      ///     for (lvalue in expression) body
+      ///
+      /// This is normalized to:
+      ///
+      ///     for (final #t in expression) {
+      ///       lvalue = #t;
+      ///       body;
+      ///     }
+      variable = new VariableDeclaration.forValue(null);
+      body = combineStatements(
+          new ExpressionStatement(
+              lvalue.buildAssignment(
+                  new VariableGet(variable), voidContext: true)),
+          body);
+    } else {
+      variable = new VariableDeclaration.forValue(
+          buildCompileTimeError("Expected lvalue, but got ${lvalue}",
+              forToken.next.next.charOffset));
+    }
+    Statement result = new ForInStatement(variable, expression, body,
+        isAsync: awaitToken != null);
+    if (breakTarget.hasUsers) {
+      result = new LabeledStatement(result);
+      breakTarget.resolveBreaks(result);
+    }
+    exitLoopOrSwitch(result);
+  }
+
+  @override
+  void handleLabel(Token token) {
+    debugEvent("Label");
+    Identifier identifier = pop();
+    push(new Label(identifier.name));
+  }
+
+  @override
+  void beginLabeledStatement(Token token, int labelCount) {
+    debugEvent("beginLabeledStatement");
+    List<Label> labels = popList(labelCount);
+    enterLocalScope();
+    LabelTarget target = new LabelTarget(member, token.charOffset);
+    for (Label label in labels) {
+      scope[label.name] = target;
+    }
+    push(target);
+  }
+
+  @override
+  void endLabeledStatement(int labelCount) {
+    debugEvent("LabeledStatement");
+    Statement statement = popStatement();
+    LabelTarget target = pop();
+    exitLocalScope();
+    if (target.breakTarget.hasUsers) {
+      if (statement is! LabeledStatement) {
+        statement = new LabeledStatement(statement);
+      }
+      target.breakTarget.resolveBreaks(statement);
+    }
+    if (target.continueTarget.hasUsers) {
+      if (statement is! LabeledStatement) {
+        statement = new LabeledStatement(statement);
+      }
+      target.continueTarget.resolveContinues(statement);
+    }
+    push(statement);
+  }
+
+  @override
+  void endRethrowStatement(Token throwToken, Token endToken) {
+    debugEvent("RethrowStatement");
+    push(new ExpressionStatement(new Rethrow()));
+  }
+
+  @override
+  void handleFinallyBlock(Token finallyKeyword) {
+    debugEvent("FinallyBlock");
+    // Do nothing, handled by [endTryStatement].
+  }
+
+  @override
+  void endWhileStatement(Token whileKeyword, Token endToken) {
+    debugEvent("WhileStatement");
+    Statement body = popStatement();
+    Expression condition = popForValue();
+    JumpTarget continueTarget = exitContinueTarget();
+    JumpTarget breakTarget = exitBreakTarget();
+    if (continueTarget.hasUsers) {
+      body = new LabeledStatement(body);
+      continueTarget.resolveContinues(body);
+    }
+    Statement result = new WhileStatement(condition, body);
+    if (breakTarget.hasUsers) {
+      result = new LabeledStatement(result);
+      breakTarget.resolveBreaks(result);
+    }
+    exitLoopOrSwitch(result);
+  }
+
+  @override
+  void handleEmptyStatement(Token token) {
+    debugEvent("EmptyStatement");
+    push(new EmptyStatement());
+  }
+
+  @override
+  void handleAssertStatement(
+      Token assertKeyword, Token commaToken, Token semicolonToken) {
+    debugEvent("AssertStatement");
+    Expression message = popForValueIfNotNull(commaToken);
+    Expression condition = popForValue();
+    push(new AssertStatement(condition, message));
+  }
+
+  @override
+  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+    debugEvent("YieldStatement");
+    push(new YieldStatement(popForValue(), isYieldStar: starToken != null));
+  }
+
+  @override
+  void beginSwitchBlock(Token token) {
+    debugEvent("beginSwitchBlock");
+    enterLocalScope();
+    enterSwitchScope();
+    enterBreakTarget(token.charOffset);
+  }
+
+  @override
+  void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) {
+    debugEvent("beginSwitchCase");
+    List labelsAndExpressions = popList(labelCount + expressionCount);
+    List<Label> labels = <Label>[];
+    List<Expression> expressions = <Expression>[];
+    if (labelsAndExpressions != null) {
+      for (var labelOrExpression in labelsAndExpressions) {
+        if (labelOrExpression is Label) {
+          labels.add(labelOrExpression);
+        } else {
+          expressions.add(toValue(labelOrExpression));
+        }
+      }
+    }
+    assert(scope == switchScope);
+    for (Label label in labels) {
+      Builder existing = scope.local[label.name];
+      if (existing == null) {
+        scope[label.name] = createGotoTarget(firstToken.charOffset);
+      } else {
+        // TODO(ahe): Should validate this is a goto target and not duplicated.
+      }
+    }
+    push(expressions);
+    push(labels);
+    enterLocalScope();
+  }
+
+  @override
+  void handleSwitchCase(
+      int labelCount,
+      int expressionCount,
+      Token defaultKeyword,
+      int statementCount,
+      Token firstToken,
+      Token endToken) {
+    debugEvent("SwitchCase");
+    Block block = popBlock(statementCount);
+    exitLocalScope();
+    List<Label> labels = pop();
+    List<Expression> expressions = pop();
+    push(new SwitchCase(expressions, block, isDefault: defaultKeyword != null));
+    push(labels);
+  }
+
+  @override
+  void endSwitchStatement(Token switchKeyword, Token endToken) {
+    debugEvent("SwitchStatement");
+    // Do nothing. Handled by [endSwitchBlock].
+  }
+
+  @override
+  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
+    debugEvent("SwitchBlock");
+    List<SwitchCase> cases =
+        new List<SwitchCase>.filled(caseCount, null, growable: true);
+    for (int i = caseCount - 1; i >= 0; i--) {
+      List<Label> labels = pop();
+      SwitchCase current = cases[i] = pop();
+      for (Label label in labels) {
+        JumpTarget target =
+            switchScope.lookup(label.name, label.fileOffset, uri);
+        if (target != null) {
+          target.resolveGotos(current);
+        }
+      }
+      // TODO(ahe): Validate that there's only one default and it's last.
+    }
+    JumpTarget target = exitBreakTarget();
+    exitSwitchScope();
+    exitLocalScope();
+    Expression expression = popForValue();
+    Statement result = new SwitchStatement(expression, cases);
+    if (target.hasUsers) {
+      result = new LabeledStatement(result);
+      target.resolveBreaks(result);
+    }
+    exitLoopOrSwitch(result);
+  }
+
+  @override
+  void handleCaseMatch(Token caseKeyword, Token colon) {
+    debugEvent("CaseMatch");
+    // Do nothing. Handled by [handleSwitchCase].
+  }
+
+  @override
+  void handleBreakStatement(
+      bool hasTarget, Token breakKeyword, Token endToken) {
+    debugEvent("BreakStatement");
+    var target = breakTarget;
+    String name;
+    if (hasTarget) {
+      Identifier identifier = pop();
+      name = identifier.name;
+      target = scope.lookup(
+          identifier.name, breakKeyword.next.charOffset, uri);
+    }
+    if (target == null && name == null) {
+      push(compileTimeErrorInLoopOrSwitch =
+          buildCompileTimeErrorStatement(
+              "No target of break.", breakKeyword.charOffset));
+    } else if (target == null || target is! JumpTarget
+        || !target.isBreakTarget) {
+      push(compileTimeErrorInLoopOrSwitch =
+          buildCompileTimeErrorStatement("Can't break to '$name'.",
+              breakKeyword.next.charOffset));
+    } else {
+      BreakStatement statement = new BreakStatement(null);
+      target.addBreak(statement);
+      push(statement);
+    }
+  }
+
+  @override
+  void handleContinueStatement(
+      bool hasTarget, Token continueKeyword, Token endToken) {
+    debugEvent("ContinueStatement");
+    var target = continueTarget;
+    String name;
+    if (hasTarget) {
+      Identifier identifier = pop();
+      name = identifier.name;
+      target = scope.lookup(
+          identifier.name, continueKeyword.next.charOffset, uri);
+      if (target != null && target is! JumpTarget) {
+        push(compileTimeErrorInLoopOrSwitch =
+            buildCompileTimeErrorStatement(
+                "Target of continue must be a label.",
+                continueKeyword.charOffset));
+        return;
+      }
+      if (target == null) {
+        if (switchScope == null) {
+          push(buildCompileTimeErrorStatement("Can't find label '$name'.",
+                  continueKeyword.next.charOffset));
+          return;
+        }
+        switchScope[identifier.name] = target =
+            createGotoTarget(identifier.fileOffset);
+      }
+      if (target.isGotoTarget) {
+        ContinueSwitchStatement statement = new ContinueSwitchStatement(null);
+        target.addGoto(statement);
+        push(statement);
+        return;
+      }
+    }
+    if (target == null) {
+      push(compileTimeErrorInLoopOrSwitch =
+          buildCompileTimeErrorStatement("No target of continue.",
+              continueKeyword.charOffset));
+    } else if (!target.isContinueTarget) {
+      push(compileTimeErrorInLoopOrSwitch =
+          buildCompileTimeErrorStatement("Can't continue at '$name'.",
+              continueKeyword.next.charOffset));
+    } else {
+      BreakStatement statement = new BreakStatement(null);
+      target.addContinue(statement);
+      push(statement);
+    }
+  }
+
+  @override
+  void endTypeVariable(Token token, Token extendsOrSuper) {
+    logEvent("TypeVariable");
+    // TODO(ahe): Implement this when enabling generic method syntax.
+  }
+
+  @override
+  void endTypeVariables(int count, Token beginToken, Token endToken) {
+    logEvent("TypeVariables");
+    // TODO(ahe): Implement this when enabling generic method syntax.
+  }
+
+  @override
+  void handleModifier(Token token) {
+    debugEvent("Modifier");
+    // TODO(ahe): Copied from outline_builder.dart.
+    push(new Modifier.fromString(token.stringValue));
+  }
+
+  @override
+  void handleModifiers(int count) {
+    debugEvent("Modifiers");
+    // TODO(ahe): Copied from outline_builder.dart.
+    push(popList(count) ?? NullValue.Modifiers);
+  }
+
+  @override
+  void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
+    super.handleRecoverableError(token, kind, arguments);
+    if (!hasParserError) {
+      print("$uri:${recoverableErrors.last}");
+    }
+    hasParserError = true;
+  }
+
+  @override
+  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+    if (isDartLibrary && kind == ErrorKind.ExpectedFunctionBody) {
+      Token recover = skipNativeClause(token);
+      if (recover != null) return recover;
+    } else if (kind == ErrorKind.UnexpectedToken) {
+      String expected = arguments["expected"];
+      const List<String> trailing = const <String>[")", "}", ";", ","];
+      if (trailing.contains(token.stringValue) && trailing.contains(expected)) {
+        arguments.putIfAbsent("actual", () => token.value);
+        handleRecoverableError(token, ErrorKind.ExpectedButGot, arguments);
+      }
+      return token;
+    }
+    return super.handleUnrecoverableError(token, kind, arguments);
+  }
+
+  void warning(error, [int charOffset = -1]) {
+    String message = new InputError(uri, charOffset, error).format();
+    print(message);
+  }
+
+  void nit(error, [int charOffset = -1]) {
+    if (!showNits) return;
+    String message = new InputError(uri, charOffset, error).format();
+    print(message);
+  }
+
+  @override
+  Expression buildCompileTimeError(error, [int charOffset = -1]) {
+    String message = new InputError(uri, charOffset, error).format();
+    print(message);
+    Builder constructor = library.loader.getCompileTimeError();
+    return new Throw(
+        buildStaticInvocation(constructor.target,
+            new Arguments(<Expression>[new StringLiteral(message)]),
+            isConst: false)); // TODO(ahe): Make this const.
+  }
+
+  Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) {
+    return new ExpressionStatement(buildCompileTimeError(error, charOffset));
+  }
+
+  @override
+  Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) {
+    return new LocalInitializer(
+        new VariableDeclaration.forValue(
+            buildCompileTimeError(error, charOffset)));
+  }
+
+
+  @override
+  Expression buildProblemExpression(Builder builder, String name) {
+    if (builder is AmbiguousBuilder) {
+      return buildCompileTimeError("Duplicated named: '$name'.");
+    } else if (builder is AccessErrorBuilder) {
+      return buildCompileTimeError("Access error: '$name'.");
+    } else {
+      return internalError("Unhandled: ${builder.runtimeType}");
+    }
+  }
+
+  @override
+  void handleOperator(Token token) {
+    debugEvent("Operator");
+    push(new Operator(token.stringValue)..fileOffset = token.charOffset);
+  }
+
+  dynamic addCompileTimeError(int charOffset, String message) {
+    return library.addCompileTimeError(charOffset, message, uri);
+  }
+
+  @override
+  void handleInvalidFunctionBody(Token token) {
+    if (member.isNative) {
+      push(NullValue.FunctionBody);
+    } else {
+      push(new Block(<Statement>[new InvalidStatement()]));
+    }
+  }
+
+  @override
+  void debugEvent(String name) {
+    // printEvent(name);
+  }
+}
+
+// TODO(ahe): Shouldn't need to be an expression.
+class UnresolvedIdentifier extends InvalidExpression {
+  final Name name;
+
+  UnresolvedIdentifier(this.name);
+
+  String toString() => "unresolved-identifier($name)";
+}
+
+// TODO(ahe): Shouldn't need to be an expression.
+class Identifier extends InvalidExpression {
+  final String name;
+
+  Identifier(this.name);
+
+  Expression get initializer => null;
+
+  String toString() => "identifier($name)";
+}
+
+// TODO(ahe): Shouldn't need to be an expression.
+class Operator extends InvalidExpression {
+  final String name;
+
+  Operator(this.name);
+
+  String toString() => "operator($name)";
+}
+
+class InitializedIdentifier extends Identifier {
+  final Expression initializer;
+
+  InitializedIdentifier(String name, this.initializer)
+      : super(name);
+
+  String toString() => "initialized-identifier($name, $initializer)";
+}
+
+// TODO(ahe): Shouldn't need to be an expression.
+class Label extends InvalidExpression {
+  String name;
+
+  Label(this.name);
+
+  String toString() => "label($name)";
+}
+
+class CascadeReceiver extends Let {
+  Let nextCascade;
+
+  CascadeReceiver(VariableDeclaration variable)
+      : super(variable,
+           makeLet(new VariableDeclaration.forValue(new InvalidExpression()),
+              new VariableGet(variable))) {
+    nextCascade = body;
+  }
+
+  void extend() {
+    assert(nextCascade.variable.initializer is! InvalidExpression);
+    Let newCascade = makeLet(
+        new VariableDeclaration.forValue(new InvalidExpression()),
+        nextCascade.body);
+    nextCascade.body = newCascade;
+    newCascade.parent = nextCascade;
+    nextCascade = newCascade;
+  }
+
+  void finalize(Expression expression) {
+    assert(nextCascade.variable.initializer is InvalidExpression);
+    nextCascade.variable.initializer = expression;
+    expression.parent = nextCascade.variable;
+  }
+}
+
+abstract class ContextAccessor extends BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  final BuilderAccessor accessor;
+
+  ContextAccessor(this.helper, this.charOffset, this.accessor);
+
+  String get plainNameForRead => internalError("Unsupported operation.");
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    print("$uri:$charOffset: Internal error: Unhandled: ${runtimeType}");
+    return internalError("Unhandled: ${runtimeType}");
+  }
+
+  Expression buildSimpleRead();
+
+  Expression buildForEffect();
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return internalError("not supported");
+  }
+
+  Expression buildNullAwareAssignment(Expression value, DartType type,
+      {bool voidContext: false}) {
+    return internalError("not supported");
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("not supported");
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("not supported");
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("not supported");
+  }
+
+  makeInvalidRead() => internalError("not supported");
+
+  makeInvalidWrite(Expression value) => internalError("not supported");
+}
+
+class DelayedAssignment extends ContextAccessor {
+  final Expression value;
+
+  final String assignmentOperator;
+
+  DelayedAssignment(BuilderHelper helper, int charOffset,
+      BuilderAccessor accessor, this.value, this.assignmentOperator)
+      : super(helper, charOffset, accessor);
+
+  Expression buildSimpleRead() {
+    return handleAssignment(false);
+  }
+
+  Expression buildForEffect() {
+    return handleAssignment(true);
+  }
+
+  Expression handleAssignment(bool voidContext) {
+    if (identical("=", assignmentOperator)) {
+      return accessor.buildAssignment(value, voidContext: voidContext);
+    } else if (identical("+=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          plusName, value, voidContext: voidContext);
+    } else if (identical("-=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          minusName, value, voidContext: voidContext);
+    } else if (identical("*=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          multiplyName, value, voidContext: voidContext);
+    } else if (identical("%=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          percentName, value, voidContext: voidContext);
+    } else if (identical("&=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          ampersandName, value, voidContext: voidContext);
+    } else if (identical("/=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          divisionName, value, voidContext: voidContext);
+    } else if (identical("<<=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          leftShiftName, value, voidContext: voidContext);
+    } else if (identical(">>=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          rightShiftName, value, voidContext: voidContext);
+    } else if (identical("??=", assignmentOperator)) {
+      return accessor.buildNullAwareAssignment(
+          value, const DynamicType(), voidContext: voidContext);
+    } else if (identical("^=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          caretName, value, voidContext: voidContext);
+    } else if (identical("|=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          barName, value, voidContext: voidContext);
+    } else if (identical("~/=", assignmentOperator)) {
+      return accessor.buildCompoundAssignment(
+          mustacheName, value, voidContext: voidContext);
+    } else {
+      return internalError("Unhandled: $assignmentOperator");
+    }
+  }
+
+  Initializer buildFieldInitializer(
+      Map<String, FieldInitializer> initializers) {
+    if (!identical("=", assignmentOperator) ||
+        !accessor.isThisPropertyAccessor) {
+      return accessor.buildFieldInitializer(initializers);
+    }
+    String name = accessor.plainNameForRead;
+    FieldInitializer initializer = initializers[name];
+    if (initializer != null && initializer.value == null) {
+      initializers.remove(name);
+      initializer.value = value
+          ..parent = initializer;
+      return initializer;
+    }
+    return accessor.buildFieldInitializer(initializers);
+  }
+}
+
+class DelayedPostfixIncrement extends ContextAccessor {
+  final Name binaryOperator;
+
+  final Procedure interfaceTarget;
+
+  DelayedPostfixIncrement(BuilderHelper helper, int charOffset,
+      BuilderAccessor accessor, this.binaryOperator, this.interfaceTarget)
+      : super(helper, charOffset, accessor);
+
+  Expression buildSimpleRead() {
+    return accessor.buildPostfixIncrement(binaryOperator, voidContext: false,
+        interfaceTarget: interfaceTarget);
+  }
+
+  Expression buildForEffect() {
+    return accessor.buildPostfixIncrement(binaryOperator, voidContext: true,
+        interfaceTarget: interfaceTarget);
+  }
+}
+
+class JumpTarget extends Builder {
+  final List<Statement> users = <Statement>[];
+
+  final JumpTargetKind kind;
+
+  JumpTarget(this.kind, MemberBuilder member, int charOffset)
+      : super(member, charOffset, member.fileUri);
+
+  bool get isBreakTarget => kind == JumpTargetKind.Break;
+
+  bool get isContinueTarget => kind == JumpTargetKind.Continue;
+
+  bool get isGotoTarget => kind == JumpTargetKind.Goto;
+
+  bool get hasUsers => users.isNotEmpty;
+
+  void addBreak(BreakStatement statement) {
+    assert(isBreakTarget);
+    users.add(statement);
+  }
+
+  void addContinue(BreakStatement statement) {
+    assert(isContinueTarget);
+    users.add(statement);
+  }
+
+  void addGoto(ContinueSwitchStatement statement) {
+    assert(isGotoTarget);
+    users.add(statement);
+  }
+
+  void resolveBreaks(LabeledStatement target) {
+    assert(isBreakTarget);
+    for (BreakStatement user in users) {
+      user.target = target;
+    }
+    users.clear();
+  }
+
+  void resolveContinues(LabeledStatement target) {
+    assert(isContinueTarget);
+    for (BreakStatement user in users) {
+      user.target = target;
+    }
+    users.clear();
+  }
+
+  void resolveGotos(SwitchCase target) {
+    assert(isGotoTarget);
+    for (ContinueSwitchStatement user in users) {
+      user.target = target;
+    }
+    users.clear();
+  }
+}
+
+class LabelTarget extends Builder implements JumpTarget {
+  final JumpTarget breakTarget;
+
+  final JumpTarget continueTarget;
+
+  LabelTarget(MemberBuilder member, int charOffset)
+      : breakTarget = new JumpTarget(JumpTargetKind.Break, member, charOffset),
+        continueTarget =
+            new JumpTarget(JumpTargetKind.Continue, member, charOffset),
+        super(member, charOffset, member.fileUri);
+
+  bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;
+
+  List<Statement> get users => internalError("Unsupported operation.");
+
+  JumpTargetKind get kind => internalError("Unsupported operation.");
+
+  bool get isBreakTarget => true;
+
+  bool get isContinueTarget => true;
+
+  bool get isGotoTarget => false;
+
+  void addBreak(BreakStatement statement) {
+    breakTarget.addBreak(statement);
+  }
+
+  void addContinue(BreakStatement statement) {
+    continueTarget.addContinue(statement);
+  }
+
+  void addGoto(ContinueSwitchStatement statement) {
+    internalError("Unsupported operation.");
+  }
+
+  void resolveBreaks(LabeledStatement target) {
+    breakTarget.resolveBreaks(target);
+  }
+
+  void resolveContinues(LabeledStatement target) {
+    continueTarget.resolveContinues(target);
+  }
+
+  void resolveGotos(SwitchCase target) {
+    internalError("Unsupported operation.");
+  }
+}
+
+class OptionalFormals {
+  final FormalParameterType kind;
+
+  final List<VariableDeclaration> formals;
+
+  OptionalFormals(this.kind, this.formals);
+}
+
+class FormalParameters {
+  final List<VariableDeclaration> required;
+  final OptionalFormals optional;
+
+  FormalParameters(this.required, this.optional);
+
+  FunctionNode addToFunction(FunctionNode function) {
+    function.requiredParameterCount = required.length;
+    function.positionalParameters.addAll(required);
+    if (optional != null) {
+      if (optional.kind.isPositional) {
+        function.positionalParameters.addAll(optional.formals);
+      } else {
+        function.namedParameters.addAll(optional.formals);
+        setParents(function.namedParameters, function);
+      }
+    }
+    setParents(function.positionalParameters, function);
+    return function;
+  }
+
+  FunctionType toFunctionType(DartType returnType) {
+    returnType ??= const DynamicType();
+    int requiredParameterCount = required.length;
+    List<DartType> positionalParameters = <DartType>[];
+    List<NamedType> namedParameters = const <NamedType>[];
+    for (VariableDeclaration parameter in required) {
+      positionalParameters.add(parameter.type);
+    }
+    if (optional != null) {
+      if (optional.kind.isPositional) {
+        for (VariableDeclaration parameter in optional.formals) {
+          positionalParameters.add(parameter.type);
+        }
+      } else {
+        namedParameters = <NamedType>[];
+        for (VariableDeclaration parameter in optional.formals) {
+          namedParameters.add(new NamedType(parameter.name, parameter.type));
+        }
+        namedParameters.sort();
+      }
+    }
+    return new FunctionType(positionalParameters, returnType,
+        namedParameters: namedParameters,
+        requiredParameterCount: requiredParameterCount);
+  }
+
+  Scope computeFormalParameterScope(Scope parent, Builder builder) {
+    if (required.length == 0 && optional == null) return parent;
+    Map<String, Builder> local = <String, Builder>{};
+    for (VariableDeclaration parameter in required) {
+      local[parameter.name] = new KernelVariableBuilder(parameter, builder);
+    }
+    if (optional != null) {
+      for (VariableDeclaration parameter in optional.formals) {
+        local[parameter.name] = new KernelVariableBuilder(parameter, builder);
+      }
+    }
+    return new Scope(local, parent, isModifiable: false);
+  }
+}
+
+/// Returns a block like this:
+///
+///     {
+///       statement;
+///       body;
+///     }
+///
+/// If [body] is a [Block], it's returned with [statement] prepended to it.
+Block combineStatements(Statement statement, Statement body) {
+  if (body is Block) {
+    body.statements.insert(0, statement);
+    statement.parent = body;
+    return body;
+  } else {
+    return new Block(<Statement>[statement, body]);
+  }
+}
+
+String debugName(String className, String name, [String prefix]) {
+  String result = name.isEmpty ? className : "$className.$name";
+  return prefix == null ? result : "$prefix.result";
+}
+
+String getNodeName(Object node) {
+  if (node is Identifier) {
+    return node.name;
+  } else if (node is UnresolvedIdentifier) {
+    return node.name.name;
+  } else if (node is TypeDeclarationBuilder) {
+    return node.name;
+  } else if (node is PrefixBuilder) {
+    return node.name;
+  } else if (node is ThisPropertyAccessor) {
+    return node.name.name;
+  } else {
+    return internalError("Unhandled: ${node.runtimeType}");
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/builder_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/builder_accessors.dart
new file mode 100644
index 0000000..2d646ed
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/builder_accessors.dart
@@ -0,0 +1,732 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.builder_accessors;
+
+export 'frontend_accessors.dart' show
+    wrapInvalid;
+
+import 'frontend_accessors.dart' show
+    Accessor;
+
+import 'package:kernel/ast.dart';
+
+import 'package:kernel/core_types.dart' show
+    CoreTypes;
+
+import '../errors.dart' show
+    internalError;
+
+import 'frontend_accessors.dart' as kernel show
+    IndexAccessor,
+    NullAwarePropertyAccessor,
+    PropertyAccessor,
+    StaticAccessor,
+    SuperPropertyAccessor,
+    ThisIndexAccessor,
+    ThisPropertyAccessor,
+    VariableAccessor;
+
+import 'frontend_accessors.dart' show
+    buildIsNull,
+    makeLet;
+
+import 'kernel_builder.dart' show
+    Builder,
+    KernelClassBuilder,
+    PrefixBuilder,
+    TypeDeclarationBuilder;
+
+abstract class BuilderHelper {
+  Uri get uri;
+
+  CoreTypes get coreTypes;
+
+  Constructor lookupConstructor(Name name, {bool isSuper});
+
+  Expression toSuperMethodInvocation(MethodInvocation node);
+
+  Expression toValue(node);
+
+  Member lookupSuperMember(Name name, {bool isSetter: false});
+
+  builderToFirstExpression(Builder builder, String name, int charOffset);
+
+  finishSend(Object receiver, Arguments arguments, int charOffset);
+
+  Expression buildCompileTimeError(error, [int charOffset]);
+
+  Initializer buildCompileTimeErrorIntializer(error, [int charOffset]);
+
+  Expression buildStaticInvocation(Procedure target, Arguments arguments);
+
+  Expression buildProblemExpression(Builder builder, String name);
+}
+
+abstract class BuilderAccessor implements Accessor {
+  BuilderHelper get helper;
+
+  int get charOffset;
+
+  String get plainNameForRead;
+
+  Uri get uri => helper.uri;
+
+  CoreTypes get coreTypes => helper.coreTypes;
+
+  String get plainNameForWrite => plainNameForRead;
+
+  Expression buildForEffect() => buildSimpleRead();
+
+  Initializer buildFieldInitializer(
+      Map<String, FieldInitializer> initializers) {
+    // TODO(ahe): This error message is really bad.
+    return helper.buildCompileTimeErrorIntializer(
+        "Can't use $plainNameForRead here.", charOffset);
+  }
+
+  Expression makeInvalidRead() {
+    return throwNoSuchMethodError(plainNameForRead, new Arguments.empty(), uri,
+        charOffset, coreTypes, isGetter: true);
+  }
+
+  Expression makeInvalidWrite(Expression value) {
+    return throwNoSuchMethodError(plainNameForWrite,
+        new Arguments(<Expression>[value]), uri, charOffset, coreTypes,
+        isSetter: true);
+  }
+
+  TreeNode doInvocation(int charOffset, Arguments arguments);
+
+  buildPropertyAccess(IncompleteSend send, bool isNullAware) {
+    if (send is SendAccessor) {
+      return buildMethodInvocation(buildSimpleRead(), send.name, send.arguments,
+          charOffset, isNullAware: isNullAware);
+    } else {
+      return PropertyAccessor.make(helper, charOffset, buildSimpleRead(),
+          send.name, null, null, isNullAware);
+    }
+  }
+
+  Expression buildThrowNoSuchMethodError(Arguments arguments) {
+    bool isGetter = false;
+    if (arguments == null) {
+      arguments = new Arguments.empty();
+      isGetter = true;
+    }
+    return throwNoSuchMethodError(plainNameForWrite, arguments, uri, charOffset,
+        coreTypes, isGetter: isGetter);
+  }
+
+  bool get isThisPropertyAccessor => false;
+}
+
+abstract class CompileTimeErrorAccessor implements Accessor {
+  Expression buildError();
+
+  Name get name => internalError("Unsupported operation.");
+
+  String get plainNameForRead => name.name;
+
+  withReceiver(Object receiver, {bool isNullAware}) => this;
+
+  Initializer buildFieldInitializer(
+      Map<String, FieldInitializer> initializers) {
+    return new LocalInitializer(new VariableDeclaration.forValue(buildError()));
+  }
+
+  doInvocation(int charOffset, Arguments arguments) => this;
+
+  buildPropertyAccess(IncompleteSend send, bool isNullAware) => this;
+
+  buildThrowNoSuchMethodError(Arguments arguments) => this;
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return buildError();
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return buildError();
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return buildError();
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return buildError();
+  }
+
+  Expression buildNullAwareAssignment(Expression value, DartType type,
+      {bool voidContext: false}) {
+    return buildError();
+  }
+
+  Expression buildSimpleRead() => buildError();
+
+  Expression makeInvalidRead() => buildError();
+
+  Expression makeInvalidWrite(Expression value) => buildError();
+}
+
+class ThisAccessor extends BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  final bool isInitializer;
+
+  final bool isSuper;
+
+  ThisAccessor(this.helper, this.charOffset, this.isInitializer,
+      {this.isSuper: false});
+
+  String get plainNameForRead => internalError(isSuper ? "super" : "this");
+
+  Expression buildSimpleRead() {
+    if (!isSuper) {
+      return new ThisExpression();
+    } else {
+      return helper.buildCompileTimeError(
+          "Can't use `super` as an expression.", charOffset);
+    }
+  }
+
+  Initializer buildFieldInitializer(
+      Map<String, FieldInitializer> initializers) {
+    String keyword = isSuper ? "super" : "this";
+    return helper.buildCompileTimeErrorIntializer(
+        "Can't use '$keyword' here, did you mean '$keyword()'?", charOffset);
+  }
+
+  buildPropertyAccess(IncompleteSend send, bool isNullAware) {
+    if (isInitializer && send is SendAccessor) {
+      return buildConstructorInitializer(
+          send.charOffset, send.name, send.arguments);
+    }
+    if (send is SendAccessor) {
+      // Notice that 'this' or 'super' can't be null. So we can ignore the
+      // value of [isNullAware].
+      MethodInvocation result = buildMethodInvocation(new ThisExpression(),
+          send.name, send.arguments, charOffset);
+      return isSuper ? helper.toSuperMethodInvocation(result) : result;
+    } else {
+      if (isSuper) {
+        Member getter = helper.lookupSuperMember(send.name);
+        Member setter = helper.lookupSuperMember(send.name, isSetter: true);
+        return new SuperPropertyAccessor(helper, charOffset, send.name, getter,
+            setter);
+      } else {
+        return new ThisPropertyAccessor(helper, charOffset, send.name, null,
+            null);
+      }
+    }
+  }
+
+  doInvocation(int charOffset, Arguments arguments) {
+    if (isInitializer) {
+      return buildConstructorInitializer(charOffset, new Name(""), arguments);
+    } else {
+      return buildMethodInvocation(new ThisExpression(), new Name("call"),
+          arguments, charOffset);
+    }
+  }
+
+  Initializer buildConstructorInitializer(int charOffset, Name name,
+      Arguments arguments) {
+    Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper);
+    Initializer result;
+    if (constructor == null) {
+      result = new LocalInitializer(
+          new VariableDeclaration.forValue(
+              throwNoSuchMethodError(
+                  name.name, arguments, uri, charOffset, coreTypes,
+                  isSuper: isSuper)));
+    } else if (isSuper) {
+      result = new SuperInitializer(constructor, arguments);
+    } else {
+      result = new RedirectingInitializer(constructor, arguments);
+    }
+    return result
+        ..fileOffset = charOffset;
+  }
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return internalError("");
+  }
+
+  Expression buildNullAwareAssignment(Expression value, DartType type,
+      {bool voidContext: false}) {
+    return internalError("");
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("");
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("");
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("");
+  }
+
+  toString() => "ThisAccessor($charOffset${isSuper ? ', super' : ''})";
+}
+
+abstract class IncompleteSend extends BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  final Name name;
+
+  IncompleteSend(this.helper, this.charOffset, this.name);
+
+  withReceiver(Object receiver, {bool isNullAware});
+}
+
+class IncompleteError extends IncompleteSend with CompileTimeErrorAccessor {
+  final Object error;
+
+  IncompleteError(BuilderHelper helper, int charOffset, this.error)
+      : super(helper, charOffset, null);
+
+  Expression buildError() {
+    return helper.buildCompileTimeError(error, charOffset);
+  }
+}
+
+class SendAccessor extends IncompleteSend {
+  final Arguments arguments;
+
+  SendAccessor(BuilderHelper helper, int charOffset, Name name, this.arguments)
+      : super(helper, charOffset, name) {
+    assert(arguments != null);
+  }
+
+  String get plainNameForRead => name.name;
+
+  Expression buildSimpleRead() {
+    return internalError("Unhandled");
+  }
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return internalError("Unhandled");
+  }
+
+  withReceiver(Object receiver, {bool isNullAware: false}) {
+    if (receiver is TypeDeclarationBuilder) {
+      /// `SomeType?.toString` is the same as `SomeType.toString`, not
+      /// `(SomeType).toString`.
+      isNullAware = false;
+    }
+    if (receiver is BuilderAccessor) {
+      return receiver.buildPropertyAccess(this, isNullAware);
+    }
+    if (receiver is PrefixBuilder) {
+      PrefixBuilder prefix = receiver;
+      receiver = helper.builderToFirstExpression(
+          prefix.exports[name.name], "${prefix.name}.${name.name}", charOffset);
+      return helper.finishSend(receiver, arguments, charOffset);
+    }
+    Expression result;
+    if (receiver is KernelClassBuilder) {
+      Builder builder = receiver.findStaticBuilder(name.name, charOffset, uri);
+      if (builder == null) {
+        return buildThrowNoSuchMethodError(arguments);
+      }
+      if (builder.hasProblem) {
+        result = helper.buildProblemExpression(builder, name.name);
+      } else {
+        Member target = builder.target;
+        if (target != null) {
+          if (target is Field) {
+            result = buildMethodInvocation(new StaticGet(target),
+                new Name("call"), arguments, charOffset,
+                isNullAware: isNullAware);
+          } else {
+            result = helper.buildStaticInvocation(target, arguments);
+          }
+        } else {
+          result = buildThrowNoSuchMethodError(arguments);
+        }
+      }
+    } else {
+      result = buildMethodInvocation(helper.toValue(receiver), name,
+          arguments, charOffset, isNullAware: isNullAware);
+    }
+    return result..fileOffset = charOffset;
+  }
+
+  Expression buildNullAwareAssignment(Expression value, DartType type,
+      {bool voidContext: false}) {
+    return internalError("");
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("");
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("Unhandled");
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("Unhandled");
+  }
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return internalError("Unhandled");
+  }
+
+  toString() => "SendAccessor($charOffset, $name, $arguments)";
+}
+
+class IncompletePropertyAccessor extends IncompleteSend {
+  IncompletePropertyAccessor(BuilderHelper helper, int charOffset, Name name)
+      : super(helper, charOffset, name);
+
+  String get plainNameForRead => name.name;
+
+  Expression buildSimpleRead() => internalError("Unhandled");
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return internalError("Unhandled");
+  }
+
+  withReceiver(Object receiver, {bool isNullAware: false}) {
+    if (receiver is TypeDeclarationBuilder) {
+      /// For reasons beyond comprehension, `SomeType?.toString` is the same as
+      /// `SomeType.toString`, not `(SomeType).toString`. WTAF!?!
+      //
+      isNullAware = false;
+    }
+    if (receiver is BuilderAccessor) {
+      return receiver.buildPropertyAccess(this, isNullAware);
+    }
+    if (receiver is PrefixBuilder) {
+      PrefixBuilder prefix = receiver;
+      return helper.builderToFirstExpression(
+          prefix.exports[name.name], name.name, charOffset);
+    }
+    if (receiver is KernelClassBuilder) {
+      Builder builder = receiver.findStaticBuilder(name.name, charOffset, uri);
+      Member getter = builder?.target;
+      Member setter;
+      if (builder == null) {
+        builder = receiver.findStaticBuilder(
+            name.name, charOffset, uri, isSetter: true);
+        if (builder == null) {
+          return buildThrowNoSuchMethodError(null);
+        }
+      }
+      if (builder.hasProblem) {
+        return helper.buildProblemExpression(builder, name.name)
+            ..fileOffset = charOffset;
+      }
+      if (getter is Field) {
+        if (!getter.isFinal && !getter.isConst) {
+          setter = getter;
+        }
+      } else if (getter is Procedure) {
+        if (getter.isGetter) {
+          builder = receiver.findStaticBuilder(
+              name.name, charOffset, uri, isSetter: true);
+          if (builder != null && !builder.hasProblem) {
+            setter = builder.target;
+          }
+        }
+      }
+      if (getter == null) {
+        return internalError("no getter for $name");
+      }
+      return new StaticAccessor(helper, charOffset, getter, setter);
+    }
+    return PropertyAccessor.make(helper, charOffset, helper.toValue(receiver),
+        name, null, null, isNullAware);
+  }
+
+  Expression buildNullAwareAssignment(Expression value, DartType type,
+      {bool voidContext: false}) {
+    return internalError("Unhandled");
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("Unhandled");
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("Unhandled");
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return internalError("Unhandled");
+  }
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return internalError("Unhandled");
+  }
+
+  toString() => "IncompletePropertyAccessor($charOffset, $name)";
+}
+
+class IndexAccessor extends kernel.IndexAccessor with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  IndexAccessor.internal(this.helper, this.charOffset, Expression receiver,
+      Expression index, Procedure getter, Procedure setter)
+      : super.internal(receiver, index, getter, setter);
+
+  String get plainNameForRead => "[]";
+
+  String get plainNameForWrite => "[]=";
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments,
+        charOffset);
+  }
+
+  toString() => "IndexAccessor()";
+
+  static BuilderAccessor make(BuilderHelper helper, int charOffset,
+      Expression receiver, Expression index, Procedure getter,
+      Procedure setter) {
+    if (receiver is ThisExpression) {
+      return new ThisIndexAccessor(helper, charOffset, index, getter, setter);
+    } else {
+      return new IndexAccessor.internal(helper, charOffset, receiver, index,
+          getter, setter);
+    }
+  }
+}
+
+class PropertyAccessor extends kernel.PropertyAccessor with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  PropertyAccessor.internal(this.helper, this.charOffset, Expression receiver,
+      Name name, Member getter, Member setter)
+      : super.internal(receiver, name, getter, setter);
+
+  String get plainNameForRead => name.name;
+
+  bool get isThisPropertyAccessor => receiver is ThisExpression;
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return buildMethodInvocation(receiver, name, arguments, charOffset);
+  }
+
+  toString() => "PropertyAccessor()";
+
+  static BuilderAccessor make(BuilderHelper helper, int charOffset,
+      Expression receiver, Name name, Member getter, Member setter,
+      bool isNullAware) {
+    if (receiver is ThisExpression) {
+      return new ThisPropertyAccessor(helper, charOffset, name, getter, setter);
+    } else {
+      return isNullAware
+          ? new NullAwarePropertyAccessor(helper, charOffset, receiver, name,
+              getter, setter, null)
+          : new PropertyAccessor.internal(helper, charOffset, receiver, name,
+              getter, setter);
+    }
+  }
+}
+
+class StaticAccessor extends kernel.StaticAccessor with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  StaticAccessor(this.helper, this.charOffset, Member readTarget,
+      Member writeTarget)
+      : super(readTarget, writeTarget) {
+    assert(readTarget != null || writeTarget != null);
+  }
+
+  String get plainNameForRead => (readTarget ?? writeTarget).name.name;
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    if (readTarget == null || isFieldOrGetter(readTarget)) {
+      return buildMethodInvocation(buildSimpleRead(), new Name("call"),
+          arguments, charOffset);
+    } else {
+      return helper.buildStaticInvocation(readTarget, arguments)
+          ..fileOffset = charOffset;
+    }
+  }
+
+  toString() => "StaticAccessor()";
+}
+
+class SuperPropertyAccessor extends kernel.SuperPropertyAccessor
+    with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  SuperPropertyAccessor(this.helper, this.charOffset, Name name, Member getter,
+      Member setter)
+      : super(name, getter, setter);
+
+  String get plainNameForRead => name.name;
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    if (getter == null || isFieldOrGetter(getter)) {
+      return buildMethodInvocation(buildSimpleRead(), new Name("call"),
+          arguments, charOffset);
+    } else {
+      return new DirectMethodInvocation(new ThisExpression(), getter, arguments)
+          ..fileOffset = charOffset;
+    }
+  }
+
+  toString() => "SuperPropertyAccessor()";
+}
+
+class ThisIndexAccessor extends kernel.ThisIndexAccessor with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  ThisIndexAccessor(this.helper, this.charOffset, Expression index,
+      Procedure getter, Procedure setter)
+      : super(index, getter, setter);
+
+  String get plainNameForRead => "[]";
+
+  String get plainNameForWrite => "[]=";
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments,
+        charOffset);
+  }
+
+  toString() => "ThisIndexAccessor()";
+}
+
+class ThisPropertyAccessor extends kernel.ThisPropertyAccessor
+    with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  ThisPropertyAccessor(this.helper, this.charOffset, Name name, Member getter,
+      Member setter)
+      : super(name, getter, setter);
+
+  String get plainNameForRead => name.name;
+
+  bool get isThisPropertyAccessor => true;
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    Member interfaceTarget = getter;
+    if (interfaceTarget is Field) {
+      // TODO(ahe): In strong mode we should probably rewrite this to
+      // `this.name.call(arguments)`.
+      interfaceTarget = null;
+    }
+    return buildMethodInvocation(new ThisExpression(), name, arguments,
+        charOffset);
+  }
+
+  toString() => "ThisPropertyAccessor()";
+}
+
+class NullAwarePropertyAccessor extends kernel.NullAwarePropertyAccessor
+    with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  NullAwarePropertyAccessor(this.helper, this.charOffset, Expression receiver,
+      Name name, Member getter, Member setter, DartType type)
+      : super(receiver, name, getter, setter, type);
+
+  String get plainNameForRead => name.name;
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return internalError("Not implemented yet.");
+  }
+
+  toString() => "NullAwarePropertyAccessor()";
+}
+
+
+class VariableAccessor extends kernel.VariableAccessor
+    with BuilderAccessor {
+  final BuilderHelper helper;
+
+  final int charOffset;
+
+  VariableAccessor(this.helper, this.charOffset, VariableDeclaration variable,
+      [DartType promotedType])
+      : super.internal(variable, promotedType);
+
+  String get plainNameForRead => variable.name;
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments,
+        charOffset);
+  }
+
+  toString() => "VariableAccessor()";
+}
+
+Expression throwNoSuchMethodError(String name, Arguments arguments, Uri uri,
+    int charOffset, CoreTypes coreTypes,
+    {bool isSuper: false, isGetter: false, isSetter: false}) {
+  print("$uri:$charOffset: method not found: '$name'.");
+  Constructor constructor = coreTypes.getCoreClass(
+      "dart:core", "NoSuchMethodError").constructors.first;
+  return new Throw(new ConstructorInvocation(
+      constructor,
+      new Arguments(<Expression>[
+          new NullLiteral(),
+          new SymbolLiteral(name),
+          new ListLiteral(arguments.positional),
+          new MapLiteral(arguments.named.map((arg) {
+              return new MapEntry(new SymbolLiteral(arg.name), arg.value);
+          }).toList()),
+          new NullLiteral()])));
+}
+
+bool isFieldOrGetter(Member member) {
+  return member is Field || (member is Procedure && member.isGetter);
+}
+
+Expression buildMethodInvocation(Expression receiver, Name name,
+    Arguments arguments, int charOffset, {bool isNullAware: false}) {
+  if (isNullAware) {
+    VariableDeclaration variable = new VariableDeclaration.forValue(receiver);
+    return makeLet(
+        variable,
+        new ConditionalExpression(
+            buildIsNull(new VariableGet(variable)),
+            new NullLiteral(),
+            new MethodInvocation(new VariableGet(variable), name, arguments)
+                ..fileOffset = charOffset,
+            const DynamicType()));
+  } else {
+    return new MethodInvocation(receiver, name, arguments)
+        ..fileOffset = charOffset;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart
new file mode 100644
index 0000000..a9e7100
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart
@@ -0,0 +1,463 @@
+// 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.
+
+// Note: copied from package:kernel at revision 7346348.
+
+/// A library to help transform compounds and null-aware accessors into
+/// let expressions.
+library kernel.frontend.accessors;
+
+import 'package:kernel/ast.dart';
+
+/// An [Accessor] represents a subexpression for which we can't yet build a
+/// kernel [Expression] because we don't yet know the context in which it is
+/// used.
+///
+/// Once the context is known, an [Accessor] can be converted into an
+/// [Expression] by calling a "build" method.
+///
+/// For example, when building a kernel representation for `a[x] = b`, after
+/// parsing `a[x]` but before parsing `= b`, we don't yet know whether to
+/// generate an invocation of `operator[]` or `operator[]=`, so we generate an
+/// [Accessor] object.  Later, after `= b` is parsed, [buildAssignment] will be
+/// called.
+abstract class Accessor {
+  /// Builds an [Expression] representing a read from the accessor.
+  Expression buildSimpleRead() {
+    return _finish(_makeSimpleRead());
+  }
+
+  /// Builds an [Expression] representing an assignment with the accessor on
+  /// the LHS and [value] on the RHS.
+  ///
+  /// The returned expression evaluates to the assigned value, unless
+  /// [voidContext] is true, in which case it may evaluate to anything.
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return _finish(_makeSimpleWrite(value, voidContext));
+  }
+
+  /// Returns an [Expression] representing a null-aware assignment (`??=`) with
+  /// the accessor on the LHS and [value] on the RHS.
+  ///
+  /// The returned expression evaluates to the assigned value, unless
+  /// [voidContext] is true, in which case it may evaluate to anything.
+  ///
+  /// [type] is the static type of the RHS.
+  Expression buildNullAwareAssignment(Expression value, DartType type,
+      {bool voidContext: false}) {
+    if (voidContext) {
+      return _finish(new ConditionalExpression(buildIsNull(_makeRead()),
+          _makeWrite(value, false), new NullLiteral(), type));
+    }
+    var tmp = new VariableDeclaration.forValue(_makeRead());
+    return _finish(makeLet(
+        tmp,
+        new ConditionalExpression(buildIsNull(new VariableGet(tmp)),
+            _makeWrite(value, false), new VariableGet(tmp), type)));
+  }
+
+  /// Returns an [Expression] representing a compound assignment (e.g. `+=`)
+  /// with the accessor on the LHS and [value] on the RHS.
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return _finish(_makeWrite(
+        makeBinary(_makeRead(), binaryOperator, interfaceTarget, value),
+        voidContext));
+  }
+
+  /// Returns an [Expression] representing a pre-increment or pre-decrement
+  /// of the accessor.
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    return buildCompoundAssignment(binaryOperator, new IntLiteral(1),
+        voidContext: voidContext, interfaceTarget: interfaceTarget);
+  }
+
+  /// Returns an [Expression] representing a post-increment or post-decrement
+  /// of the accessor.
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {bool voidContext: false, Procedure interfaceTarget}) {
+    if (voidContext) {
+      return buildPrefixIncrement(binaryOperator,
+          voidContext: true, interfaceTarget: interfaceTarget);
+    }
+    var value = new VariableDeclaration.forValue(_makeRead());
+    valueAccess() => new VariableGet(value);
+    var dummy = new VariableDeclaration.forValue(_makeWrite(
+        makeBinary(
+            valueAccess(), binaryOperator, interfaceTarget, new IntLiteral(1)),
+        true));
+    return _finish(makeLet(value, makeLet(dummy, valueAccess())));
+  }
+
+  Expression _makeSimpleRead() => _makeRead();
+
+  Expression _makeSimpleWrite(Expression value, bool voidContext) {
+    return _makeWrite(value, voidContext);
+  }
+
+  Expression _makeRead();
+
+  Expression _makeWrite(Expression value, bool voidContext);
+
+  Expression _finish(Expression body) => body;
+
+  /// Returns an [Expression] representing a compile-time error.
+  ///
+  /// At runtime, an exception will be thrown.
+  makeInvalidRead() => new InvalidExpression();
+
+  /// Returns an [Expression] representing a compile-time error wrapping
+  /// [value].
+  ///
+  /// At runtime, [value] will be evaluated before throwing an exception.
+  makeInvalidWrite(Expression value) => wrapInvalid(value);
+}
+
+class VariableAccessor extends Accessor {
+  VariableDeclaration variable;
+  DartType promotedType;
+
+  VariableAccessor(this.variable, [this.promotedType]);
+
+  VariableAccessor.internal(this.variable, this.promotedType);
+
+  _makeRead() => new VariableGet(variable, promotedType);
+
+  _makeWrite(Expression value, bool voidContext) {
+    return variable.isFinal || variable.isConst
+        ? makeInvalidWrite(value)
+        : new VariableSet(variable, value);
+  }
+}
+
+class PropertyAccessor extends Accessor {
+  VariableDeclaration _receiverVariable;
+  Expression receiver;
+  Name name;
+  Member getter, setter;
+
+  static Accessor make(
+      Expression receiver, Name name, Member getter, Member setter) {
+    if (receiver is ThisExpression) {
+      return new ThisPropertyAccessor(name, getter, setter);
+    } else {
+      return new PropertyAccessor.internal(receiver, name, getter, setter);
+    }
+  }
+
+  PropertyAccessor.internal(
+      this.receiver, this.name, this.getter, this.setter);
+
+  _makeSimpleRead() => new PropertyGet(receiver, name, getter);
+  _makeSimpleWrite(Expression value, bool voidContext) {
+    return new PropertySet(receiver, name, value, setter);
+  }
+
+  receiverAccess() {
+    _receiverVariable ??= new VariableDeclaration.forValue(receiver);
+    return new VariableGet(_receiverVariable);
+  }
+
+  _makeRead() => new PropertyGet(receiverAccess(), name, getter);
+
+  _makeWrite(Expression value, bool voidContext) {
+    return new PropertySet(receiverAccess(), name, value, setter);
+  }
+
+  _finish(Expression body) => makeLet(_receiverVariable, body);
+}
+
+/// Special case of [PropertyAccessor] to avoid creating an indirect access to
+/// 'this'.
+class ThisPropertyAccessor extends Accessor {
+  Name name;
+  Member getter, setter;
+
+  ThisPropertyAccessor(this.name, this.getter, this.setter);
+
+  _makeRead() => new PropertyGet(new ThisExpression(), name, getter);
+
+  _makeWrite(Expression value, bool voidContext) {
+    return new PropertySet(new ThisExpression(), name, value, setter);
+  }
+}
+
+class NullAwarePropertyAccessor extends Accessor {
+  VariableDeclaration receiver;
+  Name name;
+  Member getter, setter;
+  DartType type;
+
+  NullAwarePropertyAccessor(
+      Expression receiver, this.name, this.getter, this.setter, this.type)
+      : this.receiver = makeOrReuseVariable(receiver);
+
+  receiverAccess() => new VariableGet(receiver);
+
+  _makeRead() => new PropertyGet(receiverAccess(), name, getter);
+
+  _makeWrite(Expression value, bool voidContext) {
+    return new PropertySet(receiverAccess(), name, value, setter);
+  }
+
+  _finish(Expression body) => makeLet(
+      receiver,
+      new ConditionalExpression(
+          buildIsNull(receiverAccess()), new NullLiteral(), body, type));
+}
+
+class SuperPropertyAccessor extends Accessor {
+  Name name;
+  Member getter, setter;
+
+  SuperPropertyAccessor(this.name, this.getter, this.setter);
+
+  _makeRead() {
+    if (getter == null) return makeInvalidRead();
+    // TODO(ahe): Use [DirectPropertyGet] when possible.
+    Expression result = new DirectPropertyGet(new ThisExpression(), getter);
+    result = new SuperPropertyGet(name, getter);
+    return result;
+  }
+
+  _makeWrite(Expression value, bool voidContext) {
+    if (setter == null) return makeInvalidWrite(value);
+    // TODO(ahe): Use [DirectPropertySet] when possible.
+    Expression result =
+        new DirectPropertySet(new ThisExpression(), setter, value);
+    result = new SuperPropertySet(name, value, setter);
+    return result;
+  }
+}
+
+final Name _indexGet = new Name('[]');
+final Name _indexSet = new Name('[]=');
+
+class IndexAccessor extends Accessor {
+  Expression receiver;
+  Expression index;
+  VariableDeclaration receiverVariable;
+  VariableDeclaration indexVariable;
+  Procedure getter, setter;
+
+  static Accessor make(Expression receiver, Expression index, Procedure getter,
+      Procedure setter) {
+    if (receiver is ThisExpression) {
+      return new ThisIndexAccessor(index, getter, setter);
+    } else {
+      return new IndexAccessor.internal(receiver, index, getter, setter);
+    }
+  }
+
+  IndexAccessor.internal(this.receiver, this.index, this.getter, this.setter);
+
+  _makeSimpleRead() => new MethodInvocation(
+      receiver, _indexGet, new Arguments(<Expression>[index]), getter);
+
+  _makeSimpleWrite(Expression value, bool voidContext) {
+    if (!voidContext) return _makeWriteAndReturn(value);
+    return new MethodInvocation(
+        receiver, _indexSet, new Arguments(<Expression>[index, value]), setter);
+  }
+
+  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);
+  }
+
+  indexAccess() {
+    indexVariable ??= new VariableDeclaration.forValue(index);
+    return new VariableGet(indexVariable);
+  }
+
+  _makeRead() {
+    return new MethodInvocation(receiverAccess(), _indexGet,
+        new Arguments(<Expression>[indexAccess()]), getter);
+  }
+
+  _makeWrite(Expression value, bool voidContext) {
+    if (!voidContext) return _makeWriteAndReturn(value);
+    return new MethodInvocation(receiverAccess(), _indexSet,
+        new Arguments(<Expression>[indexAccess(), value]), setter);
+  }
+
+  _makeWriteAndReturn(Expression value) {
+    // The call to []= does not return the value like direct-style assignments
+    // do.  We need to bind the value in a let.
+    var valueVariable = new VariableDeclaration.forValue(value);
+    var dummy = new VariableDeclaration.forValue(new MethodInvocation(
+        receiverAccess(),
+        _indexSet,
+        new Arguments(
+            <Expression>[indexAccess(), new VariableGet(valueVariable)]),
+        setter));
+    return makeLet(
+        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+  }
+
+  Expression _finish(Expression body) {
+    return makeLet(receiverVariable, makeLet(indexVariable, body));
+  }
+}
+
+/// Special case of [IndexAccessor] to avoid creating an indirect access to
+/// 'this'.
+class ThisIndexAccessor extends Accessor {
+  Expression index;
+  VariableDeclaration indexVariable;
+  Procedure getter, setter;
+
+  ThisIndexAccessor(this.index, this.getter, this.setter);
+
+  _makeSimpleRead() {
+    return new MethodInvocation(new ThisExpression(), _indexGet,
+        new Arguments(<Expression>[index]), getter);
+  }
+
+  _makeSimpleWrite(Expression value, bool voidContext) {
+    if (!voidContext) return _makeWriteAndReturn(value);
+    return new MethodInvocation(new ThisExpression(), _indexSet,
+        new Arguments(<Expression>[index, value]), setter);
+  }
+
+  indexAccess() {
+    indexVariable ??= new VariableDeclaration.forValue(index);
+    return new VariableGet(indexVariable);
+  }
+
+  _makeRead() => new MethodInvocation(new ThisExpression(), _indexGet,
+      new Arguments(<Expression>[indexAccess()]), getter);
+
+  _makeWrite(Expression value, bool voidContext) {
+    if (!voidContext) return _makeWriteAndReturn(value);
+    return new MethodInvocation(new ThisExpression(), _indexSet,
+        new Arguments(<Expression>[indexAccess(), value]), setter);
+  }
+
+  _makeWriteAndReturn(Expression value) {
+    var valueVariable = new VariableDeclaration.forValue(value);
+    var dummy = new VariableDeclaration.forValue(new MethodInvocation(
+        new ThisExpression(),
+        _indexSet,
+        new Arguments(
+            <Expression>[indexAccess(), new VariableGet(valueVariable)]),
+        setter));
+    return makeLet(
+        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+  }
+
+  Expression _finish(Expression body) => makeLet(indexVariable, body);
+}
+
+class SuperIndexAccessor extends Accessor {
+  Expression index;
+  VariableDeclaration indexVariable;
+  Member getter, setter;
+
+  SuperIndexAccessor(this.index, this.getter, this.setter);
+
+  indexAccess() {
+    indexVariable ??= new VariableDeclaration.forValue(index);
+    return new VariableGet(indexVariable);
+  }
+
+  _makeSimpleRead() => new SuperMethodInvocation(
+      _indexGet, new Arguments(<Expression>[index]), getter);
+
+  _makeSimpleWrite(Expression value, bool voidContext) {
+    if (!voidContext) return _makeWriteAndReturn(value);
+    return new SuperMethodInvocation(
+        _indexSet, new Arguments(<Expression>[index, value]), setter);
+  }
+
+  _makeRead() {
+    return new SuperMethodInvocation(
+        _indexGet, new Arguments(<Expression>[indexAccess()]), getter);
+  }
+
+  _makeWrite(Expression value, bool voidContext) {
+    if (!voidContext) return _makeWriteAndReturn(value);
+    return new SuperMethodInvocation(
+        _indexSet, new Arguments(<Expression>[indexAccess(), value]), setter);
+  }
+
+  _makeWriteAndReturn(Expression value) {
+    var valueVariable = new VariableDeclaration.forValue(value);
+    var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation(
+        _indexSet,
+        new Arguments(
+            <Expression>[indexAccess(), new VariableGet(valueVariable)]),
+        setter));
+    return makeLet(
+        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+  }
+
+  Expression _finish(Expression body) {
+    return makeLet(indexVariable, body);
+  }
+}
+
+class StaticAccessor extends Accessor {
+  Member readTarget;
+  Member writeTarget;
+
+  StaticAccessor(this.readTarget, this.writeTarget);
+
+  _makeRead() =>
+      readTarget == null ? makeInvalidRead() : new StaticGet(readTarget);
+
+  _makeWrite(Expression value, bool voidContext) {
+    return writeTarget == null
+        ? makeInvalidWrite(value)
+        : new StaticSet(writeTarget, value);
+  }
+}
+
+class ReadOnlyAccessor extends Accessor {
+  Expression expression;
+  VariableDeclaration value;
+
+  ReadOnlyAccessor(this.expression);
+
+  _makeSimpleRead() => expression;
+
+  _makeRead() {
+    value ??= new VariableDeclaration.forValue(expression);
+    return new VariableGet(value);
+  }
+
+  _makeWrite(Expression value, bool voidContext) => makeInvalidWrite(value);
+
+  Expression _finish(Expression body) => makeLet(value, body);
+}
+
+Expression makeLet(VariableDeclaration variable, Expression body) {
+  if (variable == null) return body;
+  return new Let(variable, body);
+}
+
+Expression makeBinary(Expression left, Name operator, Procedure interfaceTarget,
+    Expression right) {
+  return new MethodInvocation(
+      left, operator, new Arguments(<Expression>[right]), interfaceTarget);
+}
+
+final Name _equalOperator = new Name('==');
+
+Expression buildIsNull(Expression value) {
+  return makeBinary(value, _equalOperator, null, new NullLiteral());
+}
+
+VariableDeclaration makeOrReuseVariable(Expression value) {
+  // TODO: Devise a way to remember if a variable declaration was reused
+  // or is fresh (hence needs a let binding).
+  return new VariableDeclaration.forValue(value);
+}
+
+Expression wrapInvalid(Expression e) {
+  return new Let(new VariableDeclaration.forValue(e), new InvalidExpression());
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
new file mode 100644
index 0000000..6eb41a4
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_builder;
+
+export 'kernel_class_builder.dart' show
+    KernelClassBuilder;
+
+export 'kernel_enum_builder.dart' show
+    KernelEnumBuilder;
+
+export 'kernel_field_builder.dart' show
+    KernelFieldBuilder;
+
+export 'kernel_formal_parameter_builder.dart' show
+    KernelFormalParameterBuilder;
+
+export 'kernel_function_type_alias_builder.dart' show
+    KernelFunctionTypeAliasBuilder;
+
+export 'kernel_named_type_builder.dart' show
+    KernelNamedTypeBuilder;
+
+export 'kernel_library_builder.dart' show
+    KernelLibraryBuilder;
+
+export 'kernel_mixin_application_builder.dart' show
+    KernelMixinApplicationBuilder;
+
+export 'kernel_named_mixin_application_builder.dart' show
+    KernelNamedMixinApplicationBuilder;
+
+export 'kernel_procedure_builder.dart' show
+    KernelConstructorBuilder,
+    KernelFunctionBuilder,
+    KernelProcedureBuilder;
+
+export 'kernel_type_builder.dart' show
+    KernelTypeBuilder;
+
+export 'kernel_type_variable_builder.dart' show
+    KernelTypeVariableBuilder;
+
+export '../builder/builder.dart';
+
+export 'kernel_variable_builder.dart' show
+    KernelVariableBuilder;
+
+export 'kernel_invalid_type_builder.dart' show
+    KernelInvalidTypeBuilder;
+
+import 'package:kernel/text/ast_to_text.dart' show
+    Printer;
+
+import 'package:kernel/ast.dart' show
+    Class,
+    DartType,
+    DynamicType,
+    Field,
+    Library,
+    Member,
+    Procedure,
+    TypeParameter;
+
+import '../errors.dart' show
+    inputError;
+
+List<DartType> computeDefaultTypeArguments(
+    List<TypeParameter> typeParameters, List<DartType> arguments) {
+  if (arguments == null) {
+    return new List<DartType>.filled(
+        typeParameters.length, const DynamicType());
+  }
+  if (arguments.length < typeParameters.length) {
+    arguments = new List<DartType>.from(arguments);
+    for (int i = arguments.length; i < typeParameters.length; i++) {
+      arguments.add(const DynamicType());
+    }
+  } else if (arguments.length > typeParameters.length) {
+    return arguments.sublist(0, typeParameters.length);
+  }
+  return arguments;
+}
+
+dynamic memberError(Member member, Object error, [int charOffset]) {
+  String name = member.name?.name;
+  if (name == "") {
+    name = Printer.emptyNameString;
+  } else if (name == null) {
+    name = "<anon>";
+  }
+  Library library = member.enclosingLibrary;
+  Class cls = member.enclosingClass;
+  String fileUri;
+  if (member is Procedure) {
+    fileUri = member.fileUri;
+  } else if (member is Field) {
+    fileUri = member.fileUri;
+  }
+  fileUri ??= cls?.fileUri ?? library.fileUri;
+  Uri uri = fileUri == null ? library.importUri : Uri.base.resolve(fileUri);
+  charOffset ??= -1;
+  if (charOffset == -1) {
+    charOffset = member.fileOffset ?? -1;
+  }
+  if (charOffset == -1) {
+    charOffset = cls?.fileOffset ?? -1;
+  }
+  name = (cls == null ? "" : "${cls.name}::") + name;
+  return inputError(uri, charOffset, "Error in $name: $error");
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
new file mode 100644
index 0000000..48dccee
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_class_builder;
+
+import 'package:kernel/ast.dart' show
+    Class,
+    DartType,
+    ExpressionStatement,
+    InterfaceType,
+    Member,
+    StringLiteral,
+    Supertype,
+    Throw;
+
+import '../errors.dart' show
+    internalError;
+
+import 'kernel_builder.dart' show
+    Builder,
+    ClassBuilder,
+    ConstructorReferenceBuilder,
+    KernelProcedureBuilder,
+    KernelTypeBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    ProcedureBuilder,
+    TypeVariableBuilder,
+    computeDefaultTypeArguments;
+
+import 'redirecting_factory_body.dart' show
+    RedirectingFactoryBody;
+
+abstract class KernelClassBuilder
+    extends ClassBuilder<KernelTypeBuilder, InterfaceType> {
+  KernelClassBuilder(
+      List<MetadataBuilder> metadata, int modifiers,
+      String name, List<TypeVariableBuilder> typeVariables,
+      KernelTypeBuilder supertype, List<KernelTypeBuilder> interfaces,
+      Map<String, Builder> members, LibraryBuilder parent, int charOffset)
+      : super(metadata, modifiers, name, typeVariables, supertype, interfaces,
+          members, parent, charOffset);
+
+  Class get cls;
+
+  Class get target => cls;
+
+  /// [arguments] have already been built.
+  InterfaceType buildTypesWithBuiltArguments(List<DartType> arguments) {
+    return arguments == null
+        ? cls.rawType
+        : new InterfaceType(cls,
+            // TODO(ahe): Not sure what to do if `arguments.length !=
+            // cls.typeParameters.length`.
+            computeDefaultTypeArguments(cls.typeParameters, arguments));
+  }
+
+  InterfaceType buildType(List<KernelTypeBuilder> arguments) {
+    List<DartType> typeArguments;
+    if (arguments != null) {
+      typeArguments = <DartType>[];
+      for (KernelTypeBuilder builder in arguments) {
+        DartType type = builder.build();
+        if (type == null) {
+          internalError("Bad type: ${builder.runtimeType}");
+        }
+        typeArguments.add(type);
+      }
+    }
+    return buildTypesWithBuiltArguments(typeArguments);
+  }
+
+  Supertype buildSupertype(List<KernelTypeBuilder> arguments) {
+    List<DartType> typeArguments;
+    if (arguments != null) {
+      typeArguments = <DartType>[];
+      for (KernelTypeBuilder builder in arguments) {
+        DartType type = builder.build();
+        if (type == null) {
+          internalError("Bad type: ${builder.runtimeType}");
+        }
+        typeArguments.add(type);
+      }
+      return new Supertype(cls, typeArguments);
+    } else {
+      return cls.asRawSupertype;
+    }
+  }
+
+  int resolveConstructors(LibraryBuilder library) {
+    int count = super.resolveConstructors(library);
+    if (count != 0) {
+      members.forEach((String name, Builder builder) {
+        if (builder is KernelProcedureBuilder && builder.isFactory) {
+          // Compute the immediate redirection target, not the effective.
+          ConstructorReferenceBuilder redirectionTarget =
+              builder.redirectionTarget;
+          if (redirectionTarget != null) {
+            assert(builder.actualBody == null);
+            Builder targetBuilder = redirectionTarget.target;
+            if (targetBuilder is ProcedureBuilder) {
+              Member target = targetBuilder.target;
+              builder.body = new RedirectingFactoryBody(target);
+            } else {
+              // TODO(ahe): Throw NSM error. This requires access to core
+              // types.
+              String message =
+                  "Missing constructor: ${redirectionTarget.fullNameForErrors}";
+              print(message);
+              builder.body = new ExpressionStatement(
+                  new Throw(new StringLiteral(message)));
+            }
+          }
+        }
+      });
+    }
+    return count;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
new file mode 100644
index 0000000..af46a61
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
@@ -0,0 +1,188 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_enum_builder;
+
+import 'package:kernel/ast.dart' show
+    Arguments,
+    AsyncMarker,
+    Class,
+    Constructor,
+    ConstructorInvocation,
+    DirectPropertyGet,
+    Expression,
+    Field,
+    FieldInitializer,
+    IntLiteral,
+    InterfaceType,
+    ListLiteral,
+    MapEntry,
+    MapLiteral,
+    MethodInvocation,
+    Name,
+    ProcedureKind,
+    ReturnStatement,
+    StaticGet,
+    StringLiteral,
+    ThisExpression,
+    VariableGet;
+
+import '../errors.dart' show
+    inputError;
+
+import '../modifier.dart' show
+    constMask,
+    finalMask,
+    staticMask;
+
+import "../source/source_class_builder.dart" show
+    SourceClassBuilder;
+
+import 'kernel_builder.dart' show
+    Builder,
+    EnumBuilder,
+    FormalParameterBuilder,
+    KernelConstructorBuilder,
+    KernelFieldBuilder,
+    KernelFormalParameterBuilder,
+    KernelLibraryBuilder,
+    KernelNamedTypeBuilder,
+    KernelProcedureBuilder,
+    KernelTypeBuilder,
+    LibraryBuilder,
+    MemberBuilder,
+    MetadataBuilder;
+
+class KernelEnumBuilder extends SourceClassBuilder
+    implements EnumBuilder<KernelTypeBuilder, InterfaceType> {
+  final List<String> constants;
+
+  final MapLiteral toStringMap;
+
+  final KernelTypeBuilder intType;
+
+  final KernelTypeBuilder stringType;
+
+  KernelEnumBuilder.internal(List<MetadataBuilder> metadata, String name,
+      Map<String, Builder> members, Class cls, this.constants, this.toStringMap,
+      this.intType, this.stringType, LibraryBuilder parent, int charOffset)
+      : super(metadata, 0, name, null, null, null, members, parent, null,
+          charOffset, cls);
+
+  factory KernelEnumBuilder(List<MetadataBuilder> metadata, String name,
+      List<String> constants, KernelLibraryBuilder parent, int charOffset) {
+    constants ??= const <String>[];
+    // TODO(ahe): These types shouldn't be looked up in scope, they come
+    // directly from dart:core.
+    KernelTypeBuilder intType = parent.addType(
+        new KernelNamedTypeBuilder("int", null, charOffset, parent.fileUri));
+    KernelTypeBuilder stringType = parent.addType(
+        new KernelNamedTypeBuilder("String", null, charOffset, parent.fileUri));
+    Class cls = new Class(name: name);
+    Map<String, Builder> members = <String, Builder>{};
+    KernelNamedTypeBuilder selfType = new KernelNamedTypeBuilder(
+        name, null, charOffset, parent.fileUri);
+    KernelTypeBuilder listType = parent.addType(
+        new KernelNamedTypeBuilder(
+            "List", <KernelTypeBuilder>[selfType], charOffset, parent.fileUri));
+
+    /// From Dart Programming Language Specification 4th Edition/December 2015:
+    ///     metadata class E {
+    ///       final int index;
+    ///       const E(this.index);
+    ///       static const E id0 = const E(0);
+    ///       ...
+    ///       static const E idn-1 = const E(n - 1);
+    ///       static const List<E> values = const <E>[id0, ..., idn-1];
+    ///       String toString() => { 0: ‘E.id0’, . . ., n-1: ‘E.idn-1’}[index]
+    ///     }
+    members["index"] = new KernelFieldBuilder(null, intType, "index", finalMask,
+        parent, charOffset);
+    KernelConstructorBuilder constructorBuilder = new KernelConstructorBuilder(
+        null, constMask, null, "", null, <FormalParameterBuilder>[
+            new KernelFormalParameterBuilder(null, 0, intType, "index", true,
+                parent, charOffset)], parent, charOffset);
+    members[""] = constructorBuilder;
+    int index = 0;
+    List<MapEntry> toStringEntries = <MapEntry>[];
+    KernelFieldBuilder valuesBuilder = new KernelFieldBuilder(null, listType,
+        "values", constMask | staticMask, parent, charOffset);
+    members["values"] = valuesBuilder;
+    KernelProcedureBuilder toStringBuilder = new KernelProcedureBuilder(null, 0,
+        stringType, "toString", null, null, AsyncMarker.Sync,
+        ProcedureKind.Method, parent, charOffset);
+    members["toString"] = toStringBuilder;
+    String className = name;
+    for (String name in constants) {
+      if (members.containsKey(name)) {
+        inputError(null, null, "Duplicated name: $name");
+        continue;
+      }
+      KernelFieldBuilder fieldBuilder =
+          new KernelFieldBuilder(null, selfType, name, constMask | staticMask,
+              parent, charOffset); // TODO(ahe): Get charOffset from [name].
+      members[name] = fieldBuilder;
+      toStringEntries.add(new MapEntry(
+              new IntLiteral(index), new StringLiteral("$className.$name")));
+      index++;
+    }
+    MapLiteral toStringMap = new MapLiteral(toStringEntries, isConst: true);
+    KernelEnumBuilder enumBuilder = new KernelEnumBuilder.internal(metadata,
+        name, members, cls, constants, toStringMap, intType, stringType,
+        parent, charOffset);
+    // TODO(sigmund): dynamic should be `covariant MemberBuilder`.
+    members.forEach((String name, dynamic b) {
+      MemberBuilder builder = b;
+      builder.parent = enumBuilder;
+    });
+    selfType.builder = enumBuilder;
+    return enumBuilder;
+  }
+
+  InterfaceType buildType(List<KernelTypeBuilder> arguments) {
+    return cls.rawType;
+  }
+
+  Class build(KernelLibraryBuilder libraryBuilder) {
+    if (constants.isEmpty) {
+      libraryBuilder.addCompileTimeError(
+          -1, "An enum declaration can't be empty.");
+    }
+    toStringMap.keyType = intType.build();
+    toStringMap.valueType = stringType.build();
+    KernelFieldBuilder indexFieldBuilder = members["index"];
+    Field indexField = indexFieldBuilder.build(libraryBuilder.library);
+    KernelProcedureBuilder toStringBuilder = members["toString"];
+    toStringBuilder.body = new ReturnStatement(
+        new MethodInvocation(toStringMap, new Name("[]"),
+            new Arguments(<Expression>[
+                    new DirectPropertyGet(new ThisExpression(), indexField)])));
+    List<Expression> values = <Expression>[];
+    for (String name in constants) {
+      KernelFieldBuilder builder = members[name];
+      values.add(new StaticGet(builder.build(libraryBuilder.library)));
+    }
+    KernelFieldBuilder valuesBuilder = members["values"];
+    valuesBuilder.build(libraryBuilder.library);
+    valuesBuilder.initializer =
+        new ListLiteral(values, typeArgument: cls.rawType, isConst: true);
+    KernelConstructorBuilder constructorBuilder = members[""];
+    Constructor constructor = constructorBuilder.build(libraryBuilder.library);
+    constructor.initializers.insert(0, new FieldInitializer(indexField,
+            new VariableGet(constructor.function.positionalParameters.single))
+        ..parent = constructor);
+    int index = 0;
+    for (String constant in constants) {
+      KernelFieldBuilder field = members[constant];
+      field.build(libraryBuilder.library);
+      Arguments arguments =
+          new Arguments(<Expression>[new IntLiteral(index++)]);
+      field.initializer =
+          new ConstructorInvocation(constructor, arguments, isConst: true);
+    }
+    return super.build(libraryBuilder);
+  }
+
+  Builder findConstructorOrFactory(String name) => null;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
new file mode 100644
index 0000000..87af171
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_field_builder;
+
+import 'package:kernel/ast.dart' show
+    Expression,
+    Field,
+    Library,
+    Name;
+
+import 'kernel_builder.dart' show
+    Builder,
+    FieldBuilder,
+    KernelTypeBuilder,
+    MetadataBuilder;
+
+import '../util/relativize.dart' show
+    relativizeUri;
+
+class KernelFieldBuilder extends FieldBuilder<Expression> {
+  final Field field;
+  final List<MetadataBuilder> metadata;
+  final KernelTypeBuilder type;
+
+  KernelFieldBuilder(this.metadata, this.type, String name, int modifiers,
+      Builder compilationUnit, int charOffset)
+      : field =
+            new Field(null, fileUri: relativizeUri(compilationUnit?.fileUri))
+                ..fileOffset = charOffset,
+        super(name, modifiers, compilationUnit, charOffset);
+
+  void set initializer(Expression value) {
+    field.initializer = value
+        ..parent = field;
+  }
+
+  Field build(Library library) {
+    field.name ??= new Name(name, library);
+    if (type != null) {
+      field.type = type.build();
+    }
+    bool isInstanceMember = !isStatic && !isTopLevel;
+    return field
+        ..isFinal = isFinal
+        ..isConst = isConst
+        ..hasImplicitGetter = isInstanceMember
+        ..hasImplicitSetter = isInstanceMember && !isConst && !isFinal
+        ..isStatic = !isInstanceMember;
+  }
+
+  Field get target => field;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart
new file mode 100644
index 0000000..d891e8e
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_formal_parameter_builder;
+
+import 'package:kernel/ast.dart' show
+    DynamicType,
+    VariableDeclaration;
+
+import 'kernel_builder.dart' show
+    FormalParameterBuilder,
+    KernelLibraryBuilder,
+    KernelTypeBuilder,
+    MetadataBuilder;
+
+class KernelFormalParameterBuilder
+    extends FormalParameterBuilder<KernelTypeBuilder> {
+  VariableDeclaration declaration;
+
+  KernelFormalParameterBuilder(List<MetadataBuilder> metadata,
+      int modifiers, KernelTypeBuilder type, String name,
+      bool hasThis, KernelLibraryBuilder compilationUnit, int charOffset)
+      : super (metadata, modifiers, type, name, hasThis, compilationUnit,
+          charOffset);
+
+  VariableDeclaration build() {
+    return declaration ??= new VariableDeclaration(
+        name, type: type?.build() ?? const DynamicType(), isFinal: isFinal,
+        isConst: isConst);
+  }
+
+  VariableDeclaration get target => declaration;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart
new file mode 100644
index 0000000..eb5c312
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_function_type_alias_builder;
+
+import 'package:kernel/ast.dart' show
+    DartType,
+    DynamicType,
+    FunctionType,
+    InvalidType,
+    NamedType,
+    TypeParameter;
+
+import 'package:kernel/type_algebra.dart' show
+    substitute;
+
+import 'kernel_builder.dart' show
+    FormalParameterBuilder,
+    FunctionTypeAliasBuilder,
+    KernelFormalParameterBuilder,
+    KernelTypeBuilder,
+    KernelTypeVariableBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    TypeVariableBuilder,
+    computeDefaultTypeArguments;
+
+class KernelFunctionTypeAliasBuilder
+    extends FunctionTypeAliasBuilder<KernelTypeBuilder, DartType> {
+  DartType thisType;
+
+  DartType type;
+
+  KernelFunctionTypeAliasBuilder(List<MetadataBuilder> metadata,
+      KernelTypeBuilder returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals, LibraryBuilder parent,
+      int charOffset)
+      : super(metadata, returnType, name, typeVariables, formals, parent,
+          charOffset);
+
+  DartType buildThisType() {
+    if (thisType != null) {
+      if (thisType == const InvalidType()) {
+        thisType = const DynamicType();
+        // TODO(ahe): Build an error somehow.
+        print("${parent.uri}: Cyclic typedef: $name.");
+      }
+      return thisType;
+    }
+    thisType = const InvalidType();
+    DartType returnType = this.returnType?.build() ?? const DynamicType();
+    List<DartType> positionalParameters = <DartType>[];
+    List<NamedType> namedParameters;
+    int requiredParameterCount = 0;
+    if (formals != null) {
+      for (KernelFormalParameterBuilder formal in formals) {
+        DartType type = formal.type?.build() ?? const DynamicType();
+        if (formal.isPositional) {
+          positionalParameters.add(type);
+          if (formal.isRequired) requiredParameterCount++;
+        } else if (formal.isNamed) {
+          namedParameters ??= <NamedType>[];
+          namedParameters.add(new NamedType(formal.name, type));
+        }
+      }
+      if (namedParameters != null) {
+        namedParameters.sort();
+      }
+    }
+    List<TypeParameter> typeParameters;
+    if (typeVariables != null) {
+      typeParameters = <TypeParameter>[];
+      for (KernelTypeVariableBuilder t in typeVariables) {
+        typeParameters.add(t.parameter);
+      }
+    }
+    return thisType = new FunctionType(positionalParameters, returnType,
+        namedParameters: namedParameters ?? const <NamedType>[],
+        typeParameters: typeParameters ?? const <TypeParameter>[],
+        requiredParameterCount: requiredParameterCount);
+  }
+
+  /// [arguments] have already been built.
+  DartType buildTypesWithBuiltArguments(List<DartType> arguments) {
+    var thisType = buildThisType();
+    if (thisType is DynamicType) return thisType;
+    FunctionType result = thisType;
+    if (result.typeParameters.isEmpty && arguments == null) return result;
+    arguments = computeDefaultTypeArguments(result.typeParameters, arguments);
+    Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
+    for (int i = 0; i < result.typeParameters.length; i++) {
+      substitution[result.typeParameters[i]] = arguments[i];
+    }
+    return substitute(result.withoutTypeParameters, substitution);
+  }
+
+  DartType buildType(List<KernelTypeBuilder> arguments) {
+    var thisType = buildThisType();
+    if (thisType is DynamicType) return thisType;
+    FunctionType result = thisType;
+    if (result.typeParameters.isEmpty && arguments == null) return result;
+    // Otherwise, substitute.
+    List<DartType> builtArguments = <DartType>[];
+    if (arguments != null) {
+      for (int i = 0; i < arguments.length; i++) {
+        builtArguments.add(arguments[i].build());
+      }
+    }
+    return buildTypesWithBuiltArguments(builtArguments);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart
new file mode 100644
index 0000000..6b24840
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_invalid_type_builder;
+
+import 'package:kernel/ast.dart' show
+    DartType,
+    DynamicType;
+
+import 'kernel_builder.dart' show
+    InvalidTypeBuilder,
+    KernelTypeBuilder;
+
+class KernelInvalidTypeBuilder
+    extends InvalidTypeBuilder<KernelTypeBuilder, DartType> {
+  KernelInvalidTypeBuilder(String name, int charOffset, Uri fileUri)
+      : super(name, null, charOffset, fileUri);
+
+  DartType buildType(List<KernelTypeBuilder> arguments) {
+    // TODO(ahe): Implement error handling.
+    print("No type for: $name");
+    return const DynamicType();
+  }
+
+  /// [Arguments] have already been built.
+  DartType buildTypesWithBuiltArguments(List<DartType> arguments) {
+    // TODO(ahe): Implement error handling.
+    print("No type for: $name");
+    return const DynamicType();
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
new file mode 100644
index 0000000..2f810ea
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -0,0 +1,381 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_library_builder;
+
+import 'package:kernel/ast.dart';
+
+import 'package:kernel/clone.dart' show
+    CloneVisitor;
+
+import '../errors.dart' show
+    internalError;
+
+import '../loader.dart' show
+    Loader;
+
+import '../modifier.dart' show
+    abstractMask,
+    staticMask;
+
+import '../source/source_library_builder.dart' show
+    DeclarationBuilder,
+    SourceLibraryBuilder;
+
+import '../source/source_class_builder.dart' show
+    SourceClassBuilder;
+
+import '../util/relativize.dart' show
+    relativizeUri;
+
+import 'kernel_builder.dart' show
+    Builder,
+    ClassBuilder,
+    ConstructorReferenceBuilder,
+    DynamicTypeBuilder,
+    FormalParameterBuilder,
+    FunctionTypeAliasBuilder,
+    KernelConstructorBuilder,
+    KernelEnumBuilder,
+    KernelFieldBuilder,
+    KernelFormalParameterBuilder,
+    KernelFunctionTypeAliasBuilder,
+    KernelInvalidTypeBuilder,
+    KernelMixinApplicationBuilder,
+    KernelNamedMixinApplicationBuilder,
+    KernelNamedTypeBuilder,
+    KernelProcedureBuilder,
+    KernelTypeBuilder,
+    KernelTypeVariableBuilder,
+    MemberBuilder,
+    MetadataBuilder,
+    MixedAccessor,
+    NamedMixinApplicationBuilder,
+    PrefixBuilder,
+    ProcedureBuilder,
+    TypeBuilder,
+    TypeVariableBuilder;
+
+class KernelLibraryBuilder
+    extends SourceLibraryBuilder<KernelTypeBuilder, Library> {
+  final Library library;
+
+  final List<Class> mixinApplicationClasses = <Class>[];
+
+  final List<List> argumentsWithMissingDefaultValues = <List>[];
+
+  final List<KernelProcedureBuilder> nativeMethods = <KernelProcedureBuilder>[];
+
+  final List<KernelTypeVariableBuilder> boundlessTypeVariables =
+      <KernelTypeVariableBuilder>[];
+
+  KernelLibraryBuilder(Uri uri, Uri fileUri, Loader loader)
+      : library = new Library(uri, fileUri: relativizeUri(fileUri)),
+        super(loader, fileUri);
+
+  Uri get uri => library.importUri;
+
+  KernelTypeBuilder addNamedType(String name,
+      List<KernelTypeBuilder> arguments, int charOffset) {
+    KernelNamedTypeBuilder type =
+        new KernelNamedTypeBuilder(name, arguments, charOffset, fileUri);
+    if (identical(name, "dynamic")) {
+      type.builder =
+          new DynamicTypeBuilder(const DynamicType(), this, charOffset);
+    } else {
+      addType(type);
+    }
+    return type;
+  }
+
+  KernelTypeBuilder addMixinApplication(KernelTypeBuilder supertype,
+      List<KernelTypeBuilder> mixins, int charOffset) {
+    KernelTypeBuilder type = new KernelMixinApplicationBuilder(
+        supertype, mixins, charOffset, fileUri);
+    return addType(type);
+  }
+
+  KernelTypeBuilder addVoidType(int charOffset) {
+    return new KernelNamedTypeBuilder("void", null, charOffset, fileUri);
+  }
+
+  void addClass(List<MetadataBuilder> metadata,
+      int modifiers, String className,
+      List<TypeVariableBuilder> typeVariables, KernelTypeBuilder supertype,
+      List<KernelTypeBuilder> interfaces, int charOffset) {
+    ClassBuilder cls = new SourceClassBuilder(metadata, modifiers, className,
+        typeVariables, supertype, interfaces, classMembers, this,
+        new List<ConstructorReferenceBuilder>.from(constructorReferences),
+        charOffset);
+    constructorReferences.clear();
+    classMembers.forEach((String name, MemberBuilder builder) {
+      while (builder != null) {
+        builder.parent = cls;
+        builder = builder.next;
+      }
+    });
+    // Nested declaration began in `OutlineBuilder.beginClassDeclaration`.
+    endNestedDeclaration().resolveTypes(typeVariables, this);
+    addBuilder(className, cls, charOffset);
+  }
+
+  void addNamedMixinApplication(
+      List<MetadataBuilder> metadata, String name,
+      List<TypeVariableBuilder> typeVariables, int modifiers,
+      KernelTypeBuilder mixinApplication, List<KernelTypeBuilder> interfaces,
+      int charOffset) {
+    NamedMixinApplicationBuilder builder =
+        new KernelNamedMixinApplicationBuilder(metadata, name, typeVariables,
+            modifiers, mixinApplication, interfaces, this, charOffset);
+    // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
+    endNestedDeclaration().resolveTypes(typeVariables, this);
+    addBuilder(name, builder, charOffset);
+  }
+
+  void addField(List<MetadataBuilder> metadata,
+      int modifiers, KernelTypeBuilder type, String name, int charOffset) {
+    addBuilder(name, new KernelFieldBuilder(
+            metadata, type, name, modifiers, this, charOffset), charOffset);
+  }
+
+  void addProcedure(List<MetadataBuilder> metadata,
+      int modifiers, KernelTypeBuilder returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals, AsyncMarker asyncModifier,
+      ProcedureKind kind, int charOffset, String nativeMethodName,
+      {bool isTopLevel}) {
+    // Nested declaration began in `OutlineBuilder.beginMethod` or
+    // `OutlineBuilder.beginTopLevelMethod`.
+    endNestedDeclaration().resolveTypes(typeVariables, this);
+    ProcedureBuilder procedure;
+    if (!isTopLevel && isConstructorName(name, currentDeclaration.name)) {
+      int index = name.indexOf(".");
+      name = index == -1 ? "" : name.substring(index + 1);
+      procedure = new KernelConstructorBuilder(metadata,
+          modifiers & ~abstractMask, returnType, name, typeVariables, formals,
+          this, charOffset, nativeMethodName);
+    } else {
+      procedure = new KernelProcedureBuilder(metadata, modifiers, returnType,
+          name, typeVariables, formals, asyncModifier, kind, this, charOffset,
+          nativeMethodName);
+    }
+    addBuilder(name, procedure, charOffset);
+    if (nativeMethodName != null) {
+      addNativeMethod(procedure);
+    }
+  }
+
+  void addFactoryMethod(List<MetadataBuilder> metadata,
+      ConstructorReferenceBuilder constructorName,
+      List<FormalParameterBuilder> formals, AsyncMarker asyncModifier,
+      ConstructorReferenceBuilder redirectionTarget, int charOffset,
+      String nativeMethodName) {
+    // Nested declaration began in `OutlineBuilder.beginFactoryMethod`.
+    DeclarationBuilder<KernelTypeBuilder> factoryDeclaration =
+        endNestedDeclaration();
+    String name = constructorName.name;
+    int index = name.indexOf(".");
+    name = index == -1 ? "" : name.substring(index + 1);
+    assert(constructorName.suffix == null);
+    KernelProcedureBuilder procedure = new KernelProcedureBuilder(metadata,
+        staticMask, null, name, <TypeVariableBuilder>[], formals, asyncModifier,
+        ProcedureKind.Factory, this, charOffset, nativeMethodName,
+        redirectionTarget);
+    currentDeclaration.addFactoryDeclaration(procedure, factoryDeclaration);
+    addBuilder(name, procedure, charOffset);
+    if (nativeMethodName != null) {
+      addNativeMethod(procedure);
+    }
+  }
+
+  void addEnum(List<MetadataBuilder> metadata, String name,
+      List<String> constants, int charOffset) {
+    addBuilder(name,
+        new KernelEnumBuilder(metadata, name, constants, this, charOffset),
+        charOffset);
+  }
+
+  void addFunctionTypeAlias(List<MetadataBuilder> metadata,
+      KernelTypeBuilder returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals, int charOffset) {
+    FunctionTypeAliasBuilder typedef = new KernelFunctionTypeAliasBuilder(
+        metadata, returnType, name, typeVariables, formals, this, charOffset);
+    // Nested declaration began in `OutlineBuilder.beginFunctionTypeAlias`.
+    endNestedDeclaration().resolveTypes(typeVariables, this);
+    addBuilder(name, typedef, charOffset);
+  }
+
+  KernelFormalParameterBuilder addFormalParameter(
+      List<MetadataBuilder> metadata, int modifiers,
+      KernelTypeBuilder type, String name, bool hasThis, int charOffset) {
+    return new KernelFormalParameterBuilder(
+        metadata, modifiers, type, name, hasThis, this, charOffset);
+  }
+
+  KernelTypeVariableBuilder addTypeVariable(String name,
+      KernelTypeBuilder bound, int charOffset) {
+    var builder = new KernelTypeVariableBuilder(name, this, charOffset, bound);
+    boundlessTypeVariables.add(builder);
+    return builder;
+  }
+
+  void buildBuilder(Builder builder) {
+    if (builder is SourceClassBuilder) {
+      Class cls = builder.build(this);
+      library.addClass(cls);
+      Class superclass = cls.superclass;
+      if (superclass != null && superclass.isMixinApplication) {
+        List<Class> mixinApplications = <Class>[];
+        mixinApplicationClasses.add(cls);
+        while (superclass != null && superclass.isMixinApplication) {
+          if (superclass.parent == null) {
+            mixinApplications.add(superclass);
+          }
+          superclass = superclass.superclass;
+        }
+        for (Class cls in mixinApplications.reversed) {
+          // TODO(ahe): Should be able to move this into the above loop as long
+          // as we don't care about matching dartk perfectly.
+          library.addClass(cls);
+          mixinApplicationClasses.add(cls);
+        }
+      }
+    } else if (builder is KernelFieldBuilder) {
+      library.addMember(builder.build(library)..isStatic = true);
+    } else if (builder is KernelProcedureBuilder) {
+      library.addMember(builder.build(library)..isStatic = true);
+    } else if (builder is FunctionTypeAliasBuilder) {
+      // Kernel discard typedefs and use their corresponding function types
+      // directly.
+    } else if (builder is KernelEnumBuilder) {
+      library.addClass(builder.build(this));
+    } else if (builder is PrefixBuilder) {
+      // Ignored. Kernel doesn't represent prefixes.
+    } else {
+      internalError("Unhandled builder: ${builder.runtimeType}");
+    }
+  }
+
+  Library build() {
+    super.build();
+    library.name = name;
+    return library;
+  }
+
+  Builder buildAmbiguousBuilder(
+      String name, Builder builder, Builder other, int charOffset) {
+    if (builder.next == null && other.next == null) {
+      if (builder.isGetter && other.isSetter) {
+        return new MixedAccessor(builder, other, this);
+      } else if (builder.isSetter && other.isGetter) {
+        return new MixedAccessor(other, builder, this);
+      }
+    }
+    return new KernelInvalidTypeBuilder(name, charOffset, fileUri);
+  }
+
+  void addArgumentsWithMissingDefaultValues(Arguments arguments,
+      FunctionNode function) {
+    assert(partOfLibrary == null);
+    argumentsWithMissingDefaultValues.add([arguments, function]);
+  }
+
+  int finishStaticInvocations() {
+    CloneVisitor cloner;
+    for (var list in argumentsWithMissingDefaultValues) {
+      final Arguments arguments = list[0];
+      final FunctionNode function = list[1];
+
+      Expression defaultArgumentFrom(Expression expression) {
+        if (expression == null) {
+          return new NullLiteral();
+        }
+        cloner ??= new CloneVisitor();
+        return cloner.clone(expression);
+      }
+
+      for (int i = function.requiredParameterCount;
+           i < function.positionalParameters.length;
+           i++) {
+        arguments.positional[i] ??=
+            defaultArgumentFrom(function.positionalParameters[i].initializer)
+            ..parent = arguments;
+      }
+      Map<String, VariableDeclaration> names;
+      for (NamedExpression expression in arguments.named) {
+        if (expression.value == null) {
+          if (names == null) {
+            names = <String, VariableDeclaration>{};
+            for (VariableDeclaration parameter in function.namedParameters) {
+              names[parameter.name] = parameter;
+            }
+          }
+          expression.value =
+              defaultArgumentFrom(names[expression.name].initializer)
+              ..parent = expression;
+        }
+      }
+    }
+    return argumentsWithMissingDefaultValues.length;
+  }
+
+  void addNativeMethod(KernelProcedureBuilder method) {
+    nativeMethods.add(method);
+  }
+
+  int finishNativeMethods() {
+    for (KernelProcedureBuilder method in nativeMethods) {
+      method.becomeNative(loader);
+    }
+    return nativeMethods.length;
+  }
+
+  List<TypeVariableBuilder> copyTypeVariables(
+      List<TypeVariableBuilder> original) {
+    List<TypeVariableBuilder> copy = <TypeVariableBuilder>[];
+    for (KernelTypeVariableBuilder variable in original) {
+      var newVariable = new KernelTypeVariableBuilder(
+          variable.name, this, variable.charOffset);
+      copy.add(newVariable);
+      boundlessTypeVariables.add(newVariable);
+    }
+    Map<TypeVariableBuilder, TypeBuilder> substitution =
+        <TypeVariableBuilder, TypeBuilder>{};
+    int i = 0;
+    for (KernelTypeVariableBuilder variable in original) {
+      substitution[variable] = copy[i++].asTypeBuilder();
+    }
+    i = 0;
+    for (KernelTypeVariableBuilder variable in original) {
+      copy[i++].bound = variable.bound?.subst(substitution);
+    }
+    return copy;
+  }
+
+  int finishTypeVariables(ClassBuilder object) {
+    int count = boundlessTypeVariables.length;
+    for (KernelTypeVariableBuilder builder in boundlessTypeVariables) {
+      builder.finish(object);
+    }
+    boundlessTypeVariables.clear();
+    return count;
+  }
+
+  @override
+  void includePart(KernelLibraryBuilder part) {
+    super.includePart(part);
+    nativeMethods.addAll(part.nativeMethods);
+    boundlessTypeVariables.addAll(part.boundlessTypeVariables);
+    mixinApplicationClasses.addAll(part.mixinApplicationClasses);
+  }
+}
+
+bool isConstructorName(String name, String className) {
+  if (name.startsWith(className)) {
+    if (name.length == className.length) return true;
+    if (name.startsWith(".", className.length)) return true;
+  }
+  return false;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_mixin_application_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_mixin_application_builder.dart
new file mode 100644
index 0000000..34a3f8d
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_mixin_application_builder.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_mixin_application_builder;
+
+import 'package:kernel/ast.dart' show
+    Class,
+    InterfaceType,
+    Supertype;
+
+import 'kernel_builder.dart' show
+    KernelTypeBuilder,
+    MixinApplicationBuilder;
+
+import '../util/relativize.dart' show
+    relativizeUri;
+
+class KernelMixinApplicationBuilder
+    extends MixinApplicationBuilder<KernelTypeBuilder>
+    implements KernelTypeBuilder {
+  final int charOffset;
+
+  final String relativeFileUri;
+
+  Supertype builtType;
+
+  KernelMixinApplicationBuilder(KernelTypeBuilder supertype,
+      List<KernelTypeBuilder> mixins, int charOffset, Uri fileUri)
+      : charOffset = charOffset,
+        relativeFileUri = relativizeUri(fileUri),
+        super(supertype, mixins, charOffset, fileUri);
+
+  InterfaceType build() => buildSupertype().asInterfaceType;
+
+  Supertype buildSupertype() {
+    if (builtType != null) return builtType;
+    Supertype supertype =
+        this.supertype.buildSupertype()?.classNode?.asRawSupertype;
+    if (supertype == null) {
+      return null;
+    }
+    for (KernelTypeBuilder builder in mixins) {
+      Supertype mixin = builder.buildSupertype()?.classNode?.asRawSupertype;
+      if (mixin == null) {
+        return null;
+      }
+      Class application = new Class(
+          name: "${supertype.classNode.name}&${mixin.classNode.name}",
+          isAbstract: true,
+          supertype: supertype,
+          mixedInType: mixin,
+          typeParameters: null, // TODO(ahe): Compute these.
+          fileUri: relativeFileUri);
+      application.fileOffset = charOffset;
+      // TODO(ahe): Use asThisSupertype instead and translate type variables.
+      supertype = application.asRawSupertype;
+    }
+    builtType = supertype;
+    return builtType;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_named_mixin_application_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_named_mixin_application_builder.dart
new file mode 100644
index 0000000..1ad94b2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_named_mixin_application_builder.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_named_mixin_application_builder;
+
+import 'package:kernel/ast.dart' show
+    InterfaceType;
+
+import '../source/source_class_builder.dart' show
+    SourceClassBuilder;
+
+import 'kernel_builder.dart' show
+    Builder,
+    KernelTypeBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    NamedMixinApplicationBuilder,
+    TypeVariableBuilder;
+
+class KernelNamedMixinApplicationBuilder extends SourceClassBuilder
+    implements NamedMixinApplicationBuilder<KernelTypeBuilder, InterfaceType> {
+
+  KernelNamedMixinApplicationBuilder(List<MetadataBuilder> metadata,
+      String name, List<TypeVariableBuilder> typeVariables,
+      int modifiers, KernelTypeBuilder mixinApplication,
+      List<KernelTypeBuilder> interfaces, LibraryBuilder parent, int charOffset)
+      : super(metadata, modifiers, name, typeVariables, mixinApplication,
+          interfaces, <String, Builder>{}, parent, null, charOffset);
+
+  KernelTypeBuilder get mixinApplication => supertype;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart
new file mode 100644
index 0000000..7ab32c1
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_interface_type_builder;
+
+import 'package:kernel/ast.dart' show
+    DartType,
+    DynamicType,
+    Supertype,
+    VoidType;
+
+import '../errors.dart' show
+    inputError;
+
+import 'kernel_builder.dart' show
+    KernelClassBuilder,
+    KernelInvalidTypeBuilder,
+    KernelTypeBuilder,
+    NamedTypeBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder,
+    TypeVariableBuilder;
+
+class KernelNamedTypeBuilder extends NamedTypeBuilder<KernelTypeBuilder>
+    implements KernelTypeBuilder {
+  TypeDeclarationBuilder<KernelTypeBuilder, DartType> builder;
+
+  KernelNamedTypeBuilder(String name, List<KernelTypeBuilder> arguments,
+      int charOffset, Uri fileUri)
+      : super(name, arguments, charOffset, fileUri);
+
+  KernelInvalidTypeBuilder buildInvalidType(String name) {
+    // TODO(ahe): Record error instead of printing.
+    print("$fileUri:$charOffset: Type not found: $name");
+    return new KernelInvalidTypeBuilder(name, charOffset, fileUri);
+  }
+
+  DartType handleMissingType() {
+    // TODO(ahe): Record error instead of printing.
+    print("$fileUri:$charOffset: No type for: $name");
+    return const DynamicType();
+  }
+
+  Supertype handleMissingSuperType() {
+    throw inputError(fileUri, charOffset, "No type for: $name");
+  }
+
+  DartType build() {
+    if (name == "void") return const VoidType();
+    if (name == "dynamic") return const DynamicType();
+    if (builder == null) return handleMissingType();
+    return builder.buildType(arguments);
+  }
+
+  Supertype buildSupertype() {
+    if (name == "void") return null;
+    if (name == "dynamic") return null;
+    if (builder == null) return handleMissingSuperType();
+    if (builder is KernelClassBuilder) {
+      KernelClassBuilder builder = this.builder;
+      return builder.buildSupertype(arguments);
+    } else {
+      return handleMissingSuperType();
+    }
+  }
+
+  TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) {
+    TypeBuilder result = substitution[builder];
+    if (result != null) {
+      assert(builder is TypeVariableBuilder);
+      return result;
+    } else if (arguments != null) {
+      List<KernelTypeBuilder> arguments;
+      int i = 0;
+      for (KernelTypeBuilder argument in this.arguments) {
+        KernelTypeBuilder type = argument.subst(substitution);
+        if (type != argument) {
+          arguments ??= this.arguments.toList();
+          arguments[i] = type;
+        }
+        i++;
+      }
+      if (arguments != null) {
+        return new KernelNamedTypeBuilder(name, arguments, charOffset, fileUri)
+            ..builder = builder;
+      }
+    }
+    return this;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
new file mode 100644
index 0000000..e01a465
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
@@ -0,0 +1,336 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_procedure_builder;
+
+import 'package:kernel/ast.dart' show
+    Arguments,
+    AsyncMarker,
+    Constructor,
+    ConstructorInvocation,
+    DartType,
+    DynamicType,
+    EmptyStatement,
+    Expression,
+    FunctionNode,
+    Initializer,
+    Library,
+    LocalInitializer,
+    Member,
+    Name,
+    NamedExpression,
+    Procedure,
+    ProcedureKind,
+    RedirectingInitializer,
+    Statement,
+    StaticInvocation,
+    StringLiteral,
+    SuperInitializer,
+    TypeParameter,
+    VariableDeclaration,
+    VariableGet,
+    VoidType,
+    setParents;
+
+import 'package:kernel/type_algebra.dart' show
+    containsTypeVariable,
+    substitute;
+
+import '../errors.dart' show
+    internalError;
+
+import '../loader.dart' show
+    Loader;
+
+import '../util/relativize.dart' show
+    relativizeUri;
+
+import 'kernel_builder.dart' show
+    Builder,
+    ClassBuilder,
+    ConstructorReferenceBuilder,
+    FormalParameterBuilder,
+    KernelFormalParameterBuilder,
+    KernelLibraryBuilder,
+    KernelTypeBuilder,
+    KernelTypeVariableBuilder,
+    MetadataBuilder,
+    ProcedureBuilder,
+    TypeVariableBuilder,
+    memberError;
+
+abstract class KernelFunctionBuilder
+    extends ProcedureBuilder<KernelTypeBuilder> {
+  final String nativeMethodName;
+
+  FunctionNode function;
+
+  Statement actualBody;
+
+  KernelFunctionBuilder(List<MetadataBuilder> metadata, int modifiers,
+      KernelTypeBuilder returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals,
+      KernelLibraryBuilder compilationUnit, int charOffset,
+      this.nativeMethodName)
+      : super(metadata, modifiers, returnType, name, typeVariables, formals,
+          compilationUnit, charOffset);
+
+  void set body(Statement newBody) {
+    if (isAbstract && newBody != null) {
+      return internalError("Attempting to set body on abstract method.");
+    }
+    actualBody = newBody;
+    if (function != null) {
+      function.body = newBody;
+      newBody?.parent = function;
+    }
+  }
+
+  Statement get body => actualBody ??= new EmptyStatement();
+
+  bool get isNative => nativeMethodName != null;
+
+  FunctionNode buildFunction() {
+    assert(function == null);
+    FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier);
+    if (typeVariables != null) {
+      for (KernelTypeVariableBuilder t in typeVariables) {
+        result.typeParameters.add(t.parameter);
+      }
+      setParents(result.typeParameters, result);
+    }
+    if (formals != null) {
+      for (KernelFormalParameterBuilder formal in formals) {
+        VariableDeclaration parameter = formal.build();
+        if (formal.isNamed) {
+          result.namedParameters.add(parameter);
+        } else {
+          result.positionalParameters.add(parameter);
+        }
+        parameter.parent = result;
+        if (formal.isRequired) {
+          result.requiredParameterCount++;
+        }
+      }
+    }
+    if (returnType != null) {
+      result.returnType = returnType.build();
+    }
+    if (!isConstructor && !isInstanceMember && parent is ClassBuilder) {
+      List<TypeParameter> typeParameters = parent.target.typeParameters;
+      if (typeParameters.isNotEmpty) {
+        Map<TypeParameter, DartType> substitution;
+        DartType removeTypeVariables(DartType type) {
+          if (substitution == null) {
+            substitution = <TypeParameter, DartType>{};
+            for (TypeParameter parameter in typeParameters) {
+              substitution[parameter] = const DynamicType();
+            }
+          }
+          print("Can only use type variables in instance methods.");
+          return substitute(type, substitution);
+        }
+        Set<TypeParameter> set = typeParameters.toSet();
+        for (VariableDeclaration parameter in result.positionalParameters) {
+          if (containsTypeVariable(parameter.type, set)) {
+            parameter.type = removeTypeVariables(parameter.type);
+          }
+        }
+        for (VariableDeclaration parameter in result.namedParameters) {
+          if (containsTypeVariable(parameter.type, set)) {
+            parameter.type = removeTypeVariables(parameter.type);
+          }
+        }
+        if (containsTypeVariable(result.returnType, set)) {
+          result.returnType = removeTypeVariables(result.returnType);
+        }
+      }
+    }
+    return function = result;
+  }
+
+  Member build(Library library);
+
+  void becomeNative(Loader loader) {
+    target.isExternal = true;
+    Builder constructor = loader.getNativeAnnotation();
+    Arguments arguments =
+        new Arguments(<Expression>[new StringLiteral(nativeMethodName)]);
+    Expression annotation;
+    if (constructor.isConstructor) {
+      annotation = new ConstructorInvocation(constructor.target, arguments)
+          ..isConst = true;
+    } else {
+      annotation = new StaticInvocation(constructor.target, arguments)
+          ..isConst = true;
+    }
+    target.addAnnotation(annotation);
+  }
+}
+
+class KernelProcedureBuilder extends KernelFunctionBuilder {
+  final Procedure procedure;
+
+  AsyncMarker actualAsyncModifier;
+
+  final ConstructorReferenceBuilder redirectionTarget;
+
+  KernelProcedureBuilder(
+      List<MetadataBuilder> metadata,
+      int modifiers, KernelTypeBuilder returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals, this.actualAsyncModifier,
+      ProcedureKind kind, KernelLibraryBuilder compilationUnit, int charOffset,
+      [String nativeMethodName, this.redirectionTarget])
+      : procedure = new Procedure(null, kind, null,
+            fileUri: relativizeUri(compilationUnit?.fileUri)),
+        super(metadata, modifiers, returnType, name, typeVariables, formals,
+            compilationUnit, charOffset, nativeMethodName);
+
+  ProcedureKind get kind => procedure.kind;
+
+  AsyncMarker get asyncModifier => actualAsyncModifier;
+
+  Statement get body {
+    if (actualBody == null && redirectionTarget == null && !isAbstract &&
+        !isExternal) {
+      actualBody = new EmptyStatement();
+    }
+    return actualBody;
+  }
+
+  void set asyncModifier(AsyncMarker newModifier) {
+    actualAsyncModifier = newModifier;
+    if (function != null) {
+      // No parent, it's an enum.
+      function.asyncMarker = actualAsyncModifier;
+    }
+  }
+
+  Procedure build(Library library) {
+    // TODO(ahe): I think we may call this twice on parts. Investigate.
+    if (procedure.name == null) {
+      procedure.function = buildFunction();
+      procedure.function.parent = procedure;
+      procedure.isAbstract = isAbstract;
+      procedure.isStatic = isStatic;
+      procedure.isExternal = isExternal;
+      procedure.isConst = isConst;
+      procedure.name = new Name(name, library);
+    }
+    return procedure;
+  }
+
+  Procedure get target => procedure;
+}
+
+// TODO(ahe): Move this to own file?
+class KernelConstructorBuilder extends KernelFunctionBuilder {
+  final Constructor constructor = new Constructor(null);
+
+  bool hasMovedSuperInitializer = false;
+
+  SuperInitializer superInitializer;
+
+  RedirectingInitializer redirectingInitializer;
+
+  KernelConstructorBuilder(
+      List<MetadataBuilder> metadata,
+      int modifiers, KernelTypeBuilder returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals,
+      KernelLibraryBuilder compilationUnit, int charOffset,
+      [String nativeMethodName])
+      : super(metadata, modifiers, returnType, name, typeVariables, formals,
+          compilationUnit, charOffset, nativeMethodName);
+
+  bool get isInstanceMember => false;
+
+  bool get isConstructor => true;
+
+  AsyncMarker get asyncModifier => AsyncMarker.Sync;
+
+  ProcedureKind get kind => null;
+
+  Constructor build(Library library) {
+    if (constructor.name == null) {
+      constructor.function = buildFunction();
+      constructor.function.parent = constructor;
+      constructor.isConst = isConst;
+      constructor.isExternal = isExternal;
+      constructor.name = new Name(name, library);
+    }
+    return constructor;
+  }
+
+  FunctionNode buildFunction() {
+    // TODO(ahe): Should complain if another type is explicitly set.
+    return super.buildFunction()
+        ..returnType = const VoidType();
+  }
+
+  Constructor get target => constructor;
+
+  void checkSuperOrThisInitializer(Initializer initializer) {
+    if (superInitializer != null || redirectingInitializer != null) {
+      memberError(target,
+          "Can't have more than one 'super' or 'this' initializer.",
+          initializer.fileOffset);
+    }
+  }
+
+  void addInitializer(Initializer initializer) {
+    List<Initializer> initializers = constructor.initializers;
+    if (initializer is SuperInitializer) {
+      checkSuperOrThisInitializer(initializer);
+      superInitializer = initializer;
+    } else if (initializer is RedirectingInitializer) {
+      checkSuperOrThisInitializer(initializer);
+      redirectingInitializer = initializer;
+      if (constructor.initializers.isNotEmpty) {
+        memberError(target, "'this' initializer must be the only initializer.",
+            initializer.fileOffset);
+      }
+    } else if (redirectingInitializer != null) {
+      memberError(target, "'this' initializer must be the only initializer.",
+          initializer.fileOffset);
+    } else if (superInitializer != null) {
+      // If there is a super initializer ([initializer] isn't it), we need to
+      // insert [initializer] before the super initializer (thus ensuring that
+      // the super initializer is always last).
+      assert(superInitializer != initializer);
+      assert(initializers.last == superInitializer);
+      initializers.removeLast();
+      if (!hasMovedSuperInitializer) {
+        // To preserve correct evaluation order, the arguments to super call
+        // must be evaluated before [initializer]. Once the super initializer
+        // has been moved once, the arguments are evaluated in the correct
+        // order.
+        hasMovedSuperInitializer = true;
+        Arguments arguments = superInitializer.arguments;
+        List<Expression> positional = arguments.positional;
+        for (int i = 0; i < positional.length; i++) {
+          VariableDeclaration variable =
+              new VariableDeclaration.forValue(positional[i], isFinal: true);
+          initializers.add(
+              new LocalInitializer(variable)..parent = constructor);
+          positional[i] = new VariableGet(variable)..parent = arguments;
+        }
+        for (NamedExpression named in arguments.named) {
+          VariableDeclaration variable =
+              new VariableDeclaration.forValue(named.value, isFinal: true);
+          named.value = new VariableGet(variable)..parent = named;
+          initializers.add(
+              new LocalInitializer(variable)..parent = constructor);
+        }
+      }
+      initializers.add(initializer..parent = constructor);
+      initializers.add(superInitializer);
+      return;
+    }
+    initializers.add(initializer);
+    initializer.parent = constructor;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
new file mode 100644
index 0000000..8704e05
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -0,0 +1,585 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_target;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    File,
+    IOSink;
+
+import 'package:kernel/ast.dart' show
+    Arguments,
+    AsyncMarker,
+    Class,
+    Constructor,
+    EmptyStatement,
+    Expression,
+    ExpressionStatement,
+    Field,
+    FieldInitializer,
+    FunctionNode,
+    Initializer,
+    InvalidInitializer,
+    Library,
+    Name,
+    NamedExpression,
+    NullLiteral,
+    ProcedureKind,
+    Program,
+    RedirectingInitializer,
+    Source,
+    StringLiteral,
+    SuperInitializer,
+    Throw,
+    VariableDeclaration,
+    VariableGet,
+    VoidType;
+
+import 'package:kernel/binary/ast_to_binary.dart' show
+    BinaryPrinter;
+
+import 'package:kernel/text/ast_to_text.dart' show
+    Printer;
+
+import 'package:kernel/transformations/mixin_full_resolution.dart' show
+    MixinFullResolution;
+
+import 'package:kernel/transformations/setup_builtin_library.dart' as
+    setup_builtin_library;
+
+import '../source/source_loader.dart' show
+    SourceLoader;
+
+import '../source/source_class_builder.dart' show
+    SourceClassBuilder;
+
+import '../target_implementation.dart' show
+    TargetImplementation;
+
+import '../translate_uri.dart' show
+    TranslateUri;
+
+import '../dill/dill_target.dart' show
+    DillTarget;
+
+import '../ast_kind.dart' show
+    AstKind;
+
+import '../errors.dart' show
+    InputError,
+    internalError,
+    reportCrash,
+    resetCrashReporting;
+
+import 'kernel_builder.dart' show
+    Builder,
+    ClassBuilder,
+    DynamicTypeBuilder,
+    InvalidTypeBuilder,
+    KernelClassBuilder,
+    KernelLibraryBuilder,
+    KernelNamedTypeBuilder,
+    KernelProcedureBuilder,
+    LibraryBuilder,
+    MixinApplicationBuilder,
+    NamedMixinApplicationBuilder,
+    NamedTypeBuilder,
+    TypeBuilder;
+
+class KernelTarget extends TargetImplementation {
+  final DillTarget dillTarget;
+  SourceLoader<Library> loader;
+  Program program;
+
+  final List errors = [];
+
+  KernelTarget(DillTarget dillTarget, TranslateUri uriTranslator)
+      : dillTarget = dillTarget,
+        super(dillTarget.ticker, uriTranslator) {
+    resetCrashReporting();
+    loader = new SourceLoader<Library>(this);
+  }
+
+  void read(Uri uri) {
+    loader.read(uri);
+  }
+
+  LibraryBuilder createLibraryBuilder(Uri uri, Uri fileUri) {
+    if (dillTarget.isLoaded) {
+      var builder = dillTarget.loader.builders[uri];
+      if (builder != null) {
+        return builder;
+      }
+    }
+    return new KernelLibraryBuilder(uri, fileUri, loader);
+  }
+
+  void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set) {
+    if (cls == null) return;
+    TypeBuilder supertype = cls.supertype;
+    add(NamedTypeBuilder type) {
+      Builder builder = type.builder;
+      if (builder is ClassBuilder) {
+        set.add(builder);
+      } else if (builder is! InvalidTypeBuilder &&
+          builder is! DynamicTypeBuilder) {
+        internalError("Unhandled: ${builder.runtimeType}");
+      }
+    }
+    if (supertype == null) {
+      // OK.
+    } else if (supertype is MixinApplicationBuilder) {
+      add(supertype.supertype);
+      for (NamedTypeBuilder t in supertype.mixins) {
+        add(t);
+      }
+    } else if (supertype is NamedTypeBuilder) {
+      add(supertype);
+    } else {
+      internalError("Unhandled: ${supertype.runtimeType}");
+    }
+    if (cls.interfaces != null) {
+      for (NamedTypeBuilder t in cls.interfaces) {
+        add(t);
+      }
+    }
+  }
+
+  List<ClassBuilder> collectAllClasses() {
+    List<ClassBuilder> result = <ClassBuilder>[];
+    loader.builders.forEach((Uri uri, LibraryBuilder library) {
+      library.members.forEach((String name, Builder member) {
+        if (member is KernelClassBuilder) {
+          result.add(member);
+        }
+      });
+      // TODO(ahe): Translate this if needed:
+      // if (library is KernelLibraryBuilder) {
+      //   result.addAll(library.mixinApplicationClasses);
+      // }
+    });
+    return result;
+  }
+
+  List<SourceClassBuilder> collectAllSourceClasses() {
+    List<SourceClassBuilder> result = <SourceClassBuilder>[];
+    loader.builders.forEach((Uri uri, LibraryBuilder library) {
+      library.members.forEach((String name, Builder member) {
+        if (member is SourceClassBuilder) {
+          result.add(member);
+        }
+      });
+    });
+    return result;
+  }
+
+  List<Class> collectAllMixinApplications() {
+    List<Class> result = <Class>[];
+    loader.builders.forEach((Uri uri, LibraryBuilder library) {
+      if (library is KernelLibraryBuilder) {
+        result.addAll(library.mixinApplicationClasses);
+      }
+    });
+    return result;
+  }
+
+  void breakCycle(ClassBuilder builder) {
+    Class cls = builder.target;
+    cls.implementedTypes.clear();
+    cls.supertype = null;
+    cls.mixedInType = null;
+    builder.supertype =
+        new KernelNamedTypeBuilder(
+            "Object", null, builder.charOffset,
+            builder.fileUri ?? Uri.parse(cls.fileUri))
+        ..builder = objectClassBuilder;
+    builder.interfaces = null;
+  }
+
+  Future<Program> handleInputError(Uri uri, InputError error,
+      {bool isFullProgram}) {
+    if (error != null) {
+      String message = error.format();
+      print(message);
+      errors.add(message);
+    }
+    program = erroneousProgram(isFullProgram);
+    return uri == null
+        ? new Future<Program>.value(program)
+        : writeLinkedProgram(uri, program, isFullProgram: isFullProgram);
+  }
+
+  Future<Program> writeProgram(Uri uri, AstKind astKind) async {
+    if (loader.first == null) return null;
+    if (errors.isNotEmpty) {
+      return handleInputError(uri, null, isFullProgram: true);
+    }
+    try {
+      if (astKind == AstKind.Analyzer) {
+        loader.buildElementStore();
+      } else {
+        loader.computeHierarchy(program);
+      }
+      await loader.buildBodies(astKind);
+      loader.finishStaticInvocations();
+      finishAllConstructors();
+      loader.finishNativeMethods();
+      transformMixinApplications();
+      errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format()));
+      if (errors.isNotEmpty) {
+        return handleInputError(uri, null, isFullProgram: true);
+      }
+      if (uri == null) return program;
+      return await writeLinkedProgram(uri, program, isFullProgram: true);
+    } on InputError catch (e) {
+      return handleInputError(uri, e, isFullProgram: true);
+    } catch (e, s) {
+      return reportCrash(e, s, loader?.currentUriForCrashReporting);
+    }
+  }
+
+  Future<Program> writeOutline(Uri uri) async {
+    if (loader.first == null) return null;
+    try {
+      await loader.buildOutlines();
+      loader.resolveParts();
+      loader.computeLibraryScopes();
+      loader.resolveTypes();
+      loader.buildProgram();
+      loader.checkSemantics();
+      List<SourceClassBuilder> sourceClasses = collectAllSourceClasses();
+      installDefaultSupertypes(sourceClasses);
+      installDefaultConstructors(sourceClasses);
+      loader.resolveConstructors();
+      loader.finishTypeVariables(objectClassBuilder);
+      program = link(new List<Library>.from(loader.libraries));
+      if (uri == null) return program;
+      return await writeLinkedProgram(uri, program, isFullProgram: false);
+    } on InputError catch (e) {
+      return handleInputError(uri, e, isFullProgram: false);
+    } catch (e, s) {
+      return reportCrash(e, s, loader?.currentUriForCrashReporting);
+    }
+  }
+
+  Program erroneousProgram(bool isFullProgram) {
+    Uri uri = loader.first?.uri ?? Uri.parse("error:error");
+    Uri fileUri = loader.first?.fileUri ?? uri;
+    KernelLibraryBuilder library =
+        new KernelLibraryBuilder(uri, fileUri, loader);
+    loader.first = library;
+    if (isFullProgram) {
+      // If this is an outline, we shouldn't add an executable main
+      // method. Similarly considerations apply to separate compilation. It
+      // could also make sense to add a way to mark .dill files as having
+      // compile-time errors.
+      KernelProcedureBuilder mainBuilder = new KernelProcedureBuilder(null, 0,
+          null, "main", null, null, AsyncMarker.Sync, ProcedureKind.Method,
+          library, -1);
+      library.addBuilder(mainBuilder.name, mainBuilder, -1);
+      mainBuilder.body = new ExpressionStatement(
+          new Throw(new StringLiteral("${errors.join('\n')}")));
+    }
+    library.build();
+    return link(<Library>[library.library]);
+  }
+
+  /// Creates a program by combining [libraries] with the libraries of
+  /// `dillTarget.loader.program`.
+  Program link(List<Library> libraries) {
+    Map<String, Source> uriToSource = <String, Source>{};
+
+    // for (Library library in libraries) {
+    //   // TODO(ahe): Compute line starts instead.
+    //   uriToLineStarts[library.fileUri] = <int>[0];
+    // }
+
+    final Program binary = dillTarget.loader.program;
+    if (binary != null) {
+      libraries.addAll(binary.libraries);
+      uriToSource.addAll(binary.uriToSource);
+    }
+
+    // TODO(ahe): Remove this line. Kernel seems to generate a default line map
+    // that used when there's no fileUri on an element. Instead, ensure all
+    // elements have a fileUri.
+    uriToSource[""] = new Source(<int>[0], "");
+    Program program = new Program(libraries, uriToSource);
+    if (loader.first != null) {
+      Builder builder = loader.first.members["main"];
+      if (builder is KernelProcedureBuilder) {
+        program.mainMethod = builder.procedure;
+      }
+    }
+    setup_builtin_library.transformProgram(program);
+    ticker.logMs("Linked program");
+    return program;
+  }
+
+  Future<Program> writeLinkedProgram(Uri uri, Program program,
+      {bool isFullProgram}) async {
+    File output = new File.fromUri(uri);
+    IOSink sink = output.openWrite();
+    try {
+      new BinaryPrinter(sink).writeProgramFile(program);
+    } finally {
+      await sink.close();
+    }
+    if (isFullProgram) {
+      ticker.logMs("Wrote program to ${uri.toFilePath()}");
+    } else {
+      ticker.logMs("Wrote outline to ${uri.toFilePath()}");
+    }
+    return null;
+  }
+
+  void installDefaultSupertypes(List<SourceClassBuilder> builders) {
+    Class objectClass = this.objectClass;
+    for (SourceClassBuilder builder in builders) {
+      Class cls = builder.target;
+      if (cls != objectClass) {
+        cls.supertype ??= objectClass.asRawSupertype;
+      }
+    }
+    ticker.logMs("Installed Object as implicit superclass");
+  }
+
+  void installDefaultConstructors(List<SourceClassBuilder> builders) {
+    Class objectClass = this.objectClass;
+    for (SourceClassBuilder builder in builders) {
+      if (builder.target != objectClass) {
+        installDefaultConstructor(builder);
+      }
+    }
+    ticker.logMs("Installed default constructors");
+  }
+
+  KernelClassBuilder get objectClassBuilder {
+    return loader.coreLibrary.exports["Object"];
+  }
+
+  Class get objectClass => objectClassBuilder.cls;
+
+  /// If [builder] doesn't have a constructors, install the defaults.
+  void installDefaultConstructor(SourceClassBuilder builder) {
+    if (!builder.constructors.isEmpty) return;
+    /// Quotes below are from [Dart Programming Language Specification, 4th
+    /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
+    if (builder is NamedMixinApplicationBuilder) {
+      /// >A mixin application of the form S with M; defines a class C with
+      /// >superclass S.
+      /// >...
+
+      /// >Let LM be the library in which M is declared. For each generative
+      /// >constructor named qi(Ti1 ai1, . . . , Tiki aiki), i in 1..n of S
+      /// >that is accessible to LM , C has an implicitly declared constructor
+      /// >named q'i = [C/S]qi of the form q'i(ai1,...,aiki) :
+      /// >super(ai1,...,aiki);.
+      Builder supertype = builder;
+      while (supertype is NamedMixinApplicationBuilder) {
+        NamedMixinApplicationBuilder named = supertype;
+        TypeBuilder type = named.mixinApplication;
+        if (type is MixinApplicationBuilder) {
+          MixinApplicationBuilder t = type;
+          type = t.supertype;
+        }
+        if (type is NamedTypeBuilder) {
+          supertype = type.builder;
+        } else {
+          internalError("Unhandled: ${type.runtimeType}");
+        }
+      }
+      if (supertype is KernelClassBuilder) {
+        for (Constructor constructor in supertype.cls.constructors) {
+          builder.addSyntheticConstructor(
+              makeMixinApplicationConstructor(builder.cls.mixin, constructor));
+        }
+      } else {
+        internalError("Unhandled: ${supertype.runtimeType}");
+      }
+    } else {
+      /// >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());
+    }
+  }
+
+  Constructor makeMixinApplicationConstructor(
+      Class mixin, Constructor constructor) {
+    VariableDeclaration copyFormal(VariableDeclaration formal) {
+      // TODO(ahe): Handle initializers.
+      return new VariableDeclaration(formal.name,
+          type: formal.type, isFinal: formal.isFinal, isConst: formal.isConst);
+    }
+    List<VariableDeclaration> positionalParameters = <VariableDeclaration>[];
+    List<VariableDeclaration> namedParameters = <VariableDeclaration>[];
+    List<Expression> positional = <Expression>[];
+    List<NamedExpression> named = <NamedExpression>[];
+    for (VariableDeclaration formal in
+             constructor.function.positionalParameters) {
+      positionalParameters.add(copyFormal(formal));
+      positional.add(new VariableGet(positionalParameters.last));
+    }
+    for (VariableDeclaration formal in
+             constructor.function.namedParameters) {
+      namedParameters.add(copyFormal(formal));
+      named.add(new NamedExpression(
+              formal.name, new VariableGet(namedParameters.last)));
+    }
+    FunctionNode function = new FunctionNode(new EmptyStatement(),
+        positionalParameters: positionalParameters,
+        namedParameters: namedParameters,
+        requiredParameterCount: constructor.function.requiredParameterCount,
+        returnType: const VoidType());
+    SuperInitializer initializer = new SuperInitializer(
+        constructor, new Arguments(positional, named: named));
+    return new Constructor(function,
+        name: constructor.name,
+        initializers: <Initializer>[initializer]);
+  }
+
+  Constructor makeDefaultConstructor() {
+    return new Constructor(
+        new FunctionNode(new EmptyStatement(), returnType: const VoidType()),
+        name: new Name(""));
+  }
+
+  void finishAllConstructors() {
+    Class objectClass = this.objectClass;
+    for (SourceClassBuilder builder in collectAllSourceClasses()) {
+      Class cls = builder.target;
+      if (cls != objectClass) {
+        finishConstructors(cls);
+      }
+    }
+    ticker.logMs("Finished constructors");
+  }
+
+  /// Ensure constructors of [cls] have the correct initializers and other
+  /// requirements.
+  void finishConstructors(Class cls) {
+    /// Quotes below are from [Dart Programming Language Specification, 4th
+    /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
+    Constructor superTarget;
+    List<Field> uninitializedFields = <Field>[];
+    for (Field field in cls.fields) {
+      if (field.initializer == null) {
+        uninitializedFields.add(field);
+      }
+    }
+    Map<Constructor, List<FieldInitializer>> fieldInitializers =
+        <Constructor, List<FieldInitializer>>{};
+    for (Constructor constructor in cls.constructors) {
+      if (!isRedirectingGenerativeConstructor(constructor)) {
+        /// >If no superinitializer is provided, an implicit superinitializer
+        /// >of the form super() is added at the end of k’s initializer list,
+        /// >unless the enclosing class is class Object.
+        if (!constructor.initializers.any(isSuperinitializerOrInvalid)) {
+          superTarget ??= defaultSuperConstructor(cls);
+          Initializer initializer;
+          if (superTarget == null) {
+            initializer = new InvalidInitializer();
+          } else {
+            initializer =
+                new SuperInitializer(superTarget, new Arguments.empty());
+          }
+          constructor.initializers.add(initializer);
+          initializer.parent = constructor;
+        }
+        if (constructor.function.body == null) {
+          /// >If a generative constructor c is not a redirecting constructor
+          /// >and no body is provided, then c implicitly has an empty body {}.
+          /// We use an empty statement instead.
+          constructor.function.body = new EmptyStatement();
+          constructor.function.body.parent = constructor.function;
+        }
+        List<FieldInitializer> myFieldInitializers = <FieldInitializer>[];
+        for (Initializer initializer in constructor.initializers) {
+          if (initializer is FieldInitializer) {
+            myFieldInitializers.add(initializer);
+          }
+        }
+        fieldInitializers[constructor] = myFieldInitializers;
+      }
+    }
+    Set<Field> initializedFields;
+    fieldInitializers.forEach(
+        (Constructor constructor, List<FieldInitializer> initializers) {
+      Iterable<Field> fields = initializers.map((i) => i.field);
+      if (initializedFields == null) {
+        initializedFields = new Set<Field>.from(fields);
+      } else {
+        initializedFields.addAll(fields);
+      }
+    });
+    // Run through all fields that aren't initialized by any constructor, and
+    // set their initializer to `null`.
+    for (Field field in uninitializedFields) {
+      if (initializedFields == null || !initializedFields.contains(field)) {
+        field.initializer = new NullLiteral()
+            ..parent = field;
+      }
+    }
+    // Run through all fields that are initialized by some constructor, and
+    // make sure that all other constructors also initialize them.
+    fieldInitializers.forEach(
+        (Constructor constructor, List<FieldInitializer> initializers) {
+      Iterable<Field> fields = initializers.map((i) => i.field);
+      for (Field field in initializedFields.difference(fields.toSet())) {
+        if (field.initializer == null) {
+          FieldInitializer initializer =
+              new FieldInitializer(field, new NullLiteral());
+          initializer.parent = constructor;
+          constructor.initializers.insert(0, initializer);
+        }
+      }
+    });
+  }
+
+  void transformMixinApplications() {
+    new MixinFullResolution().transform(program);
+    ticker.logMs("Transformed mixin applications");
+  }
+
+  void dumpIr() {
+    StringBuffer sb = new StringBuffer();
+    for (Library library in loader.libraries) {
+      Printer printer = new Printer(sb);
+      printer.writeLibraryFile(library);
+    }
+    print("$sb");
+  }
+}
+
+bool isSuperinitializerOrInvalid(Initializer initializer) {
+  return initializer is SuperInitializer
+      || initializer is InvalidInitializer;
+}
+
+bool isRedirectingGenerativeConstructor(Constructor constructor) {
+  List<Initializer> initializers = constructor.initializers;
+  return initializers.length == 1
+      && initializers.single is RedirectingInitializer;
+}
+
+/// Looks for a constructor call that matches `super()` from a constructor in
+/// [cls]. Such a constructor may have optional arguments, but no required
+/// arguments.
+Constructor defaultSuperConstructor(Class cls) {
+  Class superclass = cls.superclass;
+  while (superclass != null && superclass.isMixinApplication) {
+    superclass = superclass.superclass;
+  }
+  for (Constructor constructor in superclass.constructors) {
+    if (constructor.name.name.isEmpty) {
+      return constructor.function.requiredParameterCount == 0 ?
+          constructor : null;
+    }
+  }
+  return null;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_type_builder.dart
new file mode 100644
index 0000000..3144278
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_type_builder.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_type_builder;
+
+import 'package:kernel/ast.dart' show
+    DartType,
+    Supertype;
+
+import 'kernel_builder.dart' show
+    TypeBuilder;
+
+abstract class KernelTypeBuilder extends TypeBuilder {
+  KernelTypeBuilder(int charOffset, Uri fileUri)
+      : super(charOffset, fileUri);
+
+  DartType build();
+
+  Supertype buildSupertype();
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_type_variable_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_type_variable_builder.dart
new file mode 100644
index 0000000..e6c8356
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_type_variable_builder.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_type_variable_builder;
+
+import 'package:kernel/ast.dart' show
+    DartType,
+    TypeParameter,
+    TypeParameterType;
+
+import '../errors.dart' show
+    inputError;
+
+import 'kernel_builder.dart' show
+    KernelClassBuilder,
+    KernelLibraryBuilder,
+    KernelNamedTypeBuilder,
+    KernelTypeBuilder,
+    TypeVariableBuilder;
+
+class KernelTypeVariableBuilder
+    extends TypeVariableBuilder<KernelTypeBuilder, DartType> {
+  final TypeParameter parameter;
+
+  KernelTypeVariableBuilder(String name, KernelLibraryBuilder compilationUnit,
+      int charOffset, [KernelTypeBuilder bound])
+      : parameter = new TypeParameter(name, null),
+        super(name, bound, compilationUnit, charOffset);
+
+  DartType buildType(List<KernelTypeBuilder> arguments) {
+    if (arguments != null) {
+      return inputError(null, null,
+          "Can't use type arguments with type parameter $parameter");
+    } else {
+      return new TypeParameterType(parameter);
+    }
+  }
+
+  DartType buildTypesWithBuiltArguments(List<DartType> arguments) {
+    if (arguments != null) {
+      return inputError(null, null,
+          "Can't use type arguments with type parameter $parameter");
+    } else {
+      return buildType(null);
+    }
+  }
+
+  KernelTypeBuilder asTypeBuilder() {
+    return new KernelNamedTypeBuilder(name, null, -1, null)
+        ..builder = this;
+  }
+
+  void finish(KernelClassBuilder object) {
+    parameter.bound = bound?.build() ?? object.buildType(null);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart
new file mode 100644
index 0000000..afc7bda
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.kernel_variable_builder;
+
+import 'package:kernel/ast.dart' show
+    VariableDeclaration;
+
+import 'kernel_builder.dart' show
+    Builder;
+
+class KernelVariableBuilder extends Builder {
+  final VariableDeclaration variable;
+
+  KernelVariableBuilder(VariableDeclaration variable, Builder parent)
+      : variable = variable,
+        super(parent, variable.fileOffset, parent.fileUri);
+
+  bool get isLocal => true;
+
+  VariableDeclaration get target => variable;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
new file mode 100644
index 0000000..ada1436
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.redirecting_factory_body;
+
+import 'package:kernel/ast.dart' show
+    InvalidStatement,
+    Member,
+    Procedure;
+
+class RedirectingFactoryBody extends InvalidStatement {
+  final Member target;
+
+  RedirectingFactoryBody(this.target);
+}
+
+bool isRedirectingFactory(Member member) {
+  return member is Procedure &&
+      member.function.body is RedirectingFactoryBody;
+}
+
+Member getImmediateRedirectionTarget(Member member) {
+  if (isRedirectingFactory(member)) {
+    Procedure procedure = member;
+    RedirectingFactoryBody body = procedure.function.body;
+    return body.target;
+  } else {
+    return null;
+  }
+}
+
+Member getRedirectionTarget(Procedure member) {
+  // We use the [tortoise and hare algorithm]
+  // (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
+  // handle cycles.
+  Member tortoise = member;
+  Member hare = getImmediateRedirectionTarget(member);
+  while (tortoise != hare) {
+    if (!isRedirectingFactory(tortoise)) return tortoise;
+    tortoise = getImmediateRedirectionTarget(tortoise);
+    hare = getImmediateRedirectionTarget(getImmediateRedirectionTarget(hare));
+  }
+  return null;
+}
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
new file mode 100644
index 0000000..a96d3b5
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -0,0 +1,160 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.loader;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:collection' show
+    Queue;
+
+import 'ast_kind.dart' show
+    AstKind;
+
+import 'builder/builder.dart' show
+    Builder,
+    LibraryBuilder;
+
+import 'errors.dart' show
+    InputError,
+    firstSourceUri;
+
+import 'target_implementation.dart' show
+    TargetImplementation;
+
+import 'ticker.dart' show
+    Ticker;
+
+abstract class Loader<L> {
+  final Map<Uri, LibraryBuilder> builders = <Uri, LibraryBuilder>{};
+
+  final Queue<LibraryBuilder> unparsedLibraries = new Queue<LibraryBuilder>();
+
+  final List<L> libraries = <L>[];
+
+  final TargetImplementation target;
+
+  LibraryBuilder coreLibrary;
+
+  LibraryBuilder first;
+
+  int byteCount = 0;
+
+  Uri currentUriForCrashReporting;
+
+  Loader(this.target);
+
+  Ticker get ticker => target.ticker;
+
+  /// Look up a library builder by the the name [uri], or if such doesn't
+  /// exist, create one. The canonical URI of the library is [uri], and its
+  /// actual location is [fileUri].
+  ///
+  /// Canonical URIs have schemes like "dart", or "package", and the actual
+  /// location is often a file URI.
+  LibraryBuilder read(Uri uri, [Uri fileUri]) {
+    firstSourceUri ??= uri;
+    LibraryBuilder builder = builders.putIfAbsent(uri, () {
+      if (fileUri == null) {
+        switch (uri.scheme) {
+          case "package":
+          case "dart":
+            fileUri = target.translateUri(uri);
+            break;
+
+          default:
+            fileUri = uri;
+            break;
+        }
+      }
+      LibraryBuilder library = target.createLibraryBuilder(uri, fileUri);
+      if (uri.scheme == "dart" && uri.path == "core") {
+        coreLibrary = library;
+        target.loadExtraRequiredLibraries(this);
+      }
+      first ??= library;
+      if (library.loader == this) {
+        unparsedLibraries.addLast(library);
+      }
+      return library;
+    });
+    return builder;
+  }
+
+  void ensureCoreLibrary() {
+    if (coreLibrary == null) {
+      read(Uri.parse("dart:core"));
+      assert(coreLibrary != null);
+    }
+  }
+
+  Future<Null> buildBodies(AstKind astKind) async {
+    assert(coreLibrary != null);
+    for (LibraryBuilder library in builders.values) {
+      currentUriForCrashReporting = library.uri;
+      await buildBody(library, astKind);
+    }
+    currentUriForCrashReporting = null;
+    ticker.log((Duration elapsed, Duration sinceStart) {
+      int libraryCount = builders.length;
+      double ms =
+          elapsed.inMicroseconds / Duration.MICROSECONDS_PER_MILLISECOND;
+      String message = "Built $libraryCount compilation units";
+      print("""
+$sinceStart: $message ($byteCount bytes) in ${format(ms, 3, 0)}ms, that is,
+${format(byteCount / ms, 3, 12)} bytes/ms, and
+${format(ms / libraryCount, 3, 12)} ms/compilation unit.""");
+    });
+  }
+
+  Future<Null> buildOutlines() async {
+    ensureCoreLibrary();
+    while (unparsedLibraries.isNotEmpty) {
+      LibraryBuilder library = unparsedLibraries.removeFirst();
+      currentUriForCrashReporting = library.uri;
+      await buildOutline(library);
+    }
+    currentUriForCrashReporting = null;
+    ticker.log((Duration elapsed, Duration sinceStart) {
+      int libraryCount = builders.length;
+      double ms =
+          elapsed.inMicroseconds / Duration.MICROSECONDS_PER_MILLISECOND;
+      String message = "Built outlines for $libraryCount compilation units";
+      // TODO(ahe): Share this message with [buildBodies]. Also make it easy to
+      // tell the difference between outlines read from a dill file or source
+      // files. Currently, [libraryCount] is wrong for dill files.
+      print("""
+$sinceStart: $message ($byteCount bytes) in ${format(ms, 3, 0)}ms, that is,
+${format(byteCount / ms, 3, 12)} bytes/ms, and
+${format(ms / libraryCount, 3, 12)} ms/compilation unit.""");
+    });
+  }
+
+  Future<Null> buildOutline(covariant LibraryBuilder library);
+
+  /// Builds all the method bodies found in the given [library].
+  ///
+  /// [astKind] determines whether or not analyzer ASTs are used as an
+  /// intermediate data structure.
+  Future<Null> buildBody(covariant LibraryBuilder library, AstKind astKind);
+
+  List<InputError> collectCompileTimeErrors() {
+    List<InputError> errors = <InputError>[];
+    for (LibraryBuilder library in builders.values) {
+      if (library.loader == this) {
+        errors.addAll(library.compileTimeErrors);
+      }
+    }
+    return errors;
+  }
+
+  Builder getCompileTimeError() => target.getCompileTimeError(this);
+
+  Builder getNativeAnnotation() => target.getNativeAnnotation(this);
+}
+
+String format(double d, int fractionDigits, int width) {
+  return d.toStringAsFixed(fractionDigits).padLeft(width);
+}
diff --git a/pkg/front_end/lib/src/fasta/modifier.dart b/pkg/front_end/lib/src/fasta/modifier.dart
new file mode 100644
index 0000000..8bd8eaf
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/modifier.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.modifier;
+
+import 'errors.dart' show
+    internalError;
+
+enum ModifierEnum {
+  Abstract,
+  Const,
+  External,
+  Final,
+  Static,
+
+  // Not a real modifier.
+  Var,
+}
+
+const int abstractMask = 1;
+
+const int constMask = abstractMask << 1;
+
+const int externalMask = constMask << 1;
+
+const int finalMask = externalMask << 1;
+
+const int staticMask = finalMask << 1;
+
+/// Not a real modifier, and by setting it to null, it is automatically
+/// ignored by [Modifier.validate] below.
+const int varMask = 0;
+
+const Modifier Abstract = const Modifier(ModifierEnum.Abstract, abstractMask);
+
+const Modifier Const = const Modifier(ModifierEnum.Const, constMask);
+
+const Modifier External = const Modifier(ModifierEnum.External, externalMask);
+
+const Modifier Final = const Modifier(ModifierEnum.Final, finalMask);
+
+const Modifier Static = const Modifier(ModifierEnum.Static, staticMask);
+
+/// Not a real modifier.
+const Modifier Var = const Modifier(ModifierEnum.Var, varMask);
+
+class Modifier {
+  final ModifierEnum kind;
+
+  final int mask;
+
+  const Modifier(this.kind, this.mask);
+
+  factory Modifier.fromString(String string) {
+    if (identical('abstract', string)) return Abstract;
+    if (identical('const', string)) return Const;
+    if (identical('external', string)) return External;
+    if (identical('final', string)) return Final;
+    if (identical('static', string)) return Static;
+    if (identical('var', string)) return Var;
+    return internalError("Unhandled modifier: $string");
+  }
+
+  toString() => "modifier(${'$kind'.substring('ModifierEnum.'.length)})";
+
+  static int validate(List<Modifier> modifiers, {bool isAbstract: false}) {
+    // TODO(ahe): Implement modifier validation: ordering and uniqueness.
+    int result = isAbstract ? abstractMask : 0;
+    if (modifiers == null) return result;
+    for (Modifier modifier in modifiers) {
+      result |= modifier.mask;
+    }
+    return result;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/operator.dart b/pkg/front_end/lib/src/fasta/operator.dart
new file mode 100644
index 0000000..e6f4b23
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/operator.dart
@@ -0,0 +1,80 @@
+// 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 fasta.operators;
+
+/// The user-definable operators in Dart.
+///
+/// The names have been chosen to represent their normal semantic meaning.
+enum Operator {
+  add,
+  bitwiseAnd,
+  bitwiseNot,
+  bitwiseOr,
+  bitwiseXor,
+  divide,
+  equals,
+  greaterThan,
+  greaterThanEquals,
+  indexGet,
+  indexSet,
+  leftShift,
+  lessThan,
+  lessThanEquals,
+  modulo,
+  multiply,
+  rightShift,
+  subtract,
+  truncatingDivide,
+  unaryMinus,
+}
+
+Operator operatorFromString(String string) {
+  if (identical("+", string)) return Operator.add;
+  if (identical("&", string)) return Operator.bitwiseAnd;
+  if (identical("~", string)) return Operator.bitwiseNot;
+  if (identical("|", string)) return Operator.bitwiseOr;
+  if (identical("^", string)) return Operator.bitwiseXor;
+  if (identical("/", string)) return Operator.divide;
+  if (identical("==", string)) return Operator.equals;
+  if (identical(">", string)) return Operator.greaterThan;
+  if (identical(">=", string)) return Operator.greaterThanEquals;
+  if (identical("[]", string)) return Operator.indexGet;
+  if (identical("[]=", string)) return Operator.indexSet;
+  if (identical("<<", string)) return Operator.leftShift;
+  if (identical("<", string)) return Operator.lessThan;
+  if (identical("<=", string)) return Operator.lessThanEquals;
+  if (identical("%", string)) return Operator.modulo;
+  if (identical("*", string)) return Operator.multiply;
+  if (identical(">>", string)) return Operator.rightShift;
+  if (identical("-", string)) return Operator.subtract;
+  if (identical("~/", string)) return Operator.truncatingDivide;
+  if (identical("unary-", string)) return Operator.unaryMinus;
+  return null;
+}
+
+String operatorToString(Operator operator) {
+  switch (operator) {
+    case Operator.add: return "+";
+    case Operator.bitwiseAnd: return "&";
+    case Operator.bitwiseNot: return "~";
+    case Operator.bitwiseOr: return "|";
+    case Operator.bitwiseXor: return "^";
+    case Operator.divide: return "/";
+    case Operator.equals: return "==";
+    case Operator.greaterThan: return ">";
+    case Operator.greaterThanEquals: return ">=";
+    case Operator.indexGet: return "[]";
+    case Operator.indexSet: return "[]=";
+    case Operator.leftShift: return "<<";
+    case Operator.lessThan: return "<";
+    case Operator.lessThanEquals: return "<=";
+    case Operator.modulo: return "%";
+    case Operator.multiply: return "*";
+    case Operator.rightShift: return ">>";
+    case Operator.subtract: return "-";
+    case Operator.truncatingDivide: return "~/";
+    case Operator.unaryMinus: return "unary-";
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/outline.dart b/pkg/front_end/lib/src/fasta/outline.dart
new file mode 100644
index 0000000..05cc88f
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/outline.dart
@@ -0,0 +1,137 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.outline;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    exitCode;
+
+import 'package:kernel/verifier.dart' show
+    verifyProgram;
+
+import 'compiler_command_line.dart' show
+    CompilerCommandLine;
+
+import 'errors.dart' show
+    InputError,
+    inputError;
+
+import 'kernel/kernel_target.dart' show
+    KernelTarget;
+
+import 'dill/dill_target.dart' show
+    DillTarget;
+
+import 'ticker.dart' show
+    Ticker;
+
+import 'translate_uri.dart' show
+    TranslateUri;
+
+import 'ast_kind.dart' show
+    AstKind;
+
+// TODO(ahe): Remove this import. Instead make the SDK available as resource in
+// the executable, or something similar.
+import 'testing/kernel_chain.dart' show
+    computePatchedSdk;
+
+CompilerCommandLine parseArguments(String programName, List<String> arguments) {
+  return new CompilerCommandLine(programName, arguments);
+}
+
+Future<KernelTarget> outline(List<String> arguments) async {
+  try {
+    CompilerCommandLine cl = parseArguments("outline", arguments);
+    if (cl.verbose) print("Building outlines for ${arguments.join(' ')}");
+    return await doOutline(cl, new Ticker(isVerbose: cl.verbose), cl.output);
+  } on InputError catch (e) {
+    exitCode = 1;
+    print(e.format());
+    return null;
+  }
+}
+
+Future<Uri> compile(List<String> arguments) async {
+  try {
+    CompilerCommandLine cl = parseArguments("compile", arguments);
+    if (cl.verbose) {
+      print("Compiling directly to Kernel: ${arguments.join(' ')}");
+    }
+    return
+        await doCompile(cl, new Ticker(isVerbose: cl.verbose), AstKind.Kernel);
+  } on InputError catch (e) {
+    exitCode = 1;
+    print(e.format());
+    return null;
+  }
+}
+
+Future<Uri> kompile(List<String> arguments) async {
+  try {
+    CompilerCommandLine cl = parseArguments("kompile", arguments);
+    if (cl.verbose) print("Compiling via analyzer: ${arguments.join(' ')}");
+    return await doCompile(
+        cl, new Ticker(isVerbose: cl.verbose), AstKind.Analyzer);
+  } on InputError catch (e) {
+    exitCode = 1;
+    print(e.format());
+    return null;
+  }
+}
+
+Future<KernelTarget> doOutline(CompilerCommandLine cl, Ticker ticker,
+    [Uri output]) async {
+  Uri sdk = await computePatchedSdk();
+  ticker.logMs("Found patched SDK");
+  TranslateUri uriTranslator = await TranslateUri.parse(sdk);
+  ticker.logMs("Read packages file");
+  DillTarget dillTarget = new DillTarget(ticker, uriTranslator);
+  KernelTarget kernelTarget = new KernelTarget(dillTarget, uriTranslator);
+  Uri platform = cl.platform;
+  if (platform != null) {
+    dillTarget.read(platform);
+  }
+  String argument = cl.arguments.first;
+  Uri uri = Uri.base.resolve(argument);
+  String path = uriTranslator.translate(uri)?.path ?? argument;
+  if (path.endsWith(".dart")) {
+    kernelTarget.read(uri);
+  } else {
+    inputError(uri, -1, "Unexpected input: $uri");
+  }
+  await dillTarget.writeOutline(null);
+  await kernelTarget.writeOutline(output);
+  if (cl.dumpIr && output != null) {
+    kernelTarget.dumpIr();
+  }
+  return kernelTarget;
+}
+
+Future<Uri> doCompile(CompilerCommandLine cl, Ticker ticker,
+    AstKind kind) async {
+  KernelTarget kernelTarget = await doOutline(cl, ticker);
+  if (exitCode != 0) return null;
+  Uri uri = cl.output;
+  await kernelTarget.writeProgram(uri, kind);
+  if (cl.dumpIr) {
+    kernelTarget.dumpIr();
+  }
+  if (cl.verify) {
+    try {
+      verifyProgram(kernelTarget.program);
+      ticker.logMs("Verified program");
+    } catch (e, s) {
+      exitCode = 1;
+      print("Verification of program failed: $e");
+      if (s != null && cl.verbose) {
+        print(s);
+      }
+    }
+  }
+  return uri;
+}
diff --git a/pkg/front_end/lib/src/fasta/parser.dart b/pkg/front_end/lib/src/fasta/parser.dart
new file mode 100644
index 0000000..c70791b
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser.dart
@@ -0,0 +1,41 @@
+// 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.
+
+library fasta.parser;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    Token;
+
+import 'parser/listener.dart' show
+    Listener;
+
+import 'parser/parser.dart' show
+    Parser;
+
+import 'parser/listener.dart' show
+    ParserError;
+
+export 'parser/parser.dart' show
+    Parser,
+    optional;
+
+export 'parser/listener.dart' show
+    Listener,
+    ParserError;
+
+export 'parser/error_kind.dart' show
+    ErrorKind;
+
+export 'parser/top_level_parser.dart' show
+    TopLevelParser;
+
+export 'parser/class_member_parser.dart' show
+    ClassMemberParser;
+
+List<ParserError> parse(Token tokens) {
+  Listener listener = new Listener();
+  Parser parser = new Parser(listener);
+  parser.parseUnit(tokens);
+  return listener.recoverableErrors;
+}
diff --git a/pkg/front_end/lib/src/fasta/parser/bin/parser.dart b/pkg/front_end/lib/src/fasta/parser/bin/parser.dart
new file mode 100644
index 0000000..a20586a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/bin/parser.dart
@@ -0,0 +1,7 @@
+// 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:front_end/src/fasta/parser/main.dart' as dart_parser;
+
+main(List<String> arguments) => dart_parser.main(arguments);
diff --git a/pkg/front_end/lib/src/fasta/parser/class_member_parser.dart b/pkg/front_end/lib/src/fasta/parser/class_member_parser.dart
new file mode 100644
index 0000000..5b7613d
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/class_member_parser.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.parser.class_member_parser;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    Token;
+
+import 'listener.dart' show
+    Listener;
+
+import 'parser.dart' show
+    Parser;
+
+/// Parser similar to [TopLevelParser] but also parses class members (excluding
+/// their bodies).
+class ClassMemberParser extends Parser {
+  ClassMemberParser(Listener listener,
+      {bool asyncAwaitKeywordsEnabled: false})
+      : super(listener, asyncAwaitKeywordsEnabled: asyncAwaitKeywordsEnabled);
+
+  Token parseExpression(Token token) => skipExpression(token);
+
+  // This method is overridden for two reasons:
+  // 1. Avoid generating events for arguments.
+  // 2. Avoid calling skip expression for each argument (which doesn't work).
+  Token parseArgumentsOpt(Token token) => skipArgumentsOpt(token);
+
+  Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
+    return skipFunctionBody(token, isExpression, allowAbstract);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/parser/dart_vm_native.dart b/pkg/front_end/lib/src/fasta/parser/dart_vm_native.dart
new file mode 100644
index 0000000..c1f4d41
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/dart_vm_native.dart
@@ -0,0 +1,60 @@
+// 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.
+
+/// Implements support for Dart VM native method bodies on this form:
+///
+///     native STRING
+///
+/// This support is kept separate from parser.dart as this isn't specified in
+/// the Dart Language Specification, also we hope to remove this syntax long
+/// term and replace it with annotations as in `dart2js`.
+library fasta.parser.dart_vm_native;
+
+import '../scanner/token.dart' show
+    Token;
+
+import '../scanner/token_constants.dart' show
+    STRING_TOKEN;
+
+import '../util/link.dart' show
+    Link;
+
+import 'parser.dart' show
+    optional;
+
+/// When parsing a Dart VM library file, we may encounter a native clause
+/// instead of a function body. This method skips such a clause.
+///
+/// This method is designed to be called when encountering
+/// [ErrorKind.ExpectedBlockToSkip] in [Listener.handleUnrecoverableError].
+Token skipNativeClause(Token token) {
+  if (!optional("native", token)) return null;
+  token = token.next;
+  if (token.kind != STRING_TOKEN) return null;
+  token = token.next;
+  if (!optional(";", token)) return null;
+  return token;
+}
+
+/// When parsing a Dart VM library file, we may encounter native getters like
+///
+///     int get length native "List_getLength";
+///
+/// This will result in [identifiers] being
+///
+///     [";", '"List_getLength"', "native", "length", "get"]
+///
+/// We need to remove '"List_getLength"' and "native" from that list.
+///
+/// This method designed to be called from [Listener.handleMemberName].
+Link<Token> removeNativeClause(Link<Token> identifiers) {
+  Link<Token> result = identifiers.tail;
+  if (result.head.kind != STRING_TOKEN) return identifiers;
+  result = result.tail;
+  if (result.isEmpty) return identifiers;
+  if (optional('native', result.head)) {
+    return result.tail.prepend(identifiers.head);
+  }
+  return identifiers;
+}
diff --git a/pkg/front_end/lib/src/fasta/parser/error_kind.dart b/pkg/front_end/lib/src/fasta/parser/error_kind.dart
new file mode 100644
index 0000000..6ee9eb8
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/error_kind.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.parser.error_kind;
+
+/// Kinds of error codes.
+enum ErrorKind {
+  AsciiControlCharacter,
+  EmptyNamedParameterList,
+  EmptyOptionalParameterList,
+  Encoding,
+  ExpectedBlockToSkip,
+  ExpectedBody,
+  ExpectedButGot,
+  ExpectedClassBody,
+
+  /// This error code can be used to support non-compliant (with respect to
+  /// Dart Language Specification) Dart VM native clauses. See
+  /// [dart_vm_native.dart].
+  ExpectedClassBodyToSkip,
+
+  ExpectedDeclaration,
+  ExpectedExpression,
+  ExpectedFunctionBody,
+  ExpectedHexDigit,
+  ExpectedIdentifier,
+  ExpectedOpenParens,
+  ExpectedString,
+  ExpectedType,
+  ExtraneousModifier,
+  ExtraneousModifierReplace,
+  InvalidAwaitFor,
+  InvalidSyncModifier,
+  InvalidVoid,
+  MissingExponent,
+  NonAsciiIdentifier,
+  NonAsciiWhitespace,
+  PositionalParameterWithEquals,
+  RequiredParameterWithDefault,
+  StackOverflow,
+  UnexpectedDollarInString,
+  UnexpectedToken,
+  UnmatchedToken,
+  UnsupportedPrefixPlus,
+  UnterminatedComment,
+  UnterminatedString,
+  UnterminatedToken,
+
+  Unspecified,
+}
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
new file mode 100644
index 0000000..976f095
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -0,0 +1,828 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.parser.listener;
+
+import '../scanner/token.dart' show
+    BeginGroupToken,
+    Token;
+
+import '../util/link.dart' show
+    Link;
+
+import 'error_kind.dart' show
+    ErrorKind;
+
+/// A parser event listener that does nothing except throw exceptions
+/// on parser errors.
+///
+/// Events are methods that begin with one of: `begin`, `end`, or `handle`.
+///
+/// Events starting with `begin` and `end` come in pairs. Normally, a
+/// `beginFoo` event is followed by an `endFoo` event. There's a few exceptions
+/// documented below.
+///
+/// Events starting with `handle` are used when isn't possible to have a begin
+/// event.
+class Listener {
+  final List<ParserError> recoverableErrors = <ParserError>[];
+
+  void logEvent(String name) {}
+
+  set suppressParseErrors(bool value) {}
+
+  void beginArguments(Token token) {}
+
+  void endArguments(int count, Token beginToken, Token endToken) {
+    logEvent("Arguments");
+  }
+
+  /// Handle async modifiers `async`, `async*`, `sync`.
+  void handleAsyncModifier(Token asyncToken, Token starToken) {
+    logEvent("AsyncModifier");
+  }
+
+  void beginAwaitExpression(Token token) {}
+
+  void endAwaitExpression(Token beginToken, Token endToken) {
+    logEvent("AwaitExpression");
+  }
+
+  void beginBlock(Token token) {}
+
+  void endBlock(int count, Token beginToken, Token endToken) {
+    logEvent("Block");
+  }
+
+  void beginCascade(Token token) {}
+
+  void endCascade() {
+    logEvent("Cascade");
+  }
+
+  void beginClassBody(Token token) {}
+
+  void endClassBody(int memberCount, Token beginToken, Token endToken) {
+    logEvent("ClassBody");
+  }
+
+  void beginClassDeclaration(Token beginToken, Token name) {}
+
+  void endClassDeclaration(int interfacesCount, Token beginToken,
+      Token extendsKeyword, Token implementsKeyword, Token endToken) {
+    logEvent("ClassDeclaration");
+  }
+
+  void beginCombinators(Token token) {}
+
+  void endCombinators(int count) {
+    logEvent("Combinators");
+  }
+
+  void beginCompilationUnit(Token token) {}
+
+  void endCompilationUnit(int count, Token token) {
+    logEvent("CompilationUnit");
+  }
+
+  void beginConstructorReference(Token start) {}
+
+  void endConstructorReference(
+      Token start, Token periodBeforeName, Token endToken) {
+    logEvent("ConstructorReference");
+  }
+
+  void beginDoWhileStatement(Token token) {}
+
+  void endDoWhileStatement(
+      Token doKeyword, Token whileKeyword, Token endToken) {
+    logEvent("DoWhileStatement");
+  }
+
+  void beginDoWhileStatementBody(Token token) {
+  }
+
+  void endDoWhileStatementBody(Token token) {
+    logEvent("DoWhileStatementBody");
+  }
+
+  void beginWhileStatementBody(Token token) {
+  }
+
+  void endWhileStatementBody(Token token) {
+    logEvent("WhileStatementBody");
+  }
+
+  void beginEnum(Token enumKeyword) {}
+
+  void endEnum(Token enumKeyword, Token endBrace, int count) {
+    logEvent("Enum");
+  }
+
+  void beginExport(Token token) {}
+
+  void endExport(Token exportKeyword, Token semicolon) {
+    logEvent("Export");
+  }
+
+  void beginExpression(Token token) {}
+
+  void beginExpressionStatement(Token token) {}
+
+  void endExpressionStatement(Token token) {
+    logEvent("ExpressionStatement");
+  }
+
+  void beginFactoryMethod(Token token) {}
+
+  void endFactoryMethod(Token beginToken, Token endToken) {
+    logEvent("FactoryMethod");
+  }
+
+  void beginFormalParameter(Token token) {}
+
+  void endFormalParameter(Token thisKeyword) {
+    logEvent("FormalParameter");
+  }
+
+  void handleNoFormalParameters(Token token) {
+    logEvent("NoFormalParameters");
+  }
+
+  void beginFormalParameters(Token token) {}
+
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+    logEvent("FormalParameters");
+  }
+
+  /// Doesn't have a corresponding begin event, use [beginMember] instead.
+  void endFields(int count, Token beginToken, Token endToken) {
+    logEvent("Fields");
+  }
+
+  void beginForStatement(Token token) {}
+
+  void endForStatement(
+      int updateExpressionCount, Token beginToken, Token endToken) {
+    logEvent("ForStatement");
+  }
+
+  void beginForStatementBody(Token token) {
+  }
+
+  void endForStatementBody(Token token) {
+    logEvent("ForStatementBody");
+  }
+
+  void endForIn(
+      Token awaitToken, Token forToken, Token inKeyword, Token endToken) {
+    logEvent("ForIn");
+  }
+
+  void beginForInExpression(Token token) {
+  }
+
+  void endForInExpression(Token token) {
+    logEvent("ForInExpression");
+  }
+
+  void beginForInBody(Token token) {
+  }
+
+  void endForInBody(Token token) {
+    logEvent("ForInBody");
+  }
+
+  void beginFunction(Token token) {}
+
+  void endFunction(Token getOrSet, Token endToken) {
+    logEvent("Function");
+  }
+
+  void beginFunctionDeclaration(Token token) {}
+
+  void endFunctionDeclaration(Token token) {
+    logEvent("FunctionDeclaration");
+  }
+
+  void beginFunctionBody(Token token) {}
+
+  void endFunctionBody(int count, Token beginToken, Token endToken) {
+    logEvent("FunctionBody");
+  }
+
+  void handleNoFunctionBody(Token token) {
+    logEvent("NoFunctionBody");
+  }
+
+  void handleFunctionBodySkipped(Token token) {}
+
+  void beginFunctionName(Token token) {}
+
+  void endFunctionName(Token token) {
+    logEvent("FunctionName");
+  }
+
+  void beginFunctionTypeAlias(Token token) {}
+
+  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+    logEvent("FunctionTypeAlias");
+  }
+
+  void beginMixinApplication(Token token) {}
+
+  void endMixinApplication() {
+    logEvent("MixinApplication");
+  }
+
+  void beginNamedMixinApplication(Token beginToken, Token name) {}
+
+  void endNamedMixinApplication(
+      Token begin, Token implementsKeyword, Token endToken) {
+    logEvent("NamedMixinApplication");
+  }
+
+  void beginHide(Token hideKeyword) {}
+
+  void endHide(Token hideKeyword) {
+    logEvent("Hide");
+  }
+
+  void beginIdentifierList(Token token) {}
+
+  void endIdentifierList(int count) {
+    logEvent("IdentifierList");
+  }
+
+  void beginTypeList(Token token) {}
+
+  void endTypeList(int count) {
+    logEvent("TypeList");
+  }
+
+  void beginIfStatement(Token token) {}
+
+  void endIfStatement(Token ifToken, Token elseToken) {
+    logEvent("IfStatement");
+  }
+
+  void beginThenStatement(Token token) {
+  }
+
+  void endThenStatement(Token token) {
+    logEvent("ThenStatement");
+  }
+
+  void beginElseStatement(Token token) {
+  }
+
+  void endElseStatement(Token token) {
+    logEvent("ElseStatement");
+  }
+
+  void beginImport(Token importKeyword) {}
+
+  void endImport(Token importKeyword, Token DeferredKeyword, Token asKeyword,
+      Token semicolon) {
+    logEvent("Import");
+  }
+
+  void beginConditionalUris(Token token) {}
+
+  void endConditionalUris(int count) {
+    logEvent("ConditionalUris");
+  }
+
+  void beginConditionalUri(Token ifKeyword) {}
+
+  void endConditionalUri(Token ifKeyword, Token equalitySign) {
+    logEvent("ConditionalUri");
+  }
+
+  void beginDottedName(Token token) {}
+
+  void endDottedName(int count, Token firstIdentifier) {
+    logEvent("DottedName");
+  }
+
+  void beginInitializedIdentifier(Token token) {}
+
+  void endInitializedIdentifier() {
+    logEvent("InitializedIdentifier");
+  }
+
+  void beginFieldInitializer(Token token) {
+  }
+
+  void endFieldInitializer(Token assignment) {
+    logEvent("FieldInitializer");
+  }
+
+  void handleNoFieldInitializer(Token token) {
+    logEvent("NoFieldInitializer");
+  }
+
+  void beginVariableInitializer(Token token) {}
+
+  void endVariableInitializer(Token assignmentOperator) {
+    logEvent("VariableInitializer");
+  }
+
+  void beginInitializer(Token token) {}
+
+  void endInitializer(Token token) {
+    logEvent("ConstructorInitializer");
+  }
+
+  void beginInitializers(Token token) {}
+
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    logEvent("Initializers");
+  }
+
+  void handleNoInitializers() {
+    logEvent("NoInitializers");
+  }
+
+  /// Called after the listener has recovered from an invalid expression. The
+  /// parser will resume parsing from [token]. Exactly where the parser will
+  /// resume parsing is unspecified.
+  void handleInvalidExpression(Token token) {
+    logEvent("InvalidExpression");
+  }
+
+  /// Called after the listener has recovered from an invalid function
+  /// body. The parser expected an open curly brace `{` and will resume parsing
+  /// from [token] as if a function body had preceeded it.
+  void handleInvalidFunctionBody(Token token) {
+    logEvent("InvalidFunctionBody");
+  }
+
+  /// Called after the listener has recovered from an invalid type. The parser
+  /// expected an identifier, and will resume parsing type arguments from
+  /// [token].
+  void handleInvalidTypeReference(Token token) {
+    logEvent("InvalidTypeReference");
+  }
+
+  void handleLabel(Token token) {
+    logEvent("Label");
+  }
+
+  void beginLabeledStatement(Token token, int labelCount) {}
+
+  void endLabeledStatement(int labelCount) {
+    logEvent("LabeledStatement");
+  }
+
+  void beginLibraryName(Token token) {}
+
+  void endLibraryName(Token libraryKeyword, Token semicolon) {
+    logEvent("LibraryName");
+  }
+
+  void beginLiteralMapEntry(Token token) {}
+
+  void endLiteralMapEntry(Token colon, Token endToken) {
+    logEvent("LiteralMapEntry");
+  }
+
+  void beginLiteralString(Token token) {}
+
+  void endLiteralString(int interpolationCount) {
+    logEvent("LiteralString");
+  }
+
+  void handleStringJuxtaposition(int literalCount) {
+    logEvent("StringJuxtaposition");
+  }
+
+  void beginMember(Token token) {}
+
+  /// This event is added for convenience. Normally, one should override
+  /// [endMethod] or [endFields] instead.
+  void endMember() {
+    logEvent("Member");
+  }
+
+  /// This event can be used to support non-compliant (with respect to Dart
+  /// Language Specification) Dart VM native clauses. See
+  /// [dart_vm_native.dart].
+  Link<Token> handleMemberName(Link<Token> identifiers) => identifiers;
+
+  void beginMethod(Token token, Token name) {}
+
+  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+    logEvent("Method");
+  }
+
+  void beginMetadataStar(Token token) {}
+
+  void endMetadataStar(int count, bool forParameter) {
+    logEvent("MetadataStar");
+  }
+
+  void beginMetadata(Token token) {}
+
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    logEvent("Metadata");
+  }
+
+  void beginOptionalFormalParameters(Token token) {}
+
+  void endOptionalFormalParameters(
+      int count, Token beginToken, Token endToken) {
+    logEvent("OptionalFormalParameters");
+  }
+
+  void beginPart(Token token) {}
+
+  void endPart(Token partKeyword, Token semicolon) {
+    logEvent("Part");
+  }
+
+  void beginPartOf(Token token) {}
+
+  void endPartOf(Token partKeyword, Token semicolon) {
+    logEvent("PartOf");
+  }
+
+  void beginRedirectingFactoryBody(Token token) {}
+
+  void endRedirectingFactoryBody(Token beginToken, Token endToken) {
+    logEvent("RedirectingFactoryBody");
+  }
+
+  void beginReturnStatement(Token token) {}
+
+  void endReturnStatement(
+      bool hasExpression, Token beginToken, Token endToken) {
+    logEvent("ReturnStatement");
+  }
+
+  void beginSend(Token token) {}
+
+  void endSend(Token token) {
+    logEvent("Send");
+  }
+
+  void beginShow(Token showKeyword) {}
+
+  void endShow(Token showKeyword) {
+    logEvent("Show");
+  }
+
+  void beginSwitchStatement(Token token) {}
+
+  void endSwitchStatement(Token switchKeyword, Token endToken) {
+    logEvent("SwitchStatement");
+  }
+
+  void beginSwitchBlock(Token token) {}
+
+  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
+    logEvent("SwitchBlock");
+  }
+
+  void beginLiteralSymbol(Token token) {}
+
+  void endLiteralSymbol(Token hashToken, int identifierCount) {
+    logEvent("LiteralSymbol");
+  }
+
+  void beginThrowExpression(Token token) {}
+
+  void endThrowExpression(Token throwToken, Token endToken) {
+    logEvent("ThrowExpression");
+  }
+
+  void beginRethrowStatement(Token token) {}
+
+  void endRethrowStatement(Token throwToken, Token endToken) {
+    logEvent("RethrowStatement");
+  }
+
+  /// This event is added for convenience. Normally, one should use
+  /// [endClassDeclaration], [endNamedMixinApplication], [endEnum],
+  /// [endFunctionTypeAlias], [endLibraryName], [endImport], [endExport],
+  /// [endPart], [endPartOf], [endTopLevelFields], or [endTopLevelMethod].
+  void endTopLevelDeclaration(Token token) {
+    logEvent("TopLevelDeclaration");
+  }
+
+  void beginTopLevelMember(Token token) {}
+
+  /// Doesn't have a corresponding begin event, use [beginTopLevelMember]
+  /// instead.
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+    logEvent("TopLevelFields");
+  }
+
+  void beginTopLevelMethod(Token token, Token name) {}
+
+  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+    logEvent("TopLevelMethod");
+  }
+
+  void beginTryStatement(Token token) {}
+
+  void handleCaseMatch(Token caseKeyword, Token colon) {
+    logEvent("CaseMatch");
+  }
+
+  void beginCatchClause(Token token) {
+  }
+
+  void endCatchClause(Token token) {
+    logEvent("CatchClause");
+  }
+
+  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+    logEvent("CatchBlock");
+  }
+
+  void handleFinallyBlock(Token finallyKeyword) {
+    logEvent("FinallyBlock");
+  }
+
+  void endTryStatement(
+      int catchCount, Token tryKeyword, Token finallyKeyword) {
+    logEvent("TryStatement");
+  }
+
+  void endType(Token beginToken, Token endToken) {
+    logEvent("Type");
+  }
+
+  void beginTypeArguments(Token token) {}
+
+  void endTypeArguments(int count, Token beginToken, Token endToken) {
+    logEvent("TypeArguments");
+  }
+
+  void handleNoTypeArguments(Token token) {
+    logEvent("NoTypeArguments");
+  }
+
+  void beginTypeVariable(Token token) {}
+
+  void endTypeVariable(Token token, Token extendsOrSuper) {
+    logEvent("TypeVariable");
+  }
+
+  void beginTypeVariables(Token token) {}
+
+  void endTypeVariables(int count, Token beginToken, Token endToken) {
+    logEvent("TypeVariables");
+  }
+
+  void beginUnnamedFunction(Token token) {}
+
+  void endUnnamedFunction(Token token) {
+    logEvent("UnnamedFunction");
+  }
+
+  void beginVariablesDeclaration(Token token) {}
+
+  void endVariablesDeclaration(int count, Token endToken) {
+    logEvent("VariablesDeclaration");
+  }
+
+  void beginWhileStatement(Token token) {}
+
+  void endWhileStatement(Token whileKeyword, Token endToken) {
+    logEvent("WhileStatement");
+  }
+
+  void handleAsOperator(Token operator, Token endToken) {
+    logEvent("AsOperator");
+  }
+
+  void handleAssignmentExpression(Token token) {
+    logEvent("AssignmentExpression");
+  }
+
+  void handleBinaryExpression(Token token) {
+    logEvent("BinaryExpression");
+  }
+
+  void handleConditionalExpression(Token question, Token colon) {
+    logEvent("ConditionalExpression");
+  }
+
+  void handleConstExpression(Token token) {
+    logEvent("ConstExpression");
+  }
+
+  void beginFunctionTypedFormalParameter(Token token) {
+  }
+
+  void endFunctionTypedFormalParameter(Token token) {
+    logEvent("FunctionTypedFormalParameter");
+  }
+
+  void handleIdentifier(Token token) {
+    logEvent("Identifier");
+  }
+
+  void handleIndexedExpression(
+      Token openCurlyBracket, Token closeCurlyBracket) {
+    logEvent("IndexedExpression");
+  }
+
+  void handleIsOperator(Token operator, Token not, Token endToken) {
+    logEvent("IsOperator");
+  }
+
+  void handleLiteralBool(Token token) {
+    logEvent("LiteralBool");
+  }
+
+  void handleBreakStatement(
+      bool hasTarget, Token breakKeyword, Token endToken) {
+    logEvent("BreakStatement");
+  }
+
+  void handleContinueStatement(
+      bool hasTarget, Token continueKeyword, Token endToken) {
+    logEvent("ContinueStatement");
+  }
+
+  void handleEmptyStatement(Token token) {
+    logEvent("EmptyStatement");
+  }
+
+  void handleAssertStatement(
+      Token assertKeyword, Token commaToken, Token semicolonToken) {
+    logEvent("AssertStatement");
+  }
+
+  /** Called with either the token containing a double literal, or
+    * an immediately preceding "unary plus" token.
+    */
+  void handleLiteralDouble(Token token) {
+    logEvent("LiteralDouble");
+  }
+
+  /** Called with either the token containing an integer literal,
+    * or an immediately preceding "unary plus" token.
+    */
+  void handleLiteralInt(Token token) {
+    logEvent("LiteralInt");
+  }
+
+  void handleLiteralList(
+      int count, Token beginToken, Token constKeyword, Token endToken) {
+    logEvent("LiteralList");
+  }
+
+  void handleLiteralMap(
+      int count, Token beginToken, Token constKeyword, Token endToken) {
+    logEvent("LiteralMap");
+  }
+
+  void handleLiteralNull(Token token) {
+    logEvent("LiteralNull");
+  }
+
+  void handleModifier(Token token) {
+    logEvent("Modifier");
+  }
+
+  void handleModifiers(int count) {
+    logEvent("Modifiers");
+  }
+
+  void handleNamedArgument(Token colon) {
+    logEvent("NamedArgument");
+  }
+
+  void handleNewExpression(Token token) {
+    logEvent("NewExpression");
+  }
+
+  void handleNoArguments(Token token) {
+    logEvent("NoArguments");
+  }
+
+  void handleNoExpression(Token token) {
+    logEvent("NoExpression");
+  }
+
+  void handleNoType(Token token) {
+    logEvent("NoType");
+  }
+
+  void handleNoTypeVariables(Token token) {
+    logEvent("NoTypeVariables");
+  }
+
+  void handleOperator(Token token) {
+    logEvent("Operator");
+  }
+
+  void handleOperatorName(Token operatorKeyword, Token token) {
+    logEvent("OperatorName");
+  }
+
+  void handleParenthesizedExpression(BeginGroupToken token) {
+    logEvent("ParenthesizedExpression");
+  }
+
+  void handleQualified(Token period) {
+    logEvent("Qualified");
+  }
+
+  void handleStringPart(Token token) {
+    logEvent("StringPart");
+  }
+
+  void handleSuperExpression(Token token) {
+    logEvent("SuperExpression");
+  }
+
+  void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) {
+  }
+
+  void handleSwitchCase(
+      int labelCount,
+      int expressionCount,
+      Token defaultKeyword,
+      int statementCount,
+      Token firstToken,
+      Token endToken) {
+    logEvent("SwitchCase");
+  }
+
+  void handleThisExpression(Token token) {
+    logEvent("ThisExpression");
+  }
+
+  void handleUnaryPostfixAssignmentExpression(Token token) {
+    logEvent("UnaryPostfixAssignmentExpression");
+  }
+
+  void handleUnaryPrefixExpression(Token token) {
+    logEvent("UnaryPrefixExpression");
+  }
+
+  void handleUnaryPrefixAssignmentExpression(Token token) {
+    logEvent("UnaryPrefixAssignmentExpression");
+  }
+
+  void handleValuedFormalParameter(Token equals, Token token) {
+    logEvent("ValuedFormalParameter");
+  }
+
+  void handleVoidKeyword(Token token) {
+    logEvent("VoidKeyword");
+  }
+
+  void beginYieldStatement(Token token) {}
+
+  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+    logEvent("YieldStatement");
+  }
+
+  /// An unrecoverable error is an error that the parser can't recover from
+  /// itself, and recovery is left to the listener. If the listener can
+  /// recover, it should return a non-null continuation token. Error recovery
+  /// is tightly coupled to the parser implementation, so to recover from an
+  /// error, one must carefully examine the code in the parser that generates
+  /// the error.
+  ///
+  /// If the listener can't recover, it can throw an exception or return
+  /// `null`. In the latter case, the parser simply skips to EOF which will
+  /// often result in additional parser errors as the parser returns from its
+  /// recursive state.
+  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+    throw new ParserError.fromTokens(token, token, kind, arguments);
+  }
+
+  /// The parser noticed a syntax error, but was able to recover from it.
+  void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
+    recoverableErrors.add(
+        new ParserError.fromTokens(token, token, kind, arguments));
+  }
+}
+
+class ParserError {
+  /// Character offset from the beginning of file where this error starts.
+  final int beginOffset;
+
+  /// Character offset from the beginning of file where this error ends.
+  final int endOffset;
+
+  final ErrorKind kind;
+
+  final Map arguments;
+
+  ParserError(this.beginOffset, this.endOffset, this.kind, this.arguments);
+
+  ParserError.fromTokens(Token begin, Token end, ErrorKind kind, Map arguments)
+      : this(begin.charOffset, end.charOffset + end.charCount, kind,
+          arguments);
+
+  String toString() => "@${beginOffset}: $kind $arguments";
+}
diff --git a/pkg/front_end/lib/src/fasta/parser/main.dart b/pkg/front_end/lib/src/fasta/parser/main.dart
new file mode 100644
index 0000000..6937a25
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/main.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.parser.main;
+
+import 'dart:convert' show
+    LineSplitter,
+    UTF8;
+
+import 'dart:io' show
+    File;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    Token;
+
+import 'package:front_end/src/fasta/scanner/io.dart' show
+    readBytesFromFileSync;
+
+import 'package:front_end/src/fasta/scanner.dart' show
+    scan;
+
+import 'listener.dart' show
+    Listener;
+
+import 'top_level_parser.dart' show
+    TopLevelParser;
+
+class DebugListener extends Listener {
+  void handleIdentifier(Token token) {
+    logEvent("Identifier: ${token.value}");
+  }
+
+  void logEvent(String name) {
+    print(name);
+  }
+}
+
+main(List<String> arguments) async {
+  for (String argument in arguments) {
+    if (argument.startsWith("@")) {
+      Uri uri = Uri.base.resolve(argument.substring(1));
+      await for (String file in new File.fromUri(uri).openRead()
+                     .transform(UTF8.decoder)
+                     .transform(const LineSplitter())) {
+        outLine(uri.resolve(file));
+      }
+    } else {
+      outLine(Uri.base.resolve(argument));
+    }
+  }
+}
+
+void outLine(Uri uri) {
+  new TopLevelParser(new DebugListener()).parseUnit(
+      scan(readBytesFromFileSync(uri)).tokens);
+}
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
new file mode 100644
index 0000000..4073af5
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -0,0 +1,3322 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.parser.parser;
+
+import '../scanner.dart' show
+    ErrorToken;
+
+import '../scanner/recover.dart' show
+    closeBraceFor,
+    skipToEof;
+
+import 'package:front_end/src/fasta/scanner/keyword.dart' show
+    Keyword;
+
+import 'package:front_end/src/fasta/scanner/precedence.dart' show
+    ASSIGNMENT_PRECEDENCE,
+    AS_INFO,
+    CASCADE_PRECEDENCE,
+    EQUALITY_PRECEDENCE,
+    GT_INFO,
+    IS_INFO,
+    MINUS_MINUS_INFO,
+    OPEN_PAREN_INFO,
+    OPEN_SQUARE_BRACKET_INFO,
+    PERIOD_INFO,
+    PLUS_PLUS_INFO,
+    POSTFIX_PRECEDENCE,
+    PrecedenceInfo,
+    QUESTION_INFO,
+    QUESTION_PERIOD_INFO,
+    RELATIONAL_PRECEDENCE;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    BeginGroupToken,
+    KeywordToken,
+    SymbolToken,
+    Token,
+    isUserDefinableOperator;
+
+import 'package:front_end/src/fasta/scanner/token_constants.dart' show
+    COMMA_TOKEN,
+    DOUBLE_TOKEN,
+    EOF_TOKEN,
+    EQ_TOKEN,
+    FUNCTION_TOKEN,
+    GT_TOKEN,
+    GT_GT_TOKEN,
+    HASH_TOKEN,
+    HEXADECIMAL_TOKEN,
+    IDENTIFIER_TOKEN,
+    INT_TOKEN,
+    KEYWORD_TOKEN,
+    LT_TOKEN,
+    OPEN_CURLY_BRACKET_TOKEN,
+    OPEN_PAREN_TOKEN,
+    OPEN_SQUARE_BRACKET_TOKEN,
+    PERIOD_TOKEN,
+    SEMICOLON_TOKEN,
+    STRING_INTERPOLATION_IDENTIFIER_TOKEN,
+    STRING_INTERPOLATION_TOKEN,
+    STRING_TOKEN;
+
+import 'package:front_end/src/fasta/scanner/characters.dart' show
+    $CLOSE_CURLY_BRACKET;
+
+import 'package:front_end/src/fasta/util/link.dart' show
+    Link;
+
+import 'listener.dart' show
+    Listener;
+
+import 'error_kind.dart' show
+    ErrorKind;
+
+/// Returns true if [token] is the symbol or keyword [value].
+bool optional(String value, Token token) {
+  return identical(value, token.stringValue);
+}
+
+class FormalParameterType {
+  final String type;
+  const FormalParameterType(this.type);
+  bool get isRequired => this == REQUIRED;
+  bool get isPositional => this == POSITIONAL;
+  bool get isNamed => this == NAMED;
+  static final REQUIRED = const FormalParameterType('required');
+  static final POSITIONAL = const FormalParameterType('positional');
+  static final NAMED = const FormalParameterType('named');
+}
+
+/**
+ * An event generating parser of Dart programs. This parser expects
+ * all tokens in a linked list (aka a token stream).
+ *
+ * The class [Scanner] is used to generate a token stream. See the
+ * file scanner.dart.
+ *
+ * Subclasses of the class [Listener] are used to listen to events.
+ *
+ * Most methods of this class belong in one of two major categories:
+ * parse metods and peek methods. Parse methods all have the prefix
+ * parse, and peek methods all have the prefix peek.
+ *
+ * Parse methods generate events (by calling methods on [listener])
+ * and return the next token to parse. Peek methods do not generate
+ * events (except for errors) and may return null.
+ *
+ * Parse methods are generally named parseGrammarProductionSuffix. The
+ * suffix can be one of "opt", or "star". "opt" means zero or one
+ * matches, "star" means zero or more matches. For example,
+ * [parseMetadataStar] corresponds to this grammar snippet: [:
+ * metadata* :], and [parseTypeOpt] corresponds to: [: type? :].
+ */
+class Parser {
+  final Listener listener;
+
+  bool mayParseFunctionExpressions = true;
+
+  bool asyncAwaitKeywordsEnabled;
+
+  Parser(this.listener, {this.asyncAwaitKeywordsEnabled: false});
+
+  Token parseUnit(Token token) {
+    listener.beginCompilationUnit(token);
+    int count = 0;
+    while (!identical(token.kind, EOF_TOKEN)) {
+      token = parseTopLevelDeclaration(token);
+      count++;
+    }
+    listener.endCompilationUnit(count, token);
+    return token;
+  }
+
+  Token parseTopLevelDeclaration(Token token) {
+    token = _parseTopLevelDeclaration(token);
+    listener.endTopLevelDeclaration(token);
+    return token;
+  }
+
+  Token _parseTopLevelDeclaration(Token token) {
+    token = parseMetadataStar(token);
+    final String value = token.stringValue;
+    if ((identical(value, 'abstract') && optional('class', token.next)) ||
+        identical(value, 'class')) {
+      return parseClassOrNamedMixinApplication(token);
+    } else if (identical(value, 'enum')) {
+      return parseEnum(token);
+    } else if (identical(value, 'typedef')) {
+      return parseTypedef(token);
+    } else if (identical(value, 'library')) {
+      return parseLibraryName(token);
+    } else if (identical(value, 'import')) {
+      return parseImport(token);
+    } else if (identical(value, 'export')) {
+      return parseExport(token);
+    } else if (identical(value, 'part')) {
+      return parsePartOrPartOf(token);
+    } else {
+      return parseTopLevelMember(token);
+    }
+  }
+
+  /// library qualified ';'
+  Token parseLibraryName(Token token) {
+    Token libraryKeyword = token;
+    listener.beginLibraryName(libraryKeyword);
+    assert(optional('library', token));
+    token = parseQualified(token.next);
+    Token semicolon = token;
+    token = expect(';', token);
+    listener.endLibraryName(libraryKeyword, semicolon);
+    return token;
+  }
+
+  /// import uri (if (test) uri)* (as identifier)? combinator* ';'
+  Token parseImport(Token token) {
+    Token importKeyword = token;
+    listener.beginImport(importKeyword);
+    assert(optional('import', token));
+    token = parseLiteralStringOrRecoverExpression(token.next);
+    token = parseConditionalUris(token);
+    Token deferredKeyword;
+    if (optional('deferred', token)) {
+      deferredKeyword = token;
+      token = token.next;
+    }
+    Token asKeyword;
+    if (optional('as', token)) {
+      asKeyword = token;
+      token = parseIdentifier(token.next);
+    }
+    token = parseCombinators(token);
+    Token semicolon = token;
+    token = expect(';', token);
+    listener.endImport(importKeyword, deferredKeyword, asKeyword, semicolon);
+    return token;
+  }
+
+  /// if (test) uri
+  Token parseConditionalUris(Token token) {
+    listener.beginConditionalUris(token);
+    int count = 0;
+    while (optional('if', token)) {
+      count++;
+      token = parseConditionalUri(token);
+    }
+    listener.endConditionalUris(count);
+    return token;
+  }
+
+  Token parseConditionalUri(Token token) {
+    listener.beginConditionalUri(token);
+    Token ifKeyword = token;
+    token = expect('if', token);
+    token = expect('(', token);
+    token = parseDottedName(token);
+    Token equalitySign;
+    if (optional('==', token)) {
+      equalitySign = token;
+      token = parseLiteralStringOrRecoverExpression(token.next);
+    }
+    token = expect(')', token);
+    token = parseLiteralStringOrRecoverExpression(token);
+    listener.endConditionalUri(ifKeyword, equalitySign);
+    return token;
+  }
+
+  Token parseDottedName(Token token) {
+    listener.beginDottedName(token);
+    Token firstIdentifier = token;
+    token = parseIdentifier(token);
+    int count = 1;
+    while (optional('.', token)) {
+      token = parseIdentifier(token.next);
+      count++;
+    }
+    listener.endDottedName(count, firstIdentifier);
+    return token;
+  }
+
+  /// export uri conditional-uris* combinator* ';'
+  Token parseExport(Token token) {
+    Token exportKeyword = token;
+    listener.beginExport(exportKeyword);
+    assert(optional('export', token));
+    token = parseLiteralStringOrRecoverExpression(token.next);
+    token = parseConditionalUris(token);
+    token = parseCombinators(token);
+    Token semicolon = token;
+    token = expect(';', token);
+    listener.endExport(exportKeyword, semicolon);
+    return token;
+  }
+
+  Token parseCombinators(Token token) {
+    listener.beginCombinators(token);
+    int count = 0;
+    while (true) {
+      String value = token.stringValue;
+      if (identical('hide', value)) {
+        token = parseHide(token);
+      } else if (identical('show', value)) {
+        token = parseShow(token);
+      } else {
+        listener.endCombinators(count);
+        break;
+      }
+      count++;
+    }
+    return token;
+  }
+
+  /// hide identifierList
+  Token parseHide(Token token) {
+    Token hideKeyword = token;
+    listener.beginHide(hideKeyword);
+    assert(optional('hide', token));
+    token = parseIdentifierList(token.next);
+    listener.endHide(hideKeyword);
+    return token;
+  }
+
+  /// show identifierList
+  Token parseShow(Token token) {
+    Token showKeyword = token;
+    listener.beginShow(showKeyword);
+    assert(optional('show', token));
+    token = parseIdentifierList(token.next);
+    listener.endShow(showKeyword);
+    return token;
+  }
+
+  /// identifier (, identifier)*
+  Token parseIdentifierList(Token token) {
+    listener.beginIdentifierList(token);
+    token = parseIdentifier(token);
+    int count = 1;
+    while (optional(',', token)) {
+      token = parseIdentifier(token.next);
+      count++;
+    }
+    listener.endIdentifierList(count);
+    return token;
+  }
+
+  /// type (, type)*
+  Token parseTypeList(Token token) {
+    listener.beginTypeList(token);
+    token = parseType(token);
+    int count = 1;
+    while (optional(',', token)) {
+      token = parseType(token.next);
+      count++;
+    }
+    listener.endTypeList(count);
+    return token;
+  }
+
+  Token parsePartOrPartOf(Token token) {
+    assert(optional('part', token));
+    if (optional('of', token.next)) {
+      return parsePartOf(token);
+    } else {
+      return parsePart(token);
+    }
+  }
+
+  Token parsePart(Token token) {
+    Token partKeyword = token;
+    listener.beginPart(token);
+    assert(optional('part', token));
+    token = parseLiteralStringOrRecoverExpression(token.next);
+    Token semicolon = token;
+    token = expect(';', token);
+    listener.endPart(partKeyword, semicolon);
+    return token;
+  }
+
+  Token parsePartOf(Token token) {
+    listener.beginPartOf(token);
+    assert(optional('part', token));
+    assert(optional('of', token.next));
+    Token partKeyword = token;
+    token = parseQualified(token.next.next);
+    Token semicolon = token;
+    token = expect(';', token);
+    listener.endPartOf(partKeyword, semicolon);
+    return token;
+  }
+
+  Token parseMetadataStar(Token token, {bool forParameter: false}) {
+    listener.beginMetadataStar(token);
+    int count = 0;
+    while (optional('@', token)) {
+      token = parseMetadata(token);
+      count++;
+    }
+    listener.endMetadataStar(count, forParameter);
+    return token;
+  }
+
+  /**
+   * Parse
+   * [: '@' qualified (‘.’ identifier)? (arguments)? :]
+   */
+  Token parseMetadata(Token token) {
+    listener.beginMetadata(token);
+    Token atToken = token;
+    assert(optional('@', token));
+    token = parseIdentifier(token.next);
+    token = parseQualifiedRestOpt(token);
+    token = parseTypeArgumentsOpt(token);
+    Token period = null;
+    if (optional('.', token)) {
+      period = token;
+      token = parseIdentifier(token.next);
+    }
+    token = parseArgumentsOpt(token);
+    listener.endMetadata(atToken, period, token);
+    return token;
+  }
+
+  Token parseTypedef(Token token) {
+    Token typedefKeyword = token;
+    listener.beginFunctionTypeAlias(token);
+    token = parseReturnTypeOpt(token.next);
+    token = parseIdentifier(token);
+    token = parseTypeVariablesOpt(token);
+    token = parseFormalParameters(token);
+    listener.endFunctionTypeAlias(typedefKeyword, token);
+    return expect(';', token);
+  }
+
+  Token parseMixinApplication(Token token) {
+    listener.beginMixinApplication(token);
+    token = parseType(token);
+    token = expect('with', token);
+    token = parseTypeList(token);
+    listener.endMixinApplication();
+    return token;
+  }
+
+  Token parseReturnTypeOpt(Token token) {
+    if (identical(token.stringValue, 'void')) {
+      listener.handleVoidKeyword(token);
+      return token.next;
+    } else {
+      return parseTypeOpt(token);
+    }
+  }
+
+  Token parseFormalParametersOpt(Token token) {
+    if (optional('(', token)) {
+      return parseFormalParameters(token);
+    } else {
+      listener.handleNoFormalParameters(token);
+      return token;
+    }
+  }
+
+  Token skipFormalParameters(Token token) {
+    // TODO(ahe): Shouldn't this be `beginFormalParameters`?
+    listener.beginOptionalFormalParameters(token);
+    if (!optional('(', token)) {
+      if (optional(';', token)) {
+        reportRecoverableError(token, ErrorKind.ExpectedOpenParens);
+        return token;
+      }
+      return reportUnrecoverableError(
+          token, ErrorKind.ExpectedButGot, {"expected": "("});
+    }
+    BeginGroupToken beginGroupToken = token;
+    Token endToken = beginGroupToken.endGroup;
+    listener.endFormalParameters(0, token, endToken);
+    return endToken.next;
+  }
+
+  Token parseFormalParameters(Token token) {
+    Token begin = token;
+    listener.beginFormalParameters(begin);
+    expect('(', token);
+    int parameterCount = 0;
+    do {
+      token = token.next;
+      if (optional(')', token)) {
+        break;
+      }
+      ++parameterCount;
+      String value = token.stringValue;
+      if (identical(value, '[')) {
+        token = parseOptionalFormalParameters(token, false);
+        break;
+      } else if (identical(value, '{')) {
+        token = parseOptionalFormalParameters(token, true);
+        break;
+      }
+      token = parseFormalParameter(token, FormalParameterType.REQUIRED);
+    } while (optional(',', token));
+    listener.endFormalParameters(parameterCount, begin, token);
+    return expect(')', token);
+  }
+
+  Token parseFormalParameter(Token token, FormalParameterType type) {
+    token = parseMetadataStar(token, forParameter: true);
+    listener.beginFormalParameter(token);
+
+    // Skip over `covariant` token, if the next token is an identifier or
+    // modifier.
+    // This enables the case where `covariant` is the name of the parameter:
+    //    void foo(covariant);
+    if (identical(token.stringValue, 'covariant') &&
+        (token.next.isIdentifier() || isModifier(token.next))) {
+      token = token.next;
+    }
+    token = parseModifiers(token);
+    // TODO(ahe): Validate that there are formal parameters if void.
+    token = parseReturnTypeOpt(token);
+    Token thisKeyword = null;
+    if (optional('this', token)) {
+      thisKeyword = token;
+      // TODO(ahe): Validate field initializers are only used in
+      // constructors, and not for function-typed arguments.
+      token = expect('.', token.next);
+    }
+    token = parseIdentifier(token);
+    if (optional('(', token)) {
+      listener.beginFunctionTypedFormalParameter(token);
+      listener.handleNoTypeVariables(token);
+      token = parseFormalParameters(token);
+      listener.endFunctionTypedFormalParameter(token);
+    } else if (optional('<', token)) {
+      listener.beginFunctionTypedFormalParameter(token);
+      token = parseTypeVariablesOpt(token);
+      token = parseFormalParameters(token);
+      listener.endFunctionTypedFormalParameter(token);
+    }
+    String value = token.stringValue;
+    if ((identical('=', value)) || (identical(':', value))) {
+      // TODO(ahe): Validate that these are only used for optional parameters.
+      Token equal = token;
+      token = parseExpression(token.next);
+      listener.handleValuedFormalParameter(equal, token);
+      if (type.isRequired) {
+        reportRecoverableError(
+            equal, ErrorKind.RequiredParameterWithDefault);
+      } else if (type.isPositional && identical(':', value)) {
+        reportRecoverableError(
+            equal, ErrorKind.PositionalParameterWithEquals);
+      }
+    }
+    listener.endFormalParameter(thisKeyword);
+    return token;
+  }
+
+  Token parseOptionalFormalParameters(Token token, bool isNamed) {
+    Token begin = token;
+    listener.beginOptionalFormalParameters(begin);
+    assert((isNamed && optional('{', token)) || optional('[', token));
+    int parameterCount = 0;
+    do {
+      token = token.next;
+      if (isNamed && optional('}', token)) {
+        break;
+      } else if (!isNamed && optional(']', token)) {
+        break;
+      }
+      var type =
+          isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
+      token = parseFormalParameter(token, type);
+      ++parameterCount;
+    } while (optional(',', token));
+    if (parameterCount == 0) {
+      reportRecoverableError(
+          token,
+          isNamed
+              ? ErrorKind.EmptyNamedParameterList
+              : ErrorKind.EmptyOptionalParameterList);
+    }
+    listener.endOptionalFormalParameters(parameterCount, begin, token);
+    if (isNamed) {
+      return expect('}', token);
+    } else {
+      return expect(']', token);
+    }
+  }
+
+  Token parseTypeOpt(Token token) {
+    Token peek = peekAfterIfType(token);
+    if (peek != null && (peek.isIdentifier() || optional('this', peek))) {
+      return parseType(token);
+    }
+    listener.handleNoType(token);
+    return token;
+  }
+
+  bool isValidTypeReference(Token token) {
+    final kind = token.kind;
+    if (identical(kind, IDENTIFIER_TOKEN)) return true;
+    if (identical(kind, KEYWORD_TOKEN)) {
+      Keyword keyword = (token as KeywordToken).keyword;
+      String value = keyword.syntax;
+      return keyword.isPseudo ||
+          (identical(value, 'dynamic')) ||
+          (identical(value, 'void'));
+    }
+    return false;
+  }
+
+  /// Returns true if [token] matches '<' type (',' type)* '>' '(', and
+  /// otherwise returns false. The final '(' is not part of the grammar
+  /// construct `typeArguments`, but it is required here such that type
+  /// arguments in generic method invocations can be recognized, and as few as
+  /// possible other constructs will pass (e.g., 'a < C, D > 3').
+  bool isValidMethodTypeArguments(Token token) {
+    return tryParseMethodTypeArguments(token) != null;
+  }
+
+  /// Returns token after match if [token] matches '<' type (',' type)* '>' '(',
+  /// and otherwise returns null. Does not produce listener events. With respect
+  /// to the final '(', please see the description of
+  /// [isValidMethodTypeArguments].
+  Token tryParseMethodTypeArguments(Token token) {
+    if (!identical(token.kind, LT_TOKEN)) return null;
+    BeginGroupToken beginToken = token;
+    Token endToken = beginToken.endGroup;
+    if (endToken == null || !identical(endToken.next.kind, OPEN_PAREN_TOKEN)) {
+      return null;
+    }
+    token = tryParseType(token.next);
+    while (token != null && identical(token.kind, COMMA_TOKEN)) {
+      token = tryParseType(token.next);
+    }
+    if (token == null || !identical(token.kind, GT_TOKEN)) return null;
+    return token.next;
+  }
+
+  /// Returns token after match if [token] matches typeName typeArguments?, and
+  /// otherwise returns null. Does not produce listener events.
+  Token tryParseType(Token token) {
+    token = tryParseQualified(token);
+    if (token == null) return null;
+    Token tokenAfterQualified = token;
+    token = tryParseNestedTypeArguments(token);
+    return token == null ? tokenAfterQualified : token;
+  }
+
+  /// Returns token after match if [token] matches identifier ('.' identifier)?,
+  /// and otherwise returns null. Does not produce listener events.
+  Token tryParseQualified(Token token) {
+    if (!isValidTypeReference(token)) return null;
+    token = token.next;
+    if (!identical(token.kind, PERIOD_TOKEN)) return token;
+    token = token.next;
+    if (!identical(token.kind, IDENTIFIER_TOKEN)) return null;
+    return token.next;
+  }
+
+  /// Returns token after match if [token] matches '<' type (',' type)* '>',
+  /// and otherwise returns null. Does not produce listener events. The final
+  /// '>' may be the first character in a '>>' token, in which case a synthetic
+  /// '>' token is created and returned, representing the second '>' in the
+  /// '>>' token.
+  Token tryParseNestedTypeArguments(Token token) {
+    if (!identical(token.kind, LT_TOKEN)) return null;
+    // If the initial '<' matches the first '>' in a '>>' token, we will have
+    // `token.endGroup == null`, so we cannot rely on `token.endGroup == null`
+    // to imply that the match must fail. Hence no `token.endGroup == null`
+    // test here.
+    token = tryParseType(token.next);
+    while (token != null && identical(token.kind, COMMA_TOKEN)) {
+      token = tryParseType(token.next);
+    }
+    if (token == null) return null;
+    if (identical(token.kind, GT_TOKEN)) return token.next;
+    if (!identical(token.kind, GT_GT_TOKEN)) return null;
+    // [token] is '>>' of which the final '>' that we are parsing is the first
+    // character. In order to keep the parsing process on track we must return
+    // a synthetic '>' corresponding to the second character of that '>>'.
+    Token syntheticToken = new SymbolToken(GT_INFO, token.charOffset + 1);
+    syntheticToken.next = token.next;
+    return syntheticToken;
+  }
+
+  Token parseQualified(Token token) {
+    token = parseIdentifier(token);
+    while (optional('.', token)) {
+      token = parseQualifiedRest(token);
+    }
+    return token;
+  }
+
+  Token parseQualifiedRestOpt(Token token) {
+    if (optional('.', token)) {
+      return parseQualifiedRest(token);
+    } else {
+      return token;
+    }
+  }
+
+  Token parseQualifiedRest(Token token) {
+    assert(optional('.', token));
+    Token period = token;
+    token = parseIdentifier(token.next);
+    listener.handleQualified(period);
+    return token;
+  }
+
+  Token skipBlock(Token token) {
+    if (!optional('{', token)) {
+      return reportUnrecoverableError(token, ErrorKind.ExpectedBlockToSkip);
+    }
+    BeginGroupToken beginGroupToken = token;
+    Token endGroup = beginGroupToken.endGroup;
+    if (endGroup == null) {
+      return reportUnrecoverableError(
+          beginGroupToken, ErrorKind.UnmatchedToken);
+    } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
+      return reportUnrecoverableError(
+          beginGroupToken, ErrorKind.UnmatchedToken);
+    }
+    return beginGroupToken.endGroup;
+  }
+
+  Token parseEnum(Token token) {
+    listener.beginEnum(token);
+    Token enumKeyword = token;
+    token = parseIdentifier(token.next);
+    token = expect('{', token);
+    int count = 0;
+    if (!optional('}', token)) {
+      token = parseIdentifier(token);
+      count++;
+      while (optional(',', token)) {
+        token = token.next;
+        if (optional('}', token)) break;
+        token = parseIdentifier(token);
+        count++;
+      }
+    }
+    Token endBrace = token;
+    token = expect('}', token);
+    listener.endEnum(enumKeyword, endBrace, count);
+    return token;
+  }
+
+  Token parseClassOrNamedMixinApplication(Token token) {
+    Token begin = token;
+    Token abstractKeyword;
+    if (optional('abstract', token)) {
+      abstractKeyword = token;
+      token = token.next;
+    }
+    int modifierCount = 0;
+    if (abstractKeyword != null) {
+      parseModifier(abstractKeyword);
+      modifierCount++;
+    }
+    listener.handleModifiers(modifierCount);
+    bool isMixinApplication = optional('=', peekAfterType(token));
+    Token name = token.next;
+    token = parseIdentifier(name);
+
+    if (isMixinApplication) {
+      listener.beginNamedMixinApplication(begin, name);
+    } else {
+      listener.beginClassDeclaration(begin, name);
+    }
+
+    token = parseTypeVariablesOpt(token);
+
+    if (optional('=', token)) {
+      token = expect('=', token);
+      return parseNamedMixinApplication(token, begin, name);
+    } else {
+      return parseClass(token, begin, name);
+    }
+  }
+
+  Token parseNamedMixinApplication(Token token, Token begin, Token name) {
+    token = parseMixinApplication(token);
+    Token implementsKeyword = null;
+    if (optional('implements', token)) {
+      implementsKeyword = token;
+      token = parseTypeList(token.next);
+    }
+    listener.endNamedMixinApplication(begin, implementsKeyword, token);
+    return expect(';', token);
+  }
+
+  Token parseClass(Token token, Token begin, Token name) {
+    Token extendsKeyword;
+    if (optional('extends', token)) {
+      extendsKeyword = token;
+      if (optional('with', peekAfterType(token.next))) {
+        token = parseMixinApplication(token.next);
+      } else {
+        token = parseType(token.next);
+      }
+    } else {
+      extendsKeyword = null;
+      listener.handleNoType(token);
+    }
+    Token implementsKeyword;
+    int interfacesCount = 0;
+    if (optional('implements', token)) {
+      implementsKeyword = token;
+      do {
+        token = parseType(token.next);
+        ++interfacesCount;
+      } while (optional(',', token));
+    }
+    token = parseClassBody(token);
+    listener.endClassDeclaration(
+        interfacesCount, begin, extendsKeyword, implementsKeyword, token);
+    return token.next;
+  }
+
+  Token parseStringPart(Token token) {
+    if (token.kind != STRING_TOKEN) {
+      token = reportUnrecoverableError(token, ErrorKind.ExpectedString);
+    }
+    listener.handleStringPart(token);
+    return token.next;
+  }
+
+  Token parseIdentifier(Token token) {
+    if (!token.isIdentifier()) {
+      token = reportUnrecoverableError(token, ErrorKind.ExpectedIdentifier);
+    }
+    listener.handleIdentifier(token);
+    return token.next;
+  }
+
+  Token expect(String string, Token token) {
+    if (!identical(string, token.stringValue)) {
+      return reportUnrecoverableError(
+          token, ErrorKind.ExpectedButGot, {"expected": string});
+    }
+    return token.next;
+  }
+
+  Token parseTypeVariable(Token token) {
+    listener.beginTypeVariable(token);
+    token = parseIdentifier(token);
+    Token extendsOrSuper = null;
+    if (optional('extends', token) || optional('super', token)) {
+      extendsOrSuper = token;
+      token = parseType(token.next);
+    } else {
+      listener.handleNoType(token);
+    }
+    listener.endTypeVariable(token, extendsOrSuper);
+    return token;
+  }
+
+  /**
+   * Returns true if the stringValue of the [token] is either [value1],
+   * [value2], or [value3].
+   */
+  bool isOneOf3(Token token, String value1, String value2, String value3) {
+    String stringValue = token.stringValue;
+    return value1 == stringValue ||
+        value2 == stringValue ||
+        value3 == stringValue;
+  }
+
+  /**
+   * Returns true if the stringValue of the [token] is either [value1],
+   * [value2], [value3], or [value4].
+   */
+  bool isOneOf4(
+      Token token, String value1, String value2, String value3, String value4) {
+    String stringValue = token.stringValue;
+    return value1 == stringValue ||
+        value2 == stringValue ||
+        value3 == stringValue ||
+        value4 == stringValue;
+  }
+
+  bool notEofOrValue(String value, Token token) {
+    return !identical(token.kind, EOF_TOKEN) &&
+        !identical(value, token.stringValue);
+  }
+
+  Token parseType(Token token) {
+    Token begin = token;
+    if (isValidTypeReference(token)) {
+      token = parseIdentifier(token);
+      token = parseQualifiedRestOpt(token);
+    } else {
+      token = reportUnrecoverableError(token, ErrorKind.ExpectedType);
+      listener.handleInvalidTypeReference(token);
+    }
+    token = parseTypeArgumentsOpt(token);
+    listener.endType(begin, token);
+    return token;
+  }
+
+  Token parseTypeArgumentsOpt(Token token) {
+    return parseStuff(
+        token,
+        (t) => listener.beginTypeArguments(t),
+        (t) => parseType(t),
+        (c, bt, et) => listener.endTypeArguments(c, bt, et),
+        (t) => listener.handleNoTypeArguments(t));
+  }
+
+  Token parseTypeVariablesOpt(Token token) {
+    return parseStuff(
+        token,
+        (t) => listener.beginTypeVariables(t),
+        (t) => parseTypeVariable(t),
+        (c, bt, et) => listener.endTypeVariables(c, bt, et),
+        (t) => listener.handleNoTypeVariables(t));
+  }
+
+  // TODO(ahe): Clean this up.
+  Token parseStuff(Token token, Function beginStuff, Function stuffParser,
+      Function endStuff, Function handleNoStuff) {
+    if (optional('<', token)) {
+      Token begin = token;
+      beginStuff(begin);
+      int count = 0;
+      do {
+        token = stuffParser(token.next);
+        ++count;
+      } while (optional(',', token));
+      Token next = token.next;
+      if (identical(token.stringValue, '>>')) {
+        token = new SymbolToken(GT_INFO, token.charOffset);
+        token.next = new SymbolToken(GT_INFO, token.charOffset + 1);
+        token.next.next = next;
+      }
+      endStuff(count, begin, token);
+      return expect('>', token);
+    }
+    handleNoStuff(token);
+    return token;
+  }
+
+  Token parseTopLevelMember(Token token) {
+    Token start = token;
+    listener.beginTopLevelMember(token);
+
+    Link<Token> identifiers = findMemberName(token);
+    if (identifiers.isEmpty) {
+      return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
+    }
+    Token afterName = identifiers.head;
+    identifiers = identifiers.tail;
+
+    if (identifiers.isEmpty) {
+      return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
+    }
+    Token name = identifiers.head;
+    identifiers = identifiers.tail;
+    Token getOrSet;
+    if (!identifiers.isEmpty) {
+      String value = identifiers.head.stringValue;
+      if ((identical(value, 'get')) || (identical(value, 'set'))) {
+        getOrSet = identifiers.head;
+        identifiers = identifiers.tail;
+      }
+    }
+    Token type;
+    if (!identifiers.isEmpty) {
+      if (isValidTypeReference(identifiers.head)) {
+        type = identifiers.head;
+        identifiers = identifiers.tail;
+      }
+    }
+
+    token = afterName;
+    bool isField;
+    while (true) {
+      // Loop to allow the listener to rewrite the token stream for
+      // error handling.
+      final String value = token.stringValue;
+      if ((identical(value, '(')) ||
+          (identical(value, '{')) ||
+          (identical(value, '=>'))) {
+        isField = false;
+        break;
+      } else if ((identical(value, '=')) || (identical(value, ','))) {
+        isField = true;
+        break;
+      } else if (identical(value, ';')) {
+        if (getOrSet != null) {
+          // If we found a "get" keyword, this must be an abstract
+          // getter.
+          isField = (!identical(getOrSet.stringValue, 'get'));
+          // TODO(ahe): This feels like a hack.
+        } else {
+          isField = true;
+        }
+        break;
+      } else {
+        token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+        if (identical(token.kind, EOF_TOKEN)) return token;
+      }
+    }
+    var modifiers = identifiers.reverse();
+    return isField
+        ? parseFields(start, modifiers, type, getOrSet, name, true)
+        : parseTopLevelMethod(start, modifiers, type, getOrSet, name);
+  }
+
+  bool isVarFinalOrConst(Token token) {
+    String value = token.stringValue;
+    return identical('var', value) ||
+        identical('final', value) ||
+        identical('const', value);
+  }
+
+  Token expectVarFinalOrConst(
+      Link<Token> modifiers, bool hasType, bool allowStatic) {
+    int modifierCount = 0;
+    Token staticModifier;
+    if (allowStatic &&
+        !modifiers.isEmpty &&
+        optional('static', modifiers.head)) {
+      staticModifier = modifiers.head;
+      modifierCount++;
+      parseModifier(staticModifier);
+      modifiers = modifiers.tail;
+    }
+    if (modifiers.isEmpty) {
+      listener.handleModifiers(modifierCount);
+      return null;
+    }
+    if (modifiers.tail.isEmpty) {
+      Token modifier = modifiers.head;
+      if (isVarFinalOrConst(modifier)) {
+        modifierCount++;
+        parseModifier(modifier);
+        listener.handleModifiers(modifierCount);
+        // TODO(ahe): The caller checks for "var Type name", perhaps we should
+        // check here instead.
+        return modifier;
+      }
+    }
+
+    // Slow case to report errors.
+    List<Token> modifierList = modifiers.toList();
+    Token varFinalOrConst =
+        modifierList.firstWhere(isVarFinalOrConst, orElse: () => null);
+    if (allowStatic && staticModifier == null) {
+      staticModifier = modifierList.firstWhere(
+          (modifier) => optional('static', modifier),
+          orElse: () => null);
+      if (staticModifier != null) {
+        modifierCount++;
+        parseModifier(staticModifier);
+        modifierList.remove(staticModifier);
+      }
+    }
+    bool hasTypeOrModifier = hasType;
+    if (varFinalOrConst != null) {
+      parseModifier(varFinalOrConst);
+      modifierCount++;
+      hasTypeOrModifier = true;
+      modifierList.remove(varFinalOrConst);
+    }
+    listener.handleModifiers(modifierCount);
+    var kind = hasTypeOrModifier
+        ? ErrorKind.ExtraneousModifier
+        : ErrorKind.ExtraneousModifierReplace;
+    for (Token modifier in modifierList) {
+      reportRecoverableError(modifier, kind, {'modifier': modifier});
+    }
+    return null;
+  }
+
+  /// Removes the optional `covariant` token from the modifiers, if there
+  /// is no `static` in the list, and `covariant` is the first modifier.
+  Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) {
+    if (modifiers.isEmpty ||
+        !identical(modifiers.first.stringValue, 'covariant')) {
+      return modifiers;
+    }
+    for (Token modifier in modifiers.tail) {
+      if (identical(modifier.stringValue, 'static')) {
+        return modifiers;
+      }
+    }
+    return modifiers.tail;
+  }
+
+  Token parseFields(Token start, Link<Token> modifiers, Token type,
+      Token getOrSet, Token name, bool isTopLevel) {
+    bool hasType = type != null;
+
+    if (getOrSet == null && !isTopLevel) {
+      modifiers = removeOptCovariantTokenIfNotStatic(modifiers);
+    }
+
+    Token varFinalOrConst =
+        expectVarFinalOrConst(modifiers, hasType, !isTopLevel);
+    bool isVar = false;
+    bool hasModifier = false;
+    if (varFinalOrConst != null) {
+      hasModifier = true;
+      isVar = optional('var', varFinalOrConst);
+    }
+
+    if (getOrSet != null) {
+      var kind = (hasModifier || hasType)
+          ? ErrorKind.ExtraneousModifier
+          : ErrorKind.ExtraneousModifierReplace;
+      reportRecoverableError(getOrSet, kind, {'modifier': getOrSet});
+    }
+
+    if (!hasType) {
+      listener.handleNoType(name);
+    } else if (optional('void', type)) {
+      listener.handleNoType(name);
+      // TODO(ahe): This error is reported twice, second time is from
+      // [parseVariablesDeclarationMaybeSemicolon] via
+      // [PartialFieldListElement.parseNode].
+      reportRecoverableError(type, ErrorKind.InvalidVoid);
+    } else {
+      parseType(type);
+      if (isVar) {
+        reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier,
+            {'modifier': modifiers.head});
+      }
+    }
+
+    Token token = parseIdentifier(name);
+
+    int fieldCount = 1;
+    token = parseFieldInitializerOpt(token);
+    while (optional(',', token)) {
+      token = parseIdentifier(token.next);
+      token = parseFieldInitializerOpt(token);
+      ++fieldCount;
+    }
+    Token semicolon = token;
+    token = expectSemicolon(token);
+    if (isTopLevel) {
+      listener.endTopLevelFields(fieldCount, start, semicolon);
+    } else {
+      listener.endFields(fieldCount, start, semicolon);
+    }
+    return token;
+  }
+
+  Token parseTopLevelMethod(Token start, Link<Token> modifiers, Token type,
+      Token getOrSet, Token name) {
+    listener.beginTopLevelMethod(start, name);
+    Token externalModifier;
+    // TODO(johnniwinther): Move error reporting to resolution to give more
+    // specific error messages.
+    for (Token modifier in modifiers) {
+      if (externalModifier == null && optional('external', modifier)) {
+        externalModifier = modifier;
+      } else {
+        reportRecoverableError(
+            modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
+      }
+    }
+    if (externalModifier != null) {
+      parseModifier(externalModifier);
+      listener.handleModifiers(1);
+    } else {
+      listener.handleModifiers(0);
+    }
+
+    if (type == null) {
+      listener.handleNoType(name);
+    } else {
+      parseReturnTypeOpt(type);
+    }
+    Token token = parseIdentifier(name);
+
+    if (getOrSet == null) {
+      token = parseTypeVariablesOpt(token);
+    } else {
+      listener.handleNoTypeVariables(token);
+    }
+    token = parseFormalParametersOpt(token);
+    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
+    token = parseAsyncModifier(token);
+    token = parseFunctionBody(token, false, externalModifier != null);
+    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
+    Token endToken = token;
+    token = token.next;
+    listener.endTopLevelMethod(start, getOrSet, endToken);
+    return token;
+  }
+
+  /// Looks ahead to find the name of a member. Returns a link of the modifiers,
+  /// set/get, (operator) name, and either the start of the method body or the
+  /// end of the declaration.
+  ///
+  /// Examples:
+  ///
+  ///     int get foo;
+  /// results in
+  ///     [';', 'foo', 'get', 'int']
+  ///
+  ///
+  ///     static const List<int> foo = null;
+  /// results in
+  ///     ['=', 'foo', 'List', 'const', 'static']
+  ///
+  ///
+  ///     get foo async* { return null }
+  /// results in
+  ///     ['{', 'foo', 'get']
+  ///
+  ///
+  ///     operator *(arg) => null;
+  /// results in
+  ///     ['(', '*', 'operator']
+  ///
+  Link<Token> findMemberName(Token token) {
+    Link<Token> identifiers = const Link<Token>();
+
+    // `true` if 'get' has been seen.
+    bool isGetter = false;
+    // `true` if an identifier has been seen after 'get'.
+    bool hasName = false;
+
+    while (token.kind != EOF_TOKEN) {
+      if (optional('get', token)) {
+        isGetter = true;
+      } else if (hasName &&
+                 (optional("sync", token) || optional("async", token))) {
+        // Skip.
+        token = token.next;
+        if (optional("*", token)) {
+          // Skip.
+          token = token.next;
+        }
+        continue;
+      } else if (optional("(", token) || optional("{", token) ||
+                 optional("=>", token)) {
+        // A method.
+        identifiers = identifiers.prepend(token);
+        return listener.handleMemberName(identifiers);
+      } else if (optional("=", token) || optional(";", token) ||
+                 optional(",", token)) {
+        // A field or abstract getter.
+        identifiers = identifiers.prepend(token);
+        return listener.handleMemberName(identifiers);
+      } else if (isGetter) {
+        hasName = true;
+      }
+      identifiers = identifiers.prepend(token);
+      if (isValidTypeReference(token)) {
+        // type ...
+        if (optional('.', token.next)) {
+          // type '.' ...
+          if (token.next.next.isIdentifier()) {
+            // type '.' identifier
+            token = token.next.next;
+          }
+        }
+        if (optional('<', token.next)) {
+          if (token.next is BeginGroupToken) {
+            BeginGroupToken beginGroup = token.next;
+            if (beginGroup.endGroup == null) {
+              reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken);
+            } else {
+              token = beginGroup.endGroup;
+            }
+          }
+        }
+      }
+      token = token.next;
+    }
+    return listener.handleMemberName(const Link<Token>());
+  }
+
+  Token parseFieldInitializerOpt(Token token) {
+    if (optional('=', token)) {
+      Token assignment = token;
+      listener.beginFieldInitializer(token);
+      token = parseExpression(token.next);
+      listener.endFieldInitializer(assignment);
+    } else {
+      listener.handleNoFieldInitializer(token);
+    }
+    return token;
+  }
+
+  Token parseVariableInitializerOpt(Token token) {
+    if (optional('=', token)) {
+      Token assignment = token;
+      listener.beginVariableInitializer(token);
+      token = parseExpression(token.next);
+      listener.endVariableInitializer(assignment);
+    }
+    return token;
+  }
+
+  Token parseInitializersOpt(Token token) {
+    if (optional(':', token)) {
+      return parseInitializers(token);
+    } else {
+      listener.handleNoInitializers();
+      return token;
+    }
+  }
+
+  Token parseInitializers(Token token) {
+    Token begin = token;
+    listener.beginInitializers(begin);
+    expect(':', token);
+    int count = 0;
+    bool old = mayParseFunctionExpressions;
+    mayParseFunctionExpressions = false;
+    do {
+      token = token.next;
+      listener.beginInitializer(token);
+      token = parseExpression(token);
+      listener.endInitializer(token);
+      ++count;
+    } while (optional(',', token));
+    mayParseFunctionExpressions = old;
+    listener.endInitializers(count, begin, token);
+    return token;
+  }
+
+  Token parseLiteralStringOrRecoverExpression(Token token) {
+    if (identical(token.kind, STRING_TOKEN)) {
+      return parseLiteralString(token);
+    } else {
+      reportRecoverableError(token, ErrorKind.ExpectedString);
+      return parseExpression(token);
+    }
+  }
+
+  Token expectSemicolon(Token token) {
+    return expect(';', token);
+  }
+
+  bool isModifier(Token token) {
+    final String value = token.stringValue;
+    return (identical('final', value)) ||
+        (identical('var', value)) ||
+        (identical('const', value)) ||
+        (identical('abstract', value)) ||
+        (identical('static', value)) ||
+        (identical('external', value));
+  }
+
+  Token parseModifier(Token token) {
+    assert(isModifier(token));
+    listener.handleModifier(token);
+    return token.next;
+  }
+
+  void parseModifierList(Link<Token> tokens) {
+    int count = 0;
+    for (; !tokens.isEmpty; tokens = tokens.tail) {
+      Token token = tokens.head;
+      if (isModifier(token)) {
+        parseModifier(token);
+      } else {
+        reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+        // Skip the remaining modifiers.
+        break;
+      }
+      count++;
+    }
+    listener.handleModifiers(count);
+  }
+
+  Token parseModifiers(Token token) {
+    int count = 0;
+    while (identical(token.kind, KEYWORD_TOKEN)) {
+      if (!isModifier(token)) break;
+      token = parseModifier(token);
+      count++;
+    }
+    listener.handleModifiers(count);
+    return token;
+  }
+
+  /**
+   * Returns the first token after the type starting at [token].
+   * This method assumes that [token] is an identifier (or void).
+   * Use [peekAfterIfType] if [token] isn't known to be an identifier.
+   */
+  Token peekAfterType(Token token) {
+    // We are looking at "identifier ...".
+    Token peek = token.next;
+    if (identical(peek.kind, PERIOD_TOKEN)) {
+      if (peek.next.isIdentifier()) {
+        // Look past a library prefix.
+        peek = peek.next.next;
+      }
+    }
+    // We are looking at "qualified ...".
+    if (identical(peek.kind, LT_TOKEN)) {
+      // Possibly generic type.
+      // We are looking at "qualified '<'".
+      BeginGroupToken beginGroupToken = peek;
+      Token gtToken = beginGroupToken.endGroup;
+      if (gtToken != null) {
+        // We are looking at "qualified '<' ... '>' ...".
+        return gtToken.next;
+      }
+    }
+    return peek;
+  }
+
+  /**
+   * If [token] is the start of a type, returns the token after that type.
+   * If [token] is not the start of a type, null is returned.
+   */
+  Token peekAfterIfType(Token token) {
+    if (!optional('void', token) && !token.isIdentifier()) {
+      return null;
+    }
+    return peekAfterType(token);
+  }
+
+  Token skipClassBody(Token token) {
+    if (!optional('{', token)) {
+      return reportUnrecoverableError(token, ErrorKind.ExpectedClassBodyToSkip);
+    }
+    BeginGroupToken beginGroupToken = token;
+    Token endGroup = beginGroupToken.endGroup;
+    if (endGroup == null) {
+      return reportUnrecoverableError(
+          beginGroupToken, ErrorKind.UnmatchedToken);
+    } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
+      return reportUnrecoverableError(
+          beginGroupToken, ErrorKind.UnmatchedToken);
+    }
+    return endGroup;
+  }
+
+  Token parseClassBody(Token token) {
+    Token begin = token;
+    listener.beginClassBody(token);
+    if (!optional('{', token)) {
+      token = reportUnrecoverableError(token, ErrorKind.ExpectedClassBody);
+    }
+    token = token.next;
+    int count = 0;
+    while (notEofOrValue('}', token)) {
+      token = parseMember(token);
+      ++count;
+    }
+    expect('}', token);
+    listener.endClassBody(count, begin, token);
+    return token;
+  }
+
+  bool isGetOrSet(Token token) {
+    final String value = token.stringValue;
+    return (identical(value, 'get')) || (identical(value, 'set'));
+  }
+
+  bool isFactoryDeclaration(Token token) {
+    if (optional('external', token)) token = token.next;
+    if (optional('const', token)) token = token.next;
+    return optional('factory', token);
+  }
+
+  Token parseMember(Token token) {
+    token = parseMetadataStar(token);
+    Token start = token;
+    listener.beginMember(token);
+    if (isFactoryDeclaration(token)) {
+      token = parseFactoryMethod(token);
+      listener.endMember();
+      assert(token != null);
+      return token;
+    }
+
+    Link<Token> identifiers = findMemberName(token);
+    if (identifiers.isEmpty) {
+      return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
+    }
+    Token afterName = identifiers.head;
+    identifiers = identifiers.tail;
+
+    if (identifiers.isEmpty) {
+      return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
+    }
+    Token name = identifiers.head;
+    identifiers = identifiers.tail;
+    if (!identifiers.isEmpty) {
+      if (optional('operator', identifiers.head)) {
+        name = identifiers.head;
+        identifiers = identifiers.tail;
+      }
+    }
+    Token getOrSet;
+    if (!identifiers.isEmpty) {
+      if (isGetOrSet(identifiers.head)) {
+        getOrSet = identifiers.head;
+        identifiers = identifiers.tail;
+      }
+    }
+    Token type;
+    if (!identifiers.isEmpty) {
+      if (isValidTypeReference(identifiers.head)) {
+        type = identifiers.head;
+        identifiers = identifiers.tail;
+      }
+    }
+
+    token = afterName;
+    bool isField;
+    while (true) {
+      // Loop to allow the listener to rewrite the token stream for
+      // error handling.
+      final String value = token.stringValue;
+      if ((identical(value, '(')) ||
+          (identical(value, '.')) ||
+          (identical(value, '{')) ||
+          (identical(value, '=>')) ||
+          (identical(value, '<'))) {
+        isField = false;
+        break;
+      } else if (identical(value, ';')) {
+        if (getOrSet != null) {
+          // If we found a "get" keyword, this must be an abstract
+          // getter.
+          isField = !optional("get", getOrSet);
+          // TODO(ahe): This feels like a hack.
+        } else {
+          isField = true;
+        }
+        break;
+      } else if ((identical(value, '=')) || (identical(value, ','))) {
+        isField = true;
+        break;
+      } else {
+        token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+        if (identical(token.kind, EOF_TOKEN)) {
+          // TODO(ahe): This is a hack, see parseTopLevelMember.
+          listener.endFields(1, start, token);
+          listener.endMember();
+          return token;
+        }
+      }
+    }
+
+    var modifiers = identifiers.reverse();
+    token = isField
+        ? parseFields(start, modifiers, type, getOrSet, name, false)
+        : parseMethod(start, modifiers, type, getOrSet, name);
+    listener.endMember();
+    return token;
+  }
+
+  Token parseMethod(Token start, Link<Token> modifiers, Token type,
+      Token getOrSet, Token name) {
+    listener.beginMethod(start, name);
+    Token externalModifier;
+    Token staticModifier;
+    Token constModifier;
+    int modifierCount = 0;
+    int allowedModifierCount = 1;
+    // TODO(johnniwinther): Move error reporting to resolution to give more
+    // specific error messages.
+    for (Token modifier in modifiers) {
+      if (externalModifier == null && optional('external', modifier)) {
+        modifierCount++;
+        externalModifier = modifier;
+        if (modifierCount != allowedModifierCount) {
+          reportRecoverableError(modifier, ErrorKind.ExtraneousModifier,
+              {'modifier': modifier});
+        }
+        allowedModifierCount++;
+      } else if (staticModifier == null && optional('static', modifier)) {
+        modifierCount++;
+        staticModifier = modifier;
+        if (modifierCount != allowedModifierCount) {
+          reportRecoverableError(modifier, ErrorKind.ExtraneousModifier,
+              {'modifier': modifier});
+        }
+      } else if (constModifier == null && optional('const', modifier)) {
+        modifierCount++;
+        constModifier = modifier;
+        if (modifierCount != allowedModifierCount) {
+          reportRecoverableError(modifier, ErrorKind.ExtraneousModifier,
+              {'modifier': modifier});
+        }
+      } else {
+        reportRecoverableError(
+            modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
+      }
+    }
+    if (getOrSet != null && constModifier != null) {
+      reportRecoverableError(constModifier, ErrorKind.ExtraneousModifier,
+          {'modifier': constModifier});
+    }
+    parseModifierList(modifiers);
+
+    if (type == null) {
+      listener.handleNoType(name);
+    } else {
+      parseReturnTypeOpt(type);
+    }
+    Token token;
+    if (optional('operator', name)) {
+      token = parseOperatorName(name);
+      if (staticModifier != null) {
+        reportRecoverableError(staticModifier, ErrorKind.ExtraneousModifier,
+            {'modifier': staticModifier});
+      }
+    } else {
+      token = parseIdentifier(name);
+    }
+
+    token = parseQualifiedRestOpt(token);
+    if (getOrSet == null) {
+      token = parseTypeVariablesOpt(token);
+    } else {
+      listener.handleNoTypeVariables(token);
+    }
+    token = parseFormalParametersOpt(token);
+    token = parseInitializersOpt(token);
+    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
+    token = parseAsyncModifier(token);
+    if (optional('=', token)) {
+      token = parseRedirectingFactoryBody(token);
+    } else {
+      token = parseFunctionBody(
+          token, false, staticModifier == null || externalModifier != null);
+    }
+    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
+    listener.endMethod(getOrSet, start, token);
+    return token.next;
+  }
+
+  Token parseFactoryMethod(Token token) {
+    assert(isFactoryDeclaration(token));
+    Token start = token;
+    Token externalModifier;
+    if (identical(token.stringValue, 'external')) {
+      externalModifier = token;
+      token = token.next;
+    }
+    if (optional('const', token)) {
+      token = token.next; // Skip const.
+    }
+    Token factoryKeyword = token;
+    listener.beginFactoryMethod(factoryKeyword);
+    token = token.next; // Skip 'factory'.
+    token = parseConstructorReference(token);
+    token = parseFormalParameters(token);
+    token = parseAsyncModifier(token);
+    if (optional('=', token)) {
+      token = parseRedirectingFactoryBody(token);
+    } else {
+      token = parseFunctionBody(token, false, externalModifier != null);
+    }
+    listener.endFactoryMethod(start, token);
+    return token.next;
+  }
+
+  Token parseOperatorName(Token token) {
+    assert(optional('operator', token));
+    if (isUserDefinableOperator(token.next.stringValue)) {
+      Token operator = token;
+      token = token.next;
+      listener.handleOperatorName(operator, token);
+      return token.next;
+    } else {
+      return parseIdentifier(token);
+    }
+  }
+
+  Token parseFunction(Token token, Token getOrSet) {
+    listener.beginFunction(token);
+    token = parseModifiers(token);
+    if (identical(getOrSet, token)) {
+      // get <name>  => ...
+      token = token.next;
+      listener.handleNoType(token);
+      listener.beginFunctionName(token);
+      if (optional('operator', token)) {
+        token = parseOperatorName(token);
+      } else {
+        token = parseIdentifier(token);
+      }
+    } else if (optional('operator', token)) {
+      // operator <op> (...
+      listener.handleNoType(token);
+      listener.beginFunctionName(token);
+      token = parseOperatorName(token);
+    } else {
+      // <type>? <get>? <name>
+      token = parseReturnTypeOpt(token);
+      if (identical(getOrSet, token)) {
+        token = token.next;
+      }
+      listener.beginFunctionName(token);
+      if (optional('operator', token)) {
+        token = parseOperatorName(token);
+      } else {
+        token = parseIdentifier(token);
+      }
+    }
+    token = parseQualifiedRestOpt(token);
+    listener.endFunctionName(token);
+    if (getOrSet == null) {
+      token = parseTypeVariablesOpt(token);
+    } else {
+      listener.handleNoTypeVariables(token);
+    }
+    token = parseFormalParametersOpt(token);
+    token = parseInitializersOpt(token);
+    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
+    token = parseAsyncModifier(token);
+    token = parseFunctionBody(token, false, true);
+    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
+    listener.endFunction(getOrSet, token);
+    return token.next;
+  }
+
+  Token parseUnnamedFunction(Token token) {
+    listener.beginUnnamedFunction(token);
+    token = parseFormalParameters(token);
+    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
+    token = parseAsyncModifier(token);
+    bool isBlock = optional('{', token);
+    token = parseFunctionBody(token, true, false);
+    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
+    listener.endUnnamedFunction(token);
+    return isBlock ? token.next : token;
+  }
+
+  Token parseFunctionDeclaration(Token token) {
+    listener.beginFunctionDeclaration(token);
+    token = parseFunction(token, null);
+    listener.endFunctionDeclaration(token);
+    return token;
+  }
+
+  Token parseFunctionExpression(Token token) {
+    listener.beginFunction(token);
+    listener.handleModifiers(0);
+    token = parseReturnTypeOpt(token);
+    listener.beginFunctionName(token);
+    token = parseIdentifier(token);
+    listener.endFunctionName(token);
+    token = parseTypeVariablesOpt(token);
+    token = parseFormalParameters(token);
+    listener.handleNoInitializers();
+    bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
+    token = parseAsyncModifier(token);
+    bool isBlock = optional('{', token);
+    token = parseFunctionBody(token, true, false);
+    asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
+    listener.endFunction(null, token);
+    return isBlock ? token.next : token;
+  }
+
+  Token parseConstructorReference(Token token) {
+    Token start = token;
+    listener.beginConstructorReference(start);
+    token = parseIdentifier(token);
+    token = parseQualifiedRestOpt(token);
+    token = parseTypeArgumentsOpt(token);
+    Token period = null;
+    if (optional('.', token)) {
+      period = token;
+      token = parseIdentifier(token.next);
+    }
+    listener.endConstructorReference(start, period, token);
+    return token;
+  }
+
+  Token parseRedirectingFactoryBody(Token token) {
+    listener.beginRedirectingFactoryBody(token);
+    assert(optional('=', token));
+    Token equals = token;
+    token = parseConstructorReference(token.next);
+    Token semicolon = token;
+    expectSemicolon(token);
+    listener.endRedirectingFactoryBody(equals, semicolon);
+    return token;
+  }
+
+  Token skipFunctionBody(Token token, bool isExpression, bool allowAbstract) {
+    assert(!isExpression);
+    token = skipAsyncModifier(token);
+    String value = token.stringValue;
+    if (identical(value, ';')) {
+      if (!allowAbstract) {
+        reportRecoverableError(token, ErrorKind.ExpectedBody);
+      }
+      listener.handleNoFunctionBody(token);
+    } else {
+      if (identical(value, '=>')) {
+        token = parseExpression(token.next);
+        expectSemicolon(token);
+      } else if (identical(value, '=')) {
+        reportRecoverableError(token, ErrorKind.ExpectedBody);
+        token = parseExpression(token.next);
+        expectSemicolon(token);
+      } else {
+        token = skipBlock(token);
+      }
+      listener.handleFunctionBodySkipped(token);
+    }
+    return token;
+  }
+
+  Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
+    if (optional(';', token)) {
+      if (!allowAbstract) {
+        reportRecoverableError(token, ErrorKind.ExpectedBody);
+      }
+      listener.endFunctionBody(0, null, token);
+      return token;
+    } else if (optional('=>', token)) {
+      Token begin = token;
+      token = parseExpression(token.next);
+      if (!isExpression) {
+        expectSemicolon(token);
+        listener.endReturnStatement(true, begin, token);
+      } else {
+        listener.endReturnStatement(true, begin, null);
+      }
+      return token;
+    } else if (optional('=', token)) {
+      Token begin = token;
+      // Recover from a bad factory method.
+      reportRecoverableError(token, ErrorKind.ExpectedBody);
+      token = parseExpression(token.next);
+      if (!isExpression) {
+        expectSemicolon(token);
+        listener.endReturnStatement(true, begin, token);
+      } else {
+        listener.endReturnStatement(true, begin, null);
+      }
+      return token;
+    }
+    Token begin = token;
+    int statementCount = 0;
+    if (!optional('{', token)) {
+      token = reportUnrecoverableError(token, ErrorKind.ExpectedFunctionBody);
+      listener.handleInvalidFunctionBody(token);
+      return token;
+    }
+
+    listener.beginFunctionBody(begin);
+    token = token.next;
+    while (notEofOrValue('}', token)) {
+      token = parseStatement(token);
+      ++statementCount;
+    }
+    listener.endFunctionBody(statementCount, begin, token);
+    expect('}', token);
+    return token;
+  }
+
+  Token skipAsyncModifier(Token token) {
+    String value = token.stringValue;
+    if (identical(value, 'async')) {
+      token = token.next;
+      value = token.stringValue;
+
+      if (identical(value, '*')) {
+        token = token.next;
+      }
+    } else if (identical(value, 'sync')) {
+      token = token.next;
+      value = token.stringValue;
+
+      if (identical(value, '*')) {
+        token = token.next;
+      }
+    }
+    return token;
+  }
+
+  Token parseAsyncModifier(Token token) {
+    Token async;
+    Token star;
+    asyncAwaitKeywordsEnabled = false;
+    if (optional('async', token)) {
+      asyncAwaitKeywordsEnabled = true;
+      async = token;
+      token = token.next;
+      if (optional('*', token)) {
+        star = token;
+        token = token.next;
+      }
+    } else if (optional('sync', token)) {
+      async = token;
+      token = token.next;
+      if (optional('*', token)) {
+        asyncAwaitKeywordsEnabled = true;
+        star = token;
+        token = token.next;
+      } else {
+        reportRecoverableError(async, ErrorKind.InvalidSyncModifier);
+      }
+    }
+    listener.handleAsyncModifier(async, star);
+    return token;
+  }
+
+  int statementDepth = 0;
+  Token parseStatement(Token token) {
+    if (statementDepth++ > 500) {
+      // This happens for degenerate programs, for example, a lot of nested
+      // if-statements. The language test deep_nesting2_negative_test, for
+      // example, provokes this.
+      return reportUnrecoverableError(token, ErrorKind.StackOverflow);
+    }
+    Token result = parseStatementX(token);
+    statementDepth--;
+    return result;
+  }
+
+  Token parseStatementX(Token token) {
+    final value = token.stringValue;
+    if (identical(token.kind, IDENTIFIER_TOKEN)) {
+      return parseExpressionStatementOrDeclaration(token);
+    } else if (identical(value, '{')) {
+      return parseBlock(token);
+    } else if (identical(value, 'return')) {
+      return parseReturnStatement(token);
+    } else if (identical(value, 'var') || identical(value, 'final')) {
+      return parseVariablesDeclaration(token);
+    } else if (identical(value, 'if')) {
+      return parseIfStatement(token);
+    } else if (asyncAwaitKeywordsEnabled && identical(value, 'await')) {
+      if (identical(token.next.stringValue, 'for')) {
+        return parseForStatement(token, token.next);
+      } else {
+        return parseExpressionStatement(token);
+      }
+    } else if (identical(value, 'for')) {
+      return parseForStatement(null, token);
+    } else if (identical(value, 'rethrow')) {
+      return parseRethrowStatement(token);
+    } else if (identical(value, 'throw') && optional(';', token.next)) {
+      // TODO(kasperl): Stop dealing with throw here.
+      return parseRethrowStatement(token);
+    } else if (identical(value, 'void')) {
+      return parseExpressionStatementOrDeclaration(token);
+    } else if (identical(value, 'while')) {
+      return parseWhileStatement(token);
+    } else if (identical(value, 'do')) {
+      return parseDoWhileStatement(token);
+    } else if (identical(value, 'try')) {
+      return parseTryStatement(token);
+    } else if (identical(value, 'switch')) {
+      return parseSwitchStatement(token);
+    } else if (identical(value, 'break')) {
+      return parseBreakStatement(token);
+    } else if (identical(value, 'continue')) {
+      return parseContinueStatement(token);
+    } else if (identical(value, 'assert')) {
+      return parseAssertStatement(token);
+    } else if (identical(value, ';')) {
+      return parseEmptyStatement(token);
+    } else if (asyncAwaitKeywordsEnabled && identical(value, 'yield')) {
+      return parseYieldStatement(token);
+    } else if (identical(value, 'const')) {
+      return parseExpressionStatementOrConstDeclaration(token);
+    } else if (token.isIdentifier()) {
+      return parseExpressionStatementOrDeclaration(token);
+    } else {
+      return parseExpressionStatement(token);
+    }
+  }
+
+  Token parseYieldStatement(Token token) {
+    Token begin = token;
+    listener.beginYieldStatement(begin);
+    assert(identical('yield', token.stringValue));
+    token = token.next;
+    Token starToken;
+    if (optional('*', token)) {
+      starToken = token;
+      token = token.next;
+    }
+    token = parseExpression(token);
+    listener.endYieldStatement(begin, starToken, token);
+    return expectSemicolon(token);
+  }
+
+  Token parseReturnStatement(Token token) {
+    Token begin = token;
+    listener.beginReturnStatement(begin);
+    assert(identical('return', token.stringValue));
+    token = token.next;
+    if (optional(';', token)) {
+      listener.endReturnStatement(false, begin, token);
+    } else {
+      token = parseExpression(token);
+      listener.endReturnStatement(true, begin, token);
+    }
+    return expectSemicolon(token);
+  }
+
+  Token peekIdentifierAfterType(Token token) {
+    Token peek = peekAfterType(token);
+    if (peek != null && peek.isIdentifier()) {
+      // We are looking at "type identifier".
+      return peek;
+    } else {
+      return null;
+    }
+  }
+
+  Token peekIdentifierAfterOptionalType(Token token) {
+    Token peek = peekAfterIfType(token);
+    if (peek != null && peek.isIdentifier()) {
+      // We are looking at "type identifier".
+      return peek;
+    } else if (token.isIdentifier()) {
+      // We are looking at "identifier".
+      return token;
+    } else {
+      return null;
+    }
+  }
+
+  Token parseExpressionStatementOrDeclaration(Token token) {
+    assert(token.isIdentifier() || identical(token.stringValue, 'void'));
+    Token identifier = peekIdentifierAfterType(token);
+    if (identifier != null) {
+      assert(identifier.isIdentifier());
+      Token afterId = identifier.next;
+      int afterIdKind = afterId.kind;
+      if (identical(afterIdKind, EQ_TOKEN) ||
+          identical(afterIdKind, SEMICOLON_TOKEN) ||
+          identical(afterIdKind, COMMA_TOKEN)) {
+        // We are looking at "type identifier" followed by '=', ';', ','.
+        return parseVariablesDeclaration(token);
+      } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) {
+        // We are looking at "type identifier '('".
+        BeginGroupToken beginParen = afterId;
+        Token endParen = beginParen.endGroup;
+        // TODO(eernst): Check for NPE as described in issue 26252.
+        Token afterParens = endParen.next;
+        if (optional('{', afterParens) ||
+            optional('=>', afterParens) ||
+            optional('async', afterParens) ||
+            optional('sync', afterParens)) {
+          // We are looking at "type identifier '(' ... ')'" followed
+          // by '{', '=>', 'async', or 'sync'.
+          return parseFunctionDeclaration(token);
+        }
+      } else if (identical(afterIdKind, LT_TOKEN)) {
+        // We are looking at "type identifier '<'".
+        BeginGroupToken beginAngle = afterId;
+        Token endAngle = beginAngle.endGroup;
+        if (endAngle != null &&
+            identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
+          BeginGroupToken beginParen = endAngle.next;
+          Token endParen = beginParen.endGroup;
+          if (endParen != null) {
+            Token afterParens = endParen.next;
+            if (optional('{', afterParens) ||
+                optional('=>', afterParens) ||
+                optional('async', afterParens) ||
+                optional('sync', afterParens)) {
+              // We are looking at "type identifier '<' ... '>' '(' ... ')'"
+              // followed by '{', '=>', 'async', or 'sync'.
+              return parseFunctionDeclaration(token);
+            }
+          }
+        }
+      }
+      // Fall-through to expression statement.
+    } else {
+      if (optional(':', token.next)) {
+        return parseLabeledStatement(token);
+      } else if (optional('(', token.next)) {
+        BeginGroupToken begin = token.next;
+        // TODO(eernst): Check for NPE as described in issue 26252.
+        String afterParens = begin.endGroup.next.stringValue;
+        if (identical(afterParens, '{') ||
+            identical(afterParens, '=>') ||
+            identical(afterParens, 'async') ||
+            identical(afterParens, 'sync')) {
+          return parseFunctionDeclaration(token);
+        }
+      } else if (optional('<', token.next)) {
+        BeginGroupToken beginAngle = token.next;
+        Token endAngle = beginAngle.endGroup;
+        if (endAngle != null &&
+            identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
+          BeginGroupToken beginParen = endAngle.next;
+          Token endParen = beginParen.endGroup;
+          if (endParen != null) {
+            String afterParens = endParen.next.stringValue;
+            if (identical(afterParens, '{') ||
+                identical(afterParens, '=>') ||
+                identical(afterParens, 'async') ||
+                identical(afterParens, 'sync')) {
+              return parseFunctionDeclaration(token);
+            }
+          }
+        }
+        // Fall through to expression statement.
+      }
+    }
+    return parseExpressionStatement(token);
+  }
+
+  Token parseExpressionStatementOrConstDeclaration(Token token) {
+    assert(identical(token.stringValue, 'const'));
+    if (isModifier(token.next)) {
+      return parseVariablesDeclaration(token);
+    }
+    Token identifier = peekIdentifierAfterOptionalType(token.next);
+    if (identifier != null) {
+      assert(identifier.isIdentifier());
+      Token afterId = identifier.next;
+      int afterIdKind = afterId.kind;
+      if (identical(afterIdKind, EQ_TOKEN) ||
+          identical(afterIdKind, SEMICOLON_TOKEN) ||
+          identical(afterIdKind, COMMA_TOKEN)) {
+        // We are looking at "const type identifier" followed by '=', ';', or
+        // ','.
+        return parseVariablesDeclaration(token);
+      }
+      // Fall-through to expression statement.
+    }
+
+    return parseExpressionStatement(token);
+  }
+
+  Token parseLabel(Token token) {
+    token = parseIdentifier(token);
+    Token colon = token;
+    token = expect(':', token);
+    listener.handleLabel(colon);
+    return token;
+  }
+
+  Token parseLabeledStatement(Token token) {
+    int labelCount = 0;
+    do {
+      token = parseLabel(token);
+      labelCount++;
+    } while (token.isIdentifier() && optional(':', token.next));
+    listener.beginLabeledStatement(token, labelCount);
+    token = parseStatement(token);
+    listener.endLabeledStatement(labelCount);
+    return token;
+  }
+
+  Token parseExpressionStatement(Token token) {
+    listener.beginExpressionStatement(token);
+    token = parseExpression(token);
+    listener.endExpressionStatement(token);
+    return expectSemicolon(token);
+  }
+
+  Token skipExpression(Token token) {
+    while (true) {
+      final kind = token.kind;
+      final value = token.stringValue;
+      if ((identical(kind, EOF_TOKEN)) ||
+          (identical(value, ';')) ||
+          (identical(value, ',')) ||
+          (identical(value, '}')) ||
+          (identical(value, ')')) ||
+          (identical(value, ']'))) {
+        break;
+      }
+      if (identical(value, '=') ||
+          identical(value, '?') ||
+          identical(value, ':') ||
+          identical(value, '??')) {
+        var nextValue = token.next.stringValue;
+        if (identical(nextValue, 'const')) {
+          token = token.next;
+          nextValue = token.next.stringValue;
+        }
+        if (identical(nextValue, '{')) {
+          // Handle cases like this:
+          // class Foo {
+          //   var map;
+          //   Foo() : map = {};
+          //   Foo.x() : map = true ? {} : {};
+          // }
+          BeginGroupToken begin = token.next;
+          token = (begin.endGroup != null) ? begin.endGroup : token;
+          token = token.next;
+          continue;
+        }
+        if (identical(nextValue, '<')) {
+          // Handle cases like this:
+          // class Foo {
+          //   var map;
+          //   Foo() : map = <String, Foo>{};
+          //   Foo.x() : map = true ? <String, Foo>{} : <String, Foo>{};
+          // }
+          BeginGroupToken begin = token.next;
+          token = (begin.endGroup != null) ? begin.endGroup : token;
+          token = token.next;
+          if (identical(token.stringValue, '{')) {
+            begin = token;
+            token = (begin.endGroup != null) ? begin.endGroup : token;
+            token = token.next;
+          }
+          continue;
+        }
+      }
+      if (!mayParseFunctionExpressions && identical(value, '{')) {
+        break;
+      }
+      if (token is BeginGroupToken) {
+        BeginGroupToken begin = token;
+        token = (begin.endGroup != null) ? begin.endGroup : token;
+      } else if (token is ErrorToken) {
+        reportErrorToken(token, false);
+      }
+      token = token.next;
+    }
+    return token;
+  }
+
+  int expressionDepth = 0;
+  Token parseExpression(Token token) {
+    if (expressionDepth++ > 500) {
+      // This happens in degenerate programs, for example, with a lot of nested
+      // list literals. This is provoked by, for examaple, the language test
+      // deep_nesting1_negative_test.
+      return reportUnrecoverableError(token, ErrorKind.StackOverflow);
+    }
+    listener.beginExpression(token);
+    Token result = optional('throw', token)
+        ? parseThrowExpression(token, true)
+        : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true);
+    expressionDepth--;
+    return result;
+  }
+
+  Token parseExpressionWithoutCascade(Token token) {
+    listener.beginExpression(token);
+    return optional('throw', token)
+        ? parseThrowExpression(token, false)
+        : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false);
+  }
+
+  Token parseConditionalExpressionRest(Token token) {
+    assert(optional('?', token));
+    Token question = token;
+    token = parseExpressionWithoutCascade(token.next);
+    Token colon = token;
+    token = expect(':', token);
+    token = parseExpressionWithoutCascade(token);
+    listener.handleConditionalExpression(question, colon);
+    return token;
+  }
+
+  Token parsePrecedenceExpression(
+      Token token, int precedence, bool allowCascades) {
+    assert(precedence >= 1);
+    assert(precedence <= POSTFIX_PRECEDENCE);
+    token = parseUnaryExpression(token, allowCascades);
+    PrecedenceInfo info = token.info;
+    int tokenLevel = info.precedence;
+    for (int level = tokenLevel; level >= precedence; --level) {
+      while (identical(tokenLevel, level)) {
+        Token operator = token;
+        if (identical(tokenLevel, CASCADE_PRECEDENCE)) {
+          if (!allowCascades) {
+            return token;
+          }
+          token = parseCascadeExpression(token);
+        } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) {
+          // Right associative, so we recurse at the same precedence
+          // level.
+          listener.beginExpression(token.next);
+          token = parsePrecedenceExpression(token.next, level, allowCascades);
+          listener.handleAssignmentExpression(operator);
+        } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
+          if (identical(info, PERIOD_INFO) ||
+              identical(info, QUESTION_PERIOD_INFO)) {
+            // Left associative, so we recurse at the next higher precedence
+            // level. However, POSTFIX_PRECEDENCE is the highest level, so we
+            // should just call [parseUnaryExpression] directly. However, a
+            // unary expression isn't legal after a period, so we call
+            // [parsePrimary] instead.
+            token = parsePrimary(token.next);
+            listener.handleBinaryExpression(operator);
+          } else if ((identical(info, OPEN_PAREN_INFO)) ||
+              (identical(info, OPEN_SQUARE_BRACKET_INFO))) {
+            token = parseArgumentOrIndexStar(token);
+          } else if ((identical(info, PLUS_PLUS_INFO)) ||
+              (identical(info, MINUS_MINUS_INFO))) {
+            listener.handleUnaryPostfixAssignmentExpression(token);
+            token = token.next;
+          } else {
+            token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+          }
+        } else if (identical(info, IS_INFO)) {
+          token = parseIsOperatorRest(token);
+        } else if (identical(info, AS_INFO)) {
+          token = parseAsOperatorRest(token);
+        } else if (identical(info, QUESTION_INFO)) {
+          token = parseConditionalExpressionRest(token);
+        } else {
+          // Left associative, so we recurse at the next higher
+          // precedence level.
+          listener.beginExpression(token.next);
+          token =
+              parsePrecedenceExpression(token.next, level + 1, allowCascades);
+          listener.handleBinaryExpression(operator);
+        }
+        info = token.info;
+        tokenLevel = info.precedence;
+        if (level == EQUALITY_PRECEDENCE || level == RELATIONAL_PRECEDENCE) {
+          // We don't allow (a == b == c) or (a < b < c).
+          // Continue the outer loop if we have matched one equality or
+          // relational operator.
+          break;
+        }
+      }
+    }
+    return token;
+  }
+
+  Token parseCascadeExpression(Token token) {
+    listener.beginCascade(token);
+    assert(optional('..', token));
+    Token cascadeOperator = token;
+    token = token.next;
+    if (optional('[', token)) {
+      token = parseArgumentOrIndexStar(token);
+    } else if (token.isIdentifier()) {
+      token = parseSend(token);
+      listener.handleBinaryExpression(cascadeOperator);
+    } else {
+      return reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+    }
+    Token mark;
+    do {
+      mark = token;
+      if (optional('.', token)) {
+        Token period = token;
+        token = parseSend(token.next);
+        listener.handleBinaryExpression(period);
+      }
+      token = parseArgumentOrIndexStar(token);
+    } while (!identical(mark, token));
+
+    if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) {
+      Token assignment = token;
+      token = parseExpressionWithoutCascade(token.next);
+      listener.handleAssignmentExpression(assignment);
+    }
+    listener.endCascade();
+    return token;
+  }
+
+  Token parseUnaryExpression(Token token, bool allowCascades) {
+    String value = token.stringValue;
+    // Prefix:
+    if (asyncAwaitKeywordsEnabled && optional('await', token)) {
+      return parseAwaitExpression(token, allowCascades);
+    } else if (identical(value, '+')) {
+      // Dart no longer allows prefix-plus.
+      reportRecoverableError(token, ErrorKind.UnsupportedPrefixPlus);
+      return parseUnaryExpression(token.next, allowCascades);
+    } else if ((identical(value, '!')) ||
+        (identical(value, '-')) ||
+        (identical(value, '~'))) {
+      Token operator = token;
+      // Right associative, so we recurse at the same precedence
+      // level.
+      token = parsePrecedenceExpression(
+          token.next, POSTFIX_PRECEDENCE, allowCascades);
+      listener.handleUnaryPrefixExpression(operator);
+    } else if ((identical(value, '++')) || identical(value, '--')) {
+      // TODO(ahe): Validate this is used correctly.
+      Token operator = token;
+      // Right associative, so we recurse at the same precedence
+      // level.
+      token = parsePrecedenceExpression(
+          token.next, POSTFIX_PRECEDENCE, allowCascades);
+      listener.handleUnaryPrefixAssignmentExpression(operator);
+    } else {
+      token = parsePrimary(token);
+    }
+    return token;
+  }
+
+  Token parseArgumentOrIndexStar(Token token) {
+    while (true) {
+      if (optional('[', token)) {
+        Token openSquareBracket = token;
+        bool old = mayParseFunctionExpressions;
+        mayParseFunctionExpressions = true;
+        token = parseExpression(token.next);
+        mayParseFunctionExpressions = old;
+        listener.handleIndexedExpression(openSquareBracket, token);
+        token = expect(']', token);
+      } else if (optional('(', token)) {
+        listener.handleNoTypeArguments(token);
+        token = parseArguments(token);
+        listener.endSend(token);
+      } else {
+        break;
+      }
+    }
+    return token;
+  }
+
+  Token parsePrimary(Token token) {
+    final kind = token.kind;
+    if (kind == IDENTIFIER_TOKEN) {
+      return parseSendOrFunctionLiteral(token);
+    } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) {
+      return parseLiteralInt(token);
+    } else if (kind == DOUBLE_TOKEN) {
+      return parseLiteralDouble(token);
+    } else if (kind == STRING_TOKEN) {
+      return parseLiteralString(token);
+    } else if (kind == HASH_TOKEN) {
+      return parseLiteralSymbol(token);
+    } else if (kind == KEYWORD_TOKEN) {
+      final value = token.stringValue;
+      if (value == 'true' || value == 'false') {
+        return parseLiteralBool(token);
+      } else if (value == 'null') {
+        return parseLiteralNull(token);
+      } else if (value == 'this') {
+        return parseThisExpression(token);
+      } else if (value == 'super') {
+        return parseSuperExpression(token);
+      } else if (value == 'new') {
+        return parseNewExpression(token);
+      } else if (value == 'const') {
+        return parseConstExpression(token);
+      } else if (value == 'void') {
+        return parseFunctionExpression(token);
+      } else if (asyncAwaitKeywordsEnabled &&
+          (value == 'yield' || value == 'async')) {
+        return expressionExpected(token);
+      } else if (token.isIdentifier()) {
+        return parseSendOrFunctionLiteral(token);
+      } else {
+        return expressionExpected(token);
+      }
+    } else if (kind == OPEN_PAREN_TOKEN) {
+      return parseParenthesizedExpressionOrFunctionLiteral(token);
+    } else if (kind == OPEN_SQUARE_BRACKET_TOKEN || token.stringValue == '[]') {
+      listener.handleNoTypeArguments(token);
+      return parseLiteralListSuffix(token, null);
+    } else if (kind == OPEN_CURLY_BRACKET_TOKEN) {
+      listener.handleNoTypeArguments(token);
+      return parseLiteralMapSuffix(token, null);
+    } else if (kind == LT_TOKEN) {
+      return parseLiteralListOrMapOrFunction(token, null);
+    } else {
+      return expressionExpected(token);
+    }
+  }
+
+  Token expressionExpected(Token token) {
+    token = reportUnrecoverableError(token, ErrorKind.ExpectedExpression);
+    listener.handleInvalidExpression(token);
+    return token;
+  }
+
+  Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
+    BeginGroupToken beginGroup = token;
+    // TODO(eernst): Check for NPE as described in issue 26252.
+    Token nextToken = beginGroup.endGroup.next;
+    int kind = nextToken.kind;
+    if (mayParseFunctionExpressions &&
+        (identical(kind, FUNCTION_TOKEN) ||
+            identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
+            (identical(kind, KEYWORD_TOKEN) &&
+                (nextToken.value == 'async' || nextToken.value == 'sync')))) {
+      listener.handleNoTypeVariables(token);
+      return parseUnnamedFunction(token);
+    } else {
+      bool old = mayParseFunctionExpressions;
+      mayParseFunctionExpressions = true;
+      token = parseParenthesizedExpression(token);
+      mayParseFunctionExpressions = old;
+      return token;
+    }
+  }
+
+  Token parseParenthesizedExpression(Token token) {
+    // We expect [begin] to be of type [BeginGroupToken], but we don't know for
+    // sure until after calling expect.
+    dynamic begin = token;
+    token = expect('(', token);
+    // [begin] is now known to have type [BeginGroupToken].
+    token = parseExpression(token);
+    if (!identical(begin.endGroup, token)) {
+      reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+      token = begin.endGroup;
+    }
+    listener.handleParenthesizedExpression(begin);
+    return expect(')', token);
+  }
+
+  Token parseThisExpression(Token token) {
+    listener.handleThisExpression(token);
+    token = token.next;
+    if (optional('(', token)) {
+      // Constructor forwarding.
+      listener.handleNoTypeArguments(token);
+      token = parseArguments(token);
+      listener.endSend(token);
+    }
+    return token;
+  }
+
+  Token parseSuperExpression(Token token) {
+    listener.handleSuperExpression(token);
+    token = token.next;
+    if (optional('(', token)) {
+      // Super constructor.
+      listener.handleNoTypeArguments(token);
+      token = parseArguments(token);
+      listener.endSend(token);
+    }
+    return token;
+  }
+
+  /// '[' (expressionList ','?)? ']'.
+  ///
+  /// Provide [constKeyword] if preceded by 'const', null if not.
+  /// This is a suffix parser because it is assumed that type arguments have
+  /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
+  Token parseLiteralListSuffix(Token token, Token constKeyword) {
+    assert(optional('[', token) || optional('[]', token));
+    Token beginToken = token;
+    int count = 0;
+    if (optional('[', token)) {
+      bool old = mayParseFunctionExpressions;
+      mayParseFunctionExpressions = true;
+      do {
+        if (optional(']', token.next)) {
+          token = token.next;
+          break;
+        }
+        token = parseExpression(token.next);
+        ++count;
+      } while (optional(',', token));
+      mayParseFunctionExpressions = old;
+      listener.handleLiteralList(count, beginToken, constKeyword, token);
+      return expect(']', token);
+    }
+    // Looking at '[]'.
+    listener.handleLiteralList(0, token, constKeyword, token);
+    return token.next;
+  }
+
+  /// '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'.
+  ///
+  /// Provide token for [constKeyword] if preceded by 'const', null if not.
+  /// This is a suffix parser because it is assumed that type arguments have
+  /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
+  Token parseLiteralMapSuffix(Token token, Token constKeyword) {
+    assert(optional('{', token));
+    Token beginToken = token;
+    int count = 0;
+    bool old = mayParseFunctionExpressions;
+    mayParseFunctionExpressions = true;
+    do {
+      if (optional('}', token.next)) {
+        token = token.next;
+        break;
+      }
+      token = parseMapLiteralEntry(token.next);
+      ++count;
+    } while (optional(',', token));
+    mayParseFunctionExpressions = old;
+    listener.handleLiteralMap(count, beginToken, constKeyword, token);
+    return expect('}', token);
+  }
+
+  /// formalParameterList functionBody.
+  ///
+  /// This is a suffix parser because it is assumed that type arguments have
+  /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
+  Token parseLiteralFunctionSuffix(Token token) {
+    assert(optional('(', token));
+    BeginGroupToken beginGroup = token;
+    if (beginGroup.endGroup != null) {
+      Token nextToken = beginGroup.endGroup.next;
+      int kind = nextToken.kind;
+      if (identical(kind, FUNCTION_TOKEN) ||
+          identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
+          (identical(kind, KEYWORD_TOKEN) &&
+              (nextToken.value == 'async' || nextToken.value == 'sync'))) {
+        return parseUnnamedFunction(token);
+      }
+      // Fall through.
+    }
+    reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+    return null;
+  }
+
+  /// genericListLiteral | genericMapLiteral | genericFunctionLiteral.
+  ///
+  /// Where
+  ///   genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']'
+  ///   genericMapLiteral ::=
+  ///       typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
+  ///   genericFunctionLiteral ::=
+  ///       typeParameters formalParameterList functionBody
+  /// Provide token for [constKeyword] if preceded by 'const', null if not.
+  Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) {
+    assert(optional('<', token));
+    BeginGroupToken begin = token;
+    if (constKeyword == null &&
+        begin.endGroup != null &&
+        identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) {
+      token = parseTypeVariablesOpt(token);
+      return parseLiteralFunctionSuffix(token);
+    } else {
+      token = parseTypeArgumentsOpt(token);
+      if (optional('{', token)) {
+        return parseLiteralMapSuffix(token, constKeyword);
+      } else if ((optional('[', token)) || (optional('[]', token))) {
+        return parseLiteralListSuffix(token, constKeyword);
+      }
+      reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+      return null;
+    }
+  }
+
+  Token parseMapLiteralEntry(Token token) {
+    listener.beginLiteralMapEntry(token);
+    // Assume the listener rejects non-string keys.
+    token = parseExpression(token);
+    Token colon = token;
+    token = expect(':', token);
+    token = parseExpression(token);
+    listener.endLiteralMapEntry(colon, token);
+    return token;
+  }
+
+  Token parseSendOrFunctionLiteral(Token token) {
+    if (!mayParseFunctionExpressions) return parseSend(token);
+    Token peek = peekAfterIfType(token);
+    if (peek != null &&
+        identical(peek.kind, IDENTIFIER_TOKEN) &&
+        isFunctionDeclaration(peek.next)) {
+      return parseFunctionExpression(token);
+    } else if (isFunctionDeclaration(token.next)) {
+      return parseFunctionExpression(token);
+    } else {
+      return parseSend(token);
+    }
+  }
+
+  bool isFunctionDeclaration(Token token) {
+    if (optional('<', token)) {
+      BeginGroupToken begin = token;
+      if (begin.endGroup == null) return false;
+      token = begin.endGroup.next;
+    }
+    if (optional('(', token)) {
+      BeginGroupToken begin = token;
+      // TODO(eernst): Check for NPE as described in issue 26252.
+      String afterParens = begin.endGroup.next.stringValue;
+      if (identical(afterParens, '{') ||
+          identical(afterParens, '=>') ||
+          identical(afterParens, 'async') ||
+          identical(afterParens, 'sync')) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  Token parseRequiredArguments(Token token) {
+    if (optional('(', token)) {
+      token = parseArguments(token);
+    } else {
+      listener.handleNoArguments(token);
+      token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+    }
+    return token;
+  }
+
+  Token parseNewExpression(Token token) {
+    Token newKeyword = token;
+    token = expect('new', token);
+    token = parseConstructorReference(token);
+    token = parseRequiredArguments(token);
+    listener.handleNewExpression(newKeyword);
+    return token;
+  }
+
+  Token parseConstExpression(Token token) {
+    Token constKeyword = token;
+    token = expect('const', token);
+    final String value = token.stringValue;
+    if ((identical(value, '[')) || (identical(value, '[]'))) {
+      listener.handleNoTypeArguments(token);
+      return parseLiteralListSuffix(token, constKeyword);
+    }
+    if (identical(value, '{')) {
+      listener.handleNoTypeArguments(token);
+      return parseLiteralMapSuffix(token, constKeyword);
+    }
+    if (identical(value, '<')) {
+      return parseLiteralListOrMapOrFunction(token, constKeyword);
+    }
+    token = parseConstructorReference(token);
+    token = parseRequiredArguments(token);
+    listener.handleConstExpression(constKeyword);
+    return token;
+  }
+
+  Token parseLiteralInt(Token token) {
+    listener.handleLiteralInt(token);
+    return token.next;
+  }
+
+  Token parseLiteralDouble(Token token) {
+    listener.handleLiteralDouble(token);
+    return token.next;
+  }
+
+  Token parseLiteralString(Token token) {
+    bool old = mayParseFunctionExpressions;
+    mayParseFunctionExpressions = true;
+    token = parseSingleLiteralString(token);
+    int count = 1;
+    while (identical(token.kind, STRING_TOKEN)) {
+      token = parseSingleLiteralString(token);
+      count++;
+    }
+    if (count > 1) {
+      listener.handleStringJuxtaposition(count);
+    }
+    mayParseFunctionExpressions = old;
+    return token;
+  }
+
+  Token parseLiteralSymbol(Token token) {
+    Token hashToken = token;
+    listener.beginLiteralSymbol(hashToken);
+    token = token.next;
+    if (isUserDefinableOperator(token.stringValue)) {
+      listener.handleOperator(token);
+      listener.endLiteralSymbol(hashToken, 1);
+      return token.next;
+    } else {
+      int count = 1;
+      token = parseIdentifier(token);
+      while (identical(token.stringValue, '.')) {
+        count++;
+        token = parseIdentifier(token.next);
+      }
+      listener.endLiteralSymbol(hashToken, count);
+      return token;
+    }
+  }
+
+  /**
+   * Only called when [:token.kind === STRING_TOKEN:].
+   */
+  Token parseSingleLiteralString(Token token) {
+    listener.beginLiteralString(token);
+    // Parsing the prefix, for instance 'x of 'x${id}y${id}z'
+    token = token.next;
+    int interpolationCount = 0;
+    var kind = token.kind;
+    while (kind != EOF_TOKEN) {
+      if (identical(kind, STRING_INTERPOLATION_TOKEN)) {
+        // Parsing ${expression}.
+        token = token.next;
+        token = parseExpression(token);
+        token = expect('}', token);
+      } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) {
+        // Parsing $identifier.
+        token = token.next;
+        token = parseExpression(token);
+      } else {
+        break;
+      }
+      ++interpolationCount;
+      // Parsing the infix/suffix, for instance y and z' of 'x${id}y${id}z'
+      token = parseStringPart(token);
+      kind = token.kind;
+    }
+    listener.endLiteralString(interpolationCount);
+    return token;
+  }
+
+  Token parseLiteralBool(Token token) {
+    listener.handleLiteralBool(token);
+    return token.next;
+  }
+
+  Token parseLiteralNull(Token token) {
+    listener.handleLiteralNull(token);
+    return token.next;
+  }
+
+  Token parseSend(Token token) {
+    listener.beginSend(token);
+    token = parseIdentifier(token);
+    if (isValidMethodTypeArguments(token)) {
+      token = parseTypeArgumentsOpt(token);
+    } else {
+      listener.handleNoTypeArguments(token);
+    }
+    token = parseArgumentsOpt(token);
+    listener.endSend(token);
+    return token;
+  }
+
+  Token skipArgumentsOpt(Token token) {
+    listener.handleNoArguments(token);
+    if (optional('(', token)) {
+      BeginGroupToken begin = token;
+      return begin.endGroup.next;
+    } else {
+      return token;
+    }
+  }
+
+  Token parseArgumentsOpt(Token token) {
+    if (!optional('(', token)) {
+      listener.handleNoArguments(token);
+      return token;
+    } else {
+      return parseArguments(token);
+    }
+  }
+
+  Token parseArguments(Token token) {
+    Token begin = token;
+    listener.beginArguments(begin);
+    assert(identical('(', token.stringValue));
+    int argumentCount = 0;
+    if (optional(')', token.next)) {
+      listener.endArguments(argumentCount, begin, token.next);
+      return token.next.next;
+    }
+    bool old = mayParseFunctionExpressions;
+    mayParseFunctionExpressions = true;
+    do {
+      if (optional(')', token.next)) {
+        token = token.next;
+        break;
+      }
+      Token colon = null;
+      if (optional(':', token.next.next)) {
+        token = parseIdentifier(token.next);
+        colon = token;
+      }
+      token = parseExpression(token.next);
+      if (colon != null) listener.handleNamedArgument(colon);
+      ++argumentCount;
+    } while (optional(',', token));
+    mayParseFunctionExpressions = old;
+    listener.endArguments(argumentCount, begin, token);
+    return expect(')', token);
+  }
+
+  Token parseIsOperatorRest(Token token) {
+    assert(optional('is', token));
+    Token operator = token;
+    Token not = null;
+    if (optional('!', token.next)) {
+      token = token.next;
+      not = token;
+    }
+    token = parseType(token.next);
+    listener.handleIsOperator(operator, not, token);
+    String value = token.stringValue;
+    if (identical(value, 'is') || identical(value, 'as')) {
+      // The is- and as-operators cannot be chained, but they can take part of
+      // expressions like: foo is Foo || foo is Bar.
+      reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+    }
+    return token;
+  }
+
+  Token parseAsOperatorRest(Token token) {
+    assert(optional('as', token));
+    Token operator = token;
+    token = parseType(token.next);
+    listener.handleAsOperator(operator, token);
+    String value = token.stringValue;
+    if (identical(value, 'is') || identical(value, 'as')) {
+      // The is- and as-operators cannot be chained.
+      reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+    }
+    return token;
+  }
+
+  Token parseVariablesDeclaration(Token token) {
+    return parseVariablesDeclarationMaybeSemicolon(token, true);
+  }
+
+  Token parseVariablesDeclarationNoSemicolon(Token token) {
+    // Only called when parsing a for loop, so this is for parsing locals.
+    return parseVariablesDeclarationMaybeSemicolon(token, false);
+  }
+
+  Token parseVariablesDeclarationMaybeSemicolon(
+      Token token, bool endWithSemicolon) {
+    int count = 1;
+    listener.beginVariablesDeclaration(token);
+    token = parseModifiers(token);
+    token = parseTypeOpt(token);
+    token = parseOptionallyInitializedIdentifier(token);
+    while (optional(',', token)) {
+      token = parseOptionallyInitializedIdentifier(token.next);
+      ++count;
+    }
+    if (endWithSemicolon) {
+      Token semicolon = token;
+      token = expectSemicolon(semicolon);
+      listener.endVariablesDeclaration(count, semicolon);
+      return token;
+    } else {
+      listener.endVariablesDeclaration(count, null);
+      return token;
+    }
+  }
+
+  Token parseOptionallyInitializedIdentifier(Token token) {
+    listener.beginInitializedIdentifier(token);
+    token = parseIdentifier(token);
+    token = parseVariableInitializerOpt(token);
+    listener.endInitializedIdentifier();
+    return token;
+  }
+
+  Token parseIfStatement(Token token) {
+    Token ifToken = token;
+    listener.beginIfStatement(ifToken);
+    token = expect('if', token);
+    token = parseParenthesizedExpression(token);
+    listener.beginThenStatement(token);
+    token = parseStatement(token);
+    listener.endThenStatement(token);
+    Token elseToken = null;
+    if (optional('else', token)) {
+      elseToken = token;
+      listener.beginElseStatement(token);
+      token = parseStatement(token.next);
+      listener.endElseStatement(token);
+    }
+    listener.endIfStatement(ifToken, elseToken);
+    return token;
+  }
+
+  Token parseForStatement(Token awaitToken, Token token) {
+    Token forToken = token;
+    listener.beginForStatement(forToken);
+    token = expect('for', token);
+    token = expect('(', token);
+    token = parseVariablesDeclarationOrExpressionOpt(token);
+    if (optional('in', token)) {
+      return parseForInRest(awaitToken, forToken, token);
+    } else {
+      if (awaitToken != null) {
+        reportRecoverableError(awaitToken, ErrorKind.InvalidAwaitFor);
+      }
+      return parseForRest(forToken, token);
+    }
+  }
+
+  Token parseVariablesDeclarationOrExpressionOpt(Token token) {
+    final String value = token.stringValue;
+    if (identical(value, ';')) {
+      listener.handleNoExpression(token);
+      return token;
+    } else if (isOneOf3(token, 'var', 'final', 'const')) {
+      return parseVariablesDeclarationNoSemicolon(token);
+    }
+    Token identifier = peekIdentifierAfterType(token);
+    if (identifier != null) {
+      assert(identifier.isIdentifier());
+      if (isOneOf4(identifier.next, '=', ';', ',', 'in')) {
+        return parseVariablesDeclarationNoSemicolon(token);
+      }
+    }
+    return parseExpression(token);
+  }
+
+  Token parseForRest(Token forToken, Token token) {
+    token = expectSemicolon(token);
+    if (optional(';', token)) {
+      token = parseEmptyStatement(token);
+    } else {
+      token = parseExpressionStatement(token);
+    }
+    int expressionCount = 0;
+    while (true) {
+      if (optional(')', token)) break;
+      token = parseExpression(token);
+      ++expressionCount;
+      if (optional(',', token)) {
+        token = token.next;
+      } else {
+        break;
+      }
+    }
+    token = expect(')', token);
+    listener.beginForStatementBody(token);
+    token = parseStatement(token);
+    listener.endForStatementBody(token);
+    listener.endForStatement(expressionCount, forToken, token);
+    return token;
+  }
+
+  Token parseForInRest(Token awaitToken, Token forToken, Token token) {
+    assert(optional('in', token));
+    Token inKeyword = token;
+    token = token.next;
+    listener.beginForInExpression(token);
+    token = parseExpression(token);
+    listener.endForInExpression(token);
+    token = expect(')', token);
+    listener.beginForInBody(token);
+    token = parseStatement(token);
+    listener.endForInBody(token);
+    listener.endForIn(awaitToken, forToken, inKeyword, token);
+    return token;
+  }
+
+  Token parseWhileStatement(Token token) {
+    Token whileToken = token;
+    listener.beginWhileStatement(whileToken);
+    token = expect('while', token);
+    token = parseParenthesizedExpression(token);
+    listener.beginWhileStatementBody(token);
+    token = parseStatement(token);
+    listener.endWhileStatementBody(token);
+    listener.endWhileStatement(whileToken, token);
+    return token;
+  }
+
+  Token parseDoWhileStatement(Token token) {
+    Token doToken = token;
+    listener.beginDoWhileStatement(doToken);
+    token = expect('do', token);
+    listener.beginDoWhileStatementBody(token);
+    token = parseStatement(token);
+    listener.endDoWhileStatementBody(token);
+    Token whileToken = token;
+    token = expect('while', token);
+    token = parseParenthesizedExpression(token);
+    listener.endDoWhileStatement(doToken, whileToken, token);
+    return expectSemicolon(token);
+  }
+
+  Token parseBlock(Token token) {
+    Token begin = token;
+    listener.beginBlock(begin);
+    int statementCount = 0;
+    token = expect('{', token);
+    while (notEofOrValue('}', token)) {
+      token = parseStatement(token);
+      ++statementCount;
+    }
+    listener.endBlock(statementCount, begin, token);
+    return expect('}', token);
+  }
+
+  Token parseAwaitExpression(Token token, bool allowCascades) {
+    Token awaitToken = token;
+    listener.beginAwaitExpression(awaitToken);
+    token = expect('await', token);
+    token = parsePrecedenceExpression(token, POSTFIX_PRECEDENCE, allowCascades);
+    listener.endAwaitExpression(awaitToken, token);
+    return token;
+  }
+
+  Token parseThrowExpression(Token token, bool allowCascades) {
+    Token throwToken = token;
+    listener.beginThrowExpression(throwToken);
+    token = expect('throw', token);
+    token = allowCascades
+        ? parseExpression(token)
+        : parseExpressionWithoutCascade(token);
+    listener.endThrowExpression(throwToken, token);
+    return token;
+  }
+
+  Token parseRethrowStatement(Token token) {
+    Token throwToken = token;
+    listener.beginRethrowStatement(throwToken);
+    // TODO(kasperl): Disallow throw here.
+    if (identical(throwToken.stringValue, 'throw')) {
+      token = expect('throw', token);
+    } else {
+      token = expect('rethrow', token);
+    }
+    listener.endRethrowStatement(throwToken, token);
+    return expectSemicolon(token);
+  }
+
+  Token parseTryStatement(Token token) {
+    assert(optional('try', token));
+    Token tryKeyword = token;
+    listener.beginTryStatement(tryKeyword);
+    token = parseBlock(token.next);
+    int catchCount = 0;
+
+    String value = token.stringValue;
+    while (identical(value, 'catch') || identical(value, 'on')) {
+      listener.beginCatchClause(token);
+      var onKeyword = null;
+      if (identical(value, 'on')) {
+        // on qualified catchPart?
+        onKeyword = token;
+        token = parseType(token.next);
+        value = token.stringValue;
+      }
+      Token catchKeyword = null;
+      if (identical(value, 'catch')) {
+        catchKeyword = token;
+        // TODO(ahe): Validate the "parameters".
+        token = parseFormalParameters(token.next);
+      }
+      listener.endCatchClause(token);
+      token = parseBlock(token);
+      ++catchCount;
+      listener.handleCatchBlock(onKeyword, catchKeyword);
+      value = token.stringValue; // while condition
+    }
+
+    Token finallyKeyword = null;
+    if (optional('finally', token)) {
+      finallyKeyword = token;
+      token = parseBlock(token.next);
+      listener.handleFinallyBlock(finallyKeyword);
+    }
+    listener.endTryStatement(catchCount, tryKeyword, finallyKeyword);
+    return token;
+  }
+
+  Token parseSwitchStatement(Token token) {
+    assert(optional('switch', token));
+    Token switchKeyword = token;
+    listener.beginSwitchStatement(switchKeyword);
+    token = parseParenthesizedExpression(token.next);
+    token = parseSwitchBlock(token);
+    listener.endSwitchStatement(switchKeyword, token);
+    return token.next;
+  }
+
+  Token parseSwitchBlock(Token token) {
+    Token begin = token;
+    listener.beginSwitchBlock(begin);
+    token = expect('{', token);
+    int caseCount = 0;
+    while (!identical(token.kind, EOF_TOKEN)) {
+      if (optional('}', token)) {
+        break;
+      }
+      token = parseSwitchCase(token);
+      ++caseCount;
+    }
+    listener.endSwitchBlock(caseCount, begin, token);
+    expect('}', token);
+    return token;
+  }
+
+  /**
+   * Peek after the following labels (if any). The following token
+   * is used to determine if the labels belong to a statement or a
+   * switch case.
+   */
+  Token peekPastLabels(Token token) {
+    while (token.isIdentifier() && optional(':', token.next)) {
+      token = token.next.next;
+    }
+    return token;
+  }
+
+  /**
+   * Parse a group of labels, cases and possibly a default keyword and
+   * the statements that they select.
+   */
+  Token parseSwitchCase(Token token) {
+    Token begin = token;
+    Token defaultKeyword = null;
+    int expressionCount = 0;
+    int labelCount = 0;
+    Token peek = peekPastLabels(token);
+    while (true) {
+      // Loop until we find something that can't be part of a switch case.
+      String value = peek.stringValue;
+      if (identical(value, 'default')) {
+        while (!identical(token, peek)) {
+          token = parseLabel(token);
+          labelCount++;
+        }
+        defaultKeyword = token;
+        token = expect(':', token.next);
+        peek = token;
+        break;
+      } else if (identical(value, 'case')) {
+        while (!identical(token, peek)) {
+          token = parseLabel(token);
+          labelCount++;
+        }
+        Token caseKeyword = token;
+        token = parseExpression(token.next);
+        Token colonToken = token;
+        token = expect(':', token);
+        listener.handleCaseMatch(caseKeyword, colonToken);
+        expressionCount++;
+        peek = peekPastLabels(token);
+      } else {
+        if (expressionCount == 0) {
+          // TODO(ahe): This is probably easy to recover from.
+          reportUnrecoverableError(
+              token, ErrorKind.ExpectedButGot, {"expected": "case"});
+        }
+        break;
+      }
+    }
+    listener.beginSwitchCase(labelCount, expressionCount, begin);
+    // Finally zero or more statements.
+    int statementCount = 0;
+    while (!identical(token.kind, EOF_TOKEN)) {
+      String value = peek.stringValue;
+      if ((identical(value, 'case')) ||
+          (identical(value, 'default')) ||
+          ((identical(value, '}')) && (identical(token, peek)))) {
+        // A label just before "}" will be handled as a statement error.
+        break;
+      } else {
+        token = parseStatement(token);
+      }
+      statementCount++;
+      peek = peekPastLabels(token);
+    }
+    listener.handleSwitchCase(labelCount, expressionCount, defaultKeyword,
+        statementCount, begin, token);
+    return token;
+  }
+
+  Token parseBreakStatement(Token token) {
+    assert(optional('break', token));
+    Token breakKeyword = token;
+    token = token.next;
+    bool hasTarget = false;
+    if (token.isIdentifier()) {
+      token = parseIdentifier(token);
+      hasTarget = true;
+    }
+    listener.handleBreakStatement(hasTarget, breakKeyword, token);
+    return expectSemicolon(token);
+  }
+
+  Token parseAssertStatement(Token token) {
+    Token assertKeyword = token;
+    Token commaToken = null;
+    token = expect('assert', token);
+    token = expect('(', token);
+    bool old = mayParseFunctionExpressions;
+    mayParseFunctionExpressions = true;
+    token = parseExpression(token);
+    if (optional(',', token)) {
+      commaToken = token;
+      token = token.next;
+      token = parseExpression(token);
+    }
+    token = expect(')', token);
+    mayParseFunctionExpressions = old;
+    listener.handleAssertStatement(assertKeyword, commaToken, token);
+    return expectSemicolon(token);
+  }
+
+  Token parseContinueStatement(Token token) {
+    assert(optional('continue', token));
+    Token continueKeyword = token;
+    token = token.next;
+    bool hasTarget = false;
+    if (token.isIdentifier()) {
+      token = parseIdentifier(token);
+      hasTarget = true;
+    }
+    listener.handleContinueStatement(hasTarget, continueKeyword, token);
+    return expectSemicolon(token);
+  }
+
+  Token parseEmptyStatement(Token token) {
+    listener.handleEmptyStatement(token);
+    return expectSemicolon(token);
+  }
+
+  /// Don't call this method. Should only be used as a last resort when there
+  /// is no feasible way to recover from a parser error.
+  Token reportUnrecoverableError(Token token, ErrorKind kind, [Map arguments]) {
+    Token next;
+    if (token is ErrorToken) {
+      next = reportErrorToken(token, false);
+    } else {
+      arguments ??= {};
+      arguments.putIfAbsent("actual", () => token.value);
+      next = listener.handleUnrecoverableError(token, kind, arguments);
+    }
+    return next ?? skipToEof(token);
+  }
+
+  void reportRecoverableError(Token token, ErrorKind kind, [Map arguments]) {
+    if (token is ErrorToken) {
+      reportErrorToken(token, true);
+    } else {
+      arguments ??= {};
+      listener.handleRecoverableError(token, kind, arguments);
+    }
+  }
+
+  Token reportErrorToken(ErrorToken token, bool isRecoverable) {
+    ErrorKind kind = token.errorCode;
+    Map arguments = const {};
+    switch (kind) {
+      case ErrorKind.AsciiControlCharacter:
+      case ErrorKind.NonAsciiIdentifier:
+      case ErrorKind.NonAsciiWhitespace:
+      case ErrorKind.Encoding:
+        String hex = token.character.toRadixString(16);
+        if (hex.length < 4) {
+          String padding = "0000".substring(hex.length);
+          hex = "$padding$hex";
+        }
+        arguments = {'characterHex': hex};
+        break;
+
+      case ErrorKind.UnterminatedString:
+        arguments = {'quote': token.start};
+        break;
+
+      case ErrorKind.UnmatchedToken:
+        String begin = token.begin.value;
+        String end = closeBraceFor(begin);
+        arguments = {'begin': begin, 'end': end};
+        break;
+
+      case ErrorKind.Unspecified:
+        arguments = {"text": token.assertionMessage};
+        break;
+
+      default:
+        break;
+    }
+    if (isRecoverable) {
+      listener.handleRecoverableError(token, kind, arguments);
+      return null;
+    } else {
+      return listener.handleUnrecoverableError(token, kind, arguments);
+    }
+  }
+}
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
new file mode 100644
index 0000000..af96f3c
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.parser.top_level_parser;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    Token;
+
+import 'listener.dart' show
+    Listener;
+
+import 'class_member_parser.dart' show
+    ClassMemberParser;
+
+/// Parser which only parses top-level elements, but ignores their bodies.
+/// Use [Parser] to parse everything.
+class TopLevelParser extends ClassMemberParser {
+  TopLevelParser(Listener listener, {bool asyncAwaitKeywordsEnabled: false})
+      : super(listener, asyncAwaitKeywordsEnabled: asyncAwaitKeywordsEnabled);
+
+  Token parseClassBody(Token token) => skipClassBody(token);
+}
diff --git a/pkg/front_end/lib/src/fasta/quote.dart b/pkg/front_end/lib/src/fasta/quote.dart
new file mode 100644
index 0000000..14c6dca
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/quote.dart
@@ -0,0 +1,237 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.quote;
+
+import 'errors.dart' show
+    inputError,
+    internalError;
+
+import 'package:front_end/src/fasta/scanner/characters.dart' show
+    $BACKSLASH,
+    $BS,
+    $CLOSE_CURLY_BRACKET,
+    $CR,
+    $FF,
+    $LF,
+    $OPEN_CURLY_BRACKET,
+    $SPACE,
+    $TAB,
+    $VTAB,
+    $b,
+    $f,
+    $n,
+    $r,
+    $t,
+    $u,
+    $v,
+    $x,
+    hexDigitValue,
+    isHexDigit;
+
+enum Quote {
+  Single,
+  Double,
+  MultiLineSingle,
+  MultiLineDouble,
+  RawSingle,
+  RawDouble,
+  RawMultiLineSingle,
+  RawMultiLineDouble,
+}
+
+Quote analyzeQuote(String first) {
+  if (first.startsWith('"""')) return Quote.MultiLineDouble;
+  if (first.startsWith('r"""')) return Quote.RawMultiLineDouble;
+  if (first.startsWith("'''")) return Quote.MultiLineSingle;
+  if (first.startsWith("r'''")) return Quote.RawMultiLineSingle;
+  if (first.startsWith('"')) return Quote.Double;
+  if (first.startsWith('r"')) return Quote.RawDouble;
+  if (first.startsWith("'")) return Quote.Single;
+  if (first.startsWith("r'")) return Quote.RawSingle;
+  return internalError("Unexpected string literal: $first");
+}
+
+// Note: based on [StringValidator.quotingFromString]
+// (pkg/compiler/lib/src/string_validator.dart).
+int lengthOfOptionalWhitespacePrefix(String first, int start) {
+  List<int> codeUnits = first.codeUnits;
+  for (int i = start; i < codeUnits.length; i++) {
+    int code = codeUnits[i];
+    if (code == $BACKSLASH) {
+      i++;
+      if (i < codeUnits.length) {
+        code = codeUnits[i];
+      } else {
+        break;
+      }
+    }
+    if (code == $TAB || code == $SPACE) continue;
+    if (code == $CR) {
+      if (i + 1 < codeUnits.length && codeUnits[i] == $LF) {
+        i++;
+      }
+      return i + 1;
+    }
+    if (code == $LF) {
+      return i + 1;
+    }
+    break; // Not a white-space character.
+  }
+  return start;
+}
+
+int firstQuoteLength(String first, Quote quote) {
+  switch (quote) {
+    case Quote.Single:
+    case Quote.Double:
+      return 1;
+
+    case Quote.MultiLineSingle:
+    case Quote.MultiLineDouble:
+      return lengthOfOptionalWhitespacePrefix(first, 3);
+
+    case Quote.RawSingle:
+    case Quote.RawDouble:
+      return 2;
+
+    case Quote.RawMultiLineSingle:
+    case Quote.RawMultiLineDouble:
+      return lengthOfOptionalWhitespacePrefix(first, 4);
+  }
+  return internalError("Unhandled string quote: $quote");
+}
+
+int lastQuoteLength(Quote quote) {
+  switch (quote) {
+    case Quote.Single:
+    case Quote.Double:
+    case Quote.RawSingle:
+    case Quote.RawDouble:
+      return 1;
+
+    case Quote.MultiLineSingle:
+    case Quote.MultiLineDouble:
+    case Quote.RawMultiLineSingle:
+    case Quote.RawMultiLineDouble:
+      return 3;
+  }
+  return internalError("Unhandled string quote: $quote");
+}
+
+String unescapeFirstStringPart(String first, Quote quote) {
+  return unescape(first.substring(firstQuoteLength(first, quote)), quote);
+}
+
+String unescapeLastStringPart(String last, Quote quote) {
+  return unescape(last.substring(0, last.length - lastQuoteLength(quote)),
+      quote);
+}
+
+String unescapeString(String string) {
+  Quote quote = analyzeQuote(string);
+  return unescape(string.substring(
+      firstQuoteLength(string, quote), string.length - lastQuoteLength(quote)),
+      quote);
+}
+
+String unescape(String string, Quote quote) {
+  switch (quote) {
+    case Quote.Single:
+    case Quote.Double:
+    case Quote.MultiLineSingle:
+    case Quote.MultiLineDouble:
+      break;
+
+    case Quote.RawSingle:
+    case Quote.RawDouble:
+    case Quote.RawMultiLineSingle:
+    case Quote.RawMultiLineDouble:
+      return string;
+  }
+  return !string.contains("\\") ? string : unescapeCodeUnits(string.codeUnits);
+}
+
+const String incompleteSequence = "Incomplete escape sequence.";
+
+const String invalidCharacter = "Invalid character in escape sequence.";
+
+const String invalidCodePoint = "Invalid code point.";
+
+// Note: based on
+// [StringValidator.validateString](pkg/compiler/lib/src/string_validator.dart).
+String unescapeCodeUnits(List<int> codeUnits) {
+  // Can't use Uint8List or Uint16List here, the code units may be larger.
+  List<int> result = new List<int>(codeUnits.length);
+  int resultOffset = 0;
+  error(int offset, String message) {
+    inputError(null, null, message);
+  }
+  for (int i = 0; i < codeUnits.length; i++) {
+    int code = codeUnits[i];
+    if (code == $BACKSLASH) {
+      if (codeUnits.length == ++i) return error(i, incompleteSequence);
+      code = codeUnits[i];
+      /// `\n` for newline, equivalent to `\x0A`.
+      /// `\r` for carriage return, equivalent to `\x0D`.
+      /// `\f` for form feed, equivalent to `\x0C`.
+      /// `\b` for backspace, equivalent to `\x08`.
+      /// `\t` for tab, equivalent to `\x09`.
+      /// `\v` for vertical tab, equivalent to `\x0B`.
+      /// `\xXX` for hex escape.
+      /// `\uXXXX` or `\u{XX?X?X?X?X?}` for Unicode hex escape.
+      if (code == $n) {
+        code = $LF;
+      } else if (code == $r) {
+        code = $CR;
+      } else if (code == $f) {
+        code = $FF;
+      } else if (code == $b) {
+        code = $BS;
+      } else if (code == $t) {
+        code = $TAB;
+      } else if (code == $v) {
+        code = $VTAB;
+      } else if (code == $x) {
+        // Expect exactly 2 hex digits.
+        if (codeUnits.length <= i + 2) return error(i, incompleteSequence);
+        code = 0;
+        for (int j = 0; j < 2; j++) {
+          int digit = codeUnits[++i];
+          if (!isHexDigit(digit)) return error(i, invalidCharacter);
+          code = (code << 4) + hexDigitValue(digit);
+        }
+      } else if (code == $u) {
+        if (codeUnits.length == i + 1) return error(i, incompleteSequence);
+        code = codeUnits[i + 1];
+        if (code == $OPEN_CURLY_BRACKET) {
+          // Expect 1-6 hex digits followed by '}'.
+          if (codeUnits.length == ++i) return error(i, incompleteSequence);
+          code = 0;
+          for (int j = 0; j < 7; j++) {
+            if (codeUnits.length == ++i) return error(i, incompleteSequence);
+            int digit = codeUnits[i];
+            if (j != 0 && digit == $CLOSE_CURLY_BRACKET) break;
+            if (!isHexDigit(digit)) return error(i, invalidCharacter);
+            code = (code << 4) + hexDigitValue(digit);
+          }
+        } else {
+          // Expect exactly 4 hex digits.
+          if (codeUnits.length <= i + 4) return error(i, incompleteSequence);
+          code = 0;
+          for (int j = 0; j < 4; j++) {
+            int digit = codeUnits[++i];
+            if (!isHexDigit(digit)) return error(i, invalidCharacter);
+            code = (code << 4) + hexDigitValue(digit);
+          }
+        }
+      } else {
+        // Nothing, escaped character is passed through;
+      }
+      if (code > 0x10FFFF) return error(i, invalidCodePoint);
+    }
+    result[resultOffset++] = code;
+  }
+  return new String.fromCharCodes(result, 0, resultOffset);
+}
diff --git a/pkg/front_end/lib/src/fasta/run.dart b/pkg/front_end/lib/src/fasta/run.dart
new file mode 100644
index 0000000..5543e91
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/run.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+library fasta.run;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    stdout;
+
+import 'package:testing/testing.dart' show
+    StdioProcess;
+
+import 'testing/kernel_chain.dart' show
+    computeDartVm,
+    computePatchedSdk;
+
+import 'compiler_command_line.dart' show
+    CompilerCommandLine;
+
+Future<int> run(Uri uri, CompilerCommandLine cl) async {
+  Uri sdk = await computePatchedSdk();
+  Uri dartVm = computeDartVm(sdk);
+  List<String> arguments = <String>["${uri.toFilePath()}"]
+      ..addAll(cl.arguments.skip(1));
+  if (cl.verbose) {
+    print("Running ${dartVm.toFilePath()} ${arguments.join(' ')}");
+  }
+  StdioProcess result = await StdioProcess.run(dartVm.toFilePath(), arguments);
+  stdout.write(result.output);
+  return result.exitCode;
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner.dart b/pkg/front_end/lib/src/fasta/scanner.dart
new file mode 100644
index 0000000..903fec2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+library fasta.scanner;
+
+import 'dart:convert' show
+    UNICODE_REPLACEMENT_CHARACTER_RUNE;
+
+import 'scanner/token.dart' show
+    Token;
+
+import 'scanner/utf8_bytes_scanner.dart' show
+    Utf8BytesScanner;
+
+import 'scanner/recover.dart' show
+    defaultRecoveryStrategy;
+
+export 'scanner/token.dart' show
+    BeginGroupToken,
+    KeywordToken,
+    StringToken,
+    SymbolToken,
+    Token,
+    isBinaryOperator,
+    isMinusOperator,
+    isTernaryOperator,
+    isUnaryOperator,
+    isUserDefinableOperator;
+
+export 'scanner/error_token.dart' show
+    ErrorToken,
+    buildUnexpectedCharacterToken;
+
+export 'scanner/token_constants.dart' show
+    EOF_TOKEN;
+
+export 'scanner/utf8_bytes_scanner.dart' show
+    Utf8BytesScanner;
+
+export 'scanner/string_scanner.dart' show
+    StringScanner;
+
+export 'scanner/keyword.dart' show
+    Keyword;
+
+const int unicodeReplacementCharacter = UNICODE_REPLACEMENT_CHARACTER_RUNE;
+
+typedef Token Recover(List<int> bytes, Token tokens, List<int> lineStarts);
+
+abstract class Scanner {
+  /// Returns true if an error occured during [tokenize].
+  bool get hasErrors;
+
+  List<int> get lineStarts;
+
+  Token tokenize();
+}
+
+class ScannerResult {
+  final Token tokens;
+  final List<int> lineStarts;
+
+  ScannerResult(this.tokens, this.lineStarts);
+}
+
+ScannerResult scan(List<int> bytes,
+    {bool includeComments: false, Recover recover}) {
+  if (bytes.last != 0) {
+    throw new ArgumentError("[bytes]: the last byte must be null.");
+  }
+  Scanner scanner =
+      new Utf8BytesScanner(bytes, includeComments: includeComments);
+  Token tokens = scanner.tokenize();
+  if (scanner.hasErrors) {
+    recover ??= defaultRecoveryStrategy;
+    tokens = recover(bytes, tokens, scanner.lineStarts);
+  }
+  return new ScannerResult(tokens, scanner.lineStarts);
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
new file mode 100644
index 0000000..f4de827
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -0,0 +1,1167 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scanner.abstract_scanner;
+
+import '../scanner.dart' show
+    ErrorToken,
+    Scanner,
+    buildUnexpectedCharacterToken;
+
+import 'error_token.dart' show
+    UnmatchedToken,
+    UnterminatedToken;
+
+import 'keyword.dart' show
+    KeywordState,
+    Keyword;
+
+import 'precedence.dart';
+
+import 'token.dart' show
+    BeginGroupToken,
+    KeywordToken,
+    SymbolToken,
+    Token;
+
+import 'token_constants.dart';
+
+import 'characters.dart';
+
+abstract class AbstractScanner implements Scanner {
+  final bool includeComments;
+
+  /**
+   * The string offset for the next token that will be created.
+   *
+   * Note that in the [Utf8BytesScanner], [stringOffset] and [scanOffset] values
+   * are different. One string character can be encoded using multiple UTF-8
+   * bytes.
+   */
+  int tokenStart = -1;
+
+  /**
+   * A pointer to the token stream created by this scanner. The first token
+   * is a special token and not part of the source file. This is an
+   * implementation detail to avoids special cases in the scanner. This token
+   * is not exposed to clients of the scanner, which are expected to invoke
+   * [firstToken] to access the token stream.
+   */
+  final Token tokens = new SymbolToken(EOF_INFO, -1);
+
+  /**
+   * A pointer to the last scanned token.
+   */
+  Token tail;
+
+  final List<int> lineStarts = <int>[0];
+
+  AbstractScanner(this.includeComments) {
+    this.tail = this.tokens;
+  }
+
+  /**
+   * Advances and returns the next character.
+   *
+   * If the next character is non-ASCII, then the returned value depends on the
+   * scanner implementation. The [Utf8BytesScanner] returns a UTF-8 byte, while
+   * the [StringScanner] returns a UTF-16 code unit.
+   *
+   * The scanner ensures that [advance] is not invoked after it returned [$EOF].
+   * This allows implementations to omit bound checks if the data structure ends
+   * with '0'.
+   */
+  int advance();
+
+  /**
+   * Returns the current unicode character.
+   *
+   * If the current character is ASCII, then it is returned unchanged.
+   *
+   * The [Utf8BytesScanner] decodes the next unicode code point starting at the
+   * current position. Note that every unicode character is returned as a single
+   * code point, that is, for '\u{1d11e}' it returns 119070, and the following
+   * [advance] returns the next character.
+   *
+   * The [StringScanner] returns the current character unchanged, which might
+   * be a surrogate character. In the case of '\u{1d11e}', it returns the first
+   * code unit 55348, and the following [advance] returns the second code unit
+   * 56606.
+   *
+   * Invoking [currentAsUnicode] multiple times is safe, i.e.,
+   * [:currentAsUnicode(next) == currentAsUnicode(currentAsUnicode(next)):].
+   */
+  int currentAsUnicode(int next);
+
+  /**
+   * Returns the character at the next poisition. Like in [advance], the
+   * [Utf8BytesScanner] returns a UTF-8 byte, while the [StringScanner] returns
+   * a UTF-16 code unit.
+   */
+  int peek();
+
+  /**
+   * Notifies the scanner that unicode characters were detected in either a
+   * comment or a string literal between [startScanOffset] and the current
+   * scan offset.
+   */
+  void handleUnicode(int startScanOffset);
+
+  /**
+   * Returns the current scan offset.
+   *
+   * In the [Utf8BytesScanner] this is the offset into the byte list, in the
+   * [StringScanner] the offset in the source string.
+   */
+  int get scanOffset;
+
+  /**
+   * Returns the current string offset.
+   *
+   * In the [StringScanner] this is identical to the [scanOffset]. In the
+   * [Utf8BytesScanner] it is computed based on encountered UTF-8 characters.
+   */
+  int get stringOffset;
+
+  /**
+   * Returns the first token scanned by this [Scanner].
+   */
+  Token firstToken();
+
+  /**
+   * Returns the last token scanned by this [Scanner].
+   */
+  Token previousToken();
+
+  /**
+   * Notifies that a new token starts at current offset.
+   */
+  void beginToken() {
+    tokenStart = stringOffset;
+  }
+
+  /**
+   * Appends a substring from the scan offset [:start:] to the current
+   * [:scanOffset:] plus the [:extraOffset:]. For example, if the current
+   * scanOffset is 10, then [:appendSubstringToken(5, -1):] will append the
+   * substring string [5,9).
+   *
+   * Note that [extraOffset] can only be used if the covered character(s) are
+   * known to be ASCII.
+   */
+  void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
+      [int extraOffset]);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendPrecedenceToken(PrecedenceInfo info);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  int select(int choice, PrecedenceInfo yes, PrecedenceInfo no);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendKeywordToken(Keyword keyword);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendEofToken();
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendWhiteSpace(int next);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void lineFeedInMultiline();
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendBeginGroup(PrecedenceInfo info);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  int appendEndGroup(PrecedenceInfo info, int openKind);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendGt(PrecedenceInfo info);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendGtGt(PrecedenceInfo info);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void appendComment(start, bool asciiOnly);
+
+  /// Append [token] to the token stream.
+  void appendErrorToken(ErrorToken token);
+
+  /** Documentation in subclass [ArrayBasedScanner]. */
+  void discardOpenLt();
+
+  /// Return true when at EOF.
+  bool atEndOfFile();
+
+  Token tokenize() {
+    while (!atEndOfFile()) {
+      int next = advance();
+      while (!identical(next, $EOF)) {
+        next = bigSwitch(next);
+      }
+      if (atEndOfFile()) {
+        appendEofToken();
+      } else {
+        unexpected($EOF);
+      }
+    }
+
+    // Always pretend that there's a line at the end of the file.
+    lineStarts.add(stringOffset + 1);
+
+    return firstToken();
+  }
+
+  int bigSwitch(int next) {
+    beginToken();
+    if (identical(next, $SPACE) ||
+        identical(next, $TAB) ||
+        identical(next, $LF) ||
+        identical(next, $CR)) {
+      appendWhiteSpace(next);
+      next = advance();
+      // Sequences of spaces are common, so advance through them fast.
+      while (identical(next, $SPACE)) {
+        // We don't invoke [:appendWhiteSpace(next):] here for efficiency,
+        // assuming that it does not do anything for space characters.
+        next = advance();
+      }
+      return next;
+    }
+
+    if ($a <= next && next <= $z) {
+      if (identical($r, next)) {
+        return tokenizeRawStringKeywordOrIdentifier(next);
+      }
+      return tokenizeKeywordOrIdentifier(next, true);
+    }
+
+    if (($A <= next && next <= $Z) ||
+        identical(next, $_) ||
+        identical(next, $$)) {
+      return tokenizeIdentifier(next, scanOffset, true);
+    }
+
+    if (identical(next, $LT)) {
+      return tokenizeLessThan(next);
+    }
+
+    if (identical(next, $GT)) {
+      return tokenizeGreaterThan(next);
+    }
+
+    if (identical(next, $EQ)) {
+      return tokenizeEquals(next);
+    }
+
+    if (identical(next, $BANG)) {
+      return tokenizeExclamation(next);
+    }
+
+    if (identical(next, $PLUS)) {
+      return tokenizePlus(next);
+    }
+
+    if (identical(next, $MINUS)) {
+      return tokenizeMinus(next);
+    }
+
+    if (identical(next, $STAR)) {
+      return tokenizeMultiply(next);
+    }
+
+    if (identical(next, $PERCENT)) {
+      return tokenizePercent(next);
+    }
+
+    if (identical(next, $AMPERSAND)) {
+      return tokenizeAmpersand(next);
+    }
+
+    if (identical(next, $BAR)) {
+      return tokenizeBar(next);
+    }
+
+    if (identical(next, $CARET)) {
+      return tokenizeCaret(next);
+    }
+
+    if (identical(next, $OPEN_SQUARE_BRACKET)) {
+      return tokenizeOpenSquareBracket(next);
+    }
+
+    if (identical(next, $TILDE)) {
+      return tokenizeTilde(next);
+    }
+
+    if (identical(next, $BACKSLASH)) {
+      appendPrecedenceToken(BACKSLASH_INFO);
+      return advance();
+    }
+
+    if (identical(next, $HASH)) {
+      return tokenizeTag(next);
+    }
+
+    if (identical(next, $OPEN_PAREN)) {
+      appendBeginGroup(OPEN_PAREN_INFO);
+      return advance();
+    }
+
+    if (identical(next, $CLOSE_PAREN)) {
+      return appendEndGroup(CLOSE_PAREN_INFO, OPEN_PAREN_TOKEN);
+    }
+
+    if (identical(next, $COMMA)) {
+      appendPrecedenceToken(COMMA_INFO);
+      return advance();
+    }
+
+    if (identical(next, $COLON)) {
+      appendPrecedenceToken(COLON_INFO);
+      return advance();
+    }
+
+    if (identical(next, $SEMICOLON)) {
+      appendPrecedenceToken(SEMICOLON_INFO);
+      // Type parameters and arguments cannot contain semicolon.
+      discardOpenLt();
+      return advance();
+    }
+
+    if (identical(next, $QUESTION)) {
+      return tokenizeQuestion(next);
+    }
+
+    if (identical(next, $CLOSE_SQUARE_BRACKET)) {
+      return appendEndGroup(
+          CLOSE_SQUARE_BRACKET_INFO, OPEN_SQUARE_BRACKET_TOKEN);
+    }
+
+    if (identical(next, $BACKPING)) {
+      appendPrecedenceToken(BACKPING_INFO);
+      return advance();
+    }
+
+    if (identical(next, $OPEN_CURLY_BRACKET)) {
+      appendBeginGroup(OPEN_CURLY_BRACKET_INFO);
+      return advance();
+    }
+
+    if (identical(next, $CLOSE_CURLY_BRACKET)) {
+      return appendEndGroup(CLOSE_CURLY_BRACKET_INFO, OPEN_CURLY_BRACKET_TOKEN);
+    }
+
+    if (identical(next, $SLASH)) {
+      return tokenizeSlashOrComment(next);
+    }
+
+    if (identical(next, $AT)) {
+      return tokenizeAt(next);
+    }
+
+    if (identical(next, $DQ) || identical(next, $SQ)) {
+      return tokenizeString(next, scanOffset, false);
+    }
+
+    if (identical(next, $PERIOD)) {
+      return tokenizeDotsOrNumber(next);
+    }
+
+    if (identical(next, $0)) {
+      return tokenizeHexOrNumber(next);
+    }
+
+    // TODO(ahe): Would a range check be faster?
+    if (identical(next, $1) ||
+        identical(next, $2) ||
+        identical(next, $3) ||
+        identical(next, $4) ||
+        identical(next, $5) ||
+        identical(next, $6) ||
+        identical(next, $7) ||
+        identical(next, $8) ||
+        identical(next, $9)) {
+      return tokenizeNumber(next);
+    }
+
+    if (identical(next, $EOF)) {
+      return $EOF;
+    }
+    if (next < 0x1f) {
+      return unexpected(next);
+    }
+
+    next = currentAsUnicode(next);
+
+    return unexpected(next);
+  }
+
+  int tokenizeTag(int next) {
+    // # or #!.*[\n\r]
+    if (scanOffset == 0) {
+      if (identical(peek(), $BANG)) {
+        int start = scanOffset + 1;
+        bool asciiOnly = true;
+        do {
+          next = advance();
+          if (next > 127) asciiOnly = false;
+        } while (!identical(next, $LF) &&
+            !identical(next, $CR) &&
+            !identical(next, $EOF));
+        if (!asciiOnly) handleUnicode(start);
+        return next;
+      }
+    }
+    appendPrecedenceToken(HASH_INFO);
+    return advance();
+  }
+
+  int tokenizeTilde(int next) {
+    // ~ ~/ ~/=
+    next = advance();
+    if (identical(next, $SLASH)) {
+      return select($EQ, TILDE_SLASH_EQ_INFO, TILDE_SLASH_INFO);
+    } else {
+      appendPrecedenceToken(TILDE_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeOpenSquareBracket(int next) {
+    // [ [] []=
+    next = advance();
+    if (identical(next, $CLOSE_SQUARE_BRACKET)) {
+      Token token = previousToken();
+      if (token is KeywordToken && token.keyword.syntax == 'operator' ||
+          token is SymbolToken && token.info == HASH_INFO) {
+        return select($EQ, INDEX_EQ_INFO, INDEX_INFO);
+      }
+    }
+    appendBeginGroup(OPEN_SQUARE_BRACKET_INFO);
+    return next;
+  }
+
+  int tokenizeCaret(int next) {
+    // ^ ^=
+    return select($EQ, CARET_EQ_INFO, CARET_INFO);
+  }
+
+  int tokenizeQuestion(int next) {
+    // ? ?. ?? ??=
+    next = advance();
+    if (identical(next, $QUESTION)) {
+      return select($EQ, QUESTION_QUESTION_EQ_INFO, QUESTION_QUESTION_INFO);
+    } else if (identical(next, $PERIOD)) {
+      appendPrecedenceToken(QUESTION_PERIOD_INFO);
+      return advance();
+    } else {
+      appendPrecedenceToken(QUESTION_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeBar(int next) {
+    // | || |=
+    next = advance();
+    if (identical(next, $BAR)) {
+      appendPrecedenceToken(BAR_BAR_INFO);
+      return advance();
+    } else if (identical(next, $EQ)) {
+      appendPrecedenceToken(BAR_EQ_INFO);
+      return advance();
+    } else {
+      appendPrecedenceToken(BAR_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeAmpersand(int next) {
+    // && &= &
+    next = advance();
+    if (identical(next, $AMPERSAND)) {
+      appendPrecedenceToken(AMPERSAND_AMPERSAND_INFO);
+      return advance();
+    } else if (identical(next, $EQ)) {
+      appendPrecedenceToken(AMPERSAND_EQ_INFO);
+      return advance();
+    } else {
+      appendPrecedenceToken(AMPERSAND_INFO);
+      return next;
+    }
+  }
+
+  int tokenizePercent(int next) {
+    // % %=
+    return select($EQ, PERCENT_EQ_INFO, PERCENT_INFO);
+  }
+
+  int tokenizeMultiply(int next) {
+    // * *=
+    return select($EQ, STAR_EQ_INFO, STAR_INFO);
+  }
+
+  int tokenizeMinus(int next) {
+    // - -- -=
+    next = advance();
+    if (identical(next, $MINUS)) {
+      appendPrecedenceToken(MINUS_MINUS_INFO);
+      return advance();
+    } else if (identical(next, $EQ)) {
+      appendPrecedenceToken(MINUS_EQ_INFO);
+      return advance();
+    } else {
+      appendPrecedenceToken(MINUS_INFO);
+      return next;
+    }
+  }
+
+  int tokenizePlus(int next) {
+    // + ++ +=
+    next = advance();
+    if (identical($PLUS, next)) {
+      appendPrecedenceToken(PLUS_PLUS_INFO);
+      return advance();
+    } else if (identical($EQ, next)) {
+      appendPrecedenceToken(PLUS_EQ_INFO);
+      return advance();
+    } else {
+      appendPrecedenceToken(PLUS_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeExclamation(int next) {
+    // ! !=
+    // !== is kept for user-friendly error reporting.
+
+    next = advance();
+    if (identical(next, $EQ)) {
+      return select($EQ, BANG_EQ_EQ_INFO, BANG_EQ_INFO);
+    }
+    appendPrecedenceToken(BANG_INFO);
+    return next;
+  }
+
+  int tokenizeEquals(int next) {
+    // = == =>
+    // === is kept for user-friendly error reporting.
+
+    // Type parameters and arguments cannot contain any token that
+    // starts with '='.
+    discardOpenLt();
+
+    next = advance();
+    if (identical(next, $EQ)) {
+      return select($EQ, EQ_EQ_EQ_INFO, EQ_EQ_INFO);
+    } else if (identical(next, $GT)) {
+      appendPrecedenceToken(FUNCTION_INFO);
+      return advance();
+    }
+    appendPrecedenceToken(EQ_INFO);
+    return next;
+  }
+
+  int tokenizeGreaterThan(int next) {
+    // > >= >> >>=
+    next = advance();
+    if (identical($EQ, next)) {
+      appendPrecedenceToken(GT_EQ_INFO);
+      return advance();
+    } else if (identical($GT, next)) {
+      next = advance();
+      if (identical($EQ, next)) {
+        appendPrecedenceToken(GT_GT_EQ_INFO);
+        return advance();
+      } else {
+        appendGtGt(GT_GT_INFO);
+        return next;
+      }
+    } else {
+      appendGt(GT_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeLessThan(int next) {
+    // < <= << <<=
+    next = advance();
+    if (identical($EQ, next)) {
+      appendPrecedenceToken(LT_EQ_INFO);
+      return advance();
+    } else if (identical($LT, next)) {
+      return select($EQ, LT_LT_EQ_INFO, LT_LT_INFO);
+    } else {
+      appendBeginGroup(LT_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeNumber(int next) {
+    int start = scanOffset;
+    while (true) {
+      next = advance();
+      if ($0 <= next && next <= $9) {
+        continue;
+      } else if (identical(next, $e) || identical(next, $E)) {
+        return tokenizeFractionPart(next, start);
+      } else {
+        if (identical(next, $PERIOD)) {
+          int nextnext = peek();
+          if ($0 <= nextnext && nextnext <= $9) {
+            return tokenizeFractionPart(advance(), start);
+          }
+        }
+        appendSubstringToken(INT_INFO, start, true);
+        return next;
+      }
+    }
+  }
+
+  int tokenizeHexOrNumber(int next) {
+    int x = peek();
+    if (identical(x, $x) || identical(x, $X)) {
+      return tokenizeHex(next);
+    }
+    return tokenizeNumber(next);
+  }
+
+  int tokenizeHex(int next) {
+    int start = scanOffset;
+    next = advance(); // Advance past the $x or $X.
+    bool hasDigits = false;
+    while (true) {
+      next = advance();
+      if (($0 <= next && next <= $9) ||
+          ($A <= next && next <= $F) ||
+          ($a <= next && next <= $f)) {
+        hasDigits = true;
+      } else {
+        if (!hasDigits) {
+          unterminated('0x', shouldAdvance: false);
+          return next;
+        }
+        appendSubstringToken(HEXADECIMAL_INFO, start, true);
+        return next;
+      }
+    }
+  }
+
+  int tokenizeDotsOrNumber(int next) {
+    int start = scanOffset;
+    next = advance();
+    if (($0 <= next && next <= $9)) {
+      return tokenizeFractionPart(next, start);
+    } else if (identical($PERIOD, next)) {
+      return select($PERIOD, PERIOD_PERIOD_PERIOD_INFO, PERIOD_PERIOD_INFO);
+    } else {
+      appendPrecedenceToken(PERIOD_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeFractionPart(int next, int start) {
+    bool done = false;
+    bool hasDigit = false;
+    LOOP:
+    while (!done) {
+      if ($0 <= next && next <= $9) {
+        hasDigit = true;
+      } else if (identical($e, next) || identical($E, next)) {
+        hasDigit = true;
+        next = advance();
+        if (identical(next, $PLUS) || identical(next, $MINUS)) {
+          next = advance();
+        }
+        bool hasExponentDigits = false;
+        while (true) {
+          if ($0 <= next && next <= $9) {
+            hasExponentDigits = true;
+          } else {
+            if (!hasExponentDigits) {
+              unterminated('1e', shouldAdvance: false);
+              return next;
+            }
+            break;
+          }
+          next = advance();
+        }
+
+        done = true;
+        continue LOOP;
+      } else {
+        done = true;
+        continue LOOP;
+      }
+      next = advance();
+    }
+    if (!hasDigit) {
+      // Reduce offset, we already advanced to the token past the period.
+      appendSubstringToken(INT_INFO, start, true, -1);
+
+      // TODO(ahe): Wrong offset for the period. Cannot call beginToken because
+      // the scanner already advanced past the period.
+      if (identical($PERIOD, next)) {
+        return select($PERIOD, PERIOD_PERIOD_PERIOD_INFO, PERIOD_PERIOD_INFO);
+      }
+      appendPrecedenceToken(PERIOD_INFO);
+      return next;
+    }
+    appendSubstringToken(DOUBLE_INFO, start, true);
+    return next;
+  }
+
+  int tokenizeSlashOrComment(int next) {
+    int start = scanOffset;
+    next = advance();
+    if (identical($STAR, next)) {
+      return tokenizeMultiLineComment(next, start);
+    } else if (identical($SLASH, next)) {
+      return tokenizeSingleLineComment(next, start);
+    } else if (identical($EQ, next)) {
+      appendPrecedenceToken(SLASH_EQ_INFO);
+      return advance();
+    } else {
+      appendPrecedenceToken(SLASH_INFO);
+      return next;
+    }
+  }
+
+  int tokenizeSingleLineComment(int next, int start) {
+    bool asciiOnly = true;
+    while (true) {
+      next = advance();
+      if (next > 127) asciiOnly = false;
+      if (identical($LF, next) ||
+          identical($CR, next) ||
+          identical($EOF, next)) {
+        if (!asciiOnly) handleUnicode(start);
+        appendComment(start, asciiOnly);
+        return next;
+      }
+    }
+  }
+
+  int tokenizeMultiLineComment(int next, int start) {
+    bool asciiOnlyComment = true; // Track if the entire comment is ASCII.
+    bool asciiOnlyLines = true; // Track ASCII since the last handleUnicode.
+    int unicodeStart = start;
+    int nesting = 1;
+    next = advance();
+    while (true) {
+      if (identical($EOF, next)) {
+        if (!asciiOnlyLines) handleUnicode(unicodeStart);
+        unterminated('/*');
+        break;
+      } else if (identical($STAR, next)) {
+        next = advance();
+        if (identical($SLASH, next)) {
+          --nesting;
+          if (0 == nesting) {
+            if (!asciiOnlyLines) handleUnicode(unicodeStart);
+            next = advance();
+            appendComment(start, asciiOnlyComment);
+            break;
+          } else {
+            next = advance();
+          }
+        }
+      } else if (identical($SLASH, next)) {
+        next = advance();
+        if (identical($STAR, next)) {
+          next = advance();
+          ++nesting;
+        }
+      } else if (identical(next, $LF)) {
+        if (!asciiOnlyLines) {
+          // Synchronize the string offset in the utf8 scanner.
+          handleUnicode(unicodeStart);
+          asciiOnlyLines = true;
+          unicodeStart = scanOffset;
+        }
+        lineFeedInMultiline();
+        next = advance();
+      } else {
+        if (next > 127) {
+          asciiOnlyLines = false;
+          asciiOnlyComment = false;
+        }
+        next = advance();
+      }
+    }
+    return next;
+  }
+
+  int tokenizeRawStringKeywordOrIdentifier(int next) {
+    // [next] is $r.
+    int nextnext = peek();
+    if (identical(nextnext, $DQ) || identical(nextnext, $SQ)) {
+      int start = scanOffset;
+      next = advance();
+      return tokenizeString(next, start, true);
+    }
+    return tokenizeKeywordOrIdentifier(next, true);
+  }
+
+  int tokenizeKeywordOrIdentifier(int next, bool allowDollar) {
+    KeywordState state = KeywordState.KEYWORD_STATE;
+    int start = scanOffset;
+    while (state != null && $a <= next && next <= $z) {
+      state = state.next(next);
+      next = advance();
+    }
+    if (state == null || state.keyword == null) {
+      return tokenizeIdentifier(next, start, allowDollar);
+    }
+    if (($A <= next && next <= $Z) ||
+        ($0 <= next && next <= $9) ||
+        identical(next, $_) ||
+        identical(next, $$)) {
+      return tokenizeIdentifier(next, start, allowDollar);
+    } else {
+      appendKeywordToken(state.keyword);
+      return next;
+    }
+  }
+
+  /**
+   * [allowDollar] can exclude '$', which is not allowed as part of a string
+   * interpolation identifier.
+   */
+  int tokenizeIdentifier(int next, int start, bool allowDollar) {
+    while (true) {
+      if (($a <= next && next <= $z) ||
+          ($A <= next && next <= $Z) ||
+          ($0 <= next && next <= $9) ||
+          identical(next, $_) ||
+          (identical(next, $$) && allowDollar)) {
+        next = advance();
+      } else {
+        // Identifier ends here.
+        if (start == scanOffset) {
+          return unexpected(next);
+        } else {
+          appendSubstringToken(IDENTIFIER_INFO, start, true);
+        }
+        break;
+      }
+    }
+    return next;
+  }
+
+  int tokenizeAt(int next) {
+    appendPrecedenceToken(AT_INFO);
+    return advance();
+  }
+
+  int tokenizeString(int next, int start, bool raw) {
+    int quoteChar = next;
+    next = advance();
+    if (identical(quoteChar, next)) {
+      next = advance();
+      if (identical(quoteChar, next)) {
+        // Multiline string.
+        return tokenizeMultiLineString(quoteChar, start, raw);
+      } else {
+        // Empty string.
+        appendSubstringToken(STRING_INFO, start, true);
+        return next;
+      }
+    }
+    if (raw) {
+      return tokenizeSingleLineRawString(next, quoteChar, start);
+    } else {
+      return tokenizeSingleLineString(next, quoteChar, start);
+    }
+  }
+
+  /**
+   * [next] is the first character after the quote.
+   * [start] is the scanOffset of the quote.
+   *
+   * The token contains a substring of the source file, including the
+   * string quotes, backslashes for escaping. For interpolated strings,
+   * the parts before and after are separate tokens.
+   *
+   *   "a $b c"
+   *
+   * gives StringToken("a $), StringToken(b) and StringToken( c").
+   */
+  int tokenizeSingleLineString(int next, int quoteChar, int start) {
+    bool asciiOnly = true;
+    while (!identical(next, quoteChar)) {
+      if (identical(next, $BACKSLASH)) {
+        next = advance();
+      } else if (identical(next, $$)) {
+        if (!asciiOnly) handleUnicode(start);
+        next = tokenizeStringInterpolation(start, asciiOnly);
+        start = scanOffset;
+        asciiOnly = true;
+        continue;
+      }
+      if (next <= $CR &&
+          (identical(next, $LF) ||
+              identical(next, $CR) ||
+              identical(next, $EOF))) {
+        if (!asciiOnly) handleUnicode(start);
+        return unterminatedString(quoteChar);
+      }
+      if (next > 127) asciiOnly = false;
+      next = advance();
+    }
+    if (!asciiOnly) handleUnicode(start);
+    // Advance past the quote character.
+    next = advance();
+    appendSubstringToken(STRING_INFO, start, asciiOnly);
+    return next;
+  }
+
+  int tokenizeStringInterpolation(int start, bool asciiOnly) {
+    appendSubstringToken(STRING_INFO, start, asciiOnly);
+    beginToken(); // $ starts here.
+    int next = advance();
+    if (identical(next, $OPEN_CURLY_BRACKET)) {
+      return tokenizeInterpolatedExpression(next);
+    } else {
+      return tokenizeInterpolatedIdentifier(next);
+    }
+  }
+
+  int tokenizeInterpolatedExpression(int next) {
+    appendBeginGroup(STRING_INTERPOLATION_INFO);
+    beginToken(); // The expression starts here.
+    next = advance(); // Move past the curly bracket.
+    while (!identical(next, $EOF) && !identical(next, $STX)) {
+      next = bigSwitch(next);
+    }
+    if (identical(next, $EOF)) return next;
+    next = advance(); // Move past the $STX.
+    beginToken(); // The string interpolation suffix starts here.
+    return next;
+  }
+
+  int tokenizeInterpolatedIdentifier(int next) {
+    appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO);
+
+    if ($a <= next && next <= $z) {
+      beginToken(); // The identifier starts here.
+      next = tokenizeKeywordOrIdentifier(next, false);
+    } else if (($A <= next && next <= $Z) || identical(next, $_)) {
+      beginToken(); // The identifier starts here.
+      next = tokenizeIdentifier(next, scanOffset, false);
+    } else {
+      unterminated(r'$', shouldAdvance: false);
+    }
+    beginToken(); // The string interpolation suffix starts here.
+    return next;
+  }
+
+  int tokenizeSingleLineRawString(int next, int quoteChar, int start) {
+    bool asciiOnly = true;
+    while (next != $EOF) {
+      if (identical(next, quoteChar)) {
+        if (!asciiOnly) handleUnicode(start);
+        next = advance();
+        appendSubstringToken(STRING_INFO, start, asciiOnly);
+        return next;
+      } else if (identical(next, $LF) || identical(next, $CR)) {
+        if (!asciiOnly) handleUnicode(start);
+        return unterminatedRawString(quoteChar);
+      } else if (next > 127) {
+        asciiOnly = false;
+      }
+      next = advance();
+    }
+    if (!asciiOnly) handleUnicode(start);
+    return unterminatedRawString(quoteChar);
+  }
+
+  int tokenizeMultiLineRawString(int quoteChar, int start) {
+    bool asciiOnlyString = true;
+    bool asciiOnlyLine = true;
+    int unicodeStart = start;
+    int next = advance(); // Advance past the (last) quote (of three).
+    outer:
+    while (!identical(next, $EOF)) {
+      while (!identical(next, quoteChar)) {
+        if (identical(next, $LF)) {
+          if (!asciiOnlyLine) {
+            // Synchronize the string offset in the utf8 scanner.
+            handleUnicode(unicodeStart);
+            asciiOnlyLine = true;
+            unicodeStart = scanOffset;
+          }
+          lineFeedInMultiline();
+        } else if (next > 127) {
+          asciiOnlyLine = false;
+          asciiOnlyString = false;
+        }
+        next = advance();
+        if (identical(next, $EOF)) break outer;
+      }
+      next = advance();
+      if (identical(next, quoteChar)) {
+        next = advance();
+        if (identical(next, quoteChar)) {
+          if (!asciiOnlyLine) handleUnicode(unicodeStart);
+          next = advance();
+          appendSubstringToken(STRING_INFO, start, asciiOnlyString);
+          return next;
+        }
+      }
+    }
+    if (!asciiOnlyLine) handleUnicode(unicodeStart);
+    return unterminatedRawMultiLineString(quoteChar);
+  }
+
+  int tokenizeMultiLineString(int quoteChar, int start, bool raw) {
+    if (raw) return tokenizeMultiLineRawString(quoteChar, start);
+    bool asciiOnlyString = true;
+    bool asciiOnlyLine = true;
+    int unicodeStart = start;
+    int next = advance(); // Advance past the (last) quote (of three).
+    while (!identical(next, $EOF)) {
+      if (identical(next, $$)) {
+        if (!asciiOnlyLine) handleUnicode(unicodeStart);
+        next = tokenizeStringInterpolation(start, asciiOnlyString);
+        start = scanOffset;
+        unicodeStart = start;
+        asciiOnlyString = true; // A new string token is created for the rest.
+        asciiOnlyLine = true;
+        continue;
+      }
+      if (identical(next, quoteChar)) {
+        next = advance();
+        if (identical(next, quoteChar)) {
+          next = advance();
+          if (identical(next, quoteChar)) {
+            if (!asciiOnlyLine) handleUnicode(unicodeStart);
+            next = advance();
+            appendSubstringToken(STRING_INFO, start, asciiOnlyString);
+            return next;
+          }
+        }
+        continue;
+      }
+      if (identical(next, $BACKSLASH)) {
+        next = advance();
+        if (identical(next, $EOF)) break;
+      }
+      if (identical(next, $LF)) {
+        if (!asciiOnlyLine) {
+          // Synchronize the string offset in the utf8 scanner.
+          handleUnicode(unicodeStart);
+          asciiOnlyLine = true;
+          unicodeStart = scanOffset;
+        }
+        lineFeedInMultiline();
+      } else if (next > 127) {
+        asciiOnlyString = false;
+        asciiOnlyLine = false;
+      }
+      next = advance();
+    }
+    if (!asciiOnlyLine) handleUnicode(unicodeStart);
+    return unterminatedMultiLineString(quoteChar);
+  }
+
+  int unexpected(int character) {
+    appendErrorToken(buildUnexpectedCharacterToken(character, tokenStart));
+    return advanceAfterError(true);
+  }
+
+  int unterminated(String prefix, {bool shouldAdvance: true}) {
+    appendErrorToken(new UnterminatedToken(prefix, tokenStart, stringOffset));
+    return advanceAfterError(shouldAdvance);
+  }
+
+  int unterminatedString(int quoteChar) {
+    return unterminated(new String.fromCharCodes([quoteChar]));
+  }
+
+  int unterminatedRawString(int quoteChar) {
+    return unterminated('r${new String.fromCharCodes([quoteChar])}');
+  }
+
+  int unterminatedMultiLineString(int quoteChar) {
+    return unterminated(
+        new String.fromCharCodes([quoteChar, quoteChar, quoteChar]));
+  }
+
+  int unterminatedRawMultiLineString(int quoteChar) {
+    return unterminated(
+        'r${new String.fromCharCodes([quoteChar, quoteChar, quoteChar])}');
+  }
+
+  int advanceAfterError(bool shouldAdvance) {
+    if (atEndOfFile()) return $EOF;
+    if (shouldAdvance) {
+      return advance(); // Ensure progress.
+    } else {
+      return -1;
+    }
+  }
+
+  void unmatchedBeginGroup(BeginGroupToken begin) {
+    // We want to ensure that unmatched BeginGroupTokens are reported as
+    // errors.  However, the diet parser assumes that groups are well-balanced
+    // and will never look at the endGroup token.  This is a nice property that
+    // allows us to skip quickly over correct code. By inserting an additional
+    // synthetic token in the stream, we can keep ignoring endGroup tokens.
+    //
+    // [begin] --next--> [tail]
+    // [begin] --endG--> [synthetic] --next--> [next] --next--> [tail]
+    //
+    // This allows the diet parser to skip from [begin] via endGroup to
+    // [synthetic] and ignore the [synthetic] token (assuming it's correct),
+    // then the error will be reported when parsing the [next] token.
+    //
+    // For example, tokenize("{[1};") produces:
+    //
+    // SymbolToken({) --endGroup-----+
+    //      |                        |
+    //     next                      |
+    //      v                        |
+    // SymbolToken([) --endGroup--+  |
+    //      |                     |  |
+    //     next                   |  |
+    //      v                     |  |
+    // StringToken(1)             |  |
+    //      |                     v  |
+    //     next       SymbolToken(]) | <- Synthetic token.
+    //      |                     |  |
+    //      |                   next |
+    //      v                     |  |
+    // UnmatchedToken([)<---------+  |
+    //      |                        |
+    //     next                      |
+    //      v                        |
+    // SymbolToken(})<---------------+
+    //      |
+    //     next
+    //      v
+    // SymbolToken(;)
+    //      |
+    //     next
+    //      v
+    //     EOF
+    Token synthetic =
+        new SymbolToken(closeBraceInfoFor(begin), begin.charOffset);
+    UnmatchedToken next = new UnmatchedToken(begin);
+    begin.endGroup = synthetic;
+    synthetic.next = next;
+    appendErrorToken(next);
+  }
+}
+
+PrecedenceInfo closeBraceInfoFor(BeginGroupToken begin) {
+  return const {
+    '(': CLOSE_PAREN_INFO,
+    '[': CLOSE_SQUARE_BRACKET_INFO,
+    '{': CLOSE_CURLY_BRACKET_INFO,
+    '<': GT_INFO,
+    r'${': CLOSE_CURLY_BRACKET_INFO,
+  }[begin.value];
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart
new file mode 100644
index 0000000..b1da92b
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart
@@ -0,0 +1,253 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scanner.array_based_scanner;
+
+import 'error_token.dart' show
+    ErrorToken;
+
+import 'keyword.dart' show
+    Keyword;
+
+import 'precedence.dart' show
+    COMMENT_INFO,
+    EOF_INFO,
+    PrecedenceInfo;
+
+import 'token.dart' show
+    BeginGroupToken,
+    KeywordToken,
+    SymbolToken,
+    Token;
+
+import 'token_constants.dart' show
+    LT_TOKEN,
+    OPEN_CURLY_BRACKET_TOKEN,
+    STRING_INTERPOLATION_TOKEN;
+
+import 'characters.dart' show
+    $LF,
+    $STX;
+
+import 'abstract_scanner.dart' show
+    AbstractScanner;
+
+import 'package:front_end/src/fasta/util/link.dart' show
+    Link;
+
+abstract class ArrayBasedScanner extends AbstractScanner {
+  bool hasErrors = false;
+
+  ArrayBasedScanner(bool includeComments)
+      : super(includeComments);
+
+  /**
+   * The stack of open groups, e.g [: { ... ( .. :]
+   * Each BeginGroupToken has a pointer to the token where the group
+   * ends. This field is set when scanning the end group token.
+   */
+  Link<BeginGroupToken> groupingStack = const Link<BeginGroupToken>();
+
+  /**
+   * Appends a fixed token whose kind and content is determined by [info].
+   * Appends an *operator* token from [info].
+   *
+   * An operator token represent operators like ':', '.', ';', '&&', '==', '--',
+   * '=>', etc.
+   */
+  void appendPrecedenceToken(PrecedenceInfo info) {
+    tail.next = new SymbolToken(info, tokenStart);
+    tail = tail.next;
+  }
+
+  /**
+   * Appends a fixed token based on whether the current char is [choice] or not.
+   * If the current char is [choice] a fixed token whose kind and content
+   * is determined by [yes] is appended, otherwise a fixed token whose kind
+   * and content is determined by [no] is appended.
+   */
+  int select(int choice, PrecedenceInfo yes, PrecedenceInfo no) {
+    int next = advance();
+    if (identical(next, choice)) {
+      appendPrecedenceToken(yes);
+      return advance();
+    } else {
+      appendPrecedenceToken(no);
+      return next;
+    }
+  }
+
+  /**
+   * Appends a keyword token whose kind is determined by [keyword].
+   */
+  void appendKeywordToken(Keyword keyword) {
+    String syntax = keyword.syntax;
+    // Type parameters and arguments cannot contain 'this'.
+    if (identical(syntax, 'this')) {
+      discardOpenLt();
+    }
+    tail.next = new KeywordToken(keyword, tokenStart);
+    tail = tail.next;
+  }
+
+  void appendEofToken() {
+    beginToken();
+    discardOpenLt();
+    while (!groupingStack.isEmpty) {
+      unmatchedBeginGroup(groupingStack.head);
+      groupingStack = groupingStack.tail;
+    }
+    tail.next = new SymbolToken(EOF_INFO, tokenStart);
+    tail = tail.next;
+    // EOF points to itself so there's always infinite look-ahead.
+    tail.next = tail;
+  }
+
+  /**
+   * Notifies scanning a whitespace character. Note that [appendWhiteSpace] is
+   * not always invoked for [$SPACE] characters.
+   *
+   * This method is used by the scanners to track line breaks and create the
+   * [lineStarts] map.
+   */
+  void appendWhiteSpace(int next) {
+    if (next == $LF) {
+      lineStarts.add(stringOffset + 1); // +1, the line starts after the $LF.
+    }
+  }
+
+  /**
+   * Notifies on [$LF] characters in multi-line comments or strings.
+   *
+   * This method is used by the scanners to track line breaks and create the
+   * [lineStarts] map.
+   */
+  void lineFeedInMultiline() {
+    lineStarts.add(stringOffset + 1);
+  }
+
+  /**
+   * Appends a token that begins a new group, represented by [value].
+   * Group begin tokens are '{', '(', '[' and '${'.
+   */
+  void appendBeginGroup(PrecedenceInfo info) {
+    Token token = new BeginGroupToken(info, tokenStart);
+    tail.next = token;
+    tail = tail.next;
+
+    // { (  [ ${ cannot appear inside a type parameters / arguments.
+    if (!identical(info.kind, LT_TOKEN)) discardOpenLt();
+    groupingStack = groupingStack.prepend(token);
+  }
+
+  /**
+   * Appends a token that begins an end group, represented by [value].
+   * It handles the group end tokens '}', ')' and ']'. The tokens '>' and
+   * '>>' are handled separately bo [appendGt] and [appendGtGt].
+   */
+  int appendEndGroup(PrecedenceInfo info, int openKind) {
+    assert(!identical(openKind, LT_TOKEN)); // openKind is < for > and >>
+    discardBeginGroupUntil(openKind);
+    appendPrecedenceToken(info);
+    Token close = tail;
+    if (groupingStack.isEmpty) {
+      return advance();
+    }
+    BeginGroupToken begin = groupingStack.head;
+    if (!identical(begin.kind, openKind)) {
+      assert(begin.kind == STRING_INTERPOLATION_TOKEN &&
+          openKind == OPEN_CURLY_BRACKET_TOKEN);
+      // We're ending an interpolated expression.
+      begin.endGroup = close;
+      groupingStack = groupingStack.tail;
+      // Using "start-of-text" to signal that we're back in string
+      // scanning mode.
+      return $STX;
+    }
+    begin.endGroup = close;
+    groupingStack = groupingStack.tail;
+    return advance();
+  }
+
+  /**
+   * Discards begin group tokens until a match with [openKind] is found.
+   * This recovers nicely from from a situation like "{[}".
+   */
+  void discardBeginGroupUntil(int openKind) {
+    while (!groupingStack.isEmpty) {
+      // Don't report unmatched errors for <; it is also the less-than operator.
+      discardOpenLt();
+      if (groupingStack.isEmpty) return;
+      BeginGroupToken begin = groupingStack.head;
+      if (openKind == begin.kind) return;
+      if (openKind == OPEN_CURLY_BRACKET_TOKEN &&
+          begin.kind == STRING_INTERPOLATION_TOKEN) return;
+      unmatchedBeginGroup(begin);
+      groupingStack = groupingStack.tail;
+    }
+  }
+
+  /**
+   * Appends a token for '>'.
+   * This method does not issue unmatched errors, because > is also the
+   * greater-than operator. It does not necessarily have to close a group.
+   */
+  void appendGt(PrecedenceInfo info) {
+    appendPrecedenceToken(info);
+    if (groupingStack.isEmpty) return;
+    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+      groupingStack.head.endGroup = tail;
+      groupingStack = groupingStack.tail;
+    }
+  }
+
+  /**
+   * Appends a token for '>>'.
+   * This method does not issue unmatched errors, because >> is also the
+   * shift operator. It does not necessarily have to close a group.
+   */
+  void appendGtGt(PrecedenceInfo info) {
+    appendPrecedenceToken(info);
+    if (groupingStack.isEmpty) return;
+    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+      // Don't assign endGroup: in "T<U<V>>", the '>>' token closes the outer
+      // '<', the inner '<' is left without endGroup.
+      groupingStack = groupingStack.tail;
+    }
+    if (groupingStack.isEmpty) return;
+    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+      groupingStack.head.endGroup = tail;
+      groupingStack = groupingStack.tail;
+    }
+  }
+
+  void appendComment(start, bool asciiOnly) {
+    if (!includeComments) return;
+    appendSubstringToken(COMMENT_INFO, start, asciiOnly);
+  }
+
+  void appendErrorToken(ErrorToken token) {
+    hasErrors = true;
+    tail.next = token;
+    tail = token;
+  }
+
+  /**
+   * This method is called to discard '<' from the "grouping" stack.
+   *
+   * [PartialParser.skipExpression] relies on the fact that we do not
+   * create groups for stuff like:
+   * [:a = b < c, d = e > f:].
+   *
+   * In other words, this method is called when the scanner recognizes
+   * something which cannot possibly be part of a type parameter/argument
+   * list, like the '=' in the above example.
+   */
+  void discardOpenLt() {
+    while (!groupingStack.isEmpty &&
+        identical(groupingStack.head.kind, LT_TOKEN)) {
+      groupingStack = groupingStack.tail;
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/bin/scanner.dart b/pkg/front_end/lib/src/fasta/scanner/bin/scanner.dart
new file mode 100644
index 0000000..4d46811
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/bin/scanner.dart
@@ -0,0 +1,7 @@
+// 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.
+
+import 'package:front_end/src/fasta/scanner/main.dart' as dart_scanner;
+
+main(List<String> arguments) => dart_scanner.main(arguments);
diff --git a/pkg/front_end/lib/src/fasta/scanner/characters.dart b/pkg/front_end/lib/src/fasta/scanner/characters.dart
new file mode 100644
index 0000000..e9f1e6f
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/characters.dart
@@ -0,0 +1,143 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scanner.characters;
+
+const int $EOF = 0;
+const int $STX = 2;
+const int $BS = 8;
+const int $TAB = 9;
+const int $LF = 10;
+const int $VTAB = 11;
+const int $FF = 12;
+const int $CR = 13;
+const int $SPACE = 32;
+const int $BANG = 33;
+const int $DQ = 34;
+const int $HASH = 35;
+const int $$ = 36;
+const int $PERCENT = 37;
+const int $AMPERSAND = 38;
+const int $SQ = 39;
+const int $OPEN_PAREN = 40;
+const int $CLOSE_PAREN = 41;
+const int $STAR = 42;
+const int $PLUS = 43;
+const int $COMMA = 44;
+const int $MINUS = 45;
+const int $PERIOD = 46;
+const int $SLASH = 47;
+const int $0 = 48;
+const int $1 = 49;
+const int $2 = 50;
+const int $3 = 51;
+const int $4 = 52;
+const int $5 = 53;
+const int $6 = 54;
+const int $7 = 55;
+const int $8 = 56;
+const int $9 = 57;
+const int $COLON = 58;
+const int $SEMICOLON = 59;
+const int $LT = 60;
+const int $EQ = 61;
+const int $GT = 62;
+const int $QUESTION = 63;
+const int $AT = 64;
+const int $A = 65;
+const int $B = 66;
+const int $C = 67;
+const int $D = 68;
+const int $E = 69;
+const int $F = 70;
+const int $G = 71;
+const int $H = 72;
+const int $I = 73;
+const int $J = 74;
+const int $K = 75;
+const int $L = 76;
+const int $M = 77;
+const int $N = 78;
+const int $O = 79;
+const int $P = 80;
+const int $Q = 81;
+const int $R = 82;
+const int $S = 83;
+const int $T = 84;
+const int $U = 85;
+const int $V = 86;
+const int $W = 87;
+const int $X = 88;
+const int $Y = 89;
+const int $Z = 90;
+const int $OPEN_SQUARE_BRACKET = 91;
+const int $BACKSLASH = 92;
+const int $CLOSE_SQUARE_BRACKET = 93;
+const int $CARET = 94;
+const int $_ = 95;
+const int $BACKPING = 96;
+const int $a = 97;
+const int $b = 98;
+const int $c = 99;
+const int $d = 100;
+const int $e = 101;
+const int $f = 102;
+const int $g = 103;
+const int $h = 104;
+const int $i = 105;
+const int $j = 106;
+const int $k = 107;
+const int $l = 108;
+const int $m = 109;
+const int $n = 110;
+const int $o = 111;
+const int $p = 112;
+const int $q = 113;
+const int $r = 114;
+const int $s = 115;
+const int $t = 116;
+const int $u = 117;
+const int $v = 118;
+const int $w = 119;
+const int $x = 120;
+const int $y = 121;
+const int $z = 122;
+const int $OPEN_CURLY_BRACKET = 123;
+const int $BAR = 124;
+const int $CLOSE_CURLY_BRACKET = 125;
+const int $TILDE = 126;
+const int $DEL = 127;
+const int $NBSP = 160;
+const int $LS = 0x2028;
+const int $PS = 0x2029;
+
+const int $FIRST_SURROGATE = 0xd800;
+const int $LAST_SURROGATE = 0xdfff;
+const int $LAST_CODE_POINT = 0x10ffff;
+
+bool isHexDigit(int characterCode) {
+  if (characterCode <= $9) return $0 <= characterCode;
+  characterCode |= $a ^ $A;
+  return ($a <= characterCode && characterCode <= $f);
+}
+
+int hexDigitValue(int hexDigit) {
+  assert(isHexDigit(hexDigit));
+  // hexDigit is one of '0'..'9', 'A'..'F' and 'a'..'f'.
+  if (hexDigit <= $9) return hexDigit - $0;
+  return (hexDigit | ($a ^ $A)) - ($a - 10);
+}
+
+bool isUnicodeScalarValue(int value) {
+  return value < $FIRST_SURROGATE ||
+      (value > $LAST_SURROGATE && value <= $LAST_CODE_POINT);
+}
+
+bool isUtf16LeadSurrogate(int value) {
+  return value >= 0xd800 && value <= 0xdbff;
+}
+
+bool isUtf16TrailSurrogate(int value) {
+  return value >= 0xdc00 && value <= 0xdfff;
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/error_token.dart b/pkg/front_end/lib/src/fasta/scanner/error_token.dart
new file mode 100644
index 0000000..97579b0
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/error_token.dart
@@ -0,0 +1,219 @@
+// 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 licenset hat can be found in the LICENSE file.
+
+library dart_scanner.error_token;
+
+// TODO(ahe): ErrorKind doesn't belong in dart_parser. Move to compiler_util or
+// this package?
+import '../parser/error_kind.dart' show
+    ErrorKind;
+
+import '../scanner.dart' show
+    BeginGroupToken,
+    Token,
+    unicodeReplacementCharacter;
+
+import 'precedence.dart' show
+    BAD_INPUT_INFO,
+    PrecedenceInfo;
+
+export '../parser/error_kind.dart' show
+    ErrorKind;
+
+ErrorToken buildUnexpectedCharacterToken(int character, int charOffset) {
+  if (character < 0x1f) {
+    return new AsciiControlCharacterToken(character, charOffset);
+  }
+  switch (character) {
+    case unicodeReplacementCharacter:
+      return new EncodingErrorToken(charOffset);
+
+      /// See [General Punctuation]
+      /// (http://www.unicode.org/charts/PDF/U2000.pdf).
+    case 0x00A0: // No-break space.
+    case 0x1680: // Ogham space mark.
+    case 0x180E: // Mongolian vowel separator.
+    case 0x2000: // En quad.
+    case 0x2001: // Em quad.
+    case 0x2002: // En space.
+    case 0x2003: // Em space.
+    case 0x2004: // Three-per-em space.
+    case 0x2005: // Four-per-em space.
+    case 0x2006: // Six-per-em space.
+    case 0x2007: // Figure space.
+    case 0x2008: // Punctuation space.
+    case 0x2009: // Thin space.
+    case 0x200A: // Hair space.
+    case 0x200B: // Zero width space.
+    case 0x2028: // Line separator.
+    case 0x2029: // Paragraph separator.
+    case 0x202F: // Narrow no-break space.
+    case 0x205F: // Medium mathematical space.
+    case 0x3000: // Ideographic space.
+    case 0xFEFF: // Zero width no-break space.
+      return new NonAsciiWhitespaceToken(character, charOffset);
+
+    default:
+      return new NonAsciiIdentifierToken(character, charOffset);
+  }
+}
+
+/// Common superclass for all error tokens.
+///
+/// It's considered an implementation error to access [value] of an
+/// [ErrorToken].
+abstract class ErrorToken extends Token {
+  ErrorToken(int charOffset) : super(charOffset);
+
+  PrecedenceInfo get info => BAD_INPUT_INFO;
+
+  String get value => throw assertionMessage;
+
+  String get stringValue => null;
+
+  bool isIdentifier() => false;
+
+  String get assertionMessage;
+
+  ErrorKind get errorCode;
+
+  int get character => null;
+
+  String get start => null;
+
+  int get endOffset => null;
+
+  BeginGroupToken get begin => null;
+}
+
+/// Represents an encoding error.
+class EncodingErrorToken extends ErrorToken {
+  EncodingErrorToken(int charOffset) : super(charOffset);
+
+  String toString() => "EncodingErrorToken()";
+
+  String get assertionMessage => "Unable to decode bytes as UTF-8.";
+
+  ErrorKind get errorCode => ErrorKind.Encoding;
+}
+
+/// Represents a non-ASCII character outside a string or comment.
+class NonAsciiIdentifierToken extends ErrorToken {
+  final int character;
+
+  NonAsciiIdentifierToken(this.character, int charOffset) : super(charOffset);
+
+  String toString() => "NonAsciiIdentifierToken($character)";
+
+  String get assertionMessage {
+    String c = new String.fromCharCodes([character]);
+    String hex = character.toRadixString(16);
+    String padding = "0000".substring(hex.length);
+    hex = "$padding$hex";
+    return
+        "The non-ASCII character '$c' (U+$hex) can't be used in identifiers,"
+        " only in strings and comments.\n"
+        "Try using an US-ASCII letter, a digit, '_' (an underscore),"
+        " or '\$' (a dollar sign).";
+  }
+
+  ErrorKind get errorCode => ErrorKind.NonAsciiIdentifier;
+}
+
+/// Represents a non-ASCII whitespace outside a string or comment.
+class NonAsciiWhitespaceToken extends ErrorToken {
+  final int character;
+
+  NonAsciiWhitespaceToken(this.character, int charOffset) : super(charOffset);
+
+  String toString() => "NonAsciiWhitespaceToken($character)";
+
+  String get assertionMessage {
+    String hex = character.toRadixString(16);
+    return "The non-ASCII space character U+$hex can only be used in strings "
+        "and comments.";
+  }
+
+  ErrorKind get errorCode => ErrorKind.NonAsciiWhitespace;
+}
+
+/// Represents an ASCII control character outside a string or comment.
+class AsciiControlCharacterToken extends ErrorToken {
+  final int character;
+
+  AsciiControlCharacterToken(this.character, int charOffset)
+      : super(charOffset);
+
+  String toString() => "AsciiControlCharacterToken($character)";
+
+  String get assertionMessage {
+    String hex = character.toRadixString(16);
+    return "The control character U+$hex can only be used in strings and "
+        "comments.";
+  }
+
+  ErrorKind get errorCode => ErrorKind.AsciiControlCharacter;
+}
+
+/// Represents an unterminated string.
+class UnterminatedToken extends ErrorToken {
+  final String start;
+  final int endOffset;
+
+  UnterminatedToken(this.start, int charOffset, this.endOffset)
+      : super(charOffset);
+
+  String toString() => "UnterminatedToken($start)";
+
+  String get assertionMessage => "'$start' isn't terminated.";
+
+  int get charCount => endOffset - charOffset;
+
+  ErrorKind get errorCode {
+    switch (start) {
+      case '1e':
+        return ErrorKind.MissingExponent;
+
+      case '"':
+      case "'":
+      case '"""':
+      case "'''":
+      case 'r"':
+      case "r'":
+      case 'r"""':
+      case "r'''":
+        return ErrorKind.UnterminatedString;
+
+      case '0x':
+        return ErrorKind.ExpectedHexDigit;
+
+      case r'$':
+        return ErrorKind.UnexpectedDollarInString;
+
+      case '/*':
+        return ErrorKind.UnterminatedComment;
+
+      default:
+        return ErrorKind.UnterminatedToken;
+    }
+  }
+}
+
+/// Represents an open brace without a matching close brace.
+///
+/// In this case, brace means any of `(`, `{`, `[`, and `<`, parenthesis, curly
+/// brace, square brace, and angle brace, respectively.
+class UnmatchedToken extends ErrorToken {
+  final BeginGroupToken begin;
+
+  UnmatchedToken(BeginGroupToken begin)
+      : this.begin = begin,
+        super(begin.charOffset);
+
+  String toString() => "UnmatchedToken(${begin.value})";
+
+  String get assertionMessage => "'$begin' isn't closed.";
+
+  ErrorKind get errorCode => ErrorKind.UnmatchedToken;
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/io.dart b/pkg/front_end/lib/src/fasta/scanner/io.dart
new file mode 100644
index 0000000..476c595a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/io.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+library fasta.scanner.io;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    File,
+    RandomAccessFile;
+
+import 'dart:typed_data' show
+    Uint8List;
+
+List<int> readBytesFromFileSync(Uri uri) {
+  RandomAccessFile file = new File.fromUri(uri).openSync();
+  Uint8List list;
+  try {
+    int length = file.lengthSync();
+    // +1 to have a 0 terminated list, see [Scanner].
+    list = new Uint8List(length + 1);
+    file.readIntoSync(list, 0, length);
+  } finally {
+    file.closeSync();
+  }
+  return list;
+}
+
+Future<List<int>> readBytesFromFile(Uri uri) async {
+  RandomAccessFile file = await new File.fromUri(uri).open();
+  Uint8List list;
+  try {
+    int length = await file.length();
+    // +1 to have a 0 terminated list, see [Scanner].
+    list = new Uint8List(length + 1);
+    int read = await file.readInto(list);
+    if (read != length) {
+      throw "Error reading file: ${uri}";
+    }
+  } finally {
+    await file.close();
+  }
+  return list;
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/keyword.dart b/pkg/front_end/lib/src/fasta/scanner/keyword.dart
new file mode 100644
index 0000000..1b06fb9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/keyword.dart
@@ -0,0 +1,222 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scanner.keywords;
+
+import 'characters.dart' show
+    $a;
+
+import 'precedence.dart' show
+    PrecedenceInfo;
+
+import 'precedence.dart' show
+    AS_INFO,
+    IS_INFO,
+    KEYWORD_INFO;
+
+/**
+ * A keyword in the Dart programming language.
+ */
+class Keyword {
+  static const List<Keyword> values = const <Keyword>[
+    const Keyword("assert"),
+    const Keyword("break"),
+    const Keyword("case"),
+    const Keyword("catch"),
+    const Keyword("class"),
+    const Keyword("const"),
+    const Keyword("continue"),
+    const Keyword("default"),
+    const Keyword("do"),
+    const Keyword("else"),
+    const Keyword("enum"),
+    const Keyword("extends"),
+    const Keyword("false"),
+    const Keyword("final"),
+    const Keyword("finally"),
+    const Keyword("for"),
+    const Keyword("if"),
+    const Keyword("in"),
+    const Keyword("new"),
+    const Keyword("null"),
+    const Keyword("rethrow"),
+    const Keyword("return"),
+    const Keyword("super"),
+    const Keyword("switch"),
+    const Keyword("this"),
+    const Keyword("throw"),
+    const Keyword("true"),
+    const Keyword("try"),
+    const Keyword("var"),
+    const Keyword("void"),
+    const Keyword("while"),
+    const Keyword("with"),
+
+    // TODO(ahe): Don't think this is a reserved word.
+    // See: http://dartbug.com/5579
+    const Keyword("is", info: IS_INFO),
+
+    const Keyword("abstract", isBuiltIn: true),
+    const Keyword("as", info: AS_INFO, isBuiltIn: true),
+    const Keyword("covariant", isBuiltIn: true),
+    const Keyword("dynamic", isBuiltIn: true),
+    const Keyword("export", isBuiltIn: true),
+    const Keyword("external", isBuiltIn: true),
+    const Keyword("factory", isBuiltIn: true),
+    const Keyword("get", isBuiltIn: true),
+    const Keyword("implements", isBuiltIn: true),
+    const Keyword("import", isBuiltIn: true),
+    const Keyword("library", isBuiltIn: true),
+    const Keyword("operator", isBuiltIn: true),
+    const Keyword("part", isBuiltIn: true),
+    const Keyword("set", isBuiltIn: true),
+    const Keyword("static", isBuiltIn: true),
+    const Keyword("typedef", isBuiltIn: true),
+
+    const Keyword("async", isPseudo: true),
+    const Keyword("await", isPseudo: true),
+    const Keyword("deferred", isPseudo: true),
+    const Keyword("hide", isPseudo: true),
+    const Keyword("native", isPseudo: true),
+    const Keyword("of", isPseudo: true),
+    const Keyword("on", isPseudo: true),
+    const Keyword("patch", isPseudo: true),
+    const Keyword("show", isPseudo: true),
+    const Keyword("source", isPseudo: true),
+    const Keyword("sync", isPseudo: true),
+    const Keyword("yield", isPseudo: true),
+  ];
+
+  final String syntax;
+  final bool isPseudo;
+  final bool isBuiltIn;
+  final PrecedenceInfo info;
+
+  static Map<String, Keyword> _keywords;
+  static Map<String, Keyword> get keywords {
+    if (_keywords == null) {
+      _keywords = computeKeywordMap();
+    }
+    return _keywords;
+  }
+
+  const Keyword(this.syntax,
+      {this.isPseudo: false,
+      this.isBuiltIn: false,
+      this.info: KEYWORD_INFO});
+
+  static Map<String, Keyword> computeKeywordMap() {
+    Map<String, Keyword> result = new Map<String, Keyword>();
+    for (Keyword keyword in values) {
+      result[keyword.syntax] = keyword;
+    }
+    return result;
+  }
+
+  String toString() => syntax;
+}
+
+/**
+ * Abstract state in a state machine for scanning keywords.
+ */
+abstract class KeywordState {
+  KeywordState(this.keyword);
+
+  KeywordState next(int c);
+  final Keyword keyword;
+
+  static KeywordState _KEYWORD_STATE;
+  static KeywordState get KEYWORD_STATE {
+    if (_KEYWORD_STATE == null) {
+      List<String> strings = new List<String>(Keyword.values.length);
+      for (int i = 0; i < Keyword.values.length; i++) {
+        strings[i] = Keyword.values[i].syntax;
+      }
+      strings.sort((a, b) => a.compareTo(b));
+      _KEYWORD_STATE = computeKeywordStateTable(0, strings, 0, strings.length);
+    }
+    return _KEYWORD_STATE;
+  }
+
+  static KeywordState computeKeywordStateTable(
+      int start, List<String> strings, int offset, int length) {
+    List<KeywordState> result = new List<KeywordState>(26);
+    assert(length != 0);
+    int chunk = 0;
+    int chunkStart = -1;
+    bool isLeaf = false;
+    for (int i = offset; i < offset + length; i++) {
+      if (strings[i].length == start) {
+        isLeaf = true;
+      }
+      if (strings[i].length > start) {
+        int c = strings[i].codeUnitAt(start);
+        if (chunk != c) {
+          if (chunkStart != -1) {
+            assert(result[chunk - $a] == null);
+            result[chunk - $a] = computeKeywordStateTable(
+                start + 1, strings, chunkStart, i - chunkStart);
+          }
+          chunkStart = i;
+          chunk = c;
+        }
+      }
+    }
+    if (chunkStart != -1) {
+      assert(result[chunk - $a] == null);
+      result[chunk - $a] = computeKeywordStateTable(
+          start + 1, strings, chunkStart, offset + length - chunkStart);
+    } else {
+      assert(length == 1);
+      return new LeafKeywordState(strings[offset]);
+    }
+    if (isLeaf) {
+      return new ArrayKeywordState(result, strings[offset]);
+    } else {
+      return new ArrayKeywordState(result, null);
+    }
+  }
+}
+
+/**
+ * A state with multiple outgoing transitions.
+ */
+class ArrayKeywordState extends KeywordState {
+  final List<KeywordState> table;
+
+  ArrayKeywordState(List<KeywordState> this.table, String syntax)
+      : super((syntax == null) ? null : Keyword.keywords[syntax]);
+
+  KeywordState next(int c) => table[c - $a];
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write("[");
+    if (keyword != null) {
+      sb.write("*");
+      sb.write(keyword);
+      sb.write(" ");
+    }
+    List<KeywordState> foo = table;
+    for (int i = 0; i < foo.length; i++) {
+      if (foo[i] != null) {
+        sb.write("${new String.fromCharCodes([i + $a])}: "
+            "${foo[i]}; ");
+      }
+    }
+    sb.write("]");
+    return sb.toString();
+  }
+}
+
+/**
+ * A state that has no outgoing transitions.
+ */
+class LeafKeywordState extends KeywordState {
+  LeafKeywordState(String syntax) : super(Keyword.keywords[syntax]);
+
+  KeywordState next(int c) => null;
+
+  String toString() => keyword.syntax;
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/main.dart b/pkg/front_end/lib/src/fasta/scanner/main.dart
new file mode 100644
index 0000000..e95304b
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/main.dart
@@ -0,0 +1,36 @@
+// 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.
+
+library fasta.scanner.main;
+
+import 'io.dart' show
+    readBytesFromFileSync;
+
+import '../scanner.dart' show
+    scan;
+
+scanAll(Map<Uri, List<int>> files) {
+  Stopwatch sw = new Stopwatch()..start();
+  int byteCount = 0;
+  files.forEach((Uri uri, List<int> bytes) {
+    scan(bytes);
+    byteCount += bytes.length - 1;
+  });
+  sw.stop();
+  print("Scanning files took: ${sw.elapsed}");
+  print("Bytes/ms: ${byteCount/sw.elapsedMilliseconds}");
+}
+
+main(List<String> arguments) {
+  Map<Uri, List<int>> files = <Uri, List<int>>{};
+  Stopwatch sw = new Stopwatch()..start();
+  for (String name in arguments) {
+    Uri uri = Uri.base.resolve(name);
+    List<int> bytes = readBytesFromFileSync(uri);
+    files[uri] = bytes;
+  }
+  sw.stop();
+  print("Reading files took: ${sw.elapsed}");
+  scanAll(files);
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/precedence.dart b/pkg/front_end/lib/src/fasta/scanner/precedence.dart
new file mode 100644
index 0000000..d1a222b
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/precedence.dart
@@ -0,0 +1,198 @@
+// 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.
+
+library fasta.scanner.precedence;
+
+import 'token_constants.dart';
+
+class PrecedenceInfo {
+  final String value;
+  final int precedence;
+  final int kind;
+
+  const PrecedenceInfo(this.value, this.precedence, this.kind);
+
+  toString() => 'PrecedenceInfo($value, $precedence, $kind)';
+}
+
+// TODO(ahe): The following are not tokens in Dart.
+const PrecedenceInfo BACKPING_INFO =
+    const PrecedenceInfo('`', 0, BACKPING_TOKEN);
+const PrecedenceInfo BACKSLASH_INFO =
+    const PrecedenceInfo('\\', 0, BACKSLASH_TOKEN);
+const PrecedenceInfo PERIOD_PERIOD_PERIOD_INFO =
+    const PrecedenceInfo('...', 0, PERIOD_PERIOD_PERIOD_TOKEN);
+
+/**
+ * The cascade operator has the lowest precedence of any operator
+ * except assignment.
+ */
+const int CASCADE_PRECEDENCE = 2;
+const PrecedenceInfo PERIOD_PERIOD_INFO =
+    const PrecedenceInfo('..', CASCADE_PRECEDENCE, PERIOD_PERIOD_TOKEN);
+
+const PrecedenceInfo BANG_INFO = const PrecedenceInfo('!', 0, BANG_TOKEN);
+const PrecedenceInfo COLON_INFO = const PrecedenceInfo(':', 0, COLON_TOKEN);
+const PrecedenceInfo INDEX_INFO = const PrecedenceInfo('[]', 0, INDEX_TOKEN);
+const PrecedenceInfo MINUS_MINUS_INFO =
+    const PrecedenceInfo('--', POSTFIX_PRECEDENCE, MINUS_MINUS_TOKEN);
+const PrecedenceInfo PLUS_PLUS_INFO =
+    const PrecedenceInfo('++', POSTFIX_PRECEDENCE, PLUS_PLUS_TOKEN);
+const PrecedenceInfo TILDE_INFO = const PrecedenceInfo('~', 0, TILDE_TOKEN);
+
+const PrecedenceInfo FUNCTION_INFO =
+    const PrecedenceInfo('=>', 0, FUNCTION_TOKEN);
+const PrecedenceInfo HASH_INFO = const PrecedenceInfo('#', 0, HASH_TOKEN);
+const PrecedenceInfo INDEX_EQ_INFO =
+    const PrecedenceInfo('[]=', 0, INDEX_EQ_TOKEN);
+const PrecedenceInfo SEMICOLON_INFO =
+    const PrecedenceInfo(';', 0, SEMICOLON_TOKEN);
+const PrecedenceInfo COMMA_INFO = const PrecedenceInfo(',', 0, COMMA_TOKEN);
+
+const PrecedenceInfo AT_INFO = const PrecedenceInfo('@', 0, AT_TOKEN);
+
+// Assignment operators.
+const int ASSIGNMENT_PRECEDENCE = 1;
+const PrecedenceInfo AMPERSAND_EQ_INFO =
+    const PrecedenceInfo('&=', ASSIGNMENT_PRECEDENCE, AMPERSAND_EQ_TOKEN);
+const PrecedenceInfo BAR_EQ_INFO =
+    const PrecedenceInfo('|=', ASSIGNMENT_PRECEDENCE, BAR_EQ_TOKEN);
+const PrecedenceInfo CARET_EQ_INFO =
+    const PrecedenceInfo('^=', ASSIGNMENT_PRECEDENCE, CARET_EQ_TOKEN);
+const PrecedenceInfo EQ_INFO =
+    const PrecedenceInfo('=', ASSIGNMENT_PRECEDENCE, EQ_TOKEN);
+const PrecedenceInfo GT_GT_EQ_INFO =
+    const PrecedenceInfo('>>=', ASSIGNMENT_PRECEDENCE, GT_GT_EQ_TOKEN);
+const PrecedenceInfo LT_LT_EQ_INFO =
+    const PrecedenceInfo('<<=', ASSIGNMENT_PRECEDENCE, LT_LT_EQ_TOKEN);
+const PrecedenceInfo MINUS_EQ_INFO =
+    const PrecedenceInfo('-=', ASSIGNMENT_PRECEDENCE, MINUS_EQ_TOKEN);
+const PrecedenceInfo PERCENT_EQ_INFO =
+    const PrecedenceInfo('%=', ASSIGNMENT_PRECEDENCE, PERCENT_EQ_TOKEN);
+const PrecedenceInfo PLUS_EQ_INFO =
+    const PrecedenceInfo('+=', ASSIGNMENT_PRECEDENCE, PLUS_EQ_TOKEN);
+const PrecedenceInfo SLASH_EQ_INFO =
+    const PrecedenceInfo('/=', ASSIGNMENT_PRECEDENCE, SLASH_EQ_TOKEN);
+const PrecedenceInfo STAR_EQ_INFO =
+    const PrecedenceInfo('*=', ASSIGNMENT_PRECEDENCE, STAR_EQ_TOKEN);
+const PrecedenceInfo TILDE_SLASH_EQ_INFO =
+    const PrecedenceInfo('~/=', ASSIGNMENT_PRECEDENCE, TILDE_SLASH_EQ_TOKEN);
+const PrecedenceInfo QUESTION_QUESTION_EQ_INFO = const PrecedenceInfo(
+    '??=', ASSIGNMENT_PRECEDENCE, QUESTION_QUESTION_EQ_TOKEN);
+
+const PrecedenceInfo QUESTION_INFO =
+    const PrecedenceInfo('?', 3, QUESTION_TOKEN);
+
+const PrecedenceInfo QUESTION_QUESTION_INFO =
+    const PrecedenceInfo('??', 4, QUESTION_QUESTION_TOKEN);
+
+const PrecedenceInfo BAR_BAR_INFO =
+    const PrecedenceInfo('||', 5, BAR_BAR_TOKEN);
+
+const PrecedenceInfo AMPERSAND_AMPERSAND_INFO =
+    const PrecedenceInfo('&&', 6, AMPERSAND_AMPERSAND_TOKEN);
+
+const PrecedenceInfo BAR_INFO = const PrecedenceInfo('|', 9, BAR_TOKEN);
+
+const PrecedenceInfo CARET_INFO = const PrecedenceInfo('^', 10, CARET_TOKEN);
+
+const PrecedenceInfo AMPERSAND_INFO =
+    const PrecedenceInfo('&', 11, AMPERSAND_TOKEN);
+
+// Equality operators.
+const int EQUALITY_PRECEDENCE = 7;
+const PrecedenceInfo BANG_EQ_EQ_INFO =
+    const PrecedenceInfo('!==', EQUALITY_PRECEDENCE, BANG_EQ_EQ_TOKEN);
+const PrecedenceInfo BANG_EQ_INFO =
+    const PrecedenceInfo('!=', EQUALITY_PRECEDENCE, BANG_EQ_TOKEN);
+const PrecedenceInfo EQ_EQ_EQ_INFO =
+    const PrecedenceInfo('===', EQUALITY_PRECEDENCE, EQ_EQ_EQ_TOKEN);
+const PrecedenceInfo EQ_EQ_INFO =
+    const PrecedenceInfo('==', EQUALITY_PRECEDENCE, EQ_EQ_TOKEN);
+
+// Relational operators.
+const int RELATIONAL_PRECEDENCE = 8;
+const PrecedenceInfo GT_EQ_INFO =
+    const PrecedenceInfo('>=', RELATIONAL_PRECEDENCE, GT_EQ_TOKEN);
+const PrecedenceInfo GT_INFO =
+    const PrecedenceInfo('>', RELATIONAL_PRECEDENCE, GT_TOKEN);
+const PrecedenceInfo IS_INFO =
+    const PrecedenceInfo('is', RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
+const PrecedenceInfo AS_INFO =
+    const PrecedenceInfo('as', RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
+const PrecedenceInfo LT_EQ_INFO =
+    const PrecedenceInfo('<=', RELATIONAL_PRECEDENCE, LT_EQ_TOKEN);
+const PrecedenceInfo LT_INFO =
+    const PrecedenceInfo('<', RELATIONAL_PRECEDENCE, LT_TOKEN);
+
+// Shift operators.
+const PrecedenceInfo GT_GT_INFO = const PrecedenceInfo('>>', 12, GT_GT_TOKEN);
+const PrecedenceInfo LT_LT_INFO = const PrecedenceInfo('<<', 12, LT_LT_TOKEN);
+
+// Additive operators.
+const PrecedenceInfo MINUS_INFO = const PrecedenceInfo('-', 13, MINUS_TOKEN);
+const PrecedenceInfo PLUS_INFO = const PrecedenceInfo('+', 13, PLUS_TOKEN);
+
+// Multiplicative operators.
+const PrecedenceInfo PERCENT_INFO =
+    const PrecedenceInfo('%', 14, PERCENT_TOKEN);
+const PrecedenceInfo SLASH_INFO = const PrecedenceInfo('/', 14, SLASH_TOKEN);
+const PrecedenceInfo STAR_INFO = const PrecedenceInfo('*', 14, STAR_TOKEN);
+const PrecedenceInfo TILDE_SLASH_INFO =
+    const PrecedenceInfo('~/', 14, TILDE_SLASH_TOKEN);
+
+const int POSTFIX_PRECEDENCE = 15;
+const PrecedenceInfo PERIOD_INFO =
+    const PrecedenceInfo('.', POSTFIX_PRECEDENCE, PERIOD_TOKEN);
+const PrecedenceInfo QUESTION_PERIOD_INFO =
+    const PrecedenceInfo('?.', POSTFIX_PRECEDENCE, QUESTION_PERIOD_TOKEN);
+
+const PrecedenceInfo KEYWORD_INFO =
+    const PrecedenceInfo('keyword', 0, KEYWORD_TOKEN);
+
+const PrecedenceInfo EOF_INFO = const PrecedenceInfo('EOF', 0, EOF_TOKEN);
+
+const PrecedenceInfo IDENTIFIER_INFO =
+    const PrecedenceInfo('identifier', 0, IDENTIFIER_TOKEN);
+
+const PrecedenceInfo BAD_INPUT_INFO =
+    const PrecedenceInfo('malformed input', 0, BAD_INPUT_TOKEN);
+
+const PrecedenceInfo OPEN_PAREN_INFO =
+    const PrecedenceInfo('(', POSTFIX_PRECEDENCE, OPEN_PAREN_TOKEN);
+
+const PrecedenceInfo CLOSE_PAREN_INFO =
+    const PrecedenceInfo(')', 0, CLOSE_PAREN_TOKEN);
+
+const PrecedenceInfo OPEN_CURLY_BRACKET_INFO =
+    const PrecedenceInfo('{', 0, OPEN_CURLY_BRACKET_TOKEN);
+
+const PrecedenceInfo CLOSE_CURLY_BRACKET_INFO =
+    const PrecedenceInfo('}', 0, CLOSE_CURLY_BRACKET_TOKEN);
+
+const PrecedenceInfo INT_INFO = const PrecedenceInfo('int', 0, INT_TOKEN);
+
+const PrecedenceInfo STRING_INFO =
+    const PrecedenceInfo('string', 0, STRING_TOKEN);
+
+const PrecedenceInfo OPEN_SQUARE_BRACKET_INFO =
+    const PrecedenceInfo('[', POSTFIX_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN);
+
+const PrecedenceInfo CLOSE_SQUARE_BRACKET_INFO =
+    const PrecedenceInfo(']', 0, CLOSE_SQUARE_BRACKET_TOKEN);
+
+const PrecedenceInfo DOUBLE_INFO =
+    const PrecedenceInfo('double', 0, DOUBLE_TOKEN);
+
+const PrecedenceInfo STRING_INTERPOLATION_INFO =
+    const PrecedenceInfo('\${', 0, STRING_INTERPOLATION_TOKEN);
+
+const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO =
+    const PrecedenceInfo('\$', 0, STRING_INTERPOLATION_IDENTIFIER_TOKEN);
+
+const PrecedenceInfo HEXADECIMAL_INFO =
+    const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN);
+
+const PrecedenceInfo COMMENT_INFO =
+    const PrecedenceInfo('comment', 0, COMMENT_TOKEN);
diff --git a/pkg/front_end/lib/src/fasta/scanner/recover.dart b/pkg/front_end/lib/src/fasta/scanner/recover.dart
new file mode 100644
index 0000000..0beaad6
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/recover.dart
@@ -0,0 +1,248 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style licenset hat can be found in the LICENSE file.
+
+library fasta.scanner.recover;
+
+import 'token.dart' show
+    StringToken,
+    Token;
+
+import 'error_token.dart' show
+    NonAsciiIdentifierToken,
+    ErrorKind,
+    ErrorToken;
+
+import 'precedence.dart' as Precedence;
+
+import 'precedence.dart' show
+    PrecedenceInfo;
+
+/// Recover from errors in [tokens]. The original sources are provided as
+/// [bytes]. [lineStarts] are the beginning character offsets of lines, and
+/// must be updated if recovery is performed rewriting the original source
+/// code.
+Token defaultRecoveryStrategy(
+    List<int> bytes, Token tokens, List<int> lineStarts) {
+  // See [Parser.reportErrorToken](package:front_end/src/fasta/parser/src/parser.dart) for how
+  // it currently handles lexical errors. In addition, notice how the parser
+  // calls [handleInvalidExpression], [handleInvalidFunctionBody], and
+  // [handleInvalidTypeReference] to allow the listener to recover its internal
+  // state. See [package:compiler/src/parser/element_listener.dart] for an
+  // example of how these events are used.
+  //
+  // In addition, the scanner will attempt a bit of recovery when braces don't
+  // match up during brace grouping. See
+  // [ArrayBasedScanner.discardBeginGroupUntil](array_based_scanner.dart). For
+  // more details on brace grouping see
+  // [AbstractScanner.unmatchedBeginGroup](abstract_scanner.dart).
+
+  /// Tokens with errors.
+  ErrorToken error;
+  /// Used for appending to [error].
+  ErrorToken errorTail;
+
+  /// Tokens without errors.
+  Token good;
+  /// Used for appending to [good].
+  Token goodTail;
+
+  /// The previous token appended to [good]. Since tokens are single linked
+  /// lists, this allows us to rewrite the current token without scanning all
+  /// of [good]. This is supposed to be the token immediately before
+  /// [goodTail], that is, `beforeGoodTail.next == goodTail`.
+  Token beforeGoodTail;
+
+  recoverIdentifier(NonAsciiIdentifierToken first) {
+    List<int> codeUnits = <int>[];
+
+    // True if the previous good token is an identifier and ends right where
+    // [first] starts. This is the case for input like `blåbærgrød`. In this
+    // case, the scanner produces this sequence of tokens:
+    //
+    //     [
+    //        StringToken("bl"),
+    //        NonAsciiIdentifierToken("å"),
+    //        StringToken("b"),
+    //        NonAsciiIdentifierToken("æ"),
+    //        StringToken("rgr"),
+    //        NonAsciiIdentifierToken("ø"),
+    //        StringToken("d"),
+    //        EOF,
+    //     ]
+    bool prepend = false;
+
+    // True if following token is also an identifier that starts right where
+    // [errorTail] ends. This is the case for "b" above.
+    bool append = false;
+    if (goodTail != null) {
+      if (goodTail.info == Precedence.IDENTIFIER_INFO &&
+          goodTail.charEnd == first.charOffset) {
+        prepend = true;
+      }
+    }
+    Token next = errorTail.next;
+    if (next.info == Precedence.IDENTIFIER_INFO &&
+        errorTail.charOffset + 1 == next.charOffset) {
+      append = true;
+    }
+    if (prepend) {
+      codeUnits.addAll(goodTail.value.codeUnits);
+    }
+    NonAsciiIdentifierToken current = first;
+    while (current != errorTail) {
+      codeUnits.add(current.character);
+      current = current.next;
+    }
+    codeUnits.add(errorTail.character);
+    int charOffset = first.charOffset;
+    if (prepend) {
+      charOffset = goodTail.charOffset;
+      if (beforeGoodTail == null) {
+        // We're prepending the first good token, so the new token will become
+        // the first good token.
+        good = null;
+        goodTail = null;
+        beforeGoodTail = null;
+      } else {
+        goodTail = beforeGoodTail;
+      }
+    }
+    if (append) {
+      codeUnits.addAll(next.value.codeUnits);
+      next = next.next;
+    }
+    String value = new String.fromCharCodes(codeUnits);
+    return synthesizeToken(charOffset, value, Precedence.IDENTIFIER_INFO)
+        ..next = next;
+  }
+
+  recoverExponent() {
+    return synthesizeToken(errorTail.charOffset, "NaN", Precedence.DOUBLE_INFO)
+        ..next = errorTail.next;
+  }
+
+  recoverString() {
+    // TODO(ahe): Improve this.
+    return skipToEof(errorTail);
+  }
+
+  recoverHexDigit() {
+    return synthesizeToken(errorTail.charOffset, "-1", Precedence.INT_INFO)
+        ..next = errorTail.next;
+  }
+
+  recoverStringInterpolation() {
+    // TODO(ahe): Improve this.
+    return skipToEof(errorTail);
+  }
+
+  recoverComment() {
+    // TODO(ahe): Improve this.
+    return skipToEof(errorTail);
+  }
+
+  recoverUnmatched() {
+    // TODO(ahe): Try to use top-level keywords (such as `class`, `typedef`,
+    // and `enum`) and identation to recover.
+    return errorTail.next;
+  }
+
+  for (Token current = tokens; !current.isEof; current = current.next) {
+    if (current is ErrorToken) {
+      ErrorToken first = current;
+      Token next = current;
+      bool treatAsWhitespace = false;
+      do {
+        current = next;
+        if (errorTail == null) {
+          error = next;
+        } else {
+          errorTail.next = next;
+        }
+        errorTail = next;
+        next = next.next;
+      } while (next is ErrorToken && first.errorCode == next.errorCode);
+
+      switch (first.errorCode) {
+        case ErrorKind.Encoding:
+        case ErrorKind.NonAsciiWhitespace:
+        case ErrorKind.AsciiControlCharacter:
+          treatAsWhitespace = true;
+          break;
+
+        case ErrorKind.NonAsciiIdentifier:
+          current = recoverIdentifier(first);
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.MissingExponent:
+          current = recoverExponent();
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.UnterminatedString:
+          current = recoverString();
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.ExpectedHexDigit:
+          current = recoverHexDigit();
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.UnexpectedDollarInString:
+          current = recoverStringInterpolation();
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.UnterminatedComment:
+          current = recoverComment();
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.UnmatchedToken:
+          current = recoverUnmatched();
+          assert(current.next != null);
+          break;
+
+        case ErrorKind.UnterminatedToken: // TODO(ahe): Can this happen?
+        default:
+          treatAsWhitespace = true;
+          break;
+      }
+      if (treatAsWhitespace) continue;
+    }
+    if (goodTail == null) {
+      good = current;
+    } else {
+      goodTail.next = current;
+    }
+    beforeGoodTail = goodTail;
+    goodTail = current;
+  }
+
+  errorTail.next = good;
+  return error;
+}
+
+Token synthesizeToken(int charOffset, String value, PrecedenceInfo info) {
+  return new StringToken.fromString(info, value, charOffset);
+}
+
+Token skipToEof(Token token) {
+  while (!token.isEof) {
+    token = token.next;
+  }
+  return token;
+}
+
+String closeBraceFor(String openBrace) {
+  return const {
+    '(': ')',
+    '[': ']',
+    '{': '}',
+    '<': '>',
+    r'${': '}',
+  }[openBrace];
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/string_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/string_scanner.dart
new file mode 100644
index 0000000..641a678
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/string_scanner.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.scanner.string_scanner;
+
+import 'array_based_scanner.dart' show
+    ArrayBasedScanner;
+
+import 'precedence.dart' show
+    PrecedenceInfo;
+
+import 'token.dart' show
+    StringToken,
+    Token;
+
+/**
+ * Scanner that reads from a String and creates tokens that points to
+ * substrings.
+ */
+class StringScanner extends ArrayBasedScanner {
+  /** The file content. */
+  String string;
+
+  /** The current offset in [string]. */
+  int scanOffset = -1;
+
+  StringScanner(String string, {bool includeComments: false})
+      : string = ensureZeroTermination(string),
+        super(includeComments);
+
+  static String ensureZeroTermination(String string) {
+    return (string.isEmpty || string.codeUnitAt(string.length - 1) != 0)
+        // TODO(lry): abort instead of copying the array, or warn?
+        ? string + '\x00'
+        : string;
+  }
+
+  int advance() => string.codeUnitAt(++scanOffset);
+  int peek() => string.codeUnitAt(scanOffset + 1);
+
+  int get stringOffset => scanOffset;
+
+  int currentAsUnicode(int next) => next;
+
+  void handleUnicode(int startScanOffset) {}
+
+  Token firstToken() => tokens.next;
+  Token previousToken() => tail;
+
+  void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
+      [int extraOffset = 0]) {
+    tail.next = new StringToken.fromSubstring(
+        info, string, start, scanOffset + extraOffset, tokenStart,
+        canonicalize: true);
+    tail = tail.next;
+  }
+
+  bool atEndOfFile() => scanOffset >= string.length - 1;
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/testing/scanner_chain.dart b/pkg/front_end/lib/src/fasta/scanner/testing/scanner_chain.dart
new file mode 100644
index 0000000..138b8c4
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/testing/scanner_chain.dart
@@ -0,0 +1,33 @@
+// 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.
+
+library fasta.scanner.testing.scanner_chain;
+
+import 'package:testing/testing.dart';
+
+import 'package:front_end/src/fasta/scanner.dart';
+
+import 'package:front_end/src/fasta/scanner/io.dart';
+
+class Read extends Step<TestDescription, List<int>, ChainContext> {
+  const Read();
+
+  String get name => "read";
+
+  Future<Result<List<int>>> run(
+      TestDescription input, ChainContext context) async {
+    return pass(await readBytesFromFile(input.uri));
+  }
+}
+
+class Scan extends Step<List<int>, ScannerResult, ChainContext> {
+  const Scan();
+
+  String get name => "scan";
+
+  Future<Result<ScannerResult>> run(
+      List<int> bytes, ChainContext context) async {
+    return pass(scan(bytes));
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/scanner/token.dart b/pkg/front_end/lib/src/fasta/scanner/token.dart
new file mode 100644
index 0000000..8a72228
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/token.dart
@@ -0,0 +1,376 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scanner.token;
+
+import 'dart:collection' show
+    HashSet;
+
+import 'dart:convert' show
+    UTF8;
+
+import 'keyword.dart' show
+    Keyword;
+
+import 'precedence.dart' show
+    BAD_INPUT_INFO,
+    EOF_INFO,
+    PrecedenceInfo;
+
+import 'token_constants.dart' show
+    IDENTIFIER_TOKEN;
+
+/**
+ * A token that doubles as a linked list.
+ */
+abstract class Token {
+  /**
+   * The character offset of the start of this token within the source text.
+   */
+  final int charOffset;
+
+  Token(this.charOffset);
+
+  /**
+   * The next token in the token stream.
+   */
+  Token next;
+
+  /**
+   * The precedence info for this token. [info] determines the kind and the
+   * precedence level of this token.
+   *
+   * Defined as getter to save a field in the [KeywordToken] subclass.
+   */
+  PrecedenceInfo get info;
+
+  /**
+   * The string represented by this token, a substring of the source code.
+   *
+   * For [StringToken]s the [value] includes the quotes, explicit escapes, etc.
+   */
+  String get value;
+
+  /**
+   * For symbol and keyword tokens, returns the string value represented by this
+   * token. For [StringToken]s this method returns [:null:].
+   *
+   * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time
+   * constant originating in the [PrecedenceInfo] or in the [Keyword] instance.
+   * This allows testing for keywords and symbols using [:identical:], e.g.,
+   * [:identical('class', token.value):].
+   *
+   * Note that returning [:null:] for string tokens is important to identify
+   * symbols and keywords, we cannot use [value] instead. The string literal
+   *   "$a($b"
+   * produces ..., SymbolToken($), StringToken(a), StringToken((), ...
+   *
+   * After parsing the identifier 'a', the parser tests for a function
+   * declaration using [:identical(next.stringValue, '('):], which (rightfully)
+   * returns false because stringValue returns [:null:].
+   */
+  String get stringValue;
+
+  /**
+   * The kind enum of this token as determined by its [info].
+   */
+  int get kind => info.kind;
+
+  /**
+   * The precedence level for this token.
+   */
+  int get precedence => info.precedence;
+
+  /**
+   * True if this token is an identifier. Some keywords allowed as identifiers,
+   * see implementation in [KeywordToken].
+   */
+  bool isIdentifier();
+
+  /**
+   * Returns a textual representation of this token to be used for debugging
+   * purposes. The resulting string might contain information about the
+   * structure of the token, for example 'StringToken(foo)' for the identifier
+   * token 'foo'.
+   *
+   * Use [value] for the text actually parsed by the token.
+   */
+  String toString();
+
+  /**
+   * The number of characters parsed by this token.
+   */
+  int get charCount {
+    if (info == BAD_INPUT_INFO) {
+      // This is a token that wraps around an error message. Return 1
+      // instead of the size of the length of the error message.
+      return 1;
+    } else {
+      return value.length;
+    }
+  }
+
+  /// The character offset of the end of this token within the source text.
+  int get charEnd => charOffset + charCount;
+
+  bool get isEof => false;
+}
+
+/**
+ * A [SymbolToken] represents the symbol in its precendence info.
+ * Also used for end of file with EOF_INFO.
+ */
+class SymbolToken extends Token {
+  final PrecedenceInfo info;
+
+  SymbolToken(this.info, int charOffset) : super(charOffset);
+
+  String get value => info.value;
+
+  String get stringValue => info.value;
+
+  bool isIdentifier() => false;
+
+  String toString() => "SymbolToken($value)";
+
+  bool get isEof => info == EOF_INFO;
+}
+
+/**
+ * A [BeginGroupToken] represents a symbol that may be the beginning of
+ * a pair of brackets, i.e., ( { [ < or ${
+ * The [endGroup] token points to the matching closing bracked in case
+ * it can be identified during scanning.
+ */
+class BeginGroupToken extends SymbolToken {
+  Token endGroup;
+
+  BeginGroupToken(PrecedenceInfo info, int charOffset)
+      : super(info, charOffset);
+}
+
+/**
+ * A keyword token.
+ */
+class KeywordToken extends Token {
+  final Keyword keyword;
+
+  KeywordToken(this.keyword, int charOffset) : super(charOffset);
+
+  PrecedenceInfo get info => keyword.info;
+
+  String get value => keyword.syntax;
+
+  String get stringValue => keyword.syntax;
+
+  bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn;
+
+  String toString() => "KeywordToken($value)";
+}
+
+/**
+ * A String-valued token. Represents identifiers, string literals,
+ * number literals, comments, and error tokens, using the corresponding
+ * precedence info.
+ */
+class StringToken extends Token {
+  /**
+   * The length threshold above which substring tokens are computed lazily.
+   *
+   * For string tokens that are substrings of the program source, the actual
+   * substring extraction is performed lazily. This is beneficial because
+   * not all scanned code is actually used. For unused parts, the substrings
+   * are never computed and allocated.
+   */
+  static const int LAZY_THRESHOLD = 4;
+
+  var /* String | LazySubtring */ valueOrLazySubstring;
+
+  final PrecedenceInfo info;
+
+  /**
+   * Creates a non-lazy string token. If [canonicalize] is true, the string
+   * is canonicalized before the token is created.
+   */
+  StringToken.fromString(this.info, String value, int charOffset,
+      {bool canonicalize: false})
+      : valueOrLazySubstring = canonicalizedString(value, canonicalize),
+        super(charOffset);
+
+  /**
+   * Creates a lazy string token. If [canonicalize] is true, the string
+   * is canonicalized before the token is created.
+   */
+  StringToken.fromSubstring(
+      this.info, String data, int start, int end, int charOffset,
+      {bool canonicalize: false})
+      : super(charOffset) {
+    int length = end - start;
+    if (length <= LAZY_THRESHOLD) {
+      valueOrLazySubstring =
+          canonicalizedString(data.substring(start, end), canonicalize);
+    } else {
+      valueOrLazySubstring =
+          new LazySubstring(data, start, length, canonicalize);
+    }
+  }
+
+  /**
+   * Creates a lazy string token. If [asciiOnly] is false, the byte array
+   * is passed through a UTF-8 decoder.
+   */
+  StringToken.fromUtf8Bytes(this.info, List<int> data, int start, int end,
+      bool asciiOnly, int charOffset)
+      : super(charOffset) {
+    int length = end - start;
+    if (length <= LAZY_THRESHOLD) {
+      valueOrLazySubstring = decodeUtf8(data, start, end, asciiOnly);
+    } else {
+      valueOrLazySubstring = new LazySubstring(data, start, length, asciiOnly);
+    }
+  }
+
+  String get value {
+    if (valueOrLazySubstring is String) {
+      return valueOrLazySubstring;
+    } else {
+      assert(valueOrLazySubstring is LazySubstring);
+      var data = valueOrLazySubstring.data;
+      int start = valueOrLazySubstring.start;
+      int end = start + valueOrLazySubstring.length;
+      if (data is String) {
+        valueOrLazySubstring = canonicalizedString(
+            data.substring(start, end), valueOrLazySubstring.boolValue);
+      } else {
+        valueOrLazySubstring =
+            decodeUtf8(data, start, end, valueOrLazySubstring.boolValue);
+      }
+      return valueOrLazySubstring;
+    }
+  }
+
+  /// See [Token.stringValue] for an explanation.
+  String get stringValue => null;
+
+  bool isIdentifier() => identical(kind, IDENTIFIER_TOKEN);
+
+  String toString() => "StringToken($value)";
+
+  static final HashSet<String> canonicalizedSubstrings = new HashSet<String>();
+
+  static String canonicalizedString(String s, bool canonicalize) {
+    if (!canonicalize) return s;
+    var result = canonicalizedSubstrings.lookup(s);
+    if (result != null) return result;
+    canonicalizedSubstrings.add(s);
+    return s;
+  }
+
+  static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) {
+    var s;
+    if (asciiOnly) {
+      s = new String.fromCharCodes(data, start, end);
+    } else {
+      s = UTF8.decoder.convert(data, start, end);
+    }
+    return canonicalizedString(s, true);
+  }
+}
+
+/**
+ * This class represents the necessary information to compute a substring
+ * lazily. The substring can either originate from a string or from
+ * a [:List<int>:] of UTF-8 bytes.
+ */
+abstract class LazySubstring {
+  /** The original data, either a string or a List<int> */
+  get data;
+
+  int get start;
+  int get length;
+
+  /**
+   * If this substring is based on a String, the [boolValue] indicates wheter
+   * the resulting substring should be canonicalized.
+   *
+   * For substrings based on a byte array, the [boolValue] is true if the
+   * array only holds ASCII characters. The resulting substring will be
+   * canonicalized after decoding.
+   */
+  bool get boolValue;
+
+  LazySubstring.internal();
+
+  factory LazySubstring(data, int start, int length, bool b) {
+    // See comment on [CompactLazySubstring].
+    if (start < 0x100000 && length < 0x200) {
+      int fields = (start << 9);
+      fields = fields | length;
+      fields = fields << 1;
+      if (b) fields |= 1;
+      return new CompactLazySubstring(data, fields);
+    } else {
+      return new FullLazySubstring(data, start, length, b);
+    }
+  }
+}
+
+/**
+ * This class encodes [start], [length] and [boolValue] in a single
+ * 30 bit integer. It uses 20 bits for [start], which covers source files
+ * of 1MB. [length] has 9 bits, which covers 512 characters.
+ *
+ * The file html_dart2js.dart is currently around 1MB.
+ */
+class CompactLazySubstring extends LazySubstring {
+  final data;
+  final int fields;
+
+  CompactLazySubstring(this.data, this.fields) : super.internal();
+
+  int get start => fields >> 10;
+  int get length => (fields >> 1) & 0x1ff;
+  bool get boolValue => (fields & 1) == 1;
+}
+
+class FullLazySubstring extends LazySubstring {
+  final data;
+  final int start;
+  final int length;
+  final bool boolValue;
+  FullLazySubstring(this.data, this.start, this.length, this.boolValue)
+      : super.internal();
+}
+
+bool isUserDefinableOperator(String value) {
+  return isBinaryOperator(value) ||
+      isMinusOperator(value) ||
+      isTernaryOperator(value) ||
+      isUnaryOperator(value);
+}
+
+bool isUnaryOperator(String value) => value == '~';
+
+bool isBinaryOperator(String value) {
+  return value == '==' ||
+      value == '[]' ||
+      value == '*' ||
+      value == '/' ||
+      value == '%' ||
+      value == '~/' ||
+      value == '+' ||
+      value == '<<' ||
+      value == '>>' ||
+      value == '>=' ||
+      value == '>' ||
+      value == '<=' ||
+      value == '<' ||
+      value == '&' ||
+      value == '^' ||
+      value == '|';
+}
+
+bool isTernaryOperator(String value) => value == '[]=';
+
+bool isMinusOperator(String value) => value == '-';
diff --git a/pkg/front_end/lib/src/fasta/scanner/token_constants.dart b/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
new file mode 100644
index 0000000..b5501e4
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
@@ -0,0 +1,82 @@
+// 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.
+
+library fasta.scanner.token_constants;
+
+import 'characters.dart';
+
+const int EOF_TOKEN = 0;
+
+const int KEYWORD_TOKEN = $k;
+const int IDENTIFIER_TOKEN = $a;
+const int BAD_INPUT_TOKEN = $X;
+const int DOUBLE_TOKEN = $d;
+const int INT_TOKEN = $i;
+const int HEXADECIMAL_TOKEN = $x;
+const int STRING_TOKEN = $SQ;
+
+const int AMPERSAND_TOKEN = $AMPERSAND;
+const int BACKPING_TOKEN = $BACKPING;
+const int BACKSLASH_TOKEN = $BACKSLASH;
+const int BANG_TOKEN = $BANG;
+const int BAR_TOKEN = $BAR;
+const int COLON_TOKEN = $COLON;
+const int COMMA_TOKEN = $COMMA;
+const int EQ_TOKEN = $EQ;
+const int GT_TOKEN = $GT;
+const int HASH_TOKEN = $HASH;
+const int OPEN_CURLY_BRACKET_TOKEN = $OPEN_CURLY_BRACKET;
+const int OPEN_SQUARE_BRACKET_TOKEN = $OPEN_SQUARE_BRACKET;
+const int OPEN_PAREN_TOKEN = $OPEN_PAREN;
+const int LT_TOKEN = $LT;
+const int MINUS_TOKEN = $MINUS;
+const int PERIOD_TOKEN = $PERIOD;
+const int PLUS_TOKEN = $PLUS;
+const int QUESTION_TOKEN = $QUESTION;
+const int AT_TOKEN = $AT;
+const int CLOSE_CURLY_BRACKET_TOKEN = $CLOSE_CURLY_BRACKET;
+const int CLOSE_SQUARE_BRACKET_TOKEN = $CLOSE_SQUARE_BRACKET;
+const int CLOSE_PAREN_TOKEN = $CLOSE_PAREN;
+const int SEMICOLON_TOKEN = $SEMICOLON;
+const int SLASH_TOKEN = $SLASH;
+const int TILDE_TOKEN = $TILDE;
+const int STAR_TOKEN = $STAR;
+const int PERCENT_TOKEN = $PERCENT;
+const int CARET_TOKEN = $CARET;
+
+const int STRING_INTERPOLATION_TOKEN = 128;
+const int LT_EQ_TOKEN = STRING_INTERPOLATION_TOKEN + 1;
+const int FUNCTION_TOKEN = LT_EQ_TOKEN + 1;
+const int SLASH_EQ_TOKEN = FUNCTION_TOKEN + 1;
+const int PERIOD_PERIOD_PERIOD_TOKEN = SLASH_EQ_TOKEN + 1;
+const int PERIOD_PERIOD_TOKEN = PERIOD_PERIOD_PERIOD_TOKEN + 1;
+const int EQ_EQ_EQ_TOKEN = PERIOD_PERIOD_TOKEN + 1;
+const int EQ_EQ_TOKEN = EQ_EQ_EQ_TOKEN + 1;
+const int LT_LT_EQ_TOKEN = EQ_EQ_TOKEN + 1;
+const int LT_LT_TOKEN = LT_LT_EQ_TOKEN + 1;
+const int GT_EQ_TOKEN = LT_LT_TOKEN + 1;
+const int GT_GT_EQ_TOKEN = GT_EQ_TOKEN + 1;
+const int INDEX_EQ_TOKEN = GT_GT_EQ_TOKEN + 1;
+const int INDEX_TOKEN = INDEX_EQ_TOKEN + 1;
+const int BANG_EQ_EQ_TOKEN = INDEX_TOKEN + 1;
+const int BANG_EQ_TOKEN = BANG_EQ_EQ_TOKEN + 1;
+const int AMPERSAND_AMPERSAND_TOKEN = BANG_EQ_TOKEN + 1;
+const int AMPERSAND_EQ_TOKEN = AMPERSAND_AMPERSAND_TOKEN + 1;
+const int BAR_BAR_TOKEN = AMPERSAND_EQ_TOKEN + 1;
+const int BAR_EQ_TOKEN = BAR_BAR_TOKEN + 1;
+const int STAR_EQ_TOKEN = BAR_EQ_TOKEN + 1;
+const int PLUS_PLUS_TOKEN = STAR_EQ_TOKEN + 1;
+const int PLUS_EQ_TOKEN = PLUS_PLUS_TOKEN + 1;
+const int MINUS_MINUS_TOKEN = PLUS_EQ_TOKEN + 1;
+const int MINUS_EQ_TOKEN = MINUS_MINUS_TOKEN + 1;
+const int TILDE_SLASH_EQ_TOKEN = MINUS_EQ_TOKEN + 1;
+const int TILDE_SLASH_TOKEN = TILDE_SLASH_EQ_TOKEN + 1;
+const int PERCENT_EQ_TOKEN = TILDE_SLASH_TOKEN + 1;
+const int GT_GT_TOKEN = PERCENT_EQ_TOKEN + 1;
+const int CARET_EQ_TOKEN = GT_GT_TOKEN + 1;
+const int COMMENT_TOKEN = CARET_EQ_TOKEN + 1;
+const int STRING_INTERPOLATION_IDENTIFIER_TOKEN = COMMENT_TOKEN + 1;
+const int QUESTION_PERIOD_TOKEN = STRING_INTERPOLATION_IDENTIFIER_TOKEN + 1;
+const int QUESTION_QUESTION_TOKEN = QUESTION_PERIOD_TOKEN + 1;
+const int QUESTION_QUESTION_EQ_TOKEN = QUESTION_QUESTION_TOKEN + 1;
diff --git a/pkg/front_end/lib/src/fasta/scanner/utf8_bytes_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/utf8_bytes_scanner.dart
new file mode 100644
index 0000000..98f3293
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/scanner/utf8_bytes_scanner.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scanner.utf8_bytes_scanner;
+
+import 'dart:convert' show
+    UNICODE_BOM_CHARACTER_RUNE,
+    UTF8;
+
+import '../scanner.dart' show
+    unicodeReplacementCharacter;
+
+import 'precedence.dart' show
+    PrecedenceInfo;
+
+import 'token.dart' show
+    StringToken,
+    Token;
+
+import 'array_based_scanner.dart' show
+    ArrayBasedScanner;
+
+/**
+ * Scanner that reads from a UTF-8 encoded list of bytes and creates tokens
+ * that points to substrings.
+ */
+class Utf8BytesScanner extends ArrayBasedScanner {
+  /**
+   * The file content.
+   *
+   * The content is zero-terminated.
+   */
+  List<int> bytes;
+
+  /**
+   * Points to the offset of the last byte returned by [advance].
+   *
+   * After invoking [currentAsUnicode], the [byteOffset] points to the last
+   * byte that is part of the (unicode or ASCII) character. That way, [advance]
+   * can always increase the byte offset by 1.
+   */
+  int byteOffset = -1;
+
+  /**
+   * The getter [scanOffset] is expected to return the index where the current
+   * character *starts*. In case of a non-ascii character, after invoking
+   * [currentAsUnicode], the byte offset points to the *last* byte.
+   *
+   * This field keeps track of the number of bytes for the current unicode
+   * character. For example, if bytes 7,8,9 encode one unicode character, the
+   * [byteOffset] is 9 (after invoking [currentAsUnicode]). The [scanSlack]
+   * will be 2, so that [scanOffset] returns 7.
+   */
+  int scanSlack = 0;
+
+  /**
+   * Holds the [byteOffset] value for which the current [scanSlack] is valid.
+   */
+  int scanSlackOffset = -1;
+
+  /**
+   * Returns the byte offset of the first byte that belongs to the current
+   * character.
+   */
+  int get scanOffset {
+    if (byteOffset == scanSlackOffset) {
+      return byteOffset - scanSlack;
+    } else {
+      return byteOffset;
+    }
+  }
+
+  /**
+   * The difference between the number of bytes and the number of corresponding
+   * string characters, up to the current [byteOffset].
+   */
+  int utf8Slack = 0;
+
+  /**
+   * Creates a new Utf8BytesScanner. The source file is expected to be a
+   * [Utf8BytesSourceFile] that holds a list of UTF-8 bytes. Otherwise the
+   * string text of the source file is decoded.
+   *
+   * The list of UTF-8 bytes [file.slowUtf8Bytes()] is expected to return an
+   * array whose last element is '0' to signal the end of the file. If this
+   * is not the case, the entire array is copied before scanning.
+   */
+  Utf8BytesScanner(this.bytes, {bool includeComments: false})
+      : super(includeComments) {
+    assert(bytes.last == 0);
+    // Skip a leading BOM.
+    if (containsBomAt(0)) byteOffset += 3;
+  }
+
+  bool containsBomAt(int offset) {
+    const BOM_UTF8 = const [0xEF, 0xBB, 0xBF];
+
+    return offset + 3 < bytes.length &&
+        bytes[offset] == BOM_UTF8[0] &&
+        bytes[offset + 1] == BOM_UTF8[1] &&
+        bytes[offset + 2] == BOM_UTF8[2];
+  }
+
+  int advance() => bytes[++byteOffset];
+
+  int peek() => bytes[byteOffset + 1];
+
+  /// Returns the unicode code point starting at the byte offset [startOffset]
+  /// with the byte [nextByte].
+  int nextCodePoint(int startOffset, int nextByte) {
+    int expectedHighBytes;
+    if (nextByte < 0xC2) {
+      expectedHighBytes = 1; // Bad code unit.
+    } else if (nextByte < 0xE0) {
+      expectedHighBytes = 2;
+    } else if (nextByte < 0xF0) {
+      expectedHighBytes = 3;
+    } else if (nextByte < 0xF5) {
+      expectedHighBytes = 4;
+    } else {
+      expectedHighBytes = 1; // Bad code unit.
+    }
+    int numBytes = 0;
+    for (int i = 0; i < expectedHighBytes; i++) {
+      if (bytes[byteOffset + i] < 0x80) {
+        break;
+      }
+      numBytes++;
+    }
+    int end = startOffset + numBytes;
+    byteOffset = end - 1;
+    if (expectedHighBytes == 1 || numBytes != expectedHighBytes) {
+      return unicodeReplacementCharacter;
+    }
+    // TODO(lry): measurably slow, decode creates first a Utf8Decoder and a
+    // _Utf8Decoder instance. Also the sublist is eagerly allocated.
+    String codePoint =
+        UTF8.decode(bytes.sublist(startOffset, end), allowMalformed: true);
+    if (codePoint.length == 0) {
+      // The UTF-8 decoder discards leading BOM characters.
+      // TODO(floitsch): don't just assume that removed characters were the
+      // BOM.
+      assert(containsBomAt(startOffset));
+      codePoint = new String.fromCharCode(UNICODE_BOM_CHARACTER_RUNE);
+    }
+    if (codePoint.length == 1) {
+      utf8Slack += (numBytes - 1);
+      scanSlack = numBytes - 1;
+      scanSlackOffset = byteOffset;
+      return codePoint.codeUnitAt(0);
+    } else if (codePoint.length == 2) {
+      utf8Slack += (numBytes - 2);
+      scanSlack = numBytes - 1;
+      scanSlackOffset = byteOffset;
+      stringOffsetSlackOffset = byteOffset;
+      // In case of a surrogate pair, return a single code point.
+      return codePoint.runes.single;
+    } else {
+      return unicodeReplacementCharacter;
+    }
+  }
+
+  int lastUnicodeOffset = -1;
+  int currentAsUnicode(int next) {
+    if (next < 128) return next;
+    // Check if currentAsUnicode was already invoked.
+    if (byteOffset == lastUnicodeOffset) return next;
+    int res = nextCodePoint(byteOffset, next);
+    lastUnicodeOffset = byteOffset;
+    return res;
+  }
+
+  void handleUnicode(int startScanOffset) {
+    int end = byteOffset;
+    // TODO(lry): this measurably slows down the scanner for files with unicode.
+    String s =
+        UTF8.decode(bytes.sublist(startScanOffset, end), allowMalformed: true);
+    utf8Slack += (end - startScanOffset) - s.length;
+  }
+
+  /**
+   * This field remembers the byte offset of the last character decoded with
+   * [nextCodePoint] that used two code units in UTF-16.
+   *
+   * [nextCodePoint] returns a single code point for each unicode character,
+   * even if it needs two code units in UTF-16.
+   *
+   * For example, '\u{1d11e}' uses 4 bytes in UTF-8, and two code units in
+   * UTF-16. The [utf8Slack] is therefore 2. After invoking [nextCodePoint], the
+   * [byteOffset] points to the last (of 4) bytes. The [stringOffset] should
+   * return the offset of the first one, which is one position more left than
+   * the [utf8Slack].
+   */
+  int stringOffsetSlackOffset = -1;
+
+  int get stringOffset {
+    if (stringOffsetSlackOffset == byteOffset) {
+      return byteOffset - utf8Slack - 1;
+    } else {
+      return byteOffset - utf8Slack;
+    }
+  }
+
+  Token firstToken() => tokens.next;
+  Token previousToken() => tail;
+
+  void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
+      [int extraOffset = 0]) {
+    tail.next = new StringToken.fromUtf8Bytes(
+        info, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
+    tail = tail.next;
+  }
+
+  bool atEndOfFile() => byteOffset >= bytes.length - 1;
+}
diff --git a/pkg/front_end/lib/src/fasta/source/README.md b/pkg/front_end/lib/src/fasta/source/README.md
new file mode 100644
index 0000000..7d63b9af
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/README.md
@@ -0,0 +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 file.
+-->
+# Source Builders
+
+Builders that can be shared between multiple implementations of source builders, such as [analyzer](../analyzer/README.md) and [kernel](../kernel/README.md).
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
new file mode 100644
index 0000000..c37cc97
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -0,0 +1,567 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.diet_listener;
+
+import 'package:kernel/ast.dart' show
+    AsyncMarker;
+
+import 'package:kernel/class_hierarchy.dart' show
+    ClassHierarchy;
+
+import 'package:kernel/core_types.dart' show
+    CoreTypes;
+
+import '../parser/parser.dart' show
+    Parser,
+    optional;
+
+import '../scanner/token.dart' show
+    BeginGroupToken,
+    Token;
+
+import '../parser/dart_vm_native.dart' show
+    removeNativeClause,
+    skipNativeClause;
+
+import '../parser/error_kind.dart' show
+    ErrorKind;
+
+import '../util/link.dart' show
+    Link;
+
+import '../errors.dart' show
+    Crash,
+    InputError,
+    inputError,
+    internalError;
+
+import 'stack_listener.dart' show
+    StackListener;
+
+import '../kernel/body_builder.dart' show
+    BodyBuilder;
+
+import '../builder/builder.dart';
+
+import '../analyzer/analyzer.dart';
+
+import '../builder/scope.dart' show
+    Scope;
+
+import '../ast_kind.dart' show
+    AstKind;
+
+import 'source_library_builder.dart' show
+    SourceLibraryBuilder;
+
+import '../kernel/kernel_library_builder.dart' show
+    isConstructorName;
+
+class DietListener extends StackListener {
+  final SourceLibraryBuilder library;
+
+  final ElementStore elementStore;
+
+  final ClassHierarchy hierarchy;
+
+  final CoreTypes coreTypes;
+
+  final AstKind astKind;
+
+  final bool isDartLibrary;
+
+  ClassBuilder currentClass;
+
+  /// For top-level declarations, this is the library scope. For class members,
+  /// this is the instance scope of [currentClass].
+  Scope memberScope;
+
+  DietListener(SourceLibraryBuilder library, this.elementStore, this.hierarchy,
+      this.coreTypes, this.astKind)
+      : library = library,
+        memberScope = library.scope,
+        isDartLibrary = library.uri.scheme == "dart";
+
+  @override
+  Uri get uri => library.uri;
+
+  void discard(int n) {
+    for (int i =0; i < n; i++) {
+      pop();
+    }
+  }
+
+  @override
+  void endMetadataStar(int count, bool forParameter) {
+    debugEvent("MetadataStar");
+  }
+
+  @override
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    debugEvent("Metadata");
+    popIfNotNull(periodBeforeName);
+    discard(1);
+  }
+
+  @override
+  void endPartOf(Token partKeyword, Token semicolon) {
+    debugEvent("PartOf");
+    discard(1);
+  }
+
+  @override
+  void handleNoArguments(Token token) {
+    debugEvent("NoArguments");
+  }
+
+  @override
+  void handleModifiers(int count) {
+    debugEvent("Modifiers");
+  }
+
+  @override
+  void handleNoTypeArguments(Token token) {
+    debugEvent("NoTypeArguments");
+  }
+
+  @override
+  void handleNoType(Token token) {
+    debugEvent("NoType");
+  }
+
+  @override
+  void endType(Token beginToken, Token endToken) {
+    debugEvent("Type");
+    discard(1);
+  }
+
+  @override
+  void endTypeList(int count) {
+    debugEvent("TypeList");
+  }
+
+  @override
+  void endMixinApplication() {
+    debugEvent("MixinApplication");
+  }
+
+  @override
+  void endTypeArguments(int count, Token beginToken, Token endToken) {
+    debugEvent("TypeArguments");
+  }
+
+  @override
+  void endFieldInitializer(Token assignmentOperator) {
+    debugEvent("FieldInitializer");
+  }
+
+  @override
+  void handleNoFieldInitializer(Token token) {
+    debugEvent("NoFieldInitializer");
+  }
+
+  @override
+  void handleNoTypeVariables(Token token) {
+    debugEvent("NoTypeVariables");
+  }
+
+  @override
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+    debugEvent("FormalParameters");
+    assert(count == 0); // Count is always 0 as the diet parser skips formals.
+    if (identical(peek(), "-") && identical(beginToken.next, endToken)) {
+      pop();
+      push("unary-");
+    }
+    push(beginToken);
+  }
+
+  @override
+  void handleNoFormalParameters(Token token) {
+    debugEvent("NoFormalParameters");
+    if (identical(peek(), "-")) {
+      pop();
+      push("unary-");
+    }
+    push(token);
+  }
+
+  @override
+  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+    debugEvent("FunctionTypeAlias");
+    discard(2); // Name + endToken.
+    checkEmpty();
+  }
+
+  @override
+  void endFields(int count, Token beginToken, Token endToken) {
+    debugEvent("Fields");
+    List<String> names = popList(count);
+    Builder builder = lookupBuilder(beginToken, null, names.first);
+    buildFields(beginToken, false, builder.isInstanceMember);
+  }
+
+  @override
+  void handleAsyncModifier(Token asyncToken, Token startToken) {
+    debugEvent("AsyncModifier");
+  }
+
+  @override
+  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+    debugEvent("TopLevelMethod");
+    Token bodyToken = pop();
+    String name = pop();
+    checkEmpty();
+    buildFunctionBody(bodyToken, lookupBuilder(beginToken, getOrSet, name));
+  }
+
+  @override
+  void handleNoFunctionBody(Token token) {
+    debugEvent("NoFunctionBody");
+  }
+
+  @override
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+    debugEvent("TopLevelFields");
+    discard(count);
+    buildFields(beginToken, true, false);
+  }
+
+  @override
+  void handleVoidKeyword(Token token) {
+    debugEvent("VoidKeyword");
+  }
+
+  @override
+  void handleNoInitializers() {
+    debugEvent("NoInitializers");
+  }
+
+  @override
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    debugEvent("Initializers");
+  }
+
+  @override
+  void handleQualified(Token period) {
+    debugEvent("handleQualified");
+    // TODO(ahe): Shared with outline_builder.dart.
+    String name = pop();
+    String receiver = pop();
+    push("$receiver.$name");
+  }
+
+  @override
+  void endLibraryName(Token libraryKeyword, Token semicolon) {
+    debugEvent("endLibraryName");
+    discard(1);
+  }
+
+  @override
+  void beginLiteralString(Token token) {
+    debugEvent("beginLiteralString");
+  }
+
+  @override
+  void endLiteralString(int interpolationCount) {
+    debugEvent("endLiteralString");
+    discard(interpolationCount);
+  }
+
+  @override
+  void handleStringJuxtaposition(int literalCount) {
+    debugEvent("StringJuxtaposition");
+  }
+
+  @override
+  void endDottedName(int count, Token firstIdentifier) {
+    debugEvent("DottedName");
+    discard(count);
+  }
+
+  @override
+  void endConditionalUri(Token ifKeyword, Token equalitySign) {
+    debugEvent("ConditionalUri");
+  }
+
+  @override
+  void endConditionalUris(int count) {
+    debugEvent("ConditionalUris");
+  }
+
+  @override
+  void handleOperatorName(Token operatorKeyword, Token token) {
+    debugEvent("OperatorName");
+    push(token.stringValue);
+  }
+
+  @override
+  void endIdentifierList(int count) {
+    debugEvent("IdentifierList");
+    discard(count);
+  }
+
+  @override
+  void endShow(Token showKeyword) {
+    debugEvent("Show");
+  }
+
+  @override
+  void endHide(Token hideKeyword) {
+    debugEvent("Hide");
+  }
+
+  @override
+  void endCombinators(int count) {
+    debugEvent("Combinators");
+  }
+
+  @override
+  void endImport(Token importKeyword, Token DeferredKeyword, Token asKeyword,
+      Token semicolon) {
+    debugEvent("Import");
+    popIfNotNull(asKeyword);
+  }
+
+  @override
+  void endExport(Token exportKeyword, Token semicolon) {
+    debugEvent("Export");
+  }
+
+  @override
+  void endPart(Token partKeyword, Token semicolon) {
+    debugEvent("Part");
+  }
+
+  @override
+  void endTypeVariable(Token token, Token extendsOrSuper) {
+    debugEvent("TypeVariable");
+    discard(1);
+  }
+
+  @override
+  void endTypeVariables(int count, Token beginToken, Token endToken) {
+    debugEvent("TypeVariables");
+  }
+
+  @override
+  void handleModifier(Token token) {
+    debugEvent("Modifier");
+  }
+
+  @override
+  void endConstructorReference(
+      Token start, Token periodBeforeName, Token endToken) {
+    debugEvent("ConstructorReference");
+    popIfNotNull(periodBeforeName);
+  }
+
+  @override
+  void endFactoryMethod(Token beginToken, Token endToken) {
+    debugEvent("FactoryMethod");
+    BeginGroupToken bodyToken = pop();
+    String name = pop();
+    checkEmpty();
+    if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
+      return;
+    }
+    buildFunctionBody(bodyToken, lookupBuilder(beginToken, null, name));
+  }
+
+  @override
+  void endRedirectingFactoryBody(Token beginToken, Token endToken) {
+    debugEvent("RedirectingFactoryBody");
+    discard(1); // ConstructorReference.
+  }
+
+  @override
+  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+    debugEvent("Method");
+    Token bodyToken = pop();
+    String name = pop();
+    checkEmpty();
+    if (bodyToken == null) {
+      return;
+    }
+    buildFunctionBody(bodyToken, lookupBuilder(beginToken, getOrSet, name));
+  }
+
+  StackListener createListener(MemberBuilder builder, Scope memberScope,
+      bool isInstanceMember, [Scope formalParameterScope]) {
+    switch (astKind) {
+      case AstKind.Kernel:
+        return new BodyBuilder(library, builder, memberScope,
+            formalParameterScope, hierarchy, coreTypes, currentClass,
+            isInstanceMember);
+
+      case AstKind.Analyzer:
+        return new AstBuilder(library, builder, elementStore, memberScope);
+    }
+
+    return internalError("Unknown $astKind");
+  }
+
+  void buildFunctionBody(Token token, ProcedureBuilder builder) {
+    Scope typeParameterScope = builder.computeTypeParameterScope(memberScope);
+    Scope formalParameterScope =
+        builder.computeFormalParameterScope(typeParameterScope);
+    assert(typeParameterScope != null);
+    assert(formalParameterScope != null);
+    parseFunctionBody(
+        createListener(builder, typeParameterScope, builder.isInstanceMember,
+            formalParameterScope),
+        token);
+  }
+
+  void buildFields(Token token, bool isTopLevel, bool isInstanceMember) {
+    parseFields(createListener(null, memberScope, isInstanceMember),
+        token, isTopLevel);
+  }
+
+  @override
+  void endMember() {
+    debugEvent("Member");
+    checkEmpty();
+  }
+
+  @override
+  void beginClassBody(Token token) {
+    debugEvent("beginClassBody");
+    String name = pop();
+    assert(currentClass == null);
+    currentClass = lookupBuilder(token, null, name);
+    assert(memberScope == library.scope);
+    memberScope = currentClass.computeInstanceScope(memberScope);
+  }
+
+  @override
+  void endClassBody(int memberCount, Token beginToken, Token endToken) {
+    debugEvent("ClassBody");
+    currentClass = null;
+    checkEmpty();
+    memberScope = library.scope;
+  }
+
+  @override
+  void endClassDeclaration(int interfacesCount, Token beginToken,
+      Token extendsKeyword, Token implementsKeyword, Token endToken) {
+    debugEvent("ClassDeclaration");
+    checkEmpty();
+  }
+
+  @override
+  void endEnum(Token enumKeyword, Token endBrace, int count) {
+    debugEvent("Enum");
+    discard(count);
+    pop(); // Name.
+    checkEmpty();
+  }
+
+  @override
+  void endNamedMixinApplication(
+      Token classKeyword, Token implementsKeyword, Token endToken) {
+    debugEvent("NamedMixinApplication");
+    pop(); // Name.
+    checkEmpty();
+  }
+
+  @override
+  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+    if (isDartLibrary && kind == ErrorKind.ExpectedBlockToSkip) {
+      Token recover = skipNativeClause(token);
+      if (recover != null) {
+        assert(isTargetingDartVm);
+        return recover;
+      }
+    }
+    return super.handleUnrecoverableError(token, kind, arguments);
+  }
+
+  @override
+  Link<Token> handleMemberName(Link<Token> identifiers) {
+    if (!isDartLibrary || identifiers.isEmpty) return identifiers;
+    return removeNativeClause(identifiers);
+  }
+
+  void parseFunctionBody(StackListener listener, Token token) {
+    try {
+      Parser parser = new Parser(listener);
+      token = parser.parseFormalParametersOpt(token);
+      var formals = listener.pop();
+      listener.checkEmpty();
+      listener.prepareInitializers();
+      token = parser.parseInitializersOpt(token);
+      token = parser.parseAsyncModifier(token);
+      AsyncMarker asyncModifier = listener.pop();
+      bool isExpression = false;
+      bool allowAbstract = true;
+      parser.parseFunctionBody(token, isExpression, allowAbstract);
+      var body = listener.pop();
+      listener.checkEmpty();
+      listener.finishFunction(formals, asyncModifier, body);
+    } on InputError {
+      rethrow;
+    } catch (e, s) {
+      throw new Crash(uri, token.charOffset, e, s);
+    }
+  }
+
+  void parseFields(StackListener listener, Token token, bool isTopLevel) {
+    Parser parser = new Parser(listener);
+    if (isTopLevel) {
+      token = parser.parseTopLevelMember(token);
+    } else {
+      token = parser.parseMember(token);
+    }
+    listener.checkEmpty();
+  }
+
+  Builder lookupBuilder(Token token, Token getOrSet, String name) {
+    Builder builder;
+    if (currentClass != null) {
+      builder = currentClass.members[name];
+      if (builder == null && isConstructorName(name, currentClass.name)) {
+        int index = name.indexOf(".");
+        name = index == -1 ? "" : name.substring(index + 1);
+        builder = currentClass.members[name];
+      }
+    } else {
+      builder = library.members[name];
+    }
+    if (builder == null) {
+      return internalError("@${token.charOffset}: builder not found: $name");
+    }
+    if (builder.next != null) {
+      Builder getterBuilder;
+      Builder setterBuilder;
+      Builder current = builder;
+      while (current != null) {
+        if (current.isGetter && getterBuilder == null) {
+          getterBuilder = current;
+        } else if (current.isSetter && setterBuilder == null) {
+          setterBuilder = current;
+        } else {
+          return inputError(uri, token.charOffset, "Duplicated name: $name");
+        }
+        current = current.next;
+      }
+      assert(getOrSet != null);
+      if (optional("get", getOrSet)) return getterBuilder;
+      if (optional("set", getOrSet)) return setterBuilder;
+    }
+    return builder;
+  }
+
+  @override
+  void debugEvent(String name) {
+    // print("  ${stack.join('\n  ')}");
+    // print(name);
+  }
+
+  bool get isTargetingDartVm {
+    // TODO(ahe): Find a more reliable way to check if this is the Dart VM.
+    return coreTypes.getCoreLibrary("dart:_js_helper") == null;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/source/diet_parser.dart b/pkg/front_end/lib/src/fasta/source/diet_parser.dart
new file mode 100644
index 0000000..20a1cc7
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/diet_parser.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.diet_parser;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    BeginGroupToken,
+    Token;
+
+import 'package:front_end/src/fasta/parser/class_member_parser.dart' show
+    ClassMemberParser;
+
+import 'package:front_end/src/fasta/parser/error_kind.dart' show
+    ErrorKind;
+
+import 'package:front_end/src/fasta/parser/listener.dart' show
+    Listener;
+
+import 'package:front_end/src/fasta/parser/parser.dart' show
+    optional;
+
+// TODO(ahe): Move this to parser package.
+class DietParser extends ClassMemberParser {
+  DietParser(Listener listener, {bool asyncAwaitKeywordsEnabled: false})
+      : super(listener, asyncAwaitKeywordsEnabled: asyncAwaitKeywordsEnabled);
+
+  Token parseFormalParameters(Token token) => skipFormals(token);
+
+  Token skipFormals(Token token) {
+    listener.beginOptionalFormalParameters(token);
+    if (!optional('(', token)) {
+      if (optional(';', token)) {
+        reportRecoverableError(token, ErrorKind.ExpectedOpenParens, {});
+        return token;
+      }
+      return reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
+    }
+    BeginGroupToken beginGroupToken = token;
+    Token endToken = beginGroupToken.endGroup;
+    listener.endFormalParameters(0, token, endToken);
+    return endToken.next;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
new file mode 100644
index 0000000..e010ea9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -0,0 +1,615 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.outline_builder;
+
+import 'package:kernel/ast.dart' show
+    AsyncMarker,
+    ProcedureKind;
+
+import '../parser/parser.dart' show
+    FormalParameterType,
+    optional;
+
+import '../scanner/token.dart' show
+    Token;
+
+import '../util/link.dart' show
+    Link;
+
+import '../combinator.dart' show
+    Combinator;
+
+import '../errors.dart' show
+    internalError;
+
+import '../builder/builder.dart';
+
+import '../modifier.dart' show
+    Modifier;
+
+import 'source_library_builder.dart' show
+    SourceLibraryBuilder;
+
+import 'unhandled_listener.dart' show
+    NullValue,
+    Unhandled,
+    UnhandledListener;
+
+import '../parser/error_kind.dart' show
+    ErrorKind;
+
+import '../parser/dart_vm_native.dart' show
+    removeNativeClause,
+    skipNativeClause;
+
+import '../operator.dart' show
+    Operator,
+    operatorFromString,
+    operatorToString;
+
+import '../quote.dart' show
+    unescapeString;
+
+enum MethodBody {
+  Abstract,
+  Regular,
+  RedirectingFactoryBody,
+}
+
+AsyncMarker asyncMarkerFromTokens(Token asyncToken, Token starToken) {
+  if (asyncToken == null || identical(asyncToken.stringValue, "sync")) {
+    if (starToken == null) {
+      return AsyncMarker.Sync;
+    } else {
+      assert(identical(starToken.stringValue, "*"));
+      return AsyncMarker.SyncStar;
+    }
+  } else  if (identical(asyncToken.stringValue, "async")) {
+    if (starToken == null) {
+      return AsyncMarker.Async;
+    } else {
+      assert(identical(starToken.stringValue, "*"));
+      return AsyncMarker.AsyncStar;
+    }
+  } else {
+    return internalError("Unknown async modifier: $asyncToken");
+  }
+}
+
+class OutlineBuilder extends UnhandledListener {
+  final SourceLibraryBuilder library;
+
+  final bool isDartLibrary;
+
+  String nativeMethodName;
+
+  OutlineBuilder(SourceLibraryBuilder library)
+      : library = library,
+        isDartLibrary = library.uri.scheme == "dart";
+
+  @override
+  Uri get uri => library.uri;
+
+  @override
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    debugEvent("Metadata");
+    List arguments = pop();
+    String postfix = popIfNotNull(periodBeforeName);
+    List<TypeBuilder> typeArguments = pop();
+    if (arguments == null) {
+      String expression = pop();
+      push(new MetadataBuilder.fromExpression(expression, postfix, library,
+              beginToken.charOffset));
+    } else {
+      String typeName = pop();
+      push(new MetadataBuilder.fromConstructor(
+               library.addConstructorReference(
+                   typeName, typeArguments, postfix,
+                   beginToken.next.charOffset),
+               arguments, library, beginToken.charOffset));
+    }
+  }
+
+  @override
+  void endHide(Token hideKeyword) {
+    debugEvent("Hide");
+    List<String> names = pop();
+    push(new Combinator.hide(names, hideKeyword.charOffset, library.fileUri));
+  }
+
+  @override
+  void endShow(Token showKeyword) {
+    debugEvent("Show");
+    List<String> names = pop();
+    push(new Combinator.show(names, showKeyword.charOffset, library.fileUri));
+  }
+
+  @override
+  void endCombinators(int count) {
+    debugEvent("Combinators");
+    push(popList(count) ?? NullValue.Combinators);
+  }
+
+  @override
+  void endExport(Token exportKeyword, Token semicolon) {
+    debugEvent("Export");
+    List<Combinator> combinators = pop();
+    Unhandled conditionalUris = pop();
+    String uri = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addExport(
+        metadata, uri, conditionalUris, combinators, exportKeyword.charOffset);
+    checkEmpty();
+  }
+
+  @override
+  void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
+      Token semicolon) {
+    debugEvent("endImport");
+    List<Combinator> combinators = pop();
+    String prefix = popIfNotNull(asKeyword);
+    Unhandled conditionalUris = pop();
+    String uri = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addImport(metadata, uri, conditionalUris, prefix, combinators,
+        deferredKeyword != null, importKeyword.charOffset,
+        asKeyword?.next?.charOffset ?? -1);
+    checkEmpty();
+  }
+
+  @override
+  void endPart(Token partKeyword, Token semicolon) {
+    debugEvent("Part");
+    String uri = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addPart(metadata, uri);
+    checkEmpty();
+  }
+
+  @override
+  void handleOperatorName(Token operatorKeyword, Token token) {
+    debugEvent("OperatorName");
+    push(operatorFromString(token.stringValue));
+  }
+
+  @override
+  void endIdentifierList(int count) {
+    debugEvent("endIdentifierList");
+    push(popList(count) ?? NullValue.IdentifierList);
+  }
+
+  @override
+  void handleQualified(Token period) {
+    debugEvent("handleQualified");
+    String name = pop();
+    String receiver = pop();
+    push("$receiver.$name");
+  }
+
+  @override
+  void endLibraryName(Token libraryKeyword, Token semicolon) {
+    debugEvent("endLibraryName");
+    String name = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.name = name;
+    library.metadata = metadata;
+  }
+
+  @override
+  void beginClassDeclaration(Token begin, Token name) {
+    library.beginNestedDeclaration(name.value);
+  }
+
+  @override
+  void endClassDeclaration(int interfacesCount, Token beginToken,
+      Token extendsKeyword, Token implementsKeyword, Token endToken) {
+    debugEvent("endClassDeclaration");
+    List<TypeBuilder> interfaces = popList(interfacesCount);
+    TypeBuilder supertype = pop();
+    List<TypeVariableBuilder> typeVariables = pop();
+    String name = pop();
+    int modifiers = Modifier.validate(pop());
+    List<MetadataBuilder> metadata = pop();
+    library.addClass(metadata, modifiers, name, typeVariables, supertype,
+        interfaces, beginToken.charOffset);
+    checkEmpty();
+  }
+
+  ProcedureKind computeProcedureKind(Token token) {
+    if (token == null) return ProcedureKind.Method;
+    if (optional("get", token)) return ProcedureKind.Getter;
+    if (optional("set", token)) return ProcedureKind.Setter;
+    return internalError("Unhandled: ${token.value}");
+  }
+
+  @override
+  void beginTopLevelMethod(Token token, Token name) {
+    library.beginNestedDeclaration(name.value, hasMembers: false);
+  }
+
+  @override
+  void endTopLevelMethod(
+      Token beginToken, Token getOrSet, Token endToken) {
+    debugEvent("endTopLevelMethod");
+    MethodBody kind = pop();
+    AsyncMarker asyncModifier = pop();
+    List<FormalParameterBuilder> formals = pop();
+    List<TypeVariableBuilder> typeVariables = pop();
+    String name = pop();
+    TypeBuilder returnType = pop();
+    int modifiers = Modifier.validate(pop(),
+        isAbstract: kind == MethodBody.Abstract);
+    List<MetadataBuilder> metadata = pop();
+    checkEmpty();
+    library.addProcedure(metadata, modifiers, returnType, name,
+        typeVariables, formals, asyncModifier, computeProcedureKind(getOrSet),
+        beginToken.charOffset, nativeMethodName, isTopLevel: true);
+    nativeMethodName = null;
+  }
+
+  @override
+  void handleNoFunctionBody(Token token) {
+    debugEvent("NoFunctionBody");
+    push(MethodBody.Abstract);
+  }
+
+  @override
+  void handleFunctionBodySkipped(Token token) {
+    debugEvent("handleFunctionBodySkipped");
+    push(MethodBody.Regular);
+  }
+
+  @override
+  void beginMethod(Token token, Token name) {
+    library.beginNestedDeclaration(name.value, hasMembers: false);
+  }
+
+  @override
+  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+    debugEvent("Method");
+    MethodBody bodyKind = pop();
+    if (bodyKind == MethodBody.RedirectingFactoryBody) {
+      // This will cause an error later.
+      pop();
+    }
+    AsyncMarker asyncModifier = pop();
+    List<FormalParameterBuilder> formals = pop();
+    List<TypeVariableBuilder> typeVariables = pop();
+    dynamic nameOrOperator = pop();
+    if (Operator.subtract == nameOrOperator && formals == null) {
+      nameOrOperator = Operator.unaryMinus;
+    }
+    String name;
+    ProcedureKind kind;
+    if (nameOrOperator is Operator) {
+      name = operatorToString(nameOrOperator);
+      kind = ProcedureKind.Operator;
+    } else {
+      name = nameOrOperator;
+      kind = computeProcedureKind(getOrSet);
+    }
+    TypeBuilder returnType = pop();
+    int modifiers = Modifier.validate(pop(),
+        isAbstract: bodyKind == MethodBody.Abstract);
+    List<MetadataBuilder> metadata = pop();
+    library.addProcedure(metadata, modifiers, returnType, name, typeVariables,
+        formals, asyncModifier, kind, beginToken.charOffset, nativeMethodName,
+        isTopLevel: false);
+    nativeMethodName = null;
+  }
+
+  @override
+  void endMixinApplication() {
+    debugEvent("MixinApplication");
+    List<TypeBuilder> mixins = pop();
+    TypeBuilder supertype = pop();
+    push(library.addMixinApplication(supertype, mixins, -1));
+  }
+
+  @override
+  void beginNamedMixinApplication(Token begin, Token name) {
+    library.beginNestedDeclaration(name.value, hasMembers: false);
+  }
+
+  @override
+  void endNamedMixinApplication(
+      Token classKeyword, Token implementsKeyword, Token endToken) {
+    debugEvent("endNamedMixinApplication");
+    List<TypeBuilder> interfaces = popIfNotNull(implementsKeyword);
+    TypeBuilder mixinApplication = pop();
+    List<TypeVariableBuilder> typeVariables = pop();
+    String name = pop();
+    int modifiers = Modifier.validate(pop());
+    List<MetadataBuilder> metadata = pop();
+    library.addNamedMixinApplication(
+        metadata, name, typeVariables, modifiers, mixinApplication, interfaces,
+        classKeyword.charOffset);
+    checkEmpty();
+  }
+
+  @override
+  void endTypeArguments(int count, Token beginToken, Token endToken) {
+    debugEvent("TypeArguments");
+    push(popList(count) ?? NullValue.TypeArguments);
+  }
+
+  @override
+  void endType(Token beginToken, Token endToken) {
+    debugEvent("Type");
+    List<TypeBuilder> arguments = pop();
+    String name = pop();
+    push(library.addNamedType(name, arguments, beginToken.charOffset));
+  }
+
+  @override
+  void endTypeList(int count) {
+    debugEvent("TypeList");
+    push(popList(count) ?? NullValue.TypeList);
+  }
+
+  @override
+  void endTypeVariables(int count, Token beginToken, Token endToken) {
+    debugEvent("TypeVariables");
+    push(popList(count) ?? NullValue.TypeVariables);
+  }
+
+  @override
+  void handleVoidKeyword(Token token) {
+    debugEvent("VoidKeyword");
+    push(library.addVoidType(token.charOffset));
+  }
+
+  @override
+  void endFormalParameter(Token thisKeyword) {
+    debugEvent("FormalParameter");
+    String name = pop();
+    TypeBuilder type = pop();
+    int modifiers = Modifier.validate(pop());
+    List<MetadataBuilder> metadata = pop();
+    // TODO(ahe): Needs begin token.
+    push(library.addFormalParameter(metadata, modifiers, type, name,
+             thisKeyword != null, thisKeyword?.charOffset ?? -1));
+  }
+
+  @override
+  void handleValuedFormalParameter(Token equals, Token token) {
+    debugEvent("ValuedFormalParameter");
+    // Ignored for now.
+  }
+
+  @override
+  void endFunctionTypedFormalParameter(Token token) {
+    debugEvent("FunctionTypedFormalParameter");
+    pop(); // Function type parameters.
+    pop(); // Type variables.
+    String name = pop();
+    pop(); // Return type.
+    push(NullValue.Type);
+    push(name);
+  }
+
+  @override
+  void endOptionalFormalParameters(
+      int count, Token beginToken, Token endToken) {
+    debugEvent("OptionalFormalParameters");
+    FormalParameterType kind = optional("{", beginToken)
+        ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
+    List parameters = popList(count);
+    for (FormalParameterBuilder parameter in parameters) {
+      parameter.kind = kind;
+    }
+    push(parameters);
+  }
+
+  @override
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+    debugEvent("FormalParameters");
+    List formals = popList(count);
+    if (formals != null && formals.isNotEmpty) {
+      var last = formals.last;
+      if (last is List) {
+        // TODO(sigmund): change `List newList` back to `var` (this is a
+        // workaround for issue #28651). Eventually, make optional
+        // formals a separate stack entry (#28673).
+        List newList =
+            new List<FormalParameterBuilder>(formals.length - 1 + last.length);
+        newList.setRange(0, formals.length - 1, formals);
+        newList.setRange(formals.length - 1, newList.length, last);
+        for (int i = 0; i < last.length; i++) {
+          newList[i + formals.length - 1] = last[i];
+        }
+        formals = newList;
+      }
+    }
+    if (formals != null) {
+      for (var formal in formals) {
+        if (formal is! FormalParameterBuilder) {
+          internalError(formals);
+        }
+      }
+      formals = new List<FormalParameterBuilder>.from(formals);
+    }
+    push(formals ?? NullValue.FormalParameters);
+  }
+
+  @override
+  void endEnum(Token enumKeyword, Token endBrace, int count) {
+    List<String> constants = popList(count);
+    String name = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addEnum(metadata, name, constants, enumKeyword.charOffset);
+    checkEmpty();
+  }
+
+  @override
+  void beginFunctionTypeAlias(Token token) {
+    library.beginNestedDeclaration(null, hasMembers: false);
+  }
+
+  @override
+  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+    debugEvent("endFunctionTypeAlias");
+    List<FormalParameterBuilder> formals = pop();
+    List<TypeVariableBuilder> typeVariables = pop();
+    String name = pop();
+    TypeBuilder returnType = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addFunctionTypeAlias(
+        metadata, returnType, name, typeVariables, formals,
+        typedefKeyword.charOffset);
+    checkEmpty();
+  }
+
+  @override
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+    debugEvent("endTopLevelFields");
+    List<String> names = popList(count);
+    TypeBuilder type = pop();
+    int modifiers = Modifier.validate(pop());
+    List<MetadataBuilder> metadata = pop();
+    library.addFields(metadata, modifiers, type, names);
+    checkEmpty();
+  }
+
+  @override
+  void endFields(int count, Token beginToken, Token endToken) {
+    debugEvent("Fields");
+    List<String> names = popList(count);
+    TypeBuilder type = pop();
+    int modifiers = Modifier.validate(pop());
+    List<MetadataBuilder> metadata = pop();
+    library.addFields(metadata, modifiers, type, names);
+  }
+
+  @override
+  void endTypeVariable(Token token, Token extendsOrSuper) {
+    debugEvent("endTypeVariable");
+    TypeBuilder bound = pop();
+    String name = pop();
+    push(library.addTypeVariable(name, bound, token.charOffset));
+  }
+
+  @override
+  void endPartOf(Token partKeyword, Token semicolon) {
+    debugEvent("endPartOf");
+    String name = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addPartOf(metadata, name);
+  }
+
+  @override
+  void endConstructorReference(
+      Token start, Token periodBeforeName, Token endToken) {
+    debugEvent("ConstructorReference");
+    String suffix = popIfNotNull(periodBeforeName);
+    List<TypeBuilder> typeArguments = pop();
+    String name = pop();
+    push(library.addConstructorReference(
+            name, typeArguments, suffix, start.charOffset));
+  }
+
+  @override
+  void beginFactoryMethod(Token token) {
+    library.beginNestedDeclaration(null, hasMembers: false);
+  }
+
+  @override
+  void endFactoryMethod(Token beginToken, Token endToken) {
+    debugEvent("FactoryMethod");
+    MethodBody kind = pop();
+    ConstructorReferenceBuilder redirectionTarget;
+    if (kind == MethodBody.RedirectingFactoryBody) {
+      redirectionTarget = pop();
+    }
+    AsyncMarker asyncModifier = pop();
+    List<FormalParameterBuilder> formals = pop();
+    var name = pop();
+    List<MetadataBuilder> metadata = pop();
+    library.addFactoryMethod(metadata, name, formals, asyncModifier,
+        redirectionTarget, beginToken.charOffset, nativeMethodName);
+    nativeMethodName = null;
+  }
+
+  @override
+  void endRedirectingFactoryBody(Token beginToken, Token endToken) {
+    debugEvent("RedirectingFactoryBody");
+    push(MethodBody.RedirectingFactoryBody);
+  }
+
+  @override
+  void endFieldInitializer(Token assignmentOperator) {
+    debugEvent("FieldInitializer");
+    // Ignoring field initializers for now.
+  }
+
+  @override
+  void handleNoFieldInitializer(Token token) {
+    debugEvent("NoFieldInitializer");
+  }
+
+  @override
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    debugEvent("Initializers");
+    // Ignored for now.
+  }
+
+  @override
+  void handleNoInitializers() {
+    debugEvent("NoInitializers");
+    // This is a constructor initializer and it's ignored for now.
+  }
+
+  @override
+  void endMember() {
+    debugEvent("Member");
+    assert(nativeMethodName == null);
+  }
+
+  @override
+  void endClassBody(int memberCount, Token beginToken, Token endToken) {
+    debugEvent("ClassBody");
+  }
+
+  @override
+  void handleAsyncModifier(Token asyncToken, Token starToken) {
+    debugEvent("AsyncModifier");
+    push(asyncMarkerFromTokens(asyncToken, starToken));
+  }
+
+  @override
+  void handleModifier(Token token) {
+    debugEvent("Modifier");
+    push(new Modifier.fromString(token.stringValue));
+  }
+
+  @override
+  void handleModifiers(int count) {
+    debugEvent("Modifiers");
+    push(popList(count) ?? NullValue.Modifiers);
+  }
+
+  @override
+  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+    if (isDartLibrary && kind == ErrorKind.ExpectedBlockToSkip) {
+      Token recover = skipNativeClause(token);
+      if (recover != null) {
+        nativeMethodName = unescapeString(token.next.value);
+        return recover;
+      }
+    }
+    return super.handleUnrecoverableError(token, kind, arguments);
+  }
+
+  @override
+  Link<Token> handleMemberName(Link<Token> identifiers) {
+    if (!isDartLibrary || identifiers.isEmpty) return identifiers;
+    return removeNativeClause(identifiers);
+  }
+
+  @override
+  void debugEvent(String name) {
+    // printEvent(name);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/source/scope_listener.dart b/pkg/front_end/lib/src/fasta/source/scope_listener.dart
new file mode 100644
index 0000000..7628f85
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/scope_listener.dart
@@ -0,0 +1,212 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.scope_listener;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    Token;
+
+import 'unhandled_listener.dart' show
+    NullValue,
+    UnhandledListener;
+
+import '../builder/scope.dart' show
+    Scope;
+
+export '../builder/scope.dart' show
+    Scope;
+
+export 'unhandled_listener.dart' show
+    NullValue,
+    Unhandled;
+
+enum JumpTargetKind {
+  Break,
+  Continue,
+  Goto, // Continue label in switch.
+}
+
+abstract class ScopeListener<J> extends UnhandledListener {
+  Scope scope;
+
+  J breakTarget;
+
+  J continueTarget;
+
+  ScopeListener(this.scope);
+
+  J createJumpTarget(JumpTargetKind kind, int charOffset);
+
+  J createBreakTarget(int charOffset) {
+    return createJumpTarget(JumpTargetKind.Break, charOffset);
+  }
+
+  J createContinueTarget(int charOffset) {
+    return createJumpTarget(JumpTargetKind.Continue, charOffset);
+  }
+
+  J createGotoTarget(int charOffset) {
+    return createJumpTarget(JumpTargetKind.Goto, charOffset);
+  }
+
+  void enterLocalScope([Scope newScope]) {
+    push(scope);
+    scope = newScope ?? scope.createNestedScope();
+  }
+
+  @override
+  void exitLocalScope() {
+    scope = pop();
+    assert(scope != null);
+  }
+
+  void enterBreakTarget(int charOffset, [J target]) {
+    push(breakTarget ?? NullValue.BreakTarget);
+    breakTarget = target ?? createBreakTarget(charOffset);
+  }
+
+  void enterContinueTarget(int charOffset, [J target]) {
+    push(continueTarget ?? NullValue.ContinueTarget);
+    continueTarget = target ?? createContinueTarget(charOffset);
+  }
+
+  J exitBreakTarget() {
+    J current = breakTarget;
+    breakTarget = pop();
+    return current;
+  }
+
+  J exitContinueTarget() {
+    J current = continueTarget;
+    continueTarget = pop();
+    return current;
+  }
+
+  void enterLoop(int charOffset) {
+    enterBreakTarget(charOffset);
+    enterContinueTarget(charOffset);
+  }
+
+  @override
+  void beginFunctionBody(Token begin) {
+    debugEvent("beginFunctionBody");
+    enterLocalScope();
+  }
+
+  @override
+  void beginForStatement(Token token) {
+    debugEvent("beginForStatement");
+    enterLoop(token.charOffset);
+    enterLocalScope();
+  }
+
+  @override
+  void beginBlock(Token token) {
+    debugEvent("beginBlock");
+    enterLocalScope();
+  }
+
+  @override
+  void beginSwitchBlock(Token token) {
+    debugEvent("beginSwitchBlock");
+    enterLocalScope();
+    enterBreakTarget(token.charOffset);
+  }
+
+  @override
+  void beginDoWhileStatement(Token token) {
+    debugEvent("beginDoWhileStatement");
+    enterLoop(token.charOffset);
+  }
+
+  @override
+  void beginWhileStatement(Token token) {
+    debugEvent("beginWhileStatement");
+    enterLoop(token.charOffset);
+  }
+
+  @override
+  void beginDoWhileStatementBody(Token token) {
+    debugEvent("beginDoWhileStatementBody");
+    enterLocalScope();
+  }
+
+  @override
+  void endDoWhileStatementBody(Token token) {
+    debugEvent("endDoWhileStatementBody");
+    var body = pop();
+    exitLocalScope();
+    push(body);
+  }
+
+  @override
+  void beginWhileStatementBody(Token token) {
+    debugEvent("beginWhileStatementBody");
+    enterLocalScope();
+  }
+
+  @override
+  void endWhileStatementBody(Token token) {
+    debugEvent("endWhileStatementBody");
+    var body = pop();
+    exitLocalScope();
+    push(body);
+  }
+
+  @override
+  void beginForStatementBody(Token token) {
+    debugEvent("beginForStatementBody");
+    enterLocalScope();
+  }
+
+  @override
+  void endForStatementBody(Token token) {
+    debugEvent("endForStatementBody");
+    var body = pop();
+    exitLocalScope();
+    push(body);
+  }
+
+  @override
+  void beginForInBody(Token token) {
+    debugEvent("beginForInBody");
+    enterLocalScope();
+  }
+
+  @override
+  void endForInBody(Token token) {
+    debugEvent("endForInBody");
+    var body = pop();
+    exitLocalScope();
+    push(body);
+  }
+
+  @override
+  void beginThenStatement(Token token) {
+    debugEvent("beginThenStatement");
+    enterLocalScope();
+  }
+
+  @override
+  void endThenStatement(Token token) {
+    debugEvent("endThenStatement");
+    var body = pop();
+    exitLocalScope();
+    push(body);
+  }
+
+  @override
+  void beginElseStatement(Token token) {
+    debugEvent("beginElseStatement");
+    enterLocalScope();
+  }
+
+  @override
+  void endElseStatement(Token token) {
+    debugEvent("endElseStatement");
+    var body = pop();
+    exitLocalScope();
+    push(body);
+  }
+}
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
new file mode 100644
index 0000000..66f49af
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.source_class_builder;
+
+import 'package:kernel/ast.dart' show
+    Class,
+    Constructor,
+    Supertype,
+    TreeNode,
+    setParents;
+
+import '../errors.dart' show
+    internalError;
+
+import '../kernel/kernel_builder.dart' show
+    Builder,
+    ConstructorReferenceBuilder,
+    KernelClassBuilder,
+    KernelFieldBuilder,
+    KernelFunctionBuilder,
+    KernelLibraryBuilder,
+    KernelTypeBuilder,
+    KernelTypeVariableBuilder,
+    LibraryBuilder,
+    MetadataBuilder,
+    ProcedureBuilder,
+    TypeVariableBuilder;
+
+import '../dill/dill_member_builder.dart' show
+    DillMemberBuilder;
+
+import '../util/relativize.dart' show
+    relativizeUri;
+
+Class initializeClass(Class cls, String name, LibraryBuilder parent,
+    int charOffset) {
+  cls ??= new Class(name: name);
+  cls.fileUri ??= relativizeUri(parent.fileUri);
+  if (cls.fileOffset != TreeNode.noOffset) {
+    cls.fileOffset = charOffset;
+  }
+  return cls;
+}
+
+class SourceClassBuilder extends KernelClassBuilder {
+  final Class cls;
+
+  final Map<String, Builder> constructors;
+
+  final Map<String, Builder> membersInScope;
+
+  final List<ConstructorReferenceBuilder> constructorReferences;
+
+  SourceClassBuilder(List<MetadataBuilder> metadata, int modifiers,
+      String name, List<TypeVariableBuilder> typeVariables,
+      KernelTypeBuilder supertype, List<KernelTypeBuilder>interfaces,
+      Map<String, Builder> members, LibraryBuilder parent,
+      this.constructorReferences, int charOffset, [Class cls])
+      : cls = initializeClass(cls, name, parent, charOffset),
+        membersInScope = computeMembersInScope(members),
+        constructors = computeConstructors(members),
+        super(metadata, modifiers, name, typeVariables, supertype, interfaces,
+            members, parent, charOffset);
+
+  int resolveTypes(LibraryBuilder library) {
+    int count = 0;
+    if (typeVariables != null) {
+      for (KernelTypeVariableBuilder t in typeVariables) {
+        cls.typeParameters.add(t.parameter);
+      }
+      setParents(cls.typeParameters, cls);
+      count += cls.typeParameters.length;
+    }
+    return count + super.resolveTypes(library);
+  }
+
+  Class build(KernelLibraryBuilder library) {
+    void buildBuilder(Builder builder) {
+      if (builder is KernelFieldBuilder) {
+        // TODO(ahe): It would be nice to have a common interface for the build
+        // method to avoid duplicating these two cases.
+        cls.addMember(builder.build(library.library));
+      } else if (builder is KernelFunctionBuilder) {
+        cls.addMember(builder.build(library.library));
+      } else {
+        internalError("Unhandled builder: ${builder.runtimeType}");
+      }
+    }
+    members.forEach((String name, Builder builder) {
+      do {
+        buildBuilder(builder);
+        builder = builder.next;
+      } while (builder != null);
+    });
+    cls.supertype = supertype?.buildSupertype();
+    // TODO(ahe): If `cls.supertype` is null, and this isn't Object, report a
+    // compile-time error.
+    cls.isAbstract = isAbstract;
+    if (interfaces != null) {
+      for (KernelTypeBuilder interface in interfaces) {
+        Supertype supertype = interface.buildSupertype();
+        if (supertype != null) {
+          // TODO(ahe): Report an error if supertype is null.
+          cls.implementedTypes.add(supertype);
+        }
+      }
+    }
+    return cls;
+  }
+
+  Builder findConstructorOrFactory(String name) => constructors[name];
+
+  void addSyntheticConstructor(Constructor constructor) {
+    String name = constructor.name.name;
+    cls.constructors.add(constructor);
+    constructor.parent = cls;
+    DillMemberBuilder memberBuilder = new DillMemberBuilder(constructor, this);
+    memberBuilder.next = constructors[name];
+    constructors[name] = memberBuilder;
+  }
+}
+
+Map<String, Builder> computeMembersInScope(Map<String, Builder> members) {
+  Map<String, Builder> membersInScope = <String, Builder>{};
+  members.forEach((String name, Builder builder) {
+    if (builder is ProcedureBuilder) {
+      if (builder.isConstructor || builder.isFactory) return;
+    }
+    membersInScope[name] = builder;
+  });
+  return membersInScope;
+}
+
+Map<String, Builder> computeConstructors(Map<String, Builder> members) {
+  Map<String, Builder> constructors = <String, Builder>{};
+  members.forEach((String name, Builder builder) {
+    if (builder is ProcedureBuilder &&
+        (builder.isConstructor || builder.isFactory)) {
+      constructors[name] = builder;
+    }
+  });
+  return constructors;
+}
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
new file mode 100644
index 0000000..4da1f85
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -0,0 +1,446 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.source_library_builder;
+
+import 'package:kernel/ast.dart' show
+    AsyncMarker,
+    ProcedureKind;
+
+import '../combinator.dart' show
+    Combinator;
+
+import '../errors.dart' show
+    internalError;
+
+import '../import.dart' show
+    Import;
+
+import 'source_loader.dart' show
+    SourceLoader;
+
+import '../builder/scope.dart' show
+    Scope;
+
+import '../builder/builder.dart' show
+    Builder,
+    ConstructorReferenceBuilder,
+    FormalParameterBuilder,
+    LibraryBuilder,
+    MemberBuilder,
+    MetadataBuilder,
+    PrefixBuilder,
+    ProcedureBuilder,
+    TypeBuilder,
+    TypeDeclarationBuilder,
+    TypeVariableBuilder,
+    Unhandled;
+
+abstract class SourceLibraryBuilder<T extends TypeBuilder, R>
+    extends LibraryBuilder<T, R> {
+  final SourceLoader loader;
+
+  final DeclarationBuilder<T> libraryDeclaration =
+      new DeclarationBuilder<T>(<String, Builder>{}, null);
+
+  final List<ConstructorReferenceBuilder> constructorReferences =
+      <ConstructorReferenceBuilder>[];
+
+  final List<SourceLibraryBuilder<T, R>> parts = <SourceLibraryBuilder<T, R>>[];
+
+  final List<Import> imports = <Import>[];
+
+  final Map<String, Builder> exports = <String, Builder>{};
+
+  final Scope scope = new Scope(<String, Builder>{}, null, isModifiable: false);
+
+  final Uri fileUri;
+
+  String name;
+
+  String partOf;
+
+  List<MetadataBuilder> metadata;
+
+  /// The current declaration that is being built. When we start parsing a
+  /// declaration (class, method, and so on), we don't have enough information
+  /// to create a builder and this object records its members and types until,
+  /// for example, [addClass] is called.
+  DeclarationBuilder<T> currentDeclaration;
+
+  SourceLibraryBuilder(this.loader, Uri fileUri)
+      : fileUri = fileUri, super(fileUri) {
+    currentDeclaration = libraryDeclaration;
+  }
+
+  Uri get uri;
+
+  bool get isPart => partOf != null;
+
+  Map<String, Builder> get members => libraryDeclaration.members;
+
+  List<T> get types => libraryDeclaration.types;
+
+  /// When parsing a class, this returns a map of its members (that have been
+  /// parsed so far).
+  Map<String, MemberBuilder> get classMembers {
+    assert(currentDeclaration.parent == libraryDeclaration);
+    return currentDeclaration.members;
+  }
+
+  T addNamedType(String name, List<T> arguments, int charOffset);
+
+  T addMixinApplication(T supertype, List<T> mixins, int charOffset);
+
+  T addType(T type) {
+    currentDeclaration.addType(type);
+    return type;
+  }
+
+  T addVoidType(int charOffset);
+
+  ConstructorReferenceBuilder addConstructorReference(
+      String name, List<T> typeArguments, String suffix, int charOffset) {
+    ConstructorReferenceBuilder ref = new ConstructorReferenceBuilder(name,
+        typeArguments, suffix, this, charOffset);
+    constructorReferences.add(ref);
+    return ref;
+  }
+
+  void beginNestedDeclaration(String name, {bool hasMembers}) {
+    currentDeclaration =
+        new DeclarationBuilder(<String, MemberBuilder>{}, name, currentDeclaration);
+  }
+
+  DeclarationBuilder<T> endNestedDeclaration() {
+    DeclarationBuilder<T> previous = currentDeclaration;
+    currentDeclaration = currentDeclaration.parent;
+    return previous;
+  }
+
+  Uri resolve(String path) => uri.resolve(path);
+
+  void addExport(List<MetadataBuilder> metadata, String uri,
+      Unhandled conditionalUris, List<Combinator> combinators, int charOffset) {
+    loader.read(resolve(uri)).addExporter(this, combinators, charOffset);
+  }
+
+  void addImport(List<MetadataBuilder> metadata, String uri,
+      Unhandled conditionalUris, String prefix, List<Combinator> combinators,
+      bool deferred, int charOffset, int prefixCharOffset) {
+    imports.add(new Import(this, loader.read(resolve(uri)), prefix, combinators,
+            charOffset, prefixCharOffset));
+  }
+
+  void addPart(List<MetadataBuilder> metadata, String path) {
+    Uri resolvedUri;
+    Uri newFileUri;
+    if (uri.scheme == "dart") {
+      resolvedUri = new Uri(scheme: "dart", path: "${uri.path}/$path");
+      newFileUri = fileUri.resolve(path);
+    } else {
+      resolvedUri = uri.resolve(path);
+      newFileUri = fileUri.resolve(path);
+    }
+    parts.add(loader.read(resolvedUri, newFileUri));
+  }
+
+  void addPartOf(List<MetadataBuilder> metadata, String name) {
+    partOf = name;
+  }
+
+  void addClass(List<MetadataBuilder> metadata,
+      int modifiers, String name,
+      List<TypeVariableBuilder> typeVariables, T supertype,
+      List<T> interfaces, int charOffset);
+
+  void addNamedMixinApplication(
+      List<MetadataBuilder> metadata, String name,
+      List<TypeVariableBuilder> typeVariables, int modifiers,
+      T mixinApplication, List<T> interfaces, int charOffset);
+
+  void addField(List<MetadataBuilder> metadata,
+      int modifiers, T type, String name, int charOffset);
+
+  void addFields(List<MetadataBuilder> metadata, int modifiers,
+      T type, List<String> names) {
+    for (String name in names) {
+      // TODO(ahe): Get charOffset of name.
+      addField(metadata, modifiers, type, name, -1);
+    }
+  }
+
+  void addProcedure(List<MetadataBuilder> metadata,
+      int modifiers, T returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals, AsyncMarker asyncModifier,
+      ProcedureKind kind, int charOffset, String nativeMethodName,
+      {bool isTopLevel});
+
+  void addEnum(List<MetadataBuilder> metadata, String name,
+      List<String> constants, int charOffset);
+
+  void addFunctionTypeAlias(List<MetadataBuilder> metadata,
+      T returnType, String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals, int charOffset);
+
+  void addFactoryMethod(List<MetadataBuilder> metadata,
+      ConstructorReferenceBuilder name, List<FormalParameterBuilder> formals,
+      AsyncMarker asyncModifier, ConstructorReferenceBuilder redirectionTarget,
+      int charOffset, String nativeMethodName);
+
+  FormalParameterBuilder addFormalParameter(
+      List<MetadataBuilder> metadata, int modifiers,
+      T type, String name, bool hasThis, int charOffset);
+
+  TypeVariableBuilder addTypeVariable(String name, T bound, int charOffset);
+
+  Builder addBuilder(String name, Builder builder, int charOffset) {
+    if (name.indexOf(".") != -1) {
+      addCompileTimeError(charOffset, "Only constructors and factories can have"
+          " names containing a period ('.'): $name");
+    }
+    // TODO(ahe): Set the parent correctly here. Could then change the
+    // implementation of MemberBuilder.isTopLevel to test explicitly for a
+    // LibraryBuilder.
+    if (currentDeclaration == libraryDeclaration) {
+      if (builder is MemberBuilder) {
+        builder.parent = this;
+      } else if (builder is TypeDeclarationBuilder) {
+        builder.parent = this;
+      } else if (builder is PrefixBuilder) {
+        assert(builder.parent == this);
+      } else {
+        return internalError("Unhandled: ${builder.runtimeType}");
+      }
+    } else {
+      assert(currentDeclaration.parent == libraryDeclaration);
+    }
+    Map<String, Builder> members = currentDeclaration.members;
+    Builder existing = members[name];
+    builder.next = existing;
+    if (builder is PrefixBuilder && existing is PrefixBuilder) {
+      assert(existing.next == null);
+      builder.exports.forEach((String name, Builder builder) {
+        Builder other = existing.exports.putIfAbsent(name, () => builder);
+        if (other != builder) {
+          existing.exports[name] =
+              other.combineAmbiguousImport(name, builder, this);
+        }
+      });
+      return existing;
+    } else if (existing != null && (existing.next != null ||
+            ((!existing.isGetter || !builder.isSetter) &&
+                (!existing.isSetter || !builder.isGetter)))) {
+      addCompileTimeError(charOffset, "Duplicated definition of '$name'.");
+    }
+    return members[name] = builder;
+  }
+
+  void buildBuilder(Builder builder);
+
+  R build() {
+    members.forEach((String name, Builder builder) {
+      do {
+        buildBuilder(builder);
+        builder = builder.next;
+      } while (builder != null);
+    });
+    return null;
+  }
+
+  void validatePart() {
+    if (parts.isNotEmpty) {
+      internalError("Part with parts: $uri");
+    }
+    if (exporters.isNotEmpty) {
+      internalError(
+          "${exporters.first.exporter.uri} attempts to export the part $uri.");
+    }
+  }
+
+  void includeParts() {
+    for (SourceLibraryBuilder<T, R> part in parts.toList()) {
+      includePart(part);
+    }
+  }
+
+  void includePart(SourceLibraryBuilder<T, R> part) {
+    if (name != null) {
+      if (part.partOf == null) {
+        print("${part.uri} has no 'part of' declaration but is used as a part "
+            "by ${name} ($uri)");
+        parts.remove(part);
+        return;
+      }
+      if (part.partOf != name) {
+        print("${part.uri} is part of '${part.partOf}' but is used as a part "
+            "by '${name}' ($uri)");
+        parts.remove(part);
+        return;
+      }
+    }
+    part.members.forEach((String name, Builder builder) {
+      if (builder.next != null) {
+        assert(builder.next.next == null);
+        addBuilder(name, builder.next, builder.next.charOffset);
+      }
+      addBuilder(name, builder, builder.charOffset);
+    });
+    types.addAll(part.types);
+    constructorReferences.addAll(part.constructorReferences);
+    part.partOfLibrary = this;
+    // TODO(ahe): Include metadata from part?
+  }
+
+  void buildInitialScopes() {
+    members.forEach(addToExportScope);
+    members.forEach(addToScope);
+  }
+
+  void addImportsToScope() {
+    bool explicitCoreImport = this == loader.coreLibrary;
+    for (Import import in imports) {
+      if (import.imported == loader.coreLibrary) {
+        explicitCoreImport = true;
+      }
+      import.finalizeImports(this);
+    }
+    if (!explicitCoreImport) {
+      loader.coreLibrary.exports.forEach(addToScope);
+    }
+  }
+
+  void addToScope(String name, Builder member) {
+    Builder existing = scope.lookup(name, member.charOffset, fileUri);
+    if (existing != null) {
+      if (existing != member) {
+        scope.local[name] = existing.combineAmbiguousImport(name, member, this);
+      }
+      // TODO(ahe): handle duplicated names.
+    } else {
+      scope.local[name] = member;
+    }
+  }
+
+  bool addToExportScope(String name, Builder member) {
+    if (name.startsWith("_")) return false;
+    if (member is PrefixBuilder) return false;
+    Builder existing = exports[name];
+    if (existing != null) {
+      // TODO(ahe): handle duplicated names.
+      return false;
+    } else {
+      exports[name] = member;
+    }
+    return true;
+  }
+
+  int resolveTypes(_) {
+    int typeCount = types.length;
+    for (T t in types) {
+      t.resolveIn(scope);
+    }
+    members.forEach((String name, Builder member) {
+      typeCount += member.resolveTypes(this);
+    });
+    return typeCount;
+  }
+
+  int resolveConstructors(_) {
+    int count = 0;
+    members.forEach((String name, Builder member) {
+      count += member.resolveConstructors(this);
+    });
+    return count;
+  }
+
+  List<TypeVariableBuilder> copyTypeVariables(
+      List<TypeVariableBuilder> original);
+}
+
+/// Unlike [Scope], this scope is used during construction of builders to
+/// ensure types and members are added to and resolved in the correct location.
+class DeclarationBuilder<T extends TypeBuilder> {
+  final DeclarationBuilder<T> parent;
+
+  final Map<String, Builder> members;
+
+  final List<T> types = <T>[];
+
+  final String name;
+
+  final Map<ProcedureBuilder, DeclarationBuilder<T>> factoryDeclarations =
+      <ProcedureBuilder, DeclarationBuilder<T>>{};
+
+  DeclarationBuilder(this.members, this.name, [this.parent]);
+
+  void addMember(String name, MemberBuilder builder) {
+    if (members == null) {
+      parent.addMember(name, builder);
+    } else {
+      members[name] = builder;
+    }
+  }
+
+  MemberBuilder lookupMember(String name) {
+    return members == null ? parent.lookupMember(name) : members[name];
+  }
+
+  void addType(T type) {
+    types.add(type);
+  }
+
+  /// Resolves type variables in [types] and propagate other types to [parent].
+  void resolveTypes(List<TypeVariableBuilder> typeVariables,
+      SourceLibraryBuilder library) {
+    // TODO(ahe): The input to this method, [typeVariables], shouldn't be just
+    // type variables. It should be everything that's in scope, for example,
+    // members (of a class) or formal parameters (of a method).
+    if (typeVariables == null) {
+      // If there are no type variables in the scope, propagate our types to be
+      // resolved in the parent declaration.
+      factoryDeclarations.forEach((_, DeclarationBuilder<T> declaration) {
+        parent.types.addAll(declaration.types);
+      });
+      parent.types.addAll(types);
+    } else {
+      factoryDeclarations.forEach(
+          (ProcedureBuilder procedure, DeclarationBuilder<T> declaration) {
+        assert(procedure.typeVariables.isEmpty);
+        procedure.typeVariables.addAll(
+            library.copyTypeVariables(typeVariables));
+        declaration.resolveTypes(procedure.typeVariables, library);
+      });
+      Map<String, TypeVariableBuilder> map = <String, TypeVariableBuilder>{};
+      for (TypeVariableBuilder builder in typeVariables) {
+        map[builder.name] = builder;
+      }
+      for (T type in types) {
+        String name = type.name;
+        TypeVariableBuilder builder;
+        if (name != null) {
+          builder = map[name];
+        }
+        if (builder == null) {
+          // Since name didn't resolve in this scope, propagate it to the
+          // parent declaration.
+          parent.addType(type);
+        } else {
+          type.bind(builder);
+        }
+      }
+    }
+    types.clear();
+  }
+
+  /// Called to register [procedure] as a factory whose types are collected in
+  /// [factoryDeclaration]. Later, once the class has been built, we can
+  /// synthesize type variables on the factory matching the class'.
+  void addFactoryDeclaration(
+      ProcedureBuilder procedure, DeclarationBuilder<T> factoryDeclaration) {
+    factoryDeclarations[procedure] = factoryDeclaration;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
new file mode 100644
index 0000000..c2a6b5e
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -0,0 +1,365 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.source_loader;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    FileSystemException;
+
+import 'package:front_end/src/fasta/scanner/io.dart' show
+    readBytesFromFile;
+
+import 'package:front_end/src/fasta/scanner.dart' show
+    ErrorToken,
+    Token,
+    scan;
+
+import 'package:front_end/src/fasta/parser/class_member_parser.dart' show
+    ClassMemberParser;
+
+import 'package:kernel/ast.dart' show
+    Program;
+
+import 'package:kernel/class_hierarchy.dart' show
+    ClassHierarchy;
+
+import 'package:kernel/core_types.dart' show
+    CoreTypes;
+
+import '../errors.dart' show
+    InputError,
+    inputError;
+
+import '../export.dart' show
+    Export;
+
+import '../analyzer/element_store.dart' show
+    ElementStore;
+
+import '../builder/builder.dart' show
+    Builder,
+    ClassBuilder,
+    LibraryBuilder;
+
+import 'outline_builder.dart' show
+    OutlineBuilder;
+
+import '../loader.dart' show
+    Loader;
+
+import '../target_implementation.dart' show
+    TargetImplementation;
+
+import 'diet_listener.dart' show
+    DietListener;
+
+import 'diet_parser.dart' show
+    DietParser;
+
+import 'source_library_builder.dart' show
+    SourceLibraryBuilder;
+
+import '../ast_kind.dart' show
+    AstKind;
+
+class SourceLoader<L> extends Loader<L> {
+  // Used when building directly to kernel.
+  ClassHierarchy hierarchy;
+  CoreTypes coreTypes;
+
+  // Used when building analyzer ASTs.
+  ElementStore elementStore;
+
+  SourceLoader(TargetImplementation target)
+      : super(target);
+
+  Future<Token> tokenize(SourceLibraryBuilder library,
+      {bool suppressLexicalErrors: false}) async {
+    Uri uri = library.fileUri;
+    if (uri == null || uri.scheme != "file") {
+      return inputError(library.uri, -1, "Not found: ${library.uri}.");
+    }
+    try {
+      List<int> bytes = await readBytesFromFile(uri);
+      byteCount += bytes.length - 1;
+      Token token = scan(bytes).tokens;
+      while (token is ErrorToken) {
+        if (!suppressLexicalErrors) {
+          ErrorToken error = token;
+          String message = new InputError(
+              uri, token.charOffset, error.assertionMessage).format();
+          print(message);
+        }
+        token = token.next;
+      }
+      return token;
+    } on FileSystemException catch (e) {
+      String message = e.message;
+      String osMessage = e.osError?.message;
+      if (osMessage != null && osMessage.isNotEmpty) {
+        message = osMessage;
+      }
+      return inputError(uri, -1, message);
+    }
+  }
+
+  Future<Null> buildOutline(SourceLibraryBuilder library) async {
+    Token tokens = await tokenize(library);
+    if (tokens == null) return;
+    OutlineBuilder listener = new OutlineBuilder(library);
+    new ClassMemberParser(listener).parseUnit(tokens);
+  }
+
+  Future<Null> buildBody(LibraryBuilder library, AstKind astKind) async {
+    if (library is SourceLibraryBuilder) {
+      // We tokenize source files twice to keep memory usage low. This is the
+      // second time, and the first time was in [buildOutline] above. So this
+      // time we suppress lexical errors.
+      Token tokens = await tokenize(library, suppressLexicalErrors: true);
+      if (tokens == null) return;
+      DietListener listener = new DietListener(
+          library, elementStore, hierarchy, coreTypes, astKind);
+      DietParser parser = new DietParser(listener);
+      parser.parseUnit(tokens);
+      for (SourceLibraryBuilder part in library.parts) {
+        Token tokens = await tokenize(part);
+        if (tokens != null) {
+          parser.parseUnit(tokens);
+        }
+      }
+    }
+  }
+
+  void resolveParts() {
+    List<Uri> parts = <Uri>[];
+    builders.forEach((Uri uri, LibraryBuilder library) {
+        if (library is SourceLibraryBuilder) {
+          if (library.isPart) {
+            library.validatePart();
+            parts.add(uri);
+          } else {
+            library.includeParts();
+          }
+        }
+    });
+    parts.forEach(builders.remove);
+    ticker.logMs("Resolved parts");
+  }
+
+  void computeLibraryScopes() {
+    Set<LibraryBuilder> exporters = new Set<LibraryBuilder>();
+    Set<LibraryBuilder> exportees = new Set<LibraryBuilder>();
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      if (library is SourceLibraryBuilder) {
+        library.buildInitialScopes();
+      }
+      if (library.exporters.isNotEmpty) {
+        exportees.add(library);
+        for (Export exporter in library.exporters) {
+          exporters.add(exporter.exporter);
+        }
+      }
+    });
+    Set<SourceLibraryBuilder> both = new Set<SourceLibraryBuilder>();
+    for (LibraryBuilder exported in exportees) {
+      if (exporters.contains(exported)) {
+        both.add(exported);
+      }
+      for (Export export in exported.exporters) {
+        exported.exports.forEach(export.addToExportScope);
+      }
+    }
+    bool wasChanged = false;
+    do {
+      wasChanged = false;
+      for (SourceLibraryBuilder exported in both) {
+        for (Export export in exported.exporters) {
+          SourceLibraryBuilder exporter = export.exporter;
+          exported.exports.forEach((String name, Builder member) {
+            if (exporter.addToExportScope(name, member)) {
+              wasChanged = true;
+            }
+          });
+        }
+      }
+    } while (wasChanged);
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      if (library is SourceLibraryBuilder) {
+        library.addImportsToScope();
+      }
+    });
+    ticker.logMs("Computed library scopes");
+    // debugPrintExports();
+  }
+
+  void debugPrintExports() {
+    // TODO(sigmund): should be `covarint SourceLibraryBuilder`.
+    builders.forEach((Uri uri, dynamic l) {
+      SourceLibraryBuilder library = l;
+      Set<Builder> members = new Set<Builder>();
+      library.members.forEach((String name, Builder member) {
+        while (member != null) {
+          members.add(member);
+          member = member.next;
+        }
+      });
+      List<String> exports = <String>[];
+      library.exports.forEach((String name, Builder member) {
+        while (member != null) {
+          if (!members.contains(member)) {
+            exports.add(name);
+          }
+          member = member.next;
+        }
+      });
+      if (exports.isNotEmpty) {
+        print("$uri exports $exports");
+      }
+    });
+  }
+
+  void resolveTypes() {
+    int typeCount = 0;
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      typeCount += library.resolveTypes(null);
+    });
+    ticker.logMs("Resolved $typeCount types");
+  }
+
+  void finishStaticInvocations() {
+    int count = 0;
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      count += library.finishStaticInvocations();
+    });
+    ticker.logMs("Finished static invocations $count");
+  }
+
+  void resolveConstructors() {
+    int count = 0;
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      count += library.resolveConstructors(null);
+    });
+    ticker.logMs("Resolved $count constructors");
+  }
+
+  void finishTypeVariables(ClassBuilder object) {
+    int count = 0;
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      count += library.finishTypeVariables(object);
+    });
+    ticker.logMs("Resolved $count type-variable bounds");
+  }
+
+  void finishNativeMethods() {
+    int count = 0;
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      count += library.finishNativeMethods();
+    });
+    ticker.logMs("Finished $count native methods");
+  }
+
+  /// Returns all the supertypes (including interfaces) of [cls]
+  /// transitively. Includes [cls].
+  Set<ClassBuilder> allSupertypes(ClassBuilder cls) {
+    int length = 0;
+    Set<ClassBuilder> result = new Set<ClassBuilder>()..add(cls);
+    while (length != result.length) {
+      length = result.length;
+      result.addAll(directSupertypes(result));
+    }
+    return result;
+  }
+
+  /// Returns the direct supertypes (including interface) of [classes]. A class
+  /// from [classes] is only included if it is a supertype of one of the other
+  /// classes in [classes].
+  Set<ClassBuilder> directSupertypes(Iterable<ClassBuilder> classes) {
+    Set<ClassBuilder> result = new Set<ClassBuilder>();
+    for (ClassBuilder cls in classes) {
+      target.addDirectSupertype(cls, result);
+    }
+    return result;
+  }
+
+  /// Computes a set of classes that may have cycles. The set is empty if there
+  /// are no cycles. If the set isn't empty, it will include supertypes of
+  /// classes with cycles, as well as the classes with cycles.
+  ///
+  /// It is assumed that [classes] is a transitive closure with respect to
+  /// supertypes.
+  Iterable<ClassBuilder> cyclicCandidates(Iterable<ClassBuilder> classes) {
+    // The candidates are found by a fixed-point computation.
+    //
+    // On each iteration, the classes that have no supertypes in the input set
+    // will be removed.
+    //
+    // If there are no cycles, eventually, the set will converge on Object, and
+    // the next iteration will make the set empty (as Object has no
+    // supertypes).
+    //
+    // On the other hand, if there is a cycle, the cycle will remain in the
+    // set, and so will its supertypes, and eventually the input and output set
+    // will have the same length.
+    Iterable<ClassBuilder> input = const [];
+    Iterable<ClassBuilder> output = classes;
+    while (input.length != output.length) {
+      input = output;
+      output = directSupertypes(input);
+    }
+    return output;
+  }
+
+  void checkSemantics() {
+    List<ClassBuilder> allClasses = target.collectAllClasses();
+    Iterable<ClassBuilder> candidates = cyclicCandidates(allClasses);
+    Map<ClassBuilder, Set<ClassBuilder>> realCycles =
+        <ClassBuilder, Set<ClassBuilder>>{};
+    for (ClassBuilder cls in candidates) {
+      Set<ClassBuilder> cycles = cyclicCandidates(allSupertypes(cls));
+      if (cycles.isNotEmpty) {
+        realCycles[cls] = cycles;
+      }
+    }
+    Set<ClassBuilder> reported = new Set<ClassBuilder>();
+    realCycles.forEach((ClassBuilder cls, Set<ClassBuilder> cycles) {
+      target.breakCycle(cls);
+      if (reported.add(cls)) {
+        List<ClassBuilder> involved = <ClassBuilder>[];
+        for (ClassBuilder cls in cycles) {
+          if (realCycles.containsKey(cls)) {
+            involved.add(cls);
+            reported.add(cls);
+          }
+        }
+        print("${cls.name} is a supertype of itself via "
+            "${involved.map((c) => c.name).join(' ')}");
+      }
+    });
+    ticker.logMs("Found cycles");
+  }
+
+  void buildProgram() {
+    builders.forEach((Uri uri, LibraryBuilder library) {
+      if (library is SourceLibraryBuilder) {
+        libraries.add(library.build());
+      }
+    });
+    ticker.logMs("Built program");
+  }
+
+  void buildElementStore() {
+    elementStore = new ElementStore(coreLibrary, builders);
+    ticker.logMs("Built analyzer element model.");
+  }
+
+  void computeHierarchy(Program program) {
+    hierarchy = new ClassHierarchy(program);
+    ticker.logMs("Computed class hierarchy");
+    coreTypes = new CoreTypes(program);
+    ticker.logMs("Computed core types");
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/source/stack_listener.dart b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
new file mode 100644
index 0000000..0601d26
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
@@ -0,0 +1,241 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.stack_listener;
+
+import 'dart:collection' show
+    Queue;
+
+import 'package:front_end/src/fasta/parser.dart' show
+    ErrorKind,
+    Listener;
+
+import 'package:front_end/src/fasta/scanner.dart' show
+    BeginGroupToken,
+    Token;
+
+import 'package:kernel/ast.dart' show
+    AsyncMarker;
+
+import '../errors.dart' show
+    inputError,
+    internalError;
+
+import '../quote.dart' show
+    unescapeString;
+
+enum NullValue {
+  Arguments,
+  Block,
+  BreakTarget,
+  CascadeReceiver,
+  Combinators,
+  ContinueTarget,
+  Expression,
+  FieldInitializer,
+  FormalParameters,
+  FunctionBody,
+  IdentifierList,
+  Initializers,
+  Metadata,
+  Modifiers,
+  SwitchScope,
+  Type,
+  TypeArguments,
+  TypeList,
+  TypeVariable,
+  TypeVariables,
+}
+
+abstract class StackListener extends Listener {
+  final Queue<Object> stack = new Queue<Object>();
+
+  Uri get uri;
+
+  // TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
+  // and ast_builder.dart.
+  void finishFunction(
+      covariant formals, AsyncMarker asyncModifier, covariant body) {
+    return internalError("Unsupported operation");
+  }
+
+  // TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
+  // and ast_builder.dart.
+  void exitLocalScope() => internalError("Unsupported operation");
+
+  // TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
+  // and ast_builder.dart.
+  void prepareInitializers() => internalError("Unsupported operation");
+
+  void push(Object node) {
+    if (node == null) internalError("null not allowed.");
+    stack.addLast(node);
+  }
+
+  Object peek() {
+    Object node = stack.last;
+    return node is NullValue ? null : node;
+  }
+
+  Object pop() {
+    Object node = stack.removeLast();
+    return node is NullValue ? null : node;
+  }
+
+  Object popIfNotNull(Object value) {
+    return value == null ? null : pop();
+  }
+
+  List popList(int n) {
+    if (n == 0) return null;
+    List list = new List.filled(n, null, growable: true);
+    for (int i = n - 1; i >= 0; i--) {
+      list[i] = pop();
+    }
+    return list;
+  }
+
+  void debugEvent(String name) {
+    // printEvent(name);
+  }
+
+  void printEvent(String name) {
+    for (Object o in stack) {
+      String s = "  $o";
+      int index = s.indexOf("\n");
+      if (index != -1) {
+        s = s.substring(0, index) + "...";
+      }
+      print(s);
+    }
+    print(name);
+  }
+
+  @override
+  void logEvent(String name) {
+    internalError("Unhandled event: $name in $runtimeType $uri:\n"
+        "  ${stack.join('\n  ')}");
+  }
+
+  @override
+  void handleIdentifier(Token token) {
+    debugEvent("handleIdentifier");
+    push(token.value);
+  }
+
+  @override
+  void endInitializer(Token token) {
+    debugEvent("Initializer");
+  }
+
+  void checkEmpty() {
+    if (stack.isNotEmpty) {
+      internalError("${runtimeType}: Stack not empty $uri:\n"
+          "  ${stack.join('\n  ')}");
+    }
+    if (recoverableErrors.isNotEmpty) {
+      // TODO(ahe): Handle recoverable errors better.
+      inputError(uri, recoverableErrors.first.beginOffset,
+          recoverableErrors);
+    }
+  }
+
+  @override
+  void endTopLevelDeclaration(Token token) {
+    debugEvent("TopLevelDeclaration");
+    checkEmpty();
+  }
+
+  @override
+  void endCompilationUnit(int count, Token token) {
+    debugEvent("CompilationUnit");
+    checkEmpty();
+  }
+
+  @override
+  void handleNoTypeArguments(Token token) {
+    debugEvent("NoTypeArguments");
+    push(NullValue.TypeArguments);
+  }
+
+  @override
+  void handleNoTypeVariables(Token token) {
+    debugEvent("NoTypeVariables");
+    push(NullValue.TypeVariables);
+  }
+
+  @override
+  void handleNoType(Token token) {
+    debugEvent("NoType");
+    push(NullValue.Type);
+  }
+
+  @override
+  void handleNoFormalParameters(Token token) {
+    debugEvent("NoFormalParameters");
+    push(NullValue.FormalParameters);
+  }
+
+  @override
+  void handleNoArguments(Token token) {
+    debugEvent("NoArguments");
+    push(NullValue.Arguments);
+  }
+
+  @override
+  void handleNoFunctionBody(Token token) {
+    debugEvent("NoFunctionBody");
+    push(NullValue.FunctionBody);
+  }
+
+  @override
+  void handleNoInitializers() {
+    debugEvent("NoInitializers");
+    push(NullValue.Initializers);
+  }
+
+  @override
+  void handleParenthesizedExpression(BeginGroupToken token) {
+    debugEvent("ParenthesizedExpression");
+  }
+
+  @override
+  void beginLiteralString(Token token) {
+    debugEvent("beginLiteralString");
+    push(token);
+  }
+
+  @override
+  void endLiteralString(int interpolationCount) {
+    debugEvent("endLiteralString");
+    if (interpolationCount == 0) {
+      Token token = pop();
+      push(unescapeString(token.value));
+    } else {
+      internalError("String interpolation not implemented.");
+    }
+  }
+
+  @override
+  void handleStringJuxtaposition(int literalCount) {
+    debugEvent("StringJuxtaposition");
+    push(popList(literalCount).join(""));
+  }
+
+  @override
+  void endCatchClause(Token token) {
+    debugEvent("CatchClause");
+  }
+
+  @override
+  void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
+    super.handleRecoverableError(token, kind, arguments);
+    debugEvent("Error: ${recoverableErrors.last}");
+  }
+
+  @override
+  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+    throw inputError(uri, token.charOffset, "$kind $arguments");
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart b/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart
new file mode 100644
index 0000000..542c31b
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.unhandled_listener;
+
+import 'package:front_end/src/fasta/scanner/token.dart' show
+    Token;
+
+import 'stack_listener.dart' show
+    NullValue,
+    StackListener;
+
+export 'stack_listener.dart' show
+    NullValue;
+
+// TODO(ahe): Get rid of this.
+enum Unhandled {
+  ConditionalUri,
+  ConditionalUris,
+  DottedName,
+  Hide,
+  Initializers,
+  Interpolation,
+  Metadata,
+  Show,
+  TypeVariables,
+}
+
+// TODO(ahe): Get rid of this class when all listeners are complete.
+abstract class UnhandledListener extends StackListener {
+  @override
+  void endMetadataStar(int count, bool forParameter) {
+    debugEvent("MetadataStar");
+    push(popList(count) ?? NullValue.Metadata);
+  }
+
+  @override
+  void endConditionalUri(Token ifKeyword, Token equalitySign) {
+    debugEvent("ConditionalUri");
+    pop(); // URI.
+    popIfNotNull(equalitySign);  // String.
+    pop(); // DottedName.
+    push(Unhandled.ConditionalUri);
+  }
+
+  @override
+  void endConditionalUris(int count) {
+    debugEvent("ConditionalUris");
+    popList(count);
+    push(Unhandled.ConditionalUris);
+  }
+
+  @override
+  void endHide(Token hideKeyword) {
+    debugEvent("Hide");
+    pop();
+    push(Unhandled.Hide);
+  }
+
+  @override
+  void endShow(Token showKeyword) {
+    debugEvent("Show");
+    pop();
+    push(Unhandled.Show);
+  }
+
+  @override
+  void endCombinators(int count) {
+    debugEvent("Combinators");
+    push(popList(count) ?? NullValue.Combinators);
+  }
+
+  @override
+  void endDottedName(int count, Token firstIdentifier) {
+    debugEvent("DottedName");
+    popList(count);
+    push(Unhandled.DottedName);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/target.dart b/pkg/front_end/lib/src/fasta/target.dart
new file mode 100644
index 0000000..6c8c824
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/target.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.target;
+
+import 'dart:async' show
+    Future;
+
+import 'ticker.dart' show
+    Ticker;
+
+import 'ast_kind.dart' show
+    AstKind;
+
+/// A compilation target.
+///
+/// A target reads source files with [read] and writes out the resulting
+/// program when [writeOutline] is called.
+abstract class Target {
+  final Ticker ticker;
+
+  Target(this.ticker);
+
+  /// Instructs this target to include [uri] in its result.
+  void read(Uri uri);
+
+  /// Write the resulting program in the file [uri].
+  Future writeProgram(Uri uri, AstKind astKind);
+
+  /// Write the resulting outline in the file [uri].
+  Future writeOutline(Uri uri);
+}
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
new file mode 100644
index 0000000..d34d9ec
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.target_implementation;
+
+import 'package:kernel/target/vm.dart' show
+    VmTarget;
+
+import 'builder/builder.dart' show
+    Builder,
+    ClassBuilder,
+    LibraryBuilder;
+
+import 'loader.dart' show
+    Loader;
+
+import 'target.dart' show
+    Target;
+
+import 'ticker.dart' show
+    Ticker;
+
+import 'translate_uri.dart' show
+    TranslateUri;
+
+/// Provides the implementation details used by a loader for a target.
+abstract class TargetImplementation extends Target {
+  final TranslateUri uriTranslator;
+  Builder cachedCompileTimeError;
+  Builder cachedNativeAnnotation;
+
+  TargetImplementation(Ticker ticker, this.uriTranslator)
+      : super(ticker);
+
+  /// Creates a [LibraryBuilder] corresponding to [uri], if one doesn't exist
+  /// already.
+  LibraryBuilder createLibraryBuilder(Uri uri, Uri fileUri);
+
+  /// Add the classes extended or implemented directly by [cls] to [set].
+  void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set);
+
+  /// Returns all classes that will be included in the resulting program.
+  List<ClassBuilder> collectAllClasses();
+
+  /// The class [cls] is involved in a cyclic definition. This method should
+  /// ensure that the cycle is broken, for example, by removing superclass and
+  /// implemented interfaces.
+  void breakCycle(ClassBuilder cls);
+
+  Uri translateUri(Uri uri) => uriTranslator.translate(uri);
+
+  /// Returns a reference to the constructor used for creating a compile-time
+  /// error. The constructor is expected to accept a single argument of type
+  /// String, which is the compile-time error message.
+  Builder getCompileTimeError(Loader loader) {
+    if (cachedCompileTimeError != null) return cachedCompileTimeError;
+    return cachedCompileTimeError =
+        loader.coreLibrary.getConstructor("_CompileTimeError", isPrivate: true);
+  }
+
+  /// Returns a reference to the constructor used for creating `native`
+  /// annotations. The constructor is expected to accept a single argument of
+  /// type String, which is the name of the native method.
+  Builder getNativeAnnotation(Loader loader) {
+    if (cachedNativeAnnotation != null) return cachedNativeAnnotation;
+    LibraryBuilder internal = loader.read(Uri.parse("dart:_internal"));
+    return cachedNativeAnnotation = internal.getConstructor("ExternalName");
+  }
+
+  void loadExtraRequiredLibraries(Loader loader) {
+    for (String uri in new VmTarget(null).extraRequiredLibraries) {
+      loader.read(Uri.parse(uri));
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart b/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
new file mode 100644
index 0000000..1e16464
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
@@ -0,0 +1,384 @@
+// 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.
+
+// TODO(ahe): Copied from closure_conversion branch of kernel, remove this file
+// when closure_conversion is merged with master.
+
+library kernel.testing.kernel_chain;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    Directory,
+    File,
+    IOSink,
+    Platform;
+
+import 'dart:typed_data' show
+    Uint8List;
+
+import 'package:kernel/kernel.dart' show
+    Repository,
+    loadProgramFromBinary;
+
+import 'package:kernel/text/ast_to_text.dart' show
+    Printer;
+
+import 'package:testing/testing.dart' show
+    Result,
+    StdioProcess,
+    Step;
+
+import 'package:kernel/ast.dart' show
+    Library,
+    Program;
+
+import 'package:kernel/verifier.dart' show
+    VerifyingVisitor;
+
+import 'package:kernel/binary/ast_to_binary.dart' show
+    BinaryPrinter;
+
+import 'package:kernel/binary/ast_from_binary.dart' show
+    BinaryBuilder;
+
+import 'package:kernel/binary/loader.dart' show
+    BinaryLoader;
+
+import 'package:analyzer/src/generated/sdk.dart' show
+    DartSdk;
+
+import 'package:kernel/analyzer/loader.dart' show
+    DartLoader,
+    DartOptions,
+    createDartSdk;
+
+import 'package:kernel/target/targets.dart' show
+    Target,
+    TargetFlags,
+    getTarget;
+
+import 'package:kernel/repository.dart' show
+    Repository;
+
+import 'package:testing/testing.dart' show
+    Chain,
+    ChainContext,
+    Result,
+    StdioProcess,
+    Step,
+    TestDescription;
+
+import 'package:kernel/ast.dart' show
+    Program;
+
+import 'package:package_config/discovery.dart' show
+    loadPackagesFile;
+
+import '../environment_variable.dart' show
+    EnvironmentVariable;
+
+typedef Future<TestContext> TestContextConstructor(
+    Chain suite, Map<String, String> environment, Uri sdk, Uri vm,
+    Uri packages, bool strongMode, DartSdk dartSdk, bool updateExpectations);
+
+Future<bool> fileExists(Uri base, String path) async {
+  return await new File.fromUri(base.resolve(path)).exists();
+}
+
+final EnvironmentVariable testConfigVariable = new EnvironmentVariable(
+    "DART_CONFIGURATION",
+    "It should be something like 'ReleaseX64', depending on which"
+    " configuration you're testing.");
+
+Future<Uri> computePatchedSdk() async {
+  String config = await testConfigVariable.value;
+  String path;
+  switch (Platform.operatingSystem) {
+    case "linux":
+      path = "out/$config/patched_sdk";
+      break;
+
+    case "macos":
+      path = "xcodebuild/$config/patched_sdk";
+      break;
+
+    case "windows":
+      path = "build/$config/patched_sdk";
+      break;
+
+    default:
+      throw "Unsupported operating system: '${Platform.operatingSystem}'.";
+  }
+  Uri sdk = Uri.base.resolve("$path/");
+  const String asyncDart = "lib/async/async.dart";
+  if (!await fileExists(sdk, asyncDart)) {
+    throw "Couldn't find '$asyncDart' in '$sdk'.";
+  }
+  const String asyncSources = "lib/async/async_sources.gypi";
+  if (await fileExists(sdk, asyncSources)) {
+    throw "Found '$asyncSources' in '$sdk', so it isn't a patched SDK.";
+  }
+  return sdk;
+}
+
+Uri computeDartVm(Uri patchedSdk) {
+  return patchedSdk.resolve(Platform.isWindows ? "../dart.exe" : "../dart");
+}
+
+abstract class TestContext extends ChainContext {
+  final Uri vm;
+
+  final Uri packages;
+
+  final DartOptions options;
+
+  final DartSdk dartSdk;
+
+  TestContext(Uri sdk, this.vm, Uri packages, bool strongMode, this.dartSdk)
+      : packages = packages,
+        options = new DartOptions(strongMode: strongMode, sdk: sdk.toFilePath(),
+            packagePath: packages.toFilePath());
+
+  Future<DartLoader> createLoader() async {
+    Repository repository = new Repository();
+    return new DartLoader(repository, options, await loadPackagesFile(packages),
+        ignoreRedirectingFactories: false, dartSdk: dartSdk);
+  }
+
+  static Future<TestContext> create(Chain suite,
+      Map<String, String> environment,
+      TestContextConstructor constructor) async {
+    Uri sdk = await computePatchedSdk();
+    Uri vm = computeDartVm(sdk);
+    Uri packages = Uri.base.resolve(".packages");
+    bool strongMode = false;
+    bool updateExpectations = environment["updateExpectations"] == "true";
+    return constructor(suite, environment, sdk, vm, packages, strongMode,
+        createDartSdk(sdk.toFilePath(), strongMode: strongMode),
+        updateExpectations);
+  }
+}
+
+class Kernel extends Step<TestDescription, Program, TestContext> {
+  const Kernel();
+
+  String get name => "kernel";
+
+  Future<Result<Program>> run(
+      TestDescription description, TestContext testContext) async {
+    try {
+      DartLoader loader = await testContext.createLoader();
+      Target target = getTarget(
+          "vm", new TargetFlags(strongMode: testContext.options.strongMode));
+      Program program =
+          loader.loadProgram(description.uri, target: target);
+      for (var error in loader.errors) {
+        return fail(program, "$error");
+      }
+      target.performModularTransformations(program);
+      target.performGlobalTransformations(program);
+      return pass(program);
+    } catch (e, s) {
+      return crash(e, s);
+    }
+  }
+}
+
+
+class Print extends Step<Program, Program, TestContext> {
+  const Print();
+
+  String get name => "print";
+
+  Future<Result<Program>> run(Program program, _) async {
+    StringBuffer sb = new StringBuffer();
+    for (Library library in program.libraries) {
+      Printer printer = new Printer(sb);
+      if (library.importUri.scheme != "dart" &&
+          library.importUri.scheme != "package") {
+        printer.writeLibraryFile(library);
+      }
+    }
+    print("$sb");
+    return pass(program);
+  }
+}
+
+class Verify extends Step<Program, Program, TestContext> {
+  final bool fullCompile;
+
+  const Verify(this.fullCompile);
+
+  String get name => "verify";
+
+  Future<Result<Program>> run(Program program, TestContext testContext) async {
+    try {
+      program.accept(new VerifyingVisitor()..isOutline = !fullCompile);
+      return pass(program);
+    } catch (e, s) {
+      return new Result<Program>(
+          null, testContext.expectationSet["VerificationError"], e, s);
+    }
+  }
+}
+
+class MatchExpectation extends Step<Program, Program, TestContext> {
+  final String suffix;
+
+  // TODO(ahe): This is true by default which doesn't match well with the class
+  // name.
+  final bool updateExpectations;
+
+  const MatchExpectation(this.suffix, {this.updateExpectations: false});
+
+  String get name => "match expectations";
+
+  Future<Result<Program>> run(Program program, _) async {
+    Library library = program.libraries.firstWhere(
+        (Library library) => library.importUri.scheme != "dart");
+    Uri uri = library.importUri;
+    StringBuffer buffer = new StringBuffer();
+    new Printer(buffer).writeLibraryFile(library);
+
+    File expectedFile = new File("${uri.toFilePath()}$suffix");
+    if (await expectedFile.exists()) {
+      String expected = await expectedFile.readAsString();
+      if (expected.trim() != "$buffer".trim()) {
+        if (!updateExpectations) {
+          String diff = await runDiff(expectedFile.uri, "$buffer");
+          return fail(null, "$uri doesn't match ${expectedFile.uri}\n$diff");
+        }
+      } else {
+        return pass(program);
+      }
+    }
+    if (updateExpectations) {
+      await openWrite(expectedFile.uri, (IOSink sink) {
+        sink.writeln("$buffer".trim());
+      });
+      return pass(program);
+    } else {
+      return fail(program, """
+Please create file ${expectedFile.path} with this content:
+$buffer""");
+    }
+  }
+}
+
+class WriteDill extends Step<Program, Uri, TestContext> {
+  const WriteDill();
+
+  String get name => "write .dill";
+
+  Future<Result<Uri>> run(Program program, _) async {
+    Directory tmp = await Directory.systemTemp.createTemp();
+    Uri uri = tmp.uri.resolve("generated.dill");
+    File generated = new File.fromUri(uri);
+    IOSink sink = generated.openWrite();
+    try {
+      new BinaryPrinter(sink).writeProgramFile(program);
+    } catch (e, s) {
+      return fail(uri, e, s);
+    } finally {
+      print("Wrote `${generated.path}`");
+      await sink.close();
+    }
+    return pass(uri);
+  }
+}
+
+class ReadDill extends Step<Uri, Uri, TestContext> {
+  const ReadDill();
+
+  String get name => "read .dill";
+
+  Future<Result<Uri>> run(Uri uri, _) async {
+    try {
+      loadProgramFromBinary(uri.toFilePath());
+    } catch (e, s) {
+      return fail(uri, e, s);
+    }
+    return pass(uri);
+  }
+}
+
+class Copy extends Step<Program, Program, TestContext> {
+  const Copy();
+
+  String get name => "copy program";
+
+  Future<Result<Program>> run(Program program, _) async {
+    BytesCollector sink = new BytesCollector();
+    new BinaryPrinter(sink).writeProgramFile(program);
+    Uint8List bytes = sink.collect();
+    BinaryLoader loader = new BinaryLoader(new Repository());
+    return pass(new BinaryBuilder(loader, bytes).readProgramFile());
+  }
+}
+
+class Run extends Step<Uri, int, TestContext> {
+  const Run();
+
+  String get name => "run";
+
+  bool get isAsync => true;
+
+  bool get isRuntime => true;
+
+  Future<Result<int>> run(Uri uri, TestContext context) async {
+    File generated = new File.fromUri(uri);
+    StdioProcess process;
+    try {
+      process = await StdioProcess.run(
+          context.vm.toFilePath(), [generated.path, "Hello, World!"]);
+      print(process.output);
+    } finally {
+      generated.parent.delete(recursive: true);
+    }
+    return process.toResult();
+  }
+}
+
+class BytesCollector implements Sink<List<int>> {
+  final List<List<int>> lists = <List<int>>[];
+
+  int length = 0;
+
+  void add(List<int> data) {
+    lists.add(data);
+    length += data.length;
+  }
+
+  Uint8List collect() {
+    Uint8List result = new Uint8List(length);
+    int offset = 0;
+    for (List<int> list in lists) {
+      result.setRange(offset, offset += list.length, list);
+    }
+    lists.clear();
+    length = 0;
+    return result;
+  }
+
+  void close() {}
+}
+
+Future<String> runDiff(Uri expected, String actual) async {
+  // TODO(ahe): Implement this for Windows.
+  StdioProcess process = await StdioProcess.run(
+      "diff", <String>["-u", expected.toFilePath(), "-"], input: actual);
+  return process.output;
+}
+
+Future openWrite(Uri uri, f(IOSink sink)) async {
+  IOSink sink = new File.fromUri(uri).openWrite();
+  try {
+    await f(sink);
+  } finally {
+    await sink.close();
+  }
+  print("Wrote $uri");
+}
diff --git a/pkg/front_end/lib/src/fasta/testing/suite.dart b/pkg/front_end/lib/src/fasta/testing/suite.dart
new file mode 100644
index 0000000..022b751
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/testing/suite.dart
@@ -0,0 +1,192 @@
+// 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.
+
+library fasta.testing.suite;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:convert' show
+    JSON;
+
+import 'package:analyzer/src/generated/sdk.dart' show
+    DartSdk;
+
+import 'package:kernel/ast.dart' show
+    Library,
+    Program;
+
+import 'package:kernel/analyzer/loader.dart' show
+    DartLoader;
+
+import 'package:kernel/target/targets.dart' show
+    Target,
+    TargetFlags,
+    getTarget;
+
+import 'package:testing/testing.dart' show
+    Chain,
+    ExpectationSet,
+    Result,
+    Step,
+    TestDescription;
+
+import '../errors.dart' show
+    InputError;
+
+import 'kernel_chain.dart' show
+    MatchExpectation,
+    Print,
+    Run,
+    Verify,
+    TestContext,
+    WriteDill;
+
+import '../ticker.dart' show
+    Ticker;
+
+import '../translate_uri.dart' show
+    TranslateUri;
+
+import '../kernel/kernel_target.dart' show
+    KernelTarget;
+
+import '../dill/dill_target.dart' show
+    DillTarget;
+
+import '../ast_kind.dart' show
+    AstKind;
+
+export 'kernel_chain.dart' show
+    TestContext;
+
+export 'package:testing/testing.dart' show
+    Chain,
+    runMe;
+
+export '../ast_kind.dart' show
+    AstKind;
+
+const String ENABLE_FULL_COMPILE = " full compile ";
+
+const String AST_KIND_INDEX = " AST kind index ";
+
+const String EXPECTATIONS = '''
+[
+  {
+    "name": "VerificationError",
+    "group": "Fail"
+  }
+]
+''';
+
+String shortenAstKindName(AstKind astKind) {
+  switch (astKind) {
+    case AstKind.Analyzer: return "dartk";
+    case AstKind.Kernel: return "direct";
+  }
+  throw "Unknown AST kind: $astKind";
+}
+
+class FeContext extends TestContext {
+  final TranslateUri uriTranslator;
+
+  final List<Step> steps;
+
+  final ExpectationSet expectationSet =
+      new ExpectationSet.fromJsonList(JSON.decode(EXPECTATIONS));
+
+  Future<Program> platform;
+
+  FeContext(Uri sdk, Uri vm, Uri packages, bool strongMode,
+      DartSdk dartSdk, bool updateExpectations, this.uriTranslator,
+      bool fullCompile, AstKind astKind)
+      : steps = <Step>[
+          new Outline(fullCompile, astKind),
+          const Print(),
+          new Verify(fullCompile),
+          new MatchExpectation(
+              fullCompile
+                  ? ".${shortenAstKindName(astKind)}.expect"
+                  : ".outline.expect",
+              updateExpectations: updateExpectations)
+        ],
+        super(sdk, vm, packages, strongMode, dartSdk) {
+    if (fullCompile) {
+      steps.add(const WriteDill());
+      steps.add(const Run());
+    }
+  }
+
+  Future<Program> createPlatform() {
+    return platform ??= new Future<Program>(() async {
+      DartLoader loader = await createLoader();
+      Target target = getTarget(
+          "vm", new TargetFlags(strongMode: options.strongMode));
+      Program program = loader.loadProgram(
+          Uri.base.resolve("pkg/fasta/test/platform.dart"), target: target);
+      if (loader.errors.isNotEmpty) {
+        throw loader.errors.join("\n");
+      }
+      Library mainLibrary = program.mainMethod.enclosingLibrary;
+      program.uriToSource.remove(mainLibrary.fileUri);
+      program = new Program(
+          program.libraries.where((Library l) => l != mainLibrary).toList(),
+          program.uriToSource);
+      target.performModularTransformations(program);
+      target.performGlobalTransformations(program);
+      return program;
+    });
+  }
+
+  static Future<FeContext> create(Chain suite, Map<String, String> environment,
+      Uri sdk, Uri vm, Uri packages, bool strongMode, DartSdk dartSdk,
+      bool updateExpectations) async {
+    TranslateUri uriTranslator = await TranslateUri.parse(packages);
+    String astKindString = environment[AST_KIND_INDEX];
+    AstKind astKind = astKindString == null
+        ? null : AstKind.values[int.parse(astKindString)];
+    return new FeContext(
+        sdk, vm, packages, strongMode, dartSdk, updateExpectations,
+        uriTranslator, environment.containsKey(ENABLE_FULL_COMPILE), astKind);
+  }
+}
+
+class Outline extends Step<TestDescription, Program, FeContext> {
+  final bool fullCompile;
+
+  final AstKind astKind;
+
+  const Outline(this.fullCompile, this.astKind);
+
+  String get name {
+    return fullCompile ? "${shortenAstKindName(astKind)} compile" : "outline";
+  }
+
+  bool get isCompiler => fullCompile;
+
+  Future<Result<Program>> run(
+      TestDescription description, FeContext context) async {
+    Program platform = await context.createPlatform();
+    Ticker ticker = new Ticker();
+    DillTarget dillTarget = new DillTarget(ticker, context.uriTranslator);
+    dillTarget.loader
+        ..input = Uri.parse("org.dartlang:platform") // Make up a name.
+        ..setProgram(platform);
+    KernelTarget sourceTarget =
+        new KernelTarget(dillTarget, context.uriTranslator);
+    Program p;
+    try {
+      sourceTarget.read(description.uri);
+      await dillTarget.writeOutline(null);
+      p = await sourceTarget.writeOutline(null);
+      if (fullCompile) {
+        p = await sourceTarget.writeProgram(null, astKind);
+      }
+    } on InputError catch (e, s) {
+      return fail(null, e.error, s);
+    }
+    return pass(p);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/ticker.dart b/pkg/front_end/lib/src/fasta/ticker.dart
new file mode 100644
index 0000000..ffa94366
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/ticker.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.ticker;
+
+class Ticker {
+  final Stopwatch sw = new Stopwatch()..start();
+
+  bool isVerbose;
+
+  Duration previousTick;
+
+  Ticker({this.isVerbose: true}) {
+    previousTick = sw.elapsed;
+  }
+
+  void logMs(Object message) {
+    log((Duration elapsed, Duration sinceStart) {
+      print("$sinceStart: $message in ${elapsed.inMilliseconds}ms.");
+    });
+  }
+
+  void log(void f(Duration elapsed, Duration sinceStart)) {
+    Duration elapsed = sw.elapsed;
+    try {
+      if (isVerbose) f(elapsed - previousTick, elapsed);
+    } finally {
+      previousTick = sw.elapsed;
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/translate_uri.dart b/pkg/front_end/lib/src/fasta/translate_uri.dart
new file mode 100644
index 0000000..131fdd6
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/translate_uri.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.translate_uri;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    File;
+
+import 'package:package_config/packages_file.dart' as packages_file show
+    parse;
+
+class TranslateUri {
+  final Map<String, Uri> packages;
+  final Map<String, Uri> dartLibraries;
+
+  TranslateUri(this.packages, this.dartLibraries);
+
+  Uri translate(Uri uri) {
+    if (uri.scheme == "dart") return translateDartUri(uri);
+    if (uri.scheme == "package") return translatePackageUri(uri);
+    return null;
+  }
+
+  Uri translateDartUri(Uri uri) => dartLibraries[uri.path];
+
+  Uri translatePackageUri(Uri uri) {
+    int index = uri.path.indexOf("/");
+    if (index == -1) return null;
+    String name = uri.path.substring(0, index);
+    String path = uri.path.substring(index + 1);
+    Uri root = packages[name];
+    if (root == null) return null;
+    return root.resolve(path);
+  }
+
+  static Future<TranslateUri> parse(Uri sdk, [Uri uri]) async {
+    // This list is generated with [bin/generate_dart_libraries.dart] below.
+    //
+    // TODO(ahe): This is only used with the option --compile-sdk, and
+    // currently doesn't work outside the SDK source tree.
+    Map<String, Uri> dartLibraries = {
+      "async": sdk.resolve("lib/async/async.dart"),
+      "_blink": sdk.resolve("lib/_blink/dartium/_blink_dartium.dart"),
+      "_chrome": sdk.resolve("lib/_chrome/dart2js/chrome_dart2js.dart"),
+      "collection": sdk.resolve("lib/collection/collection.dart"),
+      "convert": sdk.resolve("lib/convert/convert.dart"),
+      "core": sdk.resolve("lib/core/core.dart"),
+      "developer": sdk.resolve("lib/developer/developer.dart"),
+      "html": sdk.resolve("lib/html/dartium/html_dartium.dart"),
+      "html_common": sdk.resolve("lib/html/html_common/html_common.dart"),
+      "indexed_db":
+          sdk.resolve("lib/indexed_db/dartium/indexed_db_dartium.dart"),
+      "io": sdk.resolve("lib/io/io.dart"),
+      "isolate": sdk.resolve("lib/isolate/isolate.dart"),
+      "js": sdk.resolve("lib/js/dartium/js_dartium.dart"),
+      "js_util": sdk.resolve("lib/js_util/dartium/js_util_dartium.dart"),
+      "math": sdk.resolve("lib/math/math.dart"),
+      "mirrors": sdk.resolve("lib/mirrors/mirrors.dart"),
+      "nativewrappers": sdk.resolve("lib/html/dartium/nativewrappers.dart"),
+      "typed_data": sdk.resolve("lib/typed_data/typed_data.dart"),
+      "svg": sdk.resolve("lib/svg/dartium/svg_dartium.dart"),
+      "web_audio": sdk.resolve("lib/web_audio/dartium/web_audio_dartium.dart"),
+      "web_gl": sdk.resolve("lib/web_gl/dartium/web_gl_dartium.dart"),
+      "web_sql": sdk.resolve("lib/web_sql/dartium/web_sql_dartium.dart"),
+      "_internal": sdk.resolve("lib/internal/internal.dart"),
+      "profiler": sdk.resolve("lib/profiler/profiler.dart"),
+      "vmservice_io": sdk.resolve("lib/vmservice_io/vmservice_io.dart"),
+      "_vmservice": sdk.resolve("lib/vmservice/vmservice.dart"),
+      "_builtin": sdk.resolve("lib/_builtin/_builtin.dart"),
+    };
+    uri ??= Uri.base.resolve(".packages");
+    File file = new File.fromUri(uri);
+    List<int> bytes = await file.readAsBytes();
+    Map<String, Uri> packages = packages_file.parse(bytes, uri);
+    return new TranslateUri(packages, dartLibraries);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/util/link.dart b/pkg/front_end/lib/src/fasta/util/link.dart
new file mode 100644
index 0000000..0748e61
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/link.dart
@@ -0,0 +1,180 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.util.link;
+
+import 'link_implementation.dart' show
+    LinkBuilderImplementation,
+    LinkEntry,
+    LinkIterator,
+    MappedLinkIterable;
+
+class Link<T> implements Iterable<T> {
+  T get head => throw new StateError("no elements");
+  Link<T> get tail => null;
+
+  const Link();
+
+  Link<T> prepend(T element) {
+    return new LinkEntry<T>(element, this);
+  }
+
+  Iterator<T> get iterator => new LinkIterator<T>(this);
+
+  void printOn(StringBuffer buffer, [separatedBy]) {}
+
+  List<T> toList({bool growable: true}) {
+    List<T> result;
+    if (!growable) {
+      result = new List<T>(slowLength());
+    } else {
+      result = new List<T>();
+      result.length = slowLength();
+    }
+    int i = 0;
+    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+      result[i++] = link.head;
+    }
+    return result;
+  }
+
+  /// Lazily maps over this linked list, returning an [Iterable].
+  Iterable<K> map<K>(K fn(T item)) {
+    return new MappedLinkIterable<T, K>(this, fn);
+  }
+
+  /// Invokes `fn` for every item in the linked list and returns the results
+  /// in a [List].
+  List mapToList(dynamic fn(T item), {bool growable: true}) {
+    List result;
+    if (!growable) {
+      result = new List(slowLength());
+    } else {
+      result = new List();
+      result.length = slowLength();
+    }
+    int i = 0;
+    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+      result[i++] = fn(link.head);
+    }
+    return result;
+  }
+
+  bool get isEmpty => true;
+  bool get isNotEmpty => false;
+
+  Link<T> reverse() => this;
+
+  Link<T> reversePrependAll(Link<T> from) {
+    if (from.isEmpty) return this;
+    return this.prepend(from.head).reversePrependAll(from.tail);
+  }
+
+  Link<T> skip(int n) {
+    if (n == 0) return this;
+    throw new RangeError('Index $n out of range');
+  }
+
+  void forEach(void f(T element)) {}
+
+  bool operator ==(other) {
+    if (other is! Link<T>) return false;
+    return other.isEmpty;
+  }
+
+  int get hashCode => throw new UnsupportedError('Link.hashCode');
+
+  String toString() => "[]";
+
+  get length {
+    throw new UnsupportedError('get:length');
+  }
+
+  int slowLength() => 0;
+
+  // TODO(ahe): Remove this method?
+  bool contains(Object element) {
+    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+      if (link.head == element) return true;
+    }
+    return false;
+  }
+
+  // TODO(ahe): Remove this method?
+  T get single {
+    if (isEmpty) throw new StateError('No elements');
+    if (!tail.isEmpty) throw new StateError('More than one element');
+    return head;
+  }
+
+  // TODO(ahe): Remove this method?
+  T get first {
+    if (isEmpty) throw new StateError('No elements');
+    return head;
+  }
+
+  /// Returns true if f returns true for all elements of this list.
+  ///
+  /// Returns true for the empty list.
+  bool every(bool f(T)) {
+    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+      if (!f(link.head)) return false;
+    }
+    return true;
+  }
+
+  Link copyWithout(e) => this;
+
+  //
+  // Unsupported Iterable<T> methods.
+  //
+  bool any(bool f(T e)) => _unsupported('any');
+  T elementAt(int i) => _unsupported('elementAt');
+  Iterable<K> expand<K>(Iterable<K> f(T e)) => _unsupported('expand');
+  T firstWhere(bool f(T e), {T orElse()}) => _unsupported('firstWhere');
+  K fold<K>(K initialValue, K combine(K value, T element)) {
+    return _unsupported('fold');
+  }
+  T get last => _unsupported('get:last');
+  T lastWhere(bool f(T e), {T orElse()}) => _unsupported('lastWhere');
+  String join([separator = '']) => _unsupported('join');
+  T reduce(T combine(T a, T b)) => _unsupported('reduce');
+  T singleWhere(bool f(T e)) => _unsupported('singleWhere');
+  Iterable<T> skipWhile(bool f(T e)) => _unsupported('skipWhile');
+  Iterable<T> take(int n) => _unsupported('take');
+  Iterable<T> takeWhile(bool f(T e)) => _unsupported('takeWhile');
+  Set<T> toSet() => _unsupported('toSet');
+  Iterable<T> where(bool f(T e)) => _unsupported('where');
+
+  _unsupported(String method) => throw new UnsupportedError(method);
+}
+
+/// Builder object for creating linked lists using [Link] or fixed-length [List]
+/// objects.
+abstract class LinkBuilder<T> {
+  factory LinkBuilder() = LinkBuilderImplementation<T>;
+
+  /// Prepends all elements added to the builder to [tail]. The resulting list
+  /// is returned and the builder is cleared.
+  Link<T> toLink([Link<T> tail = const Link()]);
+
+  /// Creates a new fixed length containing all added elements. The
+  /// resulting list is returned and the builder is cleared.
+  List<T> toList();
+
+  /// Adds the element [t] to the end of the list being built.
+  Link<T> addLast(T t);
+
+  /// Returns the first element in the list being built.
+  T get first;
+
+  /// Returns the number of elements in the list being built.
+  final int length;
+
+  /// Returns `true` if the list being built is empty.
+  final bool isEmpty;
+
+  /// Removes all added elements and resets the builder.
+  void clear();
+}
diff --git a/pkg/front_end/lib/src/fasta/util/link_implementation.dart b/pkg/front_end/lib/src/fasta/util/link_implementation.dart
new file mode 100644
index 0000000..c2773bb
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/link_implementation.dart
@@ -0,0 +1,225 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.util.link_implementation;
+
+import 'dart:collection' show
+    IterableBase;
+
+import 'link.dart' show
+    Link,
+    LinkBuilder;
+
+class LinkIterator<T> implements Iterator<T> {
+  T _current;
+  Link<T> _link;
+
+  LinkIterator(Link<T> this._link);
+
+  T get current => _current;
+
+  bool moveNext() {
+    if (_link.isEmpty) {
+      _current = null;
+      return false;
+    }
+    _current = _link.head;
+    _link = _link.tail;
+    return true;
+  }
+}
+
+typedef T Transformation<S, T>(S input);
+
+class MappedLinkIterator<S, T> extends Iterator<T> {
+  Transformation<S, T> _transformation;
+  Link<S> _link;
+  T _current;
+
+  MappedLinkIterator(this._link, this._transformation);
+
+  T get current => _current;
+
+  bool moveNext() {
+    if (_link.isEmpty) {
+      _current = null;
+      return false;
+    }
+    _current = _transformation(_link.head);
+    _link = _link.tail;
+    return true;
+  }
+}
+
+class MappedLinkIterable<S, T> extends IterableBase<T> {
+  Transformation<S, T> _transformation;
+  Link<S> _link;
+
+  MappedLinkIterable(this._link, this._transformation);
+
+  Iterator<T> get iterator {
+    return new MappedLinkIterator<S, T>(_link, _transformation);
+  }
+}
+
+class LinkEntry<T> extends Link<T> {
+  final T head;
+  Link<T> tail;
+
+  LinkEntry(T this.head, [Link<T> tail])
+      : this.tail = ((tail == null) ? const Link() : tail);
+
+  Link<T> prepend(T element) {
+    // TODO(ahe): Use new Link<T>, but this cost 8% performance on VM.
+    return new LinkEntry<T>(element, this);
+  }
+
+  void printOn(StringBuffer buffer, [separatedBy]) {
+    buffer.write(head);
+    if (separatedBy == null) separatedBy = '';
+    for (Link link = tail; link.isNotEmpty; link = link.tail) {
+      buffer.write(separatedBy);
+      buffer.write(link.head);
+    }
+  }
+
+  String toString() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.write('[ ');
+    printOn(buffer, ', ');
+    buffer.write(' ]');
+    return buffer.toString();
+  }
+
+  Link<T> reverse() {
+    Link<T> result = const Link();
+    for (Link<T> link = this; link.isNotEmpty; link = link.tail) {
+      result = result.prepend(link.head);
+    }
+    return result;
+  }
+
+  Link<T> reversePrependAll(Link<T> from) {
+    Link<T> result;
+    for (result = this; from.isNotEmpty; from = from.tail) {
+      result = result.prepend(from.head);
+    }
+    return result;
+  }
+
+  Link<T> skip(int n) {
+    Link<T> link = this;
+    for (int i = 0; i < n; i++) {
+      if (link.isEmpty) {
+        throw new RangeError('Index $n out of range');
+      }
+      link = link.tail;
+    }
+    return link;
+  }
+
+  bool get isEmpty => false;
+  bool get isNotEmpty => true;
+
+  void forEach(void f(T element)) {
+    for (Link<T> link = this; link.isNotEmpty; link = link.tail) {
+      f(link.head);
+    }
+  }
+
+  bool operator ==(other) {
+    if (other is! Link<T>) return false;
+    Link<T> myElements = this;
+    while (myElements.isNotEmpty && other.isNotEmpty) {
+      if (myElements.head != other.head) {
+        return false;
+      }
+      myElements = myElements.tail;
+      other = other.tail;
+    }
+    return myElements.isEmpty && other.isEmpty;
+  }
+
+  int get hashCode => throw new UnsupportedError('LinkEntry.hashCode');
+
+  int slowLength() {
+    int length = 0;
+    for (Link current = this; current.isNotEmpty; current = current.tail) {
+      ++length;
+    }
+    return length;
+  }
+
+  Link copyWithout(e) {
+    LinkBuilder copy = new LinkBuilder();
+    Link link = this;
+    for (; link.isNotEmpty; link = link.tail) {
+      if (link.head != e) {
+        copy.addLast(link.head);
+      }
+    }
+    return copy.toLink(link);
+  }
+}
+
+class LinkBuilderImplementation<T> implements LinkBuilder<T> {
+  LinkEntry<T> head = null;
+  LinkEntry<T> lastLink = null;
+  int length = 0;
+
+  LinkBuilderImplementation();
+
+  Link<T> toLink([Link<T> tail = const Link()]) {
+    if (head == null) return tail;
+    lastLink.tail = tail;
+    Link<T> link = head;
+    lastLink = null;
+    head = null;
+    length = 0;
+    return link;
+  }
+
+  List<T> toList() {
+    if (length == 0) return new List<T>(0);
+    List<T> list = new List<T>(length);
+    int index = 0;
+    Link<T> link = head;
+    while (link.isNotEmpty) {
+      list[index] = link.head;
+      link = link.tail;
+      index++;
+    }
+    lastLink = null;
+    head = null;
+    length = 0;
+    return list;
+  }
+
+  Link<T> addLast(T t) {
+    length++;
+    LinkEntry<T> entry = new LinkEntry<T>(t, null);
+    if (head == null) {
+      head = entry;
+    } else {
+      lastLink.tail = entry;
+    }
+    lastLink = entry;
+    return entry;
+  }
+
+  bool get isEmpty => length == 0;
+
+  T get first {
+    if (head != null) {
+      return head.head;
+    }
+    throw new StateError("no elements");
+  }
+
+  void clear() {
+    head = null;
+    lastLink = null;
+    length = 0;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/util/relativize.dart b/pkg/front_end/lib/src/fasta/util/relativize.dart
new file mode 100644
index 0000000..59e9f16
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/relativize.dart
@@ -0,0 +1,14 @@
+// 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 fasta.util.relativize;
+
+// TODO(ahe): Move more advanced version from dart2js here.
+
+String relativizeUri(Uri uri, {Uri base}) {
+  if (uri == null) return null;
+  base ??= Uri.base;
+  String result = "$uri";
+  return result.startsWith("$base") ? result.substring("$base".length) : result;
+}
diff --git a/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart b/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
index 50473eb..efd4ddd 100644
--- a/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
+++ b/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
@@ -93,7 +93,7 @@
 }
 
 class _AnalysisContextProxy implements AnalysisContext {
-  final Map<Uri, ResolvedLibrary> _resolvedLibraries;
+  final Map<Uri, Map<Uri, CompilationUnit>> _resolvedLibraries;
 
   @override
   final _SourceFactoryProxy sourceFactory = new _SourceFactoryProxy();
@@ -112,7 +112,7 @@
     assert(_resolvedLibraries.containsKey(source.uri));
     return resolutionMap
         .elementDeclaredByCompilationUnit(
-            _resolvedLibraries[source.uri].definingCompilationUnit)
+            _resolvedLibraries[source.uri][source.uri])
         .library;
   }
 
@@ -120,14 +120,9 @@
 
   CompilationUnit resolveCompilationUnit(
       Source unitSource, LibraryElement library) {
-    assert(_resolvedLibraries.containsKey(library.source.uri));
-    var resolvedLibrary = _resolvedLibraries[library.source.uri];
-    if (unitSource == library.source) {
-      return resolvedLibrary.definingCompilationUnit;
-    } else {
-      assert(resolvedLibrary.partUnits.containsKey(unitSource.uri));
-      return resolvedLibrary.partUnits[unitSource.uri];
-    }
+    var unit = _resolvedLibraries[library.source.uri][unitSource.uri];
+    assert(unit != null);
+    return unit;
   }
 }
 
diff --git a/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart b/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
index aa51fbf..d0b093b 100644
--- a/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
+++ b/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
@@ -13,12 +13,12 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/util/absolute_path.dart';
 import 'package:front_end/incremental_resolved_ast_generator.dart';
 import 'package:front_end/src/base/file_repository.dart';
 import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/base/resolve_relative_uri.dart';
 import 'package:front_end/src/base/source.dart';
 import 'package:front_end/src/dependency_grapher_impl.dart';
 import 'package:path/src/context.dart';
@@ -69,7 +69,7 @@
         await graphForProgram([_source], _options, fileReader: _fileReader);
     // TODO(paulberry): collect no-longer-referenced files from _fileState and
     // _fileRepository.
-    var libraries = <Uri, ResolvedLibrary>{};
+    var libraries = <Uri, Map<Uri, CompilationUnit>>{};
     if (!_schedulerStarted) {
       _scheduler.start();
       _schedulerStarted = true;
@@ -87,8 +87,7 @@
         var result =
             await _driver.getResult(_fileRepository.pathForUri(libraryUri));
         // TODO(paulberry): handle errors.
-        var definingCompilationUnit = result.unit;
-        var partUnits = <Uri, CompilationUnit>{};
+        var units = {libraryUri: result.unit};
         for (var partUri in libraryNode.parts) {
           // Really we ought to have a driver API that lets us request a
           // specific part of a given library.  Otherwise we will run into
@@ -97,10 +96,9 @@
           var partResult =
               await _driver.getResult(_fileRepository.pathForUri(partUri));
           // TODO(paulberry): handle errors.
-          partUnits[partUri] = partResult.unit;
+          units[partUri] = partResult.unit;
         }
-        libraries[libraryUri] =
-            new ResolvedLibrary(definingCompilationUnit, partUnits);
+        libraries[libraryUri] = units;
       }
     }
     _driver.addFile(_fileRepository.pathForUri(_source));
@@ -268,8 +266,13 @@
   @override
   Source forUri(String absoluteUri) {
     Uri uri = Uri.parse(absoluteUri);
+    return forUri2(uri);
+  }
+
+  @override
+  Source forUri2(Uri absoluteUri) {
     return new _SourceProxy(
-        uri, _fileRepository.pathForUri(uri, allocate: true));
+        absoluteUri, _fileRepository.pathForUri(absoluteUri, allocate: true));
   }
 
   noSuchMethod(Invocation invocation) => unimplemented();
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index abd0194..d9a508b 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -1000,9 +1000,6 @@
   static const TokenType INDEX_EQ =
       const TokenType._('INDEX_EQ', TokenClass.UNARY_POSTFIX_OPERATOR, '[]=');
 
-  static const TokenType IS =
-      const TokenType._('IS', TokenClass.RELATIONAL_OPERATOR, 'is');
-
   static const TokenType LT =
       const TokenType._('LT', TokenClass.RELATIONAL_OPERATOR, '<');
 
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index 5436751..5f15860 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -1,12 +1,12 @@
 name: front_end
-version: 0.1.0-alpha.0
+version: 0.1.0-alpha.1
 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: '>=1.12.0 <2.0.0'
 dependencies:
-  analyzer: '^0.29.0'
+  analyzer: 0.30.0-alpha.1
   path: '^1.3.9'
   source_span: '^1.2.3'
 dev_dependencies:
diff --git a/pkg/front_end/test/fasta/accessors.dart b/pkg/front_end/test/fasta/accessors.dart
new file mode 100644
index 0000000..453e61f
--- /dev/null
+++ b/pkg/front_end/test/fasta/accessors.dart
@@ -0,0 +1,48 @@
+// 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.
+
+void set onlySetter(value) {
+  print("onlySetter called with $value.");
+}
+
+class C {
+  void set onlySetter(value) {
+    print("C.onlySetter called with $value.");
+  }
+
+  testC() {
+    try {
+      print(onlySetter);
+      throw "No error thrown";
+    } on NoSuchMethodError catch (e) {
+      print("Expected error: $e");
+    }
+    onlySetter = "hest";
+  }
+
+  testD() {
+    print(onlySetter);
+    onlySetter = "hest";
+  }
+}
+
+class D extends C {
+  String get onlySetter() => "D.onlySetter called.";
+
+  void set onlySetter(value) {
+    print("D.onlySetter called with $value.");
+  }
+}
+
+main() {
+  try {
+    print(onlySetter);
+    throw "No error thrown";
+  } on NoSuchMethodError catch (e) {
+    print("Expected error: $e");
+  }
+  onlySetter = "fisk";
+  new C().testC();
+  new D().testD();
+}
diff --git a/pkg/front_end/test/fasta/accessors.dart.direct.expect b/pkg/front_end/test/fasta/accessors.dart.direct.expect
new file mode 100644
index 0000000..04b2ad4
--- /dev/null
+++ b/pkg/front_end/test/fasta/accessors.dart.direct.expect
@@ -0,0 +1,51 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  set onlySetter(dynamic value) → void {
+    core::print("C.onlySetter called with ${value}.");
+  }
+  method testC() → dynamic {
+    try {
+      core::print(this.onlySetter);
+      throw "No error thrown";
+    }
+    on core::NoSuchMethodError catch(dynamic e) {
+      core::print("Expected error: ${e}");
+    }
+    this.onlySetter = "hest";
+  }
+  method testD() → dynamic {
+    core::print(this.onlySetter);
+    this.onlySetter = "hest";
+  }
+}
+class D extends self::C {
+  constructor •() → void
+    : super self::C::•()
+    ;
+  set onlySetter(dynamic value) → void {
+    core::print("D.onlySetter called with ${value}.");
+  }
+  get onlySetter() → core::String
+    return "D.onlySetter called.";
+}
+static set onlySetter(dynamic value) → void {
+  core::print("onlySetter called with ${value}.");
+}
+static method main() → dynamic {
+  try {
+    core::print(throw new core::NoSuchMethodError::•(null, #onlySetter, <dynamic>[], <dynamic, dynamic>{}, null));
+    throw "No error thrown";
+  }
+  on core::NoSuchMethodError catch(dynamic e) {
+    core::print("Expected error: ${e}");
+  }
+  self::onlySetter = "fisk";
+  new self::C::•().testC();
+  new self::D::•().testD();
+}
diff --git a/pkg/front_end/test/fasta/accessors.dart.outline.expect b/pkg/front_end/test/fasta/accessors.dart.outline.expect
new file mode 100644
index 0000000..0fd3593
--- /dev/null
+++ b/pkg/front_end/test/fasta/accessors.dart.outline.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  set onlySetter(dynamic value) → void
+    ;
+  method testC() → dynamic
+    ;
+  method testD() → dynamic
+    ;
+}
+class D extends self::C {
+  constructor •() → void
+    ;
+  set onlySetter(dynamic value) → void
+    ;
+  get onlySetter() → core::String
+    ;
+}
+static set onlySetter(dynamic value) → void
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/await.dart b/pkg/front_end/test/fasta/await.dart
new file mode 100644
index 0000000..03f2945
--- /dev/null
+++ b/pkg/front_end/test/fasta/await.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() async {
+  print(await "Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/await.dart.dartk.expect b/pkg/front_end/test/fasta/await.dart.dartk.expect
new file mode 100644
index 0000000..5b1be33
--- /dev/null
+++ b/pkg/front_end/test/fasta/await.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic async {
+  core::print(await "Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/await.dart.direct.expect b/pkg/front_end/test/fasta/await.dart.direct.expect
new file mode 100644
index 0000000..5b1be33
--- /dev/null
+++ b/pkg/front_end/test/fasta/await.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic async {
+  core::print(await "Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/await.dart.outline.expect b/pkg/front_end/test/fasta/await.dart.outline.expect
new file mode 100644
index 0000000..b3304ef
--- /dev/null
+++ b/pkg/front_end/test/fasta/await.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic async 
+  ;
diff --git a/pkg/front_end/test/fasta/cascade.dart b/pkg/front_end/test/fasta/cascade.dart
new file mode 100644
index 0000000..ac3a782
--- /dev/null
+++ b/pkg/front_end/test/fasta/cascade.dart
@@ -0,0 +1,31 @@
+// 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.
+
+main() {
+  var list = [1]
+      ..add(2)
+      ..add(3)
+      ..addAll([4, 5]);
+  print(list);
+
+  list
+      ..add(2)
+      ..length
+      ..length = 0;
+  print(list);
+
+  list
+      ..add(2)
+      ..[0]
+      ..[0] = 87;
+
+  print(list);
+
+  list = [[1]]
+      ..first.last.toString()
+      ..first[0].toString()
+      ..[0].last.toString();
+
+  print(list);
+}
diff --git a/pkg/front_end/test/fasta/cascade.dart.dartk.expect b/pkg/front_end/test/fasta/cascade.dart.dartk.expect
new file mode 100644
index 0000000..688dbd7
--- /dev/null
+++ b/pkg/front_end/test/fasta/cascade.dart.dartk.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  dynamic list = let final dynamic #t1 = <dynamic>[1] in let final dynamic #t2 = #t1.add(2) in let final dynamic #t3 = #t1.add(3) in let final dynamic #t4 = #t1.addAll(<dynamic>[4, 5]) in #t1;
+  core::print(list);
+  let final dynamic #t5 = list in let final dynamic #t6 = #t5.add(2) in let final dynamic #t7 = #t5.length in let final dynamic #t8 = #t5.length = 0 in #t5;
+  core::print(list);
+  let final dynamic #t9 = list in let final dynamic #t10 = #t9.add(2) in let final dynamic #t11 = #t9.[](0) in let final dynamic #t12 = let final dynamic #t13 = #t9 in let final dynamic #t14 = 0 in let final dynamic #t15 = 87 in let final dynamic #t16 = #t13.[]=(#t14, #t15) in #t15 in #t9;
+  core::print(list);
+  list = let final dynamic #t17 = <dynamic>[<dynamic>[1]] in let final dynamic #t18 = #t17.first.last.toString() in let final dynamic #t19 = #t17.first.[](0).toString() in let final dynamic #t20 = #t17.[](0).last.toString() in #t17;
+  core::print(list);
+}
diff --git a/pkg/front_end/test/fasta/cascade.dart.direct.expect b/pkg/front_end/test/fasta/cascade.dart.direct.expect
new file mode 100644
index 0000000..f2cd187
--- /dev/null
+++ b/pkg/front_end/test/fasta/cascade.dart.direct.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  dynamic list = let final dynamic #t1 = <dynamic>[1] in let final dynamic #t2 = #t1.add(2) in let final dynamic #t3 = #t1.add(3) in let final dynamic #t4 = #t1.addAll(<dynamic>[4, 5]) in #t1;
+  core::print(list);
+  let final dynamic #t5 = list in let final dynamic #t6 = #t5.add(2) in let final dynamic #t7 = #t5.length in let final dynamic #t8 = #t5.length = 0 in #t5;
+  core::print(list);
+  let final dynamic #t9 = list in let final dynamic #t10 = #t9.add(2) in let final dynamic #t11 = #t9.[](0) in let final dynamic #t12 = #t9.[]=(0, 87) in #t9;
+  core::print(list);
+  list = let final dynamic #t13 = <dynamic>[<dynamic>[1]] in let final dynamic #t14 = #t13.first.last.toString() in let final dynamic #t15 = #t13.first.[](0).toString() in let final dynamic #t16 = #t13.[](0).last.toString() in #t13;
+  core::print(list);
+}
diff --git a/pkg/front_end/test/fasta/cascade.dart.outline.expect b/pkg/front_end/test/fasta/cascade.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/cascade.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/casts.dart b/pkg/front_end/test/fasta/casts.dart
new file mode 100644
index 0000000..2c7a621
--- /dev/null
+++ b/pkg/front_end/test/fasta/casts.dart
@@ -0,0 +1,21 @@
+// 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.
+
+main() {
+  print("" as String);
+  print(1 as int);
+  print(1.0 as double);
+
+  print("" is String);
+  print("" is int);
+  print("" is double);
+
+  print(1 is String);
+  print(1 is int);
+  print(1 is double);
+
+  print(1.0 is String);
+  print(1.0 is int);
+  print(1.0 is double);
+}
diff --git a/pkg/front_end/test/fasta/casts.dart.dartk.expect b/pkg/front_end/test/fasta/casts.dart.dartk.expect
new file mode 100644
index 0000000..c75d8ec
--- /dev/null
+++ b/pkg/front_end/test/fasta/casts.dart.dartk.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("" as core::String);
+  core::print(1 as core::int);
+  core::print(1.0 as core::double);
+  core::print("" is core::String);
+  core::print("" is core::int);
+  core::print("" is core::double);
+  core::print(1 is core::String);
+  core::print(1 is core::int);
+  core::print(1 is core::double);
+  core::print(1.0 is core::String);
+  core::print(1.0 is core::int);
+  core::print(1.0 is core::double);
+}
diff --git a/pkg/front_end/test/fasta/casts.dart.direct.expect b/pkg/front_end/test/fasta/casts.dart.direct.expect
new file mode 100644
index 0000000..c75d8ec
--- /dev/null
+++ b/pkg/front_end/test/fasta/casts.dart.direct.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("" as core::String);
+  core::print(1 as core::int);
+  core::print(1.0 as core::double);
+  core::print("" is core::String);
+  core::print("" is core::int);
+  core::print("" is core::double);
+  core::print(1 is core::String);
+  core::print(1 is core::int);
+  core::print(1 is core::double);
+  core::print(1.0 is core::String);
+  core::print(1.0 is core::int);
+  core::print(1.0 is core::double);
+}
diff --git a/pkg/front_end/test/fasta/casts.dart.outline.expect b/pkg/front_end/test/fasta/casts.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/casts.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/classes.dart b/pkg/front_end/test/fasta/classes.dart
new file mode 100644
index 0000000..1536904
--- /dev/null
+++ b/pkg/front_end/test/fasta/classes.dart
@@ -0,0 +1,29 @@
+// 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.
+
+class A {
+  final int x;
+  final int y;
+  A(this.y) : x = 42;
+  method() {
+    print("A.method x: $x y: $y");
+    print(this);
+    print(this.runtimeType);
+  }
+}
+
+class B extends A {
+  B(x) : super(x);
+  method() {
+    print("B.method x: $x y: $y");
+    super.method();
+  }
+}
+
+main() {
+  A a = new A(87);
+  B b = new B(117);
+  a.method();
+  b.method();
+}
diff --git a/pkg/front_end/test/fasta/classes.dart.direct.expect b/pkg/front_end/test/fasta/classes.dart.direct.expect
new file mode 100644
index 0000000..db0cfb8
--- /dev/null
+++ b/pkg/front_end/test/fasta/classes.dart.direct.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  final field core::int x;
+  final field core::int y;
+  constructor •(dynamic y) → void
+    : self::A::y = y, self::A::x = 42, super core::Object::•()
+    ;
+  method method() → dynamic {
+    core::print("A.method x: ${this.x} y: ${this.y}");
+    core::print(this);
+    core::print(this.runtimeType);
+  }
+}
+class B extends self::A {
+  constructor •(dynamic x) → void
+    : super self::A::•(x)
+    ;
+  method method() → dynamic {
+    core::print("B.method x: ${this.x} y: ${this.y}");
+    this.{=self::A::method}();
+  }
+}
+static method main() → dynamic {
+  self::A a = new self::A::•(87);
+  self::B b = new self::B::•(117);
+  a.method();
+  b.method();
+}
diff --git a/pkg/front_end/test/fasta/classes.dart.outline.expect b/pkg/front_end/test/fasta/classes.dart.outline.expect
new file mode 100644
index 0000000..7871b62
--- /dev/null
+++ b/pkg/front_end/test/fasta/classes.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  final field core::int x;
+  final field core::int y;
+  constructor •(dynamic y) → void
+    ;
+  method method() → dynamic
+    ;
+}
+class B extends self::A {
+  constructor •(dynamic x) → void
+    ;
+  method method() → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/compile.status b/pkg/front_end/test/fasta/compile.status
new file mode 100644
index 0000000..fec1fd2
--- /dev/null
+++ b/pkg/front_end/test/fasta/compile.status
@@ -0,0 +1,74 @@
+# 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.
+
+# Status file for the compile_test.dart (notice c, not k) test suite. This is
+# testing generating Kernel ASTs directly, that is, code in
+# pkg/fasta/lib/src/kernel/.
+
+await: Fail
+invocations: Fail
+
+rasta/abstract_constructor: Fail
+rasta/bad_constructor_redirection: Fail
+rasta/bad_continue: Fail
+rasta/bad_default_constructor: VerificationError
+rasta/bad_explicit_super_constructor: Fail
+rasta/bad_implicit_super_constructor: Fail
+rasta/bad_interpolation: Fail
+rasta/bad_redirection: Fail
+rasta/bad_setter_initializer: Fail
+rasta/bad_unicode: Fail
+rasta/breaking_bad: Fail
+rasta/class_hierarchy: Fail
+rasta/class_member: Fail
+rasta/constant_get_and_invoke: Fail
+rasta/deferred_lib: Fail
+rasta/deferred_load: Fail
+rasta/duplicated_mixin: Fail
+rasta/export: Fail
+rasta/foo: Fail
+rasta/for_loop: Fail
+rasta/generic_factory: Fail
+rasta/issue_000001: Fail
+rasta/issue_000031: Fail
+rasta/issue_000032: Fail
+rasta/issue_000034: Fail
+rasta/issue_000035: Fail
+rasta/issue_000035a: Fail
+rasta/issue_000036: Fail
+rasta/issue_000039: Fail
+rasta/issue_000041: Fail
+rasta/issue_000042: Fail
+rasta/issue_000043: Fail
+rasta/issue_000044: Fail
+rasta/issue_000045: Fail
+rasta/issue_000046: Fail
+rasta/issue_000047: Fail
+rasta/issue_000067: Fail
+rasta/issue_000069: Fail
+rasta/issue_000070: Fail
+rasta/issue_000081: Fail
+rasta/malformed_const_constructor: Fail
+rasta/malformed_function: Fail
+rasta/malformed_function_type: Fail
+rasta/mandatory_parameter_initializer: Fail
+rasta/mixin_library: Fail
+rasta/native_is_illegal: Fail
+rasta/parser_error: Fail
+rasta/static: VerificationError
+rasta/super: Fail
+rasta/super_initializer: Fail
+rasta/super_mixin: Fail
+rasta/super_operator: Fail
+rasta/switch_execution_case_t02: Fail
+rasta/switch_fall_through: Fail
+rasta/try_label: Fail
+rasta/type_literals: Fail
+rasta/type_with_parse_error: Fail
+rasta/typedef: Fail
+rasta/unresolved: Fail
+rasta/unresolved_constructor: Fail
+rasta/unresolved_for_in: Fail
+rasta/unresolved_recovery: Fail
+rasta/unsupported_platform_library: Fail
diff --git a/pkg/front_end/test/fasta/compile_test.dart b/pkg/front_end/test/fasta/compile_test.dart
new file mode 100644
index 0000000..cba4097
--- /dev/null
+++ b/pkg/front_end/test/fasta/compile_test.dart
@@ -0,0 +1,19 @@
+// 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.
+
+library fasta.test.compile_test;
+
+import 'dart:async' show
+    Future;
+
+import 'package:front_end/src/fasta/testing/suite.dart';
+
+Future<FeContext> createContext(
+    Chain suite, Map<String, String> environment) {
+  environment[ENABLE_FULL_COMPILE] = "";
+  environment[AST_KIND_INDEX] = "${AstKind.Kernel.index}";
+  return TestContext.create(suite, environment, FeContext.create);
+}
+
+main(List<String> arguments) => runMe(arguments, createContext, "testing.json");
diff --git a/pkg/front_end/test/fasta/cycles.dart b/pkg/front_end/test/fasta/cycles.dart
new file mode 100644
index 0000000..977faff
--- /dev/null
+++ b/pkg/front_end/test/fasta/cycles.dart
@@ -0,0 +1,22 @@
+// 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.
+
+class A implements C {
+}
+
+class B extends A {
+}
+
+class C extends B implements D {
+}
+
+class D {
+}
+
+main() {
+  print(new A());
+  print(new B());
+  print(new C());
+  print(new D());
+}
diff --git a/pkg/front_end/test/fasta/cycles.dart.dartk.expect b/pkg/front_end/test/fasta/cycles.dart.dartk.expect
new file mode 100644
index 0000000..52b92e7
--- /dev/null
+++ b/pkg/front_end/test/fasta/cycles.dart.dartk.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+
+class A {
+}
+class B {
+}
+class C {
+}
+class D {
+}
diff --git a/pkg/front_end/test/fasta/cycles.dart.direct.expect b/pkg/front_end/test/fasta/cycles.dart.direct.expect
new file mode 100644
index 0000000..94594c5
--- /dev/null
+++ b/pkg/front_end/test/fasta/cycles.dart.direct.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class B extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class D extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  core::print(new self::A::•());
+  core::print(new self::B::•());
+  core::print(new self::C::•());
+  core::print(new self::D::•());
+}
diff --git a/pkg/front_end/test/fasta/cycles.dart.outline.expect b/pkg/front_end/test/fasta/cycles.dart.outline.expect
new file mode 100644
index 0000000..94caec3
--- /dev/null
+++ b/pkg/front_end/test/fasta/cycles.dart.outline.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    ;
+}
+class B extends core::Object {
+  constructor •() → void
+    ;
+}
+class C extends core::Object {
+  constructor •() → void
+    ;
+}
+class D extends core::Object {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/default_values.dart b/pkg/front_end/test/fasta/default_values.dart
new file mode 100644
index 0000000..de8ccc5
--- /dev/null
+++ b/pkg/front_end/test/fasta/default_values.dart
@@ -0,0 +1,9 @@
+// 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.
+
+topLevel([a = 42]) => a;
+
+main() {
+  print(topLevel());
+}
diff --git a/pkg/front_end/test/fasta/default_values.dart.direct.expect b/pkg/front_end/test/fasta/default_values.dart.direct.expect
new file mode 100644
index 0000000..6e1163b
--- /dev/null
+++ b/pkg/front_end/test/fasta/default_values.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method topLevel([dynamic a = 42]) → dynamic
+  return a;
+static method main() → dynamic {
+  core::print(self::topLevel(42));
+}
diff --git a/pkg/front_end/test/fasta/default_values.dart.outline.expect b/pkg/front_end/test/fasta/default_values.dart.outline.expect
new file mode 100644
index 0000000..88ff556
--- /dev/null
+++ b/pkg/front_end/test/fasta/default_values.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method topLevel([dynamic a]) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/expressions.dart b/pkg/front_end/test/fasta/expressions.dart
new file mode 100644
index 0000000..9b1f55d
--- /dev/null
+++ b/pkg/front_end/test/fasta/expressions.dart
@@ -0,0 +1,77 @@
+// 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.
+
+foo({fisk}) {
+  print(fisk);
+}
+
+caller(f) {
+  f();
+}
+
+main() {
+  int i = 0;
+  print(i == 1 ? "bad" : "good");
+  print("$i");
+  print("'$i'");
+  print(" '${i}' ");
+  print(" '${i}' '${i}'");
+  print(" '$i' '${i}'");
+  print("foo" "bar");
+  print(" '${i}' '${i}'" " '$i' '${i}'");
+  try {
+    throw "fisk";
+  } on String catch (e, s) {
+    print(e);
+    if (s != null) print(s);
+  }
+  for(;false;) {}
+  var list = ["Hello, World!"];
+  print(list[i]);
+  list[i] = "Hello, Brave New World!";
+  print(list[i]);
+  i = 87;
+  print(-i);
+  print(~i);
+  print(!(i == 42));
+  print(--i);
+  print(++i);
+  print(i--);
+  print(i++);
+  print(new Object());
+  print(const Object());
+  print((new List<String>(2)).runtimeType);
+  foo(fisk: "Blorp gulp");
+  f() {
+    print("f was called");
+  }
+  caller(f);
+  caller(() {
+    print("<anon> was called");
+  });
+  g([message]) {
+    print(message);
+  }
+  g("Hello, World");
+  caller(([x]) {
+    print("<anon> was called with $x");
+  });
+  h({message}) {
+    print(message);
+  }
+  h(message: "Hello, World");
+  caller(({x}) {
+    print("<anon> was called with $x");
+  });
+  print((int).toString());
+  print(int);
+  print(int..toString());
+  try {
+    print(int?.toString());
+    throw "Shouldn't work";
+  } on NoSuchMethodError catch (e) {
+    print("As expected: $e");
+  }
+  print(int.parse("42"));
+}
diff --git a/pkg/front_end/test/fasta/expressions.dart.dartk.expect b/pkg/front_end/test/fasta/expressions.dart.dartk.expect
new file mode 100644
index 0000000..0739d73
--- /dev/null
+++ b/pkg/front_end/test/fasta/expressions.dart.dartk.expect
@@ -0,0 +1,37 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int i = 0;
+  core::print(i.==(1) ? "bad" : "good");
+  core::print("${i}");
+  core::print("'${i}'");
+  core::print(" '${i}' ");
+  core::print(" '${i}' '${i}'");
+  core::print(" '${i}' '${i}'");
+  core::print("foobar");
+  core::print(" '${i}' '${i}' '${i}' '${i}'");
+  try {
+    throw "fisk";
+  }
+  on core::String catch(dynamic e, dynamic s) {
+    core::print(e);
+    if(!s.==(null))
+      core::print(s);
+  }
+  for (; false; ) {
+  }
+  dynamic list = <dynamic>["Hello, World!"];
+  core::print(list.[](i));
+  list.[]=(i, "Hello, Brave New World!");
+  core::print(list.[](i));
+  i = 87;
+  core::print(i.unary-());
+  core::print(i.~());
+  core::print(!i.==(42));
+  core::print(i = i.-(1));
+  core::print(i = i.+(1));
+  core::print(let final dynamic #t1 = i in let final dynamic #t2 = i = #t1.-(1) in #t1);
+  core::print(let final dynamic #t3 = i in let final dynamic #t4 = i = #t3.+(1) in #t3);
+}
diff --git a/pkg/front_end/test/fasta/expressions.dart.direct.expect b/pkg/front_end/test/fasta/expressions.dart.direct.expect
new file mode 100644
index 0000000..803d58d
--- /dev/null
+++ b/pkg/front_end/test/fasta/expressions.dart.direct.expect
@@ -0,0 +1,79 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo({dynamic fisk = null}) → dynamic {
+  core::print(fisk);
+}
+static method caller(dynamic f) → dynamic {
+  f.call();
+}
+static method main() → dynamic {
+  core::int i = 0;
+  core::print(i.==(1) ? "bad" : "good");
+  core::print("${i}");
+  core::print("'${i}'");
+  core::print(" '${i}' ");
+  core::print(" '${i}' '${i}'");
+  core::print(" '${i}' '${i}'");
+  core::print("foobar");
+  core::print(" '${i}' '${i}' '${i}' '${i}'");
+  try {
+    throw "fisk";
+  }
+  on core::String catch(dynamic e, dynamic s) {
+    core::print(e);
+    if(!s.==(null))
+      core::print(s);
+  }
+  for (; false; ) {
+  }
+  dynamic list = <dynamic>["Hello, World!"];
+  core::print(list.[](i));
+  list.[]=(i, "Hello, Brave New World!");
+  core::print(list.[](i));
+  i = 87;
+  core::print(i.unary-());
+  core::print(i.~());
+  core::print(!i.==(42));
+  core::print(i = i.-(1));
+  core::print(i = i.+(1));
+  core::print(let final dynamic #t1 = i in let final dynamic #t2 = i = #t1.-(1) in #t1);
+  core::print(let final dynamic #t3 = i in let final dynamic #t4 = i = #t3.+(1) in #t3);
+  core::print(new core::Object::•());
+  core::print(const core::Object::•());
+  core::print(core::List::_internal<core::String>(2).runtimeType);
+  self::foo(fisk: "Blorp gulp");
+  function f() → dynamic {
+    core::print("f was called");
+  }
+  self::caller(f);
+  self::caller(() → dynamic {
+    core::print("<anon> was called");
+  });
+  function g([dynamic message]) → dynamic {
+    core::print(message);
+  }
+  g.call("Hello, World");
+  self::caller(([dynamic x]) → dynamic {
+    core::print("<anon> was called with ${x}");
+  });
+  function h({dynamic message}) → dynamic {
+    core::print(message);
+  }
+  h.call(message: "Hello, World");
+  self::caller(({dynamic x}) → dynamic {
+    core::print("<anon> was called with ${x}");
+  });
+  core::print(core::int.toString());
+  core::print(core::int);
+  core::print(let final dynamic #t5 = core::int in let final dynamic #t6 = #t5.toString() in #t5);
+  try {
+    core::print(throw new core::NoSuchMethodError::•(null, #toString, <dynamic>[], <dynamic, dynamic>{}, null));
+    throw "Shouldn't work";
+  }
+  on core::NoSuchMethodError catch(dynamic e) {
+    core::print("As expected: ${e}");
+  }
+  core::print(core::int::parse("42", radix: null, onError: null));
+}
diff --git a/pkg/front_end/test/fasta/expressions.dart.outline.expect b/pkg/front_end/test/fasta/expressions.dart.outline.expect
new file mode 100644
index 0000000..721ce9d
--- /dev/null
+++ b/pkg/front_end/test/fasta/expressions.dart.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+
+static method foo({dynamic fisk}) → dynamic
+  ;
+static method caller(dynamic f) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/fibonacci.dart b/pkg/front_end/test/fasta/fibonacci.dart
new file mode 100644
index 0000000..e1ab1d5
--- /dev/null
+++ b/pkg/front_end/test/fasta/fibonacci.dart
@@ -0,0 +1,14 @@
+// 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.
+
+int fibonacci(int n) {
+  if (n < 2) return n;
+  return fibonacci(n - 1) + fibonacci(n - 2);
+}
+
+main() {
+  for (int i = 0; i < 20; i++) {
+    print(fibonacci(i));
+  }
+}
diff --git a/pkg/front_end/test/fasta/fibonacci.dart.dartk.expect b/pkg/front_end/test/fasta/fibonacci.dart.dartk.expect
new file mode 100644
index 0000000..c46429a
--- /dev/null
+++ b/pkg/front_end/test/fasta/fibonacci.dart.dartk.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method fibonacci(core::int n) → core::int {
+  if(n.<(2))
+    return n;
+  return self::fibonacci(n.-(1)).+(self::fibonacci(n.-(2)));
+}
+static method main() → dynamic {
+  for (core::int i = 0; i.<(20); i = i.+(1)) {
+    core::print(self::fibonacci(i));
+  }
+}
diff --git a/pkg/front_end/test/fasta/fibonacci.dart.direct.expect b/pkg/front_end/test/fasta/fibonacci.dart.direct.expect
new file mode 100644
index 0000000..c46429a
--- /dev/null
+++ b/pkg/front_end/test/fasta/fibonacci.dart.direct.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method fibonacci(core::int n) → core::int {
+  if(n.<(2))
+    return n;
+  return self::fibonacci(n.-(1)).+(self::fibonacci(n.-(2)));
+}
+static method main() → dynamic {
+  for (core::int i = 0; i.<(20); i = i.+(1)) {
+    core::print(self::fibonacci(i));
+  }
+}
diff --git a/pkg/front_end/test/fasta/fibonacci.dart.outline.expect b/pkg/front_end/test/fasta/fibonacci.dart.outline.expect
new file mode 100644
index 0000000..585adbb
--- /dev/null
+++ b/pkg/front_end/test/fasta/fibonacci.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method fibonacci(core::int n) → core::int
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/for_in_scope.dart b/pkg/front_end/test/fasta/for_in_scope.dart
new file mode 100644
index 0000000..86fb4cf
--- /dev/null
+++ b/pkg/front_end/test/fasta/for_in_scope.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main(List<String> arguments) {
+  for (String arguments in arguments) {
+    print(arguments);
+  }
+}
diff --git a/pkg/front_end/test/fasta/for_in_scope.dart.direct.expect b/pkg/front_end/test/fasta/for_in_scope.dart.direct.expect
new file mode 100644
index 0000000..624010c
--- /dev/null
+++ b/pkg/front_end/test/fasta/for_in_scope.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main(core::List<core::String> arguments) → dynamic {
+  for (core::String arguments in arguments) {
+    core::print(arguments);
+  }
+}
diff --git a/pkg/front_end/test/fasta/for_in_scope.dart.outline.expect b/pkg/front_end/test/fasta/for_in_scope.dart.outline.expect
new file mode 100644
index 0000000..09786f2
--- /dev/null
+++ b/pkg/front_end/test/fasta/for_in_scope.dart.outline.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main(core::List<core::String> arguments) → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/functions.dart b/pkg/front_end/test/fasta/functions.dart
new file mode 100644
index 0000000..a0cd542
--- /dev/null
+++ b/pkg/front_end/test/fasta/functions.dart
@@ -0,0 +1,13 @@
+// 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.
+
+main() {
+  void local(void f({a})) {
+    f(a: "Hello, World");
+    f();
+  }
+  local(({a: "Default greeting!"}) {
+    print(a);
+  });
+}
diff --git a/pkg/front_end/test/fasta/functions.dart.direct.expect b/pkg/front_end/test/fasta/functions.dart.direct.expect
new file mode 100644
index 0000000..a816760
--- /dev/null
+++ b/pkg/front_end/test/fasta/functions.dart.direct.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  function local(({a: dynamic}) → void f) → void {
+    f.call(a: "Hello, World");
+    f.call();
+  }
+  local.call(({dynamic a = "Default greeting!"}) → dynamic {
+    core::print(a);
+  });
+}
diff --git a/pkg/front_end/test/fasta/functions.dart.outline.expect b/pkg/front_end/test/fasta/functions.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/functions.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/hello.dart b/pkg/front_end/test/fasta/hello.dart
new file mode 100644
index 0000000..bcb7f2e
--- /dev/null
+++ b/pkg/front_end/test/fasta/hello.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/hello.dart.dartk.expect b/pkg/front_end/test/fasta/hello.dart.dartk.expect
new file mode 100644
index 0000000..fea7b39
--- /dev/null
+++ b/pkg/front_end/test/fasta/hello.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/hello.dart.direct.expect b/pkg/front_end/test/fasta/hello.dart.direct.expect
new file mode 100644
index 0000000..fea7b39
--- /dev/null
+++ b/pkg/front_end/test/fasta/hello.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/hello.dart.outline.expect b/pkg/front_end/test/fasta/hello.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/hello.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/implicit_this.dart b/pkg/front_end/test/fasta/implicit_this.dart
new file mode 100644
index 0000000..ed2a435
--- /dev/null
+++ b/pkg/front_end/test/fasta/implicit_this.dart
@@ -0,0 +1,24 @@
+// 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.
+
+class C {
+  m() {
+    print("Called m");
+  }
+
+  testC() {
+    m();
+  }
+}
+
+class D extends C {
+  testD() {
+    m();
+  }
+}
+
+main() {
+  new C().testC();
+  new D().testD();
+}
diff --git a/pkg/front_end/test/fasta/implicit_this.dart.direct.expect b/pkg/front_end/test/fasta/implicit_this.dart.direct.expect
new file mode 100644
index 0000000..6fb182c
--- /dev/null
+++ b/pkg/front_end/test/fasta/implicit_this.dart.direct.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method m() → dynamic {
+    core::print("Called m");
+  }
+  method testC() → dynamic {
+    this.m();
+  }
+}
+class D extends self::C {
+  constructor •() → void
+    : super self::C::•()
+    ;
+  method testD() → dynamic {
+    this.m();
+  }
+}
+static method main() → dynamic {
+  new self::C::•().testC();
+  new self::D::•().testD();
+}
diff --git a/pkg/front_end/test/fasta/implicit_this.dart.outline.expect b/pkg/front_end/test/fasta/implicit_this.dart.outline.expect
new file mode 100644
index 0000000..bff63cc
--- /dev/null
+++ b/pkg/front_end/test/fasta/implicit_this.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  method m() → dynamic
+    ;
+  method testC() → dynamic
+    ;
+}
+class D extends self::C {
+  constructor •() → void
+    ;
+  method testD() → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/invocations.dart b/pkg/front_end/test/fasta/invocations.dart
new file mode 100644
index 0000000..aaba335
--- /dev/null
+++ b/pkg/front_end/test/fasta/invocations.dart
@@ -0,0 +1,14 @@
+// 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.
+
+main() {
+  print("Hello, World!");
+  z("Hello, World!");
+  z.print("Hello, World!");
+  y.z.print("Hello, World!");
+  x.y.z.print("Hello, World!");
+
+  1 + print("Hello, World!") + z("Hello, World!") + z.print("Hello, World!")
+      + y.z.print("Hello, World!") + x.y.z.print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/invocations.dart.dartk.expect b/pkg/front_end/test/fasta/invocations.dart.dartk.expect
new file mode 100644
index 0000000..89ed30f
--- /dev/null
+++ b/pkg/front_end/test/fasta/invocations.dart.dartk.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("Hello, World!");
+  throw new core::NoSuchMethodError::•(null, #z, <dynamic>["Hello, World!"], <dynamic, dynamic>{}, null);
+  (throw new core::NoSuchMethodError::•(null, #z, <dynamic>[], <dynamic, dynamic>{}, null)).print("Hello, World!");
+  (throw new core::NoSuchMethodError::•(null, #y, <dynamic>[], <dynamic, dynamic>{}, null)).z.print("Hello, World!");
+  (throw new core::NoSuchMethodError::•(null, #x, <dynamic>[], <dynamic, dynamic>{}, null)).y.z.print("Hello, World!");
+  1.+(core::print("Hello, World!")).+(throw new core::NoSuchMethodError::•(null, #z, <dynamic>["Hello, World!"], <dynamic, dynamic>{}, null)).+((throw new core::NoSuchMethodError::•(null, #z, <dynamic>[], <dynamic, dynamic>{}, null)).print("Hello, World!")).+((throw new core::NoSuchMethodError::•(null, #y, <dynamic>[], <dynamic, dynamic>{}, null)).z.print("Hello, World!")).+((throw new core::NoSuchMethodError::•(null, #x, <dynamic>[], <dynamic, dynamic>{}, null)).y.z.print("Hello, World!"));
+}
diff --git a/pkg/front_end/test/fasta/invocations.dart.direct.expect b/pkg/front_end/test/fasta/invocations.dart.direct.expect
new file mode 100644
index 0000000..89ed30f
--- /dev/null
+++ b/pkg/front_end/test/fasta/invocations.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("Hello, World!");
+  throw new core::NoSuchMethodError::•(null, #z, <dynamic>["Hello, World!"], <dynamic, dynamic>{}, null);
+  (throw new core::NoSuchMethodError::•(null, #z, <dynamic>[], <dynamic, dynamic>{}, null)).print("Hello, World!");
+  (throw new core::NoSuchMethodError::•(null, #y, <dynamic>[], <dynamic, dynamic>{}, null)).z.print("Hello, World!");
+  (throw new core::NoSuchMethodError::•(null, #x, <dynamic>[], <dynamic, dynamic>{}, null)).y.z.print("Hello, World!");
+  1.+(core::print("Hello, World!")).+(throw new core::NoSuchMethodError::•(null, #z, <dynamic>["Hello, World!"], <dynamic, dynamic>{}, null)).+((throw new core::NoSuchMethodError::•(null, #z, <dynamic>[], <dynamic, dynamic>{}, null)).print("Hello, World!")).+((throw new core::NoSuchMethodError::•(null, #y, <dynamic>[], <dynamic, dynamic>{}, null)).z.print("Hello, World!")).+((throw new core::NoSuchMethodError::•(null, #x, <dynamic>[], <dynamic, dynamic>{}, null)).y.z.print("Hello, World!"));
+}
diff --git a/pkg/front_end/test/fasta/invocations.dart.outline.expect b/pkg/front_end/test/fasta/invocations.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/invocations.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/kompile.status b/pkg/front_end/test/fasta/kompile.status
new file mode 100644
index 0000000..9d5ce12
--- /dev/null
+++ b/pkg/front_end/test/fasta/kompile.status
@@ -0,0 +1,110 @@
+# 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.
+
+# Status file for the kompile_test.dart (notice k, not c) test suite. This is
+# testing generating Analyzer ASTs, that is, code in
+# pkg/fasta/lib/src/analyzer/. Currently, this is behind direct-to-kernel, so
+# there are many crashes.
+
+accessors: Crash
+await: Fail
+classes: Crash
+cycles: Crash
+default_values: Crash
+expressions: Crash
+fibonacci: Crash
+for_in_scope: Crash
+functions: Crash
+implicit_this: Crash
+invocations: Fail
+map: Crash
+mixin: Crash
+operators: Crash
+statements: Crash
+top_level_accessors: Crash
+typedef: Crash
+
+rasta/abstract_constructor: Crash
+rasta/bad_constructor_redirection: Crash
+rasta/bad_continue: Crash
+rasta/bad_default_constructor: Crash
+rasta/bad_explicit_super_constructor: Crash
+rasta/bad_implicit_super_constructor: Crash
+rasta/bad_interpolation: Fail
+rasta/bad_redirection: Fail
+rasta/bad_setter_initializer: Crash
+rasta/bad_unicode: Fail
+rasta/breaking_bad: Crash
+rasta/cascades: Crash
+rasta/class_hierarchy: Fail
+rasta/class_member: Crash
+rasta/constant_get_and_invoke: Crash
+rasta/deferred_lib: Fail
+rasta/deferred_load: Crash
+rasta/duplicated_mixin: Crash
+rasta/export: Fail
+rasta/external_factory_redirection: Crash
+rasta/foo: Fail
+rasta/for_loop: Crash
+rasta/generic_factory: Crash
+rasta/issue_000001: Crash
+rasta/issue_000002: Crash
+rasta/issue_000004: Crash
+rasta/issue_000006: Crash
+rasta/issue_000007: Crash
+rasta/issue_000008: Crash
+rasta/issue_000011: Crash
+rasta/issue_000012: Crash
+rasta/issue_000025: Crash
+rasta/issue_000026: Crash
+rasta/issue_000031: Crash
+rasta/issue_000032: Fail
+rasta/issue_000034: Crash
+rasta/issue_000035: Crash
+rasta/issue_000035a: Fail
+rasta/issue_000036: Fail
+rasta/issue_000039: Crash
+rasta/issue_000041: Crash
+rasta/issue_000042: Crash
+rasta/issue_000043: Fail
+rasta/issue_000044: Fail
+rasta/issue_000045: Fail
+rasta/issue_000046: Fail
+rasta/issue_000047: Fail
+rasta/issue_000048: Crash
+rasta/issue_000052: Crash
+rasta/issue_000053: Crash
+rasta/issue_000067: Crash
+rasta/issue_000068: Crash
+rasta/issue_000069: Crash
+rasta/issue_000070: Crash
+rasta/issue_000080: Crash
+rasta/issue_000081: Crash
+rasta/malformed_const_constructor: Fail
+rasta/malformed_function: Fail
+rasta/malformed_function_type: Crash
+rasta/mandatory_parameter_initializer: Fail
+rasta/mixin_library: Crash
+rasta/native_is_illegal: Fail
+rasta/parser_error: Crash
+rasta/previsit_deferred: Crash
+rasta/static: Crash
+rasta/super: Crash
+rasta/super: Fail
+rasta/super_initializer: Crash
+rasta/super_mixin: Crash
+rasta/super_operator: Crash
+rasta/supports_reflection: Crash
+rasta/switch_execution_case_t02: Crash
+rasta/switch_fall_through: Crash
+rasta/this_invoke: Crash
+rasta/try_label: Crash
+rasta/type_literals: Crash
+rasta/type_with_parse_error: Fail
+rasta/typedef: Crash
+rasta/unresolved: Crash
+rasta/unresolved_constructor: Crash
+rasta/unresolved_for_in: Crash
+rasta/unresolved_recovery: Crash
+rasta/unsupported_platform_library: Fail
diff --git a/pkg/front_end/test/fasta/kompile_test.dart b/pkg/front_end/test/fasta/kompile_test.dart
new file mode 100644
index 0000000..34175ad
--- /dev/null
+++ b/pkg/front_end/test/fasta/kompile_test.dart
@@ -0,0 +1,19 @@
+// 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.
+
+library fasta.test.compile_test;
+
+import 'dart:async' show
+    Future;
+
+import 'package:front_end/src/fasta/testing/suite.dart';
+
+Future<FeContext> createContext(
+    Chain suite, Map<String, String> environment) {
+  environment[ENABLE_FULL_COMPILE] = "";
+  environment[AST_KIND_INDEX] = "${AstKind.Analyzer.index}";
+  return TestContext.create(suite, environment, FeContext.create);
+}
+
+main(List<String> arguments) => runMe(arguments, createContext, "testing.json");
diff --git a/pkg/front_end/test/fasta/language.status b/pkg/front_end/test/fasta/language.status
new file mode 100644
index 0000000..a5db2dc
--- /dev/null
+++ b/pkg/front_end/test/fasta/language.status
@@ -0,0 +1,909 @@
+# 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.
+
+const_constructor_syntax_test/01_generated: VerificationError
+const_constructor_syntax_test/02_generated: VerificationError
+const_constructor_syntax_test/03_generated: VerificationError
+const_constructor_test/01_generated: VerificationError
+const_factory_with_body_test/01_generated: VerificationError
+generic_constructor_mixin2_test: VerificationError
+generic_constructor_mixin3_test: VerificationError
+generic_constructor_mixin_test: VerificationError
+
+abstract_beats_arguments_test: Fail
+abstract_exact_selector_test/01_generated: Fail
+abstract_exact_selector_test/none_generated: Fail
+abstract_runtime_error_test/01_generated: Fail
+abstract_runtime_error_test/02_generated: Fail
+accessor_conflict_export2_test: Fail
+accessor_conflict_export_test: Fail
+accessor_conflict_import2_test: Fail
+assertion_test: Fail
+async_and_or_test: Fail
+async_await_catch_regression_test: Fail
+async_await_syntax_test/a05a_generated: Fail
+async_await_syntax_test/a05b_generated: Fail
+async_await_syntax_test/a06a_generated: Fail
+async_await_syntax_test/a07a_generated: Fail
+async_await_syntax_test/a08a_generated: Fail
+async_await_syntax_test/a09a_generated: Fail
+async_await_syntax_test/a10a_generated: Fail
+async_await_syntax_test/b05a_generated: Fail
+async_await_syntax_test/b06a_generated: Fail
+async_await_syntax_test/b07a_generated: Fail
+async_await_syntax_test/b08a_generated: Fail
+async_await_syntax_test/b09a_generated: Fail
+async_await_syntax_test/b10a_generated: Fail
+async_await_syntax_test/c05a_generated: Fail
+async_await_syntax_test/c06a_generated: Fail
+async_await_syntax_test/c07a_generated: Fail
+async_await_syntax_test/c08a_generated: Fail
+async_await_syntax_test/c09a_generated: Fail
+async_await_syntax_test/c10a_generated: Fail
+async_await_syntax_test/d05a_generated: Fail
+async_await_syntax_test/d06a_generated: Fail
+async_await_syntax_test/d07a_generated: Fail
+async_await_syntax_test/d08a_generated: Fail
+async_await_syntax_test/d08b_generated: Fail
+async_await_syntax_test/d09a_generated: Fail
+async_await_syntax_test/d10a_generated: Fail
+async_await_test: Fail
+async_break_in_finally_test: Fail
+async_continue_label_test/await_in_body_generated: Fail
+async_continue_label_test/await_in_condition_generated: Fail
+async_continue_label_test/await_in_init_generated: Fail
+async_continue_label_test/await_in_update_generated: Fail
+async_continue_label_test/none_generated: Fail
+async_control_structures_test: Fail
+async_finally_rethrow_test: Fail
+async_regression_23058_test: Fail
+async_rethrow_test: Fail
+async_return_types_test/nestedFuture_generated: Fail
+async_return_types_test/none_generated: Fail
+async_return_types_test/tooManyTypeParameters_generated: Fail
+async_return_types_test/wrongReturnType_generated: Fail
+async_return_types_test/wrongTypeParameter_generated: Fail
+async_star_cancel_and_throw_in_finally_test: Fail
+async_star_cancel_while_paused_test: Fail
+async_star_no_cancel2_test: Fail
+async_star_no_cancel_test: Fail
+async_star_pause_test: Fail
+async_star_regression_2238_test: Fail
+async_star_regression_23116_test: Fail
+async_star_regression_fisk_test: Fail
+async_star_stream_take_test: Fail
+async_star_take_reyield_test: Fail
+async_star_test: Fail
+async_test/none_generated: Fail
+async_test/type-mismatch1_generated: Fail
+async_test/type-mismatch2_generated: Fail
+async_test/type-mismatch3_generated: Fail
+async_test/type-mismatch4_generated: Fail
+async_this_bound_test: Fail
+async_throw_in_catch_test/forceAwait_generated: Fail
+async_throw_in_catch_test/none_generated: Fail
+asyncstar_concat_test: Fail
+asyncstar_throw_in_catch_test: Fail
+asyncstar_yield_test: Fail
+asyncstar_yieldstar_test: Fail
+await_backwards_compatibility_test/none_generated: Fail
+await_exceptions_test: Fail
+await_for_cancel_test: Fail
+await_for_test: Fail
+await_for_use_local_test: Fail
+await_future_test: Fail
+await_nonfuture_test: Fail
+await_not_started_immediately_test: Fail
+await_null_aware_test: Fail
+await_postfix_expr_test: Fail
+await_regression_test: Fail
+await_test: Fail
+built_in_identifier_test/01_generated: Fail
+call_nonexistent_static_test/01_generated: Fail
+call_nonexistent_static_test/04_generated: Fail
+call_nonexistent_static_test/06_generated: Fail
+cha_deopt1_test: Fail
+cha_deopt2_test: Fail
+cha_deopt3_test: Fail
+closure_type_variable_test: Fail
+closures_initializer_test: Fail
+compile_time_constant12_test: Fail
+compile_time_constant_k_test/01_generated: Fail
+compile_time_constant_k_test/02_generated: Fail
+compile_time_constant_k_test/03_generated: Fail
+compile_time_constant_o_test/01_generated: Fail
+compile_time_constant_o_test/02_generated: Fail
+conditional_import_string_test: Fail
+conditional_import_test: Fail
+conditional_method_invocation_test/01_generated: Fail
+conditional_method_invocation_test/02_generated: Fail
+conditional_method_invocation_test/03_generated: Fail
+conditional_method_invocation_test/04_generated: Fail
+conditional_method_invocation_test/05_generated: Fail
+conditional_method_invocation_test/06_generated: Fail
+conditional_method_invocation_test/07_generated: Fail
+conditional_method_invocation_test/08_generated: Fail
+conditional_method_invocation_test/12_generated: Fail
+conditional_method_invocation_test/13_generated: Fail
+conditional_method_invocation_test/14_generated: Fail
+conditional_method_invocation_test/15_generated: Fail
+conditional_method_invocation_test/16_generated: Fail
+conditional_method_invocation_test/17_generated: Fail
+conditional_method_invocation_test/18_generated: Fail
+conditional_method_invocation_test/19_generated: Fail
+conditional_method_invocation_test/none_generated: Fail
+conditional_property_access_test/01_generated: Fail
+conditional_property_access_test/02_generated: Fail
+conditional_property_access_test/03_generated: Fail
+conditional_property_access_test/04_generated: Fail
+conditional_property_access_test/05_generated: Fail
+conditional_property_access_test/06_generated: Fail
+conditional_property_access_test/10_generated: Fail
+conditional_property_access_test/11_generated: Fail
+conditional_property_access_test/12_generated: Fail
+conditional_property_access_test/13_generated: Fail
+conditional_property_access_test/14_generated: Fail
+conditional_property_access_test/15_generated: Fail
+conditional_property_access_test/16_generated: Fail
+conditional_property_access_test/17_generated: Fail
+conditional_property_access_test/none_generated: Fail
+conditional_property_assignment_test/01_generated: Fail
+conditional_property_assignment_test/02_generated: Fail
+conditional_property_assignment_test/03_generated: Fail
+conditional_property_assignment_test/04_generated: Fail
+conditional_property_assignment_test/05_generated: Fail
+conditional_property_assignment_test/06_generated: Fail
+conditional_property_assignment_test/07_generated: Fail
+conditional_property_assignment_test/08_generated: Fail
+conditional_property_assignment_test/09_generated: Fail
+conditional_property_assignment_test/10_generated: Fail
+conditional_property_assignment_test/11_generated: Fail
+conditional_property_assignment_test/12_generated: Fail
+conditional_property_assignment_test/13_generated: Fail
+conditional_property_assignment_test/23_generated: Fail
+conditional_property_assignment_test/24_generated: Fail
+conditional_property_assignment_test/25_generated: Fail
+conditional_property_assignment_test/26_generated: Fail
+conditional_property_assignment_test/27_generated: Fail
+conditional_property_assignment_test/28_generated: Fail
+conditional_property_assignment_test/29_generated: Fail
+conditional_property_assignment_test/30_generated: Fail
+conditional_property_assignment_test/31_generated: Fail
+conditional_property_assignment_test/32_generated: Fail
+conditional_property_assignment_test/33_generated: Fail
+conditional_property_assignment_test/34_generated: Fail
+conditional_property_assignment_test/35_generated: Fail
+conditional_property_assignment_test/none_generated: Fail
+conditional_property_increment_decrement_test/01_generated: Fail
+conditional_property_increment_decrement_test/02_generated: Fail
+conditional_property_increment_decrement_test/03_generated: Fail
+conditional_property_increment_decrement_test/04_generated: Fail
+conditional_property_increment_decrement_test/05_generated: Fail
+conditional_property_increment_decrement_test/06_generated: Fail
+conditional_property_increment_decrement_test/07_generated: Fail
+conditional_property_increment_decrement_test/08_generated: Fail
+conditional_property_increment_decrement_test/09_generated: Fail
+conditional_property_increment_decrement_test/10_generated: Fail
+conditional_property_increment_decrement_test/11_generated: Fail
+conditional_property_increment_decrement_test/12_generated: Fail
+conditional_property_increment_decrement_test/13_generated: Fail
+conditional_property_increment_decrement_test/14_generated: Fail
+conditional_property_increment_decrement_test/15_generated: Fail
+conditional_property_increment_decrement_test/16_generated: Fail
+conditional_property_increment_decrement_test/17_generated: Fail
+conditional_property_increment_decrement_test/18_generated: Fail
+conditional_property_increment_decrement_test/19_generated: Fail
+conditional_property_increment_decrement_test/20_generated: Fail
+conditional_property_increment_decrement_test/21_generated: Fail
+conditional_property_increment_decrement_test/22_generated: Fail
+conditional_property_increment_decrement_test/23_generated: Fail
+conditional_property_increment_decrement_test/24_generated: Fail
+conditional_property_increment_decrement_test/25_generated: Fail
+conditional_property_increment_decrement_test/26_generated: Fail
+conditional_property_increment_decrement_test/27_generated: Fail
+conditional_property_increment_decrement_test/28_generated: Fail
+conditional_property_increment_decrement_test/29_generated: Fail
+conditional_property_increment_decrement_test/30_generated: Fail
+conditional_property_increment_decrement_test/31_generated: Fail
+conditional_property_increment_decrement_test/32_generated: Fail
+conditional_property_increment_decrement_test/33_generated: Fail
+conditional_property_increment_decrement_test/34_generated: Fail
+conditional_property_increment_decrement_test/35_generated: Fail
+conditional_property_increment_decrement_test/36_generated: Fail
+conditional_property_increment_decrement_test/37_generated: Fail
+conditional_property_increment_decrement_test/38_generated: Fail
+conditional_property_increment_decrement_test/39_generated: Fail
+conditional_property_increment_decrement_test/40_generated: Fail
+conditional_property_increment_decrement_test/none_generated: Fail
+config_import_corelib_test: Fail
+config_import_test: Fail
+const_dynamic_type_literal_test/02_generated: Fail
+const_error_multiply_initialized_test/02_generated: Fail
+const_error_multiply_initialized_test/04_generated: Fail
+const_evaluation_test/01_generated: Fail
+const_locals_test: Fail
+const_nested_test: Fail
+const_optional_args_negative_test: Fail
+const_string_test: Fail
+constructor2_test: Fail
+constructor3_test: Fail
+constructor5_test: Fail
+constructor6_test: Fail
+crash_6725_test/01_generated: Fail
+custom_await_stack_trace_test: Fail
+cyclic_type2_test: Fail
+cyclic_type_test/00_generated: Fail
+cyclic_type_test/01_generated: Fail
+cyclic_type_test/02_generated: Fail
+cyclic_type_test/03_generated: Fail
+cyclic_type_test/04_generated: Fail
+default_class_implicit_constructor_test: Fail
+deferred_call_empty_before_load_test: Fail
+deferred_closurize_load_library_test: Fail
+deferred_constant_list_test: Fail
+deferred_constraints_constants_test/none_generated: Fail
+deferred_constraints_constants_test/reference_after_load_generated: Fail
+deferred_constraints_type_annotation_test/as_operation_generated: Fail
+deferred_constraints_type_annotation_test/catch_check_generated: Fail
+deferred_constraints_type_annotation_test/is_check_generated: Fail
+deferred_constraints_type_annotation_test/new_before_load_generated: Fail
+deferred_constraints_type_annotation_test/new_generated: Fail
+deferred_constraints_type_annotation_test/new_generic1_generated: Fail
+deferred_constraints_type_annotation_test/new_generic2_generated: Fail
+deferred_constraints_type_annotation_test/new_generic3_generated: Fail
+deferred_constraints_type_annotation_test/none_generated: Fail
+deferred_constraints_type_annotation_test/static_method_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation1_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_generic1_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_generic2_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_generic3_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_generic4_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_non_deferred_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_null_generated: Fail
+deferred_constraints_type_annotation_test/type_annotation_top_level_generated: Fail
+deferred_duplicate_prefix1_test/none_generated: Fail
+deferred_duplicate_prefix2_test/none_generated: Fail
+deferred_function_type_test: Fail
+deferred_global_test: Fail
+deferred_import_core_test: Fail
+deferred_inheritance_constraints_test/none_generated: Fail
+deferred_inheritance_constraints_test/redirecting_constructor_generated: Fail
+deferred_inlined_test: Fail
+deferred_load_constants_test/none_generated: Fail
+deferred_load_inval_code_test: Fail
+deferred_load_library_wrong_args_test/none_generated: Fail
+deferred_mixin_test: Fail
+deferred_no_prefix_test/none_generated: Fail
+deferred_no_such_method_test: Fail
+deferred_not_loaded_check_test: Fail
+deferred_only_constant_test: Fail
+deferred_optimized_test: Fail
+deferred_redirecting_factory_test: Fail
+deferred_regression_22995_test: Fail
+deferred_shadow_load_library_test: Fail
+deferred_shared_and_unshared_classes_test: Fail
+deferred_static_seperate_test: Fail
+deferred_super_dependency_test/01_generated: Fail
+duplicate_export_negative_test: Fail
+duplicate_interface_negative_test/none_generated: Fail
+dynamic_prefix_core_test/01_generated: Fail
+dynamic_test: Fail
+enum_duplicate_test/01_generated: Fail
+enum_duplicate_test/02_generated: Fail
+enum_private_test/01_generated: Fail
+enum_private_test/02_generated: Fail
+enum_private_test/none_generated: Fail
+enum_test: Fail
+evaluation_redirecting_constructor_test: Fail
+example_constructor_test: Fail
+export_double_same_main_test: Fail
+export_main_test: Fail
+f_bounded_equality_test: Fail
+field_initialization_order_test: Fail
+final_field_initialization_order_test: Fail
+final_super_field_set_test/01_generated: Fail
+first_class_types_literals_test/08_generated: Fail
+fixed_type_variable2_test/02_generated: Fail
+fixed_type_variable2_test/04_generated: Fail
+fixed_type_variable2_test/06_generated: Fail
+fixed_type_variable_test/01_generated: Fail
+fixed_type_variable_test/02_generated: Fail
+fixed_type_variable_test/03_generated: Fail
+fixed_type_variable_test/04_generated: Fail
+fixed_type_variable_test/05_generated: Fail
+fixed_type_variable_test/06_generated: Fail
+for2_test: Fail
+for_variable_capture_test: Fail
+function_propagation_test: Fail
+function_subtype0_test: Fail
+function_subtype1_test: Fail
+function_subtype2_test: Fail
+function_subtype3_test: Fail
+function_subtype_bound_closure0_test: Fail
+function_subtype_bound_closure1_test: Fail
+function_subtype_bound_closure2_test: Fail
+function_subtype_bound_closure3_test: Fail
+function_subtype_bound_closure4_test: Fail
+function_subtype_bound_closure5_test: Fail
+function_subtype_bound_closure5a_test: Fail
+function_subtype_bound_closure6_test: Fail
+function_subtype_bound_closure7_test: Fail
+function_subtype_call0_test: Fail
+function_subtype_call1_test: Fail
+function_subtype_call2_test: Fail
+function_subtype_cast0_test: Fail
+function_subtype_cast1_test: Fail
+function_subtype_cast2_test: Fail
+function_subtype_cast3_test: Fail
+function_subtype_factory0_test: Fail
+function_subtype_inline0_test: Fail
+function_subtype_local0_test: Fail
+function_subtype_local1_test: Fail
+function_subtype_local2_test: Fail
+function_subtype_local3_test: Fail
+function_subtype_local4_test: Fail
+function_subtype_local5_test: Fail
+function_subtype_named1_test: Fail
+function_subtype_named2_test: Fail
+function_subtype_not0_test: Fail
+function_subtype_not1_test: Fail
+function_subtype_not2_test: Fail
+function_subtype_not3_test: Fail
+function_subtype_optional1_test: Fail
+function_subtype_optional2_test: Fail
+function_subtype_simple0_test: Fail
+function_subtype_simple1_test: Fail
+function_subtype_simple2_test: Fail
+function_subtype_top_level0_test: Fail
+function_subtype_top_level1_test: Fail
+function_type3_test: Fail
+function_type_alias2_test: Fail
+function_type_alias3_test: Fail
+function_type_alias4_test: Fail
+function_type_alias6_test/none_generated: Fail
+function_type_alias_test: Fail
+generic2_test: Fail
+generic_closure_test: Fail
+generic_creation_test: Fail
+generic_field_mixin2_test: Fail
+generic_field_mixin3_test: Fail
+generic_field_mixin4_test: Fail
+generic_field_mixin5_test: Fail
+generic_field_mixin_test: Fail
+generic_functions_test/none_generated: Fail
+generic_inheritance_test: Fail
+generic_local_functions_test/none_generated: Fail
+generic_method_types_test/01_generated: Fail
+generic_method_types_test/02_generated: Fail
+generic_method_types_test/03_generated: Fail
+generic_method_types_test/none_generated: Fail
+generic_methods_function_type_test/none_generated: Fail
+generic_methods_generic_function_parameter_test: Fail
+generic_methods_new_test/none_generated: Fail
+generic_methods_test/none_generated: Fail
+generic_methods_type_expression_test/none_generated: Fail
+generic_sends_test/none_generated: Fail
+generic_test: Fail
+getter_closure_execution_order_test: Fail
+getter_declaration_negative_test: Fail
+getter_setter_in_lib_test: Fail
+hidden_import_test/01_generated: Fail
+hidden_import_test/02_generated: Fail
+hidden_import_test/none_generated: Fail
+if_null_assignment_behavior_test/01_generated: Fail
+if_null_assignment_behavior_test/02_generated: Fail
+if_null_assignment_behavior_test/03_generated: Fail
+if_null_assignment_behavior_test/04_generated: Fail
+if_null_assignment_behavior_test/05_generated: Fail
+if_null_assignment_behavior_test/06_generated: Fail
+if_null_assignment_behavior_test/07_generated: Fail
+if_null_assignment_behavior_test/08_generated: Fail
+if_null_assignment_behavior_test/09_generated: Fail
+if_null_assignment_behavior_test/10_generated: Fail
+if_null_assignment_behavior_test/11_generated: Fail
+if_null_assignment_behavior_test/12_generated: Fail
+if_null_assignment_behavior_test/13_generated: Fail
+if_null_assignment_behavior_test/14_generated: Fail
+if_null_assignment_behavior_test/15_generated: Fail
+if_null_assignment_behavior_test/16_generated: Fail
+if_null_assignment_behavior_test/17_generated: Fail
+if_null_assignment_behavior_test/18_generated: Fail
+if_null_assignment_behavior_test/19_generated: Fail
+if_null_assignment_behavior_test/20_generated: Fail
+if_null_assignment_behavior_test/21_generated: Fail
+if_null_assignment_behavior_test/22_generated: Fail
+if_null_assignment_behavior_test/23_generated: Fail
+if_null_assignment_behavior_test/24_generated: Fail
+if_null_assignment_behavior_test/25_generated: Fail
+if_null_assignment_behavior_test/26_generated: Fail
+if_null_assignment_behavior_test/27_generated: Fail
+if_null_assignment_behavior_test/28_generated: Fail
+if_null_assignment_behavior_test/31_generated: Fail
+if_null_assignment_behavior_test/32_generated: Fail
+if_null_assignment_behavior_test/none_generated: Fail
+implicit_scope_test: Fail
+import_combinators_test: Fail
+import_self_test/01_generated: Fail
+initializing_formal_capture_test: Fail
+initializing_formal_final_test: Fail
+inst_field_initializer1_negative_test: Fail
+instance_creation_in_function_annotation_test: Fail
+instanceof3_test: Fail
+invocation_mirror_test: Fail
+is_malformed_type_test/94_generated: Fail
+is_malformed_type_test/95_generated: Fail
+is_malformed_type_test/96_generated: Fail
+is_malformed_type_test/97_generated: Fail
+is_malformed_type_test/98_generated: Fail
+is_malformed_type_test/99_generated: Fail
+is_not_class2_test: Fail
+isnot_malformed_type_test: Fail
+issue13474_test: Fail
+issue1363_test/none_generated: Fail
+issue14014_3_test: Fail
+issue23244_test: Fail
+issue_1751477_test: Fail
+label6_negative_test: Fail
+label_test: Fail
+least_upper_bound_expansive_test/01_generated: Fail
+least_upper_bound_expansive_test/02_generated: Fail
+least_upper_bound_expansive_test/03_generated: Fail
+least_upper_bound_expansive_test/04_generated: Fail
+least_upper_bound_expansive_test/05_generated: Fail
+least_upper_bound_expansive_test/06_generated: Fail
+least_upper_bound_expansive_test/07_generated: Fail
+least_upper_bound_expansive_test/08_generated: Fail
+least_upper_bound_expansive_test/09_generated: Fail
+least_upper_bound_expansive_test/10_generated: Fail
+least_upper_bound_expansive_test/11_generated: Fail
+least_upper_bound_expansive_test/12_generated: Fail
+least_upper_bound_expansive_test/none_generated: Fail
+library_ambiguous_test/none_generated: Fail
+library_env_test/has_html_support_generated: Fail
+library_env_test/has_no_io_support_generated: Fail
+library_env_test/has_no_mirror_support_generated: Fail
+list_literal2_negative_test: Fail
+list_literal4_test: Fail
+malbounded_redirecting_factory2_test/01_generated: Fail
+malbounded_redirecting_factory2_test/02_generated: Fail
+malbounded_redirecting_factory2_test/03_generated: Fail
+malbounded_redirecting_factory2_test/04_generated: Fail
+malbounded_redirecting_factory2_test/none_generated: Fail
+malbounded_redirecting_factory_test/01_generated: Fail
+malbounded_redirecting_factory_test/02_generated: Fail
+malbounded_redirecting_factory_test/03_generated: Fail
+malbounded_redirecting_factory_test/04_generated: Fail
+malbounded_redirecting_factory_test/none_generated: Fail
+malformed2_test/00_generated: Fail
+malformed_test/none_generated: Fail
+map_literal2_negative_test: Fail
+map_literal3_test/none_generated: Fail
+map_literal4_test: Fail
+map_literal6_test: Fail
+metadata_test: Fail
+method_name_test: Fail
+method_override_test: Fail
+mixin_generic_test: Fail
+mixin_issue10216_2_test: Fail
+mixin_mixin2_test: Fail
+mixin_mixin3_test: Fail
+mixin_mixin4_test: Fail
+mixin_mixin5_test: Fail
+mixin_mixin6_test: Fail
+mixin_mixin7_test: Fail
+mixin_mixin_bound2_test: Fail
+mixin_mixin_bound_test: Fail
+mixin_mixin_test: Fail
+mixin_regress_13688_test: Fail
+mixin_super_test: Fail
+mixin_type_parameter1_test: Fail
+mixin_type_parameter2_test: Fail
+mixin_type_parameter3_test: Fail
+mixin_type_parameters_mixin_extends_test: Fail
+mixin_type_parameters_mixin_test: Fail
+mixin_type_parameters_simple_test: Fail
+mixin_type_parameters_super_extends_test: Fail
+mixin_type_parameters_super_test: Fail
+multiline_newline_test/01_generated: Fail
+multiline_newline_test/02_generated: Fail
+multiline_newline_test/03_generated: Fail
+multiline_newline_test/none_generated: Fail
+named_constructor_test/none_generated: Fail
+named_parameters_test/none_generated: Fail
+null_test/none_generated: Fail
+on_catch_malformed_type_test: Fail
+parameter_initializer5_negative_test: Fail
+parameter_initializer6_negative_test: Fail
+part2_test: Fail
+prefix16_test: Fail
+prefix22_test/none_generated: Fail
+prefix23_test/none_generated: Fail
+prefix_assignment_test/none_generated: Fail
+prefix_identifier_reference_test/none_generated: Fail
+prefix_unqualified_invocation_test/none_generated: Fail
+private_access_test/01_generated: Fail
+private_access_test/02_generated: Fail
+private_access_test/03_generated: Fail
+private_access_test/04_generated: Fail
+private_access_test/05_generated: Fail
+private_access_test/06_generated: Fail
+private_access_test/none_generated: Fail
+private_super_constructor_test/none_generated: Fail
+redirecting_constructor_initializer_test: Fail
+redirecting_factory_infinite_steps_test/01_generated: Fail
+redirecting_factory_long_test: Fail
+redirecting_factory_reflection_test: Fail
+regress_13494_test: Fail
+regress_18713_test: Fail
+regress_19413_test/none_generated: Fail
+regress_20394_test/none_generated: Fail
+regress_22438_test: Fail
+regress_22443_test: Fail
+regress_22445_test: Fail
+regress_22579_test: Fail
+regress_22700_test: Fail
+regress_22777_test: Fail
+regress_23408_test: Fail
+regress_23498_test: Fail
+regress_23500_test/01_generated: Fail
+regress_23500_test/02_generated: Fail
+regress_23500_test/none_generated: Fail
+regress_24567_test: Fail
+regress_24935_test/none_generated: Fail
+regress_26133_test: Fail
+regress_26175_test: Fail
+regress_26668_test: Fail
+regress_26948_test: Fail
+regress_27164_test: Fail
+regress_27957_test: Fail
+regress_r24720_test: Fail
+reify_typevar_test: Fail
+script1_negative_test: Fail
+script2_negative_test: Fail
+setter0_test: Fail
+setter4_test: Fail
+setter_declaration2_negative_test: Fail
+setter_declaration_negative_test: Fail
+setter_override_test/01_generated: Fail
+setter_override_test/02_generated: Fail
+setter_override_test/none_generated: Fail
+source_self_negative_test: Fail
+super_call4_test: Fail
+super_getter_setter_test: Fail
+super_no_such_method1_test/01_generated: Fail
+super_no_such_method2_test/01_generated: Fail
+super_no_such_method3_test/01_generated: Fail
+super_no_such_method4_test/01_generated: Fail
+super_no_such_method5_test/01_generated: Fail
+super_operator_index2_test: Fail
+super_operator_index3_test: Fail
+super_operator_index4_test: Fail
+super_operator_index5_test: Fail
+super_operator_index6_test: Fail
+super_operator_index7_test: Fail
+super_operator_index8_test: Fail
+super_operator_index_test/none_generated: Fail
+super_operator_test: Fail
+super_test: Fail
+switch1_negative_test: Fail
+switch4_negative_test: Fail
+switch_label_test: Fail
+switch_try_catch_test: Fail
+sync_generator1_test/01_generated: Fail
+sync_generator1_test/none_generated: Fail
+sync_generator2_test/none_generated: Fail
+sync_generator3_test/test1_generated: Fail
+sync_generator3_test/test2_generated: Fail
+syncstar_less_than_test: Fail
+syncstar_yield_test/copyParameters_generated: Fail
+syncstar_yield_test/none_generated: Fail
+syncstar_yieldstar_test: Fail
+tearoff_basic_test: Fail
+tearoff_constructor_basic_test: Fail
+top_level_non_prefixed_library_test: Fail
+try_finally_regress_25654_test: Fail
+type_checks_in_factory_method_test: Fail
+type_parameter_literal_test: Fail
+type_variable_conflict2_test/01_generated: Fail
+type_variable_function_type_test: Fail
+type_variable_typedef_test: Fail
+typedef_is_test: Fail
+typevariable_substitution2_test/01_generated: Fail
+typevariable_substitution2_test/02_generated: Fail
+typevariable_substitution2_test/none_generated: Fail
+vm/debug_break_enabled_vm_test/01_generated: Fail
+vm/debug_break_enabled_vm_test/none_generated: Fail
+vm/optimized_await_regress_test: Fail
+vm/regress_27201_test: Fail
+vm/type_cast_vm_test: Fail
+vm/type_vm_test: Fail
+yieldstar_pause_test: Fail
+
+constructor_duplicate_final_test/01_generated: MissingRuntimeError
+constructor_duplicate_final_test/02_generated: MissingRuntimeError
+external_test/13_generated: MissingRuntimeError
+external_test/20_generated: MissingRuntimeError
+flatten_test/04_generated: MissingRuntimeError
+flatten_test/08_generated: MissingRuntimeError
+flatten_test/12_generated: MissingRuntimeError
+named_parameters_type_test/01_generated: MissingRuntimeError
+named_parameters_type_test/02_generated: MissingRuntimeError
+named_parameters_type_test/03_generated: MissingRuntimeError
+not_enough_positional_arguments_test/02_generated: MissingRuntimeError
+not_enough_positional_arguments_test/05_generated: MissingRuntimeError
+positional_parameters_type_test/01_generated: MissingRuntimeError
+positional_parameters_type_test/02_generated: MissingRuntimeError
+try_catch_on_syntax_test/10_generated: MissingRuntimeError
+try_catch_on_syntax_test/11_generated: MissingRuntimeError
+
+assignable_expression_test/50_generated: MissingCompileTimeError
+async_await_syntax_test/a01b_generated: MissingCompileTimeError
+async_await_syntax_test/a01c_generated: MissingCompileTimeError
+async_await_syntax_test/a12e_generated: MissingCompileTimeError
+async_await_syntax_test/a12f_generated: MissingCompileTimeError
+async_await_syntax_test/b00a_generated: MissingCompileTimeError
+async_await_syntax_test/b00b_generated: MissingCompileTimeError
+async_await_syntax_test/b00c_generated: MissingCompileTimeError
+async_await_syntax_test/b01b_generated: MissingCompileTimeError
+async_await_syntax_test/b01c_generated: MissingCompileTimeError
+async_await_syntax_test/b12e_generated: MissingCompileTimeError
+async_await_syntax_test/b12f_generated: MissingCompileTimeError
+async_await_syntax_test/c01b_generated: MissingCompileTimeError
+async_await_syntax_test/c01c_generated: MissingCompileTimeError
+async_await_syntax_test/d01b_generated: MissingCompileTimeError
+async_await_syntax_test/d01c_generated: MissingCompileTimeError
+async_await_syntax_test/e1_generated: MissingCompileTimeError
+async_await_syntax_test/e2_generated: MissingCompileTimeError
+async_await_syntax_test/e3_generated: MissingCompileTimeError
+black_listed_test/13_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/01_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/04_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/05_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/06_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/07_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/08_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/10_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/12_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/13_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/15_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/16_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/17_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/18_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/19_generated: MissingCompileTimeError
+built_in_identifier_illegal_test/20_generated: MissingCompileTimeError
+class_cycle2_test/01_generated: MissingCompileTimeError
+class_cycle2_test/02_generated: MissingCompileTimeError
+class_cycle_test/00_generated: MissingCompileTimeError
+class_cycle_test/01_generated: MissingCompileTimeError
+compile_time_constant13_test/03_generated: MissingCompileTimeError
+compile_time_constant_c_test/02_generated: MissingCompileTimeError
+compile_time_constant_c_test/03_generated: MissingCompileTimeError
+const_conditional_test/01_generated: MissingCompileTimeError
+const_conditional_test/02_generated: MissingCompileTimeError
+const_conditional_test/03_generated: MissingCompileTimeError
+const_conditional_test/04_generated: MissingCompileTimeError
+const_conditional_test/05_generated: MissingCompileTimeError
+const_conditional_test/06_generated: MissingCompileTimeError
+const_conditional_test/07_generated: MissingCompileTimeError
+const_constructor_mixin2_test/01_generated: MissingCompileTimeError
+const_constructor_mixin3_test/01_generated: MissingCompileTimeError
+const_constructor_mixin_test/01_generated: MissingCompileTimeError
+const_constructor_nonconst_field_test/01_generated: MissingCompileTimeError
+const_constructor_super_test/01_generated: MissingCompileTimeError
+const_constructor_syntax_test/04_generated: MissingCompileTimeError
+const_error_multiply_initialized_test/01_generated: MissingCompileTimeError
+const_error_multiply_initialized_test/03_generated: MissingCompileTimeError
+const_for_in_variable_test/01_generated: MissingCompileTimeError
+const_instance_field_test/01_generated: MissingCompileTimeError
+const_switch2_test/01_generated: MissingCompileTimeError
+const_syntax_test/01_generated: MissingCompileTimeError
+const_syntax_test/02_generated: MissingCompileTimeError
+const_syntax_test/03_generated: MissingCompileTimeError
+const_syntax_test/04_generated: MissingCompileTimeError
+const_syntax_test/05_generated: MissingCompileTimeError
+const_syntax_test/06_generated: MissingCompileTimeError
+const_syntax_test/07_generated: MissingCompileTimeError
+const_syntax_test/11_generated: MissingCompileTimeError
+const_syntax_test/12_generated: MissingCompileTimeError
+constant_locals_test/01_generated: MissingCompileTimeError
+constant_locals_test/02_generated: MissingCompileTimeError
+constant_locals_test/03_generated: MissingCompileTimeError
+constant_locals_test/04_generated: MissingCompileTimeError
+constant_locals_test/05_generated: MissingCompileTimeError
+constructor_duplicate_initializers_test/03_generated: MissingCompileTimeError
+constructor_redirect2_test/01_generated: MissingCompileTimeError
+constructor_redirect_test/01_generated: MissingCompileTimeError
+cyclic_class_member_test/01_generated: MissingCompileTimeError
+cyclic_typedef_test/01_generated: MissingCompileTimeError
+cyclic_typedef_test/02_generated: MissingCompileTimeError
+cyclic_typedef_test/03_generated: MissingCompileTimeError
+cyclic_typedef_test/04_generated: MissingCompileTimeError
+cyclic_typedef_test/05_generated: MissingCompileTimeError
+cyclic_typedef_test/06_generated: MissingCompileTimeError
+cyclic_typedef_test/07_generated: MissingCompileTimeError
+cyclic_typedef_test/08_generated: MissingCompileTimeError
+cyclic_typedef_test/09_generated: MissingCompileTimeError
+cyclic_typedef_test/10_generated: MissingCompileTimeError
+cyclic_typedef_test/11_generated: MissingCompileTimeError
+dynamic2_test/00_generated: MissingCompileTimeError
+dynamic2_test/01_generated: MissingCompileTimeError
+enum_syntax_test/21_generated: MissingCompileTimeError
+export_private_test/01_generated: MissingCompileTimeError
+external_test/11_generated: MissingCompileTimeError
+external_test/12_generated: MissingCompileTimeError
+external_test/21_generated: MissingCompileTimeError
+external_test/22_generated: MissingCompileTimeError
+external_test/23_generated: MissingCompileTimeError
+external_test/24_generated: MissingCompileTimeError
+external_test/25_generated: MissingCompileTimeError
+external_test/30_generated: MissingCompileTimeError
+external_test/31_generated: MissingCompileTimeError
+field_decl_missing_var_type_test/01_generated: MissingCompileTimeError
+final_initializer_instance_reference_test/01_generated: MissingCompileTimeError
+final_is_not_const_test/01_generated: MissingCompileTimeError
+final_syntax_test/01_generated: MissingCompileTimeError
+final_syntax_test/02_generated: MissingCompileTimeError
+final_syntax_test/03_generated: MissingCompileTimeError
+final_syntax_test/04_generated: MissingCompileTimeError
+function_syntax_test/00_generated: MissingCompileTimeError
+function_syntax_test/01_generated: MissingCompileTimeError
+function_syntax_test/22_generated: MissingCompileTimeError
+function_syntax_test/64_generated: MissingCompileTimeError
+function_syntax_test/67_generated: MissingCompileTimeError
+function_syntax_test/68_generated: MissingCompileTimeError
+function_syntax_test/69_generated: MissingCompileTimeError
+function_syntax_test/71_generated: MissingCompileTimeError
+function_syntax_test/74_generated: MissingCompileTimeError
+function_type_alias5_test/00_generated: MissingCompileTimeError
+function_type_alias5_test/01_generated: MissingCompileTimeError
+function_type_alias5_test/02_generated: MissingCompileTimeError
+function_type_alias7_test/00_generated: MissingCompileTimeError
+function_type_alias7_test/02_generated: MissingCompileTimeError
+function_type_alias9_test/00_generated: MissingCompileTimeError
+generic_metadata_test/02_generated: MissingCompileTimeError
+generic_metadata_test/03_generated: MissingCompileTimeError
+getter_parameters_test/01_generated: MissingCompileTimeError
+getter_parameters_test/02_generated: MissingCompileTimeError
+getter_parameters_test/03_generated: MissingCompileTimeError
+getter_parameters_test/04_generated: MissingCompileTimeError
+import_private_test/01_generated: MissingCompileTimeError
+interface_cycle_test/01_generated: MissingCompileTimeError
+interface_cycle_test/02_generated: MissingCompileTimeError
+missing_const_constructor_test/02_generated: MissingCompileTimeError
+missing_const_constructor_test/03_generated: MissingCompileTimeError
+missing_const_constructor_test/05_generated: MissingCompileTimeError
+missing_const_constructor_test/06_generated: MissingCompileTimeError
+mixin_black_listed_test/08_generated: MissingCompileTimeError
+mixin_cyclic_test/01_generated: MissingCompileTimeError
+mixin_cyclic_test/02_generated: MissingCompileTimeError
+mixin_forwarding_constructor4_test/01_generated: MissingCompileTimeError
+mixin_forwarding_constructor4_test/02_generated: MissingCompileTimeError
+mixin_forwarding_constructor4_test/03_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/01_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/02_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/03_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/04_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/05_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/06_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/07_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/08_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/09_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/10_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/11_generated: MissingCompileTimeError
+mixin_illegal_constructor_test/12_generated: MissingCompileTimeError
+mixin_illegal_cycles_test/01_generated: MissingCompileTimeError
+mixin_illegal_cycles_test/02_generated: MissingCompileTimeError
+mixin_illegal_cycles_test/03_generated: MissingCompileTimeError
+mixin_illegal_cycles_test/04_generated: MissingCompileTimeError
+mixin_illegal_cycles_test/05_generated: MissingCompileTimeError
+mixin_illegal_cycles_test/06_generated: MissingCompileTimeError
+mixin_illegal_object_test/01_generated: MissingCompileTimeError
+mixin_illegal_object_test/02_generated: MissingCompileTimeError
+mixin_illegal_super_use_test/01_generated: MissingCompileTimeError
+mixin_illegal_super_use_test/04_generated: MissingCompileTimeError
+mixin_illegal_super_use_test/07_generated: MissingCompileTimeError
+mixin_illegal_super_use_test/10_generated: MissingCompileTimeError
+mixin_illegal_super_use_test/11_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/01_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/02_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/03_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/04_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/05_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/06_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/07_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/08_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/09_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/10_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/11_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/12_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/13_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/14_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/15_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/16_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/17_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/18_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/19_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/20_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/21_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/22_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/23_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/24_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/25_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/26_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/27_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/28_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/29_generated: MissingCompileTimeError
+mixin_illegal_superclass_test/30_generated: MissingCompileTimeError
+mixin_illegal_syntax_test/00_generated: MissingCompileTimeError
+mixin_super_constructor_named_test/01_generated: MissingCompileTimeError
+mixin_super_constructor_positionals_test/01_generated: MissingCompileTimeError
+named_parameters_aggregated_test/01_generated: MissingCompileTimeError
+named_parameters_aggregated_test/03_generated: MissingCompileTimeError
+named_parameters_default_eq_test/01_generated: MissingCompileTimeError
+named_parameters_default_eq_test/02_generated: MissingCompileTimeError
+redirecting_factory_default_values_test/01_generated: MissingCompileTimeError
+redirecting_factory_default_values_test/02_generated: MissingCompileTimeError
+ref_before_declaration_test/00_generated: MissingCompileTimeError
+ref_before_declaration_test/01_generated: MissingCompileTimeError
+ref_before_declaration_test/02_generated: MissingCompileTimeError
+ref_before_declaration_test/03_generated: MissingCompileTimeError
+ref_before_declaration_test/04_generated: MissingCompileTimeError
+ref_before_declaration_test/05_generated: MissingCompileTimeError
+ref_before_declaration_test/06_generated: MissingCompileTimeError
+ref_before_declaration_test/07_generated: MissingCompileTimeError
+regress_27617_test/1_generated: MissingCompileTimeError
+reify_typevar_static_test/00_generated: MissingCompileTimeError
+scope_variable_test/01_generated: MissingCompileTimeError
+static_final_field2_test/02_generated: MissingCompileTimeError
+static_parameter_test/01_generated: MissingCompileTimeError
+static_parameter_test/02_generated: MissingCompileTimeError
+static_parameter_test/03_generated: MissingCompileTimeError
+static_parameter_test/04_generated: MissingCompileTimeError
+static_parameter_test/05_generated: MissingCompileTimeError
+static_parameter_test/06_generated: MissingCompileTimeError
+static_parameter_test/07_generated: MissingCompileTimeError
+static_parameter_test/08_generated: MissingCompileTimeError
+static_parameter_test/09_generated: MissingCompileTimeError
+static_parameter_test/10_generated: MissingCompileTimeError
+static_parameter_test/11_generated: MissingCompileTimeError
+static_parameter_test/12_generated: MissingCompileTimeError
+super_conditional_operator_test/01_generated: MissingCompileTimeError
+super_conditional_operator_test/02_generated: MissingCompileTimeError
+super_conditional_operator_test/03_generated: MissingCompileTimeError
+super_conditional_operator_test/04_generated: MissingCompileTimeError
+super_conditional_operator_test/05_generated: MissingCompileTimeError
+super_conditional_operator_test/06_generated: MissingCompileTimeError
+super_conditional_operator_test/07_generated: MissingCompileTimeError
+super_conditional_operator_test/08_generated: MissingCompileTimeError
+super_conditional_operator_test/09_generated: MissingCompileTimeError
+super_conditional_operator_test/10_generated: MissingCompileTimeError
+super_conditional_operator_test/11_generated: MissingCompileTimeError
+super_conditional_operator_test/12_generated: MissingCompileTimeError
+super_conditional_operator_test/13_generated: MissingCompileTimeError
+super_conditional_operator_test/14_generated: MissingCompileTimeError
+super_conditional_operator_test/15_generated: MissingCompileTimeError
+super_conditional_operator_test/16_generated: MissingCompileTimeError
+switch_bad_case_test/01_generated: MissingCompileTimeError
+switch_case_test/01_generated: MissingCompileTimeError
+switch_case_test/02_generated: MissingCompileTimeError
+syntax_test/02_generated: MissingCompileTimeError
+syntax_test/03_generated: MissingCompileTimeError
+syntax_test/27_generated: MissingCompileTimeError
+syntax_test/64_generated: MissingCompileTimeError
+syntax_test/65_generated: MissingCompileTimeError
+this_conditional_operator_test/01_generated: MissingCompileTimeError
+try_catch_syntax_test/01_generated: MissingCompileTimeError
+try_catch_syntax_test/05_generated: MissingCompileTimeError
+try_catch_syntax_test/07_generated: MissingCompileTimeError
+try_catch_syntax_test/09_generated: MissingCompileTimeError
+try_catch_syntax_test/10_generated: MissingCompileTimeError
+try_catch_syntax_test/11_generated: MissingCompileTimeError
+try_catch_syntax_test/12_generated: MissingCompileTimeError
+type_variable_conflict_test/01_generated: MissingCompileTimeError
+type_variable_conflict_test/02_generated: MissingCompileTimeError
+type_variable_conflict_test/03_generated: MissingCompileTimeError
+type_variable_conflict_test/04_generated: MissingCompileTimeError
+type_variable_conflict_test/05_generated: MissingCompileTimeError
+type_variable_conflict_test/06_generated: MissingCompileTimeError
+type_variable_scope3_test/00_generated: MissingCompileTimeError
diff --git a/pkg/front_end/test/fasta/literals.dart b/pkg/front_end/test/fasta/literals.dart
new file mode 100644
index 0000000..561b82c
--- /dev/null
+++ b/pkg/front_end/test/fasta/literals.dart
@@ -0,0 +1,51 @@
+// 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.
+
+testString() {
+  print("a");
+}
+
+testInt() {
+  print(1);
+}
+
+testBool() {
+  print(true);
+  print(false);
+}
+
+testDouble() {
+  print(1.0);
+}
+
+testNull() {
+  print(null);
+}
+
+testList() {
+  print([]);
+  print(["a", "b"]);
+}
+
+testMap() {
+  print({});
+  print({"a": "b"});
+}
+
+testSymbol() {
+  print(#fisk);
+  print(#_fisk);
+  print(#fisk.hest.ko);
+}
+
+main() {
+  testString();
+  testInt();
+  testBool();
+  testDouble();
+  testNull();
+  testList();
+  testMap();
+  testSymbol();
+}
diff --git a/pkg/front_end/test/fasta/literals.dart.dartk.expect b/pkg/front_end/test/fasta/literals.dart.dartk.expect
new file mode 100644
index 0000000..bd49a1d
--- /dev/null
+++ b/pkg/front_end/test/fasta/literals.dart.dartk.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method testString() → dynamic {
+  core::print("a");
+}
+static method testInt() → dynamic {
+  core::print(1);
+}
+static method testBool() → dynamic {
+  core::print(true);
+  core::print(false);
+}
+static method testDouble() → dynamic {
+  core::print(1.0);
+}
+static method testNull() → dynamic {
+  core::print(null);
+}
+static method testList() → dynamic {
+  core::print(<dynamic>[]);
+  core::print(<dynamic>["a", "b"]);
+}
+static method testMap() → dynamic {
+  core::print(<dynamic, dynamic>{});
+  core::print(<dynamic, dynamic>{"a": "b"});
+}
+static method testSymbol() → dynamic {
+  core::print(#fisk);
+  core::print(#_fisk);
+  core::print(#fisk.hest.ko);
+}
+static method main() → dynamic {
+  self::testString();
+  self::testInt();
+  self::testBool();
+  self::testDouble();
+  self::testNull();
+  self::testList();
+  self::testMap();
+  self::testSymbol();
+}
diff --git a/pkg/front_end/test/fasta/literals.dart.direct.expect b/pkg/front_end/test/fasta/literals.dart.direct.expect
new file mode 100644
index 0000000..bd49a1d
--- /dev/null
+++ b/pkg/front_end/test/fasta/literals.dart.direct.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method testString() → dynamic {
+  core::print("a");
+}
+static method testInt() → dynamic {
+  core::print(1);
+}
+static method testBool() → dynamic {
+  core::print(true);
+  core::print(false);
+}
+static method testDouble() → dynamic {
+  core::print(1.0);
+}
+static method testNull() → dynamic {
+  core::print(null);
+}
+static method testList() → dynamic {
+  core::print(<dynamic>[]);
+  core::print(<dynamic>["a", "b"]);
+}
+static method testMap() → dynamic {
+  core::print(<dynamic, dynamic>{});
+  core::print(<dynamic, dynamic>{"a": "b"});
+}
+static method testSymbol() → dynamic {
+  core::print(#fisk);
+  core::print(#_fisk);
+  core::print(#fisk.hest.ko);
+}
+static method main() → dynamic {
+  self::testString();
+  self::testInt();
+  self::testBool();
+  self::testDouble();
+  self::testNull();
+  self::testList();
+  self::testMap();
+  self::testSymbol();
+}
diff --git a/pkg/front_end/test/fasta/literals.dart.outline.expect b/pkg/front_end/test/fasta/literals.dart.outline.expect
new file mode 100644
index 0000000..ffc79f2
--- /dev/null
+++ b/pkg/front_end/test/fasta/literals.dart.outline.expect
@@ -0,0 +1,21 @@
+library;
+import self as self;
+
+static method testString() → dynamic
+  ;
+static method testInt() → dynamic
+  ;
+static method testBool() → dynamic
+  ;
+static method testDouble() → dynamic
+  ;
+static method testNull() → dynamic
+  ;
+static method testList() → dynamic
+  ;
+static method testMap() → dynamic
+  ;
+static method testSymbol() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/map.dart b/pkg/front_end/test/fasta/map.dart
new file mode 100644
index 0000000..b2e55ab
--- /dev/null
+++ b/pkg/front_end/test/fasta/map.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print(new Map());
+}
diff --git a/pkg/front_end/test/fasta/map.dart.direct.expect b/pkg/front_end/test/fasta/map.dart.direct.expect
new file mode 100644
index 0000000..5deb82f
--- /dev/null
+++ b/pkg/front_end/test/fasta/map.dart.direct.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+static method main() → dynamic {
+  core::print(col::LinkedHashMap::•<dynamic, dynamic>(equals: null, hashCode: null, isValidKey: null));
+}
diff --git a/pkg/front_end/test/fasta/map.dart.outline.expect b/pkg/front_end/test/fasta/map.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/map.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/mixin.dart b/pkg/front_end/test/fasta/mixin.dart
new file mode 100644
index 0000000..dbe5bf8
--- /dev/null
+++ b/pkg/front_end/test/fasta/mixin.dart
@@ -0,0 +1,18 @@
+// 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.
+
+abstract class M1 {
+  m() => print("M1");
+}
+
+abstract class M2 {
+  m() => print("M2");
+}
+
+class C extends Object with M1, M2 {
+}
+
+main() {
+  new C().m();
+}
diff --git a/pkg/front_end/test/fasta/mixin.dart.direct.expect b/pkg/front_end/test/fasta/mixin.dart.direct.expect
new file mode 100644
index 0000000..ab5f3d6
--- /dev/null
+++ b/pkg/front_end/test/fasta/mixin.dart.direct.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class M1 extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method m() → dynamic
+    return core::print("M1");
+}
+abstract class M2 extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method m() → dynamic
+    return core::print("M2");
+}
+class C extends self::Object&M1&M2 {
+  constructor •() → void
+    : super self::Object&M1&M2::•()
+    ;
+}
+abstract class Object&M1 extends core::Object implements self::M1 {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method m() → dynamic
+    return core::print("M1");
+}
+abstract class Object&M1&M2 extends self::Object&M1 implements self::M2 {
+  constructor •() → void
+    : super self::Object&M1::•()
+    ;
+  method m() → dynamic
+    return core::print("M2");
+}
+static method main() → dynamic {
+  new self::C::•().m();
+}
diff --git a/pkg/front_end/test/fasta/mixin.dart.outline.expect b/pkg/front_end/test/fasta/mixin.dart.outline.expect
new file mode 100644
index 0000000..d0c955c
--- /dev/null
+++ b/pkg/front_end/test/fasta/mixin.dart.outline.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class M1 extends core::Object {
+  constructor •() → void
+    ;
+  method m() → dynamic
+    ;
+}
+abstract class M2 extends core::Object {
+  constructor •() → void
+    ;
+  method m() → dynamic
+    ;
+}
+class C extends self::Object&M1&M2 {
+  constructor •() → void
+    ;
+}
+abstract class Object&M1 = core::Object with self::M1 {
+}
+abstract class Object&M1&M2 = self::Object&M1 with self::M2 {
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/operators.dart b/pkg/front_end/test/fasta/operators.dart
new file mode 100644
index 0000000..3e4247e
--- /dev/null
+++ b/pkg/front_end/test/fasta/operators.dart
@@ -0,0 +1,51 @@
+// 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 Operators {
+  operator +(other) => null;
+  operator &(other) => null;
+  operator ~() => null;
+  operator |(other) => null;
+  operator ^(other) => null;
+  operator /(other) => null;
+  operator ==(other) => null;
+  operator >(other) => null;
+  operator >=(other) => null;
+  operator [](index) => null;
+  void operator []=(index, value) {}
+  operator <<(other) => null;
+  operator <(other) => null;
+  operator <=(other) => null;
+  operator *(other) => null;
+  operator %(other) => null;
+  operator >>(other) => null;
+  operator -(other) => null;
+  operator ~/(other) => null;
+  operator -() => null;
+}
+
+main(arguments) {
+  var a = new Operators();
+  var b = new Operators();
+  a + b;
+  a & b;
+  ~a;
+  a | b;
+  a ^ b;
+  a / b;
+  a == b;
+  a > b;
+  a >= b;
+  a[0];
+  a[0] = b;
+  a << b;
+  a < b;
+  a <= b;
+  a * b;
+  a % b;
+  a >> b;
+  a - b;
+  a ~/ b;
+  -a;
+}
diff --git a/pkg/front_end/test/fasta/operators.dart.direct.expect b/pkg/front_end/test/fasta/operators.dart.direct.expect
new file mode 100644
index 0000000..993e3d3
--- /dev/null
+++ b/pkg/front_end/test/fasta/operators.dart.direct.expect
@@ -0,0 +1,72 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Operators extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  operator +(dynamic other) → dynamic
+    return null;
+  operator &(dynamic other) → dynamic
+    return null;
+  operator ~() → dynamic
+    return null;
+  operator |(dynamic other) → dynamic
+    return null;
+  operator ^(dynamic other) → dynamic
+    return null;
+  operator /(dynamic other) → dynamic
+    return null;
+  operator ==(dynamic other) → dynamic
+    return null;
+  operator >(dynamic other) → dynamic
+    return null;
+  operator >=(dynamic other) → dynamic
+    return null;
+  operator [](dynamic index) → dynamic
+    return null;
+  operator []=(dynamic index, dynamic value) → void {}
+  operator <<(dynamic other) → dynamic
+    return null;
+  operator <(dynamic other) → dynamic
+    return null;
+  operator <=(dynamic other) → dynamic
+    return null;
+  operator *(dynamic other) → dynamic
+    return null;
+  operator %(dynamic other) → dynamic
+    return null;
+  operator >>(dynamic other) → dynamic
+    return null;
+  operator -(dynamic other) → dynamic
+    return null;
+  operator ~/(dynamic other) → dynamic
+    return null;
+  operator unary-() → dynamic
+    return null;
+}
+static method main(dynamic arguments) → dynamic {
+  dynamic a = new self::Operators::•();
+  dynamic b = new self::Operators::•();
+  a.+(b);
+  a.&(b);
+  a.~();
+  a.|(b);
+  a.^(b);
+  a./(b);
+  a.==(b);
+  a.>(b);
+  a.>=(b);
+  a.[](0);
+  a.[]=(0, b);
+  a.<<(b);
+  a.<(b);
+  a.<=(b);
+  a.*(b);
+  a.%(b);
+  a.>>(b);
+  a.-(b);
+  a.~/(b);
+  a.unary-();
+}
diff --git a/pkg/front_end/test/fasta/operators.dart.outline.expect b/pkg/front_end/test/fasta/operators.dart.outline.expect
new file mode 100644
index 0000000..0269d34
--- /dev/null
+++ b/pkg/front_end/test/fasta/operators.dart.outline.expect
@@ -0,0 +1,50 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Operators extends core::Object {
+  constructor •() → void
+    ;
+  operator +(dynamic other) → dynamic
+    ;
+  operator &(dynamic other) → dynamic
+    ;
+  operator ~() → dynamic
+    ;
+  operator |(dynamic other) → dynamic
+    ;
+  operator ^(dynamic other) → dynamic
+    ;
+  operator /(dynamic other) → dynamic
+    ;
+  operator ==(dynamic other) → dynamic
+    ;
+  operator >(dynamic other) → dynamic
+    ;
+  operator >=(dynamic other) → dynamic
+    ;
+  operator [](dynamic index) → dynamic
+    ;
+  operator []=(dynamic index, dynamic value) → void
+    ;
+  operator <<(dynamic other) → dynamic
+    ;
+  operator <(dynamic other) → dynamic
+    ;
+  operator <=(dynamic other) → dynamic
+    ;
+  operator *(dynamic other) → dynamic
+    ;
+  operator %(dynamic other) → dynamic
+    ;
+  operator >>(dynamic other) → dynamic
+    ;
+  operator -(dynamic other) → dynamic
+    ;
+  operator ~/(dynamic other) → dynamic
+    ;
+  operator unary-() → dynamic
+    ;
+}
+static method main(dynamic arguments) → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/outline.status b/pkg/front_end/test/fasta/outline.status
new file mode 100644
index 0000000..ed4adc2
--- /dev/null
+++ b/pkg/front_end/test/fasta/outline.status
@@ -0,0 +1,19 @@
+# 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.
+
+rasta/bad_redirection: Fail
+rasta/class_hierarchy: Fail
+rasta/generic_factory: Fail
+rasta/issue_000002: Fail
+rasta/issue_000032: Fail
+rasta/issue_000044: Fail
+rasta/issue_000045: Fail
+rasta/issue_000046: Fail
+rasta/issue_000047: Fail
+rasta/issue_000067: Fail
+rasta/issue_000070: Fail
+rasta/mandatory_parameter_initializer: Fail
+rasta/native_is_illegal: Fail
+rasta/super_mixin: Fail
+rasta/type_with_parse_error: Fail
diff --git a/pkg/front_end/test/fasta/outline_test.dart b/pkg/front_end/test/fasta/outline_test.dart
new file mode 100644
index 0000000..1aad820
--- /dev/null
+++ b/pkg/front_end/test/fasta/outline_test.dart
@@ -0,0 +1,17 @@
+// 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.
+
+library fasta.test.outline_test;
+
+import 'dart:async' show
+    Future;
+
+import 'package:front_end/src/fasta/testing/suite.dart';
+
+Future<FeContext> createContext(
+    Chain suite, Map<String, String> environment) {
+  return TestContext.create(suite, environment, FeContext.create);
+}
+
+main(List<String> arguments) => runMe(arguments, createContext, "testing.json");
diff --git a/pkg/front_end/test/fasta/parser/parser.status b/pkg/front_end/test/fasta/parser/parser.status
new file mode 100644
index 0000000..ed44583
--- /dev/null
+++ b/pkg/front_end/test/fasta/parser/parser.status
@@ -0,0 +1,2144 @@
+# 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.
+
+pkg/analyzer_cli/test/data/file_with_error: Fail
+pkg/dev_compiler/test/codegen/corelib/from_environment_const_type_test: Fail
+pkg/dev_compiler/test/codegen/corelib/from_environment_const_type_undefined_test: Fail
+pkg/dev_compiler/test/codegen/corelib/symbol_reserved_word_test: Fail
+pkg/dev_compiler/test/codegen/destructuring: Fail
+pkg/dev_compiler/test/codegen/language/abstract_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/application_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/argument_definition_test: Fail
+pkg/dev_compiler/test/codegen/language/assign_instance_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/async_await_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/await_backwards_compatibility_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_constructor_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_initializer1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_initializer2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_named_constructor_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/black_listed_test: Fail
+pkg/dev_compiler/test/codegen/language/body_less_constructor_wrong_arg_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/built_in_identifier_prefix_test: Fail
+pkg/dev_compiler/test/codegen/language/built_in_identifier_test: Fail
+pkg/dev_compiler/test/codegen/language/cascade_test: Fail
+pkg/dev_compiler/test/codegen/language/class_cycle2_test: Fail
+pkg/dev_compiler/test/codegen/language/class_keyword_test: Fail
+pkg/dev_compiler/test/codegen/language/class_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/closure_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/compile_time_constant13_test: Fail
+pkg/dev_compiler/test/codegen/language/const_counter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/const_native_factory_test: Fail
+pkg/dev_compiler/test/codegen/language/const_optional_args_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_initializer_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_name_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_redirect1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_redirect2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_setter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/cyclic_typedef_test: Fail
+pkg/dev_compiler/test/codegen/language/deferred_type_dependency_test: Fail
+pkg/dev_compiler/test/codegen/language/duplicate_export_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/duplicate_interface_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/enum_is_keyword_test: Fail
+pkg/dev_compiler/test/codegen/language/enum_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/export_ambiguous_main_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/extend_type_parameter2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/extend_type_parameter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/external_test: Fail
+pkg/dev_compiler/test/codegen/language/factory2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/factory_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field3a_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field6a_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field_method4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/function_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/function_type_parameter2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/function_type_parameter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/get_set_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/getter_declaration_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/illegal_declaration_test: Fail
+pkg/dev_compiler/test/codegen/language/import_combinators_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/inst_field_initializer1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/instance_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/instance_method2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/instance_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface_cycle_test: Fail
+pkg/dev_compiler/test/codegen/language/interface_static_non_final_fields_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/keyword_type_expression_test: Fail
+pkg/dev_compiler/test/codegen/language/label2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/library_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/list_literal2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/list_literal_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/literal_unary_plus_test: Fail
+pkg/dev_compiler/test/codegen/language/main_test: Fail
+pkg/dev_compiler/test/codegen/language/malformed_inheritance_test: Fail
+pkg/dev_compiler/test/codegen/language/malformed_test: Fail
+pkg/dev_compiler/test/codegen/language/map_literal2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/metadata_test: Fail
+pkg/dev_compiler/test/codegen/language/method_override2_test: Fail
+pkg/dev_compiler/test/codegen/language/mixin_forwarding_constructor4_test: Fail
+pkg/dev_compiler/test/codegen/language/mixin_illegal_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/mixin_invalid_inheritance1_test: Fail
+pkg/dev_compiler/test/codegen/language/named_constructor_test: Fail
+pkg/dev_compiler/test/codegen/language/named_parameters_aggregated_test: Fail
+pkg/dev_compiler/test/codegen/language/no_such_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/non_const_super_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/null_test: Fail
+pkg/dev_compiler/test/codegen/language/number_identifier_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_inheritance_generic_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_default_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix10_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix11_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix12_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix13_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix15_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix7_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix8_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/private_member1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/private_member2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/private_member3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/regress_23051_test: Fail
+pkg/dev_compiler/test/codegen/language/script1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/script2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/setter_declaration2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/setter_declaration_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/source_self_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/static_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/static_parameter_test: Fail
+pkg/dev_compiler/test/codegen/language/static_top_level_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation9_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch7_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/sync_generator2_test: Fail
+pkg/dev_compiler/test/codegen/language/syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/tearoff_basic_test: Fail
+pkg/dev_compiler/test/codegen/language/tearoff_constructor_basic_test: Fail
+pkg/dev_compiler/test/codegen/language/try_catch_on_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/try_catch_syntax_test: Fail
+pkg/dev_compiler/test/codegen/language/type_variable_bounds2_test: Fail
+pkg/dev_compiler/test/codegen/language/type_variable_static_context_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unbalanced_brace_test: Fail
+pkg/dev_compiler/test/codegen/language/unresolved_in_factory_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unresolved_top_level_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unresolved_top_level_var_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unsigned_right_shift_test: Fail
+pkg/dev_compiler/test/codegen/language/variable_declaration_metadata_test: Fail
+pkg/dev_compiler/test/codegen/lib/mirrors/metadata_allowed_values_test: Fail
+pkg/dev_compiler/test/codegen/lib/mirrors/metadata_scope_test: Fail
+pkg/dev_compiler/test/codegen/lib/mirrors/mirror_in_static_init_test: Fail
+pkg/dev_compiler/test/codegen/lib/mirrors/other_declarations_location_test: Fail
+pkg/dev_compiler/test/codegen/lib/mirrors/syntax_error_test: Fail
+pkg/dev_compiler/test/codegen/lib/mirrors/typevariable_mirror_metadata_test: Fail
+pkg/dev_compiler/tool/input_sdk/lib/html/dart2js/html_dart2js: Fail
+pkg/dev_compiler/tool/input_sdk/lib/indexed_db/dart2js/indexed_db_dart2js: Fail
+pkg/dev_compiler/tool/input_sdk/lib/svg/dart2js/svg_dart2js: Fail
+pkg/dev_compiler/tool/input_sdk/lib/web_audio/dart2js/web_audio_dart2js: Fail
+pkg/dev_compiler/tool/input_sdk/lib/web_gl/dart2js/web_gl_dart2js: Fail
+pkg/dev_compiler/tool/input_sdk/lib/web_sql/dart2js/web_sql_dart2js: Fail
+pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types: Fail
+pkg/dev_compiler/tool/input_sdk/private/native_typed_data: Fail
+pkg/front_end/test/fasta/rasta/bad_interpolation: Fail
+pkg/front_end/test/fasta/rasta/issue_000032: Fail
+pkg/front_end/test/fasta/rasta/issue_000035: Fail
+pkg/front_end/test/fasta/rasta/issue_000035a: Fail
+pkg/front_end/test/fasta/rasta/issue_000036: Fail
+pkg/front_end/test/fasta/rasta/issue_000039: Fail
+pkg/front_end/test/fasta/rasta/issue_000041: Fail
+pkg/front_end/test/fasta/rasta/issue_000044: Fail
+pkg/front_end/test/fasta/rasta/issue_000045: Fail
+pkg/front_end/test/fasta/rasta/issue_000046: Fail
+pkg/front_end/test/fasta/rasta/issue_000047: Fail
+pkg/front_end/test/fasta/rasta/malformed_const_constructor: Fail
+pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer: Fail
+pkg/front_end/test/fasta/rasta/native_is_illegal: Fail
+pkg/front_end/test/fasta/rasta/parser_error: Fail
+pkg/front_end/test/fasta/rasta/super: Fail
+pkg/front_end/test/fasta/rasta/type_with_parse_error: Fail
+pkg/front_end/test/fasta/rasta/unresolved_recovery: Fail
+pkg/testing/test/dart_sdk_negative_test: Fail
+runtime/bin/builtin: Fail
+runtime/bin/common_patch: Fail
+runtime/bin/directory_patch: Fail
+runtime/bin/eventhandler_patch: Fail
+runtime/bin/file_patch: Fail
+runtime/bin/file_system_entity_patch: Fail
+runtime/bin/filter_patch: Fail
+runtime/bin/io_service_patch: Fail
+runtime/bin/platform_patch: Fail
+runtime/bin/process_patch: Fail
+runtime/bin/secure_socket_patch: Fail
+runtime/bin/socket_patch: Fail
+runtime/bin/stdio_patch: Fail
+runtime/bin/vmservice/server: Fail
+runtime/bin/vmservice/vmservice_io: Fail
+runtime/lib/array: Fail
+runtime/lib/async_patch: Fail
+runtime/lib/bigint: Fail
+runtime/lib/bool_patch: Fail
+runtime/lib/class_id: Fail
+runtime/lib/compact_hash: Fail
+runtime/lib/convert_patch: Fail
+runtime/lib/core_patch: Fail
+runtime/lib/date_patch: Fail
+runtime/lib/developer: Fail
+runtime/lib/double: Fail
+runtime/lib/double_patch: Fail
+runtime/lib/errors_patch: Fail
+runtime/lib/function: Fail
+runtime/lib/function_patch: Fail
+runtime/lib/growable_array: Fail
+runtime/lib/identical_patch: Fail
+runtime/lib/integers: Fail
+runtime/lib/integers_patch: Fail
+runtime/lib/internal_patch: Fail
+runtime/lib/isolate_patch: Fail
+runtime/lib/lib_prefix: Fail
+runtime/lib/math_patch: Fail
+runtime/lib/mirror_reference: Fail
+runtime/lib/mirrors_impl: Fail
+runtime/lib/mirrors_patch: Fail
+runtime/lib/object_patch: Fail
+runtime/lib/profiler: Fail
+runtime/lib/regexp_patch: Fail
+runtime/lib/stopwatch_patch: Fail
+runtime/lib/string_buffer_patch: Fail
+runtime/lib/string_patch: Fail
+runtime/lib/timeline: Fail
+runtime/lib/type_patch: Fail
+runtime/lib/typed_data: Fail
+runtime/lib/typed_data_patch: Fail
+runtime/lib/uri_patch: Fail
+runtime/lib/vmservice_patch: Fail
+runtime/lib/weak_property: Fail
+runtime/observatory/tests/service/developer_extension_test: Fail
+runtime/observatory/tests/service/get_isolate_after_language_error_test: Fail
+samples/sample_extension/sample_asynchronous_extension: Fail
+samples/sample_extension/sample_synchronous_extension: Fail
+sdk/lib/_blink/dartium/_blink_dartium: Fail
+sdk/lib/_internal/js_runtime/lib/native_typed_data: Fail
+sdk/lib/html/dart2js/html_dart2js: Fail
+sdk/lib/indexed_db/dart2js/indexed_db_dart2js: Fail
+sdk/lib/js/dartium/js_dartium: Fail
+sdk/lib/svg/dart2js/svg_dart2js: Fail
+sdk/lib/web_audio/dart2js/web_audio_dart2js: Fail
+sdk/lib/web_gl/dart2js/web_gl_dart2js: Fail
+sdk/lib/web_sql/dart2js/web_sql_dart2js: Fail
+tests/co19/src/Language/Classes/Constructors/Constant_Constructors/syntax_t02: Fail
+tests/co19/src/Language/Classes/Constructors/Constant_Constructors/syntax_t04: Fail
+tests/co19/src/Language/Classes/Constructors/Constant_Constructors/syntax_t05: Fail
+tests/co19/src/Language/Classes/Constructors/Constant_Constructors/syntax_t06: Fail
+tests/co19/src/Language/Classes/Constructors/Factories/redirecting_constructor_t02: Fail
+tests/co19/src/Language/Classes/Constructors/Factories/redirecting_constructor_t03: Fail
+tests/co19/src/Language/Classes/Constructors/Factories/syntax_t03: Fail
+tests/co19/src/Language/Classes/Constructors/Factories/syntax_t04: Fail
+tests/co19/src/Language/Classes/Constructors/Factories/syntax_t05: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t02: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t03: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t04: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t05: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t07: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t09: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t10: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t11: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/initializers_t16: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/syntax_t03: Fail
+tests/co19/src/Language/Classes/Constructors/Generative_Constructors/syntax_t06: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t02: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t03: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t04: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t05: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t06: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t07: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t08: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t09: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t10: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t11: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t12: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t13: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t14: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t15: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t16: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t17: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t18: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t19: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t20: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t21: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/allowed_names_t22: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/optional_parameter_t05: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/optional_parameter_t07: Fail
+tests/co19/src/Language/Classes/Instance_Methods/Operators/syntax_t02: Fail
+tests/co19/src/Language/Classes/Setters/name_t08: Fail
+tests/co19/src/Language/Classes/Setters/name_t09: Fail
+tests/co19/src/Language/Classes/Setters/name_t10: Fail
+tests/co19/src/Language/Classes/Setters/name_t11: Fail
+tests/co19/src/Language/Classes/Setters/name_t12: Fail
+tests/co19/src/Language/Classes/Setters/name_t13: Fail
+tests/co19/src/Language/Classes/Setters/name_t14: Fail
+tests/co19/src/Language/Classes/Setters/name_t15: Fail
+tests/co19/src/Language/Classes/Superclasses/wrong_superclass_t06: Fail
+tests/co19/src/Language/Classes/Superinterfaces/syntax_t02: Fail
+tests/co19/src/Language/Classes/declarations_t12: Fail
+tests/co19/src/Language/Classes/declarations_t13: Fail
+tests/co19/src/Language/Classes/declarations_t14: Fail
+tests/co19/src/Language/Classes/declarations_t15: Fail
+tests/co19/src/Language/Classes/declarations_t16: Fail
+tests/co19/src/Language/Classes/declarations_t17: Fail
+tests/co19/src/Language/Classes/declarations_t18: Fail
+tests/co19/src/Language/Classes/declarations_t19: Fail
+tests/co19/src/Language/Classes/declarations_t20: Fail
+tests/co19/src/Language/Classes/declarations_t21: Fail
+tests/co19/src/Language/Classes/declarations_t22: Fail
+tests/co19/src/Language/Classes/declarations_t23: Fail
+tests/co19/src/Language/Classes/declarations_t24: Fail
+tests/co19/src/Language/Classes/declarations_t25: Fail
+tests/co19/src/Language/Classes/declarations_t26: Fail
+tests/co19/src/Language/Classes/declarations_t27: Fail
+tests/co19/src/Language/Classes/declarations_t28: Fail
+tests/co19/src/Language/Classes/declarations_t29: Fail
+tests/co19/src/Language/Classes/declarations_t30: Fail
+tests/co19/src/Language/Classes/declarations_t31: Fail
+tests/co19/src/Language/Classes/declarations_t32: Fail
+tests/co19/src/Language/Classes/definition_t02: Fail
+tests/co19/src/Language/Classes/definition_t03: Fail
+tests/co19/src/Language/Classes/definition_t04: Fail
+tests/co19/src/Language/Classes/definition_t05: Fail
+tests/co19/src/Language/Classes/definition_t06: Fail
+tests/co19/src/Language/Classes/definition_t07: Fail
+tests/co19/src/Language/Classes/definition_t08: Fail
+tests/co19/src/Language/Classes/definition_t09: Fail
+tests/co19/src/Language/Classes/definition_t10: Fail
+tests/co19/src/Language/Classes/definition_t11: Fail
+tests/co19/src/Language/Classes/definition_t12: Fail
+tests/co19/src/Language/Classes/definition_t13: Fail
+tests/co19/src/Language/Classes/definition_t14: Fail
+tests/co19/src/Language/Classes/definition_t15: Fail
+tests/co19/src/Language/Classes/definition_t16: Fail
+tests/co19/src/Language/Classes/definition_t17: Fail
+tests/co19/src/Language/Classes/definition_t18: Fail
+tests/co19/src/Language/Classes/definition_t19: Fail
+tests/co19/src/Language/Classes/definition_t21: Fail
+tests/co19/src/Language/Classes/definition_t22: Fail
+tests/co19/src/Language/Classes/member_definition_t01: Fail
+tests/co19/src/Language/Classes/member_definition_t02: Fail
+tests/co19/src/Language/Classes/member_definition_t04: Fail
+tests/co19/src/Language/Classes/member_definition_t05: Fail
+tests/co19/src/Language/Classes/member_definition_t06: Fail
+tests/co19/src/Language/Classes/member_definition_t07: Fail
+tests/co19/src/Language/Classes/member_definition_t08: Fail
+tests/co19/src/Language/Classes/member_definition_t09: Fail
+tests/co19/src/Language/Classes/member_definition_t10: Fail
+tests/co19/src/Language/Classes/member_definition_t11: Fail
+tests/co19/src/Language/Classes/member_definition_t12: Fail
+tests/co19/src/Language/Classes/member_definition_t13: Fail
+tests/co19/src/Language/Classes/member_definition_t14: Fail
+tests/co19/src/Language/Classes/member_definition_t15: Fail
+tests/co19/src/Language/Classes/member_definition_t16: Fail
+tests/co19/src/Language/Classes/member_definition_t17: Fail
+tests/co19/src/Language/Classes/member_definition_t19: Fail
+tests/co19/src/Language/Classes/member_definition_t21: Fail
+tests/co19/src/Language/Classes/member_definition_t22: Fail
+tests/co19/src/Language/Classes/member_definition_t24: Fail
+tests/co19/src/Language/Classes/member_definition_t25: Fail
+tests/co19/src/Language/Classes/method_definition_t02: Fail
+tests/co19/src/Language/Classes/method_definition_t07: Fail
+tests/co19/src/Language/Classes/method_definition_t08: Fail
+tests/co19/src/Language/Classes/method_definition_t09: Fail
+tests/co19/src/Language/Classes/mixins_t02: Fail
+tests/co19/src/Language/Enums/syntax_t04: Fail
+tests/co19/src/Language/Enums/syntax_t05: Fail
+tests/co19/src/Language/Enums/syntax_t06: Fail
+tests/co19/src/Language/Enums/syntax_t07: Fail
+tests/co19/src/Language/Enums/syntax_t08: Fail
+tests/co19/src/Language/Enums/syntax_t09: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_lib: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_lib_p2: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_t01: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_t02: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_t03: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_t04: Fail
+tests/co19/src/Language/Errors_and_Warnings/compile_error_t05: Fail
+tests/co19/src/Language/Expressions/Additive_Expressions/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Additive_Expressions/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Additive_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Additive_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Additive_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t12: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t13: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t14: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t15: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t16: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t18: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t19: Fail
+tests/co19/src/Language/Expressions/Assignable_Expressions/syntax_t20: Fail
+tests/co19/src/Language/Expressions/Await_Expressions/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Await_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Await_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Bitwise_Expressions/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Booleans/boolean_literals_t01: Fail
+tests/co19/src/Language/Expressions/Booleans/boolean_literals_t02: Fail
+tests/co19/src/Language/Expressions/Booleans/boolean_literals_t03: Fail
+tests/co19/src/Language/Expressions/Conditional/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Conditional/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Conditional/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Conditional/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Conditional/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t12: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t15: Fail
+tests/co19/src/Language/Expressions/Equality/syntax_t16: Fail
+tests/co19/src/Language/Expressions/Function_Expressions/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Function_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Function_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Function_Invocation/Actual_Argument_List_Evaluation/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t01: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t03: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t04: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t11: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t12: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t13: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t14: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t15: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t16: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t17: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t18: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t19: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t20: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t21: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t22: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t23: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t24: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t25: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t26: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t27: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t28: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t29: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t30: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t31: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t32: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t33: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t34: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t38: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t39: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t40: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t41: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t42: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t43: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t44: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t45: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t46: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t47: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t48: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t49: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t50: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t51: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_identifier_t52: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t02: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t04: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t05: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t06: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t07: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t08: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t09: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t10: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t11: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t13: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t16: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t17: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t18: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t21: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t22: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t23: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t24: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t25: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t26: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t27: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t28: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t29: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t30: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t31: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/built_in_not_dynamic_t32: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_built_in_t01: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Identifier_Reference/syntax_t09: Fail
+tests/co19/src/Language/Expressions/If_null_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/If_null_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/If_null_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/If_null_Expressions/syntax_t07: Fail
+tests/co19/src/Language/Expressions/If_null_Expressions/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Instance_Creation/Const/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Instance_Creation/Const/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Instance_Creation/New/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Instance_Creation/New/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Instance_Creation/New/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Lists/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Lists/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Lists/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Lists/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Lists/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Lists/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Logical_Boolean_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Logical_Boolean_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Logical_Boolean_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Logical_Boolean_Expressions/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Logical_Boolean_Expressions/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Logical_Boolean_Expressions/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Maps/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t12: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t13: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t14: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t15: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t17: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t18: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Method_Invocation/Super_Invocation/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t18: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t19: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t20: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t21: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t22: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t23: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t24: Fail
+tests/co19/src/Language/Expressions/Multiplicative_Expressions/syntax_t25: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t16: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t17: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t18: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t21: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t22: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t23: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t24: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t25: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t26: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t27: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t29: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t30: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t31: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t32: Fail
+tests/co19/src/Language/Expressions/Numbers/syntax_t33: Fail
+tests/co19/src/Language/Expressions/Postfix_Expressions/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Postfix_Expressions/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Postfix_Expressions/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Closurization/identical_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Closurization/identical_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Closurization/identical_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Closurization/named_parameters_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Closurization/positional_parameters_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/deferred_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/malbounded_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/malbounded_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/malformed_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/malformed_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/no_such_method_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/no_such_method_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/not_class_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/not_class_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/not_class_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/static_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/static_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/static_type_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/class_object_member_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/class_object_member_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/class_object_member_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/class_object_member_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/class_object_member_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/class_object_member_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/expression_evaluation_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/expression_evaluation_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/expression_evaluation_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/getter_lookup_t09: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/method_lookup_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/no_accessible_member_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/setter_lookup_t09: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Closurization/static_type_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_failed_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_failed_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_failed_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_failed_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_failed_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/getter_lookup_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/method_lookup_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/method_lookup_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/method_lookup_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/method_lookup_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_failed_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_failed_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_failed_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/setter_lookup_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_type_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_type_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_warning_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_warning_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_warning_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_warning_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/General_Super_Property_Extraction/static_warning_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/expression_evaluation_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Closurization/identical_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Closurization/identical_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Closurization/named_parameters_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Closurization/positional_parameters_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/deferred_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/malbounded_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/malbounded_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/malformed_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/malformed_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/no_such_method_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/no_such_method_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/not_class_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/not_class_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/not_class_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/static_type_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/static_type_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/static_type_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Named_Constructor_Extraction/static_type_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/method_identical_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/method_identical_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/method_identical_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_list_access_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_list_assignment_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t09: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t10: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t11: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t12: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t13: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t14: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t15: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t16: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_t17: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/operator_closurization_unary_bitwise_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t09: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/getter_closurization_t10: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/method_identical_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/method_identical_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/method_identical_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/method_identical_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/method_identical_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_list_access_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_list_assignment_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t09: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t10: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t11: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t12: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t13: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t14: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t15: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t16: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_t17: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/operator_closurization_unary_bitwise_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t01: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t02: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t03: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t04: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t05: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t06: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t07: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t08: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t09: Fail
+tests/co19/src/Language/Expressions/Property_Extraction/Super_Closurization/setter_closurization_t10: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t12: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t13: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t14: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t15: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t16: Fail
+tests/co19/src/Language/Expressions/Relational_Expressions/syntax_t17: Fail
+tests/co19/src/Language/Expressions/Shift/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Shift/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Shift/syntax_t04: Fail
+tests/co19/src/Language/Expressions/Shift/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Shift/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Shift/syntax_t07: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t08: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t09: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t10: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t11: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t14: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t15: Fail
+tests/co19/src/Language/Expressions/Strings/String_Interpolation/syntax_t16: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t02: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t03: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t04: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t05: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t06: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t07: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t08: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t09: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t10: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t11: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t12: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t13: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t14: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t15: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t16: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t17: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t18: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t19: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t20: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t21: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t22: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t23: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t24: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t25: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t26: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t27: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t28: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t29: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t30: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t31: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t32: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t33: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t34: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t36: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t38: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t40: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t42: Fail
+tests/co19/src/Language/Expressions/Strings/multi_line_t44: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t02: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t03: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t04: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t05: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t06: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t07: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t10: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t11: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t12: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t13: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t14: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t15: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t16: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t17: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t18: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t19: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t20: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t21: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t22: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t23: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t24: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t25: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t26: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t27: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t28: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t29: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t30: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t31: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t32: Fail
+tests/co19/src/Language/Expressions/Strings/string_literal_t33: Fail
+tests/co19/src/Language/Expressions/This/definition_t01: Fail
+tests/co19/src/Language/Expressions/This/definition_t02: Fail
+tests/co19/src/Language/Expressions/This/definition_t03: Fail
+tests/co19/src/Language/Expressions/This/definition_t04: Fail
+tests/co19/src/Language/Expressions/This/placement_t02: Fail
+tests/co19/src/Language/Expressions/Type_Cast/syntax_t02: Fail
+tests/co19/src/Language/Expressions/Type_Cast/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Type_Cast/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Type_Cast/syntax_t06: Fail
+tests/co19/src/Language/Expressions/Type_Test/syntax_t03: Fail
+tests/co19/src/Language/Expressions/Type_Test/syntax_t05: Fail
+tests/co19/src/Language/Expressions/Unary_Expressions/syntax_t24: Fail
+tests/co19/src/Language/Expressions/Unary_Expressions/syntax_t25: Fail
+tests/co19/src/Language/Expressions/Unary_Expressions/syntax_t26: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t04: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t05: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t08: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t09: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t12: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t13: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/Optional_Formals/syntax_t15: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t02: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t03: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t06: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t07: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t08: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t09: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t10: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t13: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t14: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t15: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t16: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t17: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t20: Fail
+tests/co19/src/Language/Functions/Formal_Parameters/syntax_t21: Fail
+tests/co19/src/Language/Functions/Function_Declarations/static_preface_t01: Fail
+tests/co19/src/Language/Functions/Function_Declarations/static_preface_t02: Fail
+tests/co19/src/Language/Functions/syntax_t06: Fail
+tests/co19/src/Language/Functions/syntax_t07: Fail
+tests/co19/src/Language/Functions/syntax_t08: Fail
+tests/co19/src/Language/Functions/syntax_t09: Fail
+tests/co19/src/Language/Functions/syntax_t10: Fail
+tests/co19/src/Language/Functions/syntax_t12: Fail
+tests/co19/src/Language/Functions/syntax_t13: Fail
+tests/co19/src/Language/Functions/syntax_t14: Fail
+tests/co19/src/Language/Functions/syntax_t15: Fail
+tests/co19/src/Language/Functions/syntax_t16: Fail
+tests/co19/src/Language/Functions/syntax_t17: Fail
+tests/co19/src/Language/Functions/syntax_t18: Fail
+tests/co19/src/Language/Functions/syntax_t19: Fail
+tests/co19/src/Language/Functions/syntax_t20: Fail
+tests/co19/src/Language/Functions/syntax_t21: Fail
+tests/co19/src/Language/Functions/syntax_t23: Fail
+tests/co19/src/Language/Functions/syntax_t24: Fail
+tests/co19/src/Language/Functions/syntax_t25: Fail
+tests/co19/src/Language/Functions/syntax_t28: Fail
+tests/co19/src/Language/Functions/syntax_t29: Fail
+tests/co19/src/Language/Functions/syntax_t30: Fail
+tests/co19/src/Language/Functions/syntax_t32: Fail
+tests/co19/src/Language/Functions/syntax_t33: Fail
+tests/co19/src/Language/Functions/syntax_t34: Fail
+tests/co19/src/Language/Functions/syntax_t35: Fail
+tests/co19/src/Language/Generics/syntax_t05: Fail
+tests/co19/src/Language/Generics/syntax_t06: Fail
+tests/co19/src/Language/Generics/syntax_t07: Fail
+tests/co19/src/Language/Generics/syntax_t08: Fail
+tests/co19/src/Language/Generics/syntax_t10: Fail
+tests/co19/src/Language/Generics/syntax_t11: Fail
+tests/co19/src/Language/Generics/syntax_t12: Fail
+tests/co19/src/Language/Generics/syntax_t13: Fail
+tests/co19/src/Language/Generics/syntax_t14: Fail
+tests/co19/src/Language/Generics/syntax_t15: Fail
+tests/co19/src/Language/Generics/syntax_t17: Fail
+tests/co19/src/Language/Interfaces/Superinterfaces/definition_t05: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Exports/syntax_t01_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Exports/syntax_t04_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Exports/syntax_t05_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Exports/syntax_t06_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/namespace_changes_t07: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/namespace_changes_t08: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t01: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t02: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t03: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t04: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t05: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t06: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t07: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t08: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t09: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t10: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t11: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t12: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t13: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t14: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t16: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t17: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t18: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t19: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t20: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t21: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t22: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t23: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t24: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t27: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t28: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t29: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t30: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t31: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t32: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t33: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t34: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t39: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t40: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t42: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Imports/syntax_t43: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/part_4: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/part_6: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/part_7: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/part_8: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/syntax_t02: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/syntax_t03: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/syntax_t04: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/syntax_t05: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/syntax_t07: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Parts/syntax_t08: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/syntax_t01: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/syntax_t02: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/syntax_t03: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/syntax_t04: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/syntax_t09: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/syntax_t13: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t02: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t03: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t04: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t05: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t06: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t07: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t08: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t09: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t10: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t11: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t12: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t13: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t14: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t15: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t16: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t17: Fail
+tests/co19/src/Language/Libraries_and_Scripts/Scripts/top_level_syntax_t18: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t15_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t16_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t17_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t18_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t19_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t20_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t21_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t22_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t23_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t24_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t25_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t26_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t27_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t28: Fail
+tests/co19/src/Language/Libraries_and_Scripts/definition_syntax_t29_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t02_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t03_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t04_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t05_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t06_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t07_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t08_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t09_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t10_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t11_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t12_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t13_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t14_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t15_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t16_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t17_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t18_lib: Fail
+tests/co19/src/Language/Libraries_and_Scripts/top_level_syntax_t19_lib: Fail
+tests/co19/src/Language/Metadata/before_type_param_t01: Fail
+tests/co19/src/Language/Metadata/compilation_t05: Fail
+tests/co19/src/Language/Metadata/compilation_t06: Fail
+tests/co19/src/Language/Metadata/compilation_t07: Fail
+tests/co19/src/Language/Metadata/syntax_t04: Fail
+tests/co19/src/Language/Metadata/syntax_t05: Fail
+tests/co19/src/Language/Metadata/syntax_t06: Fail
+tests/co19/src/Language/Metadata/syntax_t07: Fail
+tests/co19/src/Language/Metadata/syntax_t08: Fail
+tests/co19/src/Language/Mixins/Mixin_Application/deferred_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/documentation_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/multi_line_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/single_line_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/single_line_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/single_line_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/single_line_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Comments/single_line_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/assert_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/break_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/case_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/catch_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/class_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/const_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/continue_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/default_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/do_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/else_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/enum_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/extends_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/false_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/final_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/finally_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/for_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/if_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/in_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/is_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/new_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/null_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/rethrow_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/return_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/super_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/switch_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/this_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/throw_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/true_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/try_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/var_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/void_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/while_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/whitespace_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/whitespace_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/whitespace_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_lib: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t10: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/Reserved_Words/with_t11: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/unicode_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t01: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t02: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t03: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t04: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t05: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t06: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t07: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t08: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t09: Fail
+tests/co19/src/Language/Reference/Lexical_Rules/whitespace_t11: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_07_equality_t02: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_07_equality_t03: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_07_equality_t05: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t02: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t03: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t05: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t06: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t08: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t09: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t11: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t12: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t14: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t16: Fail
+tests/co19/src/Language/Reference/Operator_Precedence/precedence_08_relational_t18: Fail
+tests/co19/src/Language/Statements/Assert/syntax_t01: Fail
+tests/co19/src/Language/Statements/Assert/syntax_t02: Fail
+tests/co19/src/Language/Statements/Assert/syntax_t03: Fail
+tests/co19/src/Language/Statements/Assert/syntax_t04: Fail
+tests/co19/src/Language/Statements/Assert/syntax_t05: Fail
+tests/co19/src/Language/Statements/Blocks/execution_t04: Fail
+tests/co19/src/Language/Statements/Blocks/execution_t05: Fail
+tests/co19/src/Language/Statements/Break/syntax_t01: Fail
+tests/co19/src/Language/Statements/Continue/syntax_t01: Fail
+tests/co19/src/Language/Statements/Continue/syntax_t02: Fail
+tests/co19/src/Language/Statements/Do/syntax_t01: Fail
+tests/co19/src/Language/Statements/Do/syntax_t02: Fail
+tests/co19/src/Language/Statements/Do/syntax_t03: Fail
+tests/co19/src/Language/Statements/Do/syntax_t04: Fail
+tests/co19/src/Language/Statements/Do/syntax_t05: Fail
+tests/co19/src/Language/Statements/Do/syntax_t06: Fail
+tests/co19/src/Language/Statements/Do/syntax_t07: Fail
+tests/co19/src/Language/Statements/Expression_Statements/syntax_t02: Fail
+tests/co19/src/Language/Statements/Expression_Statements/syntax_t07: Fail
+tests/co19/src/Language/Statements/Expression_Statements/syntax_t12: Fail
+tests/co19/src/Language/Statements/Expression_Statements/syntax_t13: Fail
+tests/co19/src/Language/Statements/For/Asynchronous_For_in/syntax_t01: Fail
+tests/co19/src/Language/Statements/For/Asynchronous_For_in/syntax_t03: Fail
+tests/co19/src/Language/Statements/For/syntax_t01: Fail
+tests/co19/src/Language/Statements/For/syntax_t02: Fail
+tests/co19/src/Language/Statements/For/syntax_t03: Fail
+tests/co19/src/Language/Statements/For/syntax_t04: Fail
+tests/co19/src/Language/Statements/For/syntax_t05: Fail
+tests/co19/src/Language/Statements/For/syntax_t06: Fail
+tests/co19/src/Language/Statements/For/syntax_t08: Fail
+tests/co19/src/Language/Statements/For/syntax_t10: Fail
+tests/co19/src/Language/Statements/For/syntax_t14: Fail
+tests/co19/src/Language/Statements/For/syntax_t15: Fail
+tests/co19/src/Language/Statements/For/syntax_t17: Fail
+tests/co19/src/Language/Statements/If/syntax_t01: Fail
+tests/co19/src/Language/Statements/If/syntax_t02: Fail
+tests/co19/src/Language/Statements/If/syntax_t03: Fail
+tests/co19/src/Language/Statements/If/syntax_t04: Fail
+tests/co19/src/Language/Statements/If/syntax_t05: Fail
+tests/co19/src/Language/Statements/If/syntax_t06: Fail
+tests/co19/src/Language/Statements/If/syntax_t07: Fail
+tests/co19/src/Language/Statements/If/syntax_t08: Fail
+tests/co19/src/Language/Statements/Labels/scope_t03: Fail
+tests/co19/src/Language/Statements/Labels/syntax_t02: Fail
+tests/co19/src/Language/Statements/Labels/syntax_t04: Fail
+tests/co19/src/Language/Statements/Labels/syntax_t06: Fail
+tests/co19/src/Language/Statements/Labels/syntax_t07: Fail
+tests/co19/src/Language/Statements/Labels/syntax_t08: Fail
+tests/co19/src/Language/Statements/Labels/syntax_t09: Fail
+tests/co19/src/Language/Statements/Local_Function_Declaration/syntax_t02: Fail
+tests/co19/src/Language/Statements/Local_Function_Declaration/syntax_t03: Fail
+tests/co19/src/Language/Statements/Local_Variable_Declaration/syntax_t03: Fail
+tests/co19/src/Language/Statements/Local_Variable_Declaration/syntax_t04: Fail
+tests/co19/src/Language/Statements/Local_Variable_Declaration/syntax_t13: Fail
+tests/co19/src/Language/Statements/Return/syntax_t03: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t04: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t05: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t06: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t07: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t08: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t09: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t10: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t11: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t12: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t14: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t15: Fail
+tests/co19/src/Language/Statements/Switch/syntax_t18: Fail
+tests/co19/src/Language/Statements/Try/syntax_t02: Fail
+tests/co19/src/Language/Statements/Try/syntax_t03: Fail
+tests/co19/src/Language/Statements/Try/syntax_t04: Fail
+tests/co19/src/Language/Statements/Try/syntax_t07: Fail
+tests/co19/src/Language/Statements/Try/syntax_t08: Fail
+tests/co19/src/Language/Statements/Try/syntax_t09: Fail
+tests/co19/src/Language/Statements/Try/syntax_t10: Fail
+tests/co19/src/Language/Statements/Try/syntax_t11: Fail
+tests/co19/src/Language/Statements/Try/syntax_t16: Fail
+tests/co19/src/Language/Statements/Try/syntax_t17: Fail
+tests/co19/src/Language/Statements/Try/syntax_t18: Fail
+tests/co19/src/Language/Statements/Try/syntax_t19: Fail
+tests/co19/src/Language/Statements/Try/syntax_t20: Fail
+tests/co19/src/Language/Statements/Try/syntax_t21: Fail
+tests/co19/src/Language/Statements/Try/syntax_t22: Fail
+tests/co19/src/Language/Statements/While/syntax_t01: Fail
+tests/co19/src/Language/Statements/While/syntax_t02: Fail
+tests/co19/src/Language/Statements/While/syntax_t03: Fail
+tests/co19/src/Language/Statements/While/syntax_t04: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/location_t01: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/location_t03: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/location_t05: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/syntax_t07: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/syntax_t08: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/syntax_t09: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield/syntax_t10: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield_Each/syntax_t07: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield_Each/syntax_t08: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield_Each/syntax_t09: Fail
+tests/co19/src/Language/Statements/Yield_and_Yield_Each/Yield_Each/syntax_t10: Fail
+tests/co19/src/Language/Types/Static_Types/syntax_t01: Fail
+tests/co19/src/Language/Types/Static_Types/syntax_t02: Fail
+tests/co19/src/Language/Types/Static_Types/syntax_t03: Fail
+tests/co19/src/Language/Types/Static_Types/syntax_t04: Fail
+tests/co19/src/Language/Types/Static_Types/syntax_t05: Fail
+tests/co19/src/Language/Types/Static_Types/syntax_t07: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/param_default_value_t01: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/param_default_value_t04: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/param_default_value_t05: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t02: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t03: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t04: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t05: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t06: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t07: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t08: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t09: Fail
+tests/co19/src/Language/Types/Type_Declarations/Typedef/syntax_t10: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t01: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t03: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t04: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t05: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t06: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t07: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t08: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t09: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t10: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t11: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t12: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t13: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t14: Fail
+tests/co19/src/Language/Types/Type_Void/syntax_t15: Fail
+tests/co19/src/Language/Variables/library_variable_t01_lib: Fail
+tests/co19/src/Language/Variables/library_variable_t02: Fail
+tests/co19/src/Language/Variables/library_variable_t03: Fail
+tests/co19/src/Language/Variables/library_variable_t04: Fail
+tests/co19/src/Language/Variables/library_variable_t05: Fail
+tests/co19/src/Language/Variables/library_variable_t06: Fail
+tests/co19/src/Language/Variables/library_variable_t07: Fail
+tests/co19/src/Language/Variables/static_variable_t02: Fail
+tests/co19/src/Language/Variables/syntax_t03: Fail
+tests/co19/src/Language/Variables/syntax_t06: Fail
+tests/co19/src/Language/Variables/syntax_t07: Fail
+tests/co19/src/Language/Variables/syntax_t09: Fail
+tests/co19/src/Language/Variables/syntax_t10: Fail
+tests/co19/src/Language/Variables/syntax_t11: Fail
+tests/co19/src/Language/Variables/syntax_t15: Fail
+tests/co19/src/Language/Variables/syntax_t16: Fail
+tests/co19/src/Language/Variables/syntax_t17: Fail
+tests/co19/src/Language/Variables/syntax_t18: Fail
+tests/co19/src/Language/Variables/syntax_t19: Fail
+tests/co19/src/Language/Variables/syntax_t20: Fail
+tests/co19/src/Language/Variables/syntax_t21: Fail
+tests/co19/src/Language/Variables/syntax_t22: Fail
+tests/co19/src/Language/Variables/syntax_t23: Fail
+tests/co19/src/LibTest/html/HttpRequest/responseType_A01_t03: Fail
+tests/co19/src/WebPlatformTest/dom/nodes/DOMImplementation-createHTMLDocument_t01: Fail
+tests/co19/src/WebPlatformTest/dom/nodes/Document-createElement_t01: Fail
+tests/co19/src/WebPlatformTest/dom/nodes/Element-childElementCount-nochild_t01: Fail
+tests/compiler/dart2js/data/one_line_dart_program: Fail
+tests/compiler/dart2js_extra/LayoutTests_fast_mediastream_getusermedia_t01_test: Fail
+tests/compiler/dart2js_extra/deferred_custom_loader_test: Fail
+tests/compiler/dart2js_extra/empty_negative_test: Fail
+tests/compiler/dart2js_extra/invalid_annotation2_test: Fail
+tests/compiler/dart2js_extra/invalid_annotation_test: Fail
+tests/compiler/dart2js_extra/invalid_length_negative_test: Fail
+tests/compiler/dart2js_extra/switch_test: Fail
+tests/compiler/dart2js_extra/timer_negative_test: Fail
+tests/compiler/dart2js_extra/typed_locals_test: Fail
+tests/compiler/dart2js_native/abstract_class_test: Fail
+tests/compiler/dart2js_native/bound_closure_test: Fail
+tests/compiler/dart2js_native/browser_compat_1_prepatched_test: Fail
+tests/compiler/dart2js_native/browser_compat_1_unpatched_test: Fail
+tests/compiler/dart2js_native/browser_compat_2_test: Fail
+tests/compiler/dart2js_native/core_type_check_native_test: Fail
+tests/compiler/dart2js_native/dispatch_property_initialization_test: Fail
+tests/compiler/dart2js_native/downcast_test: Fail
+tests/compiler/dart2js_native/error_safeToString_test: Fail
+tests/compiler/dart2js_native/event_loop_test: Fail
+tests/compiler/dart2js_native/fake_thing_2_test: Fail
+tests/compiler/dart2js_native/fake_thing_test: Fail
+tests/compiler/dart2js_native/field_type2_test: Fail
+tests/compiler/dart2js_native/field_type_test: Fail
+tests/compiler/dart2js_native/fixup_get_tag_test: Fail
+tests/compiler/dart2js_native/hash_code_test: Fail
+tests/compiler/dart2js_native/issue9182_test: Fail
+tests/compiler/dart2js_native/jsobject_test: Fail
+tests/compiler/dart2js_native/native_call_arity1_frog_test: Fail
+tests/compiler/dart2js_native/native_call_arity2_frog_test: Fail
+tests/compiler/dart2js_native/native_call_arity3_frog_test: Fail
+tests/compiler/dart2js_native/native_checked_arguments1_frog_test: Fail
+tests/compiler/dart2js_native/native_checked_fields_frog_test: Fail
+tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test: Fail
+tests/compiler/dart2js_native/native_class_fields_2_test: Fail
+tests/compiler/dart2js_native/native_class_fields_3_test: Fail
+tests/compiler/dart2js_native/native_class_fields_test: Fail
+tests/compiler/dart2js_native/native_class_inheritance1_frog_test: Fail
+tests/compiler/dart2js_native/native_class_inheritance2_frog_test: Fail
+tests/compiler/dart2js_native/native_class_inheritance3_frog_test: Fail
+tests/compiler/dart2js_native/native_class_inheritance4_frog_test: Fail
+tests/compiler/dart2js_native/native_class_is_check1_frog_test: Fail
+tests/compiler/dart2js_native/native_class_is_check3_frog_test: Fail
+tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test: Fail
+tests/compiler/dart2js_native/native_closure_identity_frog_test: Fail
+tests/compiler/dart2js_native/native_constructor_name_test: Fail
+tests/compiler/dart2js_native/native_equals_frog_test: Fail
+tests/compiler/dart2js_native/native_exception2_test: Fail
+tests/compiler/dart2js_native/native_exceptions1_frog_test: Fail
+tests/compiler/dart2js_native/native_field_invocation2_test: Fail
+tests/compiler/dart2js_native/native_field_invocation3_test: Fail
+tests/compiler/dart2js_native/native_field_invocation4_test: Fail
+tests/compiler/dart2js_native/native_field_invocation5_test: Fail
+tests/compiler/dart2js_native/native_field_invocation6_test: Fail
+tests/compiler/dart2js_native/native_field_invocation_test: Fail
+tests/compiler/dart2js_native/native_field_name_test: Fail
+tests/compiler/dart2js_native/native_field_optimization_test: Fail
+tests/compiler/dart2js_native/native_field_rename_1_frog_test: Fail
+tests/compiler/dart2js_native/native_field_rename_2_frog_test: Fail
+tests/compiler/dart2js_native/native_library_same_name_used_frog_test: Fail
+tests/compiler/dart2js_native/native_library_same_name_used_lib2: Fail
+tests/compiler/dart2js_native/native_method_inlining_test: Fail
+tests/compiler/dart2js_native/native_method_rename1_frog_test: Fail
+tests/compiler/dart2js_native/native_method_rename2_frog_test: Fail
+tests/compiler/dart2js_native/native_method_rename3_frog_test: Fail
+tests/compiler/dart2js_native/native_method_with_keyword_name_test: Fail
+tests/compiler/dart2js_native/native_missing_method1_frog_test: Fail
+tests/compiler/dart2js_native/native_missing_method2_frog_test: Fail
+tests/compiler/dart2js_native/native_mixin_field_test: Fail
+tests/compiler/dart2js_native/native_mixin_multiple2_test: Fail
+tests/compiler/dart2js_native/native_mixin_multiple3_test: Fail
+tests/compiler/dart2js_native/native_mixin_multiple_test: Fail
+tests/compiler/dart2js_native/native_mixin_test: Fail
+tests/compiler/dart2js_native/native_mixin_with_plain_test: Fail
+tests/compiler/dart2js_native/native_named_constructors2_frog_test: Fail
+tests/compiler/dart2js_native/native_named_constructors3_frog_test: Fail
+tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test: Fail
+tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test: Fail
+tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test: Fail
+tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test: Fail
+tests/compiler/dart2js_native/native_no_such_method_exception_frog_test: Fail
+tests/compiler/dart2js_native/native_novel_html_test: Fail
+tests/compiler/dart2js_native/native_null_closure_frog_test: Fail
+tests/compiler/dart2js_native/native_null_frog_test: Fail
+tests/compiler/dart2js_native/native_property_frog_test: Fail
+tests/compiler/dart2js_native/native_testing: Fail
+tests/compiler/dart2js_native/native_to_string_frog_test: Fail
+tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test: Fail
+tests/compiler/dart2js_native/native_wrapping_function3_frog_test: Fail
+tests/compiler/dart2js_native/native_wrapping_function_frog_test: Fail
+tests/compiler/dart2js_native/oddly_named_fields_test: Fail
+tests/compiler/dart2js_native/runtimetype_test: Fail
+tests/compiler/dart2js_native/static_methods_test: Fail
+tests/compiler/dart2js_native/subclassing_1_test: Fail
+tests/compiler/dart2js_native/subclassing_2_test: Fail
+tests/compiler/dart2js_native/subclassing_3_test: Fail
+tests/compiler/dart2js_native/subclassing_4_test: Fail
+tests/compiler/dart2js_native/subclassing_5_test: Fail
+tests/compiler/dart2js_native/subclassing_constructor_1_test: Fail
+tests/compiler/dart2js_native/subclassing_super_call_test: Fail
+tests/compiler/dart2js_native/subclassing_super_field_1_test: Fail
+tests/compiler/dart2js_native/subclassing_super_field_2_test: Fail
+tests/compiler/dart2js_native/subclassing_type_test: Fail
+tests/compiler/dart2js_native/super_call_test: Fail
+tests/compiler/dart2js_native/super_property_test: Fail
+tests/corelib/from_environment_const_type_test: Fail
+tests/corelib/from_environment_const_type_undefined_test: Fail
+tests/corelib/symbol_reserved_word_test: Fail
+tests/corelib_strong/from_environment_const_type_test: Fail
+tests/corelib_strong/from_environment_const_type_undefined_test: Fail
+tests/corelib_strong/symbol_reserved_word_test: Fail
+tests/language/abstract_syntax_test: Fail
+tests/language/application_negative_test: Fail
+tests/language/arg_param_trailing_comma_test: Fail
+tests/language/argument_definition_test: Fail
+tests/language/assert_initializer_test: Fail
+tests/language/assign_instance_method_negative_test: Fail
+tests/language/async_await_syntax_test: Fail
+tests/language/await_backwards_compatibility_test: Fail
+tests/language/bad_constructor_test: Fail
+tests/language/bad_initializer1_negative_test: Fail
+tests/language/bad_initializer2_negative_test: Fail
+tests/language/bad_named_constructor_negative_test: Fail
+tests/language/bad_typedef_test: Fail
+tests/language/black_listed_test: Fail
+tests/language/body_less_constructor_wrong_arg_negative_test: Fail
+tests/language/built_in_identifier_test: Fail
+tests/language/cascade_test: Fail
+tests/language/class_cycle2_test: Fail
+tests/language/class_keyword_test: Fail
+tests/language/class_syntax_test: Fail
+tests/language/closure_call_wrong_argument_count_negative_test: Fail
+tests/language/compile_time_constant13_test: Fail
+tests/language/const_counter_negative_test: Fail
+tests/language/const_getter_test: Fail
+tests/language/const_native_factory_test: Fail
+tests/language/const_optional_args_negative_test: Fail
+tests/language/constructor3_negative_test: Fail
+tests/language/constructor_call_wrong_argument_count_negative_test: Fail
+tests/language/constructor_initializer_test: Fail
+tests/language/constructor_name_test: Fail
+tests/language/constructor_redirect1_negative_test: Fail
+tests/language/constructor_redirect2_negative_test: Fail
+tests/language/constructor_setter_negative_test: Fail
+tests/language/covariant_test: Fail
+tests/language/cyclic_typedef_test: Fail
+tests/language/deferred_type_dependency_test: Fail
+tests/language/duplicate_export_negative_test: Fail
+tests/language/duplicate_interface_negative_test: Fail
+tests/language/enum_is_keyword_test: Fail
+tests/language/enum_syntax_test: Fail
+tests/language/export_ambiguous_main_negative_test: Fail
+tests/language/extend_type_parameter2_negative_test: Fail
+tests/language/extend_type_parameter_negative_test: Fail
+tests/language/external_test: Fail
+tests/language/factory2_negative_test: Fail
+tests/language/factory_negative_test: Fail
+tests/language/field1_negative_test: Fail
+tests/language/field2_negative_test: Fail
+tests/language/field3a_negative_test: Fail
+tests/language/field4_negative_test: Fail
+tests/language/field5_negative_test: Fail
+tests/language/field6_negative_test: Fail
+tests/language/field6a_negative_test: Fail
+tests/language/field_method4_negative_test: Fail
+tests/language/function_syntax_test: Fail
+tests/language/function_type_parameter2_negative_test: Fail
+tests/language/function_type_parameter_negative_test: Fail
+tests/language/get_set_syntax_test: Fail
+tests/language/getter_declaration_negative_test: Fail
+tests/language/illegal_declaration_test: Fail
+tests/language/import_combinators_negative_test: Fail
+tests/language/inst_field_initializer1_negative_test: Fail
+tests/language/instance_call_wrong_argument_count_negative_test: Fail
+tests/language/instance_method2_negative_test: Fail
+tests/language/instance_method_negative_test: Fail
+tests/language/interface2_negative_test: Fail
+tests/language/interface_cycle_test: Fail
+tests/language/interface_static_non_final_fields_negative_test: Fail
+tests/language/keyword_type_expression_test: Fail
+tests/language/label2_negative_test: Fail
+tests/language/label3_negative_test: Fail
+tests/language/label5_negative_test: Fail
+tests/language/label6_negative_test: Fail
+tests/language/library_negative_test: Fail
+tests/language/list_literal2_negative_test: Fail
+tests/language/list_literal_syntax_test: Fail
+tests/language/literal_unary_plus_test: Fail
+tests/language/main_test: Fail
+tests/language/malformed_inheritance_test: Fail
+tests/language/malformed_test: Fail
+tests/language/map_literal2_negative_test: Fail
+tests/language/metadata_test: Fail
+tests/language/method_name_test: Fail
+tests/language/method_override2_test: Fail
+tests/language/mixin_forwarding_constructor4_test: Fail
+tests/language/mixin_illegal_syntax_test: Fail
+tests/language/mixin_invalid_inheritance1_test: Fail
+tests/language/mixin_supertype_subclass2_test: Fail
+tests/language/mixin_supertype_subclass4_test: Fail
+tests/language/mixin_supertype_subclass_test: Fail
+tests/language/named_constructor_test: Fail
+tests/language/named_parameters_aggregated_test: Fail
+tests/language/no_such_method_negative_test: Fail
+tests/language/non_const_super_negative_test: Fail
+tests/language/null_test: Fail
+tests/language/number_identifier_test: Fail
+tests/language/override_field_method1_negative_test: Fail
+tests/language/override_field_method2_negative_test: Fail
+tests/language/override_field_method4_negative_test: Fail
+tests/language/override_field_method5_negative_test: Fail
+tests/language/override_inheritance_generic_test: Fail
+tests/language/parameter_default_test: Fail
+tests/language/parameter_initializer1_negative_test: Fail
+tests/language/parameter_initializer2_negative_test: Fail
+tests/language/parameter_initializer3_negative_test: Fail
+tests/language/parameter_initializer4_negative_test: Fail
+tests/language/parameter_initializer5_negative_test: Fail
+tests/language/parameter_initializer6_negative_test: Fail
+tests/language/prefix10_negative_test: Fail
+tests/language/prefix11_negative_test: Fail
+tests/language/prefix12_negative_test: Fail
+tests/language/prefix13_negative_test: Fail
+tests/language/prefix15_negative_test: Fail
+tests/language/prefix1_negative_test: Fail
+tests/language/prefix2_negative_test: Fail
+tests/language/prefix3_negative_test: Fail
+tests/language/prefix4_negative_test: Fail
+tests/language/prefix5_negative_test: Fail
+tests/language/prefix6_negative_test: Fail
+tests/language/prefix7_negative_test: Fail
+tests/language/prefix8_negative_test: Fail
+tests/language/private_member1_negative_test: Fail
+tests/language/private_member2_negative_test: Fail
+tests/language/private_member3_negative_test: Fail
+tests/language/regress_23051_test: Fail
+tests/language/script1_negative_test: Fail
+tests/language/script2_negative_test: Fail
+tests/language/setter_declaration2_negative_test: Fail
+tests/language/setter_declaration_negative_test: Fail
+tests/language/source_self_negative_test: Fail
+tests/language/static_call_wrong_argument_count_negative_test: Fail
+tests/language/static_parameter_test: Fail
+tests/language/static_top_level_test: Fail
+tests/language/string_interpolation1_test: Fail
+tests/language/string_interpolation2_test: Fail
+tests/language/string_interpolation3_test: Fail
+tests/language/string_interpolation4_test: Fail
+tests/language/string_interpolation5_test: Fail
+tests/language/string_interpolation6_test: Fail
+tests/language/string_interpolation9_test: Fail
+tests/language/string_unicode1_negative_test: Fail
+tests/language/string_unicode2_negative_test: Fail
+tests/language/string_unicode3_negative_test: Fail
+tests/language/string_unicode4_negative_test: Fail
+tests/language/switch1_negative_test: Fail
+tests/language/switch3_negative_test: Fail
+tests/language/switch4_negative_test: Fail
+tests/language/switch5_negative_test: Fail
+tests/language/switch7_negative_test: Fail
+tests/language/sync_generator2_test: Fail
+tests/language/syntax_test: Fail
+tests/language/tearoff_basic_test: Fail
+tests/language/tearoff_constructor_basic_test: Fail
+tests/language/try_catch_on_syntax_test: Fail
+tests/language/try_catch_syntax_test: Fail
+tests/language/type_variable_bounds2_test: Fail
+tests/language/type_variable_static_context_negative_test: Fail
+tests/language/unbalanced_brace_test: Fail
+tests/language/unresolved_in_factory_negative_test: Fail
+tests/language/unresolved_top_level_method_negative_test: Fail
+tests/language/unresolved_top_level_var_negative_test: Fail
+tests/language/unsigned_right_shift_test: Fail
+tests/language/variable_declaration_metadata_test: Fail
+tests/language/vm/debug_break_enabled_vm_test: Fail
+tests/language/vm/debug_break_vm_test: Fail
+tests/language_strong/abstract_syntax_test: Fail
+tests/language_strong/application_negative_test: Fail
+tests/language_strong/argument_definition_test: Fail
+tests/language_strong/assign_instance_method_negative_test: Fail
+tests/language_strong/async_await_syntax_test: Fail
+tests/language_strong/await_backwards_compatibility_test: Fail
+tests/language_strong/bad_constructor_test: Fail
+tests/language_strong/bad_initializer1_negative_test: Fail
+tests/language_strong/bad_initializer2_negative_test: Fail
+tests/language_strong/bad_named_constructor_negative_test: Fail
+tests/language_strong/black_listed_test: Fail
+tests/language_strong/body_less_constructor_wrong_arg_negative_test: Fail
+tests/language_strong/built_in_identifier_prefix_test: Fail
+tests/language_strong/built_in_identifier_test: Fail
+tests/language_strong/cascade_test: Fail
+tests/language_strong/class_cycle2_test: Fail
+tests/language_strong/class_keyword_test: Fail
+tests/language_strong/class_syntax_test: Fail
+tests/language_strong/closure_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/compile_time_constant13_test: Fail
+tests/language_strong/const_counter_negative_test: Fail
+tests/language_strong/const_native_factory_test: Fail
+tests/language_strong/const_optional_args_negative_test: Fail
+tests/language_strong/constructor3_negative_test: Fail
+tests/language_strong/constructor_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/constructor_initializer_test: Fail
+tests/language_strong/constructor_name_test: Fail
+tests/language_strong/constructor_redirect1_negative_test: Fail
+tests/language_strong/constructor_redirect2_negative_test: Fail
+tests/language_strong/constructor_setter_negative_test: Fail
+tests/language_strong/cyclic_typedef_test: Fail
+tests/language_strong/deferred_type_dependency_test: Fail
+tests/language_strong/duplicate_export_negative_test: Fail
+tests/language_strong/duplicate_interface_negative_test: Fail
+tests/language_strong/enum_is_keyword_test: Fail
+tests/language_strong/enum_syntax_test: Fail
+tests/language_strong/export_ambiguous_main_negative_test: Fail
+tests/language_strong/extend_type_parameter2_negative_test: Fail
+tests/language_strong/extend_type_parameter_negative_test: Fail
+tests/language_strong/external_test: Fail
+tests/language_strong/factory2_negative_test: Fail
+tests/language_strong/factory_negative_test: Fail
+tests/language_strong/field1_negative_test: Fail
+tests/language_strong/field2_negative_test: Fail
+tests/language_strong/field3a_negative_test: Fail
+tests/language_strong/field4_negative_test: Fail
+tests/language_strong/field5_negative_test: Fail
+tests/language_strong/field6_negative_test: Fail
+tests/language_strong/field6a_negative_test: Fail
+tests/language_strong/field_method4_negative_test: Fail
+tests/language_strong/function_syntax_test: Fail
+tests/language_strong/function_type_parameter2_negative_test: Fail
+tests/language_strong/function_type_parameter_negative_test: Fail
+tests/language_strong/get_set_syntax_test: Fail
+tests/language_strong/getter_declaration_negative_test: Fail
+tests/language_strong/illegal_declaration_test: Fail
+tests/language_strong/import_combinators_negative_test: Fail
+tests/language_strong/inst_field_initializer1_negative_test: Fail
+tests/language_strong/instance_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/instance_method2_negative_test: Fail
+tests/language_strong/instance_method_negative_test: Fail
+tests/language_strong/interface2_negative_test: Fail
+tests/language_strong/interface_cycle_test: Fail
+tests/language_strong/interface_static_non_final_fields_negative_test: Fail
+tests/language_strong/keyword_type_expression_test: Fail
+tests/language_strong/label2_negative_test: Fail
+tests/language_strong/label3_negative_test: Fail
+tests/language_strong/label5_negative_test: Fail
+tests/language_strong/label6_negative_test: Fail
+tests/language_strong/library_negative_test: Fail
+tests/language_strong/list_literal2_negative_test: Fail
+tests/language_strong/list_literal_syntax_test: Fail
+tests/language_strong/literal_unary_plus_test: Fail
+tests/language_strong/main_test: Fail
+tests/language_strong/malformed_inheritance_test: Fail
+tests/language_strong/malformed_test: Fail
+tests/language_strong/map_literal2_negative_test: Fail
+tests/language_strong/metadata_test: Fail
+tests/language_strong/method_override2_test: Fail
+tests/language_strong/mixin_forwarding_constructor4_test: Fail
+tests/language_strong/mixin_illegal_syntax_test: Fail
+tests/language_strong/mixin_invalid_inheritance1_test: Fail
+tests/language_strong/named_constructor_test: Fail
+tests/language_strong/named_parameters_aggregated_test: Fail
+tests/language_strong/no_such_method_negative_test: Fail
+tests/language_strong/non_const_super_negative_test: Fail
+tests/language_strong/null_test: Fail
+tests/language_strong/number_identifier_test: Fail
+tests/language_strong/override_field_method1_negative_test: Fail
+tests/language_strong/override_field_method2_negative_test: Fail
+tests/language_strong/override_field_method4_negative_test: Fail
+tests/language_strong/override_field_method5_negative_test: Fail
+tests/language_strong/override_inheritance_generic_test: Fail
+tests/language_strong/parameter_default_test: Fail
+tests/language_strong/parameter_initializer1_negative_test: Fail
+tests/language_strong/parameter_initializer2_negative_test: Fail
+tests/language_strong/parameter_initializer3_negative_test: Fail
+tests/language_strong/parameter_initializer4_negative_test: Fail
+tests/language_strong/parameter_initializer6_negative_test: Fail
+tests/language_strong/prefix10_negative_test: Fail
+tests/language_strong/prefix11_negative_test: Fail
+tests/language_strong/prefix12_negative_test: Fail
+tests/language_strong/prefix13_negative_test: Fail
+tests/language_strong/prefix15_negative_test: Fail
+tests/language_strong/prefix1_negative_test: Fail
+tests/language_strong/prefix2_negative_test: Fail
+tests/language_strong/prefix3_negative_test: Fail
+tests/language_strong/prefix4_negative_test: Fail
+tests/language_strong/prefix5_negative_test: Fail
+tests/language_strong/prefix6_negative_test: Fail
+tests/language_strong/prefix7_negative_test: Fail
+tests/language_strong/prefix8_negative_test: Fail
+tests/language_strong/private_member1_negative_test: Fail
+tests/language_strong/private_member2_negative_test: Fail
+tests/language_strong/private_member3_negative_test: Fail
+tests/language_strong/regress_23051_test: Fail
+tests/language_strong/script1_negative_test: Fail
+tests/language_strong/script2_negative_test: Fail
+tests/language_strong/setter_declaration2_negative_test: Fail
+tests/language_strong/setter_declaration_negative_test: Fail
+tests/language_strong/source_self_negative_test: Fail
+tests/language_strong/static_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/static_parameter_test: Fail
+tests/language_strong/static_top_level_test: Fail
+tests/language_strong/string_interpolation9_test: Fail
+tests/language_strong/string_unicode1_negative_test: Fail
+tests/language_strong/string_unicode2_negative_test: Fail
+tests/language_strong/string_unicode3_negative_test: Fail
+tests/language_strong/string_unicode4_negative_test: Fail
+tests/language_strong/switch1_negative_test: Fail
+tests/language_strong/switch3_negative_test: Fail
+tests/language_strong/switch4_negative_test: Fail
+tests/language_strong/switch5_negative_test: Fail
+tests/language_strong/switch7_negative_test: Fail
+tests/language_strong/sync_generator2_test: Fail
+tests/language_strong/syntax_test: Fail
+tests/language_strong/tearoff_basic_test: Fail
+tests/language_strong/tearoff_constructor_basic_test: Fail
+tests/language_strong/try_catch_on_syntax_test: Fail
+tests/language_strong/try_catch_syntax_test: Fail
+tests/language_strong/type_variable_bounds2_test: Fail
+tests/language_strong/type_variable_static_context_negative_test: Fail
+tests/language_strong/unbalanced_brace_test: Fail
+tests/language_strong/unresolved_in_factory_negative_test: Fail
+tests/language_strong/unresolved_top_level_method_negative_test: Fail
+tests/language_strong/unresolved_top_level_var_negative_test: Fail
+tests/language_strong/unsigned_right_shift_test: Fail
+tests/language_strong/variable_declaration_metadata_test: Fail
+tests/lib/async/future_or_bad_type_test: Fail
+tests/lib/mirrors/metadata_allowed_values_test: Fail
+tests/lib/mirrors/metadata_scope_test: Fail
+tests/lib/mirrors/mirror_in_static_init_test: Fail
+tests/lib/mirrors/other_declarations_location_test: Fail
+tests/lib/mirrors/syntax_error_test: Fail
+tests/lib/mirrors/typevariable_mirror_metadata_test: Fail
+tests/lib_strong/mirrors/metadata_allowed_values_test: Fail
+tests/lib_strong/mirrors/metadata_scope_test: Fail
+tests/lib_strong/mirrors/mirror_in_static_init_test: Fail
+tests/lib_strong/mirrors/other_declarations_location_test: Fail
+tests/lib_strong/mirrors/syntax_error_test: Fail
+tests/lib_strong/mirrors/typevariable_mirror_metadata_test: Fail
+tests/standalone/io/process_exit_negative_test: Fail
+tests/standalone/io/snapshot_fail_script: Fail
+tests/standalone/io/test_extension: Fail
+tests/standalone/io/test_relative_extension: Fail
+tests/standalone/package/sibling_isolate: Fail
+third_party/pkg/linter/test/_data/synthetic/synthetic: Fail
+third_party/pkg/linter/test/rules/cascade_invocations: Fail
+third_party/pkg/resource/test/loader_data_test: Fail
+third_party/pkg/resource/test/loader_file_test: Fail
+third_party/pkg/resource/test/loader_http_test: Fail
diff --git a/pkg/front_end/test/fasta/parser/parser_suite.dart b/pkg/front_end/test/fasta/parser/parser_suite.dart
new file mode 100644
index 0000000..b5c1c03
--- /dev/null
+++ b/pkg/front_end/test/fasta/parser/parser_suite.dart
@@ -0,0 +1,45 @@
+// 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.
+
+import 'package:testing/testing.dart';
+
+import 'package:front_end/src/fasta/scanner.dart';
+
+import 'package:front_end/src/fasta/scanner/testing/scanner_chain.dart';
+
+import 'package:front_end/src/fasta/parser.dart';
+
+Future<ChainContext> createContext(
+    Chain suite, Map<String, String> enviroment) async {
+  return new ScannerContext();
+}
+
+class ScannerContext extends ChainContext {
+  final List<Step> steps = const <Step>[
+      const Read(),
+      const Scan(),
+      const Parse(),
+  ];
+}
+
+class Parse extends Step<ScannerResult, Null, ChainContext> {
+  const Parse();
+
+  String get name => "parse";
+
+  Future<Result<Null>> run(
+      ScannerResult result, ChainContext context) async {
+    try {
+      List<ParserError> errors = parse(result.tokens);
+      if (errors.isNotEmpty) {
+        return fail(null, errors.join("\n"));
+      }
+    } on ParserError catch (e, s) {
+      return fail(null, e, s);
+    }
+    return pass(null);
+  }
+}
+
+main(List<String> arguments) => runMe(arguments, createContext);
diff --git a/pkg/front_end/test/fasta/parser/testing.json b/pkg/front_end/test/fasta/parser/testing.json
new file mode 100644
index 0000000..b3ae4c8
--- /dev/null
+++ b/pkg/front_end/test/fasta/parser/testing.json
@@ -0,0 +1,31 @@
+{
+"":"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": "parser",
+      "kind": "Chain",
+      "source": "parser_suite.dart",
+      "path": "../../",
+      "status": "parser.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+        "README.dart",
+        "xcodebuild/",
+        "tools/sdks/"
+      ]
+    }
+  ],
+  "analyze": {
+    "uris": [
+      "../../../lib/src/fasta/parser/",
+      "../../../lib/src/fasta/parser/bin/"
+    ],
+    "exclude": [
+    ]
+  }
+}
diff --git a/pkg/front_end/test/fasta/platform.dart b/pkg/front_end/test/fasta/platform.dart
new file mode 100644
index 0000000..6fa895d
--- /dev/null
+++ b/pkg/front_end/test/fasta/platform.dart
@@ -0,0 +1,6 @@
+// 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.
+
+main() {
+}
diff --git a/pkg/front_end/test/fasta/platform.dart.dartk.expect b/pkg/front_end/test/fasta/platform.dart.dartk.expect
new file mode 100644
index 0000000..bef6d48
--- /dev/null
+++ b/pkg/front_end/test/fasta/platform.dart.dartk.expect
@@ -0,0 +1,4 @@
+library;
+import self as self;
+
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/platform.dart.direct.expect b/pkg/front_end/test/fasta/platform.dart.direct.expect
new file mode 100644
index 0000000..bef6d48
--- /dev/null
+++ b/pkg/front_end/test/fasta/platform.dart.direct.expect
@@ -0,0 +1,4 @@
+library;
+import self as self;
+
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/platform.dart.outline.expect b/pkg/front_end/test/fasta/platform.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/platform.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/README.md b/pkg/front_end/test/fasta/rasta/README.md
new file mode 100644
index 0000000..738590a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/README.md
@@ -0,0 +1,10 @@
+<!--
+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.
+-->
+# Rasta regression tests
+
+The tests in this directory were copied from [rasta](https://github.com/dart-lang/rasta/tree/dace1ed5964953ce53065fd41eebfa8920419ff0/test/kernel/regression), at commit [dace1ed](https://github.com/dart-lang/rasta/commit/dace1ed5964953ce53065fd41eebfa8920419ff0).
+
+The rasta expectation files `*.dart.txt` have been copied three times to `* .outline.expect`, `*.direct.expect`, and `*.dart.dartk.expect`.
diff --git a/pkg/front_end/test/fasta/rasta/abstract_constructor.dart b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart
new file mode 100644
index 0000000..8caa4ed
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart
@@ -0,0 +1,9 @@
+// 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.
+
+abstract class C {}
+
+main() {
+  new C();
+}
diff --git a/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.dartk.expect
new file mode 100644
index 0000000..94c244e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.dartk.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+}
+static method main() → dynamic {
+  invalid-expression;
+}
diff --git a/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.direct.expect b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.direct.expect
new file mode 100644
index 0000000..125bce0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  throw new core::NoSuchMethodError::•(null, #C, <dynamic>[], <dynamic, dynamic>{}, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.outline.expect b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.outline.expect
new file mode 100644
index 0000000..4fbe7d2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/abstract_constructor.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class C extends core::Object {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart
new file mode 100644
index 0000000..937b755
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart
@@ -0,0 +1,13 @@
+// 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.
+
+class C {
+  const C() : this.x(1);
+  const C.x();
+}
+
+main() {
+  new C();
+  const C();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.dartk.expect
new file mode 100644
index 0000000..397cac6
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.dartk.expect
@@ -0,0 +1,15 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor •() → dynamic
+    : invalid-initializer;
+  const constructor x() → dynamic
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•();
+  const self::C::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.direct.expect
new file mode 100644
index 0000000..76f0894
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.direct.expect
@@ -0,0 +1,15 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor •() → void
+    : invalid-initializer;
+  const constructor x() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•();
+  const self::C::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.outline.expect
new file mode 100644
index 0000000..d8ddaed
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_constructor_redirection.dart.outline.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor •() → void
+    ;
+  const constructor x() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_continue.dart b/pkg/front_end/test/fasta/rasta/bad_continue.dart
new file mode 100644
index 0000000..5399f78
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_continue.dart
@@ -0,0 +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.
+
+main() {
+  continue here;
+  label: continue label;
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_continue.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_continue.dart.dartk.expect
new file mode 100644
index 0000000..049014a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_continue.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  invalid-statement;
+  invalid-statement;
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_continue.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_continue.dart.direct.expect
new file mode 100644
index 0000000..2049fe7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_continue.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  throw new core::_CompileTimeError::•("pkg/front_end/test/fasta/rasta/bad_continue.dart:239: \u0027[31mError: Can't find label 'here'.\u0027[0m");
+  #L1:
+  break #L1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_continue.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_continue.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_continue.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart
new file mode 100644
index 0000000..aea5442
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart
@@ -0,0 +1,15 @@
+// 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.
+
+class A {
+  A(x);
+}
+
+class B extends A {
+}
+
+main() {
+  new B();
+  const B();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.dartk.expect
new file mode 100644
index 0000000..9ef3d02
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.dartk.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → dynamic
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  constructor •() → self::B
+    : invalid-initializer;
+}
+static method main() → dynamic {
+  new self::B::•();
+  invalid-expression;
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.direct.expect
new file mode 100644
index 0000000..9ef3d02
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.direct.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → dynamic
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  constructor •() → self::B
+    : invalid-initializer;
+}
+static method main() → dynamic {
+  new self::B::•();
+  invalid-expression;
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.outline.expect
new file mode 100644
index 0000000..b6c4bf2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_default_constructor.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → void
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart
new file mode 100644
index 0000000..2936518
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart
@@ -0,0 +1,16 @@
+// 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.
+
+class A {
+  A(x);
+}
+
+class B extends A {
+  const B() : super();
+}
+
+main() {
+  new B();
+  const B();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.dartk.expect
new file mode 100644
index 0000000..696ceca
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.dartk.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → dynamic
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  const constructor •() → dynamic
+    : invalid-initializer
+    ;
+}
+static method main() → dynamic {
+  new self::B::•();
+  const self::B::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.direct.expect
new file mode 100644
index 0000000..a0d8311
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.direct.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → void
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  const constructor •() → void
+    : invalid-initializer
+    ;
+}
+static method main() → dynamic {
+  new self::B::•();
+  const self::B::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.outline.expect
new file mode 100644
index 0000000..b8dc013
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_explicit_super_constructor.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → void
+    ;
+}
+class B extends self::A {
+  const constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart
new file mode 100644
index 0000000..e5e539c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart
@@ -0,0 +1,16 @@
+// 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.
+
+class A {
+  A(this.x);
+}
+
+class B extends A {
+  const B();
+}
+
+main() {
+  new B();
+  const B();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.dartk.expect
new file mode 100644
index 0000000..8601a57
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.dartk.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → dynamic
+    : invalid-initializer, super core::Object::•()
+    ;
+}
+class B extends self::A {
+  const constructor •() → dynamic
+    : invalid-initializer
+    ;
+}
+static method main() → dynamic {
+  new self::B::•();
+  const self::B::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.direct.expect
new file mode 100644
index 0000000..8601a57
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.direct.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → dynamic
+    : invalid-initializer, super core::Object::•()
+    ;
+}
+class B extends self::A {
+  const constructor •() → dynamic
+    : invalid-initializer
+    ;
+}
+static method main() → dynamic {
+  new self::B::•();
+  const self::B::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.outline.expect
new file mode 100644
index 0000000..b8dc013
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_implicit_super_constructor.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •(dynamic x) → void
+    ;
+}
+class B extends self::A {
+  const constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_interpolation.dart b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart
new file mode 100644
index 0000000..98fd62e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print(" $x.);
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.dartk.expect
new file mode 100644
index 0000000..1cafd63
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.dartk.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.direct.expect
new file mode 100644
index 0000000..58766fb
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.direct.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  throw "pkg/front_end/test/fasta/rasta/bad_interpolation.dart:246: \u0027[31mError: ErrorKind.ExpectedString {actual: EOF}\u0027[0m";
diff --git a/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_interpolation.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_redirection.dart b/pkg/front_end/test/fasta/rasta/bad_redirection.dart
new file mode 100644
index 0000000..e3b63df
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_redirection.dart
@@ -0,0 +1,15 @@
+// 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.
+
+class Foo {
+  Foo() = Bar;
+}
+
+class Bar extends Foo {
+  factory Bar() => null;
+}
+
+main() {
+  new Foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_redirection.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_redirection.dart.dartk.expect
new file mode 100644
index 0000000..2394a16
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_redirection.dart.dartk.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  constructor •() → dynamic
+    : super core::Object::•()
+    invalid-statement;
+}
+class Bar extends self::Foo {
+  static factory •() → self::Bar
+    return null;
+}
+static method main() → dynamic {
+  new self::Foo::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_redirection.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_redirection.dart.direct.expect
new file mode 100644
index 0000000..2394a16
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_redirection.dart.direct.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  constructor •() → dynamic
+    : super core::Object::•()
+    invalid-statement;
+}
+class Bar extends self::Foo {
+  static factory •() → self::Bar
+    return null;
+}
+static method main() → dynamic {
+  new self::Foo::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_redirection.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_redirection.dart.outline.expect
new file mode 100644
index 0000000..0f04f62
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_redirection.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  constructor •() → void
+    ;
+}
+class Bar extends self::Foo {
+  static factory •() → self::Bar
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart
new file mode 100644
index 0000000..1a26aea
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart
@@ -0,0 +1,12 @@
+// 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.
+
+class C {
+  C() : field = null;
+  set field(value) {}
+}
+
+main() {
+  new C();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.dartk.expect
new file mode 100644
index 0000000..4bccd35
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.dartk.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → dynamic
+    : invalid-initializer, super core::Object::•()
+    ;
+  set field(dynamic value) → dynamic {}
+}
+static method main() → dynamic {
+  new self::C::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.direct.expect
new file mode 100644
index 0000000..a104eb4
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.direct.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : final dynamic #t1 = throw new core::_CompileTimeError::•("pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart:237: \u0027[31mError: Can't use field here.\u0027[0m"), super core::Object::•()
+    ;
+  set field(dynamic value) → dynamic {}
+}
+static method main() → dynamic {
+  new self::C::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.outline.expect
new file mode 100644
index 0000000..e95aa3d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_setter_initializer.dart.outline.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  set field(dynamic value) → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/bad_unicode.dart b/pkg/front_end/test/fasta/rasta/bad_unicode.dart
new file mode 100644
index 0000000..51c6502
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_unicode.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print("\u00"); // Bad Unicode escape, must have 4 hex digits.
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_unicode.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/bad_unicode.dart.dartk.expect
new file mode 100644
index 0000000..06f22f0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_unicode.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(invalid-expression);
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_unicode.dart.direct.expect b/pkg/front_end/test/fasta/rasta/bad_unicode.dart.direct.expect
new file mode 100644
index 0000000..06f22f0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_unicode.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(invalid-expression);
+}
diff --git a/pkg/front_end/test/fasta/rasta/bad_unicode.dart.outline.expect b/pkg/front_end/test/fasta/rasta/bad_unicode.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/bad_unicode.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/breaking_bad.dart b/pkg/front_end/test/fasta/rasta/breaking_bad.dart
new file mode 100644
index 0000000..b82c7ed
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/breaking_bad.dart
@@ -0,0 +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.
+
+main() {
+  break;
+  walt: break walt;
+}
diff --git a/pkg/front_end/test/fasta/rasta/breaking_bad.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/breaking_bad.dart.dartk.expect
new file mode 100644
index 0000000..a5d5ed0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/breaking_bad.dart.dartk.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  invalid-statement;
+  #L1:
+  break #L1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/breaking_bad.dart.direct.expect b/pkg/front_end/test/fasta/rasta/breaking_bad.dart.direct.expect
new file mode 100644
index 0000000..9fd7b92
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/breaking_bad.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  throw new core::_CompileTimeError::•("pkg/front_end/test/fasta/rasta/breaking_bad.dart:230: \u0027[31mError: No target of break.\u0027[0m");
+  #L1:
+  break #L1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/breaking_bad.dart.outline.expect b/pkg/front_end/test/fasta/rasta/breaking_bad.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/breaking_bad.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/cascades.dart b/pkg/front_end/test/fasta/rasta/cascades.dart
new file mode 100644
index 0000000..add829e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/cascades.dart
@@ -0,0 +1,13 @@
+// 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.
+
+class A {
+  add(x) => x;
+}
+
+main() {
+  var a = new A();
+  f(x) => x;
+  a..add(f)('WHAT');
+}
diff --git a/pkg/front_end/test/fasta/rasta/cascades.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/cascades.dart.dartk.expect
new file mode 100644
index 0000000..ef94f0c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/cascades.dart.dartk.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → self::A
+    : super core::Object::•();
+  method add(dynamic x) → dynamic
+    return x;
+}
+static method main() → dynamic {
+  dynamic a = new self::A::•();
+  function f(dynamic x) → dynamic
+    return x;
+  let final dynamic #t1 = a in let final dynamic #t2 = #t1.add(f).call("WHAT") in #t1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/cascades.dart.direct.expect b/pkg/front_end/test/fasta/rasta/cascades.dart.direct.expect
new file mode 100644
index 0000000..8d6f5d1
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/cascades.dart.direct.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method add(dynamic x) → dynamic
+    return x;
+}
+static method main() → dynamic {
+  dynamic a = new self::A::•();
+  function f(dynamic x) → dynamic
+    return x;
+  let final dynamic #t1 = a in let final dynamic #t2 = #t1.add(f).call("WHAT") in #t1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/cascades.dart.outline.expect b/pkg/front_end/test/fasta/rasta/cascades.dart.outline.expect
new file mode 100644
index 0000000..8c76e17
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/cascades.dart.outline.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    ;
+  method add(dynamic x) → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/class_hierarchy.dart b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart
new file mode 100644
index 0000000..81a22f0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart
@@ -0,0 +1,18 @@
+// 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.
+
+class A extends Missing {}
+class B implements Missing {}
+class C = Object with Missing;
+
+class D {
+  factory D() = Missing;
+}
+
+void main() {
+  new A();
+  new B();
+  new C();
+  new D();
+}
diff --git a/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.dartk.expect
new file mode 100644
index 0000000..f8bf742
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.dartk.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → self::A
+    : invalid-initializer;
+}
+class B extends core::Object {
+  constructor •() → self::B
+    : invalid-initializer;
+}
+class C extends core::Object {
+  constructor •() → dynamic
+    : invalid-initializer;
+}
+class D extends core::Object {
+  static factory •() → self::D
+    invalid-statement;
+}
+static method main() → void {
+  new self::A::•();
+  new self::B::•();
+  new self::C::•();
+  invalid-expression.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.direct.expect b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.direct.expect
new file mode 100644
index 0000000..f8bf742
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.direct.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → self::A
+    : invalid-initializer;
+}
+class B extends core::Object {
+  constructor •() → self::B
+    : invalid-initializer;
+}
+class C extends core::Object {
+  constructor •() → dynamic
+    : invalid-initializer;
+}
+class D extends core::Object {
+  static factory •() → self::D
+    invalid-statement;
+}
+static method main() → void {
+  new self::A::•();
+  new self::B::•();
+  new self::C::•();
+  invalid-expression.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.outline.expect b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.outline.expect
new file mode 100644
index 0000000..fb46624
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_hierarchy.dart.outline.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    ;
+}
+class B extends core::Object {
+  constructor •() → void
+    ;
+}
+class C extends core::Object {
+  constructor •() → void
+    ;
+}
+class D extends core::Object {
+  static factory •() → self::D
+    ;
+}
+static method main() → void
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/class_member.dart b/pkg/front_end/test/fasta/rasta/class_member.dart
new file mode 100644
index 0000000..8c81300
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_member.dart
@@ -0,0 +1,17 @@
+// 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.
+
+// Tests that class members are listed in the normal order.
+
+class Foo {
+  a() {}
+  b() {}
+  c() {}
+  var field1;
+  var field2;
+  var field3;
+  Foo.constructor1();
+  Foo.constructor2();
+  Foo.constructor3();
+}
diff --git a/pkg/front_end/test/fasta/rasta/class_member.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/class_member.dart.dartk.expect
new file mode 100644
index 0000000..af49614
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_member.dart.dartk.expect
@@ -0,0 +1,21 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  field dynamic field1;
+  field dynamic field2;
+  field dynamic field3;
+  constructor constructor1() → dynamic
+    : super core::Object::•()
+    ;
+  constructor constructor2() → dynamic
+    : super core::Object::•()
+    ;
+  constructor constructor3() → dynamic
+    : super core::Object::•()
+    ;
+  method a() → dynamic {}
+  method b() → dynamic {}
+  method c() → dynamic {}
+}
diff --git a/pkg/front_end/test/fasta/rasta/class_member.dart.direct.expect b/pkg/front_end/test/fasta/rasta/class_member.dart.direct.expect
new file mode 100644
index 0000000..4f7da5e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_member.dart.direct.expect
@@ -0,0 +1,21 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  field dynamic field1 = null;
+  field dynamic field2 = null;
+  field dynamic field3 = null;
+  constructor constructor1() → void
+    : super core::Object::•()
+    ;
+  constructor constructor2() → void
+    : super core::Object::•()
+    ;
+  constructor constructor3() → void
+    : super core::Object::•()
+    ;
+  method a() → dynamic {}
+  method b() → dynamic {}
+  method c() → dynamic {}
+}
diff --git a/pkg/front_end/test/fasta/rasta/class_member.dart.outline.expect b/pkg/front_end/test/fasta/rasta/class_member.dart.outline.expect
new file mode 100644
index 0000000..d7df801
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/class_member.dart.outline.expect
@@ -0,0 +1,21 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  field dynamic field1;
+  field dynamic field2;
+  field dynamic field3;
+  constructor constructor1() → void
+    ;
+  constructor constructor2() → void
+    ;
+  constructor constructor3() → void
+    ;
+  method a() → dynamic
+    ;
+  method b() → dynamic
+    ;
+  method c() → dynamic
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart
new file mode 100644
index 0000000..3720069
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart
@@ -0,0 +1,9 @@
+// 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.
+
+const c = 1;
+main() {
+  c;
+  c();
+}
diff --git a/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.dartk.expect
new file mode 100644
index 0000000..eb9688c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.dartk.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+
+static const field dynamic c = 1;
+static method main() → dynamic {
+  self::c;
+  self::c.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.direct.expect b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.direct.expect
new file mode 100644
index 0000000..eb9688c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.direct.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+
+static const field dynamic c = 1;
+static method main() → dynamic {
+  self::c;
+  self::c.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.outline.expect b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.outline.expect
new file mode 100644
index 0000000..7c08d7a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/constant_get_and_invoke.dart.outline.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+
+static const field dynamic c;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/deferred_lib.dart b/pkg/front_end/test/fasta/rasta/deferred_lib.dart
new file mode 100644
index 0000000..b4e6442
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_lib.dart
@@ -0,0 +1,7 @@
+// 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.
+
+library deferred_lib;
+
+foo() => null;
diff --git a/pkg/front_end/test/fasta/rasta/deferred_lib.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/deferred_lib.dart.dartk.expect
new file mode 100644
index 0000000..ac7cad3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_lib.dart.dartk.expect
@@ -0,0 +1,5 @@
+library deferred_lib;
+import self as self;
+
+static method foo() → dynamic
+  return null;
diff --git a/pkg/front_end/test/fasta/rasta/deferred_lib.dart.direct.expect b/pkg/front_end/test/fasta/rasta/deferred_lib.dart.direct.expect
new file mode 100644
index 0000000..ac7cad3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_lib.dart.direct.expect
@@ -0,0 +1,5 @@
+library deferred_lib;
+import self as self;
+
+static method foo() → dynamic
+  return null;
diff --git a/pkg/front_end/test/fasta/rasta/deferred_lib.dart.outline.expect b/pkg/front_end/test/fasta/rasta/deferred_lib.dart.outline.expect
new file mode 100644
index 0000000..25280b3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_lib.dart.outline.expect
@@ -0,0 +1,5 @@
+library deferred_lib;
+import self as self;
+
+static method foo() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/deferred_load.dart b/pkg/front_end/test/fasta/rasta/deferred_load.dart
new file mode 100644
index 0000000..1ba7abd
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_load.dart
@@ -0,0 +1,10 @@
+// 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.
+
+import 'deferred_lib.dart' deferred as lib;
+
+main() {
+  lib.loadLibrary;
+  lib.loadLibrary();
+}
diff --git a/pkg/front_end/test/fasta/rasta/deferred_load.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/deferred_load.dart.dartk.expect
new file mode 100644
index 0000000..6de3c9a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_load.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  invalid-expression;
+  invalid-expression;
+}
diff --git a/pkg/front_end/test/fasta/rasta/deferred_load.dart.direct.expect b/pkg/front_end/test/fasta/rasta/deferred_load.dart.direct.expect
new file mode 100644
index 0000000..d7651c0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_load.dart.direct.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  throw new core::NoSuchMethodError::•(null, #loadLibrary, <dynamic>[], <dynamic, dynamic>{}, null);
+  throw new core::NoSuchMethodError::•(null, #lib.loadLibrary, <dynamic>[], <dynamic, dynamic>{}, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/deferred_load.dart.outline.expect b/pkg/front_end/test/fasta/rasta/deferred_load.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/deferred_load.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart
new file mode 100644
index 0000000..08368cf
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart
@@ -0,0 +1,10 @@
+// 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.
+
+class Mixin {
+  var field;
+}
+
+class A extends Object with Mixin, Mixin {
+}
diff --git a/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.dartk.expect
new file mode 100644
index 0000000..c82df79
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.dartk.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin extends core::Object {
+  field dynamic field;
+  constructor •() → self::Mixin
+    : super core::Object::•();
+}
+class A extends self::Object+Mixin+Mixin#0 {
+  constructor •() → self::A
+    : super self::Object+Mixin+Mixin#0::•();
+}
+abstract class Object+Mixin+Mixin#0 extends self::Object+Mixin#0 implements self::Mixin {
+  field dynamic field;
+  constructor •() → dynamic
+    : super self::Object+Mixin#0::•();
+}
+abstract class Object+Mixin#0 extends core::Object implements self::Mixin {
+  field dynamic field;
+  constructor •() → dynamic
+    : super core::Object::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.direct.expect b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.direct.expect
new file mode 100644
index 0000000..871625f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.direct.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin extends core::Object {
+  field dynamic field = null;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A extends self::Object&Mixin&Mixin {
+  constructor •() → void
+    : super self::Object&Mixin&Mixin::•()
+    ;
+}
+abstract class Object&Mixin extends core::Object implements self::Mixin {
+  field dynamic field = null;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+abstract class Object&Mixin&Mixin extends self::Object&Mixin implements self::Mixin {
+  field dynamic field = null;
+  constructor •() → void
+    : super self::Object&Mixin::•()
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.outline.expect b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.outline.expect
new file mode 100644
index 0000000..eb523ab
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/duplicated_mixin.dart.outline.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin extends core::Object {
+  field dynamic field;
+  constructor •() → void
+    ;
+}
+class A extends self::Object&Mixin&Mixin {
+  constructor •() → void
+    ;
+}
+abstract class Object&Mixin = core::Object with self::Mixin {
+}
+abstract class Object&Mixin&Mixin = self::Object&Mixin with self::Mixin {
+}
diff --git a/pkg/front_end/test/fasta/rasta/enum.dart b/pkg/front_end/test/fasta/rasta/enum.dart
new file mode 100644
index 0000000..58edf77
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/enum.dart
@@ -0,0 +1,10 @@
+// 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.
+
+enum Foo {
+  ec1,
+  ec2,
+}
+
+main() {}
diff --git a/pkg/front_end/test/fasta/rasta/enum.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/enum.dart.dartk.expect
new file mode 100644
index 0000000..249b79c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/enum.dart.dartk.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  final field core::int index;
+  static const field core::List<self::Foo> values = const <self::Foo>[self::Foo::ec1, self::Foo::ec2];
+  static const field self::Foo ec1 = const self::Foo::•(0);
+  static const field self::Foo ec2 = const self::Foo::•(1);
+  const constructor •(core::int index) → void
+    : self::Foo::index = index, super core::Object::•()
+    ;
+  method toString() → core::String
+    return const <core::int, core::String>{0: "Foo.ec1", 1: "Foo.ec2"}.[](this.{=self::Foo::index});
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/enum.dart.direct.expect b/pkg/front_end/test/fasta/rasta/enum.dart.direct.expect
new file mode 100644
index 0000000..249b79c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/enum.dart.direct.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  final field core::int index;
+  static const field core::List<self::Foo> values = const <self::Foo>[self::Foo::ec1, self::Foo::ec2];
+  static const field self::Foo ec1 = const self::Foo::•(0);
+  static const field self::Foo ec2 = const self::Foo::•(1);
+  const constructor •(core::int index) → void
+    : self::Foo::index = index, super core::Object::•()
+    ;
+  method toString() → core::String
+    return const <core::int, core::String>{0: "Foo.ec1", 1: "Foo.ec2"}.[](this.{=self::Foo::index});
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/enum.dart.outline.expect b/pkg/front_end/test/fasta/rasta/enum.dart.outline.expect
new file mode 100644
index 0000000..9b3c542
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/enum.dart.outline.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  final field core::int index;
+  static const field core::List<self::Foo> values = const <self::Foo>[self::Foo::ec1, self::Foo::ec2];
+  static const field self::Foo ec1 = const self::Foo::•(0);
+  static const field self::Foo ec2 = const self::Foo::•(1);
+  const constructor •(core::int index) → void
+    : self::Foo::index = index
+    ;
+  method toString() → core::String
+    return const <core::int, core::String>{0: "Foo.ec1", 1: "Foo.ec2"}.[](this.{=self::Foo::index});
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/export.dart b/pkg/front_end/test/fasta/rasta/export.dart
new file mode 100644
index 0000000..ca462cf
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/export.dart
@@ -0,0 +1,7 @@
+// 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.
+
+library export;
+
+export 'foo.dart';
diff --git a/pkg/front_end/test/fasta/rasta/export.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/export.dart.dartk.expect
new file mode 100644
index 0000000..a56f426
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/export.dart.dartk.expect
@@ -0,0 +1,2 @@
+library export;
+import self as self;
diff --git a/pkg/front_end/test/fasta/rasta/export.dart.direct.expect b/pkg/front_end/test/fasta/rasta/export.dart.direct.expect
new file mode 100644
index 0000000..a56f426
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/export.dart.direct.expect
@@ -0,0 +1,2 @@
+library export;
+import self as self;
diff --git a/pkg/front_end/test/fasta/rasta/export.dart.outline.expect b/pkg/front_end/test/fasta/rasta/export.dart.outline.expect
new file mode 100644
index 0000000..a56f426
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/export.dart.outline.expect
@@ -0,0 +1,2 @@
+library export;
+import self as self;
diff --git a/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart
new file mode 100644
index 0000000..3563f91
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart
@@ -0,0 +1,9 @@
+// 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.
+
+main() {
+  "Should redirect to LinkedHashMap constructor.";
+  new Map<Symbol, dynamic>(); // This is a patched constructor whose
+                              // implementation contains the redirection.
+}
diff --git a/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.dartk.expect
new file mode 100644
index 0000000..8977e84
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.dartk.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:collection" as col;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  "Should redirect to LinkedHashMap constructor.";
+  col::LinkedHashMap::•<core::Symbol, dynamic>();
+}
diff --git a/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.direct.expect b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.direct.expect
new file mode 100644
index 0000000..9a0f2dc
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:collection" as col;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  "Should redirect to LinkedHashMap constructor.";
+  col::LinkedHashMap::•<core::Symbol, dynamic>(equals: null, hashCode: null, isValidKey: null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.outline.expect b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/external_factory_redirection.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/foo.dart b/pkg/front_end/test/fasta/rasta/foo.dart
new file mode 100644
index 0000000..6400698
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/foo.dart
@@ -0,0 +1,9 @@
+// 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.
+
+library foo;
+
+foo() {
+  print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/rasta/foo.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/foo.dart.dartk.expect
new file mode 100644
index 0000000..5f90b5a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/foo.dart.dartk.expect
@@ -0,0 +1,7 @@
+library foo;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → dynamic {
+  core::print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/rasta/foo.dart.direct.expect b/pkg/front_end/test/fasta/rasta/foo.dart.direct.expect
new file mode 100644
index 0000000..5f90b5a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/foo.dart.direct.expect
@@ -0,0 +1,7 @@
+library foo;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → dynamic {
+  core::print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/rasta/foo.dart.outline.expect b/pkg/front_end/test/fasta/rasta/foo.dart.outline.expect
new file mode 100644
index 0000000..8376691
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/foo.dart.outline.expect
@@ -0,0 +1,5 @@
+library foo;
+import self as self;
+
+static method foo() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/for_loop.dart b/pkg/front_end/test/fasta/rasta/for_loop.dart
new file mode 100644
index 0000000..0155ab3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/for_loop.dart
@@ -0,0 +1,13 @@
+// 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.
+
+main() {
+  int c = new DateTime.now().millisecondsSinceEpoch;
+  for (int i = 0; i < 100; i++) {
+    print(i++);
+  }
+  for (int i = 0; i < 100; c < 42 ? throw "fisk" : i++) {
+    print(i++);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/for_loop.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/for_loop.dart.dartk.expect
new file mode 100644
index 0000000..6ca16b2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/for_loop.dart.dartk.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int c = new core::DateTime::now().millisecondsSinceEpoch;
+  for (core::int i = 0; i.<(100); i = i.+(1)) {
+    core::print(let final dynamic #t1 = i in let final dynamic #t2 = i = #t1.+(1) in #t1);
+  }
+  for (core::int i = 0; i.<(100); c.<(42) ? throw "fisk" : i = i.+(1)) {
+    core::print(let final dynamic #t3 = i in let final dynamic #t4 = i = #t3.+(1) in #t3);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/for_loop.dart.direct.expect b/pkg/front_end/test/fasta/rasta/for_loop.dart.direct.expect
new file mode 100644
index 0000000..6ca16b2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/for_loop.dart.direct.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int c = new core::DateTime::now().millisecondsSinceEpoch;
+  for (core::int i = 0; i.<(100); i = i.+(1)) {
+    core::print(let final dynamic #t1 = i in let final dynamic #t2 = i = #t1.+(1) in #t1);
+  }
+  for (core::int i = 0; i.<(100); c.<(42) ? throw "fisk" : i = i.+(1)) {
+    core::print(let final dynamic #t3 = i in let final dynamic #t4 = i = #t3.+(1) in #t3);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/for_loop.dart.outline.expect b/pkg/front_end/test/fasta/rasta/for_loop.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/for_loop.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/generic_factory.dart b/pkg/front_end/test/fasta/rasta/generic_factory.dart
new file mode 100644
index 0000000..d2eea56
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/generic_factory.dart
@@ -0,0 +1,41 @@
+// 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.
+
+class C1 {
+}
+
+class C2 {
+}
+
+class C3 {
+}
+
+class A<T> {
+  A.internal();
+
+  factory A.a() = B<T>.a;
+  factory A.b() = B<C1>.a;
+  factory A.c() = Missing;
+}
+
+class B<S> extends A<S> {
+  B.internal()
+      : super.internal();
+
+  factory B.a() = C<S>;
+  factory B.b() = C<C2>;
+}
+
+class C<U> extends B<U> {
+  C()
+      : super.internal();
+}
+
+main() {
+  new A<C3>.a();
+  new A<C3>.b();
+  new B<C3>.a();
+  new B<C3>.b();
+  new A<C3>.c();
+}
diff --git a/pkg/front_end/test/fasta/rasta/generic_factory.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/generic_factory.dart.dartk.expect
new file mode 100644
index 0000000..52b736e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/generic_factory.dart.dartk.expect
@@ -0,0 +1,48 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C1 extends core::Object {
+  constructor •() → self::C1
+    : super core::Object::•();
+}
+class C2 extends core::Object {
+  constructor •() → self::C2
+    : super core::Object::•();
+}
+class C3 extends core::Object {
+  constructor •() → self::C3
+    : super core::Object::•();
+}
+class A<T extends core::Object> extends core::Object {
+  constructor internal() → dynamic
+    : super core::Object::•()
+    ;
+  static factory a<T extends core::Object>() → self::A<self::A::a::T>
+    invalid-statement;
+  static factory b<T extends core::Object>() → self::A<self::A::b::T>
+    invalid-statement;
+  static factory c<T extends core::Object>() → self::A<self::A::c::T>
+    invalid-statement;
+}
+class B<S extends core::Object> extends self::A<self::B::S> {
+  constructor internal() → dynamic
+    : super self::A::internal()
+    ;
+  static factory a<S extends core::Object>() → self::B<self::B::a::S>
+    invalid-statement;
+  static factory b<S extends core::Object>() → self::B<self::B::b::S>
+    invalid-statement;
+}
+class C<U extends core::Object> extends self::B<self::C::U> {
+  constructor •() → dynamic
+    : super self::B::internal()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•<self::C3>();
+  new self::C::•<self::C1>();
+  new self::C::•<self::C3>();
+  new self::C::•<self::C2>();
+  invalid-expression.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/generic_factory.dart.direct.expect b/pkg/front_end/test/fasta/rasta/generic_factory.dart.direct.expect
new file mode 100644
index 0000000..1cd0c54
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/generic_factory.dart.direct.expect
@@ -0,0 +1,51 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C1 extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class C2 extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class C3 extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object> extends core::Object {
+  constructor internal() → void
+    : super core::Object::•()
+    ;
+  static factory a<T extends core::Object>() → self::A<self::A::a::T>
+    invalid-statement;
+  static factory b<T extends core::Object>() → self::A<self::A::b::T>
+    invalid-statement;
+  static factory c<T extends core::Object>() → self::A<self::A::c::T>
+    throw "Missing constructor: Missing";
+}
+class B<S extends core::Object> extends self::A<self::B::S> {
+  constructor internal() → void
+    : super self::A::internal()
+    ;
+  static factory a<S extends core::Object>() → self::B<self::B::a::S>
+    invalid-statement;
+  static factory b<S extends core::Object>() → self::B<self::B::b::S>
+    invalid-statement;
+}
+class C<U extends core::Object> extends self::B<self::C::U> {
+  constructor •() → void
+    : super self::B::internal()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•<self::C3>();
+  new self::C::•<self::C1>();
+  new self::C::•<self::C3>();
+  new self::C::•<self::C2>();
+  self::A::c<self::C3>();
+}
diff --git a/pkg/front_end/test/fasta/rasta/generic_factory.dart.outline.expect b/pkg/front_end/test/fasta/rasta/generic_factory.dart.outline.expect
new file mode 100644
index 0000000..346aa5a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/generic_factory.dart.outline.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C1 extends core::Object {
+  constructor •() → void
+    ;
+}
+class C2 extends core::Object {
+  constructor •() → void
+    ;
+}
+class C3 extends core::Object {
+  constructor •() → void
+    ;
+}
+class A<T extends core::Object> extends core::Object {
+  constructor internal() → void
+    ;
+  static factory a<T extends core::Object>() → self::A<self::A::a::T>
+    invalid-statement;
+  static factory b<T extends core::Object>() → self::A<self::A::b::T>
+    invalid-statement;
+  static factory c<T extends core::Object>() → self::A<self::A::c::T>
+    throw "Missing constructor: Missing";
+}
+class B<S extends core::Object> extends self::A<self::B::S> {
+  constructor internal() → void
+    ;
+  static factory a<S extends core::Object>() → self::B<self::B::a::S>
+    invalid-statement;
+  static factory b<S extends core::Object>() → self::B<self::B::b::S>
+    invalid-statement;
+}
+class C<U extends core::Object> extends self::B<self::C::U> {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/hello.dart b/pkg/front_end/test/fasta/rasta/hello.dart
new file mode 100644
index 0000000..671d11f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/hello.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/rasta/hello.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/hello.dart.dartk.expect
new file mode 100644
index 0000000..fea7b39
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/hello.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/rasta/hello.dart.direct.expect b/pkg/front_end/test/fasta/rasta/hello.dart.direct.expect
new file mode 100644
index 0000000..fea7b39
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/hello.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print("Hello, World!");
+}
diff --git a/pkg/front_end/test/fasta/rasta/hello.dart.outline.expect b/pkg/front_end/test/fasta/rasta/hello.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/hello.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/import_export.dart b/pkg/front_end/test/fasta/rasta/import_export.dart
new file mode 100644
index 0000000..8d6f2c4
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/import_export.dart
@@ -0,0 +1,9 @@
+// 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.
+
+import 'export.dart';
+
+main() {
+  foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/import_export.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/import_export.dart.dartk.expect
new file mode 100644
index 0000000..64dfcdc
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/import_export.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "./foo.dart" as foo;
+
+static method main() → dynamic {
+  foo::foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/import_export.dart.direct.expect b/pkg/front_end/test/fasta/rasta/import_export.dart.direct.expect
new file mode 100644
index 0000000..64dfcdc
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/import_export.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "./foo.dart" as foo;
+
+static method main() → dynamic {
+  foo::foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/import_export.dart.outline.expect b/pkg/front_end/test/fasta/rasta/import_export.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/import_export.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000001.dart b/pkg/front_end/test/fasta/rasta/issue_000001.dart
new file mode 100644
index 0000000..6142ebc
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000001.dart
@@ -0,0 +1,12 @@
+// 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.
+
+test0(x) {
+  print('test0');
+}
+
+main() {
+  // Incorrect number of arguments, should be NoSuchMethodError but crashes.
+  test0(0, 1);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000001.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000001.dart.dartk.expect
new file mode 100644
index 0000000..9897c9f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000001.dart.dartk.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test0(dynamic x) → dynamic {
+  core::print("test0");
+}
+static method main() → dynamic {
+  self::test0(0, 1);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000001.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000001.dart.direct.expect
new file mode 100644
index 0000000..f16af33
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000001.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test0(dynamic x) → dynamic {
+  core::print("test0");
+}
+static method main() → dynamic {
+  throw new core::NoSuchMethodError::•(null, #test0, <dynamic>[0, 1], <dynamic, dynamic>{}, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000001.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000001.dart.outline.expect
new file mode 100644
index 0000000..2a30a05
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000001.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method test0(dynamic x) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000002.dart b/pkg/front_end/test/fasta/rasta/issue_000002.dart
new file mode 100644
index 0000000..2efd103
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000002.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+var list = [1, 2, 3];
+
+class Foo {
+  final value;
+  Foo(this.value) {}
+
+  factory Foo.fac(value) {
+    return new Foo(value);
+  }
+}
+
+main() {
+  Expect.isTrue(new Uint8List.fromList(list)[1] == 2);
+  Expect.isTrue(new Foo.fac(10).value == 10);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000002.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000002.dart.dartk.expect
new file mode 100644
index 0000000..2827eb8
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000002.dart.dartk.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+import "dart:typed_data" as typ;
+
+class Foo extends core::Object {
+  final field dynamic value;
+  constructor •(dynamic value) → dynamic
+    : self::Foo::value = value, super core::Object::•() {}
+  static factory fac(dynamic value) → self::Foo {
+    return new self::Foo::•(value);
+  }
+}
+static field dynamic list = <dynamic>[1, 2, 3];
+static method main() → dynamic {
+  exp::Expect::isTrue(typ::Uint8List::fromList(self::list).[](1).==(2));
+  exp::Expect::isTrue(self::Foo::fac(10).value.==(10));
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000002.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000002.dart.direct.expect
new file mode 100644
index 0000000..6967724
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000002.dart.direct.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+import "dart:typed_data" as typ;
+
+class Foo extends core::Object {
+  final field dynamic value;
+  constructor •(dynamic value) → void
+    : self::Foo::value = value, super core::Object::•() {}
+  static factory fac(dynamic value) → dynamic {
+    return new self::Foo::•(value);
+  }
+}
+static field dynamic list = <dynamic>[1, 2, 3];
+static method main() → dynamic {
+  exp::Expect::isTrue(typ::Uint8List::fromList(self::list).[](1).==(2), null);
+  exp::Expect::isTrue(self::Foo::fac(10).value.==(10), null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000002.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000002.dart.outline.expect
new file mode 100644
index 0000000..7076215
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000002.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  final field dynamic value;
+  constructor •(dynamic value) → void
+    ;
+  static factory fac(dynamic value) → self::Foo
+    ;
+}
+static field dynamic list;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000004.dart b/pkg/front_end/test/fasta/rasta/issue_000004.dart
new file mode 100644
index 0000000..d7e9d27
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000004.dart
@@ -0,0 +1,36 @@
+// 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.
+
+import 'package:expect/expect.dart';
+
+fact4() {
+  var f = 1;
+  for (var n in [1, 2, 3, 4]) {
+    f *= n;
+  }
+  return f;
+}
+
+fact5() {
+  var f = 1, n;
+  for (n in [1, 2, 3, 4, 5]) {
+    f *= n;
+  }
+  return f;
+}
+
+var global;
+fact6() {
+  var f = 1;
+  for (global in [1, 2, 3, 4, 5, 6]) {
+    f *= global;
+  }
+  return f;
+}
+
+main() {
+  Expect.isTrue(fact4() == 24);
+  Expect.isTrue(fact5() == 120);
+  Expect.isTrue(fact6() == 720);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000004.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000004.dart.dartk.expect
new file mode 100644
index 0000000..4c7bdc0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000004.dart.dartk.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "package:expect/expect.dart" as exp;
+
+static field dynamic global;
+static method fact4() → dynamic {
+  dynamic f = 1;
+  for (dynamic n in <dynamic>[1, 2, 3, 4]) {
+    f = f.*(n);
+  }
+  return f;
+}
+static method fact5() → dynamic {
+  dynamic f = 1;
+  dynamic n;
+  for (final dynamic #t1 in <dynamic>[1, 2, 3, 4, 5]) {
+    n = #t1;
+    f = f.*(n);
+  }
+  return f;
+}
+static method fact6() → dynamic {
+  dynamic f = 1;
+  for (final dynamic #t2 in <dynamic>[1, 2, 3, 4, 5, 6]) {
+    self::global = #t2;
+    f = f.*(self::global);
+  }
+  return f;
+}
+static method main() → dynamic {
+  exp::Expect::isTrue(self::fact4().==(24));
+  exp::Expect::isTrue(self::fact5().==(120));
+  exp::Expect::isTrue(self::fact6().==(720));
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000004.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000004.dart.direct.expect
new file mode 100644
index 0000000..038545a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000004.dart.direct.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "package:expect/expect.dart" as exp;
+
+static field dynamic global;
+static method fact4() → dynamic {
+  dynamic f = 1;
+  for (dynamic n in <dynamic>[1, 2, 3, 4]) {
+    f = f.*(n);
+  }
+  return f;
+}
+static method fact5() → dynamic {
+  dynamic f = 1;
+  dynamic n;
+  for (final dynamic #t1 in <dynamic>[1, 2, 3, 4, 5]) {
+    n = #t1;
+    f = f.*(n);
+  }
+  return f;
+}
+static method fact6() → dynamic {
+  dynamic f = 1;
+  for (final dynamic #t2 in <dynamic>[1, 2, 3, 4, 5, 6]) {
+    self::global = #t2;
+    f = f.*(self::global);
+  }
+  return f;
+}
+static method main() → dynamic {
+  exp::Expect::isTrue(self::fact4().==(24), null);
+  exp::Expect::isTrue(self::fact5().==(120), null);
+  exp::Expect::isTrue(self::fact6().==(720), null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000004.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000004.dart.outline.expect
new file mode 100644
index 0000000..cf199f8f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000004.dart.outline.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+
+static field dynamic global;
+static method fact4() → dynamic
+  ;
+static method fact5() → dynamic
+  ;
+static method fact6() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000006.dart b/pkg/front_end/test/fasta/rasta/issue_000006.dart
new file mode 100644
index 0000000..8883ac2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000006.dart
@@ -0,0 +1,9 @@
+// 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.
+
+var list = [1, 2, 3];
+
+main() {
+  list.add(1);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000006.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000006.dart.dartk.expect
new file mode 100644
index 0000000..b8b4a93
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000006.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static field dynamic list = <dynamic>[1, 2, 3];
+static method main() → dynamic {
+  self::list.add(1);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000006.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000006.dart.direct.expect
new file mode 100644
index 0000000..b8b4a93
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000006.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static field dynamic list = <dynamic>[1, 2, 3];
+static method main() → dynamic {
+  self::list.add(1);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000006.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000006.dart.outline.expect
new file mode 100644
index 0000000..0ff4007
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000006.dart.outline.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+
+static field dynamic list;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000007.dart b/pkg/front_end/test/fasta/rasta/issue_000007.dart
new file mode 100644
index 0000000..7553185
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000007.dart
@@ -0,0 +1,13 @@
+// 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.
+
+class Base {}
+class Mixin {
+  foo() => print('foo');
+}
+class Sub extends Base with Mixin {}
+
+main() {
+  new Sub().foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000007.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000007.dart.dartk.expect
new file mode 100644
index 0000000..7b13cd1
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000007.dart.dartk.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  constructor •() → self::Base
+    : super core::Object::•();
+}
+class Mixin extends core::Object {
+  constructor •() → self::Mixin
+    : super core::Object::•();
+  method foo() → dynamic
+    return core::print("foo");
+}
+class Sub extends self::Base+Mixin#0 {
+  constructor •() → self::Sub
+    : super self::Base+Mixin#0::•();
+}
+abstract class Base+Mixin#0 extends self::Base implements self::Mixin {
+  constructor •() → self::Base
+    : super self::Base::•();
+  method foo() → dynamic
+    return core::print("foo");
+}
+static method main() → dynamic {
+  new self::Sub::•().foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000007.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000007.dart.direct.expect
new file mode 100644
index 0000000..dc735b0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000007.dart.direct.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class Mixin extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo() → dynamic
+    return core::print("foo");
+}
+class Sub extends self::Base&Mixin {
+  constructor •() → void
+    : super self::Base&Mixin::•()
+    ;
+}
+abstract class Base&Mixin extends self::Base implements self::Mixin {
+  constructor •() → void
+    : super self::Base::•()
+    ;
+  method foo() → dynamic
+    return core::print("foo");
+}
+static method main() → dynamic {
+  new self::Sub::•().foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000007.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000007.dart.outline.expect
new file mode 100644
index 0000000..b279d88
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000007.dart.outline.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  constructor •() → void
+    ;
+}
+class Mixin extends core::Object {
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+}
+class Sub extends self::Base&Mixin {
+  constructor •() → void
+    ;
+}
+abstract class Base&Mixin = self::Base with self::Mixin {
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000008.dart b/pkg/front_end/test/fasta/rasta/issue_000008.dart
new file mode 100644
index 0000000..b9f1f6e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000008.dart
@@ -0,0 +1,12 @@
+// 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.
+
+class C {
+  final x;
+  C(this.x);
+}
+
+main() {
+  new C(42);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000008.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000008.dart.dartk.expect
new file mode 100644
index 0000000..b63423c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000008.dart.dartk.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic x;
+  constructor •(dynamic x) → dynamic
+    : self::C::x = x, super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•(42);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000008.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000008.dart.direct.expect
new file mode 100644
index 0000000..034eb0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000008.dart.direct.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic x;
+  constructor •(dynamic x) → void
+    : self::C::x = x, super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•(42);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000008.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000008.dart.outline.expect
new file mode 100644
index 0000000..873e541
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000008.dart.outline.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic x;
+  constructor •(dynamic x) → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000011.dart b/pkg/front_end/test/fasta/rasta/issue_000011.dart
new file mode 100644
index 0000000..26790da
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000011.dart
@@ -0,0 +1,11 @@
+// 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.
+
+main() {
+  try {
+    print(42);
+  } finally {
+    print(87);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000011.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000011.dart.dartk.expect
new file mode 100644
index 0000000..aa88a42
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000011.dart.dartk.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  try {
+    core::print(42);
+  }
+  finally {
+    core::print(87);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000011.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000011.dart.direct.expect
new file mode 100644
index 0000000..aa88a42
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000011.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  try {
+    core::print(42);
+  }
+  finally {
+    core::print(87);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000011.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000011.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000011.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000012.dart b/pkg/front_end/test/fasta/rasta/issue_000012.dart
new file mode 100644
index 0000000..94fdd2f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000012.dart
@@ -0,0 +1,17 @@
+// 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.
+
+class A {
+  var field;
+}
+
+class B extends A {
+  m() {
+    super.field = 42;
+  }
+}
+
+main() {
+  new B().m();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000012.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000012.dart.dartk.expect
new file mode 100644
index 0000000..57f7075
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000012.dart.dartk.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic field;
+  constructor •() → self::A
+    : super core::Object::•();
+}
+class B extends self::A {
+  constructor •() → self::B
+    : super self::A::•();
+  method m() → dynamic {
+    super.{self::A::field} = 42;
+  }
+}
+static method main() → dynamic {
+  new self::B::•().m();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000012.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000012.dart.direct.expect
new file mode 100644
index 0000000..db0b7d9
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000012.dart.direct.expect
@@ -0,0 +1,21 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic field = null;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    : super self::A::•()
+    ;
+  method m() → dynamic {
+    this.{=self::A::field} = 42;
+  }
+}
+static method main() → dynamic {
+  new self::B::•().m();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000012.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000012.dart.outline.expect
new file mode 100644
index 0000000..9fc0897
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000012.dart.outline.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic field;
+  constructor •() → void
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    ;
+  method m() → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000025.dart b/pkg/front_end/test/fasta/rasta/issue_000025.dart
new file mode 100644
index 0000000..543f783
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000025.dart
@@ -0,0 +1,11 @@
+// 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.
+
+get x => 42;
+set x(val) { }
+
+main() {
+  print(x);
+  print(x = 87);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000025.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000025.dart.dartk.expect
new file mode 100644
index 0000000..5fabc15
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000025.dart.dartk.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static get x() → dynamic
+  return 42;
+static set x(dynamic val) → dynamic {}
+static method main() → dynamic {
+  core::print(self::x);
+  core::print(self::x = 87);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000025.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000025.dart.direct.expect
new file mode 100644
index 0000000..59011d0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000025.dart.direct.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static set x(dynamic val) → dynamic {}
+static get x() → dynamic
+  return 42;
+static method main() → dynamic {
+  core::print(self::x);
+  core::print(self::x = 87);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000025.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000025.dart.outline.expect
new file mode 100644
index 0000000..7e1c9a0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000025.dart.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+
+static set x(dynamic val) → dynamic
+  ;
+static get x() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000026.dart b/pkg/front_end/test/fasta/rasta/issue_000026.dart
new file mode 100644
index 0000000..dcf3b43
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000026.dart
@@ -0,0 +1,21 @@
+// 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.
+
+class C {
+  var a;
+  var b = 0;
+  var c = 1 + 2;
+}
+
+class D {
+  var a;
+  var b = 1;
+  var c = 2 - 3;
+  D();
+}
+
+main() {
+  new C();
+  new D();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000026.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000026.dart.dartk.expect
new file mode 100644
index 0000000..1f6448a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000026.dart.dartk.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  constructor •() → self::C
+    : self::C::b = 0, self::C::c = 1.+(2), super core::Object::•();
+}
+class D extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  constructor •() → dynamic
+    : self::D::b = 1, self::D::c = 2.-(3), super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•();
+  new self::D::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000026.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000026.dart.direct.expect
new file mode 100644
index 0000000..1f96e95
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000026.dart.direct.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field dynamic a = null;
+  field dynamic b = 0;
+  field dynamic c = 1.+(2);
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class D extends core::Object {
+  field dynamic a = null;
+  field dynamic b = 1;
+  field dynamic c = 2.-(3);
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::C::•();
+  new self::D::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000026.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000026.dart.outline.expect
new file mode 100644
index 0000000..2dd409d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000026.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  constructor •() → void
+    ;
+}
+class D extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000031.dart b/pkg/front_end/test/fasta/rasta/issue_000031.dart
new file mode 100644
index 0000000..9f6f91a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000031.dart
@@ -0,0 +1,9 @@
+// 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.
+
+import 'dart:math' as math;
+
+main() {
+  math..toString();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000031.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000031.dart.dartk.expect
new file mode 100644
index 0000000..da011b7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000031.dart.dartk.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  let final dynamic #t1 = invalid-expression in let final dynamic #t2 = #t1.toString() in #t1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000031.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000031.dart.direct.expect
new file mode 100644
index 0000000..0bda4ee
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000031.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  let final dynamic #t1 = throw new core::_CompileTimeError::•("pkg/front_end/test/fasta/rasta/issue_000031.dart: \u0027[31mError: A library can't be used as an expression.\u0027[0m") in let final dynamic #t2 = #t1.toString() in #t1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000031.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000031.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000031.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000032.dart b/pkg/front_end/test/fasta/rasta/issue_000032.dart
new file mode 100644
index 0000000..21222e2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000032.dart
@@ -0,0 +1,11 @@
+// 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.
+
+class C {
+  C<
+}
+
+main() {
+  C<
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000032.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000032.dart.dartk.expect
new file mode 100644
index 0000000..3be911b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000032.dart.dartk.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+}
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000032.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000032.dart.direct.expect
new file mode 100644
index 0000000..3be911b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000032.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+}
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000032.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000032.dart.outline.expect
new file mode 100644
index 0000000..a6165ac
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000032.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000033.dart b/pkg/front_end/test/fasta/rasta/issue_000033.dart
new file mode 100644
index 0000000..cf8392b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000033.dart
@@ -0,0 +1,7 @@
+// 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.
+
+@JS()
+main() {
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000033.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000033.dart.dartk.expect
new file mode 100644
index 0000000..bef6d48
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000033.dart.dartk.expect
@@ -0,0 +1,4 @@
+library;
+import self as self;
+
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000033.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000033.dart.direct.expect
new file mode 100644
index 0000000..bef6d48
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000033.dart.direct.expect
@@ -0,0 +1,4 @@
+library;
+import self as self;
+
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000033.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000033.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000033.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000034.dart b/pkg/front_end/test/fasta/rasta/issue_000034.dart
new file mode 100644
index 0000000..88fad1f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000034.dart
@@ -0,0 +1,11 @@
+// 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.
+
+class C {
+  const C() : this.x;
+}
+
+main() {
+  const C();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000034.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000034.dart.dartk.expect
new file mode 100644
index 0000000..6b7c59f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000034.dart.dartk.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor •() → dynamic
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  const self::C::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000034.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000034.dart.direct.expect
new file mode 100644
index 0000000..b0b7305
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000034.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor •() → void
+    : final dynamic #t1 = throw new core::_CompileTimeError::•("pkg/front_end/test/fasta/rasta/issue_000034.dart:243: \u0027[31mError: Can't use x here.\u0027[0m"), super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  const self::C::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000034.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000034.dart.outline.expect
new file mode 100644
index 0000000..9cdc3c0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000034.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035.dart b/pkg/front_end/test/fasta/rasta/issue_000035.dart
new file mode 100644
index 0000000..62e390e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035.dart
@@ -0,0 +1,5 @@
+// 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.
+
+class C {æøC();}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000035.dart.dartk.expect
new file mode 100644
index 0000000..9d3db1d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035.dart.dartk.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → dynamic
+    : super core::Object::•()
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000035.dart.direct.expect
new file mode 100644
index 0000000..57cf938
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  abstract method æøC() → dynamic;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000035.dart.outline.expect
new file mode 100644
index 0000000..1098645
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035.dart.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  abstract method æøC() → dynamic;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035a.dart b/pkg/front_end/test/fasta/rasta/issue_000035a.dart
new file mode 100644
index 0000000..d7da04e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035a.dart
@@ -0,0 +1,5 @@
+// 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.
+
+class C{

C();}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035a.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000035a.dart.dartk.expect
new file mode 100644
index 0000000..94912df
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035a.dart.dartk.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•() {}
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035a.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000035a.dart.direct.expect
new file mode 100644
index 0000000..bfc00968
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035a.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000035a.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000035a.dart.outline.expect
new file mode 100644
index 0000000..ccf680c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000035a.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000036.dart b/pkg/front_end/test/fasta/rasta/issue_000036.dart
new file mode 100644
index 0000000..9f7e17f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000036.dart
@@ -0,0 +1,5 @@
+// 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.
+
+main() => a. - 5;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000036.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000036.dart.dartk.expect
new file mode 100644
index 0000000..1cafd63
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000036.dart.dartk.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000036.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000036.dart.direct.expect
new file mode 100644
index 0000000..1cafd63
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000036.dart.direct.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000036.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000036.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000036.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000039.dart b/pkg/front_end/test/fasta/rasta/issue_000039.dart
new file mode 100644
index 0000000..f9a8f85
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000039.dart
@@ -0,0 +1,14 @@
+// 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.
+
+class A {
+  var a;
+
+  A(x) {
+    this.a = x.
+  }
+}
+
+class B extends A {
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000039.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000039.dart.dartk.expect
new file mode 100644
index 0000000..116a721
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000039.dart.dartk.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic a;
+  constructor •() → dynamic
+    : invalid-initializer;
+}
+class B extends self::A {
+  constructor •() → self::B
+    : super self::A::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000039.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000039.dart.direct.expect
new file mode 100644
index 0000000..116a721
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000039.dart.direct.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic a;
+  constructor •() → dynamic
+    : invalid-initializer;
+}
+class B extends self::A {
+  constructor •() → self::B
+    : super self::A::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000039.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000039.dart.outline.expect
new file mode 100644
index 0000000..331f7e8
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000039.dart.outline.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic a;
+  constructor •(dynamic x) → void
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000041.dart b/pkg/front_end/test/fasta/rasta/issue_000041.dart
new file mode 100644
index 0000000..4035fd7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000041.dart
@@ -0,0 +1,15 @@
+// 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.
+
+class C {
+  test() {
+    use(+super);
+  }
+}
+
+use(_) => null;
+
+main() {
+  new C().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000041.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000041.dart.dartk.expect
new file mode 100644
index 0000000..9a674a0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000041.dart.dartk.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+  method test() → dynamic {
+    self::use(invalid-expression);
+  }
+}
+static method use(dynamic _) → dynamic
+  return null;
+static method main() → dynamic {
+  new self::C::•().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000041.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000041.dart.direct.expect
new file mode 100644
index 0000000..9a674a0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000041.dart.direct.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+  method test() → dynamic {
+    self::use(invalid-expression);
+  }
+}
+static method use(dynamic _) → dynamic
+  return null;
+static method main() → dynamic {
+  new self::C::•().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000041.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000041.dart.outline.expect
new file mode 100644
index 0000000..d1fde5a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000041.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  method test() → dynamic
+    ;
+}
+static method use(dynamic _) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000042.dart b/pkg/front_end/test/fasta/rasta/issue_000042.dart
new file mode 100644
index 0000000..66893b8
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000042.dart
@@ -0,0 +1,18 @@
+// 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.
+
+main() {
+  for (var x, y in []) {}
+  L: { continue L; }
+  L: if (true) { continue L; }
+  L: switch (1) {
+    case 1:
+      continue L;
+    case 2:
+      break L;
+  }
+  try {
+  } on NoSuchMethodError {
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000042.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000042.dart.dartk.expect
new file mode 100644
index 0000000..60fee3b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000042.dart.dartk.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  invalid-statement;
+  {
+    invalid-statement;
+  }
+  if(true) {
+    invalid-statement;
+  }
+  #L1:
+  switch(1) {
+    #L2:
+    case 1:
+      invalid-statement;
+    #L3:
+    case 2:
+      break #L1;
+  }
+  try {
+  }
+  on core::NoSuchMethodError catch(no-exception-var) {
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000042.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000042.dart.direct.expect
new file mode 100644
index 0000000..60fee3b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000042.dart.direct.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  invalid-statement;
+  {
+    invalid-statement;
+  }
+  if(true) {
+    invalid-statement;
+  }
+  #L1:
+  switch(1) {
+    #L2:
+    case 1:
+      invalid-statement;
+    #L3:
+    case 2:
+      break #L1;
+  }
+  try {
+  }
+  on core::NoSuchMethodError catch(no-exception-var) {
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000042.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000042.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000042.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000043.dart b/pkg/front_end/test/fasta/rasta/issue_000043.dart
new file mode 100644
index 0000000..4aed858
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000043.dart
@@ -0,0 +1,7 @@
+// 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.
+
+class C {
+  get x => '$C'.hashCode;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000043.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000043.dart.dartk.expect
new file mode 100644
index 0000000..44eaf81
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000043.dart.dartk.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  get x() → dynamic
+    return "${self::C}".hashCode;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000043.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000043.dart.direct.expect
new file mode 100644
index 0000000..44eaf81
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000043.dart.direct.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  get x() → dynamic
+    return "${self::C}".hashCode;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000043.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000043.dart.outline.expect
new file mode 100644
index 0000000..771eec3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000043.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  get x() → dynamic
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000044.dart b/pkg/front_end/test/fasta/rasta/issue_000044.dart
new file mode 100644
index 0000000..3bd4d81
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000044.dart
@@ -0,0 +1,30 @@
+// 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.
+
+// Parse error: but the parser should recover and create something that looks
+// like `a b(c) => d`.
+a b(c) = d;
+
+class C {
+  // Good constructor.
+  const C.constant();
+
+  // Bad constructor: missing factory keyword (and additional formals).
+  C.missingFactoryKeyword() = C.constant;
+
+  // Good redirecting const factory constructor.
+  const factory C.good() = C.constant;
+
+  // Parse error, the parser should recover and create a redirecting factory
+  // constructor body.
+  C notEvenAConstructor(a) = h;
+}
+
+main() {
+  C c = null;
+  print(const C.constant());
+  print(const C.missingFactoryKeyword());
+  print(const C.good());
+  print(new C.constant().notEvenAConstructor(null));
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000044.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000044.dart.dartk.expect
new file mode 100644
index 0000000..ed6b4f7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000044.dart.dartk.expect
@@ -0,0 +1,25 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor constant() → dynamic
+    : super core::Object::•()
+    ;
+  constructor missingFactoryKeyword() → dynamic
+    : super core::Object::•()
+    invalid-statement;
+  static factory good() → self::C
+    invalid-statement;
+  method notEvenAConstructor(dynamic a) → self::C
+    invalid-statement;
+}
+static method b() → dynamic
+  invalid-statement;
+static method main() → dynamic {
+  self::C c = null;
+  core::print(const self::C::constant());
+  core::print(invalid-expression);
+  core::print(const self::C::constant());
+  core::print(new self::C::constant().notEvenAConstructor(null));
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000044.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000044.dart.direct.expect
new file mode 100644
index 0000000..ed6b4f7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000044.dart.direct.expect
@@ -0,0 +1,25 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor constant() → dynamic
+    : super core::Object::•()
+    ;
+  constructor missingFactoryKeyword() → dynamic
+    : super core::Object::•()
+    invalid-statement;
+  static factory good() → self::C
+    invalid-statement;
+  method notEvenAConstructor(dynamic a) → self::C
+    invalid-statement;
+}
+static method b() → dynamic
+  invalid-statement;
+static method main() → dynamic {
+  self::C c = null;
+  core::print(const self::C::constant());
+  core::print(invalid-expression);
+  core::print(const self::C::constant());
+  core::print(new self::C::constant().notEvenAConstructor(null));
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000044.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000044.dart.outline.expect
new file mode 100644
index 0000000..0d1a7fb
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000044.dart.outline.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  const constructor constant() → void
+    ;
+  constructor missingFactoryKeyword() → void
+    ;
+  static factory good() → self::C
+    ;
+  method notEvenAConstructor(dynamic a) → self::C
+    ;
+}
+static method b() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000045.dart b/pkg/front_end/test/fasta/rasta/issue_000045.dart
new file mode 100644
index 0000000..f8c7e61
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000045.dart
@@ -0,0 +1,5 @@
+// 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.
+
+main() => """${1}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000045.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000045.dart.dartk.expect
new file mode 100644
index 0000000..1cafd63
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000045.dart.dartk.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000045.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000045.dart.direct.expect
new file mode 100644
index 0000000..1cafd63
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000045.dart.direct.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000045.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000045.dart.outline.expect
new file mode 100644
index 0000000..1cafd63
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000045.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000046.dart b/pkg/front_end/test/fasta/rasta/issue_000046.dart
new file mode 100644
index 0000000..fe8fc70
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000046.dart
@@ -0,0 +1,7 @@
+// 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.
+
+class C {
+  C c = new Object)();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000046.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000046.dart.dartk.expect
new file mode 100644
index 0000000..2910ee2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000046.dart.dartk.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field invalid-type c;
+  constructor •() → self::C
+    : self::C::c = invalid-expression, super core::Object::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000046.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000046.dart.direct.expect
new file mode 100644
index 0000000..2910ee2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000046.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field invalid-type c;
+  constructor •() → self::C
+    : self::C::c = invalid-expression, super core::Object::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000046.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000046.dart.outline.expect
new file mode 100644
index 0000000..d3f123b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000046.dart.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field invalid-type c;
+  constructor •() → void
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000047.dart b/pkg/front_end/test/fasta/rasta/issue_000047.dart
new file mode 100644
index 0000000..9fb1dc2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000047.dart
@@ -0,0 +1,7 @@
+// 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.
+
+typedef void T(C<C>);
+
+T main() => null;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000047.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000047.dart.dartk.expect
new file mode 100644
index 0000000..a0a397b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000047.dart.dartk.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → invalid-type
+  return null;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000047.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000047.dart.direct.expect
new file mode 100644
index 0000000..a0a397b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000047.dart.direct.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → invalid-type
+  return null;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000047.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000047.dart.outline.expect
new file mode 100644
index 0000000..ab80bb0b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000047.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → invalid-type
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000048.dart b/pkg/front_end/test/fasta/rasta/issue_000048.dart
new file mode 100644
index 0000000..0211480
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000048.dart
@@ -0,0 +1,19 @@
+// 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.
+
+class A {
+  bool v1;
+  num v2;
+  A(bool this.v1, num this.v2);
+}
+
+class M1 {
+  num v2 = 0;
+}
+
+class C = A with M1;
+
+main() {
+  C c = new C(true, 2);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000048.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000048.dart.dartk.expect
new file mode 100644
index 0000000..d203f11
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000048.dart.dartk.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::bool v1;
+  field core::num v2;
+  constructor •(core::bool v1, core::num v2) → dynamic
+    : self::A::v1 = v1, self::A::v2 = v2, super core::Object::•()
+    ;
+}
+class M1 extends core::Object {
+  field core::num v2;
+  constructor •() → self::M1
+    : self::M1::v2 = 0, super core::Object::•();
+}
+class C extends self::A+M1#0 {
+  constructor •(core::bool v1, core::num v2) → dynamic
+    : super self::A+M1#0::•(v1, v2);
+}
+abstract class A+M1#0 extends self::A implements self::M1 {
+  field core::num v2;
+  constructor •(core::bool v1, core::num v2) → dynamic
+    : self::A+M1#0::v2 = 0, super self::A::•(v1, v2);
+}
+static method main() → dynamic {
+  self::C c = new self::C::•(true, 2);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000048.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000048.dart.direct.expect
new file mode 100644
index 0000000..bd4dca5
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000048.dart.direct.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::bool v1;
+  field core::num v2;
+  constructor •(core::bool v1, core::num v2) → void
+    : self::A::v1 = v1, self::A::v2 = v2, super core::Object::•()
+    ;
+}
+class M1 extends core::Object {
+  field core::num v2 = 0;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class C extends self::A&M1 {
+  constructor •(core::bool v1, core::num v2) → void
+    : super self::A&M1::•(v1, v2)
+    ;
+}
+abstract class A&M1 extends self::A implements self::M1 {
+  field core::num v2 = 0;
+  constructor •(final core::bool v1, final core::num v2) → void
+    : super self::A::•(v1, v2)
+    ;
+}
+static method main() → dynamic {
+  self::C c = new self::C::•(true, 2);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000048.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000048.dart.outline.expect
new file mode 100644
index 0000000..219634a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000048.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::bool v1;
+  field core::num v2;
+  constructor •(core::bool v1, core::num v2) → void
+    ;
+}
+class M1 extends core::Object {
+  field core::num v2;
+  constructor •() → void
+    ;
+}
+class C extends self::A&M1 {
+  constructor •(core::bool v1, core::num v2) → void
+    : super self::A::•(v1, v2)
+    ;
+}
+abstract class A&M1 = self::A with self::M1 {
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000052.dart b/pkg/front_end/test/fasta/rasta/issue_000052.dart
new file mode 100644
index 0000000..9c645a1
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000052.dart
@@ -0,0 +1,10 @@
+// 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.
+
+main() {
+  f() {
+    print('hello');
+  }
+  f();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000052.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000052.dart.dartk.expect
new file mode 100644
index 0000000..d3f72c2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000052.dart.dartk.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  function f() → dynamic {
+    core::print("hello");
+  }
+  f.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000052.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000052.dart.direct.expect
new file mode 100644
index 0000000..d3f72c2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000052.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  function f() → dynamic {
+    core::print("hello");
+  }
+  f.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000052.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000052.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000052.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000053.dart b/pkg/front_end/test/fasta/rasta/issue_000053.dart
new file mode 100644
index 0000000..86fcc4d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000053.dart
@@ -0,0 +1,13 @@
+// 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.
+
+class C {
+  operator ==(other) => throw 'x';
+  test() {
+    super == null;
+  }
+}
+main() {
+  new C().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000053.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000053.dart.dartk.expect
new file mode 100644
index 0000000..a4e10a5
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000053.dart.dartk.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+  operator ==(dynamic other) → dynamic
+    return throw "x";
+  method test() → dynamic {
+    super.{core::Object::==}(null);
+  }
+}
+static method main() → dynamic {
+  new self::C::•().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000053.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000053.dart.direct.expect
new file mode 100644
index 0000000..d77061f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000053.dart.direct.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  operator ==(dynamic other) → dynamic
+    return throw "x";
+  method test() → dynamic {
+    this.{=core::Object::==}(null);
+  }
+}
+static method main() → dynamic {
+  new self::C::•().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000053.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000053.dart.outline.expect
new file mode 100644
index 0000000..8c78f43
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000053.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  operator ==(dynamic other) → dynamic
+    ;
+  method test() → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000067.dart b/pkg/front_end/test/fasta/rasta/issue_000067.dart
new file mode 100644
index 0000000..6712407
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000067.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import "package:expect/expect.dart";
+
+class A {
+  A() {}
+  factory A.foo() = C.bar;
+  int m() {}
+}
+
+class C extends A {
+  C() {}
+  factory C.bar() = D;
+  int m() { return 1; }
+}
+
+class D extends C {
+  int m() { return 2; }
+}
+
+main() {
+  A a = new A.foo();
+  Expect.equals(2, a.m());
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000067.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000067.dart.dartk.expect
new file mode 100644
index 0000000..a6a8913
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000067.dart.dartk.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+class A extends core::Object {
+  constructor •() → dynamic
+    : super core::Object::•() {}
+  static factory foo() → self::A
+    invalid-statement;
+  method m() → core::int {}
+}
+class C extends self::A {
+  constructor •() → dynamic
+    : super self::A::•() {}
+  static factory bar() → self::C
+    invalid-statement;
+  method m() → core::int {
+    return 1;
+  }
+}
+class D extends self::C {
+  constructor •() → self::D
+    : super self::C::•();
+  method m() → core::int {
+    return 2;
+  }
+}
+static method main() → dynamic {
+  self::A a = new self::D::•();
+  exp::Expect::equals(2, a.m());
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000067.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000067.dart.direct.expect
new file mode 100644
index 0000000..26c7219
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000067.dart.direct.expect
@@ -0,0 +1,33 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+class A extends core::Object {
+  constructor •() → void
+    : super core::Object::•() {}
+  static factory foo() → self::A
+    invalid-statement;
+  method m() → core::int {}
+}
+class C extends self::A {
+  constructor •() → void
+    : super self::A::•() {}
+  static factory bar() → self::D
+    throw "Missing constructor: D";
+  method m() → core::int {
+    return 1;
+  }
+}
+class D extends self::C {
+  constructor •() → void
+    : super self::C::•()
+    ;
+  method m() → core::int {
+    return 2;
+  }
+}
+static method main() → dynamic {
+  self::A a = self::C::bar();
+  exp::Expect::equals(2, a.m(), null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000067.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000067.dart.outline.expect
new file mode 100644
index 0000000..c075e18
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000067.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    ;
+  static factory foo() → self::A
+    invalid-statement;
+  method m() → core::int
+    ;
+}
+class C extends self::A {
+  constructor •() → void
+    ;
+  static factory bar() → self::D
+    throw "Missing constructor: D";
+  method m() → core::int
+    ;
+}
+class D extends self::C {
+  constructor •() → void
+    ;
+  method m() → core::int
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000068.dart b/pkg/front_end/test/fasta/rasta/issue_000068.dart
new file mode 100644
index 0000000..d3f323b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000068.dart
@@ -0,0 +1,21 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+class G<T> {}
+
+class A {}
+class B extends A {}
+class C extends B {}
+
+main() {
+  Expect.isFalse(new G<B>() is G<C>);
+  Expect.isFalse(new G<A>() is G<B>);
+  Expect.isFalse(new G<A>() is G<C>);
+  Expect.isFalse(new G<Object>() is G<B>);
+  Expect.isFalse(new G<int>() is G<B>);
+  Expect.isFalse(new G<int>() is G<double>);
+  Expect.isFalse(new G<int>() is G<String>);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000068.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000068.dart.dartk.expect
new file mode 100644
index 0000000..eea2571
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000068.dart.dartk.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+class G<T extends core::Object> extends core::Object {
+  constructor •() → self::G<self::G::T>
+    : super core::Object::•();
+}
+class A extends core::Object {
+  constructor •() → self::A
+    : super core::Object::•();
+}
+class B extends self::A {
+  constructor •() → self::B
+    : super self::A::•();
+}
+class C extends self::B {
+  constructor •() → self::C
+    : super self::B::•();
+}
+static method main() → dynamic {
+  exp::Expect::isFalse(new self::G::•<self::B>() is self::G<self::C>);
+  exp::Expect::isFalse(new self::G::•<self::A>() is self::G<self::B>);
+  exp::Expect::isFalse(new self::G::•<self::A>() is self::G<self::C>);
+  exp::Expect::isFalse(new self::G::•<core::Object>() is self::G<self::B>);
+  exp::Expect::isFalse(new self::G::•<core::int>() is self::G<self::B>);
+  exp::Expect::isFalse(new self::G::•<core::int>() is self::G<core::double>);
+  exp::Expect::isFalse(new self::G::•<core::int>() is self::G<core::String>);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000068.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000068.dart.direct.expect
new file mode 100644
index 0000000..cf9d888
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000068.dart.direct.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+class G<T extends core::Object> extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    : super self::A::•()
+    ;
+}
+class C extends self::B {
+  constructor •() → void
+    : super self::B::•()
+    ;
+}
+static method main() → dynamic {
+  exp::Expect::isFalse(new self::G::•<self::B>() is self::G<self::C>, null);
+  exp::Expect::isFalse(new self::G::•<self::A>() is self::G<self::B>, null);
+  exp::Expect::isFalse(new self::G::•<self::A>() is self::G<self::C>, null);
+  exp::Expect::isFalse(new self::G::•<core::Object>() is self::G<self::B>, null);
+  exp::Expect::isFalse(new self::G::•<core::int>() is self::G<self::B>, null);
+  exp::Expect::isFalse(new self::G::•<core::int>() is self::G<core::double>, null);
+  exp::Expect::isFalse(new self::G::•<core::int>() is self::G<core::String>, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000068.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000068.dart.outline.expect
new file mode 100644
index 0000000..af7d585
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000068.dart.outline.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class G<T extends core::Object> extends core::Object {
+  constructor •() → void
+    ;
+}
+class A extends core::Object {
+  constructor •() → void
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    ;
+}
+class C extends self::B {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000069.dart b/pkg/front_end/test/fasta/rasta/issue_000069.dart
new file mode 100644
index 0000000..bffc4e3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000069.dart
@@ -0,0 +1,9 @@
+// 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.
+
+
+main() {
+  var x, i=0;
+  while (i++ < 5) var x=i;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000069.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000069.dart.dartk.expect
new file mode 100644
index 0000000..9b3d5ea
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000069.dart.dartk.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  dynamic x;
+  dynamic i = 0;
+  while ((let final dynamic #t1 = i in let final dynamic #t2 = i = #t1.+(1) in #t1).<(5)) {
+    dynamic x = i;
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000069.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000069.dart.direct.expect
new file mode 100644
index 0000000..d663f14
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000069.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  dynamic x;
+  dynamic i = 0;
+  while ((let final dynamic #t1 = i in let final dynamic #t2 = i = #t1.+(1) in #t1).<(5))
+    dynamic x = i;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000069.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000069.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000069.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000070.dart b/pkg/front_end/test/fasta/rasta/issue_000070.dart
new file mode 100644
index 0000000..cefc9de
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000070.dart
@@ -0,0 +1,44 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+class A<N, S, U> {
+  final List<U> field;
+
+  A(N n, S s) : field = new List<U>() {
+    Expect.isTrue(n is N);
+    Expect.isTrue(s is S);
+  }
+
+  A.empty() : field = null{}
+
+  factory A.f(S s) {
+    Expect.isTrue(s is S);
+    return new A.empty();
+  }
+
+  const A.c(U u, S s) : field = const [null];
+
+  List<U> get getter {
+    return field;
+  }
+
+  void set setter(S s){}
+}
+
+abstract class J<Aa, B>{}
+
+abstract class I<H, C, K> extends J<C, K>
+{ }
+
+
+main() {
+  new A<num, double, List>(1, 2.0);
+  A a = new A<int, int, int>.f(1);
+  const A<int, int, List>.c(const[], 1);
+
+  var z = a.getter;
+  a.setter = 1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000070.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000070.dart.dartk.expect
new file mode 100644
index 0000000..4f721a8
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000070.dart.dartk.expect
@@ -0,0 +1,41 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+class A<N extends core::Object, S extends core::Object, U extends core::Object> extends core::Object {
+  final field core::List<self::A::U> field;
+  constructor •(self::A::N n, self::A::S s) → dynamic
+    : self::A::field = core::List::•<self::A::U>(), super core::Object::•() {
+    exp::Expect::isTrue(n is self::A::N);
+    exp::Expect::isTrue(s is self::A::S);
+  }
+  constructor empty() → dynamic
+    : self::A::field = null, super core::Object::•() {}
+  const constructor c(self::A::U u, self::A::S s) → dynamic
+    : self::A::field = const <dynamic>[null], super core::Object::•()
+    ;
+  static factory f<N extends core::Object, S extends core::Object, U extends core::Object>(self::A::f::S s) → self::A<self::A::f::N, self::A::f::S, self::A::f::U> {
+    exp::Expect::isTrue(s is self::A::f::S);
+    return new self::A::empty<dynamic, dynamic, dynamic>();
+  }
+  get getter() → core::List<self::A::U> {
+    return this.field;
+  }
+  set setter(self::A::S s) → void {}
+}
+abstract class J<Aa extends core::Object, B extends core::Object> extends core::Object {
+  constructor •() → self::J<self::J::Aa, self::J::B>
+    : super core::Object::•();
+}
+abstract class I<H extends core::Object, C extends core::Object, K extends core::Object> extends self::J<self::I::C, self::I::K> {
+  constructor •() → self::I<self::I::H, self::I::C, self::I::K>
+    : super self::J::•();
+}
+static method main() → dynamic {
+  new self::A::•<core::num, core::double, core::List<dynamic>>(1, 2.0);
+  self::A<dynamic, dynamic, dynamic> a = self::A::f<core::int, core::int, core::int>(1);
+  const self::A::c<core::int, core::int, core::List<dynamic>>(const <dynamic>[], 1);
+  dynamic z = a.getter;
+  a.setter = 1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000070.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000070.dart.direct.expect
new file mode 100644
index 0000000..4ddcb53
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000070.dart.direct.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+class A<N extends core::Object, S extends core::Object, U extends core::Object> extends core::Object {
+  final field core::List<self::A::U> field;
+  constructor •(self::A::N n, self::A::S s) → void
+    : self::A::field = core::List::_internal<self::A::U>(core::_GROWABLE_ARRAY_MARKER), super core::Object::•() {
+    exp::Expect::isTrue(n is self::A::N, null);
+    exp::Expect::isTrue(s is self::A::S, null);
+  }
+  constructor empty() → void
+    : self::A::field = null, super core::Object::•() {}
+  const constructor c(self::A::U u, self::A::S s) → void
+    : self::A::field = const <dynamic>[null], super core::Object::•()
+    ;
+  static factory f<N extends core::Object, S extends core::Object, U extends core::Object>(self::A::f::S s) → self::A<self::A::f::N, self::A::f::S, self::A::f::U> {
+    exp::Expect::isTrue(s is self::A::f::S, null);
+    return new self::A::empty<dynamic, dynamic, dynamic>();
+  }
+  get getter() → core::List<self::A::U> {
+    return this.field;
+  }
+  set setter(self::A::S s) → void {}
+}
+abstract class J<Aa extends core::Object, B extends core::Object> extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+abstract class I<H extends core::Object, C extends core::Object, K extends core::Object> extends self::J<self::I::C, self::I::K> {
+  constructor •() → void
+    : super self::J::•()
+    ;
+}
+static method main() → dynamic {
+  new self::A::•<core::num, core::double, core::List<dynamic>>(1, 2.0);
+  self::A<dynamic, dynamic, dynamic> a = self::A::f<core::int, core::int, core::int>(1);
+  const self::A::c<core::int, core::int, core::List<dynamic>>(const <dynamic>[], 1);
+  dynamic z = a.getter;
+  a.setter = 1;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000070.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000070.dart.outline.expect
new file mode 100644
index 0000000..455f514
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000070.dart.outline.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<N extends core::Object, S extends core::Object, U extends core::Object> extends core::Object {
+  final field core::List<self::A::U> field;
+  constructor •(self::A::N n, self::A::S s) → void
+    ;
+  constructor empty() → void
+    ;
+  const constructor c(self::A::U u, self::A::S s) → void
+    ;
+  static factory f<N extends core::Object, S extends core::Object, U extends core::Object>(self::A::f::S s) → self::A<self::A::f::N, self::A::f::S, self::A::f::U>
+    ;
+  get getter() → core::List<self::A::U>
+    ;
+  set setter(self::A::S s) → void
+    ;
+}
+abstract class J<Aa extends core::Object, B extends core::Object> extends core::Object {
+  constructor •() → void
+    ;
+}
+abstract class I<H extends core::Object, C extends core::Object, K extends core::Object> extends self::J<self::I::C, self::I::K> {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000080.dart b/pkg/front_end/test/fasta/rasta/issue_000080.dart
new file mode 100644
index 0000000..6a0292d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000080.dart
@@ -0,0 +1,19 @@
+// 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.
+
+class Mixin {
+  var field;
+  foo() => 87;
+}
+
+class Foo extends Object with Mixin {
+  foo() => super.foo();
+  bar() => super.field;
+}
+
+main() {
+  var f = new Foo();
+  f.field = 42;
+  print(f.bar());
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000080.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000080.dart.dartk.expect
new file mode 100644
index 0000000..a88b736
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000080.dart.dartk.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin extends core::Object {
+  field dynamic field;
+  constructor •() → self::Mixin
+    : super core::Object::•();
+  method foo() → dynamic
+    return 87;
+}
+class Foo extends self::Object+Mixin#0 {
+  constructor •() → self::Foo
+    : super self::Object+Mixin#0::•();
+  method foo() → dynamic
+    return super.{self::Object+Mixin#0::foo}();
+  method bar() → dynamic
+    return super.{self::Object+Mixin#0::field};
+}
+abstract class Object+Mixin#0 extends core::Object implements self::Mixin {
+  field dynamic field;
+  constructor •() → dynamic
+    : super core::Object::•();
+  method foo() → dynamic
+    return 87;
+}
+static method main() → dynamic {
+  dynamic f = new self::Foo::•();
+  f.field = 42;
+  core::print(f.bar());
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000080.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000080.dart.direct.expect
new file mode 100644
index 0000000..48863d7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000080.dart.direct.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin extends core::Object {
+  field dynamic field = null;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo() → dynamic
+    return 87;
+}
+class Foo extends self::Object&Mixin {
+  constructor •() → void
+    : super self::Object&Mixin::•()
+    ;
+  method foo() → dynamic
+    return this.{=self::Object&Mixin::foo}();
+  method bar() → dynamic
+    return this.{=self::Object&Mixin::field};
+}
+abstract class Object&Mixin extends core::Object implements self::Mixin {
+  field dynamic field = null;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo() → dynamic
+    return 87;
+}
+static method main() → dynamic {
+  dynamic f = new self::Foo::•();
+  f.field = 42;
+  core::print(f.bar());
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000080.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000080.dart.outline.expect
new file mode 100644
index 0000000..ac14e5b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000080.dart.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin extends core::Object {
+  field dynamic field;
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+}
+class Foo extends self::Object&Mixin {
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+  method bar() → dynamic
+    ;
+}
+abstract class Object&Mixin = core::Object with self::Mixin {
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/issue_000081.dart b/pkg/front_end/test/fasta/rasta/issue_000081.dart
new file mode 100644
index 0000000..a05efa7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000081.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+class Base {
+  int hashCode = 42;
+}
+
+class Sub extends Base {
+  int _hashCode = null;
+
+  get hashCode => _hashCode ??= super.hashCode;
+
+  foo() {
+    _hashCode ??= super.hashCode;
+  }
+}
+
+main() {
+  print(new Sub().hashCode);
+  var l = [null];
+  l[0] ??= "fisk";
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000081.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/issue_000081.dart.dartk.expect
new file mode 100644
index 0000000..b43b34f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000081.dart.dartk.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  field core::int hashCode;
+  constructor •() → self::Base
+    : self::Base::hashCode = 42, super core::Object::•();
+}
+class Sub extends self::Base {
+  field core::int _hashCode;
+  constructor •() → self::Sub
+    : self::Sub::_hashCode = null, super self::Base::•();
+  get hashCode() → dynamic
+    return let final dynamic #t1 = this._hashCode in #t1.==(null) ? this._hashCode = super.{self::Base::hashCode} : #t1;
+  method foo() → dynamic {
+    this._hashCode.==(null) ? this._hashCode = super.{self::Base::hashCode} : null;
+  }
+}
+static method main() → dynamic {
+  core::print(new self::Sub::•().hashCode);
+  dynamic l = <dynamic>[null];
+  let final dynamic #t2 = l in let final dynamic #t3 = 0 in #t2.[](#t3).==(null) ? #t2.[]=(#t3, "fisk") : null;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000081.dart.direct.expect b/pkg/front_end/test/fasta/rasta/issue_000081.dart.direct.expect
new file mode 100644
index 0000000..2ed2e94
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000081.dart.direct.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  field core::int hashCode = 42;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class Sub extends self::Base {
+  field core::int _hashCode = null;
+  constructor •() → void
+    : super self::Base::•()
+    ;
+  get hashCode() → dynamic
+    return let final dynamic #t1 = this._hashCode in #t1.==(null) ? this._hashCode = this.{=self::Base::hashCode} : #t1;
+  method foo() → dynamic {
+    this._hashCode.==(null) ? this._hashCode = this.{=self::Base::hashCode} : null;
+  }
+}
+static method main() → dynamic {
+  core::print(new self::Sub::•().hashCode);
+  dynamic l = <dynamic>[null];
+  let final dynamic #t2 = l in let final dynamic #t3 = 0 in #t2.[](#t3).==(null) ? #t2.[]=(#t3, "fisk") : null;
+}
diff --git a/pkg/front_end/test/fasta/rasta/issue_000081.dart.outline.expect b/pkg/front_end/test/fasta/rasta/issue_000081.dart.outline.expect
new file mode 100644
index 0000000..0ad6433f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/issue_000081.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  field core::int hashCode;
+  constructor •() → void
+    ;
+}
+class Sub extends self::Base {
+  field core::int _hashCode;
+  constructor •() → void
+    ;
+  get hashCode() → dynamic
+    ;
+  method foo() → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart
new file mode 100644
index 0000000..05cfa99
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart
@@ -0,0 +1,15 @@
+// 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.
+
+class A {
+  const A()
+    : x = 'foo'
+    : x = 'foo'
+    ;
+}
+
+main() {
+  const A();
+  new A();
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.dartk.expect
new file mode 100644
index 0000000..e2a6950
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.dartk.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  const constructor •() → dynamic
+    : invalid-initializer;
+}
+static method main() → dynamic {
+  const self::A::•();
+  new self::A::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.direct.expect b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.direct.expect
new file mode 100644
index 0000000..e2a6950
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  const constructor •() → dynamic
+    : invalid-initializer;
+}
+static method main() → dynamic {
+  const self::A::•();
+  new self::A::•();
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.outline.expect b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.outline.expect
new file mode 100644
index 0000000..8c7b02d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_const_constructor.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  const constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function.dart b/pkg/front_end/test/fasta/rasta/malformed_function.dart
new file mode 100644
index 0000000..741004a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function.dart
@@ -0,0 +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.
+
+
+main() {
+  (null) = null;
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/malformed_function.dart.dartk.expect
new file mode 100644
index 0000000..5e950cf
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function.dart.dartk.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  let final dynamic #t1 = null in invalid-expression;
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function.dart.direct.expect b/pkg/front_end/test/fasta/rasta/malformed_function.dart.direct.expect
new file mode 100644
index 0000000..aceb2f1
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  throw new core::_CompileTimeError::•("pkg/front_end/test/fasta/rasta/malformed_function.dart:238: \u0027[31mError: Can't assign to this.\u0027[0m");
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function.dart.outline.expect b/pkg/front_end/test/fasta/rasta/malformed_function.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function_type.dart b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart
new file mode 100644
index 0000000..3b2ad71
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart
@@ -0,0 +1,9 @@
+// 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.
+
+typedef Handle Handle(String command);
+
+main() {
+  Handle h;
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.dartk.expect
new file mode 100644
index 0000000..9f6e3ea
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.dartk.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  invalid-type h;
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.direct.expect b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.direct.expect
new file mode 100644
index 0000000..9f6e3ea
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.direct.expect
@@ -0,0 +1,6 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  invalid-type h;
+}
diff --git a/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.outline.expect b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/malformed_function_type.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart
new file mode 100644
index 0000000..60805fe
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart
@@ -0,0 +1,6 @@
+// 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.
+
+main(arguments = [x]) {
+}
diff --git a/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.dartk.expect
new file mode 100644
index 0000000..3545c73
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.dartk.expect
@@ -0,0 +1,4 @@
+library;
+import self as self;
+
+static method main(dynamic arguments) → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.direct.expect b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.direct.expect
new file mode 100644
index 0000000..3545c73
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.direct.expect
@@ -0,0 +1,4 @@
+library;
+import self as self;
+
+static method main(dynamic arguments) → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.outline.expect b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.outline.expect
new file mode 100644
index 0000000..26f7900
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mandatory_parameter_initializer.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main(dynamic arguments) → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/mixin_library.dart b/pkg/front_end/test/fasta/rasta/mixin_library.dart
new file mode 100644
index 0000000..4360835
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mixin_library.dart
@@ -0,0 +1,24 @@
+// 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.
+
+library test.mixin_library;
+
+f() => 2;
+
+V() => 87;
+
+_private() => 117;
+
+class Mixin<T> {
+  var x = f(), y, z;
+  T t;
+  foo() => super.foo() + f();
+  T g(T a) => null;
+  h() => V();
+  l() => _private();
+  _privateMethod() => 49;
+  publicMethod() => _privateMethod();
+}
+
+foo(m) => m._privateMethod();
diff --git a/pkg/front_end/test/fasta/rasta/mixin_library.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/mixin_library.dart.dartk.expect
new file mode 100644
index 0000000..0742479
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mixin_library.dart.dartk.expect
@@ -0,0 +1,32 @@
+library test.mixin_library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin<T extends core::Object> extends core::Object {
+  field dynamic x;
+  field dynamic y;
+  field dynamic z;
+  field self::Mixin::T t;
+  constructor •() → self::Mixin<self::Mixin::T>
+    : self::Mixin::x = self::f(), super core::Object::•();
+  method foo() → dynamic
+    return (throw core::_unresolvedSuperMethodError(this, #foo, <dynamic>[], <dynamic, dynamic>{}, null)).+(self::f());
+  method g(self::Mixin::T a) → self::Mixin::T
+    return null;
+  method h() → dynamic
+    return self::V();
+  method l() → dynamic
+    return self::_private();
+  method _privateMethod() → dynamic
+    return 49;
+  method publicMethod() → dynamic
+    return this._privateMethod();
+}
+static method f() → dynamic
+  return 2;
+static method V() → dynamic
+  return 87;
+static method _private() → dynamic
+  return 117;
+static method foo(dynamic m) → dynamic
+  return m._privateMethod();
diff --git a/pkg/front_end/test/fasta/rasta/mixin_library.dart.direct.expect b/pkg/front_end/test/fasta/rasta/mixin_library.dart.direct.expect
new file mode 100644
index 0000000..59fc221
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mixin_library.dart.direct.expect
@@ -0,0 +1,33 @@
+library test.mixin_library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin<T extends core::Object> extends core::Object {
+  field dynamic x = self::f();
+  field dynamic y = null;
+  field dynamic z = null;
+  field self::Mixin::T t = null;
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo() → dynamic
+    return (throw new core::NoSuchMethodError::•(null, #foo, <dynamic>[], <dynamic, dynamic>{}, null)).+(self::f());
+  method g(self::Mixin::T a) → self::Mixin::T
+    return null;
+  method h() → dynamic
+    return self::V();
+  method l() → dynamic
+    return self::_private();
+  method _privateMethod() → dynamic
+    return 49;
+  method publicMethod() → dynamic
+    return this._privateMethod();
+}
+static method f() → dynamic
+  return 2;
+static method V() → dynamic
+  return 87;
+static method _private() → dynamic
+  return 117;
+static method foo(dynamic m) → dynamic
+  return m._privateMethod();
diff --git a/pkg/front_end/test/fasta/rasta/mixin_library.dart.outline.expect b/pkg/front_end/test/fasta/rasta/mixin_library.dart.outline.expect
new file mode 100644
index 0000000..18b80ce
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/mixin_library.dart.outline.expect
@@ -0,0 +1,32 @@
+library test.mixin_library;
+import self as self;
+import "dart:core" as core;
+
+class Mixin<T extends core::Object> extends core::Object {
+  field dynamic x;
+  field dynamic y;
+  field dynamic z;
+  field self::Mixin::T t;
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+  method g(self::Mixin::T a) → self::Mixin::T
+    ;
+  method h() → dynamic
+    ;
+  method l() → dynamic
+    ;
+  method _privateMethod() → dynamic
+    ;
+  method publicMethod() → dynamic
+    ;
+}
+static method f() → dynamic
+  ;
+static method V() → dynamic
+  ;
+static method _private() → dynamic
+  ;
+static method foo(dynamic m) → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/native_is_illegal.dart b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart
new file mode 100644
index 0000000..84b8275
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart
@@ -0,0 +1,12 @@
+// 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.
+
+foo() native "foo";
+
+class Bar {
+  Bar get x native "Bar_get_x";
+  set x(Bar value) native "Bar_set_x";
+  f() native "Bar_f";
+  factory Bar() native "Bar_constructor";
+}
diff --git a/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.dartk.expect
new file mode 100644
index 0000000..36cec9b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.dartk.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Bar extends core::Object {
+  get x() → self::Bar
+    return "Bar_get_x";
+  set x(self::Bar value) → dynamic
+    return "Bar_set_x";
+  method f() → dynamic
+    return "Bar_f";
+  static factory •() → self::Bar
+    return "Bar_constructor";
+}
+static method foo() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.direct.expect b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.direct.expect
new file mode 100644
index 0000000..36cec9b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.direct.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Bar extends core::Object {
+  get x() → self::Bar
+    return "Bar_get_x";
+  set x(self::Bar value) → dynamic
+    return "Bar_set_x";
+  method f() → dynamic
+    return "Bar_f";
+  static factory •() → self::Bar
+    return "Bar_constructor";
+}
+static method foo() → dynamic
+  invalid-statement;
diff --git a/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.outline.expect b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.outline.expect
new file mode 100644
index 0000000..a7ea25b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/native_is_illegal.dart.outline.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Bar extends core::Object {
+  get x() → self::Bar
+    ;
+  set x(self::Bar value) → dynamic
+    ;
+  method f() → dynamic
+    ;
+  static factory •() → self::Bar
+    ;
+}
+static method foo() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/parser_error.dart b/pkg/front_end/test/fasta/rasta/parser_error.dart
new file mode 100644
index 0000000..130d0ea
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/parser_error.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// Copy of third_party/dart-sdk/tests/language/argument_definition_test.dart.
+
+import "package:expect/expect.dart";
+
+int test(a, {b, c}) {
+  if (?b) return b;  /// 01: compile-time error
+  return a + b + c;
+}
+
+main() {
+  Expect.equals(6, test(1, b: 2, c:3));
+}
diff --git a/pkg/front_end/test/fasta/rasta/parser_error.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/parser_error.dart.dartk.expect
new file mode 100644
index 0000000..12c517d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/parser_error.dart.dartk.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "package:expect/expect.dart" as exp;
+import "dart:core" as core;
+
+static method test() → dynamic
+  invalid-statement;
+static method main() → dynamic {
+  exp::Expect::equals(6, throw core::_genericNoSuchMethod(null, #test, <dynamic>[1], <dynamic, dynamic>{#b: 2, #c: 3}, <dynamic>[]));
+}
diff --git a/pkg/front_end/test/fasta/rasta/parser_error.dart.direct.expect b/pkg/front_end/test/fasta/rasta/parser_error.dart.direct.expect
new file mode 100644
index 0000000..12c517d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/parser_error.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "package:expect/expect.dart" as exp;
+import "dart:core" as core;
+
+static method test() → dynamic
+  invalid-statement;
+static method main() → dynamic {
+  exp::Expect::equals(6, throw core::_genericNoSuchMethod(null, #test, <dynamic>[1], <dynamic, dynamic>{#b: 2, #c: 3}, <dynamic>[]));
+}
diff --git a/pkg/front_end/test/fasta/rasta/parser_error.dart.outline.expect b/pkg/front_end/test/fasta/rasta/parser_error.dart.outline.expect
new file mode 100644
index 0000000..4d53b67
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/parser_error.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test(dynamic a, {dynamic b, dynamic c}) → core::int
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/previsit_deferred.dart b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart
new file mode 100644
index 0000000..6bdd3e9
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart
@@ -0,0 +1,9 @@
+// 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.
+
+import 'deferred_lib.dart' deferred as lib;
+
+main() {
+  lib.foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.dartk.expect
new file mode 100644
index 0000000..93e2b71
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "./deferred_lib.dart" as def;
+
+static method main() → dynamic {
+  def::foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.direct.expect b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.direct.expect
new file mode 100644
index 0000000..93e2b71
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "./deferred_lib.dart" as def;
+
+static method main() → dynamic {
+  def::foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.outline.expect b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/previsit_deferred.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/static.dart b/pkg/front_end/test/fasta/rasta/static.dart
new file mode 100644
index 0000000..d9f6df7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/static.dart
@@ -0,0 +1,85 @@
+// 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.
+
+class Foo {
+  static const staticConstant = 42;
+  static var staticField = 42;
+  static staticFunction() {
+  }
+
+  static get staticGetter => null;
+  static set staticSetter(_) {}
+}
+
+use(x) {
+  if (x == new DateTime.now().millisecondsSinceEpoch) throw "Shouldn't happen";
+}
+
+main() {
+  Foo.staticConstant;
+  use(Foo.staticConstant);
+  Foo.staticField;
+  use(Foo.staticField);
+  Foo.staticFunction;
+  use(Foo.staticFunction);
+  Foo.staticGetter;
+  use(Foo.staticGetter);
+  Foo.staticSetter;
+  use(Foo.staticSetter);
+
+  Foo.staticConstant++;
+  use(Foo.staticConstant++);
+  Foo.staticField++;
+  use(Foo.staticField++);
+  Foo.staticFunction++;
+  use(Foo.staticFunction++);
+  Foo.staticGetter++;
+  use(Foo.staticGetter++);
+  Foo.staticSetter++;
+  use(Foo.staticSetter++);
+
+  ++Foo.staticConstant;
+  use(++Foo.staticConstant);
+  ++Foo.staticField;
+  use(++Foo.staticField);
+  ++Foo.staticFunction;
+  use(++Foo.staticFunction);
+  ++Foo.staticGetter;
+  use(++Foo.staticGetter);
+  ++Foo.staticSetter;
+  use(++Foo.staticSetter);
+
+  Foo.staticConstant();
+  use(Foo.staticConstant());
+  Foo.staticField();
+  use(Foo.staticField());
+  Foo.staticFunction();
+  use(Foo.staticFunction());
+  Foo.staticGetter();
+  use(Foo.staticGetter());
+  Foo.staticSetter();
+  use(Foo.staticSetter());
+
+  Foo.staticConstant = 87;
+  use(Foo.staticConstant = 87);
+  Foo.staticField = 87;
+  use(Foo.staticField = 87);
+  Foo.staticFunction = 87;
+  use(Foo.staticFunction = 87);
+  Foo.staticGetter = 87;
+  use(Foo.staticGetter = 87);
+  Foo.staticSetter = 87;
+  use(Foo.staticSetter = 87);
+
+  Foo.staticConstant ??= 87;
+  use(Foo.staticConstant ??= 87);
+  Foo.staticField ??= 87;
+  use(Foo.staticField ??= 87);
+  Foo.staticFunction ??= 87;
+  use(Foo.staticFunction ??= 87);
+  Foo.staticGetter ??= 87;
+  use(Foo.staticGetter ??= 87);
+  Foo.staticSetter ??= 87;
+  use(Foo.staticSetter ??= 87);
+}
diff --git a/pkg/front_end/test/fasta/rasta/static.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/static.dart.dartk.expect
new file mode 100644
index 0000000..5bf3f40
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/static.dart.dartk.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  static const field dynamic staticConstant = 42;
+  static field dynamic staticField = 42;
+  constructor •() → self::Foo
+    : super core::Object::•();
+  static method staticFunction() → dynamic {}
+  static get staticGetter() → dynamic
+    return null;
+  static set staticSetter(dynamic _) → dynamic {}
+}
+static method use(dynamic x) → dynamic {
+  if(x.==(new core::DateTime::now().millisecondsSinceEpoch))
+    throw "Shouldn't happen";
+}
+static method main() → dynamic {
+  self::Foo::staticConstant;
+  self::use(self::Foo::staticConstant);
+  self::Foo::staticField;
+  self::use(self::Foo::staticField);
+  self::Foo::staticFunction;
+  self::use(self::Foo::staticFunction);
+  self::Foo::staticGetter;
+  self::use(self::Foo::staticGetter);
+  invalid-expression;
+  self::use(invalid-expression);
+  let final dynamic #t1 = self::Foo::staticConstant.+(1) in invalid-expression;
+  self::use(let final dynamic #t2 = self::Foo::staticConstant in let final dynamic #t3 = let final dynamic #t4 = #t2.+(1) in invalid-expression in #t2);
+  self::Foo::staticField = self::Foo::staticField.+(1);
+  self::use(let final dynamic #t5 = self::Foo::staticField in let final dynamic #t6 = self::Foo::staticField = #t5.+(1) in #t5);
+  let final dynamic #t7 = self::Foo::staticFunction.+(1) in invalid-expression;
+  self::use(let final dynamic #t8 = self::Foo::staticFunction in let final dynamic #t9 = let final dynamic #t10 = #t8.+(1) in invalid-expression in #t8);
+  throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[self::Foo::staticGetter.+(1)], <dynamic, dynamic>{}, null);
+  self::use(let final dynamic #t11 = self::Foo::staticGetter in let final dynamic #t12 = throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[#t11.+(1)], <dynamic, dynamic>{}, null) in #t11);
+  throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null));
+  let final dynamic #t13 = self::Foo::staticConstant.+(1) in invalid-expression;
+  self::use(let final dynamic #t14 = self::Foo::staticConstant.+(1) in invalid-expression);
+  self::Foo::staticField = self::Foo::staticField.+(1);
+  self::use(self::Foo::staticField = self::Foo::staticField.+(1));
+  let final dynamic #t15 = self::Foo::staticFunction.+(1) in invalid-expression;
+  self::use(let final dynamic #t16 = self::Foo::staticFunction.+(1) in invalid-expression);
+  throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[self::Foo::staticGetter.+(1)], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[self::Foo::staticGetter.+(1)], <dynamic, dynamic>{}, null));
+  throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null));
+  self::Foo::staticConstant.call();
+  self::use(self::Foo::staticConstant.call());
+  self::Foo::staticField.call();
+  self::use(self::Foo::staticField.call());
+  self::Foo::staticFunction();
+  self::use(self::Foo::staticFunction());
+  self::Foo::staticGetter.call();
+  self::use(self::Foo::staticGetter.call());
+  invalid-expression.call();
+  self::use(invalid-expression.call());
+  let final dynamic #t17 = 87 in invalid-expression;
+  self::use(let final dynamic #t18 = 87 in invalid-expression);
+  self::Foo::staticField = 87;
+  self::use(self::Foo::staticField = 87);
+  let final dynamic #t19 = 87 in invalid-expression;
+  self::use(let final dynamic #t20 = 87 in invalid-expression);
+  let final dynamic #t21 = 87 in invalid-expression;
+  self::use(let final dynamic #t22 = 87 in invalid-expression);
+  self::Foo::staticSetter = 87;
+  self::use(self::Foo::staticSetter = 87);
+  self::Foo::staticConstant.==(null) ? let final dynamic #t23 = 87 in invalid-expression : null;
+  self::use(let final dynamic #t24 = self::Foo::staticConstant in #t24.==(null) ? let final dynamic #t25 = 87 in invalid-expression : #t24);
+  self::Foo::staticField.==(null) ? self::Foo::staticField = 87 : null;
+  self::use(let final dynamic #t26 = self::Foo::staticField in #t26.==(null) ? self::Foo::staticField = 87 : #t26);
+  self::Foo::staticFunction.==(null) ? let final dynamic #t27 = 87 in invalid-expression : null;
+  self::use(let final dynamic #t28 = self::Foo::staticFunction in #t28.==(null) ? let final dynamic #t29 = 87 in invalid-expression : #t28);
+  self::Foo::staticGetter.==(null) ? throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[87], <dynamic, dynamic>{}, null) : null;
+  self::use(let final dynamic #t30 = self::Foo::staticGetter in #t30.==(null) ? throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[87], <dynamic, dynamic>{}, null) : #t30);
+  throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null));
+}
diff --git a/pkg/front_end/test/fasta/rasta/static.dart.direct.expect b/pkg/front_end/test/fasta/rasta/static.dart.direct.expect
new file mode 100644
index 0000000..5bf3f40
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/static.dart.direct.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  static const field dynamic staticConstant = 42;
+  static field dynamic staticField = 42;
+  constructor •() → self::Foo
+    : super core::Object::•();
+  static method staticFunction() → dynamic {}
+  static get staticGetter() → dynamic
+    return null;
+  static set staticSetter(dynamic _) → dynamic {}
+}
+static method use(dynamic x) → dynamic {
+  if(x.==(new core::DateTime::now().millisecondsSinceEpoch))
+    throw "Shouldn't happen";
+}
+static method main() → dynamic {
+  self::Foo::staticConstant;
+  self::use(self::Foo::staticConstant);
+  self::Foo::staticField;
+  self::use(self::Foo::staticField);
+  self::Foo::staticFunction;
+  self::use(self::Foo::staticFunction);
+  self::Foo::staticGetter;
+  self::use(self::Foo::staticGetter);
+  invalid-expression;
+  self::use(invalid-expression);
+  let final dynamic #t1 = self::Foo::staticConstant.+(1) in invalid-expression;
+  self::use(let final dynamic #t2 = self::Foo::staticConstant in let final dynamic #t3 = let final dynamic #t4 = #t2.+(1) in invalid-expression in #t2);
+  self::Foo::staticField = self::Foo::staticField.+(1);
+  self::use(let final dynamic #t5 = self::Foo::staticField in let final dynamic #t6 = self::Foo::staticField = #t5.+(1) in #t5);
+  let final dynamic #t7 = self::Foo::staticFunction.+(1) in invalid-expression;
+  self::use(let final dynamic #t8 = self::Foo::staticFunction in let final dynamic #t9 = let final dynamic #t10 = #t8.+(1) in invalid-expression in #t8);
+  throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[self::Foo::staticGetter.+(1)], <dynamic, dynamic>{}, null);
+  self::use(let final dynamic #t11 = self::Foo::staticGetter in let final dynamic #t12 = throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[#t11.+(1)], <dynamic, dynamic>{}, null) in #t11);
+  throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null));
+  let final dynamic #t13 = self::Foo::staticConstant.+(1) in invalid-expression;
+  self::use(let final dynamic #t14 = self::Foo::staticConstant.+(1) in invalid-expression);
+  self::Foo::staticField = self::Foo::staticField.+(1);
+  self::use(self::Foo::staticField = self::Foo::staticField.+(1));
+  let final dynamic #t15 = self::Foo::staticFunction.+(1) in invalid-expression;
+  self::use(let final dynamic #t16 = self::Foo::staticFunction.+(1) in invalid-expression);
+  throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[self::Foo::staticGetter.+(1)], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[self::Foo::staticGetter.+(1)], <dynamic, dynamic>{}, null));
+  throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null));
+  self::Foo::staticConstant.call();
+  self::use(self::Foo::staticConstant.call());
+  self::Foo::staticField.call();
+  self::use(self::Foo::staticField.call());
+  self::Foo::staticFunction();
+  self::use(self::Foo::staticFunction());
+  self::Foo::staticGetter.call();
+  self::use(self::Foo::staticGetter.call());
+  invalid-expression.call();
+  self::use(invalid-expression.call());
+  let final dynamic #t17 = 87 in invalid-expression;
+  self::use(let final dynamic #t18 = 87 in invalid-expression);
+  self::Foo::staticField = 87;
+  self::use(self::Foo::staticField = 87);
+  let final dynamic #t19 = 87 in invalid-expression;
+  self::use(let final dynamic #t20 = 87 in invalid-expression);
+  let final dynamic #t21 = 87 in invalid-expression;
+  self::use(let final dynamic #t22 = 87 in invalid-expression);
+  self::Foo::staticSetter = 87;
+  self::use(self::Foo::staticSetter = 87);
+  self::Foo::staticConstant.==(null) ? let final dynamic #t23 = 87 in invalid-expression : null;
+  self::use(let final dynamic #t24 = self::Foo::staticConstant in #t24.==(null) ? let final dynamic #t25 = 87 in invalid-expression : #t24);
+  self::Foo::staticField.==(null) ? self::Foo::staticField = 87 : null;
+  self::use(let final dynamic #t26 = self::Foo::staticField in #t26.==(null) ? self::Foo::staticField = 87 : #t26);
+  self::Foo::staticFunction.==(null) ? let final dynamic #t27 = 87 in invalid-expression : null;
+  self::use(let final dynamic #t28 = self::Foo::staticFunction in #t28.==(null) ? let final dynamic #t29 = 87 in invalid-expression : #t28);
+  self::Foo::staticGetter.==(null) ? throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[87], <dynamic, dynamic>{}, null) : null;
+  self::use(let final dynamic #t30 = self::Foo::staticGetter in #t30.==(null) ? throw core::_unresolvedStaticSetterError(null, #staticGetter, <dynamic>[87], <dynamic, dynamic>{}, null) : #t30);
+  throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null);
+  self::use(throw core::_unresolvedStaticGetterError(null, #staticSetter, <dynamic>[], <dynamic, dynamic>{}, null));
+}
diff --git a/pkg/front_end/test/fasta/rasta/static.dart.outline.expect b/pkg/front_end/test/fasta/rasta/static.dart.outline.expect
new file mode 100644
index 0000000..3f3156b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/static.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  static const field dynamic staticConstant;
+  static field dynamic staticField;
+  constructor •() → void
+    ;
+  static method staticFunction() → dynamic
+    ;
+  static get staticGetter() → dynamic
+    ;
+  static set staticSetter(dynamic _) → dynamic
+    ;
+}
+static method use(dynamic x) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/super.dart b/pkg/front_end/test/fasta/rasta/super.dart
new file mode 100644
index 0000000..ce1f657
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super.dart
@@ -0,0 +1,260 @@
+// 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.
+
+class A {
+  var a;
+  var b;
+  var c;
+  var d;
+  get e => null;
+  final f;
+  set g(_) {}
+  get h => null;
+  set h(_) {}
+  get i => null;
+
+  operator [](_) => null;
+  operator []=(a, b) {}
+  operator ~() => 117;
+  operator -() => 117;
+
+  operator ==(other) => true;
+
+  void m() {}
+
+  void n() {}
+  set n(_) {}
+}
+
+class B extends A {
+  get b => null;
+  set c(x) {}
+  final d;
+  set i(x) {}}
+
+
+class C extends B {
+  test() {
+    ~super;
+    use(~super);
+    -super;
+    use(-super);
+    +super;
+    use(+super);
+    super == 87;
+    use(super == 87);
+    super != 87;
+    use(super != 87);
+
+    super.a;
+    use(super.a);
+    super.b;
+    use(super.b);
+    super.c;
+    use(super.c);
+    super.d;
+    use(super.d);
+    super.e;
+    use(super.e);
+    super.f;
+    use(super.f);
+    super.g;
+    use(super.g);
+    super.h;
+    use(super.h);
+    super.i;
+    use(super.i);
+    super[87];
+    use(super[87]);
+    super.m;
+    use(super.m);
+    super.n;
+    use(super.n);
+
+    super.a++;
+    use(super.a++);
+    super.b++;
+    use(super.b++);
+    super.c++;
+    use(super.c++);
+    super.d++;
+    use(super.d++);
+    super.e++;
+    use(super.e++);
+    super.f++;
+    use(super.f++);
+    super.g++;
+    use(super.g++);
+    super.h++;
+    use(super.h++);
+    super.i++;
+    use(super.i++);
+    super[87]++;
+    use(super[87]++);
+    super.m++;
+    use(super.m++);
+    super.n++;
+    use(super.n++);
+
+    ++super.a;
+    use(++super.a);
+    ++super.b;
+    use(++super.b);
+    ++super.c;
+    use(++super.c);
+    ++super.d;
+    use(++super.d);
+    ++super.e;
+    use(++super.e);
+    ++super.f;
+    use(++super.f);
+    ++super.g;
+    use(++super.g);
+    ++super.h;
+    use(++super.h);
+    ++super.i;
+    use(++super.i);
+    ++super[87];
+    use(++super[87]);
+    ++super.m;
+    use(++super.m);
+    ++super.n;
+    use(++super.n);
+
+    super.a();
+    use(super.a());
+    super.b();
+    use(super.b());
+    super.c();
+    use(super.c());
+    super.d();
+    use(super.d());
+    super.e();
+    use(super.e());
+    super.f();
+    use(super.f());
+    super.g();
+    use(super.g());
+    super.h();
+    use(super.h());
+    super.i();
+    use(super.i());
+    super[87]();
+    use(super[87]());
+    super.m();
+    use(super.m());
+    super.m(87);
+    use(super.m(87));
+    super.n(87);
+    use(super.n(87));
+
+    super.a = 42;
+    use(super.a = 42);
+    super.b = 42;
+    use(super.b = 42);
+    super.c = 42;
+    use(super.c = 42);
+    super.d = 42;
+    use(super.d = 42);
+    super.e = 42;
+    use(super.e = 42);
+    super.f = 42;
+    use(super.f = 42);
+    super.g = 42;
+    use(super.g = 42);
+    super.h = 42;
+    use(super.h = 42);
+    super.i = 42;
+    use(super.i = 42);
+    super[87] = 42;
+    use(super[87] = 42);
+    super.m = 42;
+    use(super.m = 42);
+    super.n = 42;
+    use(super.n = 42);
+
+    super.a ??= 42;
+    use(super.a ??= 42);
+    super.b ??= 42;
+    use(super.b ??= 42);
+    super.c ??= 42;
+    use(super.c ??= 42);
+    super.d ??= 42;
+    use(super.d ??= 42);
+    super.e ??= 42;
+    use(super.e ??= 42);
+    super.f ??= 42;
+    use(super.f ??= 42);
+    super.g ??= 42;
+    use(super.g ??= 42);
+    super.h ??= 42;
+    use(super.h ??= 42);
+    super.i ??= 42;
+    use(super.i ??= 42);
+    super[87] ??= 42;
+    use(super[87] ??= 42);
+    super.m ??= 42;
+    use(super.m ??= 42);
+    super.n ??= 42;
+    use(super.n ??= 42);
+
+    super.a += 42;
+    use(super.a += 42);
+    super.b += 42;
+    use(super.b += 42);
+    super.c += 42;
+    use(super.c += 42);
+    super.d += 42;
+    use(super.d += 42);
+    super.e += 42;
+    use(super.e += 42);
+    super.f += 42;
+    use(super.f += 42);
+    super.g += 42;
+    use(super.g += 42);
+    super.h += 42;
+    use(super.h += 42);
+    super.i += 42;
+    use(super.i += 42);
+    super[87] += 42;
+    use(super[87] += 42);
+    super.m += 42;
+    use(super.m += 42);
+    super.n += 42;
+    use(super.n += 42);
+
+    super.a -= 42;
+    use(super.a -= 42);
+    super.b -= 42;
+    use(super.b -= 42);
+    super.c -= 42;
+    use(super.c -= 42);
+    super.d -= 42;
+    use(super.d -= 42);
+    super.e -= 42;
+    use(super.e -= 42);
+    super.f -= 42;
+    use(super.f -= 42);
+    super.g -= 42;
+    use(super.g -= 42);
+    super.h -= 42;
+    use(super.h -= 42);
+    super.i -= 42;
+    use(super.i -= 42);
+    super[87] -= 42;
+    use(super[87] -= 42);
+    super.m -= 42;
+    use(super.m -= 42);
+    super.n -= 42;
+    use(super.n -= 42);
+  }
+}
+
+use(x) {
+  if (x == new DateTime.now().millisecondsSinceEpoch) throw "Shouldn't happen";
+}
+
+main() {
+  new C().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/super.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/super.dart.dartk.expect
new file mode 100644
index 0000000..f725931
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super.dart.dartk.expect
@@ -0,0 +1,259 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  field dynamic d;
+  final field dynamic f;
+  constructor •() → self::A
+    : super core::Object::•();
+  get e() → dynamic
+    return null;
+  set g(dynamic _) → dynamic {}
+  get h() → dynamic
+    return null;
+  set h(dynamic _) → dynamic {}
+  get i() → dynamic
+    return null;
+  operator [](dynamic _) → dynamic
+    return null;
+  operator []=(dynamic a, dynamic b) → dynamic {}
+  operator ~() → dynamic
+    return 117;
+  operator unary-() → dynamic
+    return 117;
+  operator ==(dynamic other) → dynamic
+    return true;
+  method m() → void {}
+  method n() → void {}
+  set n(dynamic _) → dynamic {}
+}
+class B extends self::A {
+  final field dynamic d;
+  constructor •() → self::B
+    : super self::A::•();
+  get b() → dynamic
+    return null;
+  set c(dynamic x) → dynamic {}
+  set i(dynamic x) → dynamic {}
+}
+class C extends self::B {
+  constructor •() → self::C
+    : super self::B::•();
+  method test() → dynamic {
+    super.{self::A::~}();
+    self::use(super.{self::A::~}());
+    super.{self::A::unary-}();
+    self::use(super.{self::A::unary-}());
+    invalid-expression;
+    self::use(invalid-expression);
+    super.{self::A::==}(87);
+    self::use(super.{self::A::==}(87));
+    !super.{self::A::==}(87);
+    self::use(!super.{self::A::==}(87));
+    super.{self::A::a};
+    self::use(super.{self::A::a});
+    super.{self::B::b};
+    self::use(super.{self::B::b});
+    super.{self::A::c};
+    self::use(super.{self::A::c});
+    super.{self::B::d};
+    self::use(super.{self::B::d});
+    super.{self::A::e};
+    self::use(super.{self::A::e});
+    super.{self::A::f};
+    self::use(super.{self::A::f});
+    super.g;
+    self::use(super.g);
+    super.{self::A::h};
+    self::use(super.{self::A::h});
+    super.{self::A::i};
+    self::use(super.{self::A::i});
+    super.{self::A::[]}(87);
+    self::use(super.{self::A::[]}(87));
+    super.{self::A::m};
+    self::use(super.{self::A::m});
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.+(1);
+    self::use(let final dynamic #t1 = super.{self::A::a} in let final dynamic #t2 = super.{self::A::a} = #t1.+(1) in #t1);
+    super.{self::A::b} = super.{self::B::b}.+(1);
+    self::use(let final dynamic #t3 = super.{self::B::b} in let final dynamic #t4 = super.{self::A::b} = #t3.+(1) in #t3);
+    super.{self::B::c} = super.{self::A::c}.+(1);
+    self::use(let final dynamic #t5 = super.{self::A::c} in let final dynamic #t6 = super.{self::B::c} = #t5.+(1) in #t5);
+    super.d = super.{self::B::d}.+(1);
+    self::use(let final dynamic #t7 = super.{self::B::d} in let final dynamic #t8 = super.d = #t7.+(1) in #t7);
+    super.e = super.{self::A::e}.+(1);
+    self::use(let final dynamic #t9 = super.{self::A::e} in let final dynamic #t10 = super.e = #t9.+(1) in #t9);
+    super.f = super.{self::A::f}.+(1);
+    self::use(let final dynamic #t11 = super.{self::A::f} in let final dynamic #t12 = super.f = #t11.+(1) in #t11);
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.+(1);
+    self::use(let final dynamic #t13 = super.{self::A::h} in let final dynamic #t14 = super.{self::A::h} = #t13.+(1) in #t13);
+    super.{self::B::i} = super.{self::A::i}.+(1);
+    self::use(let final dynamic #t15 = super.{self::A::i} in let final dynamic #t16 = super.{self::B::i} = #t15.+(1) in #t15);
+    let final dynamic #t17 = 87 in super.{self::A::[]=}(#t17, super.{self::A::[]}(#t17).+(1));
+    self::use(let final dynamic #t18 = 87 in let final dynamic #t19 = super.{self::A::[]}(#t18) in let final dynamic #t20 = super.{self::A::[]=}(#t18, #t19.+(1)) in #t19);
+    super.m = super.{self::A::m}.+(1);
+    self::use(let final dynamic #t21 = super.{self::A::m} in let final dynamic #t22 = super.m = #t21.+(1) in #t21);
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.+(1);
+    self::use(super.{self::A::a} = super.{self::A::a}.+(1));
+    super.{self::A::b} = super.{self::B::b}.+(1);
+    self::use(super.{self::A::b} = super.{self::B::b}.+(1));
+    super.{self::B::c} = super.{self::A::c}.+(1);
+    self::use(super.{self::B::c} = super.{self::A::c}.+(1));
+    super.d = super.{self::B::d}.+(1);
+    self::use(super.d = super.{self::B::d}.+(1));
+    super.e = super.{self::A::e}.+(1);
+    self::use(super.e = super.{self::A::e}.+(1));
+    super.f = super.{self::A::f}.+(1);
+    self::use(super.f = super.{self::A::f}.+(1));
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.+(1);
+    self::use(super.{self::A::h} = super.{self::A::h}.+(1));
+    super.{self::B::i} = super.{self::A::i}.+(1);
+    self::use(super.{self::B::i} = super.{self::A::i}.+(1));
+    let final dynamic #t23 = 87 in super.{self::A::[]=}(#t23, super.{self::A::[]}(#t23).+(1));
+    self::use(let final dynamic #t24 = 87 in let final dynamic #t25 = super.{self::A::[]}(#t24).+(1) in let final dynamic #t26 = super.{self::A::[]=}(#t24, #t25) in #t25);
+    super.m = super.{self::A::m}.+(1);
+    self::use(super.m = super.{self::A::m}.+(1));
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a}.call();
+    self::use(super.{self::A::a}.call());
+    super.{self::B::b}.call();
+    self::use(super.{self::B::b}.call());
+    super.{self::A::c}.call();
+    self::use(super.{self::A::c}.call());
+    super.{self::B::d}.call();
+    self::use(super.{self::B::d}.call());
+    super.{self::A::e}.call();
+    self::use(super.{self::A::e}.call());
+    super.{self::A::f}.call();
+    self::use(super.{self::A::f}.call());
+    super.g.call();
+    self::use(super.g.call());
+    super.{self::A::h}.call();
+    self::use(super.{self::A::h}.call());
+    super.{self::A::i}.call();
+    self::use(super.{self::A::i}.call());
+    super.{self::A::[]}(87).call();
+    self::use(super.{self::A::[]}(87).call());
+    super.{self::A::m}();
+    self::use(super.{self::A::m}());
+    super.{self::A::m}(87);
+    self::use(super.{self::A::m}(87));
+    throw core::_unresolvedSuperMethodError(this, #n, <dynamic>[87], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperMethodError(this, #n, <dynamic>[87], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = 42;
+    self::use(super.{self::A::a} = 42);
+    super.{self::A::b} = 42;
+    self::use(super.{self::A::b} = 42);
+    super.{self::B::c} = 42;
+    self::use(super.{self::B::c} = 42);
+    super.d = 42;
+    self::use(super.d = 42);
+    super.e = 42;
+    self::use(super.e = 42);
+    super.f = 42;
+    self::use(super.f = 42);
+    super.{self::A::g} = 42;
+    self::use(super.{self::A::g} = 42);
+    super.{self::A::h} = 42;
+    self::use(super.{self::A::h} = 42);
+    super.{self::B::i} = 42;
+    self::use(super.{self::B::i} = 42);
+    super.{self::A::[]=}(87, 42);
+    self::use(let final dynamic #t27 = 87 in let final dynamic #t28 = 42 in let final dynamic #t29 = super.{self::A::[]=}(#t27, #t28) in #t28);
+    super.m = 42;
+    self::use(super.m = 42);
+    throw core::_unresolvedSuperSetterError(this, #n, <dynamic>[42], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperSetterError(this, #n, <dynamic>[42], <dynamic, dynamic>{}, null));
+    super.{self::A::a}.==(null) ? super.{self::A::a} = 42 : null;
+    self::use(let final dynamic #t30 = super.{self::A::a} in #t30.==(null) ? super.{self::A::a} = 42 : #t30);
+    super.{self::B::b}.==(null) ? super.{self::A::b} = 42 : null;
+    self::use(let final dynamic #t31 = super.{self::B::b} in #t31.==(null) ? super.{self::A::b} = 42 : #t31);
+    super.{self::A::c}.==(null) ? super.{self::B::c} = 42 : null;
+    self::use(let final dynamic #t32 = super.{self::A::c} in #t32.==(null) ? super.{self::B::c} = 42 : #t32);
+    super.{self::B::d}.==(null) ? super.d = 42 : null;
+    self::use(let final dynamic #t33 = super.{self::B::d} in #t33.==(null) ? super.d = 42 : #t33);
+    super.{self::A::e}.==(null) ? super.e = 42 : null;
+    self::use(let final dynamic #t34 = super.{self::A::e} in #t34.==(null) ? super.e = 42 : #t34);
+    super.{self::A::f}.==(null) ? super.f = 42 : null;
+    self::use(let final dynamic #t35 = super.{self::A::f} in #t35.==(null) ? super.f = 42 : #t35);
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h}.==(null) ? super.{self::A::h} = 42 : null;
+    self::use(let final dynamic #t36 = super.{self::A::h} in #t36.==(null) ? super.{self::A::h} = 42 : #t36);
+    super.{self::A::i}.==(null) ? super.{self::B::i} = 42 : null;
+    self::use(let final dynamic #t37 = super.{self::A::i} in #t37.==(null) ? super.{self::B::i} = 42 : #t37);
+    let final dynamic #t38 = 87 in super.{self::A::[]}(#t38).==(null) ? super.{self::A::[]=}(#t38, 42) : null;
+    self::use(let final dynamic #t39 = 87 in let final dynamic #t40 = super.{self::A::[]}(#t39) in #t40.==(null) ? let final dynamic #t41 = 42 in let final dynamic #t42 = super.{self::A::[]=}(#t39, #t41) in #t41 : #t40);
+    super.{self::A::m}.==(null) ? super.m = 42 : null;
+    self::use(let final dynamic #t43 = super.{self::A::m} in #t43.==(null) ? super.m = 42 : #t43);
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.+(42);
+    self::use(super.{self::A::a} = super.{self::A::a}.+(42));
+    super.{self::A::b} = super.{self::B::b}.+(42);
+    self::use(super.{self::A::b} = super.{self::B::b}.+(42));
+    super.{self::B::c} = super.{self::A::c}.+(42);
+    self::use(super.{self::B::c} = super.{self::A::c}.+(42));
+    super.d = super.{self::B::d}.+(42);
+    self::use(super.d = super.{self::B::d}.+(42));
+    super.e = super.{self::A::e}.+(42);
+    self::use(super.e = super.{self::A::e}.+(42));
+    super.f = super.{self::A::f}.+(42);
+    self::use(super.f = super.{self::A::f}.+(42));
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.+(42);
+    self::use(super.{self::A::h} = super.{self::A::h}.+(42));
+    super.{self::B::i} = super.{self::A::i}.+(42);
+    self::use(super.{self::B::i} = super.{self::A::i}.+(42));
+    let final dynamic #t44 = 87 in super.{self::A::[]=}(#t44, super.{self::A::[]}(#t44).+(42));
+    self::use(let final dynamic #t45 = 87 in let final dynamic #t46 = super.{self::A::[]}(#t45).+(42) in let final dynamic #t47 = super.{self::A::[]=}(#t45, #t46) in #t46);
+    super.m = super.{self::A::m}.+(42);
+    self::use(super.m = super.{self::A::m}.+(42));
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.-(42);
+    self::use(super.{self::A::a} = super.{self::A::a}.-(42));
+    super.{self::A::b} = super.{self::B::b}.-(42);
+    self::use(super.{self::A::b} = super.{self::B::b}.-(42));
+    super.{self::B::c} = super.{self::A::c}.-(42);
+    self::use(super.{self::B::c} = super.{self::A::c}.-(42));
+    super.d = super.{self::B::d}.-(42);
+    self::use(super.d = super.{self::B::d}.-(42));
+    super.e = super.{self::A::e}.-(42);
+    self::use(super.e = super.{self::A::e}.-(42));
+    super.f = super.{self::A::f}.-(42);
+    self::use(super.f = super.{self::A::f}.-(42));
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.-(42);
+    self::use(super.{self::A::h} = super.{self::A::h}.-(42));
+    super.{self::B::i} = super.{self::A::i}.-(42);
+    self::use(super.{self::B::i} = super.{self::A::i}.-(42));
+    let final dynamic #t48 = 87 in super.{self::A::[]=}(#t48, super.{self::A::[]}(#t48).-(42));
+    self::use(let final dynamic #t49 = 87 in let final dynamic #t50 = super.{self::A::[]}(#t49).-(42) in let final dynamic #t51 = super.{self::A::[]=}(#t49, #t50) in #t50);
+    super.m = super.{self::A::m}.-(42);
+    self::use(super.m = super.{self::A::m}.-(42));
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+  }
+}
+static method use(dynamic x) → dynamic {
+  if(x.==(new core::DateTime::now().millisecondsSinceEpoch))
+    throw "Shouldn't happen";
+}
+static method main() → dynamic {
+  new self::C::•().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/super.dart.direct.expect b/pkg/front_end/test/fasta/rasta/super.dart.direct.expect
new file mode 100644
index 0000000..f725931
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super.dart.direct.expect
@@ -0,0 +1,259 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  field dynamic d;
+  final field dynamic f;
+  constructor •() → self::A
+    : super core::Object::•();
+  get e() → dynamic
+    return null;
+  set g(dynamic _) → dynamic {}
+  get h() → dynamic
+    return null;
+  set h(dynamic _) → dynamic {}
+  get i() → dynamic
+    return null;
+  operator [](dynamic _) → dynamic
+    return null;
+  operator []=(dynamic a, dynamic b) → dynamic {}
+  operator ~() → dynamic
+    return 117;
+  operator unary-() → dynamic
+    return 117;
+  operator ==(dynamic other) → dynamic
+    return true;
+  method m() → void {}
+  method n() → void {}
+  set n(dynamic _) → dynamic {}
+}
+class B extends self::A {
+  final field dynamic d;
+  constructor •() → self::B
+    : super self::A::•();
+  get b() → dynamic
+    return null;
+  set c(dynamic x) → dynamic {}
+  set i(dynamic x) → dynamic {}
+}
+class C extends self::B {
+  constructor •() → self::C
+    : super self::B::•();
+  method test() → dynamic {
+    super.{self::A::~}();
+    self::use(super.{self::A::~}());
+    super.{self::A::unary-}();
+    self::use(super.{self::A::unary-}());
+    invalid-expression;
+    self::use(invalid-expression);
+    super.{self::A::==}(87);
+    self::use(super.{self::A::==}(87));
+    !super.{self::A::==}(87);
+    self::use(!super.{self::A::==}(87));
+    super.{self::A::a};
+    self::use(super.{self::A::a});
+    super.{self::B::b};
+    self::use(super.{self::B::b});
+    super.{self::A::c};
+    self::use(super.{self::A::c});
+    super.{self::B::d};
+    self::use(super.{self::B::d});
+    super.{self::A::e};
+    self::use(super.{self::A::e});
+    super.{self::A::f};
+    self::use(super.{self::A::f});
+    super.g;
+    self::use(super.g);
+    super.{self::A::h};
+    self::use(super.{self::A::h});
+    super.{self::A::i};
+    self::use(super.{self::A::i});
+    super.{self::A::[]}(87);
+    self::use(super.{self::A::[]}(87));
+    super.{self::A::m};
+    self::use(super.{self::A::m});
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.+(1);
+    self::use(let final dynamic #t1 = super.{self::A::a} in let final dynamic #t2 = super.{self::A::a} = #t1.+(1) in #t1);
+    super.{self::A::b} = super.{self::B::b}.+(1);
+    self::use(let final dynamic #t3 = super.{self::B::b} in let final dynamic #t4 = super.{self::A::b} = #t3.+(1) in #t3);
+    super.{self::B::c} = super.{self::A::c}.+(1);
+    self::use(let final dynamic #t5 = super.{self::A::c} in let final dynamic #t6 = super.{self::B::c} = #t5.+(1) in #t5);
+    super.d = super.{self::B::d}.+(1);
+    self::use(let final dynamic #t7 = super.{self::B::d} in let final dynamic #t8 = super.d = #t7.+(1) in #t7);
+    super.e = super.{self::A::e}.+(1);
+    self::use(let final dynamic #t9 = super.{self::A::e} in let final dynamic #t10 = super.e = #t9.+(1) in #t9);
+    super.f = super.{self::A::f}.+(1);
+    self::use(let final dynamic #t11 = super.{self::A::f} in let final dynamic #t12 = super.f = #t11.+(1) in #t11);
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.+(1);
+    self::use(let final dynamic #t13 = super.{self::A::h} in let final dynamic #t14 = super.{self::A::h} = #t13.+(1) in #t13);
+    super.{self::B::i} = super.{self::A::i}.+(1);
+    self::use(let final dynamic #t15 = super.{self::A::i} in let final dynamic #t16 = super.{self::B::i} = #t15.+(1) in #t15);
+    let final dynamic #t17 = 87 in super.{self::A::[]=}(#t17, super.{self::A::[]}(#t17).+(1));
+    self::use(let final dynamic #t18 = 87 in let final dynamic #t19 = super.{self::A::[]}(#t18) in let final dynamic #t20 = super.{self::A::[]=}(#t18, #t19.+(1)) in #t19);
+    super.m = super.{self::A::m}.+(1);
+    self::use(let final dynamic #t21 = super.{self::A::m} in let final dynamic #t22 = super.m = #t21.+(1) in #t21);
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.+(1);
+    self::use(super.{self::A::a} = super.{self::A::a}.+(1));
+    super.{self::A::b} = super.{self::B::b}.+(1);
+    self::use(super.{self::A::b} = super.{self::B::b}.+(1));
+    super.{self::B::c} = super.{self::A::c}.+(1);
+    self::use(super.{self::B::c} = super.{self::A::c}.+(1));
+    super.d = super.{self::B::d}.+(1);
+    self::use(super.d = super.{self::B::d}.+(1));
+    super.e = super.{self::A::e}.+(1);
+    self::use(super.e = super.{self::A::e}.+(1));
+    super.f = super.{self::A::f}.+(1);
+    self::use(super.f = super.{self::A::f}.+(1));
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.+(1);
+    self::use(super.{self::A::h} = super.{self::A::h}.+(1));
+    super.{self::B::i} = super.{self::A::i}.+(1);
+    self::use(super.{self::B::i} = super.{self::A::i}.+(1));
+    let final dynamic #t23 = 87 in super.{self::A::[]=}(#t23, super.{self::A::[]}(#t23).+(1));
+    self::use(let final dynamic #t24 = 87 in let final dynamic #t25 = super.{self::A::[]}(#t24).+(1) in let final dynamic #t26 = super.{self::A::[]=}(#t24, #t25) in #t25);
+    super.m = super.{self::A::m}.+(1);
+    self::use(super.m = super.{self::A::m}.+(1));
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a}.call();
+    self::use(super.{self::A::a}.call());
+    super.{self::B::b}.call();
+    self::use(super.{self::B::b}.call());
+    super.{self::A::c}.call();
+    self::use(super.{self::A::c}.call());
+    super.{self::B::d}.call();
+    self::use(super.{self::B::d}.call());
+    super.{self::A::e}.call();
+    self::use(super.{self::A::e}.call());
+    super.{self::A::f}.call();
+    self::use(super.{self::A::f}.call());
+    super.g.call();
+    self::use(super.g.call());
+    super.{self::A::h}.call();
+    self::use(super.{self::A::h}.call());
+    super.{self::A::i}.call();
+    self::use(super.{self::A::i}.call());
+    super.{self::A::[]}(87).call();
+    self::use(super.{self::A::[]}(87).call());
+    super.{self::A::m}();
+    self::use(super.{self::A::m}());
+    super.{self::A::m}(87);
+    self::use(super.{self::A::m}(87));
+    throw core::_unresolvedSuperMethodError(this, #n, <dynamic>[87], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperMethodError(this, #n, <dynamic>[87], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = 42;
+    self::use(super.{self::A::a} = 42);
+    super.{self::A::b} = 42;
+    self::use(super.{self::A::b} = 42);
+    super.{self::B::c} = 42;
+    self::use(super.{self::B::c} = 42);
+    super.d = 42;
+    self::use(super.d = 42);
+    super.e = 42;
+    self::use(super.e = 42);
+    super.f = 42;
+    self::use(super.f = 42);
+    super.{self::A::g} = 42;
+    self::use(super.{self::A::g} = 42);
+    super.{self::A::h} = 42;
+    self::use(super.{self::A::h} = 42);
+    super.{self::B::i} = 42;
+    self::use(super.{self::B::i} = 42);
+    super.{self::A::[]=}(87, 42);
+    self::use(let final dynamic #t27 = 87 in let final dynamic #t28 = 42 in let final dynamic #t29 = super.{self::A::[]=}(#t27, #t28) in #t28);
+    super.m = 42;
+    self::use(super.m = 42);
+    throw core::_unresolvedSuperSetterError(this, #n, <dynamic>[42], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperSetterError(this, #n, <dynamic>[42], <dynamic, dynamic>{}, null));
+    super.{self::A::a}.==(null) ? super.{self::A::a} = 42 : null;
+    self::use(let final dynamic #t30 = super.{self::A::a} in #t30.==(null) ? super.{self::A::a} = 42 : #t30);
+    super.{self::B::b}.==(null) ? super.{self::A::b} = 42 : null;
+    self::use(let final dynamic #t31 = super.{self::B::b} in #t31.==(null) ? super.{self::A::b} = 42 : #t31);
+    super.{self::A::c}.==(null) ? super.{self::B::c} = 42 : null;
+    self::use(let final dynamic #t32 = super.{self::A::c} in #t32.==(null) ? super.{self::B::c} = 42 : #t32);
+    super.{self::B::d}.==(null) ? super.d = 42 : null;
+    self::use(let final dynamic #t33 = super.{self::B::d} in #t33.==(null) ? super.d = 42 : #t33);
+    super.{self::A::e}.==(null) ? super.e = 42 : null;
+    self::use(let final dynamic #t34 = super.{self::A::e} in #t34.==(null) ? super.e = 42 : #t34);
+    super.{self::A::f}.==(null) ? super.f = 42 : null;
+    self::use(let final dynamic #t35 = super.{self::A::f} in #t35.==(null) ? super.f = 42 : #t35);
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h}.==(null) ? super.{self::A::h} = 42 : null;
+    self::use(let final dynamic #t36 = super.{self::A::h} in #t36.==(null) ? super.{self::A::h} = 42 : #t36);
+    super.{self::A::i}.==(null) ? super.{self::B::i} = 42 : null;
+    self::use(let final dynamic #t37 = super.{self::A::i} in #t37.==(null) ? super.{self::B::i} = 42 : #t37);
+    let final dynamic #t38 = 87 in super.{self::A::[]}(#t38).==(null) ? super.{self::A::[]=}(#t38, 42) : null;
+    self::use(let final dynamic #t39 = 87 in let final dynamic #t40 = super.{self::A::[]}(#t39) in #t40.==(null) ? let final dynamic #t41 = 42 in let final dynamic #t42 = super.{self::A::[]=}(#t39, #t41) in #t41 : #t40);
+    super.{self::A::m}.==(null) ? super.m = 42 : null;
+    self::use(let final dynamic #t43 = super.{self::A::m} in #t43.==(null) ? super.m = 42 : #t43);
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.+(42);
+    self::use(super.{self::A::a} = super.{self::A::a}.+(42));
+    super.{self::A::b} = super.{self::B::b}.+(42);
+    self::use(super.{self::A::b} = super.{self::B::b}.+(42));
+    super.{self::B::c} = super.{self::A::c}.+(42);
+    self::use(super.{self::B::c} = super.{self::A::c}.+(42));
+    super.d = super.{self::B::d}.+(42);
+    self::use(super.d = super.{self::B::d}.+(42));
+    super.e = super.{self::A::e}.+(42);
+    self::use(super.e = super.{self::A::e}.+(42));
+    super.f = super.{self::A::f}.+(42);
+    self::use(super.f = super.{self::A::f}.+(42));
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.+(42);
+    self::use(super.{self::A::h} = super.{self::A::h}.+(42));
+    super.{self::B::i} = super.{self::A::i}.+(42);
+    self::use(super.{self::B::i} = super.{self::A::i}.+(42));
+    let final dynamic #t44 = 87 in super.{self::A::[]=}(#t44, super.{self::A::[]}(#t44).+(42));
+    self::use(let final dynamic #t45 = 87 in let final dynamic #t46 = super.{self::A::[]}(#t45).+(42) in let final dynamic #t47 = super.{self::A::[]=}(#t45, #t46) in #t46);
+    super.m = super.{self::A::m}.+(42);
+    self::use(super.m = super.{self::A::m}.+(42));
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::a} = super.{self::A::a}.-(42);
+    self::use(super.{self::A::a} = super.{self::A::a}.-(42));
+    super.{self::A::b} = super.{self::B::b}.-(42);
+    self::use(super.{self::A::b} = super.{self::B::b}.-(42));
+    super.{self::B::c} = super.{self::A::c}.-(42);
+    self::use(super.{self::B::c} = super.{self::A::c}.-(42));
+    super.d = super.{self::B::d}.-(42);
+    self::use(super.d = super.{self::B::d}.-(42));
+    super.e = super.{self::A::e}.-(42);
+    self::use(super.e = super.{self::A::e}.-(42));
+    super.f = super.{self::A::f}.-(42);
+    self::use(super.f = super.{self::A::f}.-(42));
+    throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #g, <dynamic>[], <dynamic, dynamic>{}, null));
+    super.{self::A::h} = super.{self::A::h}.-(42);
+    self::use(super.{self::A::h} = super.{self::A::h}.-(42));
+    super.{self::B::i} = super.{self::A::i}.-(42);
+    self::use(super.{self::B::i} = super.{self::A::i}.-(42));
+    let final dynamic #t48 = 87 in super.{self::A::[]=}(#t48, super.{self::A::[]}(#t48).-(42));
+    self::use(let final dynamic #t49 = 87 in let final dynamic #t50 = super.{self::A::[]}(#t49).-(42) in let final dynamic #t51 = super.{self::A::[]=}(#t49, #t50) in #t50);
+    super.m = super.{self::A::m}.-(42);
+    self::use(super.m = super.{self::A::m}.-(42));
+    throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null);
+    self::use(throw core::_unresolvedSuperGetterError(this, #n, <dynamic>[], <dynamic, dynamic>{}, null));
+  }
+}
+static method use(dynamic x) → dynamic {
+  if(x.==(new core::DateTime::now().millisecondsSinceEpoch))
+    throw "Shouldn't happen";
+}
+static method main() → dynamic {
+  new self::C::•().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/super.dart.outline.expect b/pkg/front_end/test/fasta/rasta/super.dart.outline.expect
new file mode 100644
index 0000000..5e860ff
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super.dart.outline.expect
@@ -0,0 +1,60 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field dynamic a;
+  field dynamic b;
+  field dynamic c;
+  field dynamic d;
+  final field dynamic f;
+  constructor •() → void
+    ;
+  get e() → dynamic
+    ;
+  set g(dynamic _) → dynamic
+    ;
+  set h(dynamic _) → dynamic
+    ;
+  get h() → dynamic
+    ;
+  get i() → dynamic
+    ;
+  operator [](dynamic _) → dynamic
+    ;
+  operator []=(dynamic a, dynamic b) → dynamic
+    ;
+  operator ~() → dynamic
+    ;
+  operator unary-() → dynamic
+    ;
+  operator ==(dynamic other) → dynamic
+    ;
+  method m() → void
+    ;
+  set n(dynamic _) → dynamic
+    ;
+  method n() → void
+    ;
+}
+class B extends self::A {
+  final field dynamic d;
+  constructor •() → void
+    ;
+  get b() → dynamic
+    ;
+  set c(dynamic x) → dynamic
+    ;
+  set i(dynamic x) → dynamic
+    ;
+}
+class C extends self::B {
+  constructor •() → void
+    ;
+  method test() → dynamic
+    ;
+}
+static method use(dynamic x) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/super_initializer.dart b/pkg/front_end/test/fasta/rasta/super_initializer.dart
new file mode 100644
index 0000000..8bf629a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_initializer.dart
@@ -0,0 +1,16 @@
+// 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.
+
+class Super {
+  Super.arg0();
+  Super.arg1(a);
+  Super.arg2(a, b);
+}
+
+class Sub extends Super {
+  var field;
+  Sub.arg0() : super.arg0(), field = 42;
+  Sub.arg1(a) : super.arg1(a), field = 42;
+  Sub.arg2(a, b) : super.arg2(a, b), field = 42;
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_initializer.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/super_initializer.dart.dartk.expect
new file mode 100644
index 0000000..0fa9f70
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_initializer.dart.dartk.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Super extends core::Object {
+  constructor arg0() → dynamic
+    : super core::Object::•()
+    ;
+  constructor arg1(dynamic a) → dynamic
+    : super core::Object::•()
+    ;
+  constructor arg2(dynamic a, dynamic b) → dynamic
+    : super core::Object::•()
+    ;
+}
+class Sub extends self::Super {
+  field dynamic field;
+  constructor arg0() → dynamic
+    : super self::Super::arg0(), self::Sub::field = 42
+    ;
+  constructor arg1(dynamic a) → dynamic
+    : super self::Super::arg1(a), self::Sub::field = 42
+    ;
+  constructor arg2(dynamic a, dynamic b) → dynamic
+    : super self::Super::arg2(a, b), self::Sub::field = 42
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_initializer.dart.direct.expect b/pkg/front_end/test/fasta/rasta/super_initializer.dart.direct.expect
new file mode 100644
index 0000000..4e61944
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_initializer.dart.direct.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Super extends core::Object {
+  constructor arg0() → void
+    : super core::Object::•()
+    ;
+  constructor arg1(dynamic a) → void
+    : super core::Object::•()
+    ;
+  constructor arg2(dynamic a, dynamic b) → void
+    : super core::Object::•()
+    ;
+}
+class Sub extends self::Super {
+  field dynamic field;
+  constructor arg0() → void
+    : self::Sub::field = 42, super self::Super::arg0()
+    ;
+  constructor arg1(dynamic a) → void
+    : final dynamic #t1 = a, self::Sub::field = 42, super self::Super::arg1(#t1)
+    ;
+  constructor arg2(dynamic a, dynamic b) → void
+    : final dynamic #t2 = a, final dynamic #t3 = b, self::Sub::field = 42, super self::Super::arg2(#t2, #t3)
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_initializer.dart.outline.expect b/pkg/front_end/test/fasta/rasta/super_initializer.dart.outline.expect
new file mode 100644
index 0000000..b5a1cdb
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_initializer.dart.outline.expect
@@ -0,0 +1,21 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Super extends core::Object {
+  constructor arg0() → void
+    ;
+  constructor arg1(dynamic a) → void
+    ;
+  constructor arg2(dynamic a, dynamic b) → void
+    ;
+}
+class Sub extends self::Super {
+  field dynamic field;
+  constructor arg0() → void
+    ;
+  constructor arg1(dynamic a) → void
+    ;
+  constructor arg2(dynamic a, dynamic b) → void
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_mixin.dart b/pkg/front_end/test/fasta/rasta/super_mixin.dart
new file mode 100644
index 0000000..a00e829
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_mixin.dart
@@ -0,0 +1,25 @@
+// 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.
+
+import "mixin_library.dart" show Mixin;
+
+class Super<S> {
+  foo() => 40;
+  f() => 3;
+}
+
+class C<V> extends Super<V> with Mixin<V> {
+}
+
+class D extends Super with Mixin {
+}
+
+class C2<V> = Super<V> with Mixin<V>;
+
+class D2 = Super with Mixin;
+
+main() {
+  print(new C().foo());
+  print(new C2().foo());
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_mixin.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/super_mixin.dart.dartk.expect
new file mode 100644
index 0000000..d81053f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_mixin.dart.dartk.expect
@@ -0,0 +1,113 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "./mixin_library.dart" as mix;
+
+class Super<S extends core::Object> extends core::Object {
+  constructor •() → self::Super<self::Super::S>
+    : super core::Object::•();
+  method foo() → dynamic
+    return 40;
+  method f() → dynamic
+    return 3;
+}
+class C<V extends core::Object> extends self::Super+Mixin#3<self::C::V, self::C::V> {
+  constructor •() → self::C<self::C::V>
+    : super self::Super+Mixin#3::•();
+}
+class D extends self::Super+Mixin#2<dynamic> {
+  constructor •() → self::D
+    : super self::Super+Mixin#2::•();
+}
+class C2<V extends core::Object> extends self::Super+Mixin#1<self::C2::V, self::C2::V> {
+  constructor •() → self::Super<self::C2::V>
+    : super self::Super+Mixin#1::•();
+}
+class D2 extends self::Super+Mixin#0<dynamic> {
+  constructor •() → self::Super<dynamic>
+    : super self::Super+Mixin#0::•();
+}
+abstract class Super+Mixin#0<T extends core::Object> extends self::Super<dynamic> implements mix::Mixin<dynamic> {
+  field self::Super+Mixin#0::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<dynamic>
+    : self::Super+Mixin#0::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#0::T a) → self::Super+Mixin#0::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+abstract class Super+Mixin#1<T extends core::Object, V extends core::Object> extends self::Super<self::Super+Mixin#1::V> implements mix::Mixin<self::Super+Mixin#1::V> {
+  field self::Super+Mixin#1::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<self::Super+Mixin#1::V>
+    : self::Super+Mixin#1::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#1::T a) → self::Super+Mixin#1::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+abstract class Super+Mixin#2<T extends core::Object> extends self::Super<dynamic> implements mix::Mixin<dynamic> {
+  field self::Super+Mixin#2::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<dynamic>
+    : self::Super+Mixin#2::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#2::T a) → self::Super+Mixin#2::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+abstract class Super+Mixin#3<T extends core::Object, V extends core::Object> extends self::Super<self::Super+Mixin#3::V> implements mix::Mixin<self::Super+Mixin#3::V> {
+  field self::Super+Mixin#3::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<self::Super+Mixin#3::V>
+    : self::Super+Mixin#3::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#3::T a) → self::Super+Mixin#3::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+static method main() → dynamic {
+  core::print(new self::C::•<dynamic>().foo());
+  core::print(new self::C2::•<dynamic>().foo());
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_mixin.dart.direct.expect b/pkg/front_end/test/fasta/rasta/super_mixin.dart.direct.expect
new file mode 100644
index 0000000..d81053f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_mixin.dart.direct.expect
@@ -0,0 +1,113 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "./mixin_library.dart" as mix;
+
+class Super<S extends core::Object> extends core::Object {
+  constructor •() → self::Super<self::Super::S>
+    : super core::Object::•();
+  method foo() → dynamic
+    return 40;
+  method f() → dynamic
+    return 3;
+}
+class C<V extends core::Object> extends self::Super+Mixin#3<self::C::V, self::C::V> {
+  constructor •() → self::C<self::C::V>
+    : super self::Super+Mixin#3::•();
+}
+class D extends self::Super+Mixin#2<dynamic> {
+  constructor •() → self::D
+    : super self::Super+Mixin#2::•();
+}
+class C2<V extends core::Object> extends self::Super+Mixin#1<self::C2::V, self::C2::V> {
+  constructor •() → self::Super<self::C2::V>
+    : super self::Super+Mixin#1::•();
+}
+class D2 extends self::Super+Mixin#0<dynamic> {
+  constructor •() → self::Super<dynamic>
+    : super self::Super+Mixin#0::•();
+}
+abstract class Super+Mixin#0<T extends core::Object> extends self::Super<dynamic> implements mix::Mixin<dynamic> {
+  field self::Super+Mixin#0::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<dynamic>
+    : self::Super+Mixin#0::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#0::T a) → self::Super+Mixin#0::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+abstract class Super+Mixin#1<T extends core::Object, V extends core::Object> extends self::Super<self::Super+Mixin#1::V> implements mix::Mixin<self::Super+Mixin#1::V> {
+  field self::Super+Mixin#1::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<self::Super+Mixin#1::V>
+    : self::Super+Mixin#1::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#1::T a) → self::Super+Mixin#1::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+abstract class Super+Mixin#2<T extends core::Object> extends self::Super<dynamic> implements mix::Mixin<dynamic> {
+  field self::Super+Mixin#2::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<dynamic>
+    : self::Super+Mixin#2::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#2::T a) → self::Super+Mixin#2::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+abstract class Super+Mixin#3<T extends core::Object, V extends core::Object> extends self::Super<self::Super+Mixin#3::V> implements mix::Mixin<self::Super+Mixin#3::V> {
+  field self::Super+Mixin#3::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → self::Super<self::Super+Mixin#3::V>
+    : self::Super+Mixin#3::x = mix::f(), super self::Super::•();
+  method publicMethod() → dynamic
+    return this._privateMethod();
+  method _privateMethod() → dynamic
+    return 49;
+  method l() → dynamic
+    return mix::_private();
+  method h() → dynamic
+    return mix::V();
+  method g(self::Super+Mixin#3::T a) → self::Super+Mixin#3::T
+    return null;
+  method foo() → dynamic
+    return super.{self::Super::foo}().+(mix::f());
+}
+static method main() → dynamic {
+  core::print(new self::C::•<dynamic>().foo());
+  core::print(new self::C2::•<dynamic>().foo());
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_mixin.dart.outline.expect b/pkg/front_end/test/fasta/rasta/super_mixin.dart.outline.expect
new file mode 100644
index 0000000..8a2de2e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_mixin.dart.outline.expect
@@ -0,0 +1,111 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "./mixin_library.dart" as mix;
+
+class Super<S extends core::Object> extends core::Object {
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+  method f() → dynamic
+    ;
+}
+class C<V extends core::Object> extends self::Super+Mixin#3<self::C::V, self::C::V> {
+  constructor •() → void
+    ;
+}
+class D extends self::Super+Mixin#2<dynamic> {
+  constructor •() → void
+    ;
+}
+class C2<V extends core::Object> extends self::Super+Mixin#1<self::C2::V, self::C2::V> {
+  constructor •() → void
+    ;
+}
+class D2 extends self::Super+Mixin#0<dynamic> {
+  constructor •() → void
+    ;
+}
+abstract class Super+Mixin#0<T extends core::Object> extends self::Super<dynamic> implements mix::Mixin<dynamic> {
+  field self::Super+Mixin#0::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → void
+    ;
+  method publicMethod() → dynamic
+    ;
+  method _privateMethod() → dynamic
+    ;
+  method l() → dynamic
+    ;
+  method h() → dynamic
+    ;
+  method g(self::Super+Mixin#0::T a) → self::Super+Mixin#0::T
+    ;
+  method foo() → dynamic
+    ;
+}
+abstract class Super+Mixin#1<T extends core::Object, V extends core::Object> extends self::Super<self::Super+Mixin#1::V> implements mix::Mixin<self::Super+Mixin#1::V> {
+  field self::Super+Mixin#1::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → void
+    ;
+  method publicMethod() → dynamic
+    ;
+  method _privateMethod() → dynamic
+    ;
+  method l() → dynamic
+    ;
+  method h() → dynamic
+    ;
+  method g(self::Super+Mixin#1::T a) → self::Super+Mixin#1::T
+    ;
+  method foo() → dynamic
+    ;
+}
+abstract class Super+Mixin#2<T extends core::Object> extends self::Super<dynamic> implements mix::Mixin<dynamic> {
+  field self::Super+Mixin#2::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → void
+    ;
+  method publicMethod() → dynamic
+    ;
+  method _privateMethod() → dynamic
+    ;
+  method l() → dynamic
+    ;
+  method h() → dynamic
+    ;
+  method g(self::Super+Mixin#2::T a) → self::Super+Mixin#2::T
+    ;
+  method foo() → dynamic
+    ;
+}
+abstract class Super+Mixin#3<T extends core::Object, V extends core::Object> extends self::Super<self::Super+Mixin#3::V> implements mix::Mixin<self::Super+Mixin#3::V> {
+  field self::Super+Mixin#3::T t;
+  field dynamic z;
+  field dynamic y;
+  field dynamic x;
+  constructor •() → void
+    ;
+  method publicMethod() → dynamic
+    ;
+  method _privateMethod() → dynamic
+    ;
+  method l() → dynamic
+    ;
+  method h() → dynamic
+    ;
+  method g(self::Super+Mixin#3::T a) → self::Super+Mixin#3::T
+    ;
+  method foo() → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/super_operator.dart b/pkg/front_end/test/fasta/rasta/super_operator.dart
new file mode 100644
index 0000000..05fa6cd
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_operator.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+class A {
+  operator + (String s) => null;
+
+  operator [] (i) => null;
+
+  operator []= (i, val) {}
+}
+
+class B extends A {
+  operator + (String s) => super + ("${s}${s}");
+
+  operator [] (i) => super[i];
+
+  operator []= (i, val) => super[i++] += val;
+}
+
+class Autobianchi {
+  g() => super[0];
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_operator.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/super_operator.dart.dartk.expect
new file mode 100644
index 0000000..39381c52
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_operator.dart.dartk.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → self::A
+    : super core::Object::•();
+  operator +(core::String s) → dynamic
+    return null;
+  operator [](dynamic i) → dynamic
+    return null;
+  operator []=(dynamic i, dynamic val) → dynamic {}
+}
+class B extends self::A {
+  constructor •() → self::B
+    : super self::A::•();
+  operator +(core::String s) → dynamic
+    return super.{self::A::+}("${s}${s}");
+  operator [](dynamic i) → dynamic
+    return super.{self::A::[]}(i);
+  operator []=(dynamic i, dynamic val) → dynamic
+    return let final dynamic #t1 = let final dynamic #t2 = i in let final dynamic #t3 = i = #t2.+(1) in #t2 in let final dynamic #t4 = super.{self::A::[]}(#t1).+(val) in let final dynamic #t5 = super.{self::A::[]=}(#t1, #t4) in #t4;
+}
+class Autobianchi extends core::Object {
+  constructor •() → self::Autobianchi
+    : super core::Object::•();
+  method g() → dynamic
+    return super.[](0);
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_operator.dart.direct.expect b/pkg/front_end/test/fasta/rasta/super_operator.dart.direct.expect
new file mode 100644
index 0000000..4d09b81
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_operator.dart.direct.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  operator +(core::String s) → dynamic
+    return null;
+  operator [](dynamic i) → dynamic
+    return null;
+  operator []=(dynamic i, dynamic val) → dynamic {}
+}
+class B extends self::A {
+  constructor •() → void
+    : super self::A::•()
+    ;
+  operator +(core::String s) → dynamic
+    return this.{=self::A::+}("${s}${s}");
+  operator [](dynamic i) → dynamic
+    return this.{=self::A::[]}(i);
+  operator []=(dynamic i, dynamic val) → dynamic
+    return let final dynamic #t1 = let final dynamic #t2 = i in let final dynamic #t3 = i = #t2.+(1) in #t2 in let final dynamic #t4 = super.{self::A::[]}(#t1).+(val) in let final dynamic #t5 = super.{self::A::[]=}(#t1, #t4) in #t4;
+}
+class Autobianchi extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method g() → dynamic
+    return super.[](0);
+}
diff --git a/pkg/front_end/test/fasta/rasta/super_operator.dart.outline.expect b/pkg/front_end/test/fasta/rasta/super_operator.dart.outline.expect
new file mode 100644
index 0000000..5a886e1
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/super_operator.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    ;
+  operator +(core::String s) → dynamic
+    ;
+  operator [](dynamic i) → dynamic
+    ;
+  operator []=(dynamic i, dynamic val) → dynamic
+    ;
+}
+class B extends self::A {
+  constructor •() → void
+    ;
+  operator +(core::String s) → dynamic
+    ;
+  operator [](dynamic i) → dynamic
+    ;
+  operator []=(dynamic i, dynamic val) → dynamic
+    ;
+}
+class Autobianchi extends core::Object {
+  constructor •() → void
+    ;
+  method g() → dynamic
+    ;
+}
diff --git a/pkg/front_end/test/fasta/rasta/supports_reflection.dart b/pkg/front_end/test/fasta/rasta/supports_reflection.dart
new file mode 100644
index 0000000..d14efa0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/supports_reflection.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print(const bool.fromEnvironment("dart.library.mirrors"));
+}
diff --git a/pkg/front_end/test/fasta/rasta/supports_reflection.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/supports_reflection.dart.dartk.expect
new file mode 100644
index 0000000..b7bfa56
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/supports_reflection.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(const core::bool::fromEnvironment("dart.library.mirrors"));
+}
diff --git a/pkg/front_end/test/fasta/rasta/supports_reflection.dart.direct.expect b/pkg/front_end/test/fasta/rasta/supports_reflection.dart.direct.expect
new file mode 100644
index 0000000..897d307
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/supports_reflection.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(const core::bool::fromEnvironment("dart.library.mirrors", defaultValue: false));
+}
diff --git a/pkg/front_end/test/fasta/rasta/supports_reflection.dart.outline.expect b/pkg/front_end/test/fasta/rasta/supports_reflection.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/supports_reflection.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart
new file mode 100644
index 0000000..e0a06c1
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+// Slightly modified copy of
+// `co19/src/Language/Statements/Switch/execution_case_t02.dart`.
+
+/**
+ * @assertion Execution of a case clause case ek: sk of a switch statement
+ * switch (e) {label11 ..label1j1 case e1: s1 … labeln1 ..labelnjn case en: sn default: sn+1}
+ * proceeds as follows:
+ * The expression ek == id  is evaluated  to an object o which is then
+ * subjected to boolean conversion yielding a value v.
+ * If v is not true, the following case,  case ek+1: sk+1 is executed if it exists.
+ * If case ek+1: sk+1 does not exist, then the default clause is executed by executing sn+1.
+ * If v is true, let h be the smallest integer such that h >= k and sh is non-empty.
+ * If no such h exists, let h = n + 1. The sequence of statements sh is then executed.
+ * If execution reaches the point after sh  then a runtime error occurs, unless h = n + 1.
+ * @description Checks that falling through produces a runtime error, unless
+ * the current clause is an empty case clause or the default clause.
+ * @static-warning
+ * @author msyabro
+ * @reviewer rodionov
+ * @issue 7537
+ */
+
+test(value) {
+  var result;
+
+  switch(value) {
+    case 1:  result = 1;
+             break;
+    case 2:  result = 2; /// static warning - case fall-through, see "Switch"
+    case 3:  result = 3; /// static warning - case fall-through, see "Switch"
+    default: result = 4;
+  }
+  return result;
+}
+
+testEmptyCases(value) {
+  var result;
+
+  switch(value) {
+    case 1:
+    case 2: result = 1; /// static warning - case fall-through, see "Switch"
+    case 3:
+    case 4: result = 2;
+            break;
+    case 5:
+    case 6:
+    default:
+  }
+
+  return result;
+}
+
+main() {
+}
diff --git a/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.dartk.expect
new file mode 100644
index 0000000..63f4c55
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.dartk.expect
@@ -0,0 +1,59 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test(dynamic value) → dynamic {
+  dynamic result;
+  #L1:
+  switch(value) {
+    #L2:
+    case 1:
+      {
+        result = 1;
+        break #L1;
+      }
+    #L3:
+    case 2:
+      {
+        result = 2;
+        throw core::_fallThroughError();
+      }
+    #L4:
+    case 3:
+      {
+        result = 3;
+        throw core::_fallThroughError();
+      }
+    #L5:
+    default:
+      result = 4;
+  }
+  return result;
+}
+static method testEmptyCases(dynamic value) → dynamic {
+  dynamic result;
+  #L6:
+  switch(value) {
+    #L7:
+    case 1:
+    case 2:
+      {
+        result = 1;
+        throw core::_fallThroughError();
+      }
+    #L8:
+    case 3:
+    case 4:
+      {
+        result = 2;
+        break #L6;
+      }
+    #L9:
+    case 5:
+    case 6:
+    default:
+      {}
+  }
+  return result;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.direct.expect b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.direct.expect
new file mode 100644
index 0000000..8dc5d5a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.direct.expect
@@ -0,0 +1,61 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test(dynamic value) → dynamic {
+  dynamic result;
+  #L1:
+  switch(value) {
+    #L2:
+    case 1:
+      {
+        result = 1;
+        break #L1;
+      }
+    #L3:
+    case 2:
+      {
+        result = 2;
+        throw core::_fallThroughError();
+      }
+    #L4:
+    case 3:
+      {
+        result = 3;
+        throw core::_fallThroughError();
+      }
+    #L5:
+    default:
+      {
+        result = 4;
+      }
+  }
+  return result;
+}
+static method testEmptyCases(dynamic value) → dynamic {
+  dynamic result;
+  #L6:
+  switch(value) {
+    #L7:
+    case 1:
+    case 2:
+      {
+        result = 1;
+        throw core::_fallThroughError();
+      }
+    #L8:
+    case 3:
+    case 4:
+      {
+        result = 2;
+        break #L6;
+      }
+    #L9:
+    case 5:
+    case 6:
+    default:
+      {}
+  }
+  return result;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.outline.expect b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.outline.expect
new file mode 100644
index 0000000..ab9a3c9
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_execution_case_t02.dart.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+
+static method test(dynamic value) → dynamic
+  ;
+static method testEmptyCases(dynamic value) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/switch_fall_through.dart b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart
new file mode 100644
index 0000000..ebc0239
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart
@@ -0,0 +1,40 @@
+// 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.
+
+main() {
+  switch (1) {
+    case 1:
+    {
+      "No fall-through error needed.";
+      break;
+      ; // Empty statement.
+    }
+    case 2:
+    {
+      "Fall-through error needed.";
+      if (true) {
+        break;
+      }
+    }
+    case 3:
+      try {
+        "No fall-through error needed.";
+      } finally {
+        break;
+      }
+    case 4:
+      try {
+        "No fall-through error needed.";
+        break;
+      } finally {
+      }
+    case 5:
+      try {
+        "Fall-through error needed.";
+      } finally {
+      }
+    case 10000:
+      "Should be last. No fall-through error, falling through allowed here.";
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.dartk.expect
new file mode 100644
index 0000000..060c252
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.dartk.expect
@@ -0,0 +1,56 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #L1:
+  switch(1) {
+    #L2:
+    case 1:
+      {
+        "No fall-through error needed.";
+        break #L1;
+        ;
+      }
+    #L3:
+    case 2:
+      {
+        {
+          "Fall-through error needed.";
+          if(true) {
+            break #L1;
+          }
+        }
+        throw core::_fallThroughError();
+      }
+    #L4:
+    case 3:
+      try {
+        "No fall-through error needed.";
+      }
+      finally {
+        break #L1;
+      }
+    #L5:
+    case 4:
+      try {
+        "No fall-through error needed.";
+        break #L1;
+      }
+      finally {
+      }
+    #L6:
+    case 5:
+      {
+        try {
+          "Fall-through error needed.";
+        }
+        finally {
+        }
+        throw core::_fallThroughError();
+      }
+    #L7:
+    case 10000:
+      "Should be last. No fall-through error, falling through allowed here.";
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.direct.expect b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.direct.expect
new file mode 100644
index 0000000..f83ad0a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.direct.expect
@@ -0,0 +1,64 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  #L1:
+  switch(1) {
+    #L2:
+    case 1:
+      {
+        {
+          "No fall-through error needed.";
+          break #L1;
+          ;
+        }
+      }
+    #L3:
+    case 2:
+      {
+        {
+          "Fall-through error needed.";
+          if(true) {
+            break #L1;
+          }
+        }
+        throw core::_fallThroughError();
+      }
+    #L4:
+    case 3:
+      {
+        try {
+          "No fall-through error needed.";
+        }
+        finally {
+          break #L1;
+        }
+      }
+    #L5:
+    case 4:
+      {
+        try {
+          "No fall-through error needed.";
+          break #L1;
+        }
+        finally {
+        }
+      }
+    #L6:
+    case 5:
+      {
+        try {
+          "Fall-through error needed.";
+        }
+        finally {
+        }
+        throw core::_fallThroughError();
+      }
+    #L7:
+    case 10000:
+      {
+        "Should be last. No fall-through error, falling through allowed here.";
+      }
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.outline.expect b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/switch_fall_through.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/this_invoke.dart b/pkg/front_end/test/fasta/rasta/this_invoke.dart
new file mode 100644
index 0000000..42b95f7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/this_invoke.dart
@@ -0,0 +1,12 @@
+// 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.
+
+class C {
+  m(x) => this(x);
+  call(x) => 42;
+}
+
+main() {
+  print(new C().m(42));
+}
diff --git a/pkg/front_end/test/fasta/rasta/this_invoke.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/this_invoke.dart.dartk.expect
new file mode 100644
index 0000000..a605b59
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/this_invoke.dart.dartk.expect
@@ -0,0 +1,15 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → self::C
+    : super core::Object::•();
+  method m(dynamic x) → dynamic
+    return this.call(x);
+  method call(dynamic x) → dynamic
+    return 42;
+}
+static method main() → dynamic {
+  core::print(new self::C::•().m(42));
+}
diff --git a/pkg/front_end/test/fasta/rasta/this_invoke.dart.direct.expect b/pkg/front_end/test/fasta/rasta/this_invoke.dart.direct.expect
new file mode 100644
index 0000000..b366a22
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/this_invoke.dart.direct.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method m(dynamic x) → dynamic
+    return this.call(x);
+  method call(dynamic x) → dynamic
+    return 42;
+}
+static method main() → dynamic {
+  core::print(new self::C::•().m(42));
+}
diff --git a/pkg/front_end/test/fasta/rasta/this_invoke.dart.outline.expect b/pkg/front_end/test/fasta/rasta/this_invoke.dart.outline.expect
new file mode 100644
index 0000000..b77f816
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/this_invoke.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  constructor •() → void
+    ;
+  method m(dynamic x) → dynamic
+    ;
+  method call(dynamic x) → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/try_label.dart b/pkg/front_end/test/fasta/rasta/try_label.dart
new file mode 100644
index 0000000..30406ac
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/try_label.dart
@@ -0,0 +1,11 @@
+// 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.
+
+main() {
+  L: try {
+    break L;
+  } finally {
+    continue L;
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/try_label.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/try_label.dart.dartk.expect
new file mode 100644
index 0000000..d6d4ae7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/try_label.dart.dartk.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  #L1:
+  try {
+    break #L1;
+  }
+  finally {
+    invalid-statement;
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/try_label.dart.direct.expect b/pkg/front_end/test/fasta/rasta/try_label.dart.direct.expect
new file mode 100644
index 0000000..d6d4ae7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/try_label.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+
+static method main() → dynamic {
+  #L1:
+  try {
+    break #L1;
+  }
+  finally {
+    invalid-statement;
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/try_label.dart.outline.expect b/pkg/front_end/test/fasta/rasta/try_label.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/try_label.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/type_literals.dart b/pkg/front_end/test/fasta/rasta/type_literals.dart
new file mode 100644
index 0000000..b3302c7
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_literals.dart
@@ -0,0 +1,109 @@
+// 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.
+
+typedef void Func();
+
+class C<T> {
+  test() {
+    // Note: we cannot write a type literal with generic type arguments. For
+    // example, `C<String>` isn't a valid expression.
+    C;
+    use(C);
+    dynamic;
+    use(dynamic);
+    T;
+    use(T);
+    Func;
+    use(Func);
+
+    C();
+    use(C());
+    dynamic();
+    use(dynamic());
+    T();
+    use(T());
+    Func();
+    use(Func());
+
+    C = 42;
+    use(C = 42);
+    dynamic = 42;
+    use(dynamic = 42);
+    T = 42;
+    use(T = 42);
+    Func = 42;
+    use(Func = 42);
+
+    C++;
+    use(C++);
+    dynamic++;
+    use(dynamic++);
+    T++;
+    use(T++);
+    Func++;
+    use(Func++);
+
+    ++C;
+    use(++C);
+    ++dynamic;
+    use(++dynamic);
+    ++T;
+    use(++T);
+    ++Func;
+    use(++Func);
+
+    C--;
+    use(C--);
+    dynamic--;
+    use(dynamic--);
+    T--;
+    use(T--);
+    Func--;
+    use(Func--);
+
+    --C;
+    use(--C);
+    --dynamic;
+    use(--dynamic);
+    --T;
+    use(--T);
+    --Func;
+    use(--Func);
+
+    C ??= 42;
+    use(C ??= 42);
+    dynamic ??= 42;
+    use(dynamic ??= 42);
+    T ??= 42;
+    use(T ??= 42);
+    Func ??= 42;
+    use(Func ??= 42);
+
+    C += 42;
+    use(C += 42);
+    dynamic += 42;
+    use(dynamic += 42);
+    T += 42;
+    use(T += 42);
+    Func += 42;
+    use(Func += 42);
+
+    C-= 42;
+    use(C-= 42);
+    dynamic-= 42;
+    use(dynamic-= 42);
+    T-= 42;
+    use(T-= 42);
+    Func-= 42;
+    use(Func-= 42);
+  }
+}
+
+use(x) {
+  if (x == new DateTime.now().millisecondsSinceEpoch) throw "Shouldn't happen";
+}
+
+main() {
+  new C().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/type_literals.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/type_literals.dart.dartk.expect
new file mode 100644
index 0000000..0fc21cf
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_literals.dart.dartk.expect
@@ -0,0 +1,97 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object> extends core::Object {
+  constructor •() → self::C<self::C::T>
+    : super core::Object::•();
+  method test() → dynamic {
+    self::C<dynamic>;
+    self::use(self::C<dynamic>);
+    dynamic;
+    self::use(dynamic);
+    self::C::T;
+    self::use(self::C::T);
+    () → void;
+    self::use(() → void);
+    self::C<dynamic>.call();
+    self::use(self::C<dynamic>.call());
+    core::Type.call();
+    self::use(core::Type.call());
+    self::C::T.call();
+    self::use(self::C::T.call());
+    () → void.call();
+    self::use(() → void.call());
+    let final dynamic #t1 = 42 in invalid-expression;
+    self::use(let final dynamic #t2 = 42 in invalid-expression);
+    let final dynamic #t3 = 42 in invalid-expression;
+    self::use(let final dynamic #t4 = 42 in invalid-expression);
+    let final dynamic #t5 = 42 in invalid-expression;
+    self::use(let final dynamic #t6 = 42 in invalid-expression);
+    let final dynamic #t7 = 42 in invalid-expression;
+    self::use(let final dynamic #t8 = 42 in invalid-expression);
+    let final dynamic #t9 = self::C<dynamic> in let final dynamic #t10 = #t9.+(1) in invalid-expression;
+    self::use(let final dynamic #t11 = self::C<dynamic> in let final dynamic #t12 = #t11 in let final dynamic #t13 = let final dynamic #t14 = #t12.+(1) in invalid-expression in #t12);
+    let final dynamic #t15 = dynamic in let final dynamic #t16 = #t15.+(1) in invalid-expression;
+    self::use(let final dynamic #t17 = dynamic in let final dynamic #t18 = #t17 in let final dynamic #t19 = let final dynamic #t20 = #t18.+(1) in invalid-expression in #t18);
+    let final dynamic #t21 = self::C::T in let final dynamic #t22 = #t21.+(1) in invalid-expression;
+    self::use(let final dynamic #t23 = self::C::T in let final dynamic #t24 = #t23 in let final dynamic #t25 = let final dynamic #t26 = #t24.+(1) in invalid-expression in #t24);
+    let final dynamic #t27 = () → void in let final dynamic #t28 = #t27.+(1) in invalid-expression;
+    self::use(let final dynamic #t29 = () → void in let final dynamic #t30 = #t29 in let final dynamic #t31 = let final dynamic #t32 = #t30.+(1) in invalid-expression in #t30);
+    let final dynamic #t33 = self::C<dynamic> in let final dynamic #t34 = #t33.+(1) in invalid-expression;
+    self::use(let final dynamic #t35 = self::C<dynamic> in let final dynamic #t36 = #t35.+(1) in invalid-expression);
+    let final dynamic #t37 = dynamic in let final dynamic #t38 = #t37.+(1) in invalid-expression;
+    self::use(let final dynamic #t39 = dynamic in let final dynamic #t40 = #t39.+(1) in invalid-expression);
+    let final dynamic #t41 = self::C::T in let final dynamic #t42 = #t41.+(1) in invalid-expression;
+    self::use(let final dynamic #t43 = self::C::T in let final dynamic #t44 = #t43.+(1) in invalid-expression);
+    let final dynamic #t45 = () → void in let final dynamic #t46 = #t45.+(1) in invalid-expression;
+    self::use(let final dynamic #t47 = () → void in let final dynamic #t48 = #t47.+(1) in invalid-expression);
+    let final dynamic #t49 = self::C<dynamic> in let final dynamic #t50 = #t49.-(1) in invalid-expression;
+    self::use(let final dynamic #t51 = self::C<dynamic> in let final dynamic #t52 = #t51 in let final dynamic #t53 = let final dynamic #t54 = #t52.-(1) in invalid-expression in #t52);
+    let final dynamic #t55 = dynamic in let final dynamic #t56 = #t55.-(1) in invalid-expression;
+    self::use(let final dynamic #t57 = dynamic in let final dynamic #t58 = #t57 in let final dynamic #t59 = let final dynamic #t60 = #t58.-(1) in invalid-expression in #t58);
+    let final dynamic #t61 = self::C::T in let final dynamic #t62 = #t61.-(1) in invalid-expression;
+    self::use(let final dynamic #t63 = self::C::T in let final dynamic #t64 = #t63 in let final dynamic #t65 = let final dynamic #t66 = #t64.-(1) in invalid-expression in #t64);
+    let final dynamic #t67 = () → void in let final dynamic #t68 = #t67.-(1) in invalid-expression;
+    self::use(let final dynamic #t69 = () → void in let final dynamic #t70 = #t69 in let final dynamic #t71 = let final dynamic #t72 = #t70.-(1) in invalid-expression in #t70);
+    let final dynamic #t73 = self::C<dynamic> in let final dynamic #t74 = #t73.-(1) in invalid-expression;
+    self::use(let final dynamic #t75 = self::C<dynamic> in let final dynamic #t76 = #t75.-(1) in invalid-expression);
+    let final dynamic #t77 = dynamic in let final dynamic #t78 = #t77.-(1) in invalid-expression;
+    self::use(let final dynamic #t79 = dynamic in let final dynamic #t80 = #t79.-(1) in invalid-expression);
+    let final dynamic #t81 = self::C::T in let final dynamic #t82 = #t81.-(1) in invalid-expression;
+    self::use(let final dynamic #t83 = self::C::T in let final dynamic #t84 = #t83.-(1) in invalid-expression);
+    let final dynamic #t85 = () → void in let final dynamic #t86 = #t85.-(1) in invalid-expression;
+    self::use(let final dynamic #t87 = () → void in let final dynamic #t88 = #t87.-(1) in invalid-expression);
+    self::C<dynamic>;
+    self::use(self::C<dynamic>);
+    dynamic;
+    self::use(dynamic);
+    let final dynamic #t89 = self::C::T in #t89.==(null) ? let final dynamic #t90 = 42 in invalid-expression : null;
+    self::use(let final dynamic #t91 = self::C::T in let final dynamic #t92 = #t91 in #t92.==(null) ? let final dynamic #t93 = 42 in invalid-expression : #t92);
+    () → void;
+    self::use(() → void);
+    let final dynamic #t94 = self::C<dynamic> in let final dynamic #t95 = #t94.+(42) in invalid-expression;
+    self::use(let final dynamic #t96 = self::C<dynamic> in let final dynamic #t97 = #t96.+(42) in invalid-expression);
+    let final dynamic #t98 = dynamic in let final dynamic #t99 = #t98.+(42) in invalid-expression;
+    self::use(let final dynamic #t100 = dynamic in let final dynamic #t101 = #t100.+(42) in invalid-expression);
+    let final dynamic #t102 = self::C::T in let final dynamic #t103 = #t102.+(42) in invalid-expression;
+    self::use(let final dynamic #t104 = self::C::T in let final dynamic #t105 = #t104.+(42) in invalid-expression);
+    let final dynamic #t106 = () → void in let final dynamic #t107 = #t106.+(42) in invalid-expression;
+    self::use(let final dynamic #t108 = () → void in let final dynamic #t109 = #t108.+(42) in invalid-expression);
+    let final dynamic #t110 = self::C<dynamic> in let final dynamic #t111 = #t110.-(42) in invalid-expression;
+    self::use(let final dynamic #t112 = self::C<dynamic> in let final dynamic #t113 = #t112.-(42) in invalid-expression);
+    let final dynamic #t114 = dynamic in let final dynamic #t115 = #t114.-(42) in invalid-expression;
+    self::use(let final dynamic #t116 = dynamic in let final dynamic #t117 = #t116.-(42) in invalid-expression);
+    let final dynamic #t118 = self::C::T in let final dynamic #t119 = #t118.-(42) in invalid-expression;
+    self::use(let final dynamic #t120 = self::C::T in let final dynamic #t121 = #t120.-(42) in invalid-expression);
+    let final dynamic #t122 = () → void in let final dynamic #t123 = #t122.-(42) in invalid-expression;
+    self::use(let final dynamic #t124 = () → void in let final dynamic #t125 = #t124.-(42) in invalid-expression);
+  }
+}
+static method use(dynamic x) → dynamic {
+  if(x.==(new core::DateTime::now().millisecondsSinceEpoch))
+    throw "Shouldn't happen";
+}
+static method main() → dynamic {
+  new self::C::•<dynamic>().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/type_literals.dart.direct.expect b/pkg/front_end/test/fasta/rasta/type_literals.dart.direct.expect
new file mode 100644
index 0000000..e57d938
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_literals.dart.direct.expect
@@ -0,0 +1,98 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object> extends core::Object {
+  constructor •() → void
+    : super core::Object::•()
+    ;
+  method test() → dynamic {
+    self::C<dynamic>;
+    self::use(self::C<dynamic>);
+    dynamic;
+    self::use(dynamic);
+    self::C::T;
+    self::use(self::C::T);
+    () → void;
+    self::use(() → void);
+    self::C<dynamic>.call();
+    self::use(self::C<dynamic>.call());
+    core::Type.call();
+    self::use(core::Type.call());
+    self::C::T.call();
+    self::use(self::C::T.call());
+    () → void.call();
+    self::use(() → void.call());
+    let final dynamic #t1 = 42 in invalid-expression;
+    self::use(let final dynamic #t2 = 42 in invalid-expression);
+    let final dynamic #t3 = 42 in invalid-expression;
+    self::use(let final dynamic #t4 = 42 in invalid-expression);
+    let final dynamic #t5 = 42 in invalid-expression;
+    self::use(let final dynamic #t6 = 42 in invalid-expression);
+    let final dynamic #t7 = 42 in invalid-expression;
+    self::use(let final dynamic #t8 = 42 in invalid-expression);
+    let final dynamic #t9 = self::C<dynamic> in let final dynamic #t10 = #t9.+(1) in invalid-expression;
+    self::use(let final dynamic #t11 = self::C<dynamic> in let final dynamic #t12 = #t11 in let final dynamic #t13 = let final dynamic #t14 = #t12.+(1) in invalid-expression in #t12);
+    let final dynamic #t15 = dynamic in let final dynamic #t16 = #t15.+(1) in invalid-expression;
+    self::use(let final dynamic #t17 = dynamic in let final dynamic #t18 = #t17 in let final dynamic #t19 = let final dynamic #t20 = #t18.+(1) in invalid-expression in #t18);
+    let final dynamic #t21 = self::C::T in let final dynamic #t22 = #t21.+(1) in invalid-expression;
+    self::use(let final dynamic #t23 = self::C::T in let final dynamic #t24 = #t23 in let final dynamic #t25 = let final dynamic #t26 = #t24.+(1) in invalid-expression in #t24);
+    let final dynamic #t27 = () → void in let final dynamic #t28 = #t27.+(1) in invalid-expression;
+    self::use(let final dynamic #t29 = () → void in let final dynamic #t30 = #t29 in let final dynamic #t31 = let final dynamic #t32 = #t30.+(1) in invalid-expression in #t30);
+    let final dynamic #t33 = self::C<dynamic> in let final dynamic #t34 = #t33.+(1) in invalid-expression;
+    self::use(let final dynamic #t35 = self::C<dynamic> in let final dynamic #t36 = #t35.+(1) in invalid-expression);
+    let final dynamic #t37 = dynamic in let final dynamic #t38 = #t37.+(1) in invalid-expression;
+    self::use(let final dynamic #t39 = dynamic in let final dynamic #t40 = #t39.+(1) in invalid-expression);
+    let final dynamic #t41 = self::C::T in let final dynamic #t42 = #t41.+(1) in invalid-expression;
+    self::use(let final dynamic #t43 = self::C::T in let final dynamic #t44 = #t43.+(1) in invalid-expression);
+    let final dynamic #t45 = () → void in let final dynamic #t46 = #t45.+(1) in invalid-expression;
+    self::use(let final dynamic #t47 = () → void in let final dynamic #t48 = #t47.+(1) in invalid-expression);
+    let final dynamic #t49 = self::C<dynamic> in let final dynamic #t50 = #t49.-(1) in invalid-expression;
+    self::use(let final dynamic #t51 = self::C<dynamic> in let final dynamic #t52 = #t51 in let final dynamic #t53 = let final dynamic #t54 = #t52.-(1) in invalid-expression in #t52);
+    let final dynamic #t55 = dynamic in let final dynamic #t56 = #t55.-(1) in invalid-expression;
+    self::use(let final dynamic #t57 = dynamic in let final dynamic #t58 = #t57 in let final dynamic #t59 = let final dynamic #t60 = #t58.-(1) in invalid-expression in #t58);
+    let final dynamic #t61 = self::C::T in let final dynamic #t62 = #t61.-(1) in invalid-expression;
+    self::use(let final dynamic #t63 = self::C::T in let final dynamic #t64 = #t63 in let final dynamic #t65 = let final dynamic #t66 = #t64.-(1) in invalid-expression in #t64);
+    let final dynamic #t67 = () → void in let final dynamic #t68 = #t67.-(1) in invalid-expression;
+    self::use(let final dynamic #t69 = () → void in let final dynamic #t70 = #t69 in let final dynamic #t71 = let final dynamic #t72 = #t70.-(1) in invalid-expression in #t70);
+    let final dynamic #t73 = self::C<dynamic> in let final dynamic #t74 = #t73.-(1) in invalid-expression;
+    self::use(let final dynamic #t75 = self::C<dynamic> in let final dynamic #t76 = #t75.-(1) in invalid-expression);
+    let final dynamic #t77 = dynamic in let final dynamic #t78 = #t77.-(1) in invalid-expression;
+    self::use(let final dynamic #t79 = dynamic in let final dynamic #t80 = #t79.-(1) in invalid-expression);
+    let final dynamic #t81 = self::C::T in let final dynamic #t82 = #t81.-(1) in invalid-expression;
+    self::use(let final dynamic #t83 = self::C::T in let final dynamic #t84 = #t83.-(1) in invalid-expression);
+    let final dynamic #t85 = () → void in let final dynamic #t86 = #t85.-(1) in invalid-expression;
+    self::use(let final dynamic #t87 = () → void in let final dynamic #t88 = #t87.-(1) in invalid-expression);
+    self::C<dynamic>;
+    self::use(self::C<dynamic>);
+    dynamic;
+    self::use(dynamic);
+    let final dynamic #t89 = self::C::T in #t89.==(null) ? let final dynamic #t90 = 42 in invalid-expression : null;
+    self::use(let final dynamic #t91 = self::C::T in let final dynamic #t92 = #t91 in #t92.==(null) ? let final dynamic #t93 = 42 in invalid-expression : #t92);
+    () → void;
+    self::use(() → void);
+    let final dynamic #t94 = self::C<dynamic> in let final dynamic #t95 = #t94.+(42) in invalid-expression;
+    self::use(let final dynamic #t96 = self::C<dynamic> in let final dynamic #t97 = #t96.+(42) in invalid-expression);
+    let final dynamic #t98 = dynamic in let final dynamic #t99 = #t98.+(42) in invalid-expression;
+    self::use(let final dynamic #t100 = dynamic in let final dynamic #t101 = #t100.+(42) in invalid-expression);
+    let final dynamic #t102 = self::C::T in let final dynamic #t103 = #t102.+(42) in invalid-expression;
+    self::use(let final dynamic #t104 = self::C::T in let final dynamic #t105 = #t104.+(42) in invalid-expression);
+    let final dynamic #t106 = () → void in let final dynamic #t107 = #t106.+(42) in invalid-expression;
+    self::use(let final dynamic #t108 = () → void in let final dynamic #t109 = #t108.+(42) in invalid-expression);
+    let final dynamic #t110 = self::C<dynamic> in let final dynamic #t111 = #t110.-(42) in invalid-expression;
+    self::use(let final dynamic #t112 = self::C<dynamic> in let final dynamic #t113 = #t112.-(42) in invalid-expression);
+    let final dynamic #t114 = dynamic in let final dynamic #t115 = #t114.-(42) in invalid-expression;
+    self::use(let final dynamic #t116 = dynamic in let final dynamic #t117 = #t116.-(42) in invalid-expression);
+    let final dynamic #t118 = self::C::T in let final dynamic #t119 = #t118.-(42) in invalid-expression;
+    self::use(let final dynamic #t120 = self::C::T in let final dynamic #t121 = #t120.-(42) in invalid-expression);
+    let final dynamic #t122 = () → void in let final dynamic #t123 = #t122.-(42) in invalid-expression;
+    self::use(let final dynamic #t124 = () → void in let final dynamic #t125 = #t124.-(42) in invalid-expression);
+  }
+}
+static method use(dynamic x) → dynamic {
+  if(x.==(new core::DateTime::now().millisecondsSinceEpoch))
+    throw "Shouldn't happen";
+}
+static method main() → dynamic {
+  new self::C::•<dynamic>().test();
+}
diff --git a/pkg/front_end/test/fasta/rasta/type_literals.dart.outline.expect b/pkg/front_end/test/fasta/rasta/type_literals.dart.outline.expect
new file mode 100644
index 0000000..6b1bbaf
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_literals.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object> extends core::Object {
+  constructor •() → void
+    ;
+  method test() → dynamic
+    ;
+}
+static method use(dynamic x) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart
new file mode 100644
index 0000000..ac9bb02
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart
@@ -0,0 +1,22 @@
+// 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.
+
+main() {
+  // When analyzing this, the class element for B hasn't tried to parse its
+  // members and isn't yet malformed.
+  new B<A>();
+}
+
+
+class A {
+  foo() {
+    // But now, the class element for B has become malformed (as hasParseError
+    // is true).
+    new B<A>();
+  }
+}
+
+class B<T> {
+  int i
+}
diff --git a/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.dartk.expect
new file mode 100644
index 0000000..18d0cca
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.dartk.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → self::A
+    : super core::Object::•();
+  method foo() → dynamic {
+    throw core::_malformedTypeError("'B' is not a type.");
+  }
+}
+class B extends core::Object {
+  constructor •() → self::B
+    : super core::Object::•();
+}
+static method main() → dynamic {
+  throw core::_malformedTypeError("'B' is not a type.");
+}
diff --git a/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.direct.expect b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.direct.expect
new file mode 100644
index 0000000..18d0cca
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.direct.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → self::A
+    : super core::Object::•();
+  method foo() → dynamic {
+    throw core::_malformedTypeError("'B' is not a type.");
+  }
+}
+class B extends core::Object {
+  constructor •() → self::B
+    : super core::Object::•();
+}
+static method main() → dynamic {
+  throw core::_malformedTypeError("'B' is not a type.");
+}
diff --git a/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.outline.expect b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.outline.expect
new file mode 100644
index 0000000..6b89dbc
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/type_with_parse_error.dart.outline.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+}
+class B extends core::Object {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/typedef.dart b/pkg/front_end/test/fasta/rasta/typedef.dart
new file mode 100644
index 0000000..37e26a6
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/typedef.dart
@@ -0,0 +1,12 @@
+// 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.
+
+typedef void Foo();
+
+main() {
+  print(Foo);
+  Foo = null;
+  Foo ??= null;
+  Foo();
+}
diff --git a/pkg/front_end/test/fasta/rasta/typedef.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/typedef.dart.dartk.expect
new file mode 100644
index 0000000..dddec20
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/typedef.dart.dartk.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(() → void);
+  let final dynamic #t1 = null in invalid-expression;
+  () → void;
+  () → void.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/typedef.dart.direct.expect b/pkg/front_end/test/fasta/rasta/typedef.dart.direct.expect
new file mode 100644
index 0000000..dddec20
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/typedef.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(() → void);
+  let final dynamic #t1 = null in invalid-expression;
+  () → void;
+  () → void.call();
+}
diff --git a/pkg/front_end/test/fasta/rasta/typedef.dart.outline.expect b/pkg/front_end/test/fasta/rasta/typedef.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/typedef.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/unresolved.dart b/pkg/front_end/test/fasta/rasta/unresolved.dart
new file mode 100644
index 0000000..39c690c
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  new Missing();
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/unresolved.dart.dartk.expect
new file mode 100644
index 0000000..7a8674f
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved.dart.dartk.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  throw core::_malformedTypeError("Cannot resolve 'Missing'.");
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved.dart.direct.expect b/pkg/front_end/test/fasta/rasta/unresolved.dart.direct.expect
new file mode 100644
index 0000000..4ea5484
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved.dart.direct.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  throw new core::NoSuchMethodError::•(null, #Missing, <dynamic>[], <dynamic, dynamic>{}, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved.dart.outline.expect b/pkg/front_end/test/fasta/rasta/unresolved.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart
new file mode 100644
index 0000000..3106df6
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart
@@ -0,0 +1,12 @@
+// 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.
+
+class Foo {
+  Foo(x, y);
+}
+
+main() {
+  new Foo();
+  new Foo.notHere();
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.dartk.expect
new file mode 100644
index 0000000..93d15b0
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.dartk.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  constructor •(dynamic x, dynamic y) → dynamic
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  invalid-expression;
+  throw core::_unresolvedConstructorError(self::Foo, #Foo.notHere, <dynamic>[], <dynamic, dynamic>{}, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.direct.expect b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.direct.expect
new file mode 100644
index 0000000..4fe083a
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.direct.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  constructor •(dynamic x, dynamic y) → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  throw new core::NoSuchMethodError::•(null, #, <dynamic>[], <dynamic, dynamic>{}, null);
+  throw new core::NoSuchMethodError::•(null, #Foo.notHere, <dynamic>[], <dynamic, dynamic>{}, null);
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.outline.expect b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.outline.expect
new file mode 100644
index 0000000..33539ac
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_constructor.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  constructor •(dynamic x, dynamic y) → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart
new file mode 100644
index 0000000..b9e9c1b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'dart:collection' as collection;
+
+typedef void VoidFunction();
+
+class Fisk {
+  it1(x) {
+    for (key in x) {
+      print(key);
+    }
+    for (Fisk in x) {
+      print(Fisk);
+    }
+    for (collection in x) {
+      print(collection);
+    }
+    for (VoidFunction in x) {
+      print(VoidFunction);
+    }
+    for (1 in x) {
+      print(key);
+    }
+  }
+}
+
+main(arguments) {
+  new Fisk();
+  for (key in arguments) {
+    print(key);
+  }
+  for (Fisk in arguments) {
+    print(Fisk);
+  }
+  for (collection in arguments) {
+    print(collection);
+  }
+  for (VoidFunction in arguments) {
+    print(VoidFunction);
+  }
+  for (1 in arguments) {
+    print(key);
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.dartk.expect
new file mode 100644
index 0000000..1d5ea67
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.dartk.expect
@@ -0,0 +1,53 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Fisk extends core::Object {
+  constructor •() → self::Fisk
+    : super core::Object::•();
+  method it1(dynamic x) → dynamic {
+    for (final dynamic #t1 in x) {
+      this.key = #t1;
+      core::print(this.key);
+    }
+    for (final dynamic #t2 in x) {
+      let final dynamic #t3 = #t2 in invalid-expression;
+      core::print(self::Fisk);
+    }
+    for (final dynamic #t4 in x) {
+      let final dynamic #t5 = #t4 in invalid-expression;
+      core::print(invalid-expression);
+    }
+    for (final dynamic #t6 in x) {
+      let final dynamic #t7 = #t6 in invalid-expression;
+      core::print(() → void);
+    }
+    for (final dynamic #t8 in x) {
+      let final dynamic #t9 = #t8 in invalid-expression;
+      core::print(this.key);
+    }
+  }
+}
+static method main(dynamic arguments) → dynamic {
+  new self::Fisk::•();
+  for (final dynamic #t10 in arguments) {
+    let final dynamic #t11 = #t10 in invalid-expression;
+    core::print(throw core::_genericNoSuchMethod(null, #key, <dynamic>[], <dynamic, dynamic>{}, null));
+  }
+  for (final dynamic #t12 in arguments) {
+    let final dynamic #t13 = #t12 in invalid-expression;
+    core::print(self::Fisk);
+  }
+  for (final dynamic #t14 in arguments) {
+    let final dynamic #t15 = #t14 in invalid-expression;
+    core::print(invalid-expression);
+  }
+  for (final dynamic #t16 in arguments) {
+    let final dynamic #t17 = #t16 in invalid-expression;
+    core::print(() → void);
+  }
+  for (final dynamic #t18 in arguments) {
+    let final dynamic #t19 = #t18 in invalid-expression;
+    core::print(throw core::_genericNoSuchMethod(null, #key, <dynamic>[], <dynamic, dynamic>{}, null));
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.direct.expect b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.direct.expect
new file mode 100644
index 0000000..1d5ea67
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.direct.expect
@@ -0,0 +1,53 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Fisk extends core::Object {
+  constructor •() → self::Fisk
+    : super core::Object::•();
+  method it1(dynamic x) → dynamic {
+    for (final dynamic #t1 in x) {
+      this.key = #t1;
+      core::print(this.key);
+    }
+    for (final dynamic #t2 in x) {
+      let final dynamic #t3 = #t2 in invalid-expression;
+      core::print(self::Fisk);
+    }
+    for (final dynamic #t4 in x) {
+      let final dynamic #t5 = #t4 in invalid-expression;
+      core::print(invalid-expression);
+    }
+    for (final dynamic #t6 in x) {
+      let final dynamic #t7 = #t6 in invalid-expression;
+      core::print(() → void);
+    }
+    for (final dynamic #t8 in x) {
+      let final dynamic #t9 = #t8 in invalid-expression;
+      core::print(this.key);
+    }
+  }
+}
+static method main(dynamic arguments) → dynamic {
+  new self::Fisk::•();
+  for (final dynamic #t10 in arguments) {
+    let final dynamic #t11 = #t10 in invalid-expression;
+    core::print(throw core::_genericNoSuchMethod(null, #key, <dynamic>[], <dynamic, dynamic>{}, null));
+  }
+  for (final dynamic #t12 in arguments) {
+    let final dynamic #t13 = #t12 in invalid-expression;
+    core::print(self::Fisk);
+  }
+  for (final dynamic #t14 in arguments) {
+    let final dynamic #t15 = #t14 in invalid-expression;
+    core::print(invalid-expression);
+  }
+  for (final dynamic #t16 in arguments) {
+    let final dynamic #t17 = #t16 in invalid-expression;
+    core::print(() → void);
+  }
+  for (final dynamic #t18 in arguments) {
+    let final dynamic #t19 = #t18 in invalid-expression;
+    core::print(throw core::_genericNoSuchMethod(null, #key, <dynamic>[], <dynamic, dynamic>{}, null));
+  }
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.outline.expect b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.outline.expect
new file mode 100644
index 0000000..b27584e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_for_in.dart.outline.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Fisk extends core::Object {
+  constructor •() → void
+    ;
+  method it1(dynamic x) → dynamic
+    ;
+}
+static method main(dynamic arguments) → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart
new file mode 100644
index 0000000..1cc6bf2
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart
@@ -0,0 +1,24 @@
+// 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.
+
+class E {
+  foo() {
+    super[4] = 42;
+    super[4] += 5;
+    return super[2];
+  }
+}
+
+beforeTestMissingTry () {
+  // Referring to this function before it has been resolved would lead to a
+  // crash.
+  testMissingTry();
+}
+
+testMissingTry() {
+  on Exception catch (e) { }
+}
+
+main() {
+}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.dartk.expect
new file mode 100644
index 0000000..4e64945
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.dartk.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class E extends core::Object {
+  constructor •() → self::E
+    : super core::Object::•();
+  method foo() → dynamic {
+    super.[]=(4, 42);
+    let final dynamic #t1 = 4 in super.[]=(#t1, super.[](#t1).+(5));
+    return super.[](2);
+  }
+}
+static method beforeTestMissingTry() → dynamic {
+  throw core::_genericNoSuchMethod(null, #testMissingTry, <dynamic>[], <dynamic, dynamic>{}, null);
+}
+static method testMissingTry() → dynamic
+  invalid-statement;
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.direct.expect b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.direct.expect
new file mode 100644
index 0000000..4e64945
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.direct.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class E extends core::Object {
+  constructor •() → self::E
+    : super core::Object::•();
+  method foo() → dynamic {
+    super.[]=(4, 42);
+    let final dynamic #t1 = 4 in super.[]=(#t1, super.[](#t1).+(5));
+    return super.[](2);
+  }
+}
+static method beforeTestMissingTry() → dynamic {
+  throw core::_genericNoSuchMethod(null, #testMissingTry, <dynamic>[], <dynamic, dynamic>{}, null);
+}
+static method testMissingTry() → dynamic
+  invalid-statement;
+static method main() → dynamic {}
diff --git a/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.outline.expect b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.outline.expect
new file mode 100644
index 0000000..36d86b3
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unresolved_recovery.dart.outline.expect
@@ -0,0 +1,16 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class E extends core::Object {
+  constructor •() → void
+    ;
+  method foo() → dynamic
+    ;
+}
+static method beforeTestMissingTry() → dynamic
+  ;
+static method testMissingTry() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart
new file mode 100644
index 0000000..ca1de9b
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart
@@ -0,0 +1,6 @@
+// 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.
+
+import 'dart:html';
+import 'dart:io';
diff --git a/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.dartk.expect b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.dartk.expect
new file mode 100644
index 0000000..cc97b3e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.dartk.expect
@@ -0,0 +1,2 @@
+library;
+import self as self;
diff --git a/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.direct.expect b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.direct.expect
new file mode 100644
index 0000000..cc97b3e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.direct.expect
@@ -0,0 +1,2 @@
+library;
+import self as self;
diff --git a/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.outline.expect b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.outline.expect
new file mode 100644
index 0000000..cc97b3e
--- /dev/null
+++ b/pkg/front_end/test/fasta/rasta/unsupported_platform_library.dart.outline.expect
@@ -0,0 +1,2 @@
+library;
+import self as self;
diff --git a/pkg/front_end/test/fasta/scanner/scanner.status b/pkg/front_end/test/fasta/scanner/scanner.status
new file mode 100644
index 0000000..6dd5db6
--- /dev/null
+++ b/pkg/front_end/test/fasta/scanner/scanner.status
@@ -0,0 +1,373 @@
+# 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.
+
+pkg/dev_compiler/test/codegen/language/application_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/assign_instance_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_initializer1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_initializer2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_named_constructor_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/bad_raw_string_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/body_less_constructor_wrong_arg_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/closure_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/const_counter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/const_optional_args_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_redirect1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_redirect2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/constructor_setter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/duplicate_export_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/duplicate_interface_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/export_ambiguous_main_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/extend_type_parameter2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/extend_type_parameter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/factory2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/factory3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/factory_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field3a_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field6a_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/field_method4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/function_type_parameter2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/function_type_parameter_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/getter_declaration_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/import_combinators_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/inst_field_initializer1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/instance_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/instance_method2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/instance_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface_injection1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface_injection2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface_static_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/interface_static_non_final_fields_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/is_not_class1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/is_not_class4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/issue1578_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/label8_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/library_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/list_literal2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/list_literal_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/map_literal2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/map_literal_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/new_expression1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/new_expression2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/new_expression3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/no_such_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/non_const_super_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/operator1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/operator2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/override_field_method5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/parameter_initializer6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix10_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix11_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix12_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix13_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix15_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix18_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix7_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/prefix8_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/private_member1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/private_member2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/private_member3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/script1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/script2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/setter_declaration2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/setter_declaration_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/source_self_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/static_call_wrong_argument_count_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_escape4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolate1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolate2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_interpolation6_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode2_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/string_unicode4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch1_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch3_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch4_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch5_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/switch7_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/test_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/type_variable_static_context_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unary_plus_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unhandled_exception_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unresolved_in_factory_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unresolved_top_level_method_negative_test: Fail
+pkg/dev_compiler/test/codegen/language/unresolved_top_level_var_negative_test: Fail
+pkg/testing/test/dart_sdk_negative_test: Fail
+tests/compiler/dart2js_extra/empty_negative_test: Fail
+tests/compiler/dart2js_extra/invalid_length_negative_test: Fail
+tests/compiler/dart2js_extra/timer_negative_test: Fail
+tests/language/application_negative_test: Fail
+tests/language/assign_instance_method_negative_test: Fail
+tests/language/bad_initializer1_negative_test: Fail
+tests/language/bad_initializer2_negative_test: Fail
+tests/language/bad_named_constructor_negative_test: Fail
+tests/language/bad_raw_string_negative_test: Fail
+tests/language/body_less_constructor_wrong_arg_negative_test: Fail
+tests/language/closure_call_wrong_argument_count_negative_test: Fail
+tests/language/const_counter_negative_test: Fail
+tests/language/const_optional_args_negative_test: Fail
+tests/language/constructor3_negative_test: Fail
+tests/language/constructor_call_wrong_argument_count_negative_test: Fail
+tests/language/constructor_redirect1_negative_test: Fail
+tests/language/constructor_redirect2_negative_test: Fail
+tests/language/constructor_setter_negative_test: Fail
+tests/language/deep_nesting1_negative_test: Fail
+tests/language/deep_nesting2_negative_test: Fail
+tests/language/duplicate_export_negative_test: Fail
+tests/language/duplicate_interface_negative_test: Fail
+tests/language/export_ambiguous_main_negative_test: Fail
+tests/language/extend_type_parameter2_negative_test: Fail
+tests/language/extend_type_parameter_negative_test: Fail
+tests/language/factory2_negative_test: Fail
+tests/language/factory3_negative_test: Fail
+tests/language/factory_negative_test: Fail
+tests/language/field1_negative_test: Fail
+tests/language/field2_negative_test: Fail
+tests/language/field3_negative_test: Fail
+tests/language/field3a_negative_test: Fail
+tests/language/field4_negative_test: Fail
+tests/language/field5_negative_test: Fail
+tests/language/field6_negative_test: Fail
+tests/language/field6a_negative_test: Fail
+tests/language/field_method4_negative_test: Fail
+tests/language/function_type_parameter2_negative_test: Fail
+tests/language/function_type_parameter_negative_test: Fail
+tests/language/getter_declaration_negative_test: Fail
+tests/language/import_combinators_negative_test: Fail
+tests/language/inst_field_initializer1_negative_test: Fail
+tests/language/instance_call_wrong_argument_count_negative_test: Fail
+tests/language/instance_method2_negative_test: Fail
+tests/language/instance_method_negative_test: Fail
+tests/language/interface2_negative_test: Fail
+tests/language/interface_injection1_negative_test: Fail
+tests/language/interface_injection2_negative_test: Fail
+tests/language/interface_static_method_negative_test: Fail
+tests/language/interface_static_non_final_fields_negative_test: Fail
+tests/language/is_not_class1_negative_test: Fail
+tests/language/is_not_class4_negative_test: Fail
+tests/language/issue1578_negative_test: Fail
+tests/language/label2_negative_test: Fail
+tests/language/label3_negative_test: Fail
+tests/language/label5_negative_test: Fail
+tests/language/label6_negative_test: Fail
+tests/language/label8_negative_test: Fail
+tests/language/library_negative_test: Fail
+tests/language/list_literal2_negative_test: Fail
+tests/language/list_literal_negative_test: Fail
+tests/language/map_literal2_negative_test: Fail
+tests/language/map_literal_negative_test: Fail
+tests/language/new_expression1_negative_test: Fail
+tests/language/new_expression2_negative_test: Fail
+tests/language/new_expression3_negative_test: Fail
+tests/language/no_such_method_negative_test: Fail
+tests/language/non_const_super_negative_test: Fail
+tests/language/operator1_negative_test: Fail
+tests/language/operator2_negative_test: Fail
+tests/language/override_field_method1_negative_test: Fail
+tests/language/override_field_method2_negative_test: Fail
+tests/language/override_field_method4_negative_test: Fail
+tests/language/override_field_method5_negative_test: Fail
+tests/language/parameter_initializer1_negative_test: Fail
+tests/language/parameter_initializer2_negative_test: Fail
+tests/language/parameter_initializer3_negative_test: Fail
+tests/language/parameter_initializer4_negative_test: Fail
+tests/language/parameter_initializer5_negative_test: Fail
+tests/language/parameter_initializer6_negative_test: Fail
+tests/language/prefix10_negative_test: Fail
+tests/language/prefix11_negative_test: Fail
+tests/language/prefix12_negative_test: Fail
+tests/language/prefix13_negative_test: Fail
+tests/language/prefix15_negative_test: Fail
+tests/language/prefix18_negative_test: Fail
+tests/language/prefix1_negative_test: Fail
+tests/language/prefix2_negative_test: Fail
+tests/language/prefix3_negative_test: Fail
+tests/language/prefix4_negative_test: Fail
+tests/language/prefix5_negative_test: Fail
+tests/language/prefix6_negative_test: Fail
+tests/language/prefix7_negative_test: Fail
+tests/language/prefix8_negative_test: Fail
+tests/language/private_member1_negative_test: Fail
+tests/language/private_member2_negative_test: Fail
+tests/language/private_member3_negative_test: Fail
+tests/language/script1_negative_test: Fail
+tests/language/script2_negative_test: Fail
+tests/language/setter_declaration2_negative_test: Fail
+tests/language/setter_declaration_negative_test: Fail
+tests/language/source_self_negative_test: Fail
+tests/language/static_call_wrong_argument_count_negative_test: Fail
+tests/language/string_escape4_negative_test: Fail
+tests/language/string_interpolate1_negative_test: Fail
+tests/language/string_interpolate2_negative_test: Fail
+tests/language/string_unicode1_negative_test: Fail
+tests/language/string_unicode2_negative_test: Fail
+tests/language/string_unicode3_negative_test: Fail
+tests/language/string_unicode4_negative_test: Fail
+tests/language/switch1_negative_test: Fail
+tests/language/switch3_negative_test: Fail
+tests/language/switch4_negative_test: Fail
+tests/language/switch5_negative_test: Fail
+tests/language/switch7_negative_test: Fail
+tests/language/test_negative_test: Fail
+tests/language/type_variable_static_context_negative_test: Fail
+tests/language/unary_plus_negative_test: Fail
+tests/language/unhandled_exception_negative_test: Fail
+tests/language/unresolved_in_factory_negative_test: Fail
+tests/language/unresolved_top_level_method_negative_test: Fail
+tests/language/unresolved_top_level_var_negative_test: Fail
+tests/language_strong/application_negative_test: Fail
+tests/language_strong/assign_instance_method_negative_test: Fail
+tests/language_strong/bad_initializer1_negative_test: Fail
+tests/language_strong/bad_initializer2_negative_test: Fail
+tests/language_strong/bad_named_constructor_negative_test: Fail
+tests/language_strong/bad_raw_string_negative_test: Fail
+tests/language_strong/body_less_constructor_wrong_arg_negative_test: Fail
+tests/language_strong/closure_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/const_counter_negative_test: Fail
+tests/language_strong/const_optional_args_negative_test: Fail
+tests/language_strong/constructor3_negative_test: Fail
+tests/language_strong/constructor_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/constructor_redirect1_negative_test: Fail
+tests/language_strong/constructor_redirect2_negative_test: Fail
+tests/language_strong/constructor_setter_negative_test: Fail
+tests/language_strong/duplicate_export_negative_test: Fail
+tests/language_strong/duplicate_interface_negative_test: Fail
+tests/language_strong/export_ambiguous_main_negative_test: Fail
+tests/language_strong/extend_type_parameter2_negative_test: Fail
+tests/language_strong/extend_type_parameter_negative_test: Fail
+tests/language_strong/factory2_negative_test: Fail
+tests/language_strong/factory3_negative_test: Fail
+tests/language_strong/factory_negative_test: Fail
+tests/language_strong/field1_negative_test: Fail
+tests/language_strong/field2_negative_test: Fail
+tests/language_strong/field3_negative_test: Fail
+tests/language_strong/field3a_negative_test: Fail
+tests/language_strong/field4_negative_test: Fail
+tests/language_strong/field5_negative_test: Fail
+tests/language_strong/field6_negative_test: Fail
+tests/language_strong/field6a_negative_test: Fail
+tests/language_strong/field_method4_negative_test: Fail
+tests/language_strong/function_type_parameter2_negative_test: Fail
+tests/language_strong/function_type_parameter_negative_test: Fail
+tests/language_strong/getter_declaration_negative_test: Fail
+tests/language_strong/import_combinators_negative_test: Fail
+tests/language_strong/inst_field_initializer1_negative_test: Fail
+tests/language_strong/instance_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/instance_method2_negative_test: Fail
+tests/language_strong/instance_method_negative_test: Fail
+tests/language_strong/interface2_negative_test: Fail
+tests/language_strong/interface_injection1_negative_test: Fail
+tests/language_strong/interface_injection2_negative_test: Fail
+tests/language_strong/interface_static_method_negative_test: Fail
+tests/language_strong/interface_static_non_final_fields_negative_test: Fail
+tests/language_strong/is_not_class1_negative_test: Fail
+tests/language_strong/is_not_class4_negative_test: Fail
+tests/language_strong/issue1578_negative_test: Fail
+tests/language_strong/label2_negative_test: Fail
+tests/language_strong/label3_negative_test: Fail
+tests/language_strong/label5_negative_test: Fail
+tests/language_strong/label6_negative_test: Fail
+tests/language_strong/label8_negative_test: Fail
+tests/language_strong/library_negative_test: Fail
+tests/language_strong/list_literal2_negative_test: Fail
+tests/language_strong/list_literal_negative_test: Fail
+tests/language_strong/map_literal2_negative_test: Fail
+tests/language_strong/map_literal_negative_test: Fail
+tests/language_strong/new_expression1_negative_test: Fail
+tests/language_strong/new_expression2_negative_test: Fail
+tests/language_strong/new_expression3_negative_test: Fail
+tests/language_strong/no_such_method_negative_test: Fail
+tests/language_strong/non_const_super_negative_test: Fail
+tests/language_strong/operator1_negative_test: Fail
+tests/language_strong/operator2_negative_test: Fail
+tests/language_strong/override_field_method1_negative_test: Fail
+tests/language_strong/override_field_method2_negative_test: Fail
+tests/language_strong/override_field_method4_negative_test: Fail
+tests/language_strong/override_field_method5_negative_test: Fail
+tests/language_strong/parameter_initializer1_negative_test: Fail
+tests/language_strong/parameter_initializer2_negative_test: Fail
+tests/language_strong/parameter_initializer3_negative_test: Fail
+tests/language_strong/parameter_initializer4_negative_test: Fail
+tests/language_strong/parameter_initializer6_negative_test: Fail
+tests/language_strong/prefix10_negative_test: Fail
+tests/language_strong/prefix11_negative_test: Fail
+tests/language_strong/prefix12_negative_test: Fail
+tests/language_strong/prefix13_negative_test: Fail
+tests/language_strong/prefix15_negative_test: Fail
+tests/language_strong/prefix18_negative_test: Fail
+tests/language_strong/prefix1_negative_test: Fail
+tests/language_strong/prefix2_negative_test: Fail
+tests/language_strong/prefix3_negative_test: Fail
+tests/language_strong/prefix4_negative_test: Fail
+tests/language_strong/prefix5_negative_test: Fail
+tests/language_strong/prefix6_negative_test: Fail
+tests/language_strong/prefix7_negative_test: Fail
+tests/language_strong/prefix8_negative_test: Fail
+tests/language_strong/private_member1_negative_test: Fail
+tests/language_strong/private_member2_negative_test: Fail
+tests/language_strong/private_member3_negative_test: Fail
+tests/language_strong/script1_negative_test: Fail
+tests/language_strong/script2_negative_test: Fail
+tests/language_strong/setter_declaration2_negative_test: Fail
+tests/language_strong/setter_declaration_negative_test: Fail
+tests/language_strong/source_self_negative_test: Fail
+tests/language_strong/static_call_wrong_argument_count_negative_test: Fail
+tests/language_strong/string_escape4_negative_test: Fail
+tests/language_strong/string_interpolate1_negative_test: Fail
+tests/language_strong/string_interpolate2_negative_test: Fail
+tests/language_strong/string_interpolation1_negative_test: Fail
+tests/language_strong/string_interpolation2_negative_test: Fail
+tests/language_strong/string_interpolation3_negative_test: Fail
+tests/language_strong/string_interpolation4_negative_test: Fail
+tests/language_strong/string_interpolation5_negative_test: Fail
+tests/language_strong/string_interpolation6_negative_test: Fail
+tests/language_strong/string_unicode1_negative_test: Fail
+tests/language_strong/string_unicode2_negative_test: Fail
+tests/language_strong/string_unicode3_negative_test: Fail
+tests/language_strong/string_unicode4_negative_test: Fail
+tests/language_strong/switch1_negative_test: Fail
+tests/language_strong/switch3_negative_test: Fail
+tests/language_strong/switch4_negative_test: Fail
+tests/language_strong/switch5_negative_test: Fail
+tests/language_strong/switch7_negative_test: Fail
+tests/language_strong/test_negative_test: Fail
+tests/language_strong/type_variable_static_context_negative_test: Fail
+tests/language_strong/unary_plus_negative_test: Fail
+tests/language_strong/unhandled_exception_negative_test: Fail
+tests/language_strong/unresolved_in_factory_negative_test: Fail
+tests/language_strong/unresolved_top_level_method_negative_test: Fail
+tests/language_strong/unresolved_top_level_var_negative_test: Fail
+tests/standalone/io/process_exit_negative_test: Fail
diff --git a/pkg/front_end/test/fasta/scanner/scanner_suite.dart b/pkg/front_end/test/fasta/scanner/scanner_suite.dart
new file mode 100644
index 0000000..64ee2f0
--- /dev/null
+++ b/pkg/front_end/test/fasta/scanner/scanner_suite.dart
@@ -0,0 +1,21 @@
+// 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.
+
+import 'package:testing/testing.dart';
+
+import 'package:front_end/src/fasta/scanner/testing/scanner_chain.dart';
+
+Future<ChainContext> createContext(
+    Chain suite, Map<String, String> enviroment) async {
+  return new ScannerContext();
+}
+
+class ScannerContext extends ChainContext {
+  final List<Step> steps = const <Step>[
+      const Read(),
+      const Scan(),
+  ];
+}
+
+main(List<String> arguments) => runMe(arguments, createContext);
diff --git a/pkg/front_end/test/fasta/scanner/testing.json b/pkg/front_end/test/fasta/scanner/testing.json
new file mode 100644
index 0000000..be732cb
--- /dev/null
+++ b/pkg/front_end/test/fasta/scanner/testing.json
@@ -0,0 +1,29 @@
+{
+"":"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": "scanner",
+      "kind": "Chain",
+      "source": "scanner_suite.dart",
+      "path": "../../../../../",
+      "status": "scanner.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+      ]
+    }
+  ],
+  "analyze": {
+    "uris": [
+      "../../../lib/src/fasta/scanner/",
+      "../../../lib/src/fasta/scanner/bin/",
+      "../../../lib/src/fasta/scanner/testing/"
+    ],
+    "exclude": [
+    ]
+  }
+}
diff --git a/pkg/front_end/test/fasta/sdk_test.dart b/pkg/front_end/test/fasta/sdk_test.dart
new file mode 100644
index 0000000..9e77054
--- /dev/null
+++ b/pkg/front_end/test/fasta/sdk_test.dart
@@ -0,0 +1,32 @@
+// 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.
+
+library fasta.test.compile_test;
+
+import 'dart:async' show
+    Future;
+
+import 'package:front_end/src/fasta/testing/suite.dart';
+
+import 'package:front_end/src/fasta/testing/kernel_chain.dart' show
+    MatchExpectation;
+
+Future<FeContext> createContext(
+    Chain suite, Map<String, String> environment) async {
+  environment[ENABLE_FULL_COMPILE] = "";
+  environment[AST_KIND_INDEX] = "${AstKind.Kernel.index}";
+  FeContext context =
+      await TestContext.create(suite, environment, FeContext.create);
+  int index;
+  for (int i = 0; i < context.steps.length; i++) {
+    if (context.steps[i] is MatchExpectation) {
+      index = i;
+      break;
+    }
+  }
+  context.steps.removeAt(index);
+  return context;
+}
+
+main(List<String> arguments) => runMe(arguments, createContext);
diff --git a/pkg/front_end/test/fasta/statements.dart b/pkg/front_end/test/fasta/statements.dart
new file mode 100644
index 0000000..9fa72f6
--- /dev/null
+++ b/pkg/front_end/test/fasta/statements.dart
@@ -0,0 +1,104 @@
+// 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.
+
+foo() {
+  try {
+    return;
+  } finally {
+    print("Hello from finally block!");
+  }
+}
+
+bar() async {
+  await for (var x in []) {
+    yield x;
+    yield* x;
+  }
+}
+
+main() {
+  do {
+    print("Hello from do-while!");
+  } while(false);
+  do var x = print("Hello from do-while!"); while(false);
+
+  for (String s in ["Hello from for-in!"]) {
+    print(s);
+  }
+  for (String s in ["Hello from for-in without block!"])
+    print(s);
+  var s;
+  for (s in ["Hello from for-in without decl!"]) {
+    print(s);
+  }
+  for (s in ["Hello from for-in without decl and block!"])
+    print(s);
+  a: b: c: print("Hello from labeled statement!");
+  try {
+    try {
+      throw "Hello from rethrow!";
+    } catch (e) {
+      rethrow;
+    }
+  } catch (e) {
+    print(e);
+  }
+  foo();
+  bool done = false;
+  while (!done) {
+    done = true;
+    print("Hello from while!");
+  }
+  ; // Testing empty statement.
+  assert(true);
+  assert(true, "Hello from assert!");
+  try {
+    assert(false, "Hello from assert!");
+  } catch (e) {
+    print(e);
+  }
+  switch (1) {
+    case 1:
+    case 2:
+      print("Hello from switch case!");
+      break;
+    default:
+      break;
+  }
+  switch (4) {
+    L2: case 2:
+      print("Hello from case 2!");
+      break;
+    L1: case 1:
+      print("Hello from case 1!");
+      continue L2;
+    L0: case 0:
+      print("Hello from case 0!");
+      continue L1;
+    case 4:
+      print("Hello from case 4!");
+      continue LD;
+    LD: default:
+      continue L0;
+  }
+  switch (4) {
+    L0: case 1:
+      print("Hello from next case 1");
+      break;
+    default:
+      continue L0;
+  }
+  int i = 0;
+  do {
+    print("Hello from do-while!");
+    if (++i < 3) continue;
+    break;
+  } while (true);
+  i = 0;
+  OUTER: while (true) {
+    print("Hello from while!");
+    if (++i < 3) continue OUTER;
+    break OUTER;
+  }
+}
diff --git a/pkg/front_end/test/fasta/statements.dart.direct.expect b/pkg/front_end/test/fasta/statements.dart.direct.expect
new file mode 100644
index 0000000..5529e5b
--- /dev/null
+++ b/pkg/front_end/test/fasta/statements.dart.direct.expect
@@ -0,0 +1,150 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → dynamic {
+  try {
+    return;
+  }
+  finally {
+    core::print("Hello from finally block!");
+  }
+}
+static method bar() → dynamic async {
+  await for (dynamic x in <dynamic>[]) {
+    yield x;
+    yield* x;
+  }
+}
+static method main() → dynamic {
+  do {
+    core::print("Hello from do-while!");
+  }
+  while (false)
+  do
+    dynamic x = core::print("Hello from do-while!");
+  while (false)
+  for (core::String s in <dynamic>["Hello from for-in!"]) {
+    core::print(s);
+  }
+  for (core::String s in <dynamic>["Hello from for-in without block!"])
+    core::print(s);
+  dynamic s;
+  for (final dynamic #t1 in <dynamic>["Hello from for-in without decl!"]) {
+    s = #t1;
+    core::print(s);
+  }
+  for (final dynamic #t2 in <dynamic>["Hello from for-in without decl and block!"]) {
+    s = #t2;
+    core::print(s);
+  }
+  core::print("Hello from labeled statement!");
+  try {
+    try {
+      throw "Hello from rethrow!";
+    }
+    on dynamic catch(dynamic e) {
+      rethrow;
+    }
+  }
+  on dynamic catch(dynamic e) {
+    core::print(e);
+  }
+  self::foo();
+  core::bool done = false;
+  while (!done) {
+    done = true;
+    core::print("Hello from while!");
+  }
+  ;
+  assert(true);
+  assert(true, "Hello from assert!");
+  try {
+    assert(false, "Hello from assert!");
+  }
+  on dynamic catch(dynamic e) {
+    core::print(e);
+  }
+  #L1:
+  switch(1) {
+    #L2:
+    case 1:
+    case 2:
+      {
+        core::print("Hello from switch case!");
+        break #L1;
+      }
+    #L3:
+    default:
+      {
+        break #L1;
+      }
+  }
+  #L4:
+  switch(4) {
+    #L5:
+    case 2:
+      {
+        core::print("Hello from case 2!");
+        break #L4;
+      }
+    #L6:
+    case 1:
+      {
+        core::print("Hello from case 1!");
+        continue #L5;
+      }
+    #L7:
+    case 0:
+      {
+        core::print("Hello from case 0!");
+        continue #L6;
+      }
+    #L8:
+    case 4:
+      {
+        core::print("Hello from case 4!");
+        continue #L9;
+      }
+    #L9:
+    default:
+      {
+        continue #L7;
+      }
+  }
+  #L10:
+  switch(4) {
+    #L11:
+    case 1:
+      {
+        core::print("Hello from next case 1");
+        break #L10;
+      }
+    #L12:
+    default:
+      {
+        continue #L11;
+      }
+  }
+  core::int i = 0;
+  #L13:
+  do
+    #L14:
+    {
+      core::print("Hello from do-while!");
+      if((i = i.+(1)).<(3))
+        break #L14;
+      break #L13;
+    }
+  while (true)
+  i = 0;
+  #L15:
+  while (true)
+    #L16:
+    {
+      core::print("Hello from while!");
+      if((i = i.+(1)).<(3))
+        break #L16;
+      break #L15;
+    }
+}
diff --git a/pkg/front_end/test/fasta/statements.dart.outline.expect b/pkg/front_end/test/fasta/statements.dart.outline.expect
new file mode 100644
index 0000000..1b94614
--- /dev/null
+++ b/pkg/front_end/test/fasta/statements.dart.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+
+static method foo() → dynamic
+  ;
+static method bar() → dynamic async 
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/testing.json b/pkg/front_end/test/fasta/testing.json
new file mode 100644
index 0000000..af7e073
--- /dev/null
+++ b/pkg/front_end/test/fasta/testing.json
@@ -0,0 +1,163 @@
+{
+"":"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": "scanner",
+      "kind": "Chain",
+      "source": "scanner/scanner_suite.dart",
+      "path": "../../../../",
+      "status": "scanner/scanner.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+      ]
+    },
+
+    {
+      "name": "parser",
+      "kind": "Chain",
+      "source": "parser/parser_suite.dart",
+      "path": "../../../../",
+      "status": "parser/parser.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+        "README.dart",
+        "/sdk/xcodebuild/",
+        "/sdk/out/",
+        "/sdk/build/",
+        "/sdk/tools/sdks/",
+        "/sdk/generated/"
+      ]
+    },
+
+    {
+      "name": "outline",
+      "kind": "Chain",
+      "source": "outline_test.dart",
+      "path": "./",
+      "status": "outline.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+        "/test/.*_test\\.dart$",
+        "/test/.*_suite\\.dart$",
+        "/test/fasta/top_level_accessors_part\\.dart$"
+      ]
+    },
+
+    {
+      "name": "compile",
+      "kind": "Chain",
+      "source": "compile_test.dart",
+      "path": "./",
+      "status": "compile.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+        "/test/.*_test\\.dart$",
+        "/test/.*_suite\\.dart$",
+        "/test/fasta/top_level_accessors_part\\.dart$"
+      ]
+    },
+
+    {
+      "name": "kompile",
+      "kind": "Chain",
+      "source": "kompile_test.dart",
+      "path": "./",
+      "status": "kompile.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+        "/test/.*_test\\.dart$",
+        "/test/.*_suite\\.dart$",
+        "/test/fasta/top_level_accessors_part\\.dart$"
+      ]
+    },
+
+    {
+      "name": "language",
+      "kind": "Chain",
+      "source": "sdk_test.dart",
+      "path": "../../../../tests/language/",
+      "status": "language.status",
+      "process-multitests": true,
+      "pattern": [
+        "_test\\.dart$"
+      ],
+      "": "deep_nesting{1,2}_negative_test are ignored because they cause a",
+      "": "crash that we're ignoring for now (it was fixed in Rasta).",
+      "": "The other tests are excluded because they try to use 'none' as ",
+      "": "subtest name in multi test.",
+      "": "Tracked by: https://github.com/dart-lang/sdk/issues/28436",
+      "exclude": [
+        "/sdk/tests/language/deep_nesting1_negative_test\\.dart$",
+        "/sdk/tests/language/deep_nesting2_negative_test\\.dart$",
+        "/sdk/tests/language/async_switch_test\\.dart$",
+        "/sdk/tests/language/arg_param_trailing_comma_test\\.dart$",
+        "/sdk/tests/language/assert_initializer_test\\.dart$",
+        "/sdk/tests/language/deferred_type_dependency_test\\.dart$",
+        "/sdk/tests/language/mixin_of_mixin_test\\.dart$",
+        "/sdk/tests/language/regress_23996_test\\.dart$",
+        "/sdk/tests/language/round_test\\.dart$"
+      ]
+    },
+
+    {
+      "name": "dart2js",
+      "kind": "test_dart",
+      "arch": "x64",
+      "mode": "release",
+      "common": "--dart2js-batch --time -pcolor --report --failure-summary -ax64 -mrelease",
+      "command-lines": [
+        "--checked dart2js",
+        "-cdart2js -rd8 --exclude-suite=observatory_ui",
+        "-cdart2js -rd8 dart2js_extra dart2js_native"
+      ]
+    }
+  ],
+
+  "analyze": {
+
+    "uris": [
+      "../../lib/src/fasta",
+      "../../lib/src/fasta/analyzer",
+      "../../lib/src/fasta/bin",
+      "../../lib/src/fasta/builder",
+      "../../lib/src/fasta/dill",
+      "../../lib/src/fasta/kernel",
+      "../../lib/src/fasta/parser",
+      "../../lib/src/fasta/parser/bin",
+      "../../lib/src/fasta/scanner",
+      "../../lib/src/fasta/scanner/bin",
+      "../../lib/src/fasta/scanner/testing",
+      "../../lib/src/fasta/source",
+      "../../lib/src/fasta/testing",
+      "../../lib/src/fasta/util",
+      "parser/parser_suite.dart",
+      "scanner/scanner_suite.dart",
+      "compile_test.dart",
+      "kompile_test.dart",
+      "outline_test.dart",
+      "sdk_test.dart",
+      "../../../../utils/kernel-service/kernel-service.dart"
+    ],
+
+    "exclude": [
+      "/third_party/pkg/",
+      "/pkg/analyzer/"
+    ]
+  }
+}
diff --git a/pkg/front_end/test/fasta/top_level_accessors.dart b/pkg/front_end/test/fasta/top_level_accessors.dart
new file mode 100644
index 0000000..a0dbc51
--- /dev/null
+++ b/pkg/front_end/test/fasta/top_level_accessors.dart
@@ -0,0 +1,7 @@
+// 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 top_level_accessors;
+
+part 'top_level_accessors_part.dart';
diff --git a/pkg/front_end/test/fasta/top_level_accessors.dart.direct.expect b/pkg/front_end/test/fasta/top_level_accessors.dart.direct.expect
new file mode 100644
index 0000000..d0b45bc0
--- /dev/null
+++ b/pkg/front_end/test/fasta/top_level_accessors.dart.direct.expect
@@ -0,0 +1,13 @@
+library top_level_accessors;
+import self as self;
+import "dart:core" as core;
+
+static get /* from pkg/front_end/test/fasta/top_level_accessors_part.dart */ exitCode() → core::int
+  return 0;
+static set /* from pkg/front_end/test/fasta/top_level_accessors_part.dart */ exitCode(core::int code) → void {
+  core::print(code);
+}
+static method /* from pkg/front_end/test/fasta/top_level_accessors_part.dart */ main() → dynamic {
+  self::exitCode = 42;
+  core::print(self::exitCode);
+}
diff --git a/pkg/front_end/test/fasta/top_level_accessors.dart.outline.expect b/pkg/front_end/test/fasta/top_level_accessors.dart.outline.expect
new file mode 100644
index 0000000..46d9b1e
--- /dev/null
+++ b/pkg/front_end/test/fasta/top_level_accessors.dart.outline.expect
@@ -0,0 +1,10 @@
+library top_level_accessors;
+import self as self;
+import "dart:core" as core;
+
+static get /* from pkg/front_end/test/fasta/top_level_accessors_part.dart */ exitCode() → core::int
+  ;
+static set /* from pkg/front_end/test/fasta/top_level_accessors_part.dart */ exitCode(core::int code) → void
+  ;
+static method /* from pkg/front_end/test/fasta/top_level_accessors_part.dart */ main() → dynamic
+  ;
diff --git a/pkg/front_end/test/fasta/top_level_accessors_part.dart b/pkg/front_end/test/fasta/top_level_accessors_part.dart
new file mode 100644
index 0000000..6aeed08
--- /dev/null
+++ b/pkg/front_end/test/fasta/top_level_accessors_part.dart
@@ -0,0 +1,16 @@
+// 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.
+
+part of top_level_accessors;
+
+void set exitCode(int code) {
+  print(code);
+}
+
+int get exitCode => 0;
+
+main() {
+  exitCode = 42;
+  print(exitCode);
+}
diff --git a/pkg/front_end/test/fasta/typedef.dart b/pkg/front_end/test/fasta/typedef.dart
new file mode 100644
index 0000000..44de722
--- /dev/null
+++ b/pkg/front_end/test/fasta/typedef.dart
@@ -0,0 +1,13 @@
+// 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.
+
+typedef _NullaryFunction();
+typedef _UnaryFunction(args);
+typedef _BinaryFunction(args, message);
+
+main() {
+  print(main is _NullaryFunction);
+  print(main is _UnaryFunction);
+  print(main is _BinaryFunction);
+}
diff --git a/pkg/front_end/test/fasta/typedef.dart.direct.expect b/pkg/front_end/test/fasta/typedef.dart.direct.expect
new file mode 100644
index 0000000..b53d1e4
--- /dev/null
+++ b/pkg/front_end/test/fasta/typedef.dart.direct.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::print(self::main is () → dynamic);
+  core::print(self::main is (dynamic) → dynamic);
+  core::print(self::main is (dynamic, dynamic) → dynamic);
+}
diff --git a/pkg/front_end/test/fasta/typedef.dart.outline.expect b/pkg/front_end/test/fasta/typedef.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/test/fasta/typedef.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/test/incremental_resolved_ast_generator_test.dart b/pkg/front_end/test/incremental_resolved_ast_generator_test.dart
index 553c9f3..40771d8 100644
--- a/pkg/front_end/test/incremental_resolved_ast_generator_test.dart
+++ b/pkg/front_end/test/incremental_resolved_ast_generator_test.dart
@@ -44,7 +44,8 @@
   /// The object under test.
   IncrementalResolvedAstGenerator incrementalResolvedAstGenerator;
 
-  Future<Map<Uri, ResolvedLibrary>> getInitialProgram(Uri startingUri) async {
+  Future<Map<Uri, Map<Uri, CompilationUnit>>> getInitialProgram(
+      Uri startingUri) async {
     fileSystem.entityForUri(sdkSummaryUri).writeAsBytesSync(_sdkSummary);
     incrementalResolvedAstGenerator = new IncrementalResolvedAstGenerator(
         startingUri,
@@ -68,7 +69,7 @@
       _checkPrintLiteralInt(mainStatements[0], expectedArgument);
     }
 
-    _checkMain(initialProgram[fooUri].definingCompilationUnit, 1);
+    _checkMain(initialProgram[fooUri][fooUri], 1);
     writeFiles({'/foo.dart': 'main() { print(2); }'});
     // Verify that the file isn't actually reread until invalidate is called.
     var deltaProgram1 = await incrementalResolvedAstGenerator.computeDelta();
@@ -76,11 +77,11 @@
     // empty map.
     // expect(deltaProgram1.newState, isEmpty);
     expect(deltaProgram1.newState.keys, unorderedEquals([fooUri]));
-    _checkMain(deltaProgram1.newState[fooUri].definingCompilationUnit, 1);
+    _checkMain(deltaProgram1.newState[fooUri][fooUri], 1);
     incrementalResolvedAstGenerator.invalidateAll();
     var deltaProgram2 = await incrementalResolvedAstGenerator.computeDelta();
     expect(deltaProgram2.newState.keys, unorderedEquals([fooUri]));
-    _checkMain(deltaProgram2.newState[fooUri].definingCompilationUnit, 2);
+    _checkMain(deltaProgram2.newState[fooUri][fooUri], 2);
   }
 
   test_invalidateAllBeforeInitialProgram() async {
@@ -102,11 +103,10 @@
     var barUri = Uri.parse('file:///bar.dart');
     var initialProgram = await getInitialProgram(fooUri);
     expect(initialProgram.keys, unorderedEquals([fooUri]));
-    expect(initialProgram[fooUri].partUnits.keys, unorderedEquals([barUri]));
+    expect(initialProgram[fooUri].keys, unorderedEquals([fooUri, barUri]));
     var mainStatements = _getFunctionStatements(
-        _getFunction(initialProgram[fooUri].definingCompilationUnit, 'main'));
-    var fDeclaration =
-        _getFunction(initialProgram[fooUri].partUnits[barUri], 'f');
+        _getFunction(initialProgram[fooUri][fooUri], 'main'));
+    var fDeclaration = _getFunction(initialProgram[fooUri][barUri], 'f');
     var fStatements = _getFunctionStatements(fDeclaration);
     expect(mainStatements, hasLength(2));
     _checkPrintLiteralInt(mainStatements[0], 1);
diff --git a/pkg/front_end/test/scanner_fasta_test.dart b/pkg/front_end/test/scanner_fasta_test.dart
new file mode 100644
index 0000000..5002705
--- /dev/null
+++ b/pkg/front_end/test/scanner_fasta_test.dart
@@ -0,0 +1,384 @@
+// 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:front_end/src/fasta/analyzer/token_utils.dart';
+import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/keyword.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/string_scanner.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/token.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/token_constants.dart' as fasta;
+import 'package:front_end/src/scanner/errors.dart';
+import 'package:front_end/src/scanner/token.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'scanner_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ScannerTest_Fasta);
+    defineReflectiveTests(ScannerTest_Fasta_Direct);
+    defineReflectiveTests(ScannerTest_Fasta_Roundtrip);
+  });
+}
+
+@reflectiveTest
+class ScannerTest_Fasta extends ScannerTestBase {
+  @override
+  Token scanWithListener(String source, ErrorListener listener,
+      {bool genericMethodComments: false,
+      bool lazyAssignmentOperators: false}) {
+    if (genericMethodComments) {
+      // Fasta doesn't support generic method comments.
+      // TODO(paulberry): once the analyzer toolchain no longer needs generic
+      // method comments, remove tests that exercise them.
+      fail('No generic method comment support in Fasta');
+    }
+    // Note: Fasta always supports lazy assignment operators (`&&=` and `||=`),
+    // so we can ignore the `lazyAssignmentOperators` flag.
+    // TODO(paulberry): once lazyAssignmentOperators are fully supported by
+    // Dart, remove this flag.
+    var scanner = new fasta.StringScanner(source, includeComments: true);
+    var token = scanner.tokenize();
+    return toAnalyzerTokenStream(token,
+        (ScannerErrorCode errorCode, int offset, List<Object> arguments) {
+      listener.errors.add(new TestError(offset, errorCode, arguments));
+    });
+  }
+
+  @override
+  @failingTest
+  void test_ampersand_ampersand_eq() {
+    // TODO(paulberry,ahe): Fasta doesn't support `&&=` yet
+    super.test_ampersand_ampersand_eq();
+  }
+
+  @override
+  @failingTest
+  void test_bar_bar_eq() {
+    // TODO(paulberry,ahe): Fasta doesn't support `||=` yet
+    super.test_bar_bar_eq();
+  }
+
+  @override
+  @failingTest
+  void test_comment_generic_method_type_assign() {
+    // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax.
+    super.test_comment_generic_method_type_assign();
+  }
+
+  @override
+  @failingTest
+  void test_comment_generic_method_type_list() {
+    // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax.
+    super.test_comment_generic_method_type_list();
+  }
+
+  @override
+  @failingTest
+  void test_index() {
+    // TODO(paulberry,ahe): "[]" should be parsed as a single token.
+    // See dartbug.com/28665.
+    super.test_index();
+  }
+
+  @override
+  @failingTest
+  void test_index_eq() {
+    // TODO(paulberry,ahe): "[]=" should be parsed as a single token.
+    // See dartbug.com/28665.
+    super.test_index_eq();
+  }
+
+  @override
+  @failingTest
+  void test_mismatched_closer() {
+    // TODO(paulberry,ahe): Fasta and analyzer recover this error differently.
+    // Figure out which recovery technique we want the front end to use.
+    super.test_mismatched_closer();
+  }
+
+  @override
+  @failingTest
+  void test_mismatched_opener() {
+    // TODO(paulberry,ahe): Fasta and analyzer recover this error differently.
+    // Figure out which recovery technique we want the front end to use.
+    super.test_mismatched_opener();
+  }
+
+  @override
+  @failingTest
+  void test_scriptTag_withArgs() {
+    // TODO(paulberry,ahe): script tags are needed by analyzer.
+    super.test_scriptTag_withArgs();
+  }
+
+  @override
+  @failingTest
+  void test_scriptTag_withoutSpace() {
+    // TODO(paulberry,ahe): script tags are needed by analyzer.
+    super.test_scriptTag_withoutSpace();
+  }
+
+  @override
+  @failingTest
+  void test_scriptTag_withSpace() {
+    // TODO(paulberry,ahe): script tags are needed by analyzer.
+    super.test_scriptTag_withSpace();
+  }
+
+  @override
+  @failingTest
+  void test_string_multi_unterminated() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_multi_unterminated();
+  }
+
+  @override
+  @failingTest
+  void test_string_multi_unterminated_interpolation_block() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_multi_unterminated_interpolation_block();
+  }
+
+  @override
+  @failingTest
+  void test_string_multi_unterminated_interpolation_identifier() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_multi_unterminated_interpolation_identifier();
+  }
+
+  @override
+  @failingTest
+  void test_string_raw_multi_unterminated() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_raw_multi_unterminated();
+  }
+
+  @override
+  @failingTest
+  void test_string_raw_simple_unterminated_eof() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_raw_simple_unterminated_eof();
+  }
+
+  @override
+  @failingTest
+  void test_string_raw_simple_unterminated_eol() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_raw_simple_unterminated_eol();
+  }
+
+  @override
+  @failingTest
+  void test_string_simple_unterminated_eof() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_simple_unterminated_eof();
+  }
+
+  @override
+  @failingTest
+  void test_string_simple_unterminated_eol() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_simple_unterminated_eol();
+  }
+
+  @override
+  @failingTest
+  void test_string_simple_unterminated_interpolation_block() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_simple_unterminated_interpolation_block();
+  }
+
+  @override
+  @failingTest
+  void test_string_simple_unterminated_interpolation_identifier() {
+    // TODO(paulberry,ahe): bad error recovery.
+    super.test_string_simple_unterminated_interpolation_identifier();
+  }
+}
+
+/// Base class for scanner tests that examine the token stream in Fasta format.
+abstract class ScannerTest_Fasta_Base {
+  fasta.Token scan(String source);
+
+  void test_match_angle_brackets() {
+    var x = scan('x<y>');
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var greaterThan = y.next;
+    expect(greaterThan.next.isEof, isTrue);
+    expect(lessThan.endGroup, same(greaterThan));
+  }
+
+  void test_match_angle_brackets_gt_gt() {
+    // When a ">>" appears in the token stream, Fasta's scanner matches it to
+    // the outer "<".  The inner "<" is left unmatched.
+    var x = scan('x<y<z>>');
+    var lessThan1 = x.next as fasta.BeginGroupToken;
+    var y = lessThan1.next;
+    var lessThan2 = y.next as fasta.BeginGroupToken;
+    var z = lessThan2.next;
+    var greaterThans = z.next;
+    expect(greaterThans.next.isEof, isTrue);
+    expect(lessThan1.endGroup, same(greaterThans));
+    expect(lessThan2.endGroup, isNull);
+  }
+
+  void test_match_angle_brackets_interrupted_by_close_brace() {
+    // A "}" appearing in the token stream interrupts matching of "<" and ">".
+    var openBrace = scan('{x<y}>z') as fasta.BeginGroupToken;
+    var x = openBrace.next;
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var closeBrace = y.next;
+    var greaterThan = closeBrace.next;
+    var z = greaterThan.next;
+    expect(z.next.isEof, isTrue);
+    expect(openBrace.endGroup, same(closeBrace));
+    expect(lessThan.endGroup, isNull);
+  }
+
+  void test_match_angle_brackets_interrupted_by_close_bracket() {
+    // A "]" appearing in the token stream interrupts matching of "<" and ">".
+    var openBracket = scan('[x<y]>z') as fasta.BeginGroupToken;
+    var x = openBracket.next;
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var closeBracket = y.next;
+    var greaterThan = closeBracket.next;
+    var z = greaterThan.next;
+    expect(z.next.isEof, isTrue);
+    expect(openBracket.endGroup, same(closeBracket));
+    expect(lessThan.endGroup, isNull);
+  }
+
+  void test_match_angle_brackets_interrupted_by_close_paren() {
+    // A ")" appearing in the token stream interrupts matching of "<" and ">".
+    var openParen = scan('(x<y)>z') as fasta.BeginGroupToken;
+    var x = openParen.next;
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var closeParen = y.next;
+    var greaterThan = closeParen.next;
+    var z = greaterThan.next;
+    expect(z.next.isEof, isTrue);
+    expect(openParen.endGroup, same(closeParen));
+    expect(lessThan.endGroup, isNull);
+  }
+
+  void test_match_angle_brackets_interrupted_by_interpolation_expr() {
+    // A "${" appearing in the token stream interrupts matching of "<" and ">".
+    var x = scan(r'x<"${y>z}"');
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var beginString = lessThan.next;
+    var beginInterpolation = beginString.next as fasta.BeginGroupToken;
+    var y = beginInterpolation.next;
+    var greaterThan = y.next;
+    var z = greaterThan.next;
+    var endInterpolation = z.next;
+    var endString = endInterpolation.next;
+    expect(endString.next.isEof, isTrue);
+    expect(lessThan.endGroup, isNull);
+    expect(beginInterpolation.endGroup, same(endInterpolation));
+  }
+
+  void test_match_angle_brackets_interrupted_by_open_brace() {
+    // A "{" appearing in the token stream interrupts matching of "<" and ">".
+    var x = scan('x<{y>z}');
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var openBrace = lessThan.next as fasta.BeginGroupToken;
+    var y = openBrace.next;
+    var greaterThan = y.next;
+    var z = greaterThan.next;
+    var closeBrace = z.next;
+    expect(closeBrace.next.isEof, isTrue);
+    expect(lessThan.endGroup, isNull);
+    expect(openBrace.endGroup, same(closeBrace));
+  }
+
+  void test_match_angle_brackets_interrupted_by_open_bracket() {
+    // A "[" appearing in the token stream interrupts matching of "<" and ">".
+    var x = scan('x<y[z>a]');
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var openBracket = y.next as fasta.BeginGroupToken;
+    var z = openBracket.next;
+    var greaterThan = z.next;
+    var a = greaterThan.next;
+    var closeBracket = a.next;
+    expect(closeBracket.next.isEof, isTrue);
+    expect(lessThan.endGroup, isNull);
+    expect(openBracket.endGroup, same(closeBracket));
+  }
+
+  void test_match_angle_brackets_interrupted_by_open_paren() {
+    // A "(" appearing in the token stream interrupts matching of "<" and ">".
+    var x = scan('x<y(z>a)');
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var openParen = y.next as fasta.BeginGroupToken;
+    var z = openParen.next;
+    var greaterThan = z.next;
+    var a = greaterThan.next;
+    var closeParen = a.next;
+    expect(closeParen.next.isEof, isTrue);
+    expect(lessThan.endGroup, isNull);
+    expect(openParen.endGroup, same(closeParen));
+  }
+
+  void test_match_angle_brackets_nested() {
+    var x = scan('x<y<z>,a>');
+    var lessThan1 = x.next as fasta.BeginGroupToken;
+    var y = lessThan1.next;
+    var lessThan2 = y.next as fasta.BeginGroupToken;
+    var z = lessThan2.next;
+    var greaterThan1 = z.next;
+    var comma = greaterThan1.next;
+    var a = comma.next;
+    var greaterThan2 = a.next;
+    expect(greaterThan2.next.isEof, isTrue);
+    expect(lessThan1.endGroup, same(greaterThan2));
+    expect(lessThan2.endGroup, same(greaterThan1));
+  }
+
+  void test_match_angle_brackets_unmatched_gt_gt() {
+    // When a ">>" appears in the token stream and there is no outer "<",
+    // Fasta's scanner leaves the inner "<" unmatched.
+    var x = scan('x<y>>z');
+    var lessThan = x.next as fasta.BeginGroupToken;
+    var y = lessThan.next;
+    var greaterThans = y.next;
+    var z = greaterThans.next;
+    expect(z.next.isEof, isTrue);
+    expect(lessThan.endGroup, isNull);
+  }
+}
+
+/// Scanner tests that exercise the Fasta scanner directly.
+@reflectiveTest
+class ScannerTest_Fasta_Direct extends ScannerTest_Fasta_Base {
+  @override
+  fasta.Token scan(String source) {
+    var scanner = new fasta.StringScanner(source, includeComments: true);
+    return scanner.tokenize();
+  }
+}
+
+/// Scanner tests that exercise the Fasta scanner, then convert the tokens to
+/// analyzer tokens, then convert back to Fasta tokens before checking
+/// assertions.
+@reflectiveTest
+class ScannerTest_Fasta_Roundtrip extends ScannerTest_Fasta_Base {
+  @override
+  fasta.Token scan(String source) {
+    var scanner = new fasta.StringScanner(source, includeComments: true);
+    var fastaTokenStream = scanner.tokenize();
+    var analyzerTokenStream = toAnalyzerTokenStream(fastaTokenStream,
+        (ScannerErrorCode errorCode, int offset, List<Object> arguments) {
+      fail('Unexpected error: $errorCode, $offset, $arguments');
+    });
+    return fromAnalyzerTokenStream(analyzerTokenStream);
+  }
+}
diff --git a/pkg/front_end/test/scanner_roundtrip_test.dart b/pkg/front_end/test/scanner_roundtrip_test.dart
new file mode 100644
index 0000000..a327451
--- /dev/null
+++ b/pkg/front_end/test/scanner_roundtrip_test.dart
@@ -0,0 +1,96 @@
+// 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:front_end/src/fasta/analyzer/token_utils.dart';
+import 'package:front_end/src/scanner/errors.dart';
+import 'package:front_end/src/scanner/token.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'scanner_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ScannerTest_RoundTrip);
+  });
+}
+
+/// Scanner tests that use the analyzer scanner, then convert the resulting
+/// token stream into a Fasta token stream, then convert back to an analyzer
+/// token stream before verifying assertions.
+///
+/// These tests help to validate the correctness of the analyzer->Fasta token
+/// stream conversion.
+@reflectiveTest
+class ScannerTest_RoundTrip extends ScannerTest {
+  @override
+  Token scanWithListener(String source, ErrorListener listener,
+      {bool genericMethodComments: false,
+      bool lazyAssignmentOperators: false}) {
+    var analyzerToken = super.scanWithListener(source, listener,
+        genericMethodComments: genericMethodComments,
+        lazyAssignmentOperators: lazyAssignmentOperators);
+    var fastaToken = fromAnalyzerTokenStream(analyzerToken);
+    return toAnalyzerTokenStream(fastaToken,
+        (ScannerErrorCode errorCode, int offset, List<Object> arguments) {
+      // Since [scanWithListener] reports errors to the listener, we don't
+      // expect any error tokens in the Fasta token stream; so this callback
+      // should never be called.
+      fail('Unexpected error reported: $errorCode, $offset, $arguments');
+    });
+  }
+
+  @override
+  @failingTest
+  void test_ampersand_ampersand_eq() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support lazy assignment
+    // operators.
+    super.test_ampersand_ampersand_eq();
+  }
+
+  @override
+  @failingTest
+  void test_bar_bar_eq() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support lazy assignment
+    // operators.
+    super.test_bar_bar_eq();
+  }
+
+  @override
+  @failingTest
+  void test_comment_generic_method_type_assign() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support generic comment
+    // syntax.
+    super.test_comment_generic_method_type_assign();
+  }
+
+  @override
+  @failingTest
+  void test_comment_generic_method_type_list() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support generic comment
+    // syntax.
+    super.test_comment_generic_method_type_list();
+  }
+
+  @override
+  @failingTest
+  void test_scriptTag_withArgs() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support script tag
+    super.test_scriptTag_withArgs();
+  }
+
+  @override
+  @failingTest
+  void test_scriptTag_withoutSpace() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support script tag
+    super.test_scriptTag_withoutSpace();
+  }
+
+  @override
+  @failingTest
+  void test_scriptTag_withSpace() {
+    // TODO(paulberry,ahe): Fasta scanner doesn't support script tag
+    super.test_scriptTag_withSpace();
+  }
+}
diff --git a/pkg/front_end/test/scanner_test.dart b/pkg/front_end/test/scanner_test.dart
index 69e802d..fd30f8d 100644
--- a/pkg/front_end/test/scanner_test.dart
+++ b/pkg/front_end/test/scanner_test.dart
@@ -68,6 +68,18 @@
   }
 }
 
+class ErrorListener {
+  final errors = <TestError>[];
+
+  void assertErrors(List<TestError> expectedErrors) {
+    expect(errors, unorderedEquals(expectedErrors));
+  }
+
+  void assertNoErrors() {
+    assertErrors([]);
+  }
+}
+
 @reflectiveTest
 class KeywordStateTest {
   void test_KeywordState() {
@@ -113,17 +125,29 @@
 }
 
 @reflectiveTest
-class ScannerTest {
-  void fail_incomplete_string_interpolation() {
-    // https://code.google.com/p/dart/issues/detail?id=18073
-    _assertErrorAndTokens(
-        ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [
-      new StringToken(TokenType.STRING, "\"foo ", 0),
-      new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5),
-      new StringToken(TokenType.IDENTIFIER, "bar", 7)
-    ]);
+class ScannerTest extends ScannerTestBase {
+  @override
+  Token scanWithListener(String source, ErrorListener listener,
+      {bool genericMethodComments: false,
+      bool lazyAssignmentOperators: false}) {
+    Scanner scanner =
+        new _TestScanner(new CharSequenceReader(source), listener);
+    scanner.scanGenericMethodComments = genericMethodComments;
+    scanner.scanLazyAssignmentOperators = lazyAssignmentOperators;
+    return scanner.tokenize();
   }
 
+  @override
+  @failingTest
+  void test_incomplete_string_interpolation() {
+    super.test_incomplete_string_interpolation();
+  }
+}
+
+abstract class ScannerTestBase {
+  Token scanWithListener(String source, ErrorListener listener,
+      {bool genericMethodComments: false, bool lazyAssignmentOperators: false});
+
   void test_ampersand() {
     _assertToken(TokenType.AMPERSAND, "&");
   }
@@ -141,6 +165,23 @@
     _assertToken(TokenType.AMPERSAND_EQ, "&=");
   }
 
+  void test_angle_brackets_are_ordinary_tokens() {
+    // Analyzer's token streams don't consider "<" to be an opener.
+    var lessThan = _scan('<>');
+    var greaterThan = lessThan.next;
+    expect(greaterThan.next.type, TokenType.EOF);
+    expect(lessThan, isNot(new isInstanceOf<BeginToken>()));
+    expect(greaterThan, isNot(new isInstanceOf<BeginToken>()));
+  }
+
+  void test_async_star() {
+    Token token = _scan("async*");
+    expect(token.type, TokenType.IDENTIFIER);
+    expect(token.lexeme, 'async');
+    expect(token.next.type, TokenType.STAR);
+    expect(token.next.next.type, TokenType.EOF);
+  }
+
   void test_at() {
     _assertToken(TokenType.AT, "@");
   }
@@ -230,6 +271,36 @@
     _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */");
   }
 
+  void test_comment_multi_consecutive_2() {
+    Token token = _scan("/* x */ /* y */ z");
+    expect(token.type, TokenType.IDENTIFIER);
+    expect(token.precedingComments, isNotNull);
+    expect(token.precedingComments.value(), "/* x */");
+    expect(token.precedingComments.previous, isNull);
+    expect(token.precedingComments.next, isNotNull);
+    expect(token.precedingComments.next.value(), "/* y */");
+    expect(
+        token.precedingComments.next.previous, same(token.precedingComments));
+    expect(token.precedingComments.next.next, isNull);
+  }
+
+  void test_comment_multi_consecutive_3() {
+    Token token = _scan("/* x */ /* y */ /* z */ a");
+    expect(token.type, TokenType.IDENTIFIER);
+    expect(token.precedingComments, isNotNull);
+    expect(token.precedingComments.value(), "/* x */");
+    expect(token.precedingComments.previous, isNull);
+    expect(token.precedingComments.next, isNotNull);
+    expect(token.precedingComments.next.value(), "/* y */");
+    expect(
+        token.precedingComments.next.previous, same(token.precedingComments));
+    expect(token.precedingComments.next.next, isNotNull);
+    expect(token.precedingComments.next.next.value(), "/* z */");
+    expect(token.precedingComments.next.next.previous,
+        same(token.precedingComments.next));
+    expect(token.precedingComments.next.next.next, isNull);
+  }
+
   void test_comment_multi_lineEnds() {
     String code = r'''
 /**
@@ -237,7 +308,7 @@
  * bbb
  * c
  */''';
-    _ErrorListener listener = new _ErrorListener();
+    ErrorListener listener = new ErrorListener();
     Scanner scanner = new _TestScanner(new CharSequenceReader(code), listener);
     scanner.tokenize();
     expect(
@@ -304,6 +375,10 @@
     _assertToken(TokenType.EQ_EQ, "==");
   }
 
+  void test_function() {
+    _assertToken(TokenType.FUNCTION, "=>");
+  }
+
   void test_gt() {
     _assertToken(TokenType.GT, ">");
   }
@@ -353,6 +428,16 @@
     _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0312", [0x312]);
   }
 
+  void test_incomplete_string_interpolation() {
+    // https://code.google.com/p/dart/issues/detail?id=18073
+    _assertErrorAndTokens(
+        ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [
+      new StringToken(TokenType.STRING, "\"foo ", 0),
+      new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5),
+      new StringToken(TokenType.IDENTIFIER, "bar", 7)
+    ]);
+  }
+
   void test_index() {
     _assertToken(TokenType.INDEX, "[]");
   }
@@ -381,6 +466,14 @@
     _assertKeywordToken("assert");
   }
 
+  void test_keyword_async() {
+    _assertIdentifierToken("async");
+  }
+
+  void test_keyword_await() {
+    _assertIdentifierToken("await");
+  }
+
   void test_keyword_break() {
     _assertKeywordToken("break");
   }
@@ -461,6 +554,10 @@
     _assertKeywordToken("get");
   }
 
+  void test_keyword_hide() {
+    _assertIdentifierToken("hide");
+  }
+
   void test_keyword_if() {
     _assertKeywordToken("if");
   }
@@ -485,6 +582,10 @@
     _assertKeywordToken("library");
   }
 
+  void test_keyword_native() {
+    _assertIdentifierToken("native");
+  }
+
   void test_keyword_new() {
     _assertKeywordToken("new");
   }
@@ -493,6 +594,14 @@
     _assertKeywordToken("null");
   }
 
+  void test_keyword_of() {
+    _assertIdentifierToken("of");
+  }
+
+  void test_keyword_on() {
+    _assertIdentifierToken("on");
+  }
+
   void test_keyword_operator() {
     _assertKeywordToken("operator");
   }
@@ -501,6 +610,10 @@
     _assertKeywordToken("part");
   }
 
+  void test_keyword_patch() {
+    _assertIdentifierToken("patch");
+  }
+
   void test_keyword_rethrow() {
     _assertKeywordToken("rethrow");
   }
@@ -513,6 +626,14 @@
     _assertKeywordToken("set");
   }
 
+  void test_keyword_show() {
+    _assertIdentifierToken("show");
+  }
+
+  void test_keyword_source() {
+    _assertIdentifierToken("source");
+  }
+
   void test_keyword_static() {
     _assertKeywordToken("static");
   }
@@ -525,6 +646,10 @@
     _assertKeywordToken("switch");
   }
 
+  void test_keyword_sync() {
+    _assertIdentifierToken("sync");
+  }
+
   void test_keyword_this() {
     _assertKeywordToken("this");
   }
@@ -561,6 +686,10 @@
     _assertKeywordToken("with");
   }
 
+  void test_keyword_yield() {
+    _assertIdentifierToken("yield");
+  }
+
   void test_lt() {
     _assertToken(TokenType.LT, "<");
   }
@@ -577,6 +706,46 @@
     _assertToken(TokenType.LT_LT_EQ, "<<=");
   }
 
+  void test_matching_braces() {
+    var openBrace1 = _scan('{1: {2: 3}}') as BeginToken;
+    var one = openBrace1.next;
+    var colon1 = one.next;
+    var openBrace2 = colon1.next as BeginToken;
+    var two = openBrace2.next;
+    var colon2 = two.next;
+    var three = colon2.next;
+    var closeBrace1 = three.next;
+    var closeBrace2 = closeBrace1.next;
+    expect(closeBrace2.next.type, TokenType.EOF);
+    expect(openBrace1.endToken, same(closeBrace2));
+    expect(openBrace2.endToken, same(closeBrace1));
+  }
+
+  void test_matching_brackets() {
+    var openBracket1 = _scan('[1, [2]]') as BeginToken;
+    var one = openBracket1.next;
+    var comma = one.next;
+    var openBracket2 = comma.next as BeginToken;
+    var two = openBracket2.next;
+    var closeBracket1 = two.next;
+    var closeBracket2 = closeBracket1.next;
+    expect(closeBracket2.next.type, TokenType.EOF);
+    expect(openBracket1.endToken, same(closeBracket2));
+    expect(openBracket2.endToken, same(closeBracket1));
+  }
+
+  void test_matching_parens() {
+    var openParen1 = _scan('(f(x))') as BeginToken;
+    var f = openParen1.next;
+    var openParen2 = f.next as BeginToken;
+    var x = openParen2.next;
+    var closeParen1 = x.next;
+    var closeParen2 = closeParen1.next;
+    expect(closeParen2.next.type, TokenType.EOF);
+    expect(openParen1.endToken, same(closeParen2));
+    expect(openParen2.endToken, same(closeParen1));
+  }
+
   void test_minus() {
     _assertToken(TokenType.MINUS, "-");
   }
@@ -589,6 +758,49 @@
     _assertToken(TokenType.MINUS_MINUS, "--");
   }
 
+  void test_mismatched_closer() {
+    // When openers and closers are mismatched, analyzer favors considering the
+    // closer to be mismatched, which means that `(])` parses as a pair of
+    // matched parentheses with an unmatched closing bracket between them.
+    var openParen = _scan('(])') as BeginToken;
+    var closeBracket = openParen.next;
+    var closeParen = closeBracket.next;
+    expect(closeParen.next.type, TokenType.EOF);
+    expect(openParen.endToken, same(closeParen));
+  }
+
+  void test_mismatched_opener() {
+    // When openers and closers are mismatched, analyzer favors considering the
+    // closer to be mismatched, which means that `([)` parses as three unmatched
+    // tokens.
+    var openParen = _scan('([)') as BeginToken;
+    var openBracket = openParen.next as BeginToken;
+    var closeParen = openBracket.next;
+    expect(closeParen.next.type, TokenType.EOF);
+    expect(openParen.endToken, isNull);
+    expect(openBracket.endToken, isNull);
+  }
+
+  void test_mismatched_opener_in_interpolation() {
+    // In an interpolation expression, analyzer considers a closing `}` to
+    // always matche the preceding unmatched `{`, even if there are intervening
+    // unmatched tokens, which means that `"${({(}}"` parses as though the open
+    // parens are unmatched but everything else is matched.
+    var stringStart = _scan(r'"${({(}}"');
+    var interpolationStart = stringStart.next as BeginToken;
+    var openParen1 = interpolationStart.next as BeginToken;
+    var openBrace = openParen1.next as BeginToken;
+    var openParen2 = openBrace.next as BeginToken;
+    var closeBrace = openParen2.next;
+    var interpolationEnd = closeBrace.next;
+    var stringEnd = interpolationEnd.next;
+    expect(stringEnd.next.type, TokenType.EOF);
+    expect(interpolationStart.endToken, same(interpolationEnd));
+    expect(openParen1.endToken, isNull);
+    expect(openBrace.endToken, same(closeBrace));
+    expect(openParen2.endToken, isNull);
+  }
+
   void test_open_curly_bracket() {
     _assertToken(TokenType.OPEN_CURLY_BRACKET, "{");
   }
@@ -691,7 +903,7 @@
 
   void test_setSourceStart() {
     int offsetDelta = 42;
-    _ErrorListener listener = new _ErrorListener();
+    ErrorListener listener = new ErrorListener();
     Scanner scanner =
         new _TestScanner(new SubSequenceReader("a", offsetDelta), listener);
     scanner.setSourceStart(3, 9);
@@ -949,6 +1161,14 @@
     ]);
   }
 
+  void test_sync_star() {
+    Token token = _scan("sync*");
+    expect(token.type, TokenType.IDENTIFIER);
+    expect(token.lexeme, 'sync');
+    expect(token.next.type, TokenType.STAR);
+    expect(token.next.next.type, TokenType.EOF);
+  }
+
   void test_tilde() {
     _assertToken(TokenType.TILDE, "~");
   }
@@ -962,8 +1182,18 @@
   }
 
   void test_unclosedPairInInterpolation() {
-    _ErrorListener listener = new _ErrorListener();
-    _scanWithListener("'\${(}'", listener);
+    ErrorListener listener = new ErrorListener();
+    scanWithListener("'\${(}'", listener);
+  }
+
+  void test_unmatched_openers() {
+    var openBrace = _scan('{[(') as BeginToken;
+    var openBracket = openBrace.next as BeginToken;
+    var openParen = openBracket.next as BeginToken;
+    expect(openParen.next.type, TokenType.EOF);
+    expect(openBrace.endToken, isNull);
+    expect(openBracket.endToken, isNull);
+    expect(openParen.endToken, isNull);
   }
 
   void _assertComment(TokenType commentType, String source,
@@ -1005,10 +1235,10 @@
   void _assertError(
       ScannerErrorCode expectedError, int expectedOffset, String source,
       [List<Object> arguments]) {
-    _ErrorListener listener = new _ErrorListener();
-    _scanWithListener(source, listener);
+    ErrorListener listener = new ErrorListener();
+    scanWithListener(source, listener);
     listener.assertErrors(
-        [new _TestError(expectedOffset, 1, expectedError, arguments)]);
+        [new TestError(expectedOffset, expectedError, arguments)]);
   }
 
   /**
@@ -1022,14 +1252,33 @@
    */
   void _assertErrorAndTokens(ScannerErrorCode expectedError, int expectedOffset,
       String source, List<Token> expectedTokens) {
-    _ErrorListener listener = new _ErrorListener();
-    Token token = _scanWithListener(source, listener);
-    listener
-        .assertErrors([new _TestError(expectedOffset, 1, expectedError, null)]);
+    ErrorListener listener = new ErrorListener();
+    Token token = scanWithListener(source, listener);
+    listener.assertErrors([new TestError(expectedOffset, expectedError, null)]);
     _checkTokens(token, expectedTokens);
   }
 
   /**
+   * Assert that when scanned the given [source] contains a single identifier
+   * token with the same lexeme as the original source.
+   */
+  void _assertIdentifierToken(String source) {
+    void check(String s, int expectedOffset) {
+      Token token = _scan(s);
+      expect(token, isNotNull);
+      expect(token.type, TokenType.IDENTIFIER);
+      expect(token.offset, expectedOffset);
+      expect(token.length, source.length);
+      expect(token.lexeme, source);
+      expect(token.value(), source);
+      expect(token.next.type, TokenType.EOF);
+    }
+
+    check(source, 0);
+    check(' $source ', 1);
+  }
+
+  /**
    * Assert that when scanned the given [source] contains a single keyword token
    * with the same lexeme as the original source.
    */
@@ -1140,22 +1389,53 @@
   Token _scan(String source,
       {bool genericMethodComments: false,
       bool lazyAssignmentOperators: false}) {
-    _ErrorListener listener = new _ErrorListener();
-    Token token = _scanWithListener(source, listener,
+    ErrorListener listener = new ErrorListener();
+    Token token = scanWithListener(source, listener,
         genericMethodComments: genericMethodComments,
         lazyAssignmentOperators: lazyAssignmentOperators);
     listener.assertNoErrors();
     return token;
   }
+}
 
-  Token _scanWithListener(String source, _ErrorListener listener,
-      {bool genericMethodComments: false,
-      bool lazyAssignmentOperators: false}) {
-    Scanner scanner =
-        new _TestScanner(new CharSequenceReader(source), listener);
-    scanner.scanGenericMethodComments = genericMethodComments;
-    scanner.scanLazyAssignmentOperators = lazyAssignmentOperators;
-    return scanner.tokenize();
+class TestError {
+  final int offset;
+  final ErrorCode errorCode;
+  final List<Object> arguments;
+
+  TestError(this.offset, this.errorCode, this.arguments);
+
+  @override
+  get hashCode {
+    var h = new JenkinsSmiHash()..add(offset)..add(errorCode);
+    if (arguments != null) {
+      for (Object argument in arguments) {
+        h.add(argument);
+      }
+    }
+    return h.hashCode;
+  }
+
+  @override
+  operator ==(Object other) {
+    if (other is TestError &&
+        offset == other.offset &&
+        errorCode == other.errorCode) {
+      if (arguments == null) return other.arguments == null;
+      if (other.arguments == null) return false;
+      if (arguments.length != other.arguments.length) return false;
+      for (int i = 0; i < arguments.length; i++) {
+        if (arguments[i] != other.arguments[i]) return false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  toString() {
+    var argString = arguments == null ? '' : '(${arguments.join(', ')})';
+    return 'Error($offset, $errorCode$argString)';
   }
 }
 
@@ -1180,7 +1460,6 @@
     expect(TokenType.GT_GT_EQ.isOperator, isTrue);
     expect(TokenType.INDEX.isOperator, isTrue);
     expect(TokenType.INDEX_EQ.isOperator, isTrue);
-    expect(TokenType.IS.isOperator, isTrue);
     expect(TokenType.LT.isOperator, isTrue);
     expect(TokenType.LT_EQ.isOperator, isTrue);
     expect(TokenType.LT_LT.isOperator, isTrue);
@@ -1227,64 +1506,8 @@
   }
 }
 
-class _ErrorListener {
-  final errors = <_TestError>[];
-
-  void assertErrors(List<_TestError> expectedErrors) {
-    expect(errors, unorderedEquals(expectedErrors));
-  }
-
-  void assertNoErrors() {
-    assertErrors([]);
-  }
-}
-
-class _TestError {
-  final int offset;
-  final int length;
-  final ErrorCode errorCode;
-  final List<Object> arguments;
-
-  _TestError(this.offset, this.length, this.errorCode, this.arguments);
-
-  @override
-  get hashCode {
-    var h = new JenkinsSmiHash()..add(offset)..add(length)..add(errorCode);
-    if (arguments != null) {
-      for (Object argument in arguments) {
-        h.add(argument);
-      }
-    }
-    return h.hashCode;
-  }
-
-  @override
-  operator ==(Object other) {
-    if (other is _TestError &&
-        offset == other.offset &&
-        length == other.length &&
-        errorCode == other.errorCode) {
-      if (arguments == null) return other.arguments == null;
-      if (other.arguments == null) return false;
-      if (arguments.length != other.arguments.length) return false;
-      for (int i = 0; i < arguments.length; i++) {
-        if (arguments[i] != other.arguments[i]) return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  toString() {
-    var end = offset + length;
-    var argString = arguments == null ? '' : '(${arguments.join(', ')})';
-    return 'Error($offset..$end, $errorCode$argString)';
-  }
-}
-
 class _TestScanner extends Scanner {
-  final _ErrorListener listener;
+  final ErrorListener listener;
 
   _TestScanner(CharacterReader reader, [this.listener]) : super(reader);
 
@@ -1292,7 +1515,7 @@
   void reportError(
       ScannerErrorCode errorCode, int offset, List<Object> arguments) {
     if (listener != null) {
-      listener.errors.add(new _TestError(offset, 1, errorCode, arguments));
+      listener.errors.add(new TestError(offset, errorCode, arguments));
     }
   }
 }
diff --git a/pkg/front_end/test/subpackage_relationships_test.dart b/pkg/front_end/test/subpackage_relationships_test.dart
index 9df8ff4..05f3e5a 100644
--- a/pkg/front_end/test/subpackage_relationships_test.dart
+++ b/pkg/front_end/test/subpackage_relationships_test.dart
@@ -16,10 +16,8 @@
 /// Map from subpackage name to the rules for what the subpackage is allowed to
 /// depend directly on.
 ///
-/// Each subdirectory of `lib/src` is considered a subpackage.  Files in
-/// `lib/src` but not in a subdirectory are considered to be in the `lib/src`
-/// subpackage.  Files outside of `lib/src` (but still in `lib`) are considered
-/// to be in the `lib` subpackage.
+/// Each listed directory is considered a subpackage.  Each package contains all
+/// of its descendant files that are not in a more deeply nested subpackage.
 ///
 /// TODO(paulberry): stuff in lib/src shouldn't depend on lib; lib should just
 /// re-export stuff in lib/src.
@@ -33,7 +31,81 @@
       allowedDependencies: ['lib', 'lib/src/base', 'lib/src/scanner']),
   'lib/src/base': new SubpackageRules(
       mayImportAnalyzer: true, allowedDependencies: ['lib']),
-  'lib/src/scanner': new SubpackageRules(allowedDependencies: ['lib/src/base']),
+  'lib/src/fasta':
+      new SubpackageRules(mayImportAnalyzer: true, allowedDependencies: [
+    'lib/src/fasta/builder',
+    'lib/src/fasta/dill',
+    'lib/src/fasta/kernel',
+    'lib/src/fasta/parser',
+    'lib/src/fasta/scanner',
+    'lib/src/fasta/testing',
+    'lib/src/fasta/util',
+  ]),
+  'lib/src/fasta/analyzer':
+      new SubpackageRules(mayImportAnalyzer: true, allowedDependencies: [
+    'lib/src/scanner',
+    'lib/src/fasta',
+    'lib/src/fasta/builder',
+    'lib/src/fasta/dill',
+    'lib/src/fasta/kernel',
+    'lib/src/fasta/parser',
+    'lib/src/fasta/scanner',
+    'lib/src/fasta/source',
+  ]),
+  'lib/src/fasta/bin': new SubpackageRules(allowedDependencies: [
+    'lib/src/fasta',
+  ]),
+  'lib/src/fasta/builder': new SubpackageRules(allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/dill',
+    'lib/src/fasta/parser',
+    'lib/src/fasta/source',
+  ]),
+  'lib/src/fasta/dill': new SubpackageRules(allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/kernel',
+  ]),
+  'lib/src/fasta/kernel': new SubpackageRules(allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/builder',
+    'lib/src/fasta/dill',
+    'lib/src/fasta/parser',
+    'lib/src/fasta/scanner',
+    'lib/src/fasta/source',
+    'lib/src/fasta/util',
+  ]),
+  'lib/src/fasta/parser':
+      new SubpackageRules(allowSubdirs: true, allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/scanner',
+    'lib/src/fasta/util',
+  ]),
+  'lib/src/fasta/scanner':
+      new SubpackageRules(allowSubdirs: true, allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/parser',
+    'lib/src/fasta/util',
+  ]),
+  'lib/src/fasta/source': new SubpackageRules(allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/analyzer',
+    'lib/src/fasta/builder',
+    'lib/src/fasta/dill',
+    'lib/src/fasta/kernel',
+    'lib/src/fasta/parser',
+    'lib/src/fasta/scanner',
+    'lib/src/fasta/util',
+  ]),
+  'lib/src/fasta/testing':
+      new SubpackageRules(mayImportAnalyzer: true, allowedDependencies: [
+    'lib/src/fasta',
+    'lib/src/fasta/dill',
+    'lib/src/fasta/kernel',
+  ]),
+  'lib/src/fasta/util': new SubpackageRules(),
+  'lib/src/scanner': new SubpackageRules(allowedDependencies: [
+    'lib/src/base',
+  ]),
 };
 
 /// Rules for what a subpackage may depend directly on.
@@ -41,12 +113,21 @@
   /// Indicates whether the subpackage may directly depend on analyzer.
   final bool mayImportAnalyzer;
 
+  /// Indicates whether dart files may exist in subdirectories of this
+  /// subpackage.
+  ///
+  /// If `false`, any subdirectory of this subpackage must be a separate
+  /// subpackage.
+  final bool allowSubdirs;
+
   /// Indicates which other subpackages a given subpackage may directly depend
   /// on.
   final List<String> allowedDependencies;
 
   SubpackageRules(
-      {this.mayImportAnalyzer: false, this.allowedDependencies: const []});
+      {this.mayImportAnalyzer: false,
+      this.allowSubdirs: false,
+      this.allowedDependencies: const []});
 }
 
 class _SubpackageRelationshipsTest {
@@ -134,8 +215,26 @@
   String subpackageForUri(Uri src) {
     if (src.scheme != 'package') return null;
     if (src.pathSegments[0] != 'front_end') return null;
-    if (src.pathSegments[1] != 'src') return 'lib';
-    if (src.pathSegments.length == 3) return 'lib/src';
-    return 'lib/src/${src.pathSegments[2]}';
+    var pathWithLib = 'lib/${src.pathSegments.skip(1).join('/')}';
+    String subpackage;
+    String pathWithinSubpackage;
+    for (var subpackagePath in subpackageRules.keys) {
+      var subpackagePathWithSlash = '$subpackagePath/';
+      if (pathWithLib.startsWith(subpackagePathWithSlash) &&
+          (subpackage == null || subpackage.length < subpackagePath.length)) {
+        subpackage = subpackagePath;
+        pathWithinSubpackage =
+            pathWithLib.substring(subpackagePathWithSlash.length);
+      }
+    }
+    if (subpackage == null) {
+      problem('Uri $src is inside package:front_end but is not in any known '
+          'subpackage');
+    } else if (!subpackageRules[subpackage].allowSubdirs &&
+        pathWithinSubpackage.contains('/')) {
+      problem('Uri $src is in a subfolder of $subpackage, but that '
+          'subpackage does not allow dart files in subdirectories.');
+    }
+    return subpackage;
   }
 }
diff --git a/pkg/front_end/tool/perf.dart b/pkg/front_end/tool/perf.dart
index 7c4e4cd..47dfea6 100644
--- a/pkg/front_end/tool/perf.dart
+++ b/pkg/front_end/tool/perf.dart
@@ -6,7 +6,7 @@
 library front_end.tool.perf;
 
 import 'dart:async';
-import 'dart:io' show exit;
+import 'dart:io' show Directory, File, Platform, exit;
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/error/listener.dart';
@@ -30,6 +30,7 @@
 import 'package:front_end/src/scanner/token.dart';
 import 'package:kernel/kernel.dart' hide Source;
 import 'package:package_config/discovery.dart';
+import 'package:path/path.dart' as path;
 
 main(List<String> args) async {
   // TODO(sigmund): provide sdk folder as well.
@@ -92,6 +93,16 @@
 /// Factory to load and resolve app, packages, and sdk sources.
 SourceFactory sources;
 
+/// File URI of the root of the SDK source tree.
+final _repoUri = Platform.script.resolve('../../../');
+
+/// Path to the root of the built SDK that is being used to execute this script.
+final _sdkPath = _findSdkPath();
+
+/// File URI to the root of the built SDK that is being used to execute this
+/// script.
+final _sdkUri = new Uri.directory(_sdkPath);
+
 /// Add to [files] all sources reachable from [start].
 void collectSources(Source start, Set<Source> files) {
   if (!files.add(start)) return;
@@ -115,16 +126,12 @@
   var options = new CompilerOptions()
     ..strongMode = false
     ..compileSdk = compileSdk
-    ..packagesFileUri = new Uri.file('.packages')
+    ..packagesFileUri = _repoUri.resolve('.packages')
     ..onError = ((e) => print('${e.message}'));
   if (useSdkSummary) {
-    // TODO(sigmund): adjust path based on the benchmark runner architecture.
-    // Possibly let the runner make the file available at an architecture
-    // independent location.
-    options.sdkSummary =
-        new Uri.file('out/ReleaseX64/dart-sdk/lib/_internal/spec.sum');
+    options.sdkSummary = _sdkUri.resolve('lib/_internal/spec.sum');
   } else {
-    options.sdkRoot = new Uri.file('sdk');
+    options.sdkRoot = _sdkUri;
   }
   Program program = await kernelForProgram(entryUri, options);
   dartkTimer.stop();
@@ -299,7 +306,7 @@
     new ResourceUriResolver(provider),
     new PackageMapUriResolver(provider, packageMap),
     new DartUriResolver(
-        new FolderBasedDartSdk(provider, provider.getFolder('sdk'))),
+        new FolderBasedDartSdk(provider, provider.getFolder(_sdkPath))),
   ]);
 }
 
@@ -322,6 +329,22 @@
   return unlinkedUnit;
 }
 
+String _findSdkPath() {
+  var executable = Platform.resolvedExecutable;
+  var executableDir = path.dirname(executable);
+  for (var candidate in [
+    path.dirname(executableDir),
+    path.join(executableDir, 'dart-sdk')
+  ]) {
+    if (new File(path.join(candidate, 'lib', 'dart_server.platform'))
+        .existsSync()) {
+      return candidate;
+    }
+  }
+  // Not found; guess "sdk" relative to the current directory.
+  return new Directory('sdk').absolute.path;
+}
+
 /// Simple container for a mapping from URI string to an unlinked summary.
 class _UnlinkedSummaries {
   final summariesByUri = <String, UnlinkedUnit>{};
diff --git a/pkg/front_end/tool/perf_test.dart b/pkg/front_end/tool/perf_test.dart
index 66093ed..2d265fd 100644
--- a/pkg/front_end/tool/perf_test.dart
+++ b/pkg/front_end/tool/perf_test.dart
@@ -6,6 +6,19 @@
 /// the code here just has a dummy import to the rest of the code.
 library front_end.tool.perf_test;
 
+import 'dart:io' show Platform;
 import 'perf.dart' as m;
 
-main() => print('done ${m.inputSize}');
+main() async {
+  var benchIds = [
+    'scan',
+    'parse',
+    'kernel_gen_e2e',
+    'kernel_gen_e2e_sum',
+    'linked_summarize'
+  ];
+  var inputFile = Platform.script.resolve('../lib/file_system.dart').path;
+  for (var id in benchIds) {
+    await m.main([id, inputFile]);
+  }
+}
diff --git a/pkg/kernel/bin/dartk.dart b/pkg/kernel/bin/dartk.dart
index b8666a4..84fbf77 100755
--- a/pkg/kernel/bin/dartk.dart
+++ b/pkg/kernel/bin/dartk.dart
@@ -7,6 +7,7 @@
 import 'dart:io';
 
 import 'batch_util.dart';
+import 'util.dart';
 
 import 'package:args/args.dart';
 import 'package:kernel/analyzer/loader.dart';
@@ -15,6 +16,7 @@
 import 'package:kernel/kernel.dart';
 import 'package:kernel/log.dart';
 import 'package:kernel/target/targets.dart';
+import 'package:kernel/transformations/treeshaker.dart';
 import 'package:path/path.dart' as path;
 
 // Returns the path to the current sdk based on `Platform.resolvedExecutable`.
@@ -56,6 +58,10 @@
   ..addOption('url-mapping',
       allowMultiple: true,
       help: 'A custom url mapping of the form `<scheme>:<name>::<uri>`.')
+  ..addOption('embedder-entry-points-manifest',
+      allowMultiple: true,
+      help: 'A path to a file describing entrypoints '
+          '(lines of the form `<library>,<class>,<member>`).')
   ..addFlag('verbose',
       abbr: 'v',
       negatable: false,
@@ -77,7 +83,9 @@
       help: 'When printing a library as text, also print its dependencies\n'
           'on external libraries.')
   ..addFlag('show-offsets',
-      help: 'When printing a library as text, also print node offsets');
+      help: 'When printing a library as text, also print node offsets')
+  ..addFlag('tree-shake',
+      defaultsTo: false, help: 'Enable tree-shaking if the target supports it');
 
 String getUsage() => """
 Usage: dartk [options] FILE
@@ -280,6 +288,12 @@
 
   List<String> urlMapping = options['url-mapping'] as List<String>;
   var customUriMappings = parseCustomUriMappings(urlMapping);
+
+  List<String> embedderEntryPointManifests =
+      options['embedder-entry-points-manifest'] as List<String>;
+  List<ProgramRoot> programRoots =
+      parseProgramRoots(embedderEntryPointManifests);
+
   var repository = new Repository();
 
   Program program;
@@ -288,7 +302,10 @@
   List<String> loadedFiles;
   Function getLoadedFiles;
   List errors = const [];
-  TargetFlags targetFlags = new TargetFlags(strongMode: options['strong']);
+  TargetFlags targetFlags = new TargetFlags(
+      strongMode: options['strong'],
+      treeShake: options['tree-shake'],
+      programRoots: programRoots);
   Target target = getTarget(options['target'], targetFlags);
 
   var declaredVariables = <String, String>{};
@@ -323,6 +340,7 @@
       program = loader.loadProgram(fileUri, target: target);
     } else {
       var library = loader.loadLibrary(fileUri);
+      loader.loadSdkInterface(program, target);
       assert(library ==
           repository.getLibraryReference(applicationRoot.relativeUri(fileUri)));
       program = new Program(repository.libraries);
@@ -362,9 +380,13 @@
   }
 
   // Apply target-specific transformations.
-  if (target != null && options['link'] && canContinueCompilation) {
-    target.transformProgram(program);
+  if (target != null && canContinueCompilation) {
+    target.performModularTransformations(program);
     runVerifier();
+    if (options['link']) {
+      target.performGlobalTransformations(program);
+      runVerifier();
+    }
   }
 
   if (options['no-output']) {
@@ -400,5 +422,9 @@
     print('writer.flush_time = $flushTime ms');
   }
 
+  if (options['tolerant']) {
+    return CompilerOutcome.Ok;
+  }
+
   return errors.length > 0 ? CompilerOutcome.Fail : CompilerOutcome.Ok;
 }
diff --git a/pkg/kernel/bin/transform.dart b/pkg/kernel/bin/transform.dart
index 37f1838..5e73214 100755
--- a/pkg/kernel/bin/transform.dart
+++ b/pkg/kernel/bin/transform.dart
@@ -15,6 +15,7 @@
 import 'package:kernel/transformations/closure_conversion.dart' as closures;
 import 'package:kernel/transformations/treeshaker.dart' as treeshaker;
 
+import 'util.dart';
 import 'batch_util.dart';
 
 ArgParser parser = new ArgParser()
@@ -29,6 +30,10 @@
       negatable: false,
       help: 'Be verbose (e.g. prints transformed main library).',
       defaultsTo: false)
+  ..addOption('embedder-entry-points-manifest',
+      allowMultiple: true,
+      help: 'A path to a file describing entrypoints '
+          '(lines of the form `<library>,<class>,<member>`).')
   ..addOption('transformation',
       abbr: 't',
       help: 'The transformation to apply.',
@@ -62,6 +67,11 @@
     output = '${input.substring(0, input.lastIndexOf('.'))}.transformed.dill';
   }
 
+  List<String> embedderEntryPointManifests =
+      options['embedder-entry-points-manifest'] as List<String>;
+  List<treeshaker.ProgramRoot> programRoots =
+      parseProgramRoots(embedderEntryPointManifests);
+
   var program = loadProgramFromBinary(input);
   switch (options['transformation']) {
     case 'continuation':
@@ -77,7 +87,8 @@
       program = closures.transformProgram(program);
       break;
     case 'treeshake':
-      program = treeshaker.transformProgram(program);
+      program =
+          treeshaker.transformProgram(program, programRoots: programRoots);
       break;
     default:
       throw 'Unknown transformation';
diff --git a/pkg/kernel/bin/util.dart b/pkg/kernel/bin/util.dart
new file mode 100644
index 0000000..e46e4f5
--- /dev/null
+++ b/pkg/kernel/bin/util.dart
@@ -0,0 +1,67 @@
+// 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:io';
+
+import 'package:kernel/transformations/treeshaker.dart';
+
+/// Parses all given [embedderEntryPointManifests] and returns the program roots
+/// specified in them.
+///
+/// A embedder manifest consists of lines of the following form:
+///
+///   <import-uri>,<class-name>,<member-name>
+///
+/// Where
+///
+///   <import-uri> : The uri of the library which contains the root.
+///   <class-name> : Is either the name of the class or '::' for the library.
+///   <member-name>: Can be of the forms:
+///
+///     - get:<name>
+///     - set:<name>
+///     - <field-name>
+///     - <procedure-name>
+///     - <constructor-name>
+///     - <klass>.<factory-constructor-name>
+///     - *external-instantiation*
+///
+List<ProgramRoot> parseProgramRoots(List<String> embedderEntryPointManifests) {
+  List<ProgramRoot> roots = <ProgramRoot>[];
+
+  for (var file in embedderEntryPointManifests) {
+    var lines = new File(file).readAsStringSync().trim().split('\n');
+    for (var line in lines) {
+      var parts = line.split(',');
+      assert(parts.length == 3);
+
+      var library = parts[0];
+      var klass = parts[1];
+      var member = parts[2];
+
+      // The vm represents the toplevel class as '::'.
+      if (klass == '::') klass = null;
+
+      ProgramRootKind kind = ProgramRootKind.Other;
+
+      if (member.startsWith('set:')) {
+        kind = ProgramRootKind.Setter;
+        member = member.substring('set:'.length);
+      } else if (member.startsWith('get:')) {
+        kind = ProgramRootKind.Getter;
+        member = member.substring('get:'.length);
+      } else if (member == "*external-instantiation*") {
+        kind = ProgramRootKind.ExternallyInstantiatedClass;
+        member = null;
+      } else if (member.startsWith('$klass.')) {
+        kind = ProgramRootKind.Constructor;
+        member = member.substring('$klass.'.length);
+      }
+
+      roots.add(new ProgramRoot(library, klass, member, kind));
+    }
+  }
+
+  return roots;
+}
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index a287dd6..6059690 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -175,15 +175,28 @@
   StringReference importUri;
   // An absolute path URI to the .dart file from which the library was created.
   UriReference fileUri;
+  List<DeferredImport> deferredImports;
   List<Class> classes;
   List<Field> fields;
   List<Procedure> procedures;
 }
 
+type DeferredImport {
+  LibraryReference importedLibrary;
+  StringReference name;
+}
+
+type DeferredImportReference {
+  // Index into deferredImports in the enclosing Library.
+  UInt index;
+}
+
 abstract type Node {
   Byte tag;
 }
 
+enum ClassLevel { Type = 0, Hierarchy = 1, Mixin = 2, Body = 3, }
+
 // A class can be represented at one of three levels: type, hierarchy, or body.
 //
 // If the enclosing library is external, a class is either at type or
@@ -197,7 +210,7 @@
 type NormalClass extends Class {
   Byte tag = 2;
   FileOffset fileOffset;
-  Byte flags (isAbstract, isTypeLevel);
+  Byte flags (isAbstract, xx); // Where xx is index into ClassLevel
   StringReference name;
   // An absolute path URI to the .dart file from which the class was created.
   UriReference fileUri;
@@ -664,6 +677,16 @@
   Expression body;
 }
 
+type LoadLibrary extends Expression {
+  Byte tag = 14;
+  DeferredImportReference import;
+}
+
+type CheckLibraryIsLoaded extends Expression {
+  Byte tag = 13;
+  DeferredImportReference import;
+}
+
 abstract type Statement extends Node {}
 
 type InvalidStatement extends Statement {
diff --git a/pkg/kernel/lib/analyzer/ast_from_analyzer.dart b/pkg/kernel/lib/analyzer/ast_from_analyzer.dart
index 06e0f5e..45ebe7b 100644
--- a/pkg/kernel/lib/analyzer/ast_from_analyzer.dart
+++ b/pkg/kernel/lib/analyzer/ast_from_analyzer.dart
@@ -2455,12 +2455,13 @@
   /// This is true for redirecting factories with a resolved target. These are
   /// always bypassed at the call site.
   bool _isIgnoredMember(ClassMember node) {
-    return node is ConstructorDeclaration &&
-        node.factoryKeyword != null &&
-        resolutionMap
-                .elementDeclaredByConstructorDeclaration(node)
-                .redirectedConstructor !=
-            null;
+    if (node is ConstructorDeclaration && node.factoryKeyword != null) {
+      var element = resolutionMap.elementDeclaredByConstructorDeclaration(node);
+      return element.redirectedConstructor != null &&
+          (element.isSynthetic || scope.loader.ignoreRedirectingFactories);
+    } else {
+      return false;
+    }
   }
 
   visitClassDeclaration(ClassDeclaration node) {
@@ -2822,21 +2823,65 @@
     procedure.function = function..parent = procedure;
     handleNativeBody(node.body);
     if (node.redirectedConstructor != null) {
-      // Redirecting factories with resolved targets don't show up here.
-      assert(resolutionMap
-              .elementDeclaredByConstructorDeclaration(node)
-              .redirectedConstructor ==
-          null);
-      var function = procedure.function;
-      var name = node.redirectedConstructor.type.name.name;
-      if (node.redirectedConstructor.name != null) {
-        name += '.' + node.redirectedConstructor.name.name;
+      // Add a new synthetic field to [classNode] for representing factory
+      // constructors. This is used by the new frontend engine to support
+      // resolving source code.
+      //
+      // The synthetic field looks like this:
+      //
+      //     final _redirecting# = [c1, ..., cn];
+      //
+      // Where each c1 ... cn are an instance of [StaticGet] whose target is
+      // the redirecting factory created above. The new frontend engine reads
+      // this field and rewrites them.
+      //
+      // TODO(ahe): Generate the correct factory body instead. This requires
+      // access to default values from other files, we'll probably never do
+      // that in this file, and instead rely on the new compiler for this.
+      var element = resolutionMap.elementDeclaredByConstructorDeclaration(node);
+      assert(!element.isSynthetic);
+      var expression;
+      if (node.element.redirectedConstructor != null) {
+        assert(!scope.loader.ignoreRedirectingFactories);
+        ConstructorElement element = node.element.redirectedConstructor;
+        while (element.isFactory && element.redirectedConstructor != null) {
+          element = element.redirectedConstructor;
+        }
+        ast.Member target = scope.getMemberReference(element);
+        assert(target != null);
+        expression = new ast.Let(
+            new ast.VariableDeclaration.forValue(new ast.StaticGet(target)),
+            new ast.InvalidExpression());
+        ast.Name constructors =
+            new ast.Name("_redirecting#", scope.currentLibrary);
+        ast.Field constructorsField;
+        for (ast.Field field in classNode.fields) {
+          if (field.name == constructors) {
+            constructorsField = field;
+            break;
+          }
+        }
+        if (constructorsField == null) {
+          ast.ListLiteral literal = new ast.ListLiteral(<ast.Expression>[]);
+          constructorsField = new ast.Field(constructors, isStatic: true,
+              initializer: literal, fileUri: classNode.fileUri)
+              ..fileOffset = classNode.fileOffset;
+          classNode.addMember(constructorsField);
+        }
+        ast.ListLiteral literal = constructorsField.initializer;
+        literal.expressions.add(new ast.StaticGet(procedure)..parent = literal);
+      } else {
+        var name = node.redirectedConstructor.type.name.name;
+        if (node.redirectedConstructor.name != null) {
+          name += '.' + node.redirectedConstructor.name.name;
+        }
+        // TODO(asgerf): Sometimes a TypeError should be thrown.
+        expression = scope.buildThrowNoSuchMethodError(
+            new ast.NullLiteral(), name, new ast.Arguments.empty());
       }
-      // TODO(asgerf): Sometimes a TypeError should be thrown.
-      function.body = new ast.ExpressionStatement(
-          scope.buildThrowNoSuchMethodError(
-              new ast.NullLiteral(), name, new ast.Arguments.empty()))
-        ..parent = function;
+      var function = procedure.function;
+      function.body = new ast.ExpressionStatement(expression)
+          ..parent = function;
     }
   }
 
diff --git a/pkg/kernel/lib/analyzer/loader.dart b/pkg/kernel/lib/analyzer/loader.dart
index d3743af..d9dbf13 100644
--- a/pkg/kernel/lib/analyzer/loader.dart
+++ b/pkg/kernel/lib/analyzer/loader.dart
@@ -82,6 +82,9 @@
   ast.Class getSharedMixinApplicationClass(
       ast.Library library, ast.Class supertype, ast.Class mixin);
   bool get strongMode;
+
+  /// Whether or not to include redirecting factories in the output.
+  bool get ignoreRedirectingFactories;
 }
 
 class DartLoader implements ReferenceLevelLoader {
@@ -103,12 +106,18 @@
   /// so as not to expose partially initialized classes.
   final List<ast.Class> temporaryClassWorklist = [];
 
+  final Map<LibraryElement, List<ClassElement>> mixinLibraryWorklist = {};
+
+  final bool ignoreRedirectingFactories;
+
   LibraryElement _libraryBeingLoaded = null;
 
   bool get strongMode => context.analysisOptions.strongMode;
 
   DartLoader(this.repository, DartOptions options, Packages packages,
-      {DartSdk dartSdk, AnalysisContext context})
+      {DartSdk dartSdk,
+      AnalysisContext context,
+      this.ignoreRedirectingFactories: true})
       : this.context =
             context ?? createContext(options, packages, dartSdk: dartSdk),
         this.applicationRoot = options.applicationRoot;
@@ -193,7 +202,7 @@
       }
     }
     libraryElements.add(element);
-    _iterateWorklist();
+    _iterateTemporaryClassWorklist();
     // Ensure everything is stored in the original declaration order.
     library.classes
       ..clear()
@@ -382,15 +391,43 @@
     }
   }
 
-  void promoteToBodyLevel(ast.Class classNode, ClassElement element,
+  void promoteToMixinLevel(ast.Class classNode, ClassElement element,
       NamedCompilationUnitMember astNode) {
-    if (classNode.level == ast.ClassLevel.Body) return;
+    if (classNode.level.index >= ast.ClassLevel.Mixin.index) return;
     promoteToHierarchyLevel(classNode);
-    classNode.level = ast.ClassLevel.Body;
+    classNode.level = ast.ClassLevel.Mixin;
     // Clear out the member references that were put in the class.
     // The AST builder will load them all put back in the right order.
     classNode..fields.clear()..procedures.clear()..constructors.clear();
     new ClassBodyBuilder(this, classNode, element).build(astNode);
+
+    // Ensure mixed-in classes are available.
+    for (var mixin in element.mixins) {
+      _ensureMixinBecomesLoaded(mixin.element);
+    }
+  }
+
+  /// Ensures that [element] eventually becomes loaded at least at mixin level.
+  void _ensureMixinBecomesLoaded(ClassElement element) {
+    if (isLibraryBeingLoaded(element.library)) {
+      return;
+    }
+    var class_ = getClassReference(element);
+    if (class_.level.index >= ast.ClassLevel.Mixin.index) {
+      return;
+    }
+    var list = mixinLibraryWorklist[element.library] ??= <ClassElement>[];
+    list.add(element);
+  }
+
+  void promoteToBodyLevel(ast.Class classNode, ClassElement element,
+      NamedCompilationUnitMember astNode) {
+    if (classNode.level == ast.ClassLevel.Body) return;
+    promoteToMixinLevel(classNode, element, astNode);
+    classNode.level = ast.ClassLevel.Body;
+    // This frontend delivers the same contents for classes at body and mixin
+    // levels, even though as specified, the mixin level does not require all
+    // the static members to be present.  So no additional work is needed.
   }
 
   ast.TypeParameter tryGetClassTypeParameter(TypeParameterElement element) {
@@ -611,6 +648,11 @@
   }
 
   void ensureLibraryIsLoaded(ast.Library node) {
+    _ensureLibraryIsLoaded(node);
+    _iterateMixinLibraryWorklist();
+  }
+
+  void _ensureLibraryIsLoaded(ast.Library node) {
     if (!node.isExternal) return;
     node.isExternal = false;
     var source = context.sourceFactory
@@ -643,6 +685,23 @@
     }
   }
 
+  void loadSdkInterface(ast.Program program, Target target) {
+    var requiredSdkMembers = target.requiredSdkClasses;
+    for (var libraryUri in requiredSdkMembers.keys) {
+      var source = context.sourceFactory.forUri2(Uri.parse(libraryUri));
+      var libraryElement = context.computeLibraryElement(source);
+      for (var member in requiredSdkMembers[libraryUri]) {
+        var type = libraryElement.getType(member);
+        if (type == null) {
+          throw 'Could not find $member in $libraryUri';
+        }
+        promoteToTypeLevel(getClassReference(type));
+      }
+    }
+    _iterateTemporaryClassWorklist();
+    _iterateMixinLibraryWorklist();
+  }
+
   void loadEverything({Target target, bool compileSdk}) {
     compileSdk ??= true;
     if (compileSdk) {
@@ -682,13 +741,29 @@
     return list;
   }
 
-  void _iterateWorklist() {
+  void _iterateTemporaryClassWorklist() {
     while (temporaryClassWorklist.isNotEmpty) {
       var element = temporaryClassWorklist.removeLast();
       promoteToTypeLevel(element);
     }
   }
 
+  void _iterateMixinLibraryWorklist() {
+    // The worklist groups classes in the same library together so that we
+    // request resolved ASTs for each library only once.
+    while (mixinLibraryWorklist.isNotEmpty) {
+      LibraryElement library = mixinLibraryWorklist.keys.first;
+      _libraryBeingLoaded = library;
+      List<ClassElement> classes = mixinLibraryWorklist.remove(library);
+      for (var class_ in classes) {
+        var classNode = getClassReference(class_);
+        promoteToMixinLevel(classNode, class_, class_.computeNode());
+      }
+      _libraryBeingLoaded = null;
+    }
+    _iterateTemporaryClassWorklist();
+  }
+
   ast.Procedure _getMainMethod(Uri uri) {
     Source source = context.sourceFactory.forUri2(uri);
     LibraryElement library = context.computeLibraryElement(source);
@@ -708,8 +783,7 @@
         ast.ProcedureKind.Method,
         new ast.FunctionNode(new ast.ExpressionStatement(new ast.Throw(
             new ast.StringLiteral('Program has no main method')))),
-        isStatic: true)
-      ..fileUri = library.fileUri;
+        isStatic: true)..fileUri = library.fileUri;
     library.addMember(main);
     return main;
   }
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index f35e754..2f3cb11 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -179,6 +179,7 @@
   bool isExternal;
 
   String name;
+  final List<DeferredImport> deferredImports;
   final List<Class> classes;
   final List<Procedure> procedures;
   final List<Field> fields;
@@ -186,10 +187,13 @@
   Library(this.importUri,
       {this.name,
       this.isExternal: false,
+      List<DeferredImport> imports,
       List<Class> classes,
       List<Procedure> procedures,
-      List<Field> fields})
-      : this.classes = classes ?? <Class>[],
+      List<Field> fields,
+      this.fileUri})
+      : this.deferredImports = imports ?? <DeferredImport>[],
+        this.classes = classes ?? <Class>[],
         this.procedures = procedures ?? <Procedure>[],
         this.fields = fields ?? <Field>[] {
     setParents(this.classes, this);
@@ -248,6 +252,22 @@
   }
 }
 
+/// An import of form: `import <url> deferred as <name>;`.
+class DeferredImport extends TreeNode {
+  Library importedLibrary;
+  String name;
+
+  DeferredImport(this.importedLibrary, this.name);
+
+  Library get enclosingLibrary => parent;
+
+  accept(TreeVisitor v) => v.visitDeferredImport(this);
+
+  visitChildren(Visitor v) {}
+
+  transformChildren(Transformer v) {}
+}
+
 /// The degree to which the contents of a class have been loaded into memory.
 ///
 /// Each level imply the requirements of the previous ones.
@@ -274,6 +294,18 @@
   /// members needed to detect override constraints.
   Hierarchy,
 
+  /// All instance members of the class have their body loaded, and their
+  /// annotations are present.
+  ///
+  /// All supertypes of this class are at [Hierarchy] level or higher.
+  ///
+  /// If this class is a mixin application, then its mixin is loaded at [Mixin]
+  /// level or higher.
+  ///
+  /// This level exists so the contents of a mixin can be cloned into a
+  /// mixin application.
+  Mixin,
+
   /// All members of the class are fully loaded and are in the correct order.
   ///
   /// Annotations are present on classes and members.
@@ -1517,7 +1549,7 @@
 }
 
 /// Directly call an instance method, bypassing ordinary dispatch.
-class DirectMethodInvocation extends Expression {
+class DirectMethodInvocation extends InvocationExpression {
   Expression receiver;
   Procedure target;
   Arguments arguments;
@@ -1527,6 +1559,8 @@
     arguments?.parent = this;
   }
 
+  Name get name => target?.name;
+
   visitChildren(Visitor v) {
     receiver?.accept(v);
     target?.acceptReference(v);
@@ -1830,7 +1864,7 @@
   Name name;
   Arguments arguments;
 
-  Member interfaceTarget;
+  Procedure interfaceTarget;
 
   SuperMethodInvocation(this.name, this.arguments, this.interfaceTarget) {
     arguments?.parent = this;
@@ -2434,6 +2468,51 @@
   }
 }
 
+/// Attempt to load the library referred to by a deferred import.
+///
+/// This instruction is concerned with:
+/// - keeping track whether the deferred import is marked as 'loaded'
+/// - keeping track of whether the library code has already been downloaded
+/// - actually downloading and linking the library
+///
+/// Should return a future.  The value in this future will be the same value
+/// seen by callers of `loadLibrary` functions.
+///
+/// On backends that link the entire program eagerly, this instruction needs
+/// to mark the deferred import as 'loaded' and return a future.
+class LoadLibrary extends Expression {
+  /// Reference to a deferred import in the enclosing library.
+  DeferredImport import;
+
+  LoadLibrary(this.import);
+
+  DartType getStaticType(TypeEnvironment types) {
+    return types.futureType(const DynamicType());
+  }
+
+  accept(ExpressionVisitor v) => v.visitLoadLibrary(this);
+
+  visitChildren(Visitor v) {}
+  transformChildren(Transformer v) {}
+}
+
+/// Checks that the given deferred import has been marked as 'loaded'.
+class CheckLibraryIsLoaded extends Expression {
+  /// Reference to a deferred import in the enclosing library.
+  DeferredImport import;
+
+  CheckLibraryIsLoaded(this.import);
+
+  DartType getStaticType(TypeEnvironment types) {
+    return types.objectType;
+  }
+
+  accept(ExpressionVisitor v) => v.visitCheckLibraryIsLoaded(this);
+
+  visitChildren(Visitor v) {}
+  transformChildren(Transformer v) {}
+}
+
 // ------------------------------------------------------------------------
 //                              STATEMENTS
 // ------------------------------------------------------------------------
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 8c940f6..100fe98 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -187,8 +187,7 @@
       readLibrary();
     }
     var mainMethod = readMemberReference(allowNull: true);
-    return new Program(importTable, uriToSource)
-      ..mainMethod = mainMethod;
+    return new Program(importTable, uriToSource)..mainMethod = mainMethod;
   }
 
   Map<String, Source> readUriToSource() {
@@ -226,6 +225,11 @@
     return importTable[index];
   }
 
+  DeferredImport readDeferredImportReference() {
+    int index = readUInt();
+    return _currentLibrary.deferredImports[index];
+  }
+
   Class readClassReference({bool allowNull: false}) {
     int tag = readByte();
     if (tag == Tag.NullReference) {
@@ -292,6 +296,7 @@
     // TODO(jensj): We currently save (almost the same) uri twice.
     _currentLibrary.fileUri = readUriReference();
 
+    _readDeferredImports(_currentLibrary);
     _fillLazilyLoadedList(_currentLibrary.classes, (int tag, int index) {
       readClass(loader.getClassReference(_currentLibrary, tag, index), tag);
     });
@@ -306,6 +311,19 @@
     debugPath.removeLast();
   }
 
+  void _readDeferredImports(Library library) {
+    int count = readUInt();
+    library.deferredImports.length = count;
+    for (int i = 0; i < count; ++i) {
+      var importNode = _readDeferredImport();
+      library.deferredImports.add(importNode..parent = library);
+    }
+  }
+
+  DeferredImport _readDeferredImport() {
+    return new DeferredImport(readLibraryReference(), readStringReference());
+  }
+
   void readClass(Class node, int tag) {
     assert(node != null);
     switch (tag) {
@@ -324,9 +342,8 @@
     node.fileOffset = readOffset();
     int flags = readByte();
     node.isAbstract = flags & 0x1 != 0;
-    node.level = _currentLibrary.isExternal
-        ? (flags & 0x2 != 0) ? ClassLevel.Type : ClassLevel.Hierarchy
-        : ClassLevel.Body;
+    int levelIndex = (flags >> 1) & 0x3;
+    node.level = ClassLevel.values[levelIndex + 1];
     node.name = readStringOrNullIfEmpty();
     node.fileUri = readUriReference();
     node.annotations = readAnnotationList(node);
@@ -351,9 +368,8 @@
     node.fileOffset = readOffset();
     int flags = readByte();
     node.isAbstract = flags & 0x1 != 0;
-    node.level = _currentLibrary.isExternal
-        ? (flags & 0x2 != 0) ? ClassLevel.Type : ClassLevel.Hierarchy
-        : ClassLevel.Body;
+    int levelIndex = (flags >> 1) & 0x3;
+    node.level = ClassLevel.values[levelIndex];
     node.name = readStringOrNullIfEmpty();
     node.fileUri = readUriReference();
     node.annotations = readAnnotationList(node);
@@ -530,6 +546,10 @@
         ? tagByte
         : (tagByte & Tag.SpecializedTagMask);
     switch (tag) {
+      case Tag.LoadLibrary:
+        return new LoadLibrary(readDeferredImportReference());
+      case Tag.CheckLibraryIsLoaded:
+        return new CheckLibraryIsLoaded(readDeferredImportReference());
       case Tag.InvalidExpression:
         return new InvalidExpression();
       case Tag.VariableGet:
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 6d3dabd..a137d86 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -24,6 +24,7 @@
   final GlobalIndexer _globalIndexer;
   final StringIndexer _stringIndexer = new StringIndexer();
   final StringIndexer _sourceUriIndexer = new StringIndexer();
+  Map<DeferredImport, int> _deferredImportIndexer = <DeferredImport, int>{};
 
   final BufferedSink _sink;
 
@@ -175,6 +176,14 @@
     writeUInt30(index);
   }
 
+  void writeDeferredImportReference(DeferredImport node) {
+    int index = _deferredImportIndexer[node];
+    if (index == null) {
+      throw 'Reference to deferred import $node out of scope';
+    }
+    writeUInt30(index);
+  }
+
   void writeClassIndex(Class node) {
     writeUInt30(_globalIndexer[node]);
   }
@@ -269,11 +278,29 @@
     writeStringReference('${node.importUri}');
     // TODO(jensj): We save (almost) the same URI twice.
     writeUriReference(node.fileUri ?? '');
+    writeDeferredImports(node);
     writeNodeList(node.classes);
     writeNodeList(node.fields);
     writeNodeList(node.procedures);
   }
 
+  void writeDeferredImports(Library library) {
+    _deferredImportIndexer = library.deferredImports.isEmpty
+        ? const <DeferredImport, int>{}
+        : <DeferredImport, int>{};
+    writeUInt30(library.deferredImports.length);
+    for (int i = 0; i < library.deferredImports.length; ++i) {
+      var importNode = library.deferredImports[i];
+      _deferredImportIndexer[importNode] = i;
+      writeDeferredImport(importNode);
+    }
+  }
+
+  void writeDeferredImport(DeferredImport node) {
+    writeLibraryReference(node.importedLibrary);
+    writeStringReference(node.name);
+  }
+
   void writeAnnotation(Expression annotation) {
     _variableIndexer ??= new VariableIndexer();
     writeNode(annotation);
@@ -283,11 +310,14 @@
     writeList(annotations, writeAnnotation);
   }
 
+  int _encodeClassFlags(bool isAbstract, ClassLevel level) {
+    int abstactFlag = isAbstract ? 1 : 0;
+    int levelFlags = (level.index - 1) << 1;
+    return abstactFlag | levelFlags;
+  }
+
   visitClass(Class node) {
-    int flags = node.isAbstract ? 1 : 0;
-    if (node.level == ClassLevel.Type) {
-      flags |= 0x2;
-    }
+    int flags = _encodeClassFlags(node.isAbstract, node.level);
     if (node.isMixinApplication) {
       writeByte(Tag.MixinClass);
       writeOffset(node, node.fileOffset);
@@ -712,6 +742,16 @@
     --_variableIndexer.stackHeight;
   }
 
+  visitLoadLibrary(LoadLibrary node) {
+    writeByte(Tag.LoadLibrary);
+    writeDeferredImportReference(node.import);
+  }
+
+  visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
+    writeByte(Tag.CheckLibraryIsLoaded);
+    writeDeferredImportReference(node.import);
+  }
+
   writeStatementOrEmpty(Statement node) {
     if (node == null) {
       writeByte(Tag.EmptyStatement);
@@ -1098,6 +1138,10 @@
     node.visitChildren(this);
   }
 
+  visitDeferredImport(DeferredImport node) {
+    put(node.name);
+  }
+
   visitClass(Class node) {
     putOptional(node.name);
     node.visitChildren(this);
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 226b190..336b360 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -20,6 +20,8 @@
   static const int RedirectingInitializer = 10;
   static const int LocalInitializer = 11;
 
+  static const int CheckLibraryIsLoaded = 13;
+  static const int LoadLibrary = 14;
   static const int DirectPropertyGet = 15;
   static const int DirectPropertySet = 16;
   static const int DirectMethodInvocation = 17;
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 3b9a6a2..70b8d10 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -119,11 +119,13 @@
   }
 
   visitStaticInvocation(StaticInvocation node) {
-    return new StaticInvocation(node.target, clone(node.arguments));
+    return new StaticInvocation(node.target, clone(node.arguments),
+        isConst: node.isConst);
   }
 
   visitConstructorInvocation(ConstructorInvocation node) {
-    return new ConstructorInvocation(node.target, clone(node.arguments));
+    return new ConstructorInvocation(node.target, clone(node.arguments),
+        isConst: node.isConst);
   }
 
   visitNot(Not node) {
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 28ce858..72bf93d9 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -27,6 +27,33 @@
   Class functionClass;
   Class invocationClass;
 
+  static final Map<String, List<String>> requiredClasses = {
+    'dart:core': [
+      'Object',
+      'Null',
+      'bool',
+      'int',
+      'num',
+      'double',
+      'String',
+      'List',
+      'Map',
+      'Iterable',
+      'Iterator',
+      'Symbol',
+      'Type',
+      'Function',
+      'Invocation',
+    ],
+    'dart:_internal': [
+      'Symbol',
+    ],
+    'dart:async': [
+      'Future',
+      'Stream',
+    ]
+  };
+
   Library getCoreLibrary(String uri) => _dartLibraries[uri]?.library;
 
   Class getCoreClass(String libraryUri, String className) {
diff --git a/pkg/kernel/lib/frontend/accessors.dart b/pkg/kernel/lib/frontend/accessors.dart
index 48bb2c5..ce098c3 100644
--- a/pkg/kernel/lib/frontend/accessors.dart
+++ b/pkg/kernel/lib/frontend/accessors.dart
@@ -32,13 +32,13 @@
       {bool voidContext: false}) {
     if (voidContext) {
       return _finish(new ConditionalExpression(buildIsNull(_makeRead()),
-          _makeWrite(value, voidContext), new NullLiteral(), type));
+          _makeWrite(value, false), new NullLiteral(), type));
     }
     var tmp = new VariableDeclaration.forValue(_makeRead());
     return _finish(makeLet(
         tmp,
         new ConditionalExpression(buildIsNull(new VariableGet(tmp)),
-            _makeWrite(value, voidContext), new VariableGet(tmp), type)));
+            _makeWrite(value, false), new VariableGet(tmp), type)));
   }
 
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
diff --git a/pkg/kernel/lib/target/flutter.dart b/pkg/kernel/lib/target/flutter.dart
index 5673a22..4ba7964 100644
--- a/pkg/kernel/lib/target/flutter.dart
+++ b/pkg/kernel/lib/target/flutter.dart
@@ -50,8 +50,11 @@
         'dart:vmservice_sky',
       ];
 
-  void transformProgram(Program program) {
+  void performModularTransformations(Program program) {
     new mix.MixinFullResolution().transform(program);
+  }
+
+  void performGlobalTransformations(Program program) {
     cont.transformProgram(program);
 
     // Repair `_getMainClosure()` function in dart:{_builtin,ui} libraries.
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 1c06273..ec89ffb 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -4,16 +4,20 @@
 library kernel.target.targets;
 
 import '../ast.dart';
-
+import '../core_types.dart';
+import '../transformations/treeshaker.dart' show ProgramRoot;
+import 'flutter.dart';
 import 'vm.dart';
 import 'vmcc.dart';
-import 'flutter.dart';
 
 final List<String> targetNames = targets.keys.toList();
 
 class TargetFlags {
   bool strongMode;
-  TargetFlags({this.strongMode: false});
+  bool treeShake;
+  List<ProgramRoot> programRoots;
+
+  TargetFlags({this.strongMode: false, this.treeShake: false, this.programRoots: const <ProgramRoot>[]});
 }
 
 typedef Target _TargetBuilder(TargetFlags flags);
@@ -47,12 +51,27 @@
   /// by the target.
   Map<String, String> get extraDeclaredVariables => const <String, String>{};
 
+  /// Classes from the SDK whose interface is required for the modular
+  /// transformations.
+  Map<String, List<String>> get requiredSdkClasses => CoreTypes.requiredClasses;
+
   bool get strongMode;
 
   /// If true, the SDK should be loaded in strong mode.
   bool get strongModeSdk => strongMode;
 
-  void transformProgram(Program program);
+  /// Perform target-specific modular transformations.
+  ///
+  /// These transformations should not be whole-program transformations.  They
+  /// should expect that the program will contain external libraries.
+  void performModularTransformations(Program program);
+
+  /// Perform target-specific whole-program transformations.
+  ///
+  /// These transformations should be optimizations and not required for
+  /// correctness.  Everything should work if a simple and fast linker chooses
+  /// not to apply these transformations.
+  void performGlobalTransformations(Program program);
 
   String toString() => 'Target($name)';
 }
@@ -65,5 +84,6 @@
   bool get strongMode => flags.strongMode;
   String get name => 'none';
   List<String> get extraRequiredLibraries => <String>[];
-  void transformProgram(Program program) {}
+  void performModularTransformations(Program program) {}
+  void performGlobalTransformations(Program program) {}
 }
diff --git a/pkg/kernel/lib/target/vm.dart b/pkg/kernel/lib/target/vm.dart
index c12403e..1366cae 100644
--- a/pkg/kernel/lib/target/vm.dart
+++ b/pkg/kernel/lib/target/vm.dart
@@ -4,6 +4,7 @@
 library kernel.target.vm;
 
 import '../ast.dart';
+import '../class_hierarchy.dart';
 import '../core_types.dart';
 import '../transformations/continuation.dart' as cont;
 import '../transformations/erasure.dart';
@@ -54,23 +55,33 @@
         'dart:io',
       ];
 
-  void transformProgram(Program program) {
-    var mixins = new mix.MixinFullResolution();
-    mixins.transform(program);
+  ClassHierarchy _hierarchy;
 
-    var hierarchy = mixins.hierarchy;
+  void performModularTransformations(Program program) {
+    var mixins = new mix.MixinFullResolution()..transform(program);
+
+    _hierarchy = mixins.hierarchy;
+  }
+
+  void performGlobalTransformations(Program program) {
     var coreTypes = new CoreTypes(program);
 
     if (strongMode) {
-      new InsertTypeChecks(hierarchy: hierarchy, coreTypes: coreTypes)
+      new InsertTypeChecks(hierarchy: _hierarchy, coreTypes: coreTypes)
           .transformProgram(program);
-      new InsertCovarianceChecks(hierarchy: hierarchy, coreTypes: coreTypes)
+      new InsertCovarianceChecks(hierarchy: _hierarchy, coreTypes: coreTypes)
           .transformProgram(program);
     }
 
-    new TreeShaker(program,
-            hierarchy: hierarchy, coreTypes: coreTypes, strongMode: strongMode)
-        .transform(program);
+    if (flags.treeShake) {
+      new TreeShaker(program,
+              hierarchy: _hierarchy,
+              coreTypes: coreTypes,
+              strongMode: strongMode,
+              programRoots: flags.programRoots)
+          .transform(program);
+      _hierarchy = null; // Hierarchy must be recomputed.
+    }
 
     cont.transformProgram(program);
 
diff --git a/pkg/kernel/lib/target/vmcc.dart b/pkg/kernel/lib/target/vmcc.dart
index b292457..028e584 100644
--- a/pkg/kernel/lib/target/vmcc.dart
+++ b/pkg/kernel/lib/target/vmcc.dart
@@ -16,8 +16,8 @@
   String get name => "vmcc";
 
   @override
-  void transformProgram(Program program) {
-    super.transformProgram(program);
+  void performGlobalTransformations(Program program) {
+    super.performGlobalTransformations(program);
     cc.transformProgram(program);
   }
 }
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index a0e7227..8fa2c67 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -302,6 +302,9 @@
         endLine('import "$importPath" as $prefix;');
       }
     }
+    for (var import in library.deferredImports) {
+      import.accept(this);
+    }
     endLine();
     var inner = new Printer._inner(this, imports);
     library.classes.forEach(inner.writeNode);
@@ -396,10 +399,14 @@
   }
 
   void writeNode(Node node) {
-    if (showOffsets && node is TreeNode) {
-      writeWord("[${node.fileOffset}]");
+    if (node == null) {
+      writeSymbol("<Null>");
+    } else {
+      if (showOffsets && node is TreeNode) {
+        writeWord("[${node.fileOffset}]");
+      }
+      node.accept(this);
     }
-    node.accept(this);
   }
 
   void writeOptionalNode(Node node) {
@@ -985,6 +992,30 @@
     writeExpression(node.body);
   }
 
+  visitLoadLibrary(LoadLibrary node) {
+    writeWord('LoadLibrary');
+    writeSymbol('(');
+    writeWord(node.import.name);
+    writeSymbol(')');
+    state = WORD;
+  }
+
+  visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
+    writeWord('CheckLibraryIsLoaded');
+    writeSymbol('(');
+    writeWord(node.import.name);
+    writeSymbol(')');
+    state = WORD;
+  }
+
+  visitDeferredImport(DeferredImport node) {
+    write('import "');
+    write('${node.importedLibrary.importUri}');
+    write('" deferred as ');
+    write(node.name);
+    endLine(';');
+  }
+
   defaultExpression(Expression node) {
     writeWord('${node.runtimeType}');
   }
@@ -1162,6 +1193,9 @@
 
   visitForInStatement(ForInStatement node) {
     writeIndentation();
+    if (node.isAsync) {
+      writeSpaced('await');
+    }
     writeSpaced('for');
     writeSymbol('(');
     writeVariableDeclaration(node.variable, useVarKeyword: true);
diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart
index f92d680..112ea43 100644
--- a/pkg/kernel/lib/transformations/continuation.dart
+++ b/pkg/kernel/lib/transformations/continuation.dart
@@ -7,6 +7,7 @@
 import 'dart:math' as math;
 
 import '../ast.dart';
+import '../core_types.dart';
 import '../visitor.dart';
 
 import 'async.dart';
@@ -112,11 +113,12 @@
 }
 
 class SyncStarFunctionRewriter extends ContinuationRewriterBase {
-  final VariableDeclaration iteratorVariable =
-      new VariableDeclaration(":iterator");
+  final VariableDeclaration iteratorVariable;
 
   SyncStarFunctionRewriter(helper, enclosingFunction)
-      : super(helper, enclosingFunction);
+      : iteratorVariable = new VariableDeclaration(':iterator')
+            ..type = helper.iteratorClass.rawType,
+        super(helper, enclosingFunction);
 
   FunctionNode rewrite() {
     // :sync_body(:iterator) {
@@ -128,7 +130,9 @@
         requiredParameterCount: 1,
         asyncMarker: AsyncMarker.SyncYielding)
       ..fileOffset = enclosingFunction.fileOffset
-      ..fileEndOffset = enclosingFunction.fileEndOffset;
+      ..fileEndOffset = enclosingFunction.fileEndOffset
+      ..returnType = helper.coreTypes.boolClass.rawType;
+
     final closureFunction =
         new FunctionDeclaration(nestedClosureVariable, function)
           ..fileOffset = enclosingFunction.parent.fileOffset;
@@ -151,7 +155,10 @@
     //    :iterator.current_=
     //    :iterator.isYieldEach=
     // and return `true` as long as it did something and `false` when it's done.
-    return enclosingFunction.body.accept(this);
+    return new Block(<Statement>[
+        enclosingFunction.body.accept(this),
+        new ReturnStatement(new BoolLiteral(false))
+    ]);
   }
 
   visitYieldStatement(YieldStatement node) {
@@ -175,6 +182,13 @@
     statements.add(createContinuationPoint(new BoolLiteral(true)));
     return new Block(statements);
   }
+
+  TreeNode visitReturnStatement(ReturnStatement node) {
+    // sync* functions cannot return a value.
+    assert(node.expression == null || node.expression is NullLiteral);
+    node.expression = new BoolLiteral(false)..parent = node;
+    return node;
+  }
 }
 
 abstract class AsyncRewriterBase extends ContinuationRewriterBase {
@@ -755,15 +769,37 @@
   FunctionNode rewrite() {
     var statements = <Statement>[];
 
-    // var :completer = new Completer.sync();
+    // The original function return type should be Future<T> because the
+    // function is async. If it was, we make a Completer<T>.  Otherwise
+    // We will make a malformed type.
+    var future_type = enclosingFunction.returnType;
+    DartType returnType = const DynamicType();
+    if (future_type is InterfaceType) {
+      if (future_type.classNode == helper.futureClass) {
+        if (future_type.typeArguments.length == 0) {
+          returnType = const DynamicType();
+        } else if (future_type.typeArguments.length == 1) {
+          returnType = future_type.typeArguments[0];
+        } else {
+          returnType = const InvalidType();
+        }
+      }
+    }
+    var completerTypeArguments = <DartType>[returnType];
+    var completerType = new InterfaceType(
+        helper.completerClass, completerTypeArguments);
+
+    // final Completer<T> :completer = new Completer<T>.sync();
     completerVariable = new VariableDeclaration(":completer",
         initializer: new StaticInvocation(helper.completerConstructor,
-            new Arguments([], types: [const DynamicType()]))
+            new Arguments([], types: completerTypeArguments))
           ..fileOffset = enclosingFunction.body.fileOffset,
-        isFinal: true);
+        isFinal: true,
+        type: completerType);
     statements.add(completerVariable);
 
-    returnVariable = new VariableDeclaration(":return_value");
+    returnVariable = new VariableDeclaration(
+        ":return_value", type: returnType);
     statements.add(returnVariable);
 
     setupAsyncContinuations(statements);
@@ -827,6 +863,9 @@
 class HelperNodes {
   final Library asyncLibrary;
   final Library coreLibrary;
+  final Class iteratorClass;
+  final Class futureClass;
+  final Class completerClass;
   final Procedure printProcedure;
   final Procedure completerConstructor;
   final Procedure futureMicrotaskConstructor;
@@ -836,10 +875,14 @@
   final Procedure asyncThenWrapper;
   final Procedure asyncErrorWrapper;
   final Procedure awaitHelper;
+  final CoreTypes coreTypes;
 
   HelperNodes(
       this.asyncLibrary,
       this.coreLibrary,
+      this.iteratorClass,
+      this.futureClass,
+      this.completerClass,
       this.printProcedure,
       this.completerConstructor,
       this.syncIterableConstructor,
@@ -848,7 +891,8 @@
       this.streamControllerConstructor,
       this.asyncThenWrapper,
       this.asyncErrorWrapper,
-      this.awaitHelper);
+      this.awaitHelper,
+      this.coreTypes);
 
   factory HelperNodes.fromProgram(Program program) {
     Library findLibrary(String name) {
@@ -895,6 +939,7 @@
 
     var completerClass = findClass(asyncLibrary, 'Completer');
     var futureClass = findClass(asyncLibrary, 'Future');
+    var iteratorClass = findClass(coreLibrary, 'Iterator');
 
     // The VM's dart:async implementation has renamed _StreamIteratorImpl to
     // _StreamIterator.  To support both old and new library implementations we
@@ -917,6 +962,9 @@
     return new HelperNodes(
         asyncLibrary,
         coreLibrary,
+        iteratorClass,
+        futureClass,
+        completerClass,
         findProcedure(coreLibrary, 'print'),
         findFactoryConstructor(completerClass, 'sync'),
         findConstructor(syncIterableClass, ''),
@@ -925,6 +973,7 @@
         findConstructor(streamControllerClass, ''),
         findProcedure(asyncLibrary, '_asyncThenWrapperHelper'),
         findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'),
-        findProcedure(asyncLibrary, '_awaitHelper'));
+        findProcedure(asyncLibrary, '_awaitHelper'),
+        new CoreTypes(program));
   }
 }
diff --git a/pkg/kernel/lib/transformations/mixin_full_resolution.dart b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
index 1cd1160..8d84347 100644
--- a/pkg/kernel/lib/transformations/mixin_full_resolution.dart
+++ b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
@@ -31,6 +31,8 @@
     // the mixin and constructors from the base class.
     var processedClasses = new Set<Class>();
     for (var library in program.libraries) {
+      if (library.isExternal) continue;
+
       for (var class_ in library.classes) {
         transformClass(processedClasses, transformedClasses, class_);
       }
@@ -41,6 +43,8 @@
 
     // Resolve all super call expressions and super initializers.
     for (var library in program.libraries) {
+      if (library.isExternal) continue;
+
       for (var class_ in library.classes) {
         final bool hasTransformedSuperclass =
             transformedClasses.contains(class_.superclass);
@@ -74,7 +78,8 @@
     if (!processedClasses.add(class_)) return;
 
     // Ensure super classes have been transformed before this class.
-    if (class_.superclass != null) {
+    if (class_.superclass != null &&
+        class_.superclass.level.index >= ClassLevel.Mixin.index) {
       transformClass(processedClasses, transformedClasses, class_.superclass);
     }
 
@@ -82,6 +87,12 @@
     // constructors in this class.
     if (!class_.isMixinApplication) return;
 
+    if (class_.mixedInClass.level.index < ClassLevel.Mixin.index) {
+      throw new Exception(
+          'Class "${class_.name}" mixes in "${class_.mixedInClass.name}" from'
+          ' an external library.  Did you forget --link?');
+    }
+
     transformedClasses.add(class_);
 
     // Clone fields and methods from the mixin class.
@@ -179,7 +190,7 @@
       return new DirectPropertyGet(new ThisExpression(), target);
     } else {
       return _callNoSuchMethod(node.name.name, new Arguments.empty(), node,
-          isGetter: true);
+          isGetter: true, isSuper: true);
     }
   }
 
@@ -195,7 +206,7 @@
           new VariableDeclaration.forValue(visit(node.value));
       Expression result = _callNoSuchMethod(
           node.name.name, new Arguments([new VariableGet(rightHandSide)]), node,
-          isSetter: true);
+          isSetter: true, isSuper: true);
       VariableDeclaration call = new VariableDeclaration.forValue(result);
       return new Let(
           rightHandSide, new Let(call, new VariableGet(rightHandSide)));
diff --git a/pkg/kernel/lib/transformations/setup_builtin_library.dart b/pkg/kernel/lib/transformations/setup_builtin_library.dart
index cc4149a..3fe2f14 100644
--- a/pkg/kernel/lib/transformations/setup_builtin_library.dart
+++ b/pkg/kernel/lib/transformations/setup_builtin_library.dart
@@ -37,9 +37,14 @@
     throw new Exception('Could not find "_getMainClosure" in "$libraryUri"');
   }
 
-  var returnMainStatement = new ReturnStatement(new StaticGet(mainMethod));
-  getMainClosure.body = returnMainStatement;
-  returnMainStatement.parent = getMainClosure;
+  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 program;
 }
diff --git a/pkg/kernel/lib/transformations/treeshaker.dart b/pkg/kernel/lib/transformations/treeshaker.dart
index 90540a0..27ef8fb 100644
--- a/pkg/kernel/lib/transformations/treeshaker.dart
+++ b/pkg/kernel/lib/transformations/treeshaker.dart
@@ -9,11 +9,48 @@
 import '../core_types.dart';
 import '../type_environment.dart';
 
-Program transformProgram(Program program) {
-  new TreeShaker(program).transform(program);
+Program transformProgram(Program program, {List<ProgramRoot> programRoots}) {
+  new TreeShaker(program, programRoots: programRoots).transform(program);
   return program;
 }
 
+enum ProgramRootKind {
+  /// The root is a class which will be instantiated by
+  /// external / non-Dart code.
+  ExternallyInstantiatedClass,
+
+  /// The root is a setter function or a field.
+  Setter,
+
+  /// The root is a getter function or a field.
+  Getter,
+
+  /// The root is some kind of constructor.
+  Constructor,
+
+  /// The root is a field, normal procedure or constructor.
+  Other,
+}
+
+/// A program root which the vm or embedder uses and needs to be retained.
+class ProgramRoot {
+  /// The library the root is contained in.
+  final String library;
+
+  /// The name of the class inside the library (optional).
+  final String klass;
+
+  /// The name of the member inside the library (or class, optional).
+  final String member;
+
+  /// The kind of this program root.
+  final ProgramRootKind kind;
+
+  ProgramRoot(this.library, this.klass, this.member, this.kind);
+
+  String toString() => "ProgramRoot($library, $klass, $member, $kind)";
+}
+
 /// Tree shaking based on class hierarchy analysis.
 ///
 /// Any dynamic dispatch not on `this` is conservatively assumed to target
@@ -30,13 +67,13 @@
 ///
 /// If the `dart:mirrors` library is used then nothing will be tree-shaken.
 //
-// TODO(asgerf): Shake off parts of the core libraries based on the Target.
 // TODO(asgerf): Tree shake unused instance fields.
 class TreeShaker {
   final Program program;
   final ClassHierarchy hierarchy;
   final CoreTypes coreTypes;
   final bool strongMode;
+  final List<ProgramRoot> programRoots;
 
   /// Map from classes to set of names that have been dispatched with that class
   /// as the static receiver type (meaning any subtype of that class can be
@@ -107,10 +144,17 @@
   /// Set to true if any use of the `dart:mirrors` API is found.
   bool isUsingMirrors = false;
 
+  /// If we have roots, we will shake, even if we encounter some elements from
+  /// the mirrors library.
+  bool get forceShaking => programRoots != null && programRoots.isNotEmpty;
+
   TreeShaker(Program program,
-      {ClassHierarchy hierarchy, CoreTypes coreTypes, bool strongMode: false})
+      {ClassHierarchy hierarchy,
+      CoreTypes coreTypes,
+      bool strongMode: false,
+      List<ProgramRoot> programRoots})
       : this._internal(program, hierarchy ?? new ClassHierarchy(program),
-            coreTypes ?? new CoreTypes(program), strongMode);
+            coreTypes ?? new CoreTypes(program), strongMode, programRoots);
 
   bool isMemberBodyUsed(Member member) {
     return _usedMembers.containsKey(member);
@@ -145,8 +189,8 @@
     new _TreeShakingTransformer(this).transform(program);
   }
 
-  TreeShaker._internal(
-      this.program, ClassHierarchy hierarchy, this.coreTypes, this.strongMode)
+  TreeShaker._internal(this.program, ClassHierarchy hierarchy, this.coreTypes,
+      this.strongMode, this.programRoots)
       : this.hierarchy = hierarchy,
         this._dispatchedNames = new List<Set<Name>>(hierarchy.classes.length),
         this._usedMembersWithHost =
@@ -179,6 +223,8 @@
     _addDispatchedName(hierarchy.rootClass, new Name('noSuchMethod'));
     _addPervasiveUses();
     _addUsedMember(null, program.mainMethod);
+    programRoots?.forEach(_addUsedRoot);
+
     _iterateWorklist();
 
     // Mark overridden members in order to preserve abstract members as
@@ -370,6 +416,49 @@
     visitList(classNode.annotations, _visitor);
   }
 
+  /// Registers the given root as being used.
+  void _addUsedRoot(ProgramRoot root) {
+    Library rootLibrary = _findLibraryRoot(root, program);
+
+    if (root.kind == ProgramRootKind.ExternallyInstantiatedClass) {
+      Class rootClass = _findClassRoot(root, rootLibrary);
+
+      // This is a class which will be instantiated by non-Dart code (whether it
+      // has a valid generative construtor or not).
+      _addInstantiatedClass(rootClass);
+
+      // We keep all the constructors of externally instantiated classes.
+      // Sometimes the runtime might do a constructor call and sometimes it
+      // might just allocate the class without invoking the constructor.
+      // So we try to be on the safe side here!
+      for (var constructor in rootClass.constructors) {
+        _addUsedMember(rootClass, constructor);
+      }
+
+      // We keep all factory constructors as well for the same reason.
+      for (var member in rootClass.procedures) {
+        if (member.isStatic && member.kind == ProcedureKind.Factory) {
+          _addUsedMember(rootClass, member);
+        }
+      }
+    } else {
+      if (root.klass != null) {
+        // For class members we mark the Field/Procedure/Constructor as used.
+        // We also mark it as instantiated if it's a constructor.
+        Class rootClass = _findClassRoot(root, rootLibrary);
+        Member rootMember = _findMemberRoot(root, rootClass.members);
+        _addUsedMember(rootClass, rootMember);
+        if (rootMember is Constructor) {
+          _addInstantiatedClass(rootClass);
+        }
+      } else {
+        // For library members we mark the Field/Procedure as used.
+        Member rootMember = _findMemberRoot(root, rootLibrary.members);
+        _addUsedMember(null, rootMember);
+      }
+    }
+  }
+
   /// Registers the given class as being used in a type annotation.
   void _addClassUsedInType(Class classNode) {
     int index = hierarchy.getClassIndex(classNode);
@@ -400,7 +489,7 @@
   ///   the initializer list of another constructor.
   /// - Procedures are used if they can be invoked or torn off.
   void _addUsedMember(Class host, Member member) {
-    if (member.enclosingLibrary == _mirrorsLibrary) {
+    if (!forceShaking && member.enclosingLibrary == _mirrorsLibrary) {
       throw new _UsingMirrorsException();
     }
     if (host != null) {
@@ -808,7 +897,7 @@
 
   void transform(Program program) {
     for (var library in program.libraries) {
-      if (library.importUri.scheme == 'dart') {
+      if (!shaker.forceShaking && library.importUri.scheme == 'dart') {
         // The backend expects certain things to be present in the core
         // libraries, so we currently don't shake off anything there.
         continue;
@@ -979,3 +1068,53 @@
 /// Exception that is thrown to stop the tree shaking analysis when a use
 /// of `dart:mirrors` is found.
 class _UsingMirrorsException {}
+
+Library _findLibraryRoot(ProgramRoot root, Program program) {
+  for (var library in program.libraries) {
+    if (library.importUri.toString() == root.library) {
+      return library;
+    }
+  }
+
+  throw "$root not found!";
+}
+
+Class _findClassRoot(ProgramRoot root, Library rootLibrary) {
+  for (var klass in rootLibrary.classes) {
+    if (klass.name == root.klass) {
+      return klass;
+    }
+  }
+  throw "$root not found!";
+}
+
+Member _findMemberRoot(ProgramRoot root, Iterable<Member> membersToSearch) {
+  for (var member in membersToSearch) {
+    if (member.name.name == root.member) {
+      switch (root.kind) {
+        case ProgramRootKind.Constructor:
+          if (member is Procedure && member.kind == ProcedureKind.Factory ||
+              member is Constructor) {
+            return member;
+          }
+          break;
+        case ProgramRootKind.Setter:
+          if (member is Procedure && member.kind == ProcedureKind.Setter ||
+              member is Field) {
+            return member;
+          }
+          break;
+        case ProgramRootKind.Getter:
+          if (member is Procedure && member.kind == ProcedureKind.Getter ||
+              member is Field) {
+            return member;
+          }
+          break;
+        case ProgramRootKind.Other:
+          return member;
+        default:
+      }
+    }
+  }
+  throw "$root not found!";
+}
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 45159b2..c6a8937 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -680,6 +680,16 @@
   }
 
   @override
+  DartType visitLoadLibrary(LoadLibrary node) {
+    return environment.futureType(const DynamicType());
+  }
+
+  @override
+  DartType visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
+    return environment.objectType;
+  }
+
+  @override
   visitAssertStatement(AssertStatement node) {
     visitExpression(node.condition);
     if (node.message != null) {
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 1a1b5ad..2724791 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -10,6 +10,33 @@
   VerifyingVisitor.check(program);
 }
 
+class VerificationError {
+  final TreeNode context;
+
+  final TreeNode node;
+
+  final String details;
+
+  VerificationError(this.context, this.node, this.details);
+
+  toString() {
+    Location location;
+    try {
+      location = node?.location ?? context?.location;
+    } catch (_) {
+      // TODO(ahe): Fix the compiler instead.
+    }
+    if (location != null) {
+      String file = location.file ?? "";
+      return "$file:${location.line}:${location.column}: Verification error:"
+          " $details";
+    } else {
+      return
+          "Verification error: $details\nContext: '$context'.\nNode: '$node'.";
+    }
+  }
+}
+
 /// Checks that a kernel program is well-formed.
 ///
 /// This does not include any kind of type checking.
@@ -19,6 +46,10 @@
   final List<VariableDeclaration> variableStack = <VariableDeclaration>[];
   bool classTypeParametersAreInScope = false;
 
+  /// If true, relax certain checks for *outline* mode. For example, don't
+  /// attempt to validate constructor initializers.
+  bool isOutline = false;
+
   Member currentMember;
   Class currentClass;
   TreeNode currentParent;
@@ -33,11 +64,15 @@
     visitChildren(node);
   }
 
+  problem(TreeNode node, String details) {
+    throw new VerificationError(context, node, details);
+  }
+
   TreeNode enterParent(TreeNode node) {
     if (!identical(node.parent, currentParent)) {
-      throw 'Incorrect parent pointer on ${node.runtimeType} in $context. '
-          'Parent pointer is ${node.parent.runtimeType}, '
-          'actual parent is ${currentParent.runtimeType}.';
+      problem(node,
+          "Incorrect parent pointer: expected '${node.parent.runtimeType}',"
+          " but found: '${currentParent.runtimeType}'.");
     }
     var oldParent = currentParent;
     currentParent = node;
@@ -71,7 +106,8 @@
 
   void declareMember(Member member) {
     if (member.transformerFlags & TransformerFlag.seenByVerifier != 0) {
-      throw '$member has been declared more than once (${member.location})';
+      problem(member.function,
+          "Member '$member' has been declared more than once.");
     }
     member.transformerFlags |= TransformerFlag.seenByVerifier;
   }
@@ -82,7 +118,7 @@
 
   void declareVariable(VariableDeclaration variable) {
     if (variable.flags & VariableDeclaration.FlagInScope != 0) {
-      throw '$variable declared more than once (${variable.location})';
+      problem(variable, "Variable '$variable' declared more than once.");
     }
     variable.flags |= VariableDeclaration.FlagInScope;
     variableStack.add(variable);
@@ -96,7 +132,7 @@
     for (int i = 0; i < parameters.length; ++i) {
       var parameter = parameters[i];
       if (!typeParameters.add(parameter)) {
-        throw 'Type parameter $parameter redeclared in $context';
+        problem(parameter, "Type parameter '$parameter' redeclared.");
       }
     }
   }
@@ -107,29 +143,32 @@
 
   void checkVariableInScope(VariableDeclaration variable, TreeNode where) {
     if (variable.flags & VariableDeclaration.FlagInScope == 0) {
-      throw 'Variable $variable used out of scope in $context '
-          '(${where.location})';
+      problem(where, "Variable '$variable' used out of scope.");
     }
   }
 
   visitProgram(Program program) {
-    for (var library in program.libraries) {
-      for (var class_ in library.classes) {
-        if (!classes.add(class_)) {
-          throw 'Class $class_ declared more than once';
+    try {
+      for (var library in program.libraries) {
+        for (var class_ in library.classes) {
+          if (!classes.add(class_)) {
+            problem(class_, "Class '$class_' declared more than once.");
+          }
+        }
+        library.members.forEach(declareMember);
+        for (var class_ in library.classes) {
+          class_.members.forEach(declareMember);
         }
       }
-      library.members.forEach(declareMember);
-      for (var class_ in library.classes) {
-        class_.members.forEach(declareMember);
+      visitChildren(program);
+    } finally {
+      for (var library in program.libraries) {
+        library.members.forEach(undeclareMember);
+        for (var class_ in library.classes) {
+          class_.members.forEach(undeclareMember);
+        }
       }
-    }
-    visitChildren(program);
-    for (var library in program.libraries) {
-      library.members.forEach(undeclareMember);
-      for (var class_ in library.classes) {
-        class_.members.forEach(undeclareMember);
-      }
+      variableStack.forEach(undeclareVariable);
     }
   }
 
@@ -164,6 +203,9 @@
     int stackHeight = enterLocalScope();
     visitChildren(node.function);
     visitList(node.initializers, this);
+    if (!isOutline) {
+      checkInitializers(node);
+    }
     exitLocalScope(stackHeight);
     classTypeParametersAreInScope = false;
     visitList(node.annotations, this);
@@ -197,8 +239,8 @@
   visitFunctionType(FunctionType node) {
     for (int i = 1; i < node.namedParameters.length; ++i) {
       if (node.namedParameters[i - 1].compareTo(node.namedParameters[i]) >= 0) {
-        throw 'Named parameters are not sorted on function type found in '
-            '$context';
+        problem(currentParent,
+            "Named parameters are not sorted on function type ($node).");
       }
     }
     declareTypeParameters(node.typeParameters);
@@ -250,13 +292,13 @@
   visitStaticGet(StaticGet node) {
     visitChildren(node);
     if (node.target == null) {
-      throw 'StaticGet without target found in $context.';
+      problem(node, "StaticGet without target.");
     }
     if (!node.target.hasGetter) {
-      throw 'StaticGet to ${node.target} without getter found in $context';
+      problem(node, "StaticGet of '${node.target}' without getter.");
     }
     if (node.target.isInstanceMember) {
-      throw 'StaticGet to ${node.target} that is not static found in $context';
+      problem(node, "StaticGet of '${node.target}' that's an instance member.");
     }
   }
 
@@ -264,34 +306,49 @@
   visitStaticSet(StaticSet node) {
     visitChildren(node);
     if (node.target == null) {
-      throw 'StaticSet without target found in $context.';
+      problem(node, "StaticSet without target.");
     }
     if (!node.target.hasSetter) {
-      throw 'StaticSet to ${node.target} without setter found in $context';
+      problem(node, "StaticSet to '${node.target}' without setter.");
     }
     if (node.target.isInstanceMember) {
-      throw 'StaticSet to ${node.target} that is not static found in $context';
+      problem(node, "StaticSet to '${node.target}' that's an instance member.");
     }
   }
 
   @override
   visitStaticInvocation(StaticInvocation node) {
-    visitChildren(node);
-    if (node.target == null) {
-      throw 'StaticInvocation without target found in $context.';
-    }
+    checkTargetedInvocation(node.target, node);
     if (node.target.isInstanceMember) {
-      throw 'StaticInvocation to ${node.target} that is not static found in '
-          '$context';
+      problem(node,
+          "StaticInvocation of '${node.target}' that's an instance member.");
     }
-    if (!areArgumentsCompatible(node.arguments, node.target.function)) {
-      throw 'StaticInvocation with incompatible arguments to '
-          '${node.target} found in $context';
+    if (node.isConst &&
+        (!node.target.isConst || !node.target.isExternal ||
+            node.target.kind != ProcedureKind.Factory)) {
+      problem(node, "Constant StaticInvocation of '${node.target}' that isn't"
+          " a const external factory.");
     }
-    if (node.arguments.types.length !=
-        node.target.function.typeParameters.length) {
-      throw 'Wrong number of type arguments provided in StaticInvocation '
-          'to ${node.target} found in $context';
+  }
+
+  void checkTargetedInvocation(Member target, InvocationExpression node) {
+    visitChildren(node);
+    if (target == null) {
+      problem(node, "${node.runtimeType} without target.");
+    }
+    if (target.function == null) {
+      problem(node, "${node.runtimeType} without function.");
+    }
+    if (!areArgumentsCompatible(node.arguments, target.function)) {
+      problem(node,
+          "${node.runtimeType} with incompatible arguments for '${target}'.");
+    }
+    int expectedTypeParameters = target is Constructor
+        ? target.enclosingClass.typeParameters.length
+        : target.function.typeParameters.length;
+    if (node.arguments.types.length != expectedTypeParameters) {
+      problem(node, "${node.runtimeType} with wrong number of type arguments"
+          " for '${target}'.");
     }
   }
 
@@ -299,15 +356,14 @@
   visitDirectPropertyGet(DirectPropertyGet node) {
     visitChildren(node);
     if (node.target == null) {
-      throw 'DirectPropertyGet without target found in $context.';
+      problem(node, "DirectPropertyGet without target.");
     }
     if (!node.target.hasGetter) {
-      throw 'DirectPropertyGet to ${node.target} without getter found in '
-          '$context';
+      problem(node, "DirectPropertyGet of '${node.target}' without getter.");
     }
     if (!node.target.isInstanceMember) {
-      throw 'DirectPropertyGet to ${node.target} that is static found in '
-          '$context';
+      problem(node, "DirectPropertyGet of '${node.target}' that isn't an"
+          " instance member.");
     }
   }
 
@@ -315,56 +371,33 @@
   visitDirectPropertySet(DirectPropertySet node) {
     visitChildren(node);
     if (node.target == null) {
-      throw 'DirectPropertySet without target found in $context.';
+      problem(node, "DirectPropertySet without target.");
     }
     if (!node.target.hasSetter) {
-      throw 'DirectPropertyGet to ${node.target} without setter found in '
-          '$context';
+      problem(node, "DirectPropertySet of '${node.target}' without setter.");
     }
     if (!node.target.isInstanceMember) {
-      throw 'DirectPropertySet to ${node.target} that is static found in '
-          '$context';
+      problem(node, "DirectPropertySet of '${node.target}' that is static.");
     }
   }
 
   @override
   visitDirectMethodInvocation(DirectMethodInvocation node) {
-    visitChildren(node);
-    if (node.target == null) {
-      throw 'DirectMethodInvocation without target found in $context.';
-    }
-    if (!node.target.isInstanceMember) {
-      throw 'DirectMethodInvocation to ${node.target} that is static found in '
-          '$context';
-    }
-    if (!areArgumentsCompatible(node.arguments, node.target.function)) {
-      throw 'DirectMethodInvocation with incompatible arguments to '
-          '${node.target} found in $context';
-    }
-    if (node.arguments.types.length !=
-        node.target.function.typeParameters.length) {
-      throw 'Wrong number of type arguments provided in DirectMethodInvocation '
-          'to ${node.target} found in $context';
+    checkTargetedInvocation(node.target, node);
+    if (node.receiver == null) {
+      problem(node, "DirectMethodInvocation without receiver.");
     }
   }
 
   @override
   visitConstructorInvocation(ConstructorInvocation node) {
-    visitChildren(node);
-    if (node.target == null) {
-      throw 'ConstructorInvocation without target found in $context.';
-    }
+    checkTargetedInvocation(node.target, node);
     if (node.target.enclosingClass.isAbstract) {
-      throw 'ConstructorInvocation to abstract class found in $context';
+      problem(node, "ConstructorInvocation of abstract class.");
     }
-    if (!areArgumentsCompatible(node.arguments, node.target.function)) {
-      throw 'ConstructorInvocation with incompatible arguments to '
-          '${node.target} found in $context';
-    }
-    if (node.arguments.types.length !=
-        node.target.enclosingClass.typeParameters.length) {
-      throw 'Wrong number of type arguments provided in ConstructorInvocation '
-          'to ${node.target} found in $context';
+    if (node.isConst && !node.target.isConst) {
+      problem(node, "Constant ConstructorInvocation fo '${node.target}' that"
+          " isn't const.");
     }
   }
 
@@ -390,16 +423,16 @@
   @override
   defaultMemberReference(Member node) {
     if (node.transformerFlags & TransformerFlag.seenByVerifier == 0) {
-      throw 'Dangling reference to $node found in $context.\n'
-          'Parent pointer is set to ${node.parent}';
+      problem(node,
+          "Dangling reference to '$node', parent is: '${node.parent}'.");
     }
   }
 
   @override
   visitClassReference(Class node) {
     if (!classes.contains(node)) {
-      throw 'Dangling reference to $node found in $context.\n'
-          'Parent pointer is set to ${node.parent}';
+      problem(node,
+          "Dangling reference to '$node', parent is: '${node.parent}'.");
     }
   }
 
@@ -407,13 +440,12 @@
   visitTypeParameterType(TypeParameterType node) {
     var parameter = node.parameter;
     if (!typeParameters.contains(parameter)) {
-      throw 'Type parameter $parameter referenced out of scope in $context.\n'
-          'Parent pointer is set to ${parameter.parent}';
+      problem(currentParent, "Type parameter '$parameter' referenced out of"
+          " scope, parent is: '${parameter.parent}'.");
     }
     if (parameter.parent is Class && !classTypeParametersAreInScope) {
-      throw 'Type parameter $parameter referenced from static context '
-          'in $context.\n'
-          'Parent pointer is set to ${parameter.parent}';
+      problem(currentParent, "Type parameter '$parameter' referenced from"
+          " static context, parent is '${parameter.parent}'.");
     }
   }
 
@@ -421,9 +453,9 @@
   visitInterfaceType(InterfaceType node) {
     node.visitChildren(this);
     if (node.typeArguments.length != node.classNode.typeParameters.length) {
-      throw 'Type $node provides ${node.typeArguments.length} type arguments '
-          'but the class declares ${node.classNode.typeParameters.length} '
-          'parameters. Found in $context.';
+      problem(currentParent, "Type $node provides ${node.typeArguments.length}"
+          " type arguments but the class declares"
+          " ${node.classNode.typeParameters.length} parameters.");
     }
   }
 }
@@ -439,9 +471,10 @@
 
   defaultTreeNode(TreeNode node) {
     if (node.parent != parent) {
-      throw 'Parent pointer on ${node.runtimeType} '
-          'is ${node.parent.runtimeType} '
-          'but should be ${parent.runtimeType}';
+      throw new VerificationError(parent, node,
+          "Parent pointer on '${node.runtimeType}' "
+          "is '${node.parent.runtimeType}' "
+          "but should be '${parent.runtimeType}'.");
     }
     var oldParent = parent;
     parent = node;
@@ -449,3 +482,7 @@
     parent = oldParent;
   }
 }
+
+void checkInitializers(Constructor constructor) {
+  // TODO(ahe): I'll add more here in other CLs.
+}
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index bbefd95..5aec3f7 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -51,6 +51,9 @@
   R visitBoolLiteral(BoolLiteral node) => defaultBasicLiteral(node);
   R visitNullLiteral(NullLiteral node) => defaultBasicLiteral(node);
   R visitLet(Let node) => defaultExpression(node);
+  R visitLoadLibrary(LoadLibrary node) => defaultExpression(node);
+  R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) =>
+      defaultExpression(node);
 }
 
 abstract class StatementVisitor<R> {
@@ -155,6 +158,9 @@
   R visitBoolLiteral(BoolLiteral node) => defaultBasicLiteral(node);
   R visitNullLiteral(NullLiteral node) => defaultBasicLiteral(node);
   R visitLet(Let node) => defaultExpression(node);
+  R visitLoadLibrary(LoadLibrary node) => defaultExpression(node);
+  R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) =>
+      defaultExpression(node);
 
   // Statements
   R defaultStatement(Statement node) => defaultTreeNode(node);
@@ -204,6 +210,7 @@
 
   // Other tree nodes
   R visitLibrary(Library node) => defaultTreeNode(node);
+  R visitDeferredImport(DeferredImport node) => defaultTreeNode(node);
   R visitTypeParameter(TypeParameter node) => defaultTreeNode(node);
   R visitFunctionNode(FunctionNode node) => defaultTreeNode(node);
   R visitArguments(Arguments node) => defaultTreeNode(node);
diff --git a/pkg/kernel/test/baseline_spec_mode_test.dart b/pkg/kernel/test/baseline_spec_mode_test.dart
index f365d78..c4dda84 100644
--- a/pkg/kernel/test/baseline_spec_mode_test.dart
+++ b/pkg/kernel/test/baseline_spec_mode_test.dart
@@ -17,10 +17,15 @@
   bool get strongMode => false;
 
   @override
-  List<String> transformProgram(Program program) {
+  List<String> performModularTransformations(Program program) {
     new MixinFullResolution().transform(program);
     return const <String>[];
   }
+
+  @override
+  List<String> performGlobalTransformations(Program program) {
+    return const <String>[];
+  }
 }
 
 void main() {
diff --git a/pkg/kernel/test/baseline_strong_mode_test.dart b/pkg/kernel/test/baseline_strong_mode_test.dart
index 00ffcf0..e116f85 100644
--- a/pkg/kernel/test/baseline_strong_mode_test.dart
+++ b/pkg/kernel/test/baseline_strong_mode_test.dart
@@ -24,9 +24,14 @@
   bool get strongMode => true;
 
   @override
-  List<String> transformProgram(Program program) {
-    List<String> errors = <String>[];
+  List<String> performModularTransformations(Program program) {
     new MixinFullResolution().transform(program);
+    return const <String>[];
+  }
+
+  @override
+  List<String> performGlobalTransformations(Program program) {
+    List<String> errors = <String>[];
     new InsertTypeChecks().transformProgram(program);
     new InsertCovarianceChecks().transformProgram(program);
     new TestTypeChecker(
diff --git a/pkg/kernel/test/baseline_tester.dart b/pkg/kernel/test/baseline_tester.dart
index b954e20..e79251b 100644
--- a/pkg/kernel/test/baseline_tester.dart
+++ b/pkg/kernel/test/baseline_tester.dart
@@ -24,7 +24,9 @@
   /// Annotations to apply on the textual output.
   Annotator get annotator => null;
 
-  List<String> transformProgram(Program program);
+  // Return a list of strings so that we can accumulate errors.
+  List<String> performModularTransformations(Program program);
+  List<String> performGlobalTransformations(Program program);
 }
 
 void runBaselineTests(String folderName, TestTarget target) {
@@ -52,7 +54,10 @@
                 applicationRoot: applicationRoot));
         var program = loader.loadProgram(dartPath, target: target);
         verifyProgram(program);
-        var errors = target.transformProgram(program);
+        var errors = <String>[];
+        errors.addAll(target.performModularTransformations(program));
+        verifyProgram(program);
+        errors.addAll(target.performGlobalTransformations(program));
         verifyProgram(program);
 
         var buffer = new StringBuffer();
diff --git a/pkg/kernel/test/baseline_type_propagation_test.dart b/pkg/kernel/test/baseline_type_propagation_test.dart
index 3911df3..b8d03e9 100644
--- a/pkg/kernel/test/baseline_type_propagation_test.dart
+++ b/pkg/kernel/test/baseline_type_propagation_test.dart
@@ -24,8 +24,13 @@
   bool get strongMode => false;
 
   @override
-  List<String> transformProgram(Program program) {
+  List<String> performModularTransformations(Program program) {
     new MixinFullResolution().transform(program);
+    return const <String>[];
+  }
+
+  @override
+  List<String> performGlobalTransformations(Program program) {
     var visualizer = new Visualizer(program);
     var builder = new Builder(program, visualizer: visualizer);
     var solver = new Solver(builder);
diff --git a/pkg/kernel/test/closures/suite.dart b/pkg/kernel/test/closures/suite.dart
index 4c3b9a5..76e2c51 100644
--- a/pkg/kernel/test/closures/suite.dart
+++ b/pkg/kernel/test/closures/suite.dart
@@ -148,7 +148,9 @@
       for (var error in loader.errors) {
         return fail(program, "$error");
       }
-      target.transformProgram(program);
+      target
+        ..performModularTransformations(program)
+        ..performGlobalTransformations(program);
       return pass(program);
     } catch (e, s) {
       return crash(e, s);
diff --git a/pkg/kernel/testcases/strong-mode/covariant_generic.baseline.txt b/pkg/kernel/testcases/strong-mode/covariant_generic.baseline.txt
index 9b0d0d7..5bd8f3c 100644
--- a/pkg/kernel/testcases/strong-mode/covariant_generic.baseline.txt
+++ b/pkg/kernel/testcases/strong-mode/covariant_generic.baseline.txt
@@ -23,22 +23,22 @@
     this.{=self::Foo::setter} = x as self::Foo::T;
 }
 static method main() → dynamic {
-  self::Foo<core::int> fooInt = new self::Foo::•<core::int>(1, (core::int x) → void {});
+  self::Foo<core::int> fooInt = new self::Foo::•<core::int>(1, (core::int x) → core::Null {});
   fooInt.{self::Foo::method}(3);
   fooInt.{self::Foo::setter} = 3;
-  fooInt.{self::Foo::withCallback}((core::int x) → void {});
-  fooInt.{self::Foo::withCallback}((core::num x) → void {});
+  fooInt.{self::Foo::withCallback}((core::int x) → core::Null {});
+  fooInt.{self::Foo::withCallback}((core::num x) → core::Null {});
   fooInt.{self::Foo::mutableField} = 3;
-  fooInt.{self::Foo::mutableCallbackField} = (core::int x) → void {};
+  fooInt.{self::Foo::mutableCallbackField} = (core::int x) → core::Null {};
   self::Foo<core::num> fooNum = fooInt;
   fooNum.{self::Foo::method$cc}(3);
   fooNum.{self::Foo::method$cc}(2.5);
   fooNum.{self::Foo::setter$cc} = 3;
   fooNum.{self::Foo::setter$cc} = 2.5;
-  fooNum.{self::Foo::withCallback}((core::num x) → void {});
+  fooNum.{self::Foo::withCallback}((core::num x) → core::Null {});
   fooNum.{self::Foo::mutableField$cc} = 3;
   fooNum.{self::Foo::mutableField$cc} = 2.5;
   fooNum.{self::Foo::mutableCallbackField}.call(3);
   fooNum.{self::Foo::mutableCallbackField}.call(2.5);
-  fooNum.{self::Foo::mutableCallbackField} = (core::num x) → void {};
+  fooNum.{self::Foo::mutableCallbackField} = (core::num x) → core::Null {};
 }
diff --git a/pkg/meta/meta.iml b/pkg/meta/meta.iml
new file mode 100644
index 0000000..b89b508
--- /dev/null
+++ b/pkg/meta/meta.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.pub" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/packages" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Dart SDK" level="application" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 0bb8e1e..83593b4 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -20,12 +20,29 @@
 dev_compiler/test/codegen/*: Skip
 dev_compiler/gen/*: SkipByDesign
 
+# Anything in rasta is input to fasta unit tests and shouldn't be run as tests.
+front_end/test/fasta/rasta/*: SkipByDesign
+
+# sdk_test would take too long to complete, and should be run in a different
+# way.
+front_end/test/fasta/sdk_test: SkipByDesign
+
+front_end/test/fasta/compile_test: Pass, Slow
+
+[ $runtime != vm || $mode != release || $system == windows ]
+front_end/test/fasta/*: Skip
+
 [ $runtime == vm && $mode == release && $system == linux ]
 kernel/test/closures_test: Slow, Pass
+kernel/test/baseline_type_propagation_test: Slow, Pass
 
 [ $runtime != vm || $mode != release || $system != linux ]
 kernel/test/closures_test: Skip
 
+# Don't analyze tests in strong mode yet
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 # Analyze dev_compiler but don't run its tests
 [ $compiler != dart2analyzer ]
 dev_compiler/test/*: Skip
@@ -44,6 +61,20 @@
 
 [ $runtime == vm && $checked ]
 analysis_server/test/completion_test: Pass, Slow
+analysis_server/test/socket_server_test: Skip # Pass, Slow
+
+[ $runtime == vm && $checked && $system == windows ]
+front_end/tool/perf_test: Slow, Pass
+
+[ $runtime == vm && $use_sdk ]
+front_end/test/fasta/compile_test: Skip # Issue 28629
+front_end/test/fasta/kompile_test: Skip # Issue 28629
+front_end/test/fasta/outline_test: Skip # Issue 28629
+
+[ $runtime == vm && $use_sdk == false ]
+front_end/test/incremental_kernel_generator_test: Skip # Issue 28698
+front_end/test/incremental_resolved_ast_generator_test: Skip # Issue 28698
+front_end/tool/perf_test: Skip # Issue 28698
 
 [ $runtime == vm && $system == windows]
 analysis_server/*: Skip # Issue 27557
@@ -51,13 +82,18 @@
 analysis_server/test/integration/analysis/analysis_options_test: RuntimeError # Issue 24796
 analyzer/test/generated/all_the_rest_test: Fail # Issue 21772
 analyzer/test/generated/source_factory_test: RuntimeError # Issue 26828
-kernel/test/baseline_type_propagation_test: RuntimeError # Issue 28243
+kernel/test/baseline_type_propagation_test: RuntimeError, Timeout # Issue 28243
 kernel/test/baseline_spec_mode_test: RuntimeError # Issue 28243
 kernel/test/baseline_strong_mode_test: RuntimeError # Issue 28243
 
+[ $runtime == vm && $system == macos]
+kernel/test/baseline_type_propagation_test: Slow, Pass
+
 [ $compiler == dart2js ]
 analysis_server/test/integration: SkipByDesign # Analysis server integration tests don't make sense to run under dart2js, since the code under test always runs in the Dart vm as a subprocess.
 analyzer_cli/test/*: SkipByDesign # Only meant to run on vm
+analyzer_plugin/test/*: SkipByDesign # Only meant to run on vm
+analyzer_plugin/tool/*: SkipByDesign # Only meant to run on vm
 collection/test/equality_test/01: Fail # Issue 1533
 collection/test/equality_test/02: Fail # Issue 1533
 collection/test/equality_test/03: Fail # Issue 1533
@@ -153,9 +189,6 @@
 [ $compiler == dart2js && $runtime == chrome && $system == macos ]
 third_party/di_tests/di_test: Pass, Slow # Issue 22896
 
-[ $use_repository_packages ]
-analyzer/test/*: PubGetError
-
 [ $compiler == dart2js && $cps_ir && $host_checked ]
 analyzer/test/dart/ast/ast_test: Crash # Issue 24485
 analyzer/test/dart/ast/visitor_test: Crash # Issue 24485
diff --git a/pkg/pkgbuild.status b/pkg/pkgbuild.status
index 7ba877f..4fbd4ac 100644
--- a/pkg/pkgbuild.status
+++ b/pkg/pkgbuild.status
@@ -2,16 +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.
 
-[ $use_public_packages ]
-pkg/compiler: SkipByDesign # js_ast is not published
-third_party/pkg/linter: Skip # Issue 27937
-
-[ ($use_repository_packages || $use_public_packages) ]
-pkg/dev_compiler: SkipByDesign # we have relative paths to analyzer
 pkg/analyzer: Fail # Issue 27654
+pkg/analyzer_plugin: SkipByDesign # Issue 27937
+pkg/compiler: SkipByDesign # js_ast is not published
+pkg/dev_compiler: SkipByDesign # we have relative paths to analyzer
 pkg/front_end: Fail # Issue 27655
 pkg/kernel: SkipByDesign # Issue 27937
 third_party/pkg/linter: SkipByDesign # Issue 27937
-
-[ $use_repository_packages ]
-third_party/pkg_tested/dart_style: Fail # Issue https://github.com/dart-lang/dart_style/issues/562
diff --git a/pkg/testing/README.md b/pkg/testing/README.md
new file mode 100644
index 0000000..e32ab37
--- /dev/null
+++ b/pkg/testing/README.md
@@ -0,0 +1,265 @@
+<!--
+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.
+-->
+# Test Infrastructure without Batteries
+
+This package:
+
+  * Provides a way to test a compiler in multiple steps.
+
+  * Provides a way to run standalone tests. A standalone test is a test that has a `main` method, and can be run as a standalone program.
+
+  * Ensures all tests and implementations are free of warnings (using dartanalyzer).
+
+This package is not:
+
+  * A replacement for `package:test`. This package can be used to run `package:test` tests, and `package:test` can be viewed as the batteries that aren't included in this package.
+
+## Motivation
+
+We want to test tool chains, for example, a Dart compiler. Depending on the tool chain, it may comprise several individual steps. For example, to test dart2js, you have these steps:
+
+  1. Run dart2js on a Dart source file to produce a Javascript output file.
+
+  2. Run the Javascript file from step 1 on a Javascript interpreter and report if the program threw an exception.
+
+On the other hand, to test a Dart VM, there's only one step:
+
+  1. Run the Dart source file in the Dart VM and report if the program threw an exception.
+
+Similarly, to test dartanalyzer, there's also a single step:
+
+  1. Analyze the Dart source file and report if there were any problems.
+
+In general, a tool chain can have more steps, for example, a pub transformer.
+
+Furthermore, multiple tool chains may share the input sources and should agree on the behavior. For example, you should be able to compile `hello-world.dart` with dart2js and run it on d8 and it shouldn't throw an exception, running `hello-world.dart` on the Dart VM shouldn't throw an exception, and analysing it with dartanalyzer should report nothing.
+
+In addition, parts of the tool chain may have been implemented in Dart and have unit tests written in Dart, for example, using [package:test](https://github.com/dart-lang/test). We want to run these unit tests, and have noticed that compiler unit tests in general run faster when run from the same Dart VM process (due to dynamic optimizations kicking in). For this reason, it's convenient to have a single Dart program that runs all tests. On the other hand, when developing, it's often convenient to run just a single test.
+
+For this reason, we want to support running unit tests individually, or combined in one program. And we also want the Dart-based implementation to be free of problems with respect to dartanalyzer.
+
+## Test Suites
+
+A test suite is a collection of tests. Based on the above motivation, we have two kinds of suites:
+
+  1. [Chain](#Chain), a test suite for tool chains.
+
+  2. [Dart](#Dart), a test suite for Dart-based unit tests.
+
+## Getting Started
+
+  1. Create a [configuration file](#Configuration) named `testing.json`.
+
+  2. Run `bin/run_tests.dart`.
+
+## Configuration
+
+The test runner is configured using a JSON file. A minimal configuration file is:
+
+```json
+{
+}
+```
+
+### Chain
+
+A `Chain` suite is a suite that's designed to test a tool chain and can be used to test anything that can be divided into one or more steps.
+
+Here a complete example of a `Chain` suite:
+
+```json
+{
+  "suites": [
+    {
+      "name": "golden",
+      "kind": "Chain",
+      "source": "test/golden_suite.dart",
+      "path": "test/golden/",
+      "status": "test/golden.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+      ]
+    }
+  ]
+}
+```
+
+The properties of a `Chain` suite are:
+
+*name*: a name for the suite. For simple packages, `test` or the package name are good candidates. In the Dart SDK, for example, it would be things like `language`, `corelib`, etc.
+
+*kind*: always `Chain` for this kind of suite.
+
+*source*: a relative URI to a Dart program that implements the steps in the suite. See [below](#Implementing-a-Chain-Suite).
+
+*path*: a URI relative to the configuration file which is the root directory of all files in this suite. For now, only file URIs are supported. Each file is passed to the first step in the suite.
+
+*status*: a URI relative to the configuration file which lists the status of tests.
+
+*pattern*: a list of regular expressions that match file names that are tests.
+
+*exclude*: a list of regular expressions that exclude files from being included in this suite.
+
+#### Implementing a Chain Suite
+
+The `source` property of a `Chain` suite is a Dart program that must provide a top-level method with this name and signature:
+
+```dart
+Future<ChainContext> createContext(Chain suite) async { ... }
+```
+
+A suite is expected to implement a subclass of `ChainContext` which defines the steps that make up the chain and return it from `createContext`.
+
+A step is a subclass of `Step`. The input to the first step is a `TestDescription`. The input to step n+1 is the output of step n.
+
+Here is an example of a suite that runs tests on the Dart VM:
+
+```dart
+import 'testing.dart';
+
+Future<ChainContext> createContext(
+    Chain suite, Map<String, String> enviroment) async {
+  return new VmContext();
+}
+
+class VmContext extends ChainContext {
+  final List<Step> steps = const <Step>[const DartVmStep()];
+}
+
+class DartVmStep extends Step<TestDescription, int, VmContext> {
+  const DartVmStep();
+
+  String get name => "Dart VM";
+
+  Future<Result<int>> run(TestDescription input, VmContext context) async {
+    StdioProcess process = await StdioProcess.run("dart", [input.file.path]);
+    return process.toResult();
+  }
+}
+
+main(List<String> arguments) => runMe(arguments, createContext);
+```
+
+An example with multiple steps in the chain can be found in the Kernel package's [suite](https://github.com/dart-lang/kernel/blob/closure_conversion/test/closures/suite.dart). Notice how this suite stores an `AnalysisContext` in its `TestContext` and is this way able to reuse the same `AnalysisContext` in all tests.
+
+### Dart
+
+The `Dart` suite is for running unit tests written in Dart. Each test is a Dart program with a main method that can be run directly from the command line.
+
+The suite generates a new Dart program which combines all the tests included in the suite, so they can all be run (in sequence) in the same process. Such tests must be co-operative and must clean up after themselves.
+
+You can use any test-framework, for example, `package:test` in these individual programs, as long as the frameworks are well-behaved with respect to global state, see [below](#Well-Behaved-Tests).
+
+Here is a complete example of a `Dart` suite:
+
+```json
+{
+  "suites": [
+    {
+      "name": "my-package",
+      "path": "test/",
+      "kind": "Dart",
+      "pattern": [
+        "_test\\.dart$"
+      ],
+      "exclude": [
+        "/test/golden/"
+      ]
+    }
+  ]
+}
+```
+
+The properties of a `Dart` suite are:
+
+*name*: a name for the suite. For simple packages, `test` or the package name are good candidates. In the Dart SDK, for example, the names could be the name of the component that's tested by this suite's unit tests, for example, `dart2js`.
+
+*path*: a URI relative to the configuration file which is the root directory of all files in this suite. For now, only file URIs are supported.
+
+*kind*: always `Dart` for this kind of suite.
+
+*pattern*: a list of regular expressions that match file names that are tests.
+
+*exclude*: a list of regular expressions that exclude files from being included in this suite.
+
+#### Well-Behaved Tests
+
+The `Dart` suite makes certain assumptions about the tests it runs.
+
+ * All tests use the same packages configuration file.
+
+ * An asynchronous test returns a `Future` from its `main`.
+
+ * Tests manages global state.
+
+All tests are imported into the same program as individual libraries, which is why they all must use the same `.packages` file. The tests aren't concatenated, so they have the lexical scope you'd normally expect from a Dart library.
+
+Tests are run in order. In particular, the test framework will not start the next test until any future returned from the current test's `main` method complete. In addition, asynchronous tests are expected to have finished all asynchronous operations when the future returned from their `main` method completes (with or without an error).
+
+Tests are expected to manage global state (aka static state). Simply put: clean up after yourself. But if it's simpler to ensure global state is reset before running a test and not clean up afterwards, that's also fine as long as all tests agree on how to manage their shared global state.
+
+### Configuring Analyzed Programs
+
+By default, all tests in `Dart` suites are analyzed by the `dartanalyzer`. It is possible to exclude tests from analysis, and it's possible to add additional files to be analyzed. Here is a complete example of a `Dart` suite and analyzer configuration:
+
+```json
+{
+  "suites": [
+    {
+      "name": "my-package",
+      "path": "test/",
+      "kind": "Dart",
+      "pattern": [
+        "_test\\.dart$"
+      ],
+      "exclude": [
+        "/test/golden/"
+      ]
+    }
+  ],
+  "analyze": {
+    "uris": [
+      "lib/",
+    ],
+    "exclude": [
+      "/third_party/"
+    ]
+  }
+}
+```
+
+The properties of the `analyze` section are:
+
+*uris*: a list of URIs relative to the configuration file that should also be analyzed. For now, only file URIs are supported.
+
+*exclude*: a list of regular expression that matches file names that should be excluded from analysis. For now, the files are still analyzed but diagnostics are suppressed and ignored.
+
+## Integrating with Other Test Runners
+
+### `test.dart`
+
+To run the suite `my_suite` from `test.dart`, create a file named `mysuite_test.dart` with this content:
+
+    import 'package:async_helper/async_helper.dart' show asyncTest;
+
+    import 'package:testing/testing.dart' show run;
+
+    main(List<String> arguments) => asyncTest(run(arguments, ["my_suite"]));
+
+### `package:test`
+
+To run the suite `my_suite` from `package:test`, create a file named `mysuite_test.dart` with this content:
+
+    import 'package:test/test.dart' show Timeout, test;
+
+    import 'package:testing/testing.dart' show run;
+
+    main() {
+      test("my_suite", () => run([], ["my_suite"]),
+          timeout: new Timeout(new Duration(minutes: 5)));
+    }
diff --git a/pkg/testing/bin/run_tests.dart b/pkg/testing/bin/run_tests.dart
new file mode 100755
index 0000000..06581f6
--- /dev/null
+++ b/pkg/testing/bin/run_tests.dart
@@ -0,0 +1,8 @@
+#!/usr/bin/env dart -c
+// 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.
+
+import "package:testing/src/run_tests.dart" as run_tests;
+
+main(List<String> arguments) => run_tests.main(arguments);
diff --git a/pkg/testing/bin/testing.dart b/pkg/testing/bin/testing.dart
new file mode 100644
index 0000000..2e01c72
--- /dev/null
+++ b/pkg/testing/bin/testing.dart
@@ -0,0 +1,7 @@
+// 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.
+
+import "package:testing/src/run_tests.dart" as run_tests;
+
+main(List<String> arguments) => run_tests.main(arguments);
diff --git a/pkg/testing/lib/dart_vm_suite.dart b/pkg/testing/lib/dart_vm_suite.dart
new file mode 100644
index 0000000..0edfdbc
--- /dev/null
+++ b/pkg/testing/lib/dart_vm_suite.dart
@@ -0,0 +1,29 @@
+// 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.
+
+library testing.dart_vm_suite;
+
+import 'testing.dart';
+
+Future<ChainContext> createContext(
+    Chain suite, Map<String, String> enviroment) async {
+  return new VmContext();
+}
+
+class VmContext extends ChainContext {
+  final List<Step> steps = const <Step>[const DartVmStep()];
+}
+
+class DartVmStep extends Step<TestDescription, int, VmContext> {
+  const DartVmStep();
+
+  String get name => "Dart VM";
+
+  Future<Result<int>> run(TestDescription input, VmContext context) async {
+    StdioProcess process = await StdioProcess.run("dart", [input.file.path]);
+    return process.toResult();
+  }
+}
+
+main(List<String> arguments) => runMe(arguments, createContext);
diff --git a/pkg/testing/lib/src/analyze.dart b/pkg/testing/lib/src/analyze.dart
new file mode 100644
index 0000000..1a7503a
--- /dev/null
+++ b/pkg/testing/lib/src/analyze.dart
@@ -0,0 +1,154 @@
+// 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.
+
+library testing.analyze;
+
+import 'dart:async' show
+    Stream,
+    Future;
+
+import 'dart:convert' show
+    LineSplitter,
+    UTF8;
+
+import 'dart:io' show
+    File,
+    Process;
+
+import '../testing.dart' show
+    dartSdk;
+
+import 'log.dart' show
+    isVerbose;
+
+import 'suite.dart' show
+    Suite;
+
+class Analyze extends Suite {
+  final List<Uri> uris;
+
+  final List<RegExp> exclude;
+
+  Analyze(this.uris, this.exclude)
+      : super("analyze", "analyze", null);
+
+  Future<Null> run(Uri packages, List<Uri> extraUris) {
+    List<Uri> allUris = new List<Uri>.from(uris);
+    if (extraUris != null) {
+      allUris.addAll(extraUris);
+    }
+    return analyzeUris(packages, allUris, exclude);
+  }
+
+  static Future<Analyze> fromJsonMap(
+      Uri base, Map json, List<Suite> suites) async {
+    List<Uri> uris = new List<Uri>.from(
+        json["uris"].map((String relative) => base.resolve(relative)));
+
+    List<RegExp> exclude =
+        new List<RegExp>.from(json["exclude"].map((String p) => new RegExp(p)));
+
+    return new Analyze(uris, exclude);
+  }
+
+  String toString() => "Analyze($uris, $exclude)";
+}
+
+class AnalyzerDiagnostic {
+  final String kind;
+
+  final String detailedKind;
+
+  final String code;
+
+  final Uri uri;
+
+  final int line;
+
+  final int startColumn;
+
+  final int endColumn;
+
+  final String message;
+
+  AnalyzerDiagnostic(this.kind, this.detailedKind, this.code, this.uri,
+      this.line, this.startColumn, this.endColumn, this.message);
+
+  factory AnalyzerDiagnostic.fromLine(String line) {
+    List<String> parts = line.split("|");
+    if (parts.length != 8) {
+      throw "Malformed output: $line";
+    }
+    return new AnalyzerDiagnostic(parts[0], parts[1], parts[2],
+        Uri.base.resolve(parts[3]),
+        int.parse(parts[4]), int.parse(parts[5]), int.parse(parts[6]),
+        parts[7]);
+  }
+
+  String toString() {
+    return "$uri:$line:$startColumn: "
+        "${kind == 'INFO' ? 'warning: hint' : kind.toLowerCase()}:\n"
+        "[$code] $message";
+  }
+}
+
+Stream<AnalyzerDiagnostic> parseAnalyzerOutput(
+    Stream<List<int>> stream) async* {
+  Stream<String> lines =
+      stream.transform(UTF8.decoder).transform(new LineSplitter());
+  await for (String line in lines) {
+    yield new AnalyzerDiagnostic.fromLine(line);
+  }
+}
+
+/// Run dartanalyzer on all tests in [uris].
+Future<Null> analyzeUris(
+    Uri packages, List<Uri> uris, List<RegExp> exclude) async {
+  if (uris.isEmpty) return;
+  const String analyzerPath = "bin/dartanalyzer";
+  Uri analyzer = dartSdk.resolve(analyzerPath);
+  if (!await new File.fromUri(analyzer).exists()) {
+    throw "Couldn't find '$analyzerPath' in '${dartSdk.toFilePath()}'";
+  }
+  List<String> arguments = <String>[
+      "--packages=${packages.toFilePath()}",
+      "--package-warnings",
+      "--format=machine",
+  ];
+  arguments.addAll(uris.map((Uri uri) => uri.toFilePath()));
+  if (isVerbose) {
+    print("Running:\n  ${analyzer.toFilePath()} ${arguments.join(' ')}");
+  } else {
+    print("Running dartanalyzer.");
+  }
+  Stopwatch sw = new Stopwatch()..start();
+  Process process = await Process.start(analyzer.toFilePath(), arguments);
+  process.stdin.close();
+  Future stdoutFuture = parseAnalyzerOutput(process.stdout).toList();
+  Future stderrFuture = parseAnalyzerOutput(process.stderr).toList();
+  await process.exitCode;
+  List<AnalyzerDiagnostic> diagnostics = <AnalyzerDiagnostic>[];
+  diagnostics.addAll(await stdoutFuture);
+  diagnostics.addAll(await stderrFuture);
+  bool hasOutput = false;
+  Set<String> seen = new Set<String>();
+  for (AnalyzerDiagnostic diagnostic in diagnostics) {
+    String path = diagnostic.uri.path;
+    if (diagnostic.code == "DEPRECATED_MEMBER_USE") continue;
+    if (diagnostic.code == "MISSING_RETURN") continue;
+    if (diagnostic.code == "UNNECESSARY_CAST") continue;
+    if (exclude.any((RegExp r) => path.contains(r))) continue;
+    String message = "$diagnostic";
+    if (seen.add(message)) {
+      hasOutput = true;
+      print(message);
+    }
+  }
+  if (hasOutput) {
+    throw "Non-empty output from analyzer.";
+  }
+  sw.stop();
+  print("Running analyzer took: ${sw.elapsed}.");
+}
+
diff --git a/pkg/testing/lib/src/chain.dart b/pkg/testing/lib/src/chain.dart
new file mode 100644
index 0000000..4f970c1
--- /dev/null
+++ b/pkg/testing/lib/src/chain.dart
@@ -0,0 +1,363 @@
+// 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.
+
+library testing.chain;
+
+import 'dart:async' show
+    Future,
+    Stream;
+
+import 'dart:convert' show
+    JSON,
+    JsonEncoder;
+
+import 'dart:io' show
+    Directory,
+    File,
+    FileSystemEntity,
+    exitCode;
+
+import 'suite.dart' show
+    Suite;
+
+import '../testing.dart' show
+    TestDescription;
+
+import 'test_dart/status_file_parser.dart' show
+    ReadTestExpectations,
+    TestExpectations;
+
+import 'zone_helper.dart' show
+    runGuarded;
+
+import 'error_handling.dart' show
+    withErrorHandling;
+
+import 'log.dart' show
+    logMessage,
+    logStepComplete,
+    logStepStart,
+    logSuiteComplete,
+    logTestComplete,
+    logUnexpectedResult,
+    splitLines;
+
+import 'multitest.dart' show
+    MultitestTransformer,
+    isError;
+
+import 'expectation.dart' show
+    Expectation,
+    ExpectationSet;
+
+typedef Future<ChainContext> CreateContext(
+    Chain suite, Map<String, String> environment);
+
+/// A test suite for tool chains, for example, a compiler.
+class Chain extends Suite {
+  final Uri source;
+
+  final Uri uri;
+
+  final List<RegExp> pattern;
+
+  final List<RegExp> exclude;
+
+  final bool processMultitests;
+
+  Chain(String name, String kind, this.source, this.uri, Uri statusFile,
+      this.pattern, this.exclude, this.processMultitests)
+      : super(name, kind, statusFile);
+
+  factory Chain.fromJsonMap(Uri base, Map json, String name, String kind) {
+    Uri source = base.resolve(json["source"]);
+    Uri uri = base.resolve(json["path"]);
+    Uri statusFile = base.resolve(json["status"]);
+    List<RegExp> pattern = new List<RegExp>.from(
+        json["pattern"].map((String p) => new RegExp(p)));
+    List<RegExp> exclude = new List<RegExp>.from(
+        json["exclude"].map((String p) => new RegExp(p)));
+    bool processMultitests = json["process-multitests"] ?? false;
+    return new Chain(name, kind, source, uri, statusFile, pattern, exclude,
+        processMultitests);
+  }
+
+  void writeImportOn(StringSink sink) {
+    sink.write("import '");
+    sink.write(source);
+    sink.write("' as ");
+    sink.write(name);
+    sink.writeln(";");
+  }
+
+  void writeClosureOn(StringSink sink) {
+    sink.write("await runChain(");
+    sink.write(name);
+    sink.writeln(".createContext, environment, selectors, r'''");
+    const String jsonExtraIndent = "    ";
+    sink.write(jsonExtraIndent);
+    sink.writeAll(splitLines(new JsonEncoder.withIndent("  ").convert(this)),
+        jsonExtraIndent);
+    sink.writeln("''');");
+  }
+
+  Map toJson() {
+    return {
+      "name": name,
+      "kind": kind,
+      "source": "$source",
+      "path": "$uri",
+      "status": "$statusFile",
+      "process-multitests": processMultitests,
+      "pattern": []..addAll(pattern.map((RegExp r) => r.pattern)),
+      "exclude": []..addAll(exclude.map((RegExp r) => r.pattern)),
+    };
+  }
+}
+
+abstract class ChainContext {
+  const ChainContext();
+
+  List<Step> get steps;
+
+  ExpectationSet get expectationSet => ExpectationSet.Default;
+
+  Future<Null> run(Chain suite, Set<String> selectors) async {
+    TestExpectations expectations = await ReadTestExpectations(
+        <String>[suite.statusFile.toFilePath()], {}, expectationSet);
+    Stream<TestDescription> stream = list(suite);
+    if (suite.processMultitests) {
+      stream = stream.transform(new MultitestTransformer());
+    }
+    List<TestDescription> descriptions = await stream.toList();
+    descriptions.sort();
+    Map<TestDescription, Result> unexpectedResults =
+        <TestDescription, Result>{};
+    Map<TestDescription, Set<Expectation>> unexpectedOutcomes =
+        <TestDescription, Set<Expectation>>{};
+    int completed = 0;
+    List<Future> futures = <Future>[];
+    for (TestDescription description in descriptions) {
+      String selector = "${suite.name}/${description.shortName}";
+      if (selectors.isNotEmpty &&
+          !selectors.contains(selector) &&
+          !selectors.contains(suite.name)) {
+        continue;
+      }
+      final Set<Expectation> expectedOutcomes =
+          expectations.expectations(description.shortName);
+      final StringBuffer sb = new StringBuffer();
+      final Step lastStep = steps.isNotEmpty ? steps.last : null;
+      final Iterator<Step> iterator = steps.iterator;
+
+      Result result;
+      // Records the outcome of the last step that was run.
+      Step lastStepRun;
+
+      /// Performs one step of [iterator].
+      ///
+      /// If `step.isAsync` is true, the corresponding step is said to be
+      /// asynchronous.
+      ///
+      /// If a step is asynchrouns the future returned from this function will
+      /// complete after the the first asynchronous step is scheduled.  This
+      /// allows us to start processing the next test while an external process
+      /// completes as steps can be interleaved. To ensure all steps are
+      /// completed, wait for [futures].
+      ///
+      /// Otherwise, the future returned will complete when all steps are
+      /// completed. This ensures that tests are run in sequence without
+      /// interleaving steps.
+      Future doStep(dynamic input) async {
+        Future future;
+        bool isAsync = false;
+        if (iterator.moveNext()) {
+          Step step = iterator.current;
+          lastStepRun = step;
+          isAsync = step.isAsync;
+          logStepStart(completed, unexpectedResults.length, descriptions.length,
+              suite, description, step);
+          // TODO(ahe): It's important to share the zone error reporting zone
+          // between all the tasks. Otherwise, if a future completes with an
+          // error in one zone, and gets stored, it becomes an uncaught error
+          // in other zones (this happened in createPlatform).
+          future = runGuarded(() async {
+            try {
+              return await step.run(input, this);
+            } catch (error, trace) {
+              return step.unhandledError(error, trace);
+            }
+          }, printLineOnStdout: sb.writeln);
+        } else {
+          future = new Future.value(null);
+        }
+        future = future.then((Result currentResult) {
+          if (currentResult != null) {
+            logStepComplete(completed, unexpectedResults.length,
+                descriptions.length, suite, description, lastStepRun);
+            result = currentResult;
+            if (currentResult.outcome == Expectation.Pass) {
+              // The input to the next step is the output of this step.
+              return doStep(result.output);
+            }
+          }
+          if (description.multitestExpectations != null) {
+            if (isError(description.multitestExpectations)) {
+              result = toNegativeTestResult(
+                  result, description.multitestExpectations);
+            }
+          } else if (lastStep == lastStepRun &&
+              description.shortName.endsWith("negative_test")) {
+            if (result.outcome == Expectation.Pass) {
+              result.addLog("Negative test didn't report an error.\n");
+            } else if (result.outcome == Expectation.Fail) {
+              result.addLog("Negative test reported an error as expeceted.\n");
+            }
+            result = toNegativeTestResult(result);
+          }
+          if (!expectedOutcomes.contains(result.outcome)) {
+            result.addLog("$sb");
+            unexpectedResults[description] = result;
+            unexpectedOutcomes[description] = expectedOutcomes;
+            logUnexpectedResult(suite, description, result, expectedOutcomes);
+            exitCode = 1;
+          } else {
+            logMessage(sb);
+          }
+          logTestComplete(++completed, unexpectedResults.length,
+              descriptions.length, suite, description);
+        });
+        if (isAsync) {
+          futures.add(future);
+          return null;
+        } else {
+          return future;
+        }
+      }
+      // The input of the first step is [description].
+      await doStep(description);
+    }
+    await Future.wait(futures);
+    logSuiteComplete();
+    if (unexpectedResults.isNotEmpty) {
+      unexpectedResults.forEach((TestDescription description, Result result) {
+        logUnexpectedResult(suite, description, result,
+            unexpectedOutcomes[description]);
+      });
+      print("${unexpectedResults.length} failed:");
+      unexpectedResults.forEach((TestDescription description, Result result) {
+        print("${suite.name}/${description.shortName}: ${result.outcome}");
+      });
+    }
+  }
+
+  Stream<TestDescription> list(Chain suite) async* {
+    Directory testRoot = new Directory.fromUri(suite.uri);
+    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 TestDescription(suite.uri, entity);
+        }
+      }
+    } else {
+      throw "${suite.uri} isn't a directory";
+    }
+  }
+
+  Result toNegativeTestResult(Result result, [Set<String> expectations]) {
+    Expectation outcome = result.outcome;
+    if (outcome == Expectation.Pass) {
+      if (expectations == null) {
+        outcome = Expectation.Fail;
+      } else if (expectations.contains("compile-time error")) {
+        outcome = expectationSet["MissingCompileTimeError"];
+      } else if (expectations.contains("runtime error") ||
+          expectations.contains("dynamic type error")) {
+        outcome = expectationSet["MissingRuntimeError"];
+      } else {
+        outcome = Expectation.Fail;
+      }
+    } else if (outcome == Expectation.Fail) {
+      outcome = Expectation.Pass;
+    }
+    return result.copyWithOutcome(outcome);
+  }
+}
+
+abstract class Step<I, O, C extends ChainContext> {
+  const Step();
+
+  String get name;
+
+  bool get isAsync => false;
+
+  bool get isCompiler => false;
+
+  bool get isRuntime => false;
+
+  Future<Result<O>> run(I input, C context);
+
+  Result<O> unhandledError(error, StackTrace trace) {
+    return new Result<O>.crash(error, trace);
+  }
+
+  Result<O> pass(O output) => new Result<O>.pass(output);
+
+  Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace);
+
+  Result<O> fail(O output, [error, StackTrace trace]) {
+    return new Result<O>.fail(output, error, trace);
+  }
+}
+
+class Result<O> {
+  final O output;
+
+  final Expectation outcome;
+
+  final error;
+
+  final StackTrace trace;
+
+  final List<String> logs = <String>[];
+
+  Result(this.output, this.outcome, this.error, this.trace);
+
+  Result.pass(O output)
+      : this(output, Expectation.Pass, null, null);
+
+  Result.crash(error, StackTrace trace)
+      : this(null, Expectation.Crash, error, trace);
+
+  Result.fail(O output, [error, StackTrace trace])
+      : this(output, Expectation.Fail, error, trace);
+
+  String get log => logs.join();
+
+  void addLog(String log) {
+    logs.add(log);
+  }
+
+  Result<O> copyWithOutcome(Expectation outcome) {
+    return new Result<O>(output, outcome, error, trace)
+        ..logs.addAll(logs);
+  }
+}
+
+/// This is called from generated code.
+Future<Null> runChain(
+    CreateContext f, Map<String, String> environment, Set<String> selectors,
+    String json) {
+  return withErrorHandling(() async {
+    Chain suite = new Suite.fromJsonMap(Uri.base, JSON.decode(json));
+    print("Running ${suite.name}");
+    ChainContext context = await f(suite, environment);
+    return context.run(suite, selectors);
+  });
+}
diff --git a/pkg/testing/lib/src/discover.dart b/pkg/testing/lib/src/discover.dart
new file mode 100644
index 0000000..2195947
--- /dev/null
+++ b/pkg/testing/lib/src/discover.dart
@@ -0,0 +1,95 @@
+// 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.
+
+library testing.discover;
+
+import 'dart:io' show
+    Directory,
+    FileSystemEntity,
+    Platform,
+    Process;
+
+import 'dart:async' show
+    Future,
+    Stream,
+    StreamController,
+    StreamSubscription;
+
+import '../testing.dart' show
+  TestDescription;
+
+final Uri packageConfig = computePackageConfig();
+
+final Uri dartSdk = computeDartSdk();
+
+/// Common arguments when running a dart program. Returns a copy that can
+/// safely be modified by caller.
+List<String> get dartArguments => <String>["-c", "--packages=$packageConfig"];
+
+Stream<TestDescription> listTests(List<Uri> testRoots, {Pattern pattern}) {
+  StreamController<TestDescription> controller =
+      new StreamController<TestDescription>();
+  Map<Uri, StreamSubscription> subscriptions = <Uri, StreamSubscription>{};
+  for (Uri testRootUri in testRoots) {
+    subscriptions[testRootUri] = null;
+    Directory testRoot = new Directory.fromUri(testRootUri);
+    testRoot.exists().then((bool exists) {
+      if (exists) {
+        Stream<FileSystemEntity> stream =
+            testRoot.list(recursive: true, followLinks: false);
+        var subscription = stream.listen((FileSystemEntity entity) {
+          TestDescription description =
+              TestDescription.from(testRootUri, entity, pattern: pattern);
+          if (description != null) {
+            controller.add(description);
+          }
+        }, onError: (error, StackTrace trace) {
+          controller.addError(error, trace);
+        }, onDone: () {
+          subscriptions.remove(testRootUri);
+          if (subscriptions.isEmpty) {
+            controller.close(); // TODO(ahe): catchError???
+          }
+        });
+        subscriptions[testRootUri] = subscription;
+      } else {
+        controller.addError("$testRootUri isn't a directory");
+        subscriptions.remove(testRootUri);
+      }
+      if (subscriptions.isEmpty) {
+        controller.close(); // TODO(ahe): catchError???
+      }
+    });
+  }
+  return controller.stream;
+}
+
+Uri computePackageConfig() {
+  String path = Platform.packageConfig;
+  if (path != null) return Uri.base.resolve(path);
+  return Uri.base.resolve(".packages");
+}
+
+Uri computeDartSdk() {
+  String dartSdkPath = Platform.environment["DART_SDK"]
+      ?? const String.fromEnvironment("DART_SDK");
+  if (dartSdkPath != null) {
+    return Uri.base.resolveUri(new Uri.file(dartSdkPath));
+  } else {
+    return Uri.base.resolve(Platform.resolvedExecutable).resolve("../");
+  }
+}
+
+Future<Process> startDart(
+    Uri program,
+    [List<String> arguments,
+     List<String> vmArguments]) {
+  List<String> allArguments = <String>[];
+  allArguments.addAll(vmArguments ?? dartArguments);
+  allArguments.add(program.toFilePath());
+  if (arguments != null) {
+    allArguments.addAll(arguments);
+  }
+  return Process.start(Platform.resolvedExecutable, allArguments);
+}
diff --git a/pkg/testing/lib/src/error_handling.dart b/pkg/testing/lib/src/error_handling.dart
new file mode 100644
index 0000000..325afed
--- /dev/null
+++ b/pkg/testing/lib/src/error_handling.dart
@@ -0,0 +1,30 @@
+// 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.
+
+library testing.error_handling;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    exitCode,
+    stderr;
+
+import 'dart:isolate' show
+    ReceivePort;
+
+Future withErrorHandling(Future f()) async {
+  final ReceivePort port = new ReceivePort();
+  try {
+    return await f();
+  } catch (e, trace) {
+    exitCode = 1;
+    stderr.writeln(e);
+    if (trace != null) {
+      stderr.writeln(trace);
+    }
+  } finally {
+    port.close();
+  }
+}
diff --git a/pkg/testing/lib/src/expectation.dart b/pkg/testing/lib/src/expectation.dart
new file mode 100644
index 0000000..0900c52
--- /dev/null
+++ b/pkg/testing/lib/src/expectation.dart
@@ -0,0 +1,120 @@
+// 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 testing.expectation;
+
+/// An expectation represents the expected outcome of a test (or if it should
+/// be skipped).
+///
+/// An expectation belongs to a group, for example, [ExpectationGroup.Fail].
+///
+/// Each expectation group has a canonical expectation, defined below. You can
+/// use the canonical expectation instead of a more specific one. Note this
+/// isn't implemented yet.
+class Expectation {
+  static const Expectation Pass =
+      const Expectation("Pass", ExpectationGroup.Pass);
+
+  static const Expectation Crash =
+      const Expectation("Crash", ExpectationGroup.Crash);
+
+  static const Expectation Timeout =
+      const Expectation("Timeout", ExpectationGroup.Timeout);
+
+  static const Expectation Fail =
+      const Expectation("Fail", ExpectationGroup.Fail);
+
+  static const Expectation Skip =
+      const Expectation("Skip", ExpectationGroup.Skip);
+
+  final String name;
+
+  final ExpectationGroup group;
+
+  const Expectation(this.name, this.group);
+
+  String toString() => name;
+}
+
+class ExpectationSet {
+  static const ExpectationSet Default = const ExpectationSet(
+      const <String, Expectation>{
+        "pass": Expectation.Pass,
+        "crash": Expectation.Crash,
+        "timeout": Expectation.Timeout,
+        "fail": Expectation.Fail,
+        "skip": Expectation.Skip,
+        "missingcompiletimeerror":
+            const Expectation("MissingCompileTimeError", ExpectationGroup.Fail),
+        "missingruntimeerror":
+            const Expectation("MissingRuntimeError", ExpectationGroup.Fail),
+      });
+
+  final Map<String, Expectation> internalMap;
+
+  const ExpectationSet(this.internalMap);
+
+  operator[] (String name) {
+    return internalMap[name.toLowerCase()]
+        ?? (throw "No expectation named: '$name'.");
+  }
+
+  factory ExpectationSet.fromJsonList(List data) {
+    Map<String, Expectation> internalMap =
+        new Map<String, Expectation>.from(Default.internalMap);
+    for (Map map in data) {
+      String name;
+      String group;
+      map.forEach((String key, String value) {
+        switch (key) {
+          case "name":
+            name = value;
+            break;
+
+          case "group":
+            group = value;
+            break;
+
+          default:
+            throw "Unrecoginized key: '$key' in '$map'.";
+        }
+      });
+      if (name == null) {
+        throw "No name provided in '$map'";
+      }
+      if (group == null) {
+        throw "No group provided in '$map'";
+      }
+      Expectation expectation = new Expectation(name, groupFromString(group));
+      name = name.toLowerCase();
+      if (internalMap.containsKey(name)) {
+        throw "Duplicated expectation name: '$name'.";
+      }
+      internalMap[name] = expectation;
+    }
+    return new ExpectationSet(internalMap);
+  }
+}
+
+enum ExpectationGroup {
+  Crash,
+  Fail,
+  Meta,
+  Pass,
+  Skip,
+  Timeout,
+}
+
+ExpectationGroup groupFromString(String name) {
+  switch (name) {
+    case "Crash": return ExpectationGroup.Crash;
+    case "Fail": return ExpectationGroup.Fail;
+    case "Meta": return ExpectationGroup.Meta;
+    case "Pass": return ExpectationGroup.Pass;
+    case "Skip": return ExpectationGroup.Skip;
+    case "Timeout": return ExpectationGroup.Timeout;
+    default:
+      throw "Unrecognized group: '$name'.";
+  }
+}
diff --git a/pkg/testing/lib/src/log.dart b/pkg/testing/lib/src/log.dart
new file mode 100644
index 0000000..5ff7cb8
--- /dev/null
+++ b/pkg/testing/lib/src/log.dart
@@ -0,0 +1,164 @@
+// 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.
+
+library testing.log;
+
+import 'chain.dart' show
+    Result,
+    Step;
+
+import 'suite.dart' show
+    Suite;
+
+import 'test_description.dart' show
+    TestDescription;
+
+import 'expectation.dart' show
+    Expectation;
+
+/// ANSI escape code for moving cursor one line up.
+/// See [CSI codes](https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes).
+const String cursorUp = "\u001b[1A";
+
+/// ANSI escape code for erasing the entire line.
+/// See [CSI codes](https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes).
+const String eraseLine = "\u001b[2K";
+
+final Stopwatch wallclock = new Stopwatch()..start();
+
+bool _isVerbose = const bool.fromEnvironment("verbose");
+
+bool get isVerbose => _isVerbose;
+
+void enableVerboseOutput() {
+  _isVerbose = true;
+}
+
+void logTestComplete(int completed, int failed, int total,
+    Suite suite, TestDescription description) {
+  String message = formatProgress(completed, failed, total);
+  if (suite != null) {
+    message += ": ${formatTestDescription(suite, description)}";
+  }
+  logProgress(message);
+}
+
+void logStepStart(int completed, int failed, int total,
+    Suite suite, TestDescription description, Step step) {
+  String message = formatProgress(completed, failed, total);
+  if (suite != null) {
+    message += ": ${formatTestDescription(suite, description)} ${step.name}";
+    if (step.isAsync) {
+      message += "...";
+    }
+  }
+  logProgress(message);
+}
+
+void logStepComplete(int completed, int failed, int total,
+    Suite suite, TestDescription description, Step step) {
+  if (!step.isAsync) return;
+  String message = formatProgress(completed, failed, total);
+  if (suite != null) {
+    message += ": ${formatTestDescription(suite, description)} ${step.name}!";
+  }
+  logProgress(message);
+}
+
+void logProgress(String message) {
+  if (isVerbose) {
+    print(message);
+  } else {
+    print("$eraseLine$message$cursorUp");
+  }
+}
+
+String formatProgress(int completed, int failed, int total) {
+  Duration elapsed = wallclock.elapsed;
+  String percent = pad((completed / total * 100.0).toStringAsFixed(1), 5);
+  String good = pad(completed - failed, 5);
+  String bad = pad(failed, 5);
+  String minutes = pad(elapsed.inMinutes, 2, filler: "0");
+  String seconds = pad(elapsed.inSeconds % 60, 2, filler: "0");
+  return "[ $minutes:$seconds | $percent% | +$good | -$bad ]";
+}
+
+String formatTestDescription(Suite suite, TestDescription description) {
+  return "${suite.name}/${description.shortName}";
+}
+
+void logMessage(Object message) {
+  if (isVerbose) {
+    print("$message");
+  }
+}
+
+void logNumberedLines(String text) {
+  if (isVerbose) {
+    print(numberedLines(text));
+  }
+}
+
+void logUnexpectedResult(Suite suite, TestDescription description,
+    Result result, Set<Expectation> expectedOutcomes) {
+  print("${eraseLine}UNEXPECTED: ${suite.name}/${description.shortName}");
+  Uri statusFile = suite.statusFile;
+  if (statusFile != null) {
+    String path = statusFile.toFilePath();
+    if (result.outcome == Expectation.Pass) {
+      print("The test unexpectedly passed, please update $path.");
+    } else {
+      print("The test had the outcome ${result.outcome}, but the status file "
+          "($path) allows these outcomes: ${expectedOutcomes.join(' ')}");
+    }
+  }
+  String log = result.log;
+  if (log.isNotEmpty) {
+    print(log);
+  }
+  if (result.error != null) {
+    print(result.error);
+    if (result.trace != null) {
+      print(result.trace);
+    }
+  }
+}
+
+void logSuiteComplete() {
+  if (!isVerbose) {
+    print("");
+  }
+}
+
+void logUncaughtError(error, StackTrace stackTrace) {
+  logMessage(error);
+  if (stackTrace != null) {
+    logMessage(stackTrace);
+  }
+}
+
+String pad(Object o, int pad, {String filler: " "}) {
+  String result = (filler * pad) + "$o";
+  return result.substring(result.length - pad);
+}
+
+String numberedLines(String text) {
+  StringBuffer result = new StringBuffer();
+  int lineNumber = 1;
+  List<String> lines = splitLines(text);
+  int pad = "${lines.length}".length;
+  String fill = " " * pad;
+  for (String line in lines) {
+    String paddedLineNumber = "$fill$lineNumber";
+    paddedLineNumber =
+        paddedLineNumber.substring(paddedLineNumber.length - pad);
+    result.write("$paddedLineNumber: $line");
+    lineNumber++;
+  }
+  return '$result';
+}
+
+List<String> splitLines(String text) {
+  return text.split(new RegExp('^', multiLine: true));
+}
diff --git a/pkg/testing/lib/src/multitest.dart b/pkg/testing/lib/src/multitest.dart
new file mode 100644
index 0000000..5d4d123
--- /dev/null
+++ b/pkg/testing/lib/src/multitest.dart
@@ -0,0 +1,137 @@
+// 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.
+
+library testing.multitest;
+
+import 'dart:async' show
+    Stream,
+    StreamTransformer;
+
+import 'dart:io' show
+    Directory,
+    File;
+
+import 'log.dart' show
+    splitLines;
+
+import 'test_description.dart' show
+    TestDescription;
+
+bool isError(Set<String> expectations) {
+  if (expectations.contains("compile-time error")) return true;
+  if (expectations.contains("runtime error")) return true;
+  return false;
+}
+
+bool isCheckedModeError(Set<String> expectations) {
+  if (expectations.contains("checked mode compile-time error")) return true;
+  if (expectations.contains("dynamic type error")) return true;
+  return isError(expectations);
+}
+
+class MultitestTransformer
+    implements StreamTransformer<TestDescription, TestDescription> {
+  static const String multitestMarker = "///";
+
+  static const List<String> validOutcomesList = const <String>[
+      "ok",
+      "compile-time error",
+      "runtime error",
+      "static type warning",
+      "dynamic type error",
+      "checked mode compile-time error",
+    ];
+
+  static final Set<String> validOutcomes =
+      new Set<String>.from(validOutcomesList);
+
+  Stream<TestDescription> bind(Stream<TestDescription> stream) async* {
+    List<String> errors = <String>[];
+    reportError(String error) {
+      errors.add(error);
+      print(error);
+    }
+    nextTest: await for (TestDescription test in stream) {
+      String contents = await test.file.readAsString();
+      if (!contents.contains(multitestMarker)) {
+        yield test;
+        continue nextTest;
+      }
+      // Note: this is modified in the loop below.
+      List<String> linesWithoutAnnotations = <String>[];
+      Map<String, List<String>> testsAsLines = <String, List<String>>{
+        "none": linesWithoutAnnotations,
+      };
+      Map<String, Set<String>> outcomes = <String, Set<String>>{
+        "none": new Set<String>(),
+      };
+      int lineNumber = 0;
+      for (String line in splitLines(contents)) {
+        lineNumber++;
+        int index = line.indexOf(multitestMarker);
+        String subtestName;
+        List<String> subtestOutcomesList;
+        if (index != -1) {
+          String annotationText =
+              line.substring(index + multitestMarker.length).trim();
+          index = annotationText.indexOf(":");
+          if (index != -1) {
+            subtestName = annotationText.substring(0, index).trim();
+            subtestOutcomesList = annotationText.substring(index + 1).split(",")
+                .map((s) => s.trim()).toList();
+            if (subtestName == "none") {
+              reportError(test.formatError(
+                      "$lineNumber: $subtestName can't be used as test name."));
+              continue nextTest;
+            }
+            if (subtestOutcomesList.isEmpty) {
+              reportError(test.formatError(
+                      "$lineNumber: Expected <testname>:<outcomes>"));
+              continue nextTest;
+            }
+          }
+        }
+        if (subtestName != null) {
+          List<String> lines = testsAsLines.putIfAbsent(subtestName,
+              () => new List<String>.from(linesWithoutAnnotations));
+          lines.add(line);
+          Set<String> subtestOutcomes = outcomes.putIfAbsent(subtestName,
+              () => new Set<String>());
+          if (subtestOutcomesList.length != 1 ||
+              subtestOutcomesList.single != "continued") {
+            for (String outcome in subtestOutcomesList) {
+              if (validOutcomes.contains(outcome)) {
+                subtestOutcomes.add(outcome);
+              } else {
+                reportError(test.formatError(
+                        "$lineNumber: '$outcome' isn't a recognized outcome."));
+                continue nextTest;
+              }
+            }
+          }
+        } else {
+          for (List<String> lines in testsAsLines.values) {
+            // This will also modify [linesWithoutAnnotations].
+            lines.add(line);
+          }
+        }
+      }
+      Uri root = Uri.base.resolve("generated/");
+      Directory generated = new Directory.fromUri(root.resolve(test.shortName));
+      generated = await generated.create(recursive: true);
+      for (String name in testsAsLines.keys) {
+        List<String> lines = testsAsLines[name];
+        Uri uri = generated.uri.resolve("${name}_generated.dart");
+        TestDescription subtest =
+            new TestDescription(root, new File.fromUri(uri));
+        subtest.multitestExpectations = outcomes[name];
+        await subtest.file.writeAsString(lines.join(""));
+        yield subtest;
+      }
+    }
+    if (errors.isNotEmpty) {
+      throw "Error: ${errors.join("\n")}";
+    }
+  }
+}
diff --git a/pkg/testing/lib/src/run.dart b/pkg/testing/lib/src/run.dart
new file mode 100644
index 0000000..2f9feda
--- /dev/null
+++ b/pkg/testing/lib/src/run.dart
@@ -0,0 +1,280 @@
+// 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.
+
+library testing.run;
+
+import 'dart:async' show
+    Future,
+    Stream;
+
+import 'dart:convert' show
+    JSON;
+
+import 'dart:io' show
+    Platform;
+
+import 'dart:isolate' show
+    Isolate,
+    ReceivePort;
+
+import 'test_root.dart' show
+    TestRoot;
+
+import 'test_description.dart' show
+    TestDescription;
+
+import 'error_handling.dart' show
+    withErrorHandling;
+
+import 'chain.dart' show
+    CreateContext;
+
+import '../testing.dart' show
+    Chain,
+    ChainContext,
+    TestDescription,
+    listTests;
+
+import 'analyze.dart' show
+    Analyze;
+
+import 'log.dart' show
+    isVerbose,
+    logMessage,
+    logNumberedLines,
+    splitLines;
+
+import 'suite.dart' show
+    Dart,
+    Suite;
+
+import 'test_dart.dart' show
+    TestDart;
+
+import 'zone_helper.dart' show
+    acknowledgeControlMessages;
+
+Future<TestRoot> computeTestRoot(String configurationPath, Uri base) {
+  Uri configuration = configurationPath == null
+      ? Uri.base.resolve("testing.json")
+      : base.resolve(configurationPath);
+  return TestRoot.fromUri(configuration);
+}
+
+/// This is called from a Chain suite, and helps implement main. In most cases,
+/// main will look like this:
+///
+///     main(List<String> arguments) => runMe(arguments, createContext);
+///
+/// The optional argument [configurationPath] should be used when
+/// `testing.json` isn't located in the current working directory and is a path
+/// relative to `Platform.script`.
+Future<Null> runMe(
+    List<String> arguments, CreateContext f, [String configurationPath]) {
+  return withErrorHandling(() async {
+    TestRoot testRoot =
+        await computeTestRoot(configurationPath, Platform.script);
+    for (Chain suite in testRoot.toolChains) {
+      if (Platform.script == suite.source) {
+        print("Running suite ${suite.name}...");
+        ChainContext context = await f(suite, <String, String>{});
+        await context.run(suite, new Set<String>());
+      }
+    }
+  });
+}
+
+/// This is called from a `_test.dart` file, and helps integration in other
+/// test runner frameworks.
+///
+/// For example, to run the suite `my_suite` from `test.dart`, create a file
+/// with this content:
+///
+///     import 'package:async_helper/async_helper.dart' show asyncTest;
+///
+///     import 'package:testing/testing.dart' show run;
+///
+///     main(List<String> arguments) => asyncTest(run(arguments, ["my_suite"]));
+///
+/// To run run the same suite from `package:test`, create a file with this
+/// content:
+///
+///     import 'package:test/test.dart' show Timeout, test;
+///
+///     import 'package:testing/testing.dart' show run;
+///
+///     main() {
+///       test("my_suite", () => run([], ["my_suite"]),
+///           timeout: new Timeout(new Duration(minutes: 5)));
+///     }
+///
+/// The optional argument [configurationPath] should be used when
+/// `testing.json` isn't located in the current working directory and is a path
+/// relative to `Uri.base`.
+Future<Null> run(
+    List<String> arguments, List<String> suiteNames,
+    [String configurationPath]) {
+  return withErrorHandling(() async {
+    TestRoot root = await computeTestRoot(configurationPath, Uri.base);
+    List<Suite> suites = root.suites.where(
+        (Suite suite) => suiteNames.contains(suite.name)).toList();
+    SuiteRunner runner = new SuiteRunner(suites, <String, String>{}, null,
+        new Set<String>(), new Set<String>());
+    String program = await runner.generateDartProgram();
+    await runner.analyze(root.packages);
+    if (program != null) {
+      await runProgram(program, root.packages);
+    }
+  });
+}
+
+Future<Null> runProgram(String program, Uri packages) async {
+  logMessage("Running:");
+  logNumberedLines(program);
+  Uri dataUri = new Uri.dataFromString(program);
+  ReceivePort exitPort = new ReceivePort();
+  Isolate isolate = await Isolate.spawnUri(dataUri, <String>[], null,
+      paused: true, onExit: exitPort.sendPort, errorsAreFatal: false,
+      checked: true, packageConfig: packages);
+  List error;
+  var subscription = isolate.errors.listen((data) {
+    error = data;
+    exitPort.close();
+  });
+  await acknowledgeControlMessages(isolate, resume: isolate.pauseCapability);
+  await for (var _ in exitPort) {
+    exitPort.close();
+  }
+  subscription.cancel();
+  return error == null
+      ? null
+      : new Future<Null>.error(error[0], new StackTrace.fromString(error[1]));
+}
+
+class SuiteRunner {
+  final List<Suite> suites;
+
+  final Map<String, String> environment;
+
+  final List<String> selectors;
+
+  final Set<String> selectedSuites;
+
+  final Set<String> skippedSuites;
+
+  final List<Uri> testUris = <Uri>[];
+
+  SuiteRunner(this.suites, this.environment, Iterable<String> selectors,
+      this.selectedSuites, this.skippedSuites)
+      : selectors = selectors.toList(growable: false);
+
+  bool shouldRunSuite(Suite suite) {
+    return !skippedSuites.contains(suite.name) &&
+        (selectedSuites.isEmpty || selectedSuites.contains(suite.name));
+  }
+
+  Future<String> generateDartProgram() async {
+    testUris.clear();
+    StringBuffer imports = new StringBuffer();
+    StringBuffer dart = new StringBuffer();
+    StringBuffer chain = new StringBuffer();
+    bool hasRunnableTests = false;
+
+    await for (TestDescription description in listDescriptions()) {
+      hasRunnableTests = true;
+      description.writeImportOn(imports);
+      description.writeClosureOn(dart);
+    }
+
+    await for (Chain suite in listChainSuites()) {
+      hasRunnableTests = true;
+      suite.writeImportOn(imports);
+      suite.writeClosureOn(chain);
+    }
+
+    bool isFirstTestDartSuite = true;
+    for (TestDart suite in listTestDartSuites()) {
+      if (shouldRunSuite(suite)) {
+        hasRunnableTests = true;
+        if (isFirstTestDartSuite) {
+          suite.writeFirstImportOn(imports);
+        }
+        isFirstTestDartSuite = false;
+        suite.writeRunCommandOn(chain);
+      }
+    }
+
+    if (!hasRunnableTests) return null;
+
+    return """
+library testing.generated;
+
+import 'dart:async' show Future;
+
+import 'dart:convert' show JSON;
+
+import 'package:testing/src/run_tests.dart' show runTests;
+
+import 'package:testing/src/chain.dart' show runChain;
+
+import 'package:testing/src/log.dart' show enableVerboseOutput, isVerbose;
+
+${imports.toString().trim()}
+
+Future<Null> main() async {
+  if ($isVerbose) enableVerboseOutput();
+  Map<String, String> environment = JSON.decode('${JSON.encode(environment)}');
+  Set<String> selectors = JSON.decode('${JSON.encode(selectors)}').toSet();
+  await runTests(<String, Function> {
+      ${splitLines(dart.toString().trim()).join('      ')}
+  });
+  ${splitLines(chain.toString().trim()).join('  ')}
+}
+""";
+  }
+
+  Future<bool> analyze(Uri packages) async {
+    bool hasAnalyzerSuites = false;
+    for (Analyze suite in listAnalyzerSuites()) {
+      if (shouldRunSuite(suite)) {
+        hasAnalyzerSuites = true;
+        await suite.run(packages, testUris);
+      }
+    }
+    return hasAnalyzerSuites;
+  }
+
+  Stream<TestDescription> listDescriptions() async* {
+    for (Dart suite in suites.where((Suite suite) => suite is Dart)) {
+      await for (TestDescription description in
+                     listTests(<Uri>[suite.uri], pattern: "")) {
+        testUris.add(await Isolate.resolvePackageUri(description.uri));
+        if (shouldRunSuite(suite)) {
+          String path = description.file.uri.path;
+          if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
+          if (suite.pattern.any((RegExp r) => path.contains(r))) {
+            yield description;
+          }
+        }
+      }
+    }
+  }
+
+  Stream<Chain> listChainSuites() async* {
+    for (Chain suite in suites.where((Suite suite) => suite is Chain)) {
+      testUris.add(await Isolate.resolvePackageUri(suite.source));
+      if (shouldRunSuite(suite)) {
+        yield suite;
+      }
+    }
+  }
+
+  Iterable<Suite> listTestDartSuites() {
+    return suites.where((Suite suite) => suite is TestDart);
+  }
+
+  Iterable<Suite> listAnalyzerSuites() {
+    return suites.where((Suite suite) => suite is Analyze);
+  }
+}
diff --git a/pkg/testing/lib/src/run_tests.dart b/pkg/testing/lib/src/run_tests.dart
new file mode 100644
index 0000000..bc29a3b
--- /dev/null
+++ b/pkg/testing/lib/src/run_tests.dart
@@ -0,0 +1,200 @@
+// 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.
+
+library testing.run_tests;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:io' show
+    Directory,
+    File,
+    FileSystemEntity;
+
+import 'dart:io' as io show
+    exitCode;
+
+import 'dart:isolate' show
+    Isolate;
+
+import 'error_handling.dart' show
+    withErrorHandling;
+
+import 'test_root.dart' show
+    TestRoot;
+
+import 'zone_helper.dart' show
+    runGuarded;
+
+import 'log.dart' show
+    enableVerboseOutput,
+    isVerbose,
+    logMessage,
+    logSuiteComplete,
+    logTestComplete;
+
+import 'run.dart' show
+    SuiteRunner,
+    runProgram;
+
+class CommandLine {
+  final Set<String> options;
+  final List<String> arguments;
+
+  CommandLine(this.options, this.arguments);
+
+  bool get verbose => options.contains("--verbose") || options.contains("-v");
+
+  Set<String> get skip => commaSeparated("--skip=");
+
+  Set<String> commaSeparated(String prefix) {
+    return options.expand((String s) {
+      if (!s.startsWith(prefix)) return const [];
+      s = s.substring(prefix.length);
+      return s.split(",");
+    }).toSet();
+  }
+
+  Map<String, String> get environment {
+    Map<String, String> result = <String, String>{};
+    for (String option in options) {
+      if (option.startsWith("-D")) {
+        int equalIndex = option.indexOf("=");
+        if (equalIndex != -1) {
+          String key = option.substring(2, equalIndex);
+          String value = option.substring(equalIndex + 1);
+          result[key] = value;
+        }
+      }
+    }
+    return result;
+  }
+
+  Set<String> get selectedSuites {
+    return selectors.map((String selector) {
+      int index = selector.indexOf("/");
+      return index == -1 ? selector : selector.substring(0, index);
+    }).toSet();
+  }
+
+  Iterable<String> get selectors => arguments;
+
+  Future<Uri> get configuration async {
+    const String configPrefix = "--config=";
+    List<String> configurationPaths = options
+        .where((String option) => option.startsWith(configPrefix))
+        .map((String option) => option.substring(configPrefix.length))
+        .toList();
+    if (configurationPaths.length > 1) {
+      return fail("Only one --config option is supported");
+    }
+    String configurationPath;
+    if (configurationPaths.length == 1) {
+      configurationPath = configurationPaths.single;
+    } else {
+      configurationPath = "testing.json";
+      if (!await new File(configurationPath).exists()) {
+        Directory test = new Directory("test");
+        if (await test.exists()) {
+          List<FileSystemEntity> candiates =
+              await test.list(recursive: true, followLinks: false)
+              .where((FileSystemEntity entity) {
+                  return entity is File &&
+                  entity.uri.path.endsWith("/testing.json");
+                }).toList();
+          switch (candiates.length) {
+            case 0:
+              return fail("Couldn't locate: '$configurationPath'.");
+
+            case 1:
+              configurationPath = candiates.single.path;
+              break;
+
+            default:
+              return fail(
+                  "Usage: run_tests.dart [$configPrefix=configuration_file]\n"
+                  "Where configuration_file is one of:\n  "
+                  "${candiates.map((File file) => file.path).join('\n  ')}");
+          }
+        }
+      }
+    }
+    logMessage("Reading configuration file '$configurationPath'.");
+    Uri configuration =
+        await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath));
+    if (configuration == null ||
+        !await new File.fromUri(configuration).exists()) {
+      return fail("Couldn't locate: '$configurationPath'.");
+    }
+    return configuration;
+  }
+
+  static CommandLine parse(List<String> arguments) {
+    int index = arguments.indexOf("--");
+    Set<String> options;
+    if (index != -1) {
+      options = new Set<String>.from(arguments.getRange(0, index - 1));
+      arguments = arguments.sublist(index + 1);
+    } else {
+      options =
+          arguments.where((argument) => argument.startsWith("-")).toSet();
+      arguments =
+          arguments.where((argument) => !argument.startsWith("-")).toList();
+    }
+    return new CommandLine(options, arguments);
+  }
+}
+
+fail(String message) {
+  print(message);
+  io.exitCode = 1;
+  return null;
+}
+
+main(List<String> arguments) => withErrorHandling(() async {
+  CommandLine cl = CommandLine.parse(arguments);
+  if (cl.verbose) {
+    enableVerboseOutput();
+  }
+  Map<String, String> environment = cl.environment;
+  Uri configuration = await cl.configuration;
+  if (configuration == null) return;
+  if (!isVerbose) {
+    print("Use --verbose to display more details.");
+  }
+  TestRoot root = await TestRoot.fromUri(configuration);
+  SuiteRunner runner = new SuiteRunner(root.suites, environment, cl.selectors,
+      cl.selectedSuites, cl.skip);
+  String program = await runner.generateDartProgram();
+  bool hasAnalyzerSuites = await runner.analyze(root.packages);
+  Stopwatch sw = new Stopwatch()..start();
+  if (program == null) {
+    if (!hasAnalyzerSuites) {
+      fail("No tests configured.");
+    }
+  } else {
+    await runProgram(program, root.packages);
+  }
+  print("Running tests took: ${sw.elapsed}.");
+});
+
+Future<Null> runTests(Map<String, Function> tests) =>
+withErrorHandling(() async {
+  int completed = 0;
+  for (String name in tests.keys) {
+    StringBuffer sb = new StringBuffer();
+    try {
+      await runGuarded(() {
+        print("Running test $name");
+        return tests[name]();
+      }, printLineOnStdout: sb.writeln);
+      logMessage(sb);
+    } catch (e) {
+      print(sb);
+      rethrow;
+    }
+    logTestComplete(++completed, 0, tests.length, null, null);
+  }
+  logSuiteComplete();
+});
diff --git a/pkg/testing/lib/src/stdio_process.dart b/pkg/testing/lib/src/stdio_process.dart
new file mode 100644
index 0000000..35aa4e7
--- /dev/null
+++ b/pkg/testing/lib/src/stdio_process.dart
@@ -0,0 +1,94 @@
+// 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.
+
+library testing.stdio_process;
+
+import 'dart:async' show
+    EventSink,
+    Future,
+    Stream,
+    StreamTransformer,
+    Timer;
+
+import 'dart:convert' show
+    UTF8;
+
+import 'dart:io' show
+    Process,
+    ProcessSignal,
+    Stdout;
+
+import 'dart:io' as io show
+    stderr,
+    stdout;
+
+import 'chain.dart' show
+    Result;
+
+class StdioProcess {
+  final int exitCode;
+
+  final String output;
+
+  StdioProcess(this.exitCode, this.output);
+
+  Result<int> toResult({int expected: 0}) {
+    if (exitCode == expected) {
+      return new Result<int>.pass(exitCode);
+    } else {
+      return new Result<int>.fail(exitCode, output);
+    }
+  }
+
+  static StreamTransformer<String, String> transformToStdio(Stdout stdio) {
+    return new StreamTransformer<String, String>.fromHandlers(
+        handleData: (String data, EventSink<String> sink) {
+          sink.add(data);
+          stdio.write(data);
+        });
+  }
+
+  static Future<StdioProcess> run(
+      String executable, List<String> arguments,
+      {String input, Duration timeout: const Duration(seconds: 60),
+       bool suppressOutput: true}) async {
+    Process process = await Process.start(executable, arguments);
+    Timer timer;
+    StringBuffer sb = new StringBuffer();
+    if (timeout != null) {
+      timer = new Timer(timeout, () {
+        sb.write("Process timed out: ");
+        sb.write(executable);
+        sb.write(" ");
+        sb.writeAll(arguments, " ");
+        sb.writeln();
+        sb.writeln("Sending SIGTERM to process");
+        process.kill();
+        timer = new Timer(const Duration(seconds: 10), () {
+          sb.writeln("Sending SIGKILL to process");
+          process.kill(ProcessSignal.SIGKILL);
+        });
+      });
+    }
+    if (input != null) {
+      process.stdin.write(input);
+      await process.stdin.flush();
+    }
+    Future closeFuture = process.stdin.close();
+    Stream stdoutStream = process.stdout.transform(UTF8.decoder);
+    Stream stderrStream = process.stderr.transform(UTF8.decoder);
+    if (!suppressOutput) {
+      stdoutStream = stdoutStream.transform(transformToStdio(io.stdout));
+      stderrStream = stderrStream.transform(transformToStdio(io.stderr));
+    }
+    Future<List<String>> stdoutFuture = stdoutStream.toList();
+    Future<List<String>> stderrFuture = stderrStream.toList();
+    int exitCode = await process.exitCode;
+    timer?.cancel();
+    sb.writeAll(await stdoutFuture);
+    sb.writeAll(await stderrFuture);
+    await closeFuture;
+    return new StdioProcess(exitCode, "$sb");
+  }
+}
diff --git a/pkg/testing/lib/src/suite.dart b/pkg/testing/lib/src/suite.dart
new file mode 100644
index 0000000..e8007b2
--- /dev/null
+++ b/pkg/testing/lib/src/suite.dart
@@ -0,0 +1,90 @@
+// 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.
+
+library testing.suite;
+
+import 'chain.dart' show
+    Chain;
+
+import 'test_dart.dart' show
+    TestDart;
+
+/// Records the properties of a test suite.
+abstract class Suite {
+  final String name;
+
+  final String kind;
+
+  final Uri statusFile;
+
+  Suite(this.name, this.kind, this.statusFile);
+
+  factory Suite.fromJsonMap(Uri base, Map json) {
+    String kind = json["kind"].toLowerCase();
+    String name = json["name"];
+    switch (kind) {
+      case "dart":
+        return new Dart.fromJsonMap(base, json, name);
+
+      case "chain":
+        return new Chain.fromJsonMap(base, json, name, kind);
+
+      case "test_dart":
+        return new TestDart.fromJsonMap(base, json, name, kind);
+
+      default:
+        throw "Suite '$name' has unknown kind '$kind'.";
+    }
+  }
+
+  String toString() => "Suite($name, $kind)";
+}
+
+/// A suite of standalone tests. The tests are combined and run as one program.
+///
+/// A standalone test is a test with a `main` method. The test is considered
+/// successful if main doesn't throw an error (or if `main` returns a future,
+/// that future completes without errors).
+///
+/// The tests are combined by generating a Dart file which imports all the main
+/// methods and calls them sequentially.
+///
+/// Example JSON configuration:
+///
+///     {
+///       "name": "test",
+///       "kind": "Dart",
+///       # Root directory of tests in this suite.
+///       "path": "test/",
+///       # Files in `path` that match any of the following regular expressions
+///       # are considered to be part of this suite.
+///       "pattern": [
+///         "_test.dart$"
+///       ],
+///       # Except if they match any of the following regular expressions.
+///       "exclude": [
+///         "/golden/"
+///       ]
+///     }
+class Dart extends Suite {
+  final Uri uri;
+
+  final List<RegExp> pattern;
+
+  final List<RegExp> exclude;
+
+  Dart(String name, this.uri, this.pattern, this.exclude)
+      : super(name, "dart", null);
+
+  factory Dart.fromJsonMap(Uri base, Map json, String name) {
+    Uri uri = base.resolve(json["path"]);
+    List<RegExp> pattern = new List<RegExp>.from(
+        json["pattern"].map((String p) => new RegExp(p)));
+    List<RegExp> exclude = new List<RegExp>.from(
+        json["exclude"].map((String p) => new RegExp(p)));
+    return new Dart(name, uri, pattern, exclude);
+  }
+
+  String toString() => "Dart($name, $uri, $pattern, $exclude)";
+}
diff --git a/pkg/testing/lib/src/test_dart.dart b/pkg/testing/lib/src/test_dart.dart
new file mode 100644
index 0000000..8c89ed5
--- /dev/null
+++ b/pkg/testing/lib/src/test_dart.dart
@@ -0,0 +1,83 @@
+// 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.
+
+library testing.test_dart;
+
+import 'dart:convert' show
+    JSON;
+
+import 'dart:io' show
+    Platform;
+
+import 'suite.dart' show
+    Suite;
+
+/// A suite that runs test.dart.
+class TestDart extends Suite {
+  final String common;
+
+  final String processes;
+
+  final List<String> commandLines;
+
+  TestDart(String name, this.common, this.processes, this.commandLines)
+      : super(name, "test_dart",
+          // This suite doesn't know what it's status file is because test.dart
+          // doesn't know.
+          null);
+
+  factory TestDart.fromJsonMap(Uri base, Map json, String name, String kind) {
+    String common = json["common"] ?? "";
+    // TODO(ahe): Compute this value based on number of cores.
+    String processes = json["processes"] ?? "-j16";
+    List<String> commandLines = json["command-lines"] ?? <String>[];
+    return new TestDart(name, common, processes, commandLines);
+  }
+
+  void writeFirstImportOn(StringSink sink) {
+    sink.writeln("import 'dart:io' as io;");
+    sink.writeln(
+        "import 'package:testing/src/stdio_process.dart' show StdioProcess;");
+  }
+
+  void writeRunCommandOn(StringSink sink) {
+    Uri dartVm;
+    if (Platform.isMacOS) {
+      dartVm = Uri.base.resolve("tools/sdks/mac/dart-sdk/bin/dart");
+    } else if (Platform.isWindows) {
+      dartVm = Uri.base.resolve("tools/sdks/win/dart-sdk/bin/dart.exe");
+    } else if (Platform.isLinux) {
+      dartVm = Uri.base.resolve("tools/sdks/linux/dart-sdk/bin/dart");
+    } else {
+      throw "Operating system not supported: ${Platform.operatingSystem}";
+    }
+    List<String> processedArguments = <String>[];
+    processedArguments.add(Uri.base.resolve(
+            "tools/testing/dart/package_testing_support.dart").toFilePath());
+    for (String commandLine in commandLines) {
+      String arguments = common;
+      arguments += " $processes";
+      arguments += " $commandLine";
+      processedArguments.add(arguments);
+    }
+    String executable = JSON.encode(dartVm.toFilePath());
+    String arguments = JSON.encode(processedArguments);
+    sink.write("""
+  {
+    print('Running $arguments');
+    StdioProcess process = await StdioProcess.run($executable, $arguments,
+        suppressOutput: false, timeout: null);
+    if (process.exitCode != 0) {
+      print(process.output);
+      io.exitCode = 1;
+    }
+  }
+""");
+  }
+
+  String toString() {
+    return "TestDart($name, ${JSON.encode(common)}, ${JSON.encode(processes)},"
+        " ${JSON.encode(commandLines)})";
+  }
+}
diff --git a/pkg/testing/lib/src/test_dart/README.md b/pkg/testing/lib/src/test_dart/README.md
new file mode 100644
index 0000000..dfa0d1e
--- /dev/null
+++ b/pkg/testing/lib/src/test_dart/README.md
@@ -0,0 +1,7 @@
+<!--
+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.
+-->
+Files in this directory are copied from
+[test.dart](https://github.com/dart-lang/sdk/tree/master/tools/testing/dart).
diff --git a/pkg/testing/lib/src/test_dart/path.dart b/pkg/testing/lib/src/test_dart/path.dart
new file mode 100644
index 0000000..a3d35aa
--- /dev/null
+++ b/pkg/testing/lib/src/test_dart/path.dart
@@ -0,0 +1,311 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library legacy_path;
+
+import 'dart:io';
+import 'dart:math';
+
+// TODO: Remove this class, and use the URI class for all path manipulation.
+class Path {
+  final String _path;
+  final bool isWindowsShare;
+
+  Path(String source)
+      : _path = _clean(source),
+        isWindowsShare = _isWindowsShare(source);
+
+  Path.raw(String source)
+      : _path = source,
+        isWindowsShare = false;
+
+  Path._internal(String this._path, bool this.isWindowsShare);
+
+  static String _clean(String source) {
+    if (Platform.operatingSystem == 'windows') return _cleanWindows(source);
+    // Remove trailing slash from directories:
+    if (source.length > 1 && source.endsWith('/')) {
+      return source.substring(0, source.length - 1);
+    }
+    return source;
+  }
+
+  static String _cleanWindows(String source) {
+    // Change \ to /.
+    var clean = source.replaceAll('\\', '/');
+    // Add / before intial [Drive letter]:
+    if (clean.length >= 2 && clean[1] == ':') {
+      clean = '/$clean';
+    }
+    if (_isWindowsShare(source)) {
+      return clean.substring(1, clean.length);
+    }
+    return clean;
+  }
+
+  static bool _isWindowsShare(String source) {
+    return Platform.operatingSystem == 'windows' && source.startsWith('\\\\');
+  }
+
+  int get hashCode => _path.hashCode;
+  bool get isEmpty => _path.isEmpty;
+  bool get isAbsolute => _path.startsWith('/');
+  bool get hasTrailingSeparator => _path.endsWith('/');
+
+  String toString() => _path;
+
+  Path relativeTo(Path base) {
+    // Returns a path "relative" such that
+    // base.join(relative) == this.canonicalize.
+    // Throws exception if an impossible case is reached.
+    if (base.isAbsolute != isAbsolute ||
+        base.isWindowsShare != isWindowsShare) {
+      throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+          "  Path and base must both be relative, or both absolute.\n"
+          "  Arguments: $_path.relativeTo($base)");
+    }
+
+    var basePath = base.toString();
+    // Handle drive letters specially on Windows.
+    if (base.isAbsolute && Platform.operatingSystem == 'windows') {
+      bool baseHasDrive =
+          basePath.length >= 4 && basePath[2] == ':' && basePath[3] == '/';
+      bool pathHasDrive =
+          _path.length >= 4 && _path[2] == ':' && _path[3] == '/';
+      if (baseHasDrive && pathHasDrive) {
+        int baseDrive = basePath.codeUnitAt(1) | 32; // Convert to uppercase.
+        if (baseDrive >= 'a'.codeUnitAt(0) &&
+            baseDrive <= 'z'.codeUnitAt(0) &&
+            baseDrive == (_path.codeUnitAt(1) | 32)) {
+          if (basePath[1] != _path[1]) {
+            // Replace the drive letter in basePath with that from _path.
+            basePath = '/${_path[1]}:/${basePath.substring(4)}';
+            base = new Path(basePath);
+          }
+        } else {
+          throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+              "  Base path and target path are on different Windows drives.\n"
+              "  Arguments: $_path.relativeTo($base)");
+        }
+      } else if (baseHasDrive != pathHasDrive) {
+        throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+            "  Base path must start with a drive letter if and "
+            "only if target path does.\n"
+            "  Arguments: $_path.relativeTo($base)");
+      }
+    }
+    if (_path.startsWith(basePath)) {
+      if (_path == basePath) return new Path('.');
+      // There must be a '/' at the end of the match, or immediately after.
+      int matchEnd = basePath.length;
+      if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') {
+        // Drop any extra '/' characters at matchEnd
+        while (matchEnd < _path.length && _path[matchEnd] == '/') {
+          matchEnd++;
+        }
+        return new Path(_path.substring(matchEnd)).canonicalize();
+      }
+    }
+
+    List<String> baseSegments = base.canonicalize().segments();
+    List<String> pathSegments = canonicalize().segments();
+    if (baseSegments.length == 1 && baseSegments[0] == '.') {
+      baseSegments = [];
+    }
+    if (pathSegments.length == 1 && pathSegments[0] == '.') {
+      pathSegments = [];
+    }
+    int common = 0;
+    int length = min(pathSegments.length, baseSegments.length);
+    while (common < length && pathSegments[common] == baseSegments[common]) {
+      common++;
+    }
+    final segments = new List<String>();
+
+    if (common < baseSegments.length && baseSegments[common] == '..') {
+      throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+          "  Base path has more '..'s than path does.\n"
+          "  Arguments: $_path.relativeTo($base)");
+    }
+    for (int i = common; i < baseSegments.length; i++) {
+      segments.add('..');
+    }
+    for (int i = common; i < pathSegments.length; i++) {
+      segments.add('${pathSegments[i]}');
+    }
+    if (segments.isEmpty) {
+      segments.add('.');
+    }
+    if (hasTrailingSeparator) {
+      segments.add('');
+    }
+    return new Path(segments.join('/'));
+  }
+
+  Path join(Path further) {
+    if (further.isAbsolute) {
+      throw new ArgumentError(
+          "Path.join called with absolute Path as argument.");
+    }
+    if (isEmpty) {
+      return further.canonicalize();
+    }
+    if (hasTrailingSeparator) {
+      var joined = new Path._internal('$_path${further}', isWindowsShare);
+      return joined.canonicalize();
+    }
+    var joined = new Path._internal('$_path/${further}', isWindowsShare);
+    return joined.canonicalize();
+  }
+
+  // Note: The URI RFC names for canonicalize, join, and relativeTo
+  // are normalize, resolve, and relativize.  But resolve and relativize
+  // drop the last segment of the base path (the filename), on URIs.
+  Path canonicalize() {
+    if (isCanonical) return this;
+    return makeCanonical();
+  }
+
+  bool get isCanonical {
+    // Contains no consecutive path separators.
+    // Contains no segments that are '.'.
+    // Absolute paths have no segments that are '..'.
+    // All '..' segments of a relative path are at the beginning.
+    if (isEmpty) return false; // The canonical form of '' is '.'.
+    if (_path == '.') return true;
+    List segs = _path.split('/'); // Don't mask the getter 'segments'.
+    if (segs[0] == '') {
+      // Absolute path
+      segs[0] = null; // Faster than removeRange().
+    } else {
+      // A canonical relative path may start with .. segments.
+      for (int pos = 0; pos < segs.length && segs[pos] == '..'; ++pos) {
+        segs[pos] = null;
+      }
+    }
+    if (segs.last == '') segs.removeLast(); // Path ends with /.
+    // No remaining segments can be ., .., or empty.
+    return !segs.any((s) => s == '' || s == '.' || s == '..');
+  }
+
+  Path makeCanonical() {
+    bool isAbs = isAbsolute;
+    List segs = segments();
+    String drive;
+    if (isAbs && !segs.isEmpty && segs[0].length == 2 && segs[0][1] == ':') {
+      drive = segs[0];
+      segs.removeRange(0, 1);
+    }
+    List newSegs = [];
+    for (String segment in segs) {
+      switch (segment) {
+        case '..':
+          // Absolute paths drop leading .. markers, including after a drive.
+          if (newSegs.isEmpty) {
+            if (isAbs) {
+              // Do nothing: drop the segment.
+            } else {
+              newSegs.add('..');
+            }
+          } else if (newSegs.last == '..') {
+            newSegs.add('..');
+          } else {
+            newSegs.removeLast();
+          }
+          break;
+        case '.':
+        case '':
+          // Do nothing - drop the segment.
+          break;
+        default:
+          newSegs.add(segment);
+          break;
+      }
+    }
+
+    List segmentsToJoin = [];
+    if (isAbs) {
+      segmentsToJoin.add('');
+      if (drive != null) {
+        segmentsToJoin.add(drive);
+      }
+    }
+
+    if (newSegs.isEmpty) {
+      if (isAbs) {
+        segmentsToJoin.add('');
+      } else {
+        segmentsToJoin.add('.');
+      }
+    } else {
+      segmentsToJoin.addAll(newSegs);
+      if (hasTrailingSeparator) {
+        segmentsToJoin.add('');
+      }
+    }
+    return new Path._internal(segmentsToJoin.join('/'), isWindowsShare);
+  }
+
+  String toNativePath() {
+    if (isEmpty) return '.';
+    if (Platform.operatingSystem == 'windows') {
+      String nativePath = _path;
+      // Drop '/' before a drive letter.
+      if (nativePath.length >= 3 &&
+          nativePath.startsWith('/') &&
+          nativePath[2] == ':') {
+        nativePath = nativePath.substring(1);
+      }
+      nativePath = nativePath.replaceAll('/', '\\');
+      if (isWindowsShare) {
+        return '\\$nativePath';
+      }
+      return nativePath;
+    }
+    return _path;
+  }
+
+  List<String> segments() {
+    List result = _path.split('/');
+    if (isAbsolute) result.removeRange(0, 1);
+    if (hasTrailingSeparator) result.removeLast();
+    return result;
+  }
+
+  Path append(String finalSegment) {
+    if (isEmpty) {
+      return new Path._internal(finalSegment, isWindowsShare);
+    } else if (hasTrailingSeparator) {
+      return new Path._internal('$_path$finalSegment', isWindowsShare);
+    } else {
+      return new Path._internal('$_path/$finalSegment', isWindowsShare);
+    }
+  }
+
+  String get filenameWithoutExtension {
+    var name = filename;
+    if (name == '.' || name == '..') return name;
+    int pos = name.lastIndexOf('.');
+    return (pos < 0) ? name : name.substring(0, pos);
+  }
+
+  String get extension {
+    var name = filename;
+    int pos = name.lastIndexOf('.');
+    return (pos < 0) ? '' : name.substring(pos + 1);
+  }
+
+  Path get directoryPath {
+    int pos = _path.lastIndexOf('/');
+    if (pos < 0) return new Path('');
+    while (pos > 0 && _path[pos - 1] == '/') --pos;
+    var dirPath = (pos > 0) ? _path.substring(0, pos) : '/';
+    return new Path._internal(dirPath, isWindowsShare);
+  }
+
+  String get filename {
+    int pos = _path.lastIndexOf('/');
+    return _path.substring(pos + 1);
+  }
+}
diff --git a/pkg/testing/lib/src/test_dart/status_expression.dart b/pkg/testing/lib/src/test_dart/status_expression.dart
new file mode 100644
index 0000000..c5b0b80
--- /dev/null
+++ b/pkg/testing/lib/src/test_dart/status_expression.dart
@@ -0,0 +1,314 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library status_expression;
+
+/**
+ * Parse and evaluate expressions in a .status file for Dart and V8.
+ * There are set expressions and Boolean expressions in a .status file.
+ * The grammar is:
+ *   BooleanExpression := $variableName == value | $variableName != value |
+ *                        $variableName | (BooleanExpression) |
+ *                        BooleanExpression && BooleanExpression |
+ *                        BooleanExpression || BooleanExpression
+ *
+ *   SetExpression := value | (SetExpression) |
+ *                    SetExpression || SetExpression |
+ *                    SetExpression if BooleanExpression |
+ *                    SetExpression , SetExpression
+ *
+ *  Productions are listed in order of precedence, and the || and , operators
+ *  both evaluate to set union, but with different precedence.
+ *
+ *  Values and variableNames are non-empty strings of word characters, matching
+ *  the RegExp \w+.
+ *
+ *  Expressions evaluate as expected, with values of variables found in
+ *  an environment passed to the evaluator.  The SetExpression "value"
+ *  evaluates to a singleton set containing that value. "A if B" evaluates
+ *  to A if B is true, and to the empty set if B is false.
+ */
+
+class ExprEvaluationException {
+  String error;
+
+  ExprEvaluationException(this.error);
+
+  toString() => error;
+}
+
+class Token {
+  static const String LEFT_PAREN = "(";
+  static const String RIGHT_PAREN = ")";
+  static const String DOLLAR_SYMBOL = r"$";
+  static const String UNION = ",";
+  static const String EQUALS = "==";
+  static const String NOT_EQUALS = "!=";
+  static const String AND = "&&";
+  static const String OR = "||";
+}
+
+class Tokenizer {
+  String expression;
+  List<String> tokens;
+
+  Tokenizer(String this.expression) : tokens = new List<String>();
+
+  // Tokens are : "(", ")", "$", ",", "&&", "||", "==", "!=", and (maximal) \w+.
+  static final testRegexp =
+      new RegExp(r"^([()$\w\s,]|(\&\&)|(\|\|)|(\=\=)|(\!\=))+$");
+  static final regexp = new RegExp(r"[()$,]|(\&\&)|(\|\|)|(\=\=)|(\!\=)|\w+");
+
+  List<String> tokenize() {
+    if (!testRegexp.hasMatch(expression)) {
+      throw new FormatException("Syntax error in '$expression'");
+    }
+    for (Match match in regexp.allMatches(expression)) tokens.add(match[0]);
+    return tokens;
+  }
+}
+
+abstract class BooleanExpression {
+  bool evaluate(Map<String, String> environment);
+}
+
+abstract class SetExpression {
+  Set<String> evaluate(Map<String, String> environment);
+}
+
+class Comparison implements BooleanExpression {
+  TermVariable left;
+  TermConstant right;
+  bool negate;
+
+  Comparison(this.left, this.right, this.negate);
+
+  bool evaluate(environment) {
+    return negate !=
+        (left.termValue(environment) == right.termValue(environment));
+  }
+
+  String toString() =>
+      "(\$${left.name} ${negate ? '!=' : '=='} ${right.value})";
+}
+
+class TermVariable {
+  String name;
+
+  TermVariable(this.name);
+
+  String termValue(environment) {
+    var value = environment[name];
+    if (value == null) {
+      throw new ExprEvaluationException("Could not find '$name' in environment "
+          "while evaluating status file expression.");
+    }
+    return value.toString();
+  }
+}
+
+class TermConstant {
+  String value;
+
+  TermConstant(String this.value);
+
+  String termValue(environment) => value;
+}
+
+class BooleanVariable implements BooleanExpression {
+  TermVariable variable;
+
+  BooleanVariable(this.variable);
+
+  bool evaluate(environment) => variable.termValue(environment) == 'true';
+  String toString() => "(bool \$${variable.name})";
+}
+
+class BooleanOperation implements BooleanExpression {
+  String op;
+  BooleanExpression left;
+  BooleanExpression right;
+
+  BooleanOperation(this.op, this.left, this.right);
+
+  bool evaluate(environment) => (op == Token.AND)
+      ? left.evaluate(environment) && right.evaluate(environment)
+      : left.evaluate(environment) || right.evaluate(environment);
+  String toString() => "($left $op $right)";
+}
+
+class SetUnion implements SetExpression {
+  SetExpression left;
+  SetExpression right;
+
+  SetUnion(this.left, this.right);
+
+  // Overwrites left.evaluate(env).
+  // Set.addAll does not return this.
+  Set<String> evaluate(environment) {
+    Set<String> result = left.evaluate(environment);
+    result.addAll(right.evaluate(environment));
+    return result;
+  }
+
+  String toString() => "($left || $right)";
+}
+
+class SetIf implements SetExpression {
+  SetExpression left;
+  BooleanExpression right;
+
+  SetIf(this.left, this.right);
+
+  Set<String> evaluate(environment) => right.evaluate(environment)
+      ? left.evaluate(environment)
+      : new Set<String>();
+  String toString() => "($left if $right)";
+}
+
+class SetConstant implements SetExpression {
+  String value;
+
+  SetConstant(String v) : value = v.toLowerCase();
+
+  Set<String> evaluate(environment) => new Set<String>.from([value]);
+  String toString() => value;
+}
+
+// An iterator that allows peeking at the current token.
+class Scanner {
+  List<String> tokens;
+  Iterator tokenIterator;
+  String current;
+
+  Scanner(this.tokens) {
+    tokenIterator = tokens.iterator;
+    advance();
+  }
+
+  bool hasMore() => current != null;
+
+  void advance() {
+    current = tokenIterator.moveNext() ? tokenIterator.current : null;
+  }
+}
+
+class ExpressionParser {
+  Scanner scanner;
+
+  ExpressionParser(this.scanner);
+
+  SetExpression parseSetExpression() => parseSetUnion();
+
+  SetExpression parseSetUnion() {
+    SetExpression left = parseSetIf();
+    while (scanner.hasMore() && scanner.current == Token.UNION) {
+      scanner.advance();
+      SetExpression right = parseSetIf();
+      left = new SetUnion(left, right);
+    }
+    return left;
+  }
+
+  SetExpression parseSetIf() {
+    SetExpression left = parseSetOr();
+    while (scanner.hasMore() && scanner.current == "if") {
+      scanner.advance();
+      BooleanExpression right = parseBooleanExpression();
+      left = new SetIf(left, right);
+    }
+    return left;
+  }
+
+  SetExpression parseSetOr() {
+    SetExpression left = parseSetAtomic();
+    while (scanner.hasMore() && scanner.current == Token.OR) {
+      scanner.advance();
+      SetExpression right = parseSetAtomic();
+      left = new SetUnion(left, right);
+    }
+    return left;
+  }
+
+  SetExpression parseSetAtomic() {
+    if (scanner.current == Token.LEFT_PAREN) {
+      scanner.advance();
+      SetExpression value = parseSetExpression();
+      if (scanner.current != Token.RIGHT_PAREN) {
+        throw new FormatException("Missing right parenthesis in expression");
+      }
+      scanner.advance();
+      return value;
+    }
+    if (!new RegExp(r"^\w+$").hasMatch(scanner.current)) {
+      throw new FormatException(
+          "Expected identifier in expression, got ${scanner.current}");
+    }
+    SetExpression value = new SetConstant(scanner.current);
+    scanner.advance();
+    return value;
+  }
+
+  BooleanExpression parseBooleanExpression() => parseBooleanOr();
+
+  BooleanExpression parseBooleanOr() {
+    BooleanExpression left = parseBooleanAnd();
+    while (scanner.hasMore() && scanner.current == Token.OR) {
+      scanner.advance();
+      BooleanExpression right = parseBooleanAnd();
+      left = new BooleanOperation(Token.OR, left, right);
+    }
+    return left;
+  }
+
+  BooleanExpression parseBooleanAnd() {
+    BooleanExpression left = parseBooleanAtomic();
+    while (scanner.hasMore() && scanner.current == Token.AND) {
+      scanner.advance();
+      BooleanExpression right = parseBooleanAtomic();
+      left = new BooleanOperation(Token.AND, left, right);
+    }
+    return left;
+  }
+
+  BooleanExpression parseBooleanAtomic() {
+    if (scanner.current == Token.LEFT_PAREN) {
+      scanner.advance();
+      BooleanExpression value = parseBooleanExpression();
+      if (scanner.current != Token.RIGHT_PAREN) {
+        throw new FormatException("Missing right parenthesis in expression");
+      }
+      scanner.advance();
+      return value;
+    }
+
+    // The only atomic booleans are of the form $variable == value or
+    // of the form $variable.
+    if (scanner.current != Token.DOLLAR_SYMBOL) {
+      throw new FormatException(
+          "Expected \$ in expression, got ${scanner.current}");
+    }
+    scanner.advance();
+    if (!new RegExp(r"^\w+$").hasMatch(scanner.current)) {
+      throw new FormatException(
+          "Expected identifier in expression, got ${scanner.current}");
+    }
+    TermVariable left = new TermVariable(scanner.current);
+    scanner.advance();
+    if (scanner.current == Token.EQUALS ||
+        scanner.current == Token.NOT_EQUALS) {
+      bool negate = scanner.current == Token.NOT_EQUALS;
+      scanner.advance();
+      if (!new RegExp(r"^\w+$").hasMatch(scanner.current)) {
+        throw new FormatException(
+            "Expected value in expression, got ${scanner.current}");
+      }
+      TermConstant right = new TermConstant(scanner.current);
+      scanner.advance();
+      return new Comparison(left, right, negate);
+    } else {
+      return new BooleanVariable(left);
+    }
+  }
+}
diff --git a/pkg/testing/lib/src/test_dart/status_file_parser.dart b/pkg/testing/lib/src/test_dart/status_file_parser.dart
new file mode 100644
index 0000000..a7c00de
--- /dev/null
+++ b/pkg/testing/lib/src/test_dart/status_file_parser.dart
@@ -0,0 +1,253 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library status_file_parser;
+
+import "dart:async";
+import "dart:convert" show LineSplitter, UTF8;
+import "dart:io";
+
+import "path.dart";
+import "status_expression.dart";
+
+import '../expectation.dart' show
+    Expectation,
+    ExpectationSet;
+
+final RegExp SplitComment = new RegExp("^([^#]*)(#.*)?\$");
+final RegExp HeaderPattern = new RegExp(r"^\[([^\]]+)\]");
+final RegExp RulePattern = new RegExp(r"\s*([^: ]*)\s*:(.*)");
+final RegExp IssueNumberPattern = new RegExp("[Ii]ssue ([0-9]+)");
+
+class StatusFile {
+  final Path location;
+
+  StatusFile(this.location);
+}
+
+// TODO(whesse): Implement configuration_info library that contains data
+// structures for test configuration, including Section.
+class Section {
+  final StatusFile statusFile;
+
+  final BooleanExpression condition;
+  final List<TestRule> testRules;
+  final int lineNumber;
+
+  Section.always(this.statusFile, this.lineNumber)
+      : condition = null,
+        testRules = new List<TestRule>();
+  Section(this.statusFile, this.condition, this.lineNumber)
+      : testRules = new List<TestRule>();
+
+  bool isEnabled(environment) =>
+      condition == null || condition.evaluate(environment);
+
+  String toString() {
+    return "Section: $condition";
+  }
+}
+
+Future<TestExpectations> ReadTestExpectations(
+    List<String> statusFilePaths, Map environment,
+    ExpectationSet expectationSet) {
+  var testExpectations = new TestExpectations(expectationSet);
+  return Future.wait(statusFilePaths.map((String statusFile) {
+    return ReadTestExpectationsInto(testExpectations, statusFile, environment);
+  })).then((_) => testExpectations);
+}
+
+Future ReadTestExpectationsInto(
+    TestExpectations expectations, String statusFilePath, environment) {
+  var completer = new Completer();
+  List<Section> sections = new List<Section>();
+
+  void sectionsRead() {
+    for (Section section in sections) {
+      if (section.isEnabled(environment)) {
+        for (var rule in section.testRules) {
+          expectations.addRule(rule, environment);
+        }
+      }
+    }
+    completer.complete();
+  }
+
+  ReadConfigurationInto(new Path(statusFilePath), sections, sectionsRead);
+  return completer.future;
+}
+
+void ReadConfigurationInto(Path path, sections, onDone) {
+  StatusFile statusFile = new StatusFile(path);
+  File file = new File(path.toNativePath());
+  if (!file.existsSync()) {
+    throw new Exception('Cannot find test status file $path');
+  }
+  int lineNumber = 0;
+  Stream<String> lines =
+      file.openRead().transform(UTF8.decoder).transform(new LineSplitter());
+
+  Section currentSection = new Section.always(statusFile, -1);
+  sections.add(currentSection);
+
+  lines.listen((String line) {
+    lineNumber++;
+    Match match = SplitComment.firstMatch(line);
+    line = (match == null) ? "" : match[1];
+    line = line.trim();
+    if (line.isEmpty) return;
+
+    // Extract the comment to get the issue number if needed.
+    String comment = (match == null || match[2] == null) ? "" : match[2];
+
+    match = HeaderPattern.firstMatch(line);
+    if (match != null) {
+      String condition_string = match[1].trim();
+      List<String> tokens = new Tokenizer(condition_string).tokenize();
+      ExpressionParser parser = new ExpressionParser(new Scanner(tokens));
+      currentSection =
+          new Section(statusFile, parser.parseBooleanExpression(), lineNumber);
+      sections.add(currentSection);
+      return;
+    }
+
+    match = RulePattern.firstMatch(line);
+    if (match != null) {
+      String name = match[1].trim();
+      // TODO(whesse): Handle test names ending in a wildcard (*).
+      String expression_string = match[2].trim();
+      List<String> tokens = new Tokenizer(expression_string).tokenize();
+      SetExpression expression =
+          new ExpressionParser(new Scanner(tokens)).parseSetExpression();
+
+      // Look for issue number in comment.
+      String issueString = null;
+      match = IssueNumberPattern.firstMatch(comment);
+      if (match != null) {
+        issueString = match[1];
+        if (issueString == null) issueString = match[2];
+      }
+      int issue = issueString != null ? int.parse(issueString) : null;
+      currentSection.testRules
+          .add(new TestRule(name, expression, issue, lineNumber));
+      return;
+    }
+
+    print("unmatched line: $line");
+  }, onDone: onDone);
+}
+
+class TestRule {
+  String name;
+  SetExpression expression;
+  int issue;
+  int lineNumber;
+
+  TestRule(this.name, this.expression, this.issue, this.lineNumber);
+
+  bool get hasIssue => issue != null;
+
+  String toString() => 'TestRule($name, $expression, $issue)';
+}
+
+class TestExpectations {
+  // Only create one copy of each Set<Expectation>.
+  // We just use .toString as a key, so we may make a few
+  // sets that only differ in their toString element order.
+  static Map _cachedSets = new Map();
+
+  final ExpectationSet expectationSet;
+
+  Map _map;
+  bool _preprocessed = false;
+  Map _regExpCache;
+  Map _keyToRegExps;
+
+  /**
+   * Create a TestExpectations object. See the [expectations] method
+   * for an explanation of matching.
+   */
+  TestExpectations(this.expectationSet) : _map = new Map();
+
+  /**
+   * Add a rule to the expectations.
+   */
+  void addRule(testRule, environment) {
+    // Once we have started using the expectations we cannot add more
+    // rules.
+    if (_preprocessed) {
+      throw "TestExpectations.addRule: cannot add more rules";
+    }
+    var names = testRule.expression.evaluate(environment);
+    var expectations = names.map((name) => expectationSet[name]);
+    _map.putIfAbsent(testRule.name, () => new Set()).addAll(expectations);
+  }
+
+  /**
+   * Compute the expectations for a test based on the filename.
+   *
+   * For every (key, expectation) pair. Match the key with the file
+   * name. Return the union of the expectations for all the keys
+   * that match.
+   *
+   * Normal matching splits the key and the filename into path
+   * components and checks that the anchored regular expression
+   * "^$keyComponent\$" matches the corresponding filename component.
+   */
+  Set<Expectation> expectations(String filename) {
+    var result = new Set();
+    var splitFilename = filename.split('/');
+
+    // Create mapping from keys to list of RegExps once and for all.
+    _preprocessForMatching();
+
+    _map.forEach((key, expectation) {
+      List regExps = _keyToRegExps[key];
+      if (regExps.length > splitFilename.length) return;
+      for (var i = 0; i < regExps.length; i++) {
+        if (!regExps[i].hasMatch(splitFilename[i])) return;
+      }
+      // If all components of the status file key matches the filename
+      // add the expectations to the result.
+      result.addAll(expectation);
+    });
+
+    // If no expectations were found the expectation is that the test
+    // passes.
+    if (result.isEmpty) {
+      result.add(Expectation.Pass);
+    }
+    return _cachedSets.putIfAbsent(result.toString(), () => result);
+  }
+
+  // Preprocess the expectations for matching against
+  // filenames. Generate lists of regular expressions once and for all
+  // for each key.
+  void _preprocessForMatching() {
+    if (_preprocessed) return;
+
+    _keyToRegExps = new Map();
+    _regExpCache = new Map();
+
+    _map.forEach((key, expectations) {
+      if (_keyToRegExps[key] != null) return;
+      var splitKey = key.split('/');
+      var regExps = new List(splitKey.length);
+      for (var i = 0; i < splitKey.length; i++) {
+        var component = splitKey[i];
+        var regExp = _regExpCache[component];
+        if (regExp == null) {
+          var pattern = "^${splitKey[i]}\$".replaceAll('*', '.*');
+          regExp = new RegExp(pattern);
+          _regExpCache[component] = regExp;
+        }
+        regExps[i] = regExp;
+      }
+      _keyToRegExps[key] = regExps;
+    });
+
+    _regExpCache = null;
+    _preprocessed = true;
+  }
+}
diff --git a/pkg/testing/lib/src/test_description.dart b/pkg/testing/lib/src/test_description.dart
new file mode 100644
index 0000000..9b1c5b3
--- /dev/null
+++ b/pkg/testing/lib/src/test_description.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.md file.
+
+library testing.test_description;
+
+import 'dart:io' show
+    File,
+    FileSystemEntity;
+
+class TestDescription implements Comparable<TestDescription> {
+  final Uri root;
+  final File file;
+  final Uri output;
+
+  /// If non-null, this is a generated multitest, and the set contains the
+  /// expected outcomes.
+  Set<String> multitestExpectations;
+
+  TestDescription(this.root, this.file, {this.output});
+
+  Uri get uri => file.uri;
+
+  String get shortName {
+    String baseName = "$uri".substring("$root".length);
+    return baseName.substring(0, baseName.length - ".dart".length);
+  }
+
+  String get escapedName => shortName.replaceAll("/", "__");
+
+  void writeImportOn(StringSink sink) {
+    sink.write("import '");
+    sink.write(uri);
+    sink.write("' as ");
+    sink.write(escapedName);
+    sink.writeln(" show main;");
+  }
+
+  void writeClosureOn(StringSink sink) {
+    sink.write('    "');
+    sink.write(shortName);
+    sink.write('": ');
+    sink.write(escapedName);
+    sink.writeln('.main,');
+  }
+
+  static TestDescription from(
+      Uri root, FileSystemEntity entity, {Pattern pattern}) {
+    if (entity is! File) return null;
+    pattern ??= "_test.dart";
+    String path = entity.uri.path;
+    bool hasMatch = false;
+    if (pattern is String) {
+      if (path.endsWith(pattern)) hasMatch = true;
+    } else if (path.contains(pattern)) {
+      hasMatch = true;
+    }
+    return hasMatch ? new TestDescription(root, entity) : null;
+  }
+
+  int compareTo(TestDescription other) => "$uri".compareTo("${other.uri}");
+
+  String formatError(String message) {
+    String base = Uri.base.toFilePath();
+    String path = uri.toFilePath();
+    if (path.startsWith(base)) {
+      path = path.substring(base.length);
+    }
+    return "$path:$message";
+  }
+}
diff --git a/pkg/testing/lib/src/test_root.dart b/pkg/testing/lib/src/test_root.dart
new file mode 100644
index 0000000..4729de5
--- /dev/null
+++ b/pkg/testing/lib/src/test_root.dart
@@ -0,0 +1,104 @@
+// 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.
+
+library testing.test_root;
+
+import 'dart:async' show
+    Future;
+
+import 'dart:convert' show
+    JSON;
+
+import 'dart:io' show
+    File;
+
+import '../testing.dart' show
+    Chain;
+
+import 'analyze.dart' show
+    Analyze;
+
+import 'suite.dart' show
+    Dart,
+    Suite;
+
+/// Records properties of a test root. The information is read from a JSON file.
+///
+/// Example with comments:
+///     {
+///       # Path to the `.packages` file used.
+///       "packages": "test/.packages",
+///       # A list of test suites (collection of tests).
+///       "suites": [
+///         # A list of suite objects. See the subclasses of [Suite] below.
+///       ],
+///       "analyze": {
+///         # Uris to analyze.
+///         "uris": [
+///           "lib/",
+///           "bin/dartk.dart",
+///           "bin/repl.dart",
+///           "test/log_analyzer.dart",
+///           "third_party/testing/lib/"
+///         ],
+///         # Regular expressions of file names to ignore when analyzing.
+///         "exclude": [
+///           "/third_party/dart-sdk/pkg/compiler/",
+///           "/third_party/kernel/"
+///         ]
+///       }
+///     }
+class TestRoot {
+  final Uri packages;
+
+  final List<Suite> suites;
+
+  TestRoot(this.packages, this.suites);
+
+  Analyze get analyze => suites.last;
+
+  List<Uri> get urisToAnalyze => analyze.uris;
+
+  List<RegExp> get excludedFromAnalysis => analyze.exclude;
+
+  Iterable<Dart> get dartSuites {
+    return new List<Dart>.from(
+        suites.where((Suite suite) => suite is Dart));
+  }
+
+  Iterable<Chain> get toolChains {
+    return new List<Chain>.from(
+        suites.where((Suite suite) => suite is Chain));
+  }
+
+  String toString() {
+    return "TestRoot($suites, $urisToAnalyze)";
+  }
+
+  static Future<TestRoot> fromUri(Uri uri) async {
+    String json = await new File.fromUri(uri).readAsString();
+    Map data = JSON.decode(json);
+
+    addDefaults(data);
+
+    Uri packages = uri.resolve(data["packages"]);
+
+    List<Suite> suites = new List<Suite>.from(
+        data["suites"].map((Map json) => new Suite.fromJsonMap(uri, json)));
+
+    Analyze analyze = await Analyze.fromJsonMap(uri, data["analyze"], suites);
+
+    suites.add(analyze);
+
+    return new TestRoot(packages, suites);
+  }
+
+  static void addDefaults(Map data) {
+    data.putIfAbsent("packages", () => ".packages");
+    data.putIfAbsent("suites", () => []);
+    Map analyze = data.putIfAbsent("analyze", () => {});
+    analyze.putIfAbsent("uris", () => []);
+    analyze.putIfAbsent("exclude", () => []);
+  }
+}
diff --git a/pkg/testing/lib/src/zone_helper.dart b/pkg/testing/lib/src/zone_helper.dart
new file mode 100644
index 0000000..0429260
--- /dev/null
+++ b/pkg/testing/lib/src/zone_helper.dart
@@ -0,0 +1,102 @@
+// 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.
+
+/// Helper functions for running code in a Zone.
+library testing.zone_helper;
+
+import 'dart:async' show
+    Completer,
+    Future,
+    ZoneSpecification,
+    runZoned;
+
+import 'dart:io' show
+    exit,
+    stderr;
+
+import 'dart:isolate' show
+    Capability,
+    Isolate,
+    ReceivePort;
+
+import 'log.dart' show
+    logUncaughtError;
+
+Future runGuarded(
+    Future f(),
+    {void printLineOnStdout(line),
+     void handleLateError(error, StackTrace stackTrace)}) {
+
+  var printWrapper;
+  if (printLineOnStdout != null) {
+    printWrapper = (_1, _2, _3, String line) {
+      printLineOnStdout(line);
+    };
+  }
+
+  Completer completer = new Completer();
+
+  handleUncaughtError(error, StackTrace stackTrace) {
+    logUncaughtError(error, stackTrace);
+    if (!completer.isCompleted) {
+      completer.completeError(error, stackTrace);
+    } else if (handleLateError != null) {
+      handleLateError(error, stackTrace);
+    } else {
+      String errorString = "error.toString() failed.";
+      try {
+        errorString = "$error";
+      } catch (_) {
+        // Ignored.
+      }
+      stderr.write("$errorString\n" +
+          (stackTrace == null ? "" : "$stackTrace"));
+      stderr.flush();
+      exit(255);
+    }
+  }
+
+  ZoneSpecification specification = new ZoneSpecification(print: printWrapper);
+
+  ReceivePort errorPort = new ReceivePort();
+  Future errorFuture = errorPort.listen((List errors) {
+    Isolate.current.removeErrorListener(errorPort.sendPort);
+    errorPort.close();
+    var error = errors[0];
+    var stackTrace = errors[1];
+    if (stackTrace != null) {
+      stackTrace = new StackTrace.fromString(stackTrace);
+    }
+    handleUncaughtError(error, stackTrace);
+  }).asFuture();
+
+  Isolate.current.setErrorsFatal(false);
+  Isolate.current.addErrorListener(errorPort.sendPort);
+  return acknowledgeControlMessages(Isolate.current).then((_) {
+    runZoned(
+        () => new Future(f).then(completer.complete),
+        zoneSpecification: specification,
+        onError: handleUncaughtError);
+
+    return completer.future.whenComplete(() {
+      errorPort.close();
+      Isolate.current.removeErrorListener(errorPort.sendPort);
+      return acknowledgeControlMessages(Isolate.current)
+          .then((_) => errorFuture);
+    });
+  });
+}
+
+/// Ping [isolate] to ensure control messages have been delivered.  Control
+/// messages are things like [Isolate.addErrorListener] and
+/// [Isolate.addOnExitListener].
+Future acknowledgeControlMessages(Isolate isolate, {Capability resume}) {
+  ReceivePort ping = new ReceivePort();
+  Isolate.current.ping(ping.sendPort);
+  if (resume == null) {
+    return ping.first;
+  } else {
+    return ping.first.then((_) => isolate.resume(resume));
+  }
+}
diff --git a/pkg/testing/lib/testing.dart b/pkg/testing/lib/testing.dart
new file mode 100644
index 0000000..6145d6b
--- /dev/null
+++ b/pkg/testing/lib/testing.dart
@@ -0,0 +1,29 @@
+// 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.
+
+library testing;
+
+export 'dart:async' show
+    Future;
+
+export 'src/discover.dart';
+
+export 'src/test_description.dart';
+
+export 'src/chain.dart' show
+    Chain,
+    ChainContext,
+    Result,
+    Step;
+
+export 'src/stdio_process.dart' show
+    StdioProcess;
+
+export 'src/run.dart' show
+    run,
+    runMe;
+
+export 'src/expectation.dart' show
+    Expectation,
+    ExpectationSet;
diff --git a/pkg/testing/test/dart_sdk_negative_test.dart b/pkg/testing/test/dart_sdk_negative_test.dart
new file mode 100644
index 0000000..21b36ff
--- /dev/null
+++ b/pkg/testing/test/dart_sdk_negative_test.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  throw "This is a negative test.";
+}
diff --git a/pkg/testing/test/dart_vm_suite.status b/pkg/testing/test/dart_vm_suite.status
new file mode 100644
index 0000000..53fe05a
--- /dev/null
+++ b/pkg/testing/test/dart_vm_suite.status
@@ -0,0 +1,3 @@
+# 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.
diff --git a/pkg/testing/test/hello_test.dart b/pkg/testing/test/hello_test.dart
new file mode 100644
index 0000000..671d11f
--- /dev/null
+++ b/pkg/testing/test/hello_test.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  print("Hello, World!");
+}
diff --git a/pkg/testing/testing.json b/pkg/testing/testing.json
new file mode 100644
index 0000000..408ac55
--- /dev/null
+++ b/pkg/testing/testing.json
@@ -0,0 +1,24 @@
+{ "Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file":0,
+  "for details. All rights reserved. Use of this source code is governed by a":0,
+  "BSD-style license that can be found in the LICENSE.md file.":0,
+  "suites": [
+    {
+      "name": "dart_vm",
+      "kind": "Chain",
+      "source": "package:testing/dart_vm_suite.dart",
+      "path": "test/",
+      "status": "test/dart_vm_suite.status",
+      "pattern": [
+        "\\.dart$"
+      ],
+      "exclude": [
+      ]
+    }
+  ],
+  "analyze": {
+    "uris": [
+      "lib/",
+      "bin/run_tests.dart"
+    ]
+  }
+}
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 05d33f7..335f853 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -2,6 +2,8 @@
 # for 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("runtime_args.gni")
+
 declare_args() {
   # Instead of using is_debug, we introduce a different flag for specifying a
   # Debug build of Dart so that clients can still use a Release build of Dart
@@ -149,6 +151,12 @@
     defines += [ "NDEBUG" ]
   }
 
+  include_dirs = []
+  if (dart_use_tcmalloc) {
+    defines += [ "DART_USE_TCMALLOC" ]
+    include_dirs += [ "../third_party/tcmalloc/gperftools/src" ]
+  }
+
   if (!is_win) {
     cflags = [
       "-Werror",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index c3140f0..3404bbf 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -297,6 +297,10 @@
 
   include_dirs = [ ".." ]
 
+  if (dart_use_tcmalloc) {
+    deps += [ "//third_party/tcmalloc" ]
+  }
+
   if (is_mac) {
     libs = [
       "CoreFoundation.framework",
@@ -574,11 +578,14 @@
 
     if (dart_use_tcmalloc) {
       deps += [ "//third_party/tcmalloc" ]
-      defines += [ "DART_USE_TCMALLOC" ]
     }
 
     sources = [
+                "error_exit.cc",
+                "error_exit.h",
                 "main.cc",
+                "snapshot_utils.cc",
+                "snapshot_utils.h",
                 "vmservice_impl.cc",
                 "vmservice_impl.h",
                 "$target_gen_dir/resources_gen.cc",
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index d546638..3119ce0 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -1122,12 +1122,16 @@
         '../../third_party/', # Zlib
       ],
       'sources': [
-        'main.cc',
         'builtin.h',
         'builtin_common.cc',
         'builtin_natives.cc',
         'builtin_nolib.cc',
+        'error_exit.cc',
+        'error_exit.h',
         'io_natives.h',
+        'main.cc',
+        'snapshot_utils.cc',
+        'snapshot_utils.h',
         'vmservice_impl.cc',
         'vmservice_impl.h',
         '<(observatory_assets_cc_file)',
@@ -1151,9 +1155,6 @@
           'dependencies': [
             '../third_party/tcmalloc/tcmalloc.gypi:tcmalloc',
           ],
-          'defines': [
-            'DART_USE_TCMALLOC'
-          ],
         }],
       ],
       'configurations': {
@@ -1184,13 +1185,17 @@
         '../../third_party/', # Zlib
       ],
       'sources': [
-        'main.cc',
         'builtin.h',
         'builtin_common.cc',
         'builtin_natives.cc',
         'builtin_nolib.cc',
+        'error_exit.cc',
+        'error_exit.h',
         'io_natives.h',
+        'main.cc',
         'snapshot_empty.cc',
+        'snapshot_utils.cc',
+        'snapshot_utils.h',
         'vmservice_impl.cc',
         'vmservice_impl.h',
         '<(observatory_assets_cc_file)',
@@ -1230,14 +1235,18 @@
         '..',
       ],
       'sources': [
-        'main.cc',
         'builtin.cc',
         'builtin.h',
         'builtin_common.cc',
         'builtin_natives.cc',
+        'error_exit.cc',
+        'error_exit.h',
         'io_natives.h',
+        'main.cc',
         'observatory_assets_empty.cc',
         'snapshot_empty.cc',
+        'snapshot_utils.cc',
+        'snapshot_utils.h',
         'vmservice_impl.cc',
         'vmservice_impl.h',
         # Include generated source files.
@@ -1348,9 +1357,6 @@
           'dependencies': [
             '../third_party/tcmalloc/tcmalloc.gypi:tcmalloc',
           ],
-          'defines': [
-            'DART_USE_TCMALLOC'
-          ],
         }],
       ],
       'configurations': {
diff --git a/runtime/bin/builtin_in.cc b/runtime/bin/builtin_in.cc
index 2fd818b..73044c8 100644
--- a/runtime/bin/builtin_in.cc
+++ b/runtime/bin/builtin_in.cc
@@ -8,6 +8,7 @@
 
 // This file is used to generate the mapping of standalone dart libraries
 // to the corresponding files that implement them.
+{{SOURCE_ARRAYS}}
 const char* {{VAR_NAME}}[] = {
 {{LIBRARY_SOURCE_MAP}}
 {{PART_SOURCE_MAP}}
diff --git a/runtime/bin/directory_test.cc b/runtime/bin/directory_test.cc
index da4a084..de9970e 100644
--- a/runtime/bin/directory_test.cc
+++ b/runtime/bin/directory_test.cc
@@ -11,7 +11,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(DirectoryCurrentNoScope) {
+VM_UNIT_TEST_CASE(DirectoryCurrentNoScope) {
   char* current_dir = dart::bin::Directory::CurrentNoScope();
   EXPECT_NOTNULL(current_dir);
   free(current_dir);
diff --git a/runtime/bin/embedded_dart_io.cc b/runtime/bin/embedded_dart_io.cc
index 8b1b7fb..6dfbd86 100644
--- a/runtime/bin/embedded_dart_io.cc
+++ b/runtime/bin/embedded_dart_io.cc
@@ -6,6 +6,7 @@
 
 #include "bin/directory.h"
 #include "bin/eventhandler.h"
+#include "bin/platform.h"
 #include "bin/utils.h"
 #include "bin/thread.h"
 
@@ -24,5 +25,15 @@
   Directory::SetSystemTemp(system_temp);
 }
 
+
+void SetExecutableName(const char* executable_name) {
+  Platform::SetExecutableName(executable_name);
+}
+
+
+void SetExecutableArguments(int script_index, char** argv) {
+  Platform::SetExecutableArguments(script_index, argv);
+}
+
 }  // namespace bin
 }  // namespace dart
diff --git a/runtime/bin/embedded_dart_io.h b/runtime/bin/embedded_dart_io.h
index 84f5aa4..9ce24b9 100644
--- a/runtime/bin/embedded_dart_io.h
+++ b/runtime/bin/embedded_dart_io.h
@@ -27,6 +27,12 @@
 // Should Stderr events be captured?
 bool ShouldCaptureStderr();
 
+// Set the executable name used by Platform.executable.
+void SetExecutableName(const char* executable_name);
+
+// Set the arguments used by Platform.executableArguments.
+void SetExecutableArguments(int script_index, char** argv);
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/error_exit.cc b/runtime/bin/error_exit.cc
new file mode 100644
index 0000000..191a8e5
--- /dev/null
+++ b/runtime/bin/error_exit.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include "bin/error_exit.h"
+
+#include "bin/log.h"
+#include "bin/platform.h"
+#include "bin/process.h"
+#include "bin/eventhandler.h"
+#include "include/dart_api.h"
+#include "platform/assert.h"
+#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
+void ErrorExit(int exit_code, const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  Log::VPrintErr(format, arguments);
+  va_end(arguments);
+
+  Dart_ExitScope();
+  Dart_ShutdownIsolate();
+
+  // Terminate process exit-code handler.
+  Process::TerminateExitCodeHandler();
+
+  char* error = Dart_Cleanup();
+  if (error != NULL) {
+    Log::PrintErr("VM cleanup failed: %s\n", error);
+    free(error);
+  }
+
+  EventHandler::Stop();
+  Platform::Exit(exit_code);
+}
+
+}  // namespace bin
+}  // namespace dart
diff --git a/runtime/bin/error_exit.h b/runtime/bin/error_exit.h
new file mode 100644
index 0000000..acf4cbe
--- /dev/null
+++ b/runtime/bin/error_exit.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef RUNTIME_BIN_ERROR_EXIT_H_
+#define RUNTIME_BIN_ERROR_EXIT_H_
+
+namespace dart {
+namespace bin {
+
+// Exit code indicating an internal Dart Frontend error.
+static const int kDartFrontendErrorExitCode = 252;
+// Exit code indicating an API error.
+static const int kApiErrorExitCode = 253;
+// Exit code indicating a compilation error.
+static const int kCompilationErrorExitCode = 254;
+// Exit code indicating an unhandled error that is not a compilation error.
+static const int kErrorExitCode = 255;
+// Exit code indicating a vm restart request.  Never returned to the user.
+static const int kRestartRequestExitCode = 1000;
+
+void ErrorExit(int exit_code, const char* format, ...);
+
+}  // namespace bin
+}  // namespace dart
+
+#endif  // RUNTIME_BIN_ERROR_EXIT_H_
diff --git a/runtime/bin/eventhandler_test.cc b/runtime/bin/eventhandler_test.cc
index 098113d..cef2b94 100644
--- a/runtime/bin/eventhandler_test.cc
+++ b/runtime/bin/eventhandler_test.cc
@@ -9,7 +9,7 @@
 namespace dart {
 namespace bin {
 
-UNIT_TEST_CASE(CircularLinkedList) {
+VM_UNIT_TEST_CASE(CircularLinkedList) {
   CircularLinkedList<int> list;
 
   EXPECT(!list.HasHead());
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index f988712..bd4af31 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -145,13 +145,13 @@
 
 
 void Handle::Close() {
+  MonitorLocker ml(monitor_);
   if (!SupportsOverlappedIO()) {
     // If the handle uses synchronous I/O (e.g. stdin), cancel any pending
     // operation before closing the handle, so the read thread is not blocked.
     BOOL result = CancelIoEx(handle_, NULL);
     ASSERT(result || (GetLastError() == ERROR_NOT_FOUND));
   }
-  MonitorLocker ml(monitor_);
   if (!IsClosing()) {
     // Close the socket and set the closing state. This close method can be
     // called again if this socket has pending IO operations in flight.
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 1abd906..feeb130 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -11,15 +11,14 @@
 #include "bin/embedded_dart_io.h"
 #include "bin/io_buffer.h"
 #include "bin/utils.h"
-
 #include "include/dart_api.h"
 #include "include/dart_tools_api.h"
+#include "platform/globals.h"
 
 namespace dart {
 namespace bin {
 
 static const int kFileNativeFieldIndex = 0;
-static const int kMSPerSecond = 1000;
 
 // The file pointer has been passed into Dart as an intptr_t and it is safe
 // to pull it out of Dart as a 64-bit integer, cast it to an intptr_t and
@@ -346,13 +345,52 @@
   const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
   int64_t return_value = File::LastModified(name);
   if (return_value >= 0) {
-    Dart_SetReturnValue(args, Dart_NewInteger(return_value * kMSPerSecond));
+    Dart_SetReturnValue(args,
+                        Dart_NewInteger(return_value * kMillisecondsPerSecond));
   } else {
     Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
 
+void FUNCTION_NAME(File_SetLastModified)(Dart_NativeArguments args) {
+  const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+  int64_t millis;
+  if (!DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &millis)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "The second argument must be a 64-bit int."));
+  }
+  if (!File::SetLastModified(name, millis)) {
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+  }
+}
+
+
+void FUNCTION_NAME(File_LastAccessed)(Dart_NativeArguments args) {
+  const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+  int64_t return_value = File::LastAccessed(name);
+  if (return_value >= 0) {
+    Dart_SetReturnValue(args,
+                        Dart_NewInteger(return_value * kMillisecondsPerSecond));
+  } else {
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+  }
+}
+
+
+void FUNCTION_NAME(File_SetLastAccessed)(Dart_NativeArguments args) {
+  const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+  int64_t millis;
+  if (!DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &millis)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "The second argument must be a 64-bit int."));
+  }
+  if (!File::SetLastAccessed(name, millis)) {
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+  }
+}
+
+
 void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
   File* file = GetFile(args);
   ASSERT(file != NULL);
@@ -846,12 +884,58 @@
 }
 
 
+CObject* File::LastAccessedRequest(const CObjectArray& request) {
+  if ((request.Length() == 1) && request[0]->IsString()) {
+    CObjectString filepath(request[0]);
+    int64_t return_value = File::LastAccessed(filepath.CString());
+    if (return_value >= 0) {
+      return new CObjectIntptr(
+          CObject::NewInt64(return_value * kMillisecondsPerSecond));
+    } else {
+      return CObject::NewOSError();
+    }
+  }
+  return CObject::IllegalArgumentError();
+}
+
+
+CObject* File::SetLastAccessedRequest(const CObjectArray& request) {
+  if ((request.Length() == 2) && request[0]->IsString() &&
+      request[1]->IsInt32OrInt64()) {
+    CObjectString filepath(request[0]);
+    const int64_t millis = CObjectInt32OrInt64ToInt64(request[1]);
+    if (File::SetLastAccessed(filepath.CString(), millis)) {
+      return CObject::Null();
+    } else {
+      return CObject::NewOSError();
+    }
+  }
+  return CObject::IllegalArgumentError();
+}
+
+
 CObject* File::LastModifiedRequest(const CObjectArray& request) {
   if ((request.Length() == 1) && request[0]->IsString()) {
     CObjectString filepath(request[0]);
     int64_t return_value = File::LastModified(filepath.CString());
     if (return_value >= 0) {
-      return new CObjectIntptr(CObject::NewInt64(return_value * kMSPerSecond));
+      return new CObjectIntptr(
+          CObject::NewInt64(return_value * kMillisecondsPerSecond));
+    } else {
+      return CObject::NewOSError();
+    }
+  }
+  return CObject::IllegalArgumentError();
+}
+
+
+CObject* File::SetLastModifiedRequest(const CObjectArray& request) {
+  if ((request.Length() == 2) && request[0]->IsString() &&
+      request[1]->IsInt32OrInt64()) {
+    CObjectString filepath(request[0]);
+    const int64_t millis = CObjectInt32OrInt64ToInt64(request[1]);
+    if (File::SetLastModified(filepath.CString(), millis)) {
+      return CObject::Null();
     } else {
       return CObject::NewOSError();
     }
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 300e561..d5d76b7 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -163,6 +163,9 @@
   static int64_t LengthFromPath(const char* path);
   static void Stat(const char* path, int64_t* data);
   static time_t LastModified(const char* path);
+  static bool SetLastModified(const char* path, int64_t millis);
+  static time_t LastAccessed(const char* path);
+  static bool SetLastAccessed(const char* path, int64_t millis);
   static bool IsAbsolutePath(const char* path);
   static const char* PathSeparator();
   static const char* StringEscapedPathSeparator();
@@ -190,6 +193,9 @@
   static CObject* LengthRequest(const CObjectArray& request);
   static CObject* LengthFromPathRequest(const CObjectArray& request);
   static CObject* LastModifiedRequest(const CObjectArray& request);
+  static CObject* SetLastModifiedRequest(const CObjectArray& request);
+  static CObject* LastAccessedRequest(const CObjectArray& request);
+  static CObject* SetLastAccessedRequest(const CObjectArray& request);
   static CObject* FlushRequest(const CObjectArray& request);
   static CObject* ReadByteRequest(const CObjectArray& request);
   static CObject* WriteByteRequest(const CObjectArray& request);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 74aa81f..4ec84278 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -15,6 +15,7 @@
 #include <sys/stat.h>      // NOLINT
 #include <sys/types.h>     // NOLINT
 #include <unistd.h>        // NOLINT
+#include <utime.h>         // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/fdutils.h"
@@ -386,18 +387,26 @@
 }
 
 
+static bool StatHelper(const char* name, struct stat* st) {
+  if (NO_RETRY_EXPECTED(stat(name, st)) != 0) {
+    return false;
+  }
+  // Signal an error if it's a directory.
+  if (S_ISDIR(st->st_mode)) {
+    errno = EISDIR;
+    return false;
+  }
+  // Otherwise assume the caller knows what it's doing.
+  return true;
+}
+
+
 int64_t File::LengthFromPath(const char* name) {
   struct stat st;
-  if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_size;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_size;
 }
 
 
@@ -426,16 +435,49 @@
 
 time_t File::LastModified(const char* name) {
   struct stat st;
-  if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_mtime;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_mtime;
+}
+
+
+time_t File::LastAccessed(const char* name) {
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return -1;
+  }
+  return st.st_atime;
+}
+
+
+bool File::SetLastAccessed(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = millis / kMillisecondsPerSecond;
+  times.modtime = st.st_mtime;
+  return utime(name, &times) == 0;
+}
+
+
+bool File::SetLastModified(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = st.st_atime;
+  times.modtime = millis / kMillisecondsPerSecond;
+  return utime(name, &times) == 0;
 }
 
 
diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
index 7175d55..1959595 100644
--- a/runtime/bin/file_fuchsia.cc
+++ b/runtime/bin/file_fuchsia.cc
@@ -14,6 +14,7 @@
 #include <sys/stat.h>   // NOLINT
 #include <sys/types.h>  // NOLINT
 #include <unistd.h>     // NOLINT
+#include <utime.h>      // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/fdutils.h"
@@ -359,18 +360,26 @@
 }
 
 
-int64_t File::LengthFromPath(const char* name) {
-  struct stat st;
-  if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_size;
+static bool StatHelper(const char* name, struct stat64* st) {
+  if (NO_RETRY_EXPECTED(stat64(name, st)) != 0) {
+    return false;
   }
-  return -1;
+  // Signal an error if it's a directory.
+  if (S_ISDIR(st->st_mode)) {
+    errno = EISDIR;
+    return false;
+  }
+  // Otherwise assume the caller knows what it's doing.
+  return true;
+}
+
+
+int64_t File::LengthFromPath(const char* name) {
+  struct stat64 st;
+  if (!StatHelper(name, &st)) {
+    return -1;
+  }
+  return st.st_size;
 }
 
 
@@ -399,16 +408,49 @@
 
 time_t File::LastModified(const char* name) {
   struct stat st;
-  if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_mtime;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_mtime;
+}
+
+
+time_t File::LastAccessed(const char* name) {
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return -1;
+  }
+  return st.st_atime;
+}
+
+
+bool File::SetLastAccessed(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = millis / kMillisecondsPerSecond;
+  times.modtime = st.st_mtime;
+  return utime(name, &times) == 0;
+}
+
+
+bool File::SetLastModified(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = st.st_atime;
+  times.modtime = millis / kMillisecondsPerSecond;
+  return utime(name, &times) == 0;
 }
 
 
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index fd2a3c2..33d809f 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -15,6 +15,7 @@
 #include <sys/stat.h>      // NOLINT
 #include <sys/types.h>     // NOLINT
 #include <unistd.h>        // NOLINT
+#include <utime.h>         // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/fdutils.h"
@@ -387,18 +388,26 @@
 }
 
 
+static bool StatHelper(const char* name, struct stat64* st) {
+  if (TEMP_FAILURE_RETRY(stat64(name, st)) != 0) {
+    return false;
+  }
+  // Signal an error if it's a directory.
+  if (S_ISDIR(st->st_mode)) {
+    errno = EISDIR;
+    return false;
+  }
+  // Otherwise assume the caller knows what it's doing.
+  return true;
+}
+
+
 int64_t File::LengthFromPath(const char* name) {
   struct stat64 st;
-  if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_size;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_size;
 }
 
 
@@ -433,16 +442,49 @@
 
 time_t File::LastModified(const char* name) {
   struct stat64 st;
-  if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_mtime;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_mtime;
+}
+
+
+time_t File::LastAccessed(const char* name) {
+  struct stat64 st;
+  if (!StatHelper(name, &st)) {
+    return -1;
+  }
+  return st.st_atime;
+}
+
+
+bool File::SetLastAccessed(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat64 st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = millis / kMillisecondsPerSecond;
+  times.modtime = st.st_mtime;
+  return utime(name, &times) == 0;
+}
+
+
+bool File::SetLastModified(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat64 st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = st.st_atime;
+  times.modtime = millis / kMillisecondsPerSecond;
+  return utime(name, &times) == 0;
 }
 
 
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 767908e..842982f 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -15,6 +15,7 @@
 #include <sys/mman.h>  // NOLINT
 #include <sys/stat.h>  // NOLINT
 #include <unistd.h>    // NOLINT
+#include <utime.h>     // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/fdutils.h"
@@ -344,18 +345,26 @@
 }
 
 
+static bool StatHelper(const char* name, struct stat* st) {
+  if (NO_RETRY_EXPECTED(stat(name, st)) != 0) {
+    return false;
+  }
+  // Signal an error if it's a directory.
+  if (S_ISDIR(st->st_mode)) {
+    errno = EISDIR;
+    return false;
+  }
+  // Otherwise assume the caller knows what it's doing.
+  return true;
+}
+
+
 int64_t File::LengthFromPath(const char* name) {
   struct stat st;
-  if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_size;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_size;
 }
 
 
@@ -393,16 +402,49 @@
 
 time_t File::LastModified(const char* name) {
   struct stat st;
-  if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
-    // Signal an error if it's a directory.
-    if (S_ISDIR(st.st_mode)) {
-      errno = EISDIR;
-      return -1;
-    }
-    // Otherwise assume the caller knows what it's doing.
-    return st.st_mtime;
+  if (!StatHelper(name, &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_mtime;
+}
+
+
+time_t File::LastAccessed(const char* name) {
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return -1;
+  }
+  return st.st_atime;
+}
+
+
+bool File::SetLastAccessed(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = millis / kMillisecondsPerSecond;
+  times.modtime = st.st_mtime;
+  return utime(name, &times) == 0;
+}
+
+
+bool File::SetLastModified(const char* name, int64_t millis) {
+  // First get the current times.
+  struct stat st;
+  if (!StatHelper(name, &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct utimbuf times;
+  times.actime = st.st_atime;
+  times.modtime = millis / kMillisecondsPerSecond;
+  return utime(name, &times) == 0;
 }
 
 
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 5e4b16a..ec98f04 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -17,6 +17,11 @@
   @patch static _copy(String oldPath, String newPath) native "File_Copy";
   @patch static _lengthFromPath(String path) native "File_LengthFromPath";
   @patch static _lastModified(String path) native "File_LastModified";
+  @patch static _setLastModified(String path, int millis)
+      native "File_SetLastModified";
+  @patch static _lastAccessed(String path) native "File_LastAccessed";
+  @patch static _setLastAccessed(String path, int millis)
+      native "File_SetLastAccessed";
   @patch static _open(String path, int mode) native "File_Open";
   @patch static int _openStdio(int fd) native "File_OpenStdio";
 }
diff --git a/runtime/bin/file_unsupported.cc b/runtime/bin/file_unsupported.cc
index 88e85c6..9196c22 100644
--- a/runtime/bin/file_unsupported.cc
+++ b/runtime/bin/file_unsupported.cc
@@ -108,6 +108,24 @@
 }
 
 
+void FUNCTION_NAME(File_LastAccessed)(Dart_NativeArguments args) {
+  Dart_ThrowException(
+      DartUtils::NewInternalError("File is not supported on this platform"));
+}
+
+
+void FUNCTION_NAME(File_SetLastModified)(Dart_NativeArguments args) {
+  Dart_ThrowException(
+      DartUtils::NewInternalError("File is not supported on this platform"));
+}
+
+
+void FUNCTION_NAME(File_SetLastAccessed)(Dart_NativeArguments args) {
+  Dart_ThrowException(
+      DartUtils::NewInternalError("File is not supported on this platform"));
+}
+
+
 void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
   Dart_ThrowException(
       DartUtils::NewInternalError("File is not supported on this platform"));
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 3cfdf69..9101ee6 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -12,6 +12,7 @@
 #include <stdio.h>     // NOLINT
 #include <string.h>    // NOLINT
 #include <sys/stat.h>  // NOLINT
+#include <sys/utime.h>  // NOLINT
 #include <WinIoCtl.h>  // NOLINT
 
 #include "bin/builtin.h"
@@ -255,15 +256,23 @@
 }
 
 
+static bool StatHelper(wchar_t* path, struct __stat64* st) {
+  int stat_status = _wstat64(path, st);
+  if (stat_status != 0) {
+    return false;
+  }
+  if ((st->st_mode & S_IFMT) != S_IFREG) {
+    SetLastError(ERROR_NOT_SUPPORTED);
+    return false;
+  }
+  return true;
+}
+
+
 bool File::Exists(const char* name) {
   struct __stat64 st;
   Utf8ToWideScope system_name(name);
-  bool stat_status = _wstat64(system_name.wide(), &st);
-  if (stat_status == 0) {
-    return ((st.st_mode & S_IFMT) == S_IFREG);
-  } else {
-    return false;
-  }
+  return StatHelper(system_name.wide(), &st);
 }
 
 
@@ -442,16 +451,10 @@
 int64_t File::LengthFromPath(const char* name) {
   struct __stat64 st;
   Utf8ToWideScope system_name(name);
-  int stat_status = _wstat64(system_name.wide(), &st);
-  if (stat_status == 0) {
-    if ((st.st_mode & S_IFMT) == S_IFREG) {
-      return st.st_size;
-    } else {
-      // ERROR_DIRECTORY_NOT_SUPPORTED is not always in the message table.
-      SetLastError(ERROR_NOT_SUPPORTED);
-    }
+  if (!StatHelper(system_name.wide(), &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_size;
 }
 
 
@@ -539,19 +542,55 @@
 }
 
 
+time_t File::LastAccessed(const char* name) {
+  struct __stat64 st;
+  Utf8ToWideScope system_name(name);
+  if (!StatHelper(system_name.wide(), &st)) {
+    return -1;
+  }
+  return st.st_atime;
+}
+
+
 time_t File::LastModified(const char* name) {
   struct __stat64 st;
   Utf8ToWideScope system_name(name);
-  int stat_status = _wstat64(system_name.wide(), &st);
-  if (stat_status == 0) {
-    if ((st.st_mode & S_IFMT) == S_IFREG) {
-      return st.st_mtime;
-    } else {
-      // ERROR_DIRECTORY_NOT_SUPPORTED is not always in the message table.
-      SetLastError(ERROR_NOT_SUPPORTED);
-    }
+  if (!StatHelper(system_name.wide(), &st)) {
+    return -1;
   }
-  return -1;
+  return st.st_mtime;
+}
+
+
+bool File::SetLastAccessed(const char* name, int64_t millis) {
+  // First get the current times.
+  struct __stat64 st;
+  Utf8ToWideScope system_name(name);
+  if (!StatHelper(system_name.wide(), &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct __utimbuf64 times;
+  times.actime = millis / kMillisecondsPerSecond;
+  times.modtime = st.st_mtime;
+  return _wutime64(system_name.wide(), &times) == 0;
+}
+
+
+bool File::SetLastModified(const char* name, int64_t millis) {
+  // First get the current times.
+  struct __stat64 st;
+  Utf8ToWideScope system_name(name);
+  if (!StatHelper(system_name.wide(), &st)) {
+    return false;
+  }
+
+  // Set the new time:
+  struct __utimbuf64 times;
+  times.actime = st.st_atime;
+  times.modtime = millis / kMillisecondsPerSecond;
+  return _wutime64(system_name.wide(), &times) == 0;
 }
 
 
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index ef809ba..732493d 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -385,6 +385,7 @@
     Log::PrintErr("Error: Unable to write snapshot file: %s\n\n", filename);
     Dart_ExitScope();
     Dart_ShutdownIsolate();
+    Dart_Cleanup();
     exit(kErrorExitCode);
   }
   if (!file->WriteFully(buffer, size)) {
@@ -447,7 +448,7 @@
     result = Dart_NewStringFromUTF8(payload, payload_length);
     free(payload);
   } else {
-    result = DartUtils::NewString(result_string);
+    result = Dart_NewApiError(result_string);
     free(result_string);
   }
   return result;
diff --git a/runtime/bin/hashmap_test.cc b/runtime/bin/hashmap_test.cc
index bad384b..a0ca5b9 100644
--- a/runtime/bin/hashmap_test.cc
+++ b/runtime/bin/hashmap_test.cc
@@ -171,7 +171,7 @@
 }
 
 
-UNIT_TEST_CASE(HashMap_Basic) {
+VM_UNIT_TEST_CASE(HashMap_Basic) {
   TestSet(WordHash, 100);
   TestSet(Hash, 100);
   TestSet(CollisionHash1, 50);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index d6d5c09..2c58242 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -50,6 +50,9 @@
   V(File_LengthFromPath, 1)                                                    \
   V(File_Stat, 1)                                                              \
   V(File_LastModified, 1)                                                      \
+  V(File_SetLastModified, 2)                                                   \
+  V(File_LastAccessed, 1)                                                      \
+  V(File_SetLastAccessed, 2)                                                   \
   V(File_Flush, 1)                                                             \
   V(File_Lock, 4)                                                              \
   V(File_Create, 1)                                                            \
diff --git a/runtime/bin/io_service.h b/runtime/bin/io_service.h
index 7439253..51691f5 100644
--- a/runtime/bin/io_service.h
+++ b/runtime/bin/io_service.h
@@ -30,33 +30,36 @@
   V(File, Truncate, 10)                                                        \
   V(File, Length, 11)                                                          \
   V(File, LengthFromPath, 12)                                                  \
-  V(File, LastModified, 13)                                                    \
-  V(File, Flush, 14)                                                           \
-  V(File, ReadByte, 15)                                                        \
-  V(File, WriteByte, 16)                                                       \
-  V(File, Read, 17)                                                            \
-  V(File, ReadInto, 18)                                                        \
-  V(File, WriteFrom, 19)                                                       \
-  V(File, CreateLink, 20)                                                      \
-  V(File, DeleteLink, 21)                                                      \
-  V(File, RenameLink, 22)                                                      \
-  V(File, LinkTarget, 23)                                                      \
-  V(File, Type, 24)                                                            \
-  V(File, Identical, 25)                                                       \
-  V(File, Stat, 26)                                                            \
-  V(File, Lock, 27)                                                            \
-  V(Socket, Lookup, 28)                                                        \
-  V(Socket, ListInterfaces, 29)                                                \
-  V(Socket, ReverseLookup, 30)                                                 \
-  V(Directory, Create, 31)                                                     \
-  V(Directory, Delete, 32)                                                     \
-  V(Directory, Exists, 33)                                                     \
-  V(Directory, CreateTemp, 34)                                                 \
-  V(Directory, ListStart, 35)                                                  \
-  V(Directory, ListNext, 36)                                                   \
-  V(Directory, ListStop, 37)                                                   \
-  V(Directory, Rename, 38)                                                     \
-  V(SSLFilter, ProcessFilter, 39)
+  V(File, LastAccessed, 13)                                                    \
+  V(File, SetLastAccessed, 14)                                                 \
+  V(File, LastModified, 15)                                                    \
+  V(File, SetLastModified, 16)                                                 \
+  V(File, Flush, 17)                                                           \
+  V(File, ReadByte, 18)                                                        \
+  V(File, WriteByte, 19)                                                       \
+  V(File, Read, 20)                                                            \
+  V(File, ReadInto, 21)                                                        \
+  V(File, WriteFrom, 22)                                                       \
+  V(File, CreateLink, 23)                                                      \
+  V(File, DeleteLink, 24)                                                      \
+  V(File, RenameLink, 25)                                                      \
+  V(File, LinkTarget, 26)                                                      \
+  V(File, Type, 27)                                                            \
+  V(File, Identical, 28)                                                       \
+  V(File, Stat, 29)                                                            \
+  V(File, Lock, 30)                                                            \
+  V(Socket, Lookup, 31)                                                        \
+  V(Socket, ListInterfaces, 32)                                                \
+  V(Socket, ReverseLookup, 33)                                                 \
+  V(Directory, Create, 34)                                                     \
+  V(Directory, Delete, 35)                                                     \
+  V(Directory, Exists, 36)                                                     \
+  V(Directory, CreateTemp, 37)                                                 \
+  V(Directory, ListStart, 38)                                                  \
+  V(Directory, ListNext, 39)                                                   \
+  V(Directory, ListStop, 40)                                                   \
+  V(Directory, Rename, 41)                                                     \
+  V(SSLFilter, ProcessFilter, 42)
 
 #define DECLARE_REQUEST(type, method, id) k##type##method##Request = id,
 
diff --git a/runtime/bin/io_service_no_ssl.h b/runtime/bin/io_service_no_ssl.h
index 125f237..abedd1c 100644
--- a/runtime/bin/io_service_no_ssl.h
+++ b/runtime/bin/io_service_no_ssl.h
@@ -16,7 +16,7 @@
 namespace bin {
 
 // This list must be kept in sync with the list in sdk/lib/io/io_service.dart
-// In this modified version, though, the request 39 for SSLFilter::ProcessFilter
+// In this modified version, though, the request 42 for SSLFilter::ProcessFilter
 // is removed, for use in contexts in which secure sockets are not enabled.
 #define IO_SERVICE_REQUEST_LIST(V)                                             \
   V(File, Exists, 0)                                                           \
@@ -32,32 +32,35 @@
   V(File, Truncate, 10)                                                        \
   V(File, Length, 11)                                                          \
   V(File, LengthFromPath, 12)                                                  \
-  V(File, LastModified, 13)                                                    \
-  V(File, Flush, 14)                                                           \
-  V(File, ReadByte, 15)                                                        \
-  V(File, WriteByte, 16)                                                       \
-  V(File, Read, 17)                                                            \
-  V(File, ReadInto, 18)                                                        \
-  V(File, WriteFrom, 19)                                                       \
-  V(File, CreateLink, 20)                                                      \
-  V(File, DeleteLink, 21)                                                      \
-  V(File, RenameLink, 22)                                                      \
-  V(File, LinkTarget, 23)                                                      \
-  V(File, Type, 24)                                                            \
-  V(File, Identical, 25)                                                       \
-  V(File, Stat, 26)                                                            \
-  V(File, Lock, 27)                                                            \
-  V(Socket, Lookup, 28)                                                        \
-  V(Socket, ListInterfaces, 29)                                                \
-  V(Socket, ReverseLookup, 30)                                                 \
-  V(Directory, Create, 31)                                                     \
-  V(Directory, Delete, 32)                                                     \
-  V(Directory, Exists, 33)                                                     \
-  V(Directory, CreateTemp, 34)                                                 \
-  V(Directory, ListStart, 35)                                                  \
-  V(Directory, ListNext, 36)                                                   \
-  V(Directory, ListStop, 37)                                                   \
-  V(Directory, Rename, 38)
+  V(File, LastAccessed, 13)                                                    \
+  V(File, SetLastAccessed, 14)                                                 \
+  V(File, LastModified, 15)                                                    \
+  V(File, SetLastModified, 16)                                                 \
+  V(File, Flush, 17)                                                           \
+  V(File, ReadByte, 18)                                                        \
+  V(File, WriteByte, 19)                                                       \
+  V(File, Read, 20)                                                            \
+  V(File, ReadInto, 21)                                                        \
+  V(File, WriteFrom, 22)                                                       \
+  V(File, CreateLink, 23)                                                      \
+  V(File, DeleteLink, 24)                                                      \
+  V(File, RenameLink, 25)                                                      \
+  V(File, LinkTarget, 26)                                                      \
+  V(File, Type, 27)                                                            \
+  V(File, Identical, 28)                                                       \
+  V(File, Stat, 29)                                                            \
+  V(File, Lock, 30)                                                            \
+  V(Socket, Lookup, 31)                                                        \
+  V(Socket, ListInterfaces, 32)                                                \
+  V(Socket, ReverseLookup, 33)                                                 \
+  V(Directory, Create, 34)                                                     \
+  V(Directory, Delete, 35)                                                     \
+  V(Directory, Exists, 36)                                                     \
+  V(Directory, CreateTemp, 37)                                                 \
+  V(Directory, ListStart, 38)                                                  \
+  V(Directory, ListNext, 39)                                                   \
+  V(Directory, ListStop, 40)                                                   \
+  V(Directory, Rename, 41)
 
 #define DECLARE_REQUEST(type, method, id) k##type##method##Request = id,
 
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index b5f958d..6a104c1 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -13,6 +13,7 @@
 #include "bin/dartutils.h"
 #include "bin/directory.h"
 #include "bin/embedded_dart_io.h"
+#include "bin/error_exit.h"
 #include "bin/eventhandler.h"
 #include "bin/extensions.h"
 #include "bin/file.h"
@@ -21,6 +22,7 @@
 #include "bin/log.h"
 #include "bin/platform.h"
 #include "bin/process.h"
+#include "bin/snapshot_utils.h"
 #include "bin/thread.h"
 #include "bin/utils.h"
 #include "bin/vmservice_impl.h"
@@ -95,12 +97,6 @@
 static bool use_blobs = false;
 
 
-extern const char* kVmSnapshotDataSymbolName;
-extern const char* kVmSnapshotInstructionsSymbolName;
-extern const char* kIsolateSnapshotDataSymbolName;
-extern const char* kIsolateSnapshotInstructionsSymbolName;
-
-
 // Global flag that is used to indicate that we want to trace resolution of
 // URIs and the loading of libraries, parts and scripts.
 static bool trace_loading = false;
@@ -125,37 +121,6 @@
 // checks are disabled.
 static bool vm_service_dev_mode = false;
 
-// Exit code indicating an API error.
-static const int kApiErrorExitCode = 253;
-// Exit code indicating a compilation error.
-static const int kCompilationErrorExitCode = 254;
-// Exit code indicating an unhandled error that is not a compilation error.
-static const int kErrorExitCode = 255;
-// Exit code indicating a vm restart request.  Never returned to the user.
-static const int kRestartRequestExitCode = 1000;
-
-static void ErrorExit(int exit_code, const char* format, ...) {
-  va_list arguments;
-  va_start(arguments, format);
-  Log::VPrintErr(format, arguments);
-  va_end(arguments);
-
-  Dart_ExitScope();
-  Dart_ShutdownIsolate();
-
-  // Terminate process exit-code handler.
-  Process::TerminateExitCodeHandler();
-
-  char* error = Dart_Cleanup();
-  if (error != NULL) {
-    Log::PrintErr("VM cleanup failed: %s\n", error);
-    free(error);
-  }
-
-  EventHandler::Stop();
-  Platform::Exit(exit_code);
-}
-
 
 // The environment provided through the command line using -D options.
 static dart::HashMap* environment = NULL;
@@ -806,10 +771,21 @@
   }
 
 
-static void SnapshotOnExitHook(int64_t exit_code);
+static void SnapshotOnExitHook(int64_t exit_code) {
+  if (Dart_CurrentIsolate() != main_isolate) {
+    Log::PrintErr(
+        "A snapshot was requested, but a secondary isolate "
+        "performed a hard exit (%" Pd64 ").\n",
+        exit_code);
+    Platform::Exit(kErrorExitCode);
+  }
+  if (exit_code == 0) {
+    Snapshot::GenerateAppJIT(snapshot_filename);
+  }
+}
 
 
-// Returns true on success, false on failure.
+// Returns newly created Isolate on success, NULL on failure.
 static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate,
                                                 const char* script_uri,
                                                 const char* main,
@@ -819,14 +795,18 @@
                                                 char** error,
                                                 int* exit_code) {
   ASSERT(script_uri != NULL);
-  if (strcmp(script_uri, DART_KERNEL_ISOLATE_NAME) == 0) {
+  const bool is_service_isolate =
+      strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0;
+  const bool is_kernel_isolate =
+      strcmp(script_uri, DART_KERNEL_ISOLATE_NAME) == 0;
+  if (is_kernel_isolate) {
     if (!use_dart_frontend) {
       *error = strdup("Kernel isolate not supported.");
       return NULL;
-    } else {
-      if (packages_config == NULL) {
-        packages_config = commandline_packages_file;
-      }
+    }
+    script_uri = frontend_filename;
+    if (packages_config == NULL) {
+      packages_config = commandline_packages_file;
     }
   }
 
@@ -849,16 +829,50 @@
     isolate_run_app_snapshot = true;
     isolate_snapshot_data = app_isolate_snapshot_data;
     isolate_snapshot_instructions = app_isolate_snapshot_instructions;
+  } else if (!is_main_isolate) {
+    const uint8_t* file_vm_snapshot_data = NULL;
+    const uint8_t* file_vm_snapshot_instructions = NULL;
+    const uint8_t* file_isolate_snapshot_data = NULL;
+    const uint8_t* file_isolate_snapshot_instructions = NULL;
+    if (Snapshot::ReadAppSnapshot(
+            script_uri, &file_vm_snapshot_data, &file_vm_snapshot_instructions,
+            &file_isolate_snapshot_data, &file_isolate_snapshot_instructions)) {
+      // TODO(rmacnak): We are leaking the snapshot when the isolate shuts down.
+      isolate_run_app_snapshot = true;
+      isolate_snapshot_data = file_isolate_snapshot_data;
+      isolate_snapshot_instructions = file_isolate_snapshot_instructions;
+    }
   }
 #endif
 
-  // If the script is a Kernel binary, then we will try to bootstrap from the
-  // script.
   const uint8_t* kernel_file = NULL;
   intptr_t kernel_length = -1;
-  const bool is_kernel =
-      !isolate_run_app_snapshot &&
-      TryReadKernel(script_uri, &kernel_file, &kernel_length);
+  bool is_kernel = false;
+
+  if (!is_kernel_isolate && !is_service_isolate) {
+    if (use_dart_frontend) {
+      Dart_KernelCompilationResult result = Dart_CompileToKernel(script_uri);
+      *error = result.error;  // Copy error message (if any).
+      switch (result.status) {
+        case Dart_KernelCompilationStatus_Ok:
+          is_kernel = true;
+          kernel_file = result.kernel;
+          kernel_length = result.kernel_size;
+          break;
+        case Dart_KernelCompilationStatus_Error:
+          *exit_code = kCompilationErrorExitCode;
+          return NULL;
+        case Dart_KernelCompilationStatus_Crash:
+          *exit_code = kDartFrontendErrorExitCode;
+          return NULL;
+        case Dart_KernelCompilationStatus_Unknown:
+          *exit_code = kErrorExitCode;
+          return NULL;
+      }
+    } else if (!isolate_run_app_snapshot) {
+      is_kernel = TryReadKernel(script_uri, &kernel_file, &kernel_length);
+    }
+  }
 
   void* kernel_program = NULL;
   if (is_kernel) {
@@ -868,6 +882,8 @@
 
   IsolateData* isolate_data =
       new IsolateData(script_uri, package_root, packages_config);
+  // If the script is a Kernel binary, then we will try to bootstrap from the
+  // script.
   Dart_Isolate isolate =
       is_kernel ? Dart_CreateIsolateFromKernel(script_uri, main, kernel_program,
                                                flags, isolate_data, error)
@@ -929,10 +945,6 @@
   result = DartUtils::SetupServiceLoadPort();
   CHECK_RESULT(result);
 
-  if (Dart_IsKernelIsolate(isolate)) {
-    script_uri = frontend_filename;
-  }
-
   // Setup package root if specified.
   result = DartUtils::SetupPackageRoot(package_root, packages_config);
   CHECK_RESULT(result);
@@ -940,16 +952,6 @@
   result = Dart_SetEnvironmentCallback(EnvironmentCallback);
   CHECK_RESULT(result);
 
-  if (!Dart_IsKernelIsolate(isolate) && use_dart_frontend) {
-    // This must be the main script to be loaded. Wait for Kernel isolate
-    // to finish initialization.
-    Dart_Port port = Dart_ServiceWaitForKernelPort();
-    if (port == ILLEGAL_PORT) {
-      *error = strdup("Error while initializing Kernel isolate");
-      return NULL;
-    }
-  }
-
   if (isolate_run_app_snapshot) {
     result = DartUtils::SetupIOLibrary(script_uri);
     CHECK_RESULT(result);
@@ -975,6 +977,12 @@
     if (!is_kernel) {
       result = Loader::LibraryTagHandler(Dart_kScriptTag, Dart_Null(), uri);
       CHECK_RESULT(result);
+    } else {
+      // Various core-library parts will send requests to the Loader to resolve
+      // relative URIs and perform other related tasks. We need Loader to be
+      // initialized for this to work because loading from Kernel binary
+      // bypasses normal source code loading paths that initialize it.
+      Loader::InitForSnapshot(script_uri);
     }
 
     Dart_TimelineEvent("LoadScript", Dart_TimelineGetMicros(),
@@ -1261,345 +1269,15 @@
 }
 
 
-static void WriteSnapshotFile(const char* filename,
-                              bool write_magic_number,
-                              const uint8_t* buffer,
-                              const intptr_t size) {
-  char* concat = NULL;
-  File* file = File::Open(filename, File::kWriteTruncate);
-  if (file == NULL) {
-    ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n",
-              filename);
-  }
-
-  if (write_magic_number) {
-    // Write the magic number to indicate file is a script snapshot.
-    DartUtils::WriteMagicNumber(file);
-  }
-
-  if (!file->WriteFully(buffer, size)) {
-    ErrorExit(kErrorExitCode, "Unable to write file %s for writing snapshot\n",
-              filename);
-  }
-  file->Release();
-  if (concat != NULL) {
-    delete concat;
-  }
-}
-
-
-static const int64_t kAppSnapshotHeaderSize = 5 * sizeof(int64_t);  // NOLINT
-static const int64_t kAppSnapshotMagicNumber = 0xf6f6dcdc;
-static const int64_t kAppSnapshotPageSize = 4 * KB;
-
-
-static bool ReadAppSnapshotBlobs(const char* script_name,
-                                 const uint8_t** vm_data_buffer,
-                                 const uint8_t** vm_instructions_buffer,
-                                 const uint8_t** isolate_data_buffer,
-                                 const uint8_t** isolate_instructions_buffer) {
-  File* file = File::Open(script_name, File::kRead);
-  if (file == NULL) {
-    return false;
-  }
-  if (file->Length() < kAppSnapshotHeaderSize) {
-    file->Release();
-    return false;
-  }
-  int64_t header[5];
-  ASSERT(sizeof(header) == kAppSnapshotHeaderSize);
-  if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) {
-    file->Release();
-    return false;
-  }
-  if (header[0] != kAppSnapshotMagicNumber) {
-    file->Release();
-    return false;
-  }
-
-  int64_t vm_data_size = header[1];
-  int64_t vm_data_position =
-      Utils::RoundUp(file->Position(), kAppSnapshotPageSize);
-  int64_t vm_instructions_size = header[2];
-  int64_t vm_instructions_position = vm_data_position + vm_data_size;
-  if (vm_instructions_size != 0) {
-    vm_instructions_position =
-        Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize);
-  }
-  int64_t isolate_data_size = header[3];
-  int64_t isolate_data_position = Utils::RoundUp(
-      vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize);
-  int64_t isolate_instructions_size = header[4];
-  int64_t isolate_instructions_position =
-      isolate_data_position + isolate_data_size;
-  if (isolate_instructions_size != 0) {
-    isolate_instructions_position =
-        Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize);
-  }
-
-  if (vm_data_size != 0) {
-    *vm_data_buffer = reinterpret_cast<const uint8_t*>(
-        file->Map(File::kReadOnly, vm_data_position, vm_data_size));
-    if (vm_data_buffer == NULL) {
-      Log::PrintErr("Failed to memory map snapshot\n");
-      Platform::Exit(kErrorExitCode);
-    }
-  }
-
-  if (vm_instructions_size != 0) {
-    *vm_instructions_buffer = reinterpret_cast<const uint8_t*>(file->Map(
-        File::kReadExecute, vm_instructions_position, vm_instructions_size));
-    if (*vm_instructions_buffer == NULL) {
-      Log::PrintErr("Failed to memory map snapshot\n");
-      Platform::Exit(kErrorExitCode);
-    }
-  }
-
-  *isolate_data_buffer = reinterpret_cast<const uint8_t*>(
-      file->Map(File::kReadOnly, isolate_data_position, isolate_data_size));
-  if (isolate_data_buffer == NULL) {
-    Log::PrintErr("Failed to memory map snapshot\n");
-    Platform::Exit(kErrorExitCode);
-  }
-
-  if (isolate_instructions_size == 0) {
-    *isolate_instructions_buffer = NULL;
-  } else {
-    *isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
-        file->Map(File::kReadExecute, isolate_instructions_position,
-                  isolate_instructions_size));
-    if (*isolate_instructions_buffer == NULL) {
-      Log::PrintErr("Failed to memory map snapshot\n");
-      Platform::Exit(kErrorExitCode);
-    }
-  }
-
-  file->Release();
-  return true;
-}
-
-
-#if defined(DART_PRECOMPILED_RUNTIME)
-static bool ReadAppSnapshotDynamicLibrary(
-    const char* script_name,
-    const uint8_t** vm_data_buffer,
-    const uint8_t** vm_instructions_buffer,
-    const uint8_t** isolate_data_buffer,
-    const uint8_t** isolate_instructions_buffer) {
-  void* library = Extensions::LoadExtensionLibrary(script_name);
-  if (library == NULL) {
-    return false;
-  }
-
-  *vm_data_buffer = reinterpret_cast<const uint8_t*>(
-      Extensions::ResolveSymbol(library, kVmSnapshotDataSymbolName));
-  if (*vm_data_buffer == NULL) {
-    Log::PrintErr("Failed to resolve symbol '%s'\n", kVmSnapshotDataSymbolName);
-    Platform::Exit(kErrorExitCode);
-  }
-
-  *vm_instructions_buffer = reinterpret_cast<const uint8_t*>(
-      Extensions::ResolveSymbol(library, kVmSnapshotInstructionsSymbolName));
-  if (*vm_instructions_buffer == NULL) {
-    Log::PrintErr("Failed to resolve symbol '%s'\n",
-                  kVmSnapshotInstructionsSymbolName);
-    Platform::Exit(kErrorExitCode);
-  }
-
-  *isolate_data_buffer = reinterpret_cast<const uint8_t*>(
-      Extensions::ResolveSymbol(library, kIsolateSnapshotDataSymbolName));
-  if (*isolate_data_buffer == NULL) {
-    Log::PrintErr("Failed to resolve symbol '%s'\n",
-                  kIsolateSnapshotDataSymbolName);
-    Platform::Exit(kErrorExitCode);
-  }
-
-  *isolate_instructions_buffer =
-      reinterpret_cast<const uint8_t*>(Extensions::ResolveSymbol(
-          library, kIsolateSnapshotInstructionsSymbolName));
-  if (*isolate_instructions_buffer == NULL) {
-    Log::PrintErr("Failed to resolve symbol '%s'\n",
-                  kIsolateSnapshotInstructionsSymbolName);
-    Platform::Exit(kErrorExitCode);
-  }
-
-  return true;
-}
-#endif  // defined(DART_PRECOMPILED_RUNTIME)
-
-
-static bool ReadAppSnapshot(const char* script_name,
-                            const uint8_t** vm_data_buffer,
-                            const uint8_t** vm_instructions_buffer,
-                            const uint8_t** isolate_data_buffer,
-                            const uint8_t** isolate_instructions_buffer) {
-  if (File::GetType(script_name, true) != File::kIsFile) {
-    // If 'script_name' refers to a pipe, don't read to check for an app
-    // snapshot since we cannot rewind if it isn't (and couldn't mmap it in
-    // anyway if it was).
-    return false;
-  }
-  if (ReadAppSnapshotBlobs(script_name, vm_data_buffer, vm_instructions_buffer,
-                           isolate_data_buffer, isolate_instructions_buffer)) {
-    return true;
-  }
-#if defined(DART_PRECOMPILED_RUNTIME)
-  // For testing AOT with the standalone embedder, we also support loading
-  // from a dynamic library to simulate what happens on iOS.
-  return ReadAppSnapshotDynamicLibrary(
-      script_name, vm_data_buffer, vm_instructions_buffer, isolate_data_buffer,
-      isolate_instructions_buffer);
-#else
-  return false;
-#endif  //  defined(DART_PRECOMPILED_RUNTIME)
-}
-
-
-static bool WriteInt64(File* file, int64_t size) {
-  return file->WriteFully(&size, sizeof(size));
-}
-
-
-static void WriteAppSnapshot(const char* filename,
-                             uint8_t* vm_data_buffer,
-                             intptr_t vm_data_size,
-                             uint8_t* vm_instructions_buffer,
-                             intptr_t vm_instructions_size,
-                             uint8_t* isolate_data_buffer,
-                             intptr_t isolate_data_size,
-                             uint8_t* isolate_instructions_buffer,
-                             intptr_t isolate_instructions_size) {
-  File* file = File::Open(filename, File::kWriteTruncate);
-  if (file == NULL) {
-    ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
-  }
-
-  file->WriteFully(&kAppSnapshotMagicNumber, sizeof(kAppSnapshotMagicNumber));
-  WriteInt64(file, vm_data_size);
-  WriteInt64(file, vm_instructions_size);
-  WriteInt64(file, isolate_data_size);
-  WriteInt64(file, isolate_instructions_size);
-  ASSERT(file->Position() == kAppSnapshotHeaderSize);
-
-  file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
-  if (!file->WriteFully(vm_data_buffer, vm_data_size)) {
-    ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
-  }
-
-  if (vm_instructions_size != 0) {
-    file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
-    if (!file->WriteFully(vm_instructions_buffer, vm_instructions_size)) {
-      ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
-                filename);
-    }
-  }
-
-  file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
-  if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) {
-    ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
-  }
-
-  if (isolate_instructions_size != 0) {
-    file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
-    if (!file->WriteFully(isolate_instructions_buffer,
-                          isolate_instructions_size)) {
-      ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
-                filename);
-    }
-  }
-
-  file->Flush();
-  file->Release();
-}
-
-
-static void GenerateScriptSnapshot() {
-  // First create a snapshot.
-  uint8_t* buffer = NULL;
-  intptr_t size = 0;
-  Dart_Handle result = Dart_CreateScriptSnapshot(&buffer, &size);
-  if (Dart_IsError(result)) {
-    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
-  }
-
-  WriteSnapshotFile(snapshot_filename, true, buffer, size);
-}
-
-
-static void GenerateAppAOTSnapshotAsBlobs() {
-  uint8_t* vm_data_buffer = NULL;
-  intptr_t vm_data_size = 0;
-  uint8_t* vm_instructions_buffer = NULL;
-  intptr_t vm_instructions_size = 0;
-  uint8_t* isolate_data_buffer = NULL;
-  intptr_t isolate_data_size = 0;
-  uint8_t* isolate_instructions_buffer = NULL;
-  intptr_t isolate_instructions_size = 0;
-  Dart_Handle result = Dart_CreateAppAOTSnapshotAsBlobs(
-      &vm_data_buffer, &vm_data_size, &vm_instructions_buffer,
-      &vm_instructions_size, &isolate_data_buffer, &isolate_data_size,
-      &isolate_instructions_buffer, &isolate_instructions_size);
-  if (Dart_IsError(result)) {
-    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
-  }
-  WriteAppSnapshot(snapshot_filename, vm_data_buffer, vm_data_size,
-                   vm_instructions_buffer, vm_instructions_size,
-                   isolate_data_buffer, isolate_data_size,
-                   isolate_instructions_buffer, isolate_instructions_size);
-}
-
-static void GenerateAppAOTSnapshotAsAssembly() {
-  uint8_t* assembly_buffer = NULL;
-  intptr_t assembly_size = 0;
-  Dart_Handle result =
-      Dart_CreateAppAOTSnapshotAsAssembly(&assembly_buffer, &assembly_size);
-  if (Dart_IsError(result)) {
-    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
-  }
-  WriteSnapshotFile(snapshot_filename, false, assembly_buffer, assembly_size);
-}
-
-
 static void GenerateAppAOTSnapshot() {
   if (use_blobs) {
-    GenerateAppAOTSnapshotAsBlobs();
+    Snapshot::GenerateAppAOTAsBlobs(snapshot_filename);
   } else {
-    GenerateAppAOTSnapshotAsAssembly();
+    Snapshot::GenerateAppAOTAsAssembly(snapshot_filename);
   }
 }
 
 
-static void GenerateAppJITSnapshot() {
-#if defined(TARGET_ARCH_X64)
-  uint8_t* isolate_data_buffer = NULL;
-  intptr_t isolate_data_size = 0;
-  uint8_t* isolate_instructions_buffer = NULL;
-  intptr_t isolate_instructions_size = 0;
-  Dart_Handle result = Dart_CreateAppJITSnapshotAsBlobs(
-      &isolate_data_buffer, &isolate_data_size, &isolate_instructions_buffer,
-      &isolate_instructions_size);
-  if (Dart_IsError(result)) {
-    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
-  }
-  WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_data_buffer,
-                   isolate_data_size, isolate_instructions_buffer,
-                   isolate_instructions_size);
-#else
-  uint8_t* isolate_buffer = NULL;
-  intptr_t isolate_size = 0;
-
-  Dart_Handle result =
-      Dart_CreateSnapshot(NULL, NULL, &isolate_buffer, &isolate_size);
-  if (Dart_IsError(result)) {
-    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
-  }
-
-  WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_buffer,
-                   isolate_size, NULL, 0);
-#endif  // defined(TARGET_ARCH_X64)
-}
-
-
 #define CHECK_RESULT(result)                                                   \
   if (Dart_IsError(result)) {                                                  \
     if (Dart_IsVMRestartRequest(result)) {                                     \
@@ -1614,17 +1292,17 @@
   }
 
 
-static void SnapshotOnExitHook(int64_t exit_code) {
-  if (Dart_CurrentIsolate() != main_isolate) {
-    Log::PrintErr(
-        "A snapshot was requested, but a secondary isolate "
-        "performed a hard exit (%" Pd64 ").\n",
-        exit_code);
-    Platform::Exit(kErrorExitCode);
+static void WriteFile(const char* filename,
+                      const uint8_t* buffer,
+                      const intptr_t size) {
+  File* file = File::Open(filename, File::kWriteTruncate);
+  if (file == NULL) {
+    ErrorExit(kErrorExitCode, "Unable to open file %s\n", filename);
   }
-  if (exit_code == 0) {
-    GenerateAppJITSnapshot();
+  if (!file->WriteFully(buffer, size)) {
+    ErrorExit(kErrorExitCode, "Unable to write file %s\n", filename);
   }
+  file->Release();
 }
 
 
@@ -1667,7 +1345,7 @@
   Dart_EnterScope();
 
   if (gen_snapshot_kind == kScript) {
-    GenerateScriptSnapshot();
+    Snapshot::GenerateScript(snapshot_filename);
   } else {
     // Lookup the library of the root script.
     Dart_Handle root_lib = Dart_RootLibrary();
@@ -1798,7 +1476,7 @@
       if (gen_snapshot_kind == kAppJIT) {
         if (!Dart_IsCompilationError(result) &&
             !Dart_IsVMRestartRequest(result)) {
-          GenerateAppJITSnapshot();
+          Snapshot::GenerateAppJIT(snapshot_filename);
         }
       }
       CHECK_RESULT(result);
@@ -1810,7 +1488,7 @@
         if (Dart_IsError(result)) {
           ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
         }
-        WriteSnapshotFile(save_feedback_filename, false, buffer, size);
+        WriteFile(save_feedback_filename, buffer, size);
       }
     }
   }
@@ -1961,9 +1639,9 @@
     Platform::Exit(kErrorExitCode);
   }
 
-  if (ReadAppSnapshot(script_name, &vm_snapshot_data, &vm_snapshot_instructions,
-                      &app_isolate_snapshot_data,
-                      &app_isolate_snapshot_instructions)) {
+  if (Snapshot::ReadAppSnapshot(
+          script_name, &vm_snapshot_data, &vm_snapshot_instructions,
+          &app_isolate_snapshot_data, &app_isolate_snapshot_instructions)) {
     vm_run_app_snapshot = true;
   }
 
diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc
index 0d3338c..e69466a2 100644
--- a/runtime/bin/platform_linux.cc
+++ b/runtime/bin/platform_linux.cc
@@ -54,6 +54,10 @@
     perror("sigaction() failed.");
     return false;
   }
+  if (sigaction(SIGTRAP, &act, NULL) != 0) {
+    perror("sigaction() failed.");
+    return false;
+  }
   return true;
 }
 
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 0c6de4d..537bb1e 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -59,6 +59,10 @@
     perror("sigaction() failed.");
     return false;
   }
+  if (sigaction(SIGTRAP, &act, NULL) != 0) {
+    perror("sigaction() failed.");
+    return false;
+  }
   return true;
 }
 
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
index 4b4b5d5..02c5055 100644
--- a/runtime/bin/process_fuchsia.cc
+++ b/runtime/bin/process_fuchsia.cc
@@ -236,15 +236,15 @@
     item_count_ = 1;
 
     while (!do_shutdown_) {
-      LOG_INFO("ExitCodeHandler Calling mx_handle_wait_many: %ld items\n",
+      LOG_INFO("ExitCodeHandler Calling mx_object_wait_many: %ld items\n",
                item_count_);
       mx_status_t status =
-          mx_handle_wait_many(items_, item_count_, MX_TIME_INFINITE);
+          mx_object_wait_many(items_, item_count_, MX_TIME_INFINITE);
       if (status < 0) {
         FATAL1("Exit code handler handle wait failed: %s\n",
                mx_status_get_string(status));
       }
-      LOG_INFO("ExitCodeHandler mx_handle_wait_many returned\n");
+      LOG_INFO("ExitCodeHandler mx_object_wait_many returned\n");
 
       bool have_interrupt = false;
       intptr_t remove_count = 0;
@@ -637,18 +637,9 @@
       }
       program_environment_[environment_length] = NULL;
     }
-
-    binary_vmo_ = MX_HANDLE_INVALID;
-    launchpad_ = NULL;
   }
 
   ~ProcessStarter() {
-    if (binary_vmo_ != MX_HANDLE_INVALID) {
-      mx_handle_close(binary_vmo_);
-    }
-    if (launchpad_ != NULL) {
-      launchpad_destroy(launchpad_);
-    }
     if (read_in_ != -1) {
       close(read_in_);
     }
@@ -672,27 +663,32 @@
     LOG_INFO("ProcessStarter: Start() set up exit_pipe_fds (%d, %d)\n",
              exit_pipe_fds[0], exit_pipe_fds[1]);
 
-    mx_status_t status = SetupLaunchpad();
+    // Set up a launchpad.
+    launchpad_t* lp = NULL;
+    mx_status_t status = SetupLaunchpad(&lp);
     if (status != NO_ERROR) {
       close(exit_pipe_fds[0]);
       close(exit_pipe_fds[1]);
       return status;
     }
+    ASSERT(lp != NULL);
 
+    // Launch it.
     LOG_INFO("ProcessStarter: Start() Calling launchpad_start\n");
-    mx_handle_t process = launchpad_start(launchpad_);
-    launchpad_destroy(launchpad_);
-    launchpad_ = NULL;
-    if (process < 0) {
+    mx_handle_t process = MX_HANDLE_INVALID;
+    const char* errormsg = NULL;
+    status = launchpad_go(lp, &process, &errormsg);
+    lp = NULL;  // launchpad_go() calls launchpad_destroy() on the launchpad.
+    if (status < 0) {
       LOG_INFO("ProcessStarter: Start() launchpad_start failed\n");
       const intptr_t kMaxMessageSize = 256;
       close(exit_pipe_fds[0]);
       close(exit_pipe_fds[1]);
       char* message = DartUtils::ScopedCString(kMaxMessageSize);
       snprintf(message, kMaxMessageSize, "%s:%d: launchpad_start failed: %s\n",
-               __FILE__, __LINE__, mx_status_get_string(process));
+               __FILE__, __LINE__, errormsg);
       *os_error_message_ = message;
-      return process;
+      return status;
     }
 
     LOG_INFO("ProcessStarter: Start() adding %ld to list with exit_pipe %d\n",
@@ -727,57 +723,36 @@
     return status;                                                             \
   }
 
-  mx_status_t SetupLaunchpad() {
+  mx_status_t SetupLaunchpad(launchpad_t** launchpad) {
+    // Set up a vmo for the binary.
     mx_handle_t binary_vmo = launchpad_vmo_from_file(path_);
     CHECK_FOR_ERROR(binary_vmo, "launchpad_vmo_from_file");
-    binary_vmo_ = binary_vmo;
 
-    launchpad_t* lp;
-    mx_status_t status;
-
+    // Run the child process in the same "job".
     mx_handle_t job = MX_HANDLE_INVALID;
-    status = mx_handle_duplicate(mx_job_default(), MX_RIGHT_SAME_RIGHTS, &job);
+    mx_status_t status =
+        mx_handle_duplicate(mx_job_default(), MX_RIGHT_SAME_RIGHTS, &job);
+    if (status != NO_ERROR) {
+      mx_handle_close(binary_vmo);
+    }
     CHECK_FOR_ERROR(status, "mx_handle_duplicate");
 
-    status = launchpad_create(job, program_arguments_[0], &lp);
-    CHECK_FOR_ERROR(status, "launchpad_create");
-    launchpad_ = lp;
-
-    status =
-        launchpad_arguments(lp, program_arguments_count_, program_arguments_);
-    CHECK_FOR_ERROR(status, "launchpad_arguments");
-
-    status = launchpad_environ(lp, program_environment_);
-    CHECK_FOR_ERROR(status, "launchpad_environ");
-
+    // Set up the launchpad.
+    launchpad_t* lp = NULL;
+    launchpad_create(job, program_arguments_[0], &lp);
+    launchpad_arguments(lp, program_arguments_count_, program_arguments_);
+    launchpad_environ(lp, program_environment_);
+    launchpad_clone_mxio_root(lp);
     // TODO(zra): Use the supplied working directory when launchpad adds an
     // API to set it.
-
-    status = launchpad_clone_mxio_root(lp);
-    CHECK_FOR_ERROR(status, "launchpad_clone_mxio_root");
-
-    status = launchpad_add_pipe(lp, &write_out_, 0);
-    CHECK_FOR_ERROR(status, "launchpad_add_pipe");
-
-    status = launchpad_add_pipe(lp, &read_in_, 1);
-    CHECK_FOR_ERROR(status, "launchpad_add_pipe");
-
-    status = launchpad_add_pipe(lp, &read_err_, 2);
-    CHECK_FOR_ERROR(status, "launchpad_add_pipe");
-
-    status = launchpad_add_vdso_vmo(lp);
-    CHECK_FOR_ERROR(status, "launchpad_add_vdso_vmo");
-
-    status = launchpad_elf_load(lp, binary_vmo);
-    CHECK_FOR_ERROR(status, "launchpad_elf_load");
-    binary_vmo_ = MX_HANDLE_INVALID;  // launchpad_elf_load consumes the handle.
-
-    status = launchpad_load_vdso(lp, MX_HANDLE_INVALID);
-    CHECK_FOR_ERROR(status, "launchpad_load_vdso");
-
-    status = launchpad_clone_mxio_cwd(lp);
-    CHECK_FOR_ERROR(status, "launchpad_clone_mxio_cwd");
-
+    launchpad_clone_mxio_cwd(lp);
+    launchpad_add_pipe(lp, &write_out_, 0);
+    launchpad_add_pipe(lp, &read_in_, 1);
+    launchpad_add_pipe(lp, &read_err_, 2);
+    launchpad_add_vdso_vmo(lp);
+    launchpad_elf_load(lp, binary_vmo);
+    launchpad_load_vdso(lp, MX_HANDLE_INVALID);
+    *launchpad = lp;
     return NO_ERROR;
   }
 
@@ -791,9 +766,6 @@
   intptr_t program_arguments_count_;
   char** program_environment_;
 
-  mx_handle_t binary_vmo_;
-  launchpad_t* launchpad_;
-
   const char* path_;
   const char* working_directory_;
   ProcessStartMode mode_;
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index c6e11b4..784ee99 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -35,9 +35,16 @@
 
 
 void TestCase::Run() {
-  fprintf(stdout, "Running test: %s\n", name());
+  OS::Print("Running test: %s\n", name());
   (*run_)();
-  fprintf(stdout, "Done: %s\n", name());
+  OS::Print("Done: %s\n", name());
+}
+
+
+void RawTestCase::Run() {
+  OS::Print("Running test: %s\n", name());
+  (*run_)();
+  OS::Print("Done: %s\n", name());
 }
 
 
@@ -46,7 +53,7 @@
     this->Run();
     run_matches++;
   } else if (run_filter == kList) {
-    fprintf(stdout, "%s\n", this->name());
+    OS::Print("%s\n", this->name());
     run_matches++;
   }
 }
@@ -60,18 +67,18 @@
               this->score());
     run_matches++;
   } else if (run_filter == kList) {
-    fprintf(stdout, "%s\n", this->name());
+    OS::Print("%s\n", this->name());
     run_matches++;
   }
 }
 
 
 static void PrintUsage() {
-  fprintf(stderr,
-          "run_vm_tests [--list | --benchmarks | "
-          "<test name> | <benchmark name>]\n");
-  fprintf(stderr, "run_vm_tests [vm-flags ...] <test name>\n");
-  fprintf(stderr, "run_vm_tests [vm-flags ...] <benchmark name>\n");
+  OS::PrintErr(
+      "run_vm_tests [--list | --benchmarks | "
+      "<test name> | <benchmark name>]\n");
+  OS::PrintErr("run_vm_tests [vm-flags ...] <test name>\n");
+  OS::PrintErr("run_vm_tests [vm-flags ...] <benchmark name>\n");
 }
 
 
@@ -90,6 +97,7 @@
       // List all tests and benchmarks and exit without initializing the VM.
       TestCaseBase::RunAll();
       Benchmark::RunAll(argv[0]);
+      TestCaseBase::RunAllRaw();
       fflush(stdout);
       return 0;
     } else if (strcmp(argv[1], "--benchmarks") == 0) {
@@ -122,9 +130,10 @@
   err_msg = Dart::Cleanup();
   ASSERT(err_msg == NULL);
 
+  TestCaseBase::RunAllRaw();
   // Print a warning message if no tests or benchmarks were matched.
   if (run_matches == 0) {
-    fprintf(stderr, "No tests matched: %s\n", run_filter);
+    OS::PrintErr("No tests matched: %s\n", run_filter);
     return 1;
   }
   if (DynamicAssertionHelper::failed()) {
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index da8e19c..8d077d8 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -252,7 +252,7 @@
   drain_fd(stderr_pipe, test_stderr);
 
   mx_status_t r =
-      mx_handle_wait_one(p, MX_PROCESS_SIGNALED, MX_TIME_INFINITE, NULL);
+      mx_object_wait_one(p, MX_PROCESS_SIGNALED, MX_TIME_INFINITE, NULL);
   RETURN_IF_ERROR(r);
 
   mx_info_process_t proc_info;
diff --git a/runtime/bin/secure_socket_boringssl.cc b/runtime/bin/secure_socket_boringssl.cc
index 280d1f7..41a6198 100644
--- a/runtime/bin/secure_socket_boringssl.cc
+++ b/runtime/bin/secure_socket_boringssl.cc
@@ -13,6 +13,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/stat.h>
@@ -34,6 +35,7 @@
 #include "bin/socket.h"
 #include "bin/thread.h"
 #include "bin/utils.h"
+#include "platform/text_buffer.h"
 #include "platform/utils.h"
 
 #include "include/dart_api.h"
@@ -78,39 +80,40 @@
 const char* commandline_root_certs_file = NULL;
 const char* commandline_root_certs_cache = NULL;
 
-/* Get the error messages from BoringSSL, and put them in buffer as a
- * null-terminated string. */
-static void FetchErrorString(char* buffer, int length) {
-  buffer[0] = '\0';
-  int error = ERR_get_error();
-  while (error != 0) {
-    int used = strlen(buffer);
-    int free_length = length - used;
-    if (free_length > 16) {
-      // Enough room for error code at least.
-      if (used > 0) {
-        buffer[used] = '\n';
-        buffer[used + 1] = '\0';
-        used++;
-        free_length--;
-      }
-      ERR_error_string_n(error, buffer + used, free_length);
-      // ERR_error_string_n is guaranteed to leave a null-terminated string.
+// Get the error messages from BoringSSL, and put them in buffer as a
+// null-terminated string.
+static void FetchErrorString(const SSL* ssl, TextBuffer* text_buffer) {
+  uint32_t error = 0;
+  const char* path = NULL;
+  int line = -1;
+  const char* sep = File::PathSeparator();
+  do {
+    error = ERR_get_error_line(&path, &line);
+    const char* file = strrchr(path, sep[0]);
+    path = file ? file + 1 : path;
+    if ((ssl != NULL) && (ERR_GET_LIB(error) == ERR_LIB_SSL) &&
+        (ERR_GET_REASON(error) == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
+      intptr_t result = SSL_get_verify_result(ssl);
+      text_buffer->Printf("\n\t%s: %s (%s:%d)", ERR_reason_error_string(error),
+                          X509_verify_cert_error_string(result), path, line);
+    } else if (error != 0) {
+      text_buffer->Printf("\n\t%s (%s:%d)", ERR_reason_error_string(error),
+                          path, line);
     }
-    error = ERR_get_error();
-  }
+  } while (error != 0);
 }
 
 
-/* Handle an error reported from the BoringSSL library. */
+// Handle an error reported from the BoringSSL library.
 static void ThrowIOException(int status,
                              const char* exception_type,
-                             const char* message) {
-  char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
-  FetchErrorString(error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
+                             const char* message,
+                             const SSL* ssl) {
   Dart_Handle exception;
   {
-    OSError os_error_struct(status, error_string, OSError::kBoringSSL);
+    TextBuffer error_string(SSL_ERROR_MESSAGE_BUFFER_SIZE);
+    FetchErrorString(ssl, &error_string);
+    OSError os_error_struct(status, error_string.buf(), OSError::kBoringSSL);
     Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
     exception =
         DartUtils::NewDartIOException(exception_type, message, os_error);
@@ -448,7 +451,10 @@
 }
 
 
-void CheckStatus(int status, const char* type, const char* message) {
+void CheckStatusSSL(int status,
+                    const char* type,
+                    const char* message,
+                    const SSL* ssl) {
   // TODO(24183): Take appropriate action on failed calls,
   // throw exception that includes all messages from the error stack.
   if (status == 1) {
@@ -461,7 +467,12 @@
     ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
     Log::PrintErr("ERROR: %d %s\n", error, error_string);
   }
-  ThrowIOException(status, type, message);
+  ThrowIOException(status, type, message, ssl);
+}
+
+
+void CheckStatus(int status, const char* type, const char* message) {
+  CheckStatusSSL(status, type, message, NULL);
 }
 
 
@@ -816,7 +827,7 @@
     Log::Print("Looking for trusted roots in %s\n", file);
   }
   if (!File::Exists(file)) {
-    ThrowIOException(-1, "TlsException", "Failed to find root cert file");
+    ThrowIOException(-1, "TlsException", "Failed to find root cert file", NULL);
   }
   int status = SSL_CTX_load_verify_locations(context->context(), file, NULL);
   CheckStatus(status, "TlsException", "Failure trusting builtin roots");
@@ -831,7 +842,8 @@
     Log::Print("Looking for trusted roots in %s\n", cache);
   }
   if (Directory::Exists(cache) != Directory::EXISTS) {
-    ThrowIOException(-1, "TlsException", "Failed to find root cert cache");
+    ThrowIOException(-1, "TlsException", "Failed to find root cert cache",
+                     NULL);
   }
   int status = SSL_CTX_load_verify_locations(context->context(), NULL, cache);
   CheckStatus(status, "TlsException", "Failure trusting builtin roots");
@@ -1193,11 +1205,11 @@
     return result;
   } else {
     int32_t error_code = static_cast<int32_t>(ERR_peek_error());
-    char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
-    FetchErrorString(error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
+    TextBuffer error_string(SSL_ERROR_MESSAGE_BUFFER_SIZE);
+    FetchErrorString(filter->ssl_, &error_string);
     CObjectArray* result = new CObjectArray(CObject::NewArray(2));
     result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code)));
-    result->SetAt(1, new CObjectString(CObject::NewString(error_string)));
+    result->SetAt(1, new CObjectString(CObject::NewString(error_string.buf())));
     return result;
   }
 }
@@ -1514,7 +1526,7 @@
   BIO* ssl_side;
   status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_,
                             kInternalBIOSize);
-  CheckStatus(status, "TlsException", "BIO_new_bio_pair");
+  CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair", ssl_);
 
   assert(context != NULL);
   ssl_ = SSL_new(context);
@@ -1532,7 +1544,7 @@
   } else {
     SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
     status = SSL_set_tlsext_host_name(ssl_, hostname);
-    CheckStatus(status, "TlsException", "Set SNI host name");
+    CheckStatusSSL(status, "TlsException", "Set SNI host name", ssl_);
     // Sets the hostname in the certificate-checking object, so it is checked
     // against the certificate presented by the server.
     X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_);
@@ -1543,8 +1555,8 @@
     X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0);
     status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
                                          hostname_, strlen(hostname_));
-    CheckStatus(status, "TlsException",
-                "Set hostname for certificate checking");
+    CheckStatusSSL(status, "TlsException",
+                   "Set hostname for certificate checking", ssl_);
   }
   // Make the connection:
   if (is_server_) {
@@ -1597,9 +1609,10 @@
     in_handshake_ = true;
     return;
   }
-  CheckStatus(status, "HandshakeException", is_server_
-                                                ? "Handshake error in server"
-                                                : "Handshake error in client");
+  CheckStatusSSL(
+      status, "HandshakeException",
+      is_server_ ? "Handshake error in server" : "Handshake error in client",
+      ssl_);
   // Handshake succeeded.
   if (in_handshake_) {
     // TODO(24071): Check return value of SSL_get_verify_result, this
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
new file mode 100644
index 0000000..741d797
--- /dev/null
+++ b/runtime/bin/snapshot_utils.cc
@@ -0,0 +1,349 @@
+// 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.
+
+#include "bin/snapshot_utils.h"
+
+#include "bin/dartutils.h"
+#include "bin/error_exit.h"
+#include "bin/extensions.h"
+#include "bin/file.h"
+#include "bin/platform.h"
+#include "include/dart_api.h"
+#include "platform/utils.h"
+
+namespace dart {
+namespace bin {
+
+extern const char* kVmSnapshotDataSymbolName;
+extern const char* kVmSnapshotInstructionsSymbolName;
+extern const char* kIsolateSnapshotDataSymbolName;
+extern const char* kIsolateSnapshotInstructionsSymbolName;
+
+static const int64_t kAppSnapshotHeaderSize = 5 * kInt64Size;
+static const int64_t kAppSnapshotMagicNumber = 0xf6f6dcdc;
+static const int64_t kAppSnapshotPageSize = 4 * KB;
+
+static bool ReadAppSnapshotBlobs(const char* script_name,
+                                 const uint8_t** vm_data_buffer,
+                                 const uint8_t** vm_instructions_buffer,
+                                 const uint8_t** isolate_data_buffer,
+                                 const uint8_t** isolate_instructions_buffer) {
+  File* file = File::Open(script_name, File::kRead);
+  if (file == NULL) {
+    return false;
+  }
+  if (file->Length() < kAppSnapshotHeaderSize) {
+    file->Release();
+    return false;
+  }
+  int64_t header[5];
+  ASSERT(sizeof(header) == kAppSnapshotHeaderSize);
+  if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) {
+    file->Release();
+    return false;
+  }
+  if (header[0] != kAppSnapshotMagicNumber) {
+    file->Release();
+    return false;
+  }
+
+  int64_t vm_data_size = header[1];
+  int64_t vm_data_position =
+      Utils::RoundUp(file->Position(), kAppSnapshotPageSize);
+  int64_t vm_instructions_size = header[2];
+  int64_t vm_instructions_position = vm_data_position + vm_data_size;
+  if (vm_instructions_size != 0) {
+    vm_instructions_position =
+        Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize);
+  }
+  int64_t isolate_data_size = header[3];
+  int64_t isolate_data_position = Utils::RoundUp(
+      vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize);
+  int64_t isolate_instructions_size = header[4];
+  int64_t isolate_instructions_position =
+      isolate_data_position + isolate_data_size;
+  if (isolate_instructions_size != 0) {
+    isolate_instructions_position =
+        Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize);
+  }
+
+  if (vm_data_size != 0) {
+    *vm_data_buffer = reinterpret_cast<const uint8_t*>(
+        file->Map(File::kReadOnly, vm_data_position, vm_data_size));
+    if (vm_data_buffer == NULL) {
+      Log::PrintErr("Failed to memory map snapshot\n");
+      Platform::Exit(kErrorExitCode);
+    }
+  }
+
+  if (vm_instructions_size != 0) {
+    *vm_instructions_buffer = reinterpret_cast<const uint8_t*>(file->Map(
+        File::kReadExecute, vm_instructions_position, vm_instructions_size));
+    if (*vm_instructions_buffer == NULL) {
+      Log::PrintErr("Failed to memory map snapshot\n");
+      Platform::Exit(kErrorExitCode);
+    }
+  }
+
+  *isolate_data_buffer = reinterpret_cast<const uint8_t*>(
+      file->Map(File::kReadOnly, isolate_data_position, isolate_data_size));
+  if (isolate_data_buffer == NULL) {
+    Log::PrintErr("Failed to memory map snapshot\n");
+    Platform::Exit(kErrorExitCode);
+  }
+
+  if (isolate_instructions_size == 0) {
+    *isolate_instructions_buffer = NULL;
+  } else {
+    *isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
+        file->Map(File::kReadExecute, isolate_instructions_position,
+                  isolate_instructions_size));
+    if (*isolate_instructions_buffer == NULL) {
+      Log::PrintErr("Failed to memory map snapshot\n");
+      Platform::Exit(kErrorExitCode);
+    }
+  }
+
+  file->Release();
+  return true;
+}
+
+
+#if defined(DART_PRECOMPILED_RUNTIME)
+static bool ReadAppSnapshotDynamicLibrary(
+    const char* script_name,
+    const uint8_t** vm_data_buffer,
+    const uint8_t** vm_instructions_buffer,
+    const uint8_t** isolate_data_buffer,
+    const uint8_t** isolate_instructions_buffer) {
+  void* library = Extensions::LoadExtensionLibrary(script_name);
+  if (library == NULL) {
+    return false;
+  }
+
+  *vm_data_buffer = reinterpret_cast<const uint8_t*>(
+      Extensions::ResolveSymbol(library, kVmSnapshotDataSymbolName));
+  if (*vm_data_buffer == NULL) {
+    Log::PrintErr("Failed to resolve symbol '%s'\n", kVmSnapshotDataSymbolName);
+    Platform::Exit(kErrorExitCode);
+  }
+
+  *vm_instructions_buffer = reinterpret_cast<const uint8_t*>(
+      Extensions::ResolveSymbol(library, kVmSnapshotInstructionsSymbolName));
+  if (*vm_instructions_buffer == NULL) {
+    Log::PrintErr("Failed to resolve symbol '%s'\n",
+                  kVmSnapshotInstructionsSymbolName);
+    Platform::Exit(kErrorExitCode);
+  }
+
+  *isolate_data_buffer = reinterpret_cast<const uint8_t*>(
+      Extensions::ResolveSymbol(library, kIsolateSnapshotDataSymbolName));
+  if (*isolate_data_buffer == NULL) {
+    Log::PrintErr("Failed to resolve symbol '%s'\n",
+                  kIsolateSnapshotDataSymbolName);
+    Platform::Exit(kErrorExitCode);
+  }
+
+  *isolate_instructions_buffer =
+      reinterpret_cast<const uint8_t*>(Extensions::ResolveSymbol(
+          library, kIsolateSnapshotInstructionsSymbolName));
+  if (*isolate_instructions_buffer == NULL) {
+    Log::PrintErr("Failed to resolve symbol '%s'\n",
+                  kIsolateSnapshotInstructionsSymbolName);
+    Platform::Exit(kErrorExitCode);
+  }
+
+  return true;
+}
+#endif  // defined(DART_PRECOMPILED_RUNTIME)
+
+
+bool Snapshot::ReadAppSnapshot(const char* script_name,
+                               const uint8_t** vm_data_buffer,
+                               const uint8_t** vm_instructions_buffer,
+                               const uint8_t** isolate_data_buffer,
+                               const uint8_t** isolate_instructions_buffer) {
+  if (File::GetType(script_name, true) != File::kIsFile) {
+    // If 'script_name' refers to a pipe, don't read to check for an app
+    // snapshot since we cannot rewind if it isn't (and couldn't mmap it in
+    // anyway if it was).
+    return false;
+  }
+  if (ReadAppSnapshotBlobs(script_name, vm_data_buffer, vm_instructions_buffer,
+                           isolate_data_buffer, isolate_instructions_buffer)) {
+    return true;
+  }
+#if defined(DART_PRECOMPILED_RUNTIME)
+  // For testing AOT with the standalone embedder, we also support loading
+  // from a dynamic library to simulate what happens on iOS.
+  return ReadAppSnapshotDynamicLibrary(
+      script_name, vm_data_buffer, vm_instructions_buffer, isolate_data_buffer,
+      isolate_instructions_buffer);
+#else
+  return false;
+#endif  //  defined(DART_PRECOMPILED_RUNTIME)
+}
+
+
+static void WriteSnapshotFile(const char* filename,
+                              bool write_magic_number,
+                              const uint8_t* buffer,
+                              const intptr_t size) {
+  File* file = File::Open(filename, File::kWriteTruncate);
+  if (file == NULL) {
+    ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n",
+              filename);
+  }
+
+  if (write_magic_number) {
+    // Write the magic number to indicate file is a script snapshot.
+    DartUtils::WriteMagicNumber(file);
+  }
+
+  if (!file->WriteFully(buffer, size)) {
+    ErrorExit(kErrorExitCode, "Unable to write file %s for writing snapshot\n",
+              filename);
+  }
+  file->Release();
+}
+
+
+static bool WriteInt64(File* file, int64_t size) {
+  return file->WriteFully(&size, sizeof(size));
+}
+
+
+static void WriteAppSnapshot(const char* filename,
+                             uint8_t* vm_data_buffer,
+                             intptr_t vm_data_size,
+                             uint8_t* vm_instructions_buffer,
+                             intptr_t vm_instructions_size,
+                             uint8_t* isolate_data_buffer,
+                             intptr_t isolate_data_size,
+                             uint8_t* isolate_instructions_buffer,
+                             intptr_t isolate_instructions_size) {
+  File* file = File::Open(filename, File::kWriteTruncate);
+  if (file == NULL) {
+    ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
+  }
+
+  file->WriteFully(&kAppSnapshotMagicNumber, sizeof(kAppSnapshotMagicNumber));
+  WriteInt64(file, vm_data_size);
+  WriteInt64(file, vm_instructions_size);
+  WriteInt64(file, isolate_data_size);
+  WriteInt64(file, isolate_instructions_size);
+  ASSERT(file->Position() == kAppSnapshotHeaderSize);
+
+  file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+  if (!file->WriteFully(vm_data_buffer, vm_data_size)) {
+    ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
+  }
+
+  if (vm_instructions_size != 0) {
+    file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+    if (!file->WriteFully(vm_instructions_buffer, vm_instructions_size)) {
+      ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
+                filename);
+    }
+  }
+
+  file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+  if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) {
+    ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
+  }
+
+  if (isolate_instructions_size != 0) {
+    file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+    if (!file->WriteFully(isolate_instructions_buffer,
+                          isolate_instructions_size)) {
+      ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
+                filename);
+    }
+  }
+
+  file->Flush();
+  file->Release();
+}
+
+
+void Snapshot::GenerateScript(const char* snapshot_filename) {
+  // First create a snapshot.
+  uint8_t* buffer = NULL;
+  intptr_t size = 0;
+  Dart_Handle result = Dart_CreateScriptSnapshot(&buffer, &size);
+  if (Dart_IsError(result)) {
+    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
+  }
+
+  WriteSnapshotFile(snapshot_filename, true, buffer, size);
+}
+
+
+void Snapshot::GenerateAppJIT(const char* snapshot_filename) {
+#if defined(TARGET_ARCH_X64)
+  uint8_t* isolate_data_buffer = NULL;
+  intptr_t isolate_data_size = 0;
+  uint8_t* isolate_instructions_buffer = NULL;
+  intptr_t isolate_instructions_size = 0;
+  Dart_Handle result = Dart_CreateAppJITSnapshotAsBlobs(
+      &isolate_data_buffer, &isolate_data_size, &isolate_instructions_buffer,
+      &isolate_instructions_size);
+  if (Dart_IsError(result)) {
+    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
+  }
+  WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_data_buffer,
+                   isolate_data_size, isolate_instructions_buffer,
+                   isolate_instructions_size);
+#else
+  uint8_t* isolate_buffer = NULL;
+  intptr_t isolate_size = 0;
+
+  Dart_Handle result =
+      Dart_CreateSnapshot(NULL, NULL, &isolate_buffer, &isolate_size);
+  if (Dart_IsError(result)) {
+    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
+  }
+
+  WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_buffer,
+                   isolate_size, NULL, 0);
+#endif  // defined(TARGET_ARCH_X64)
+}
+
+
+void Snapshot::GenerateAppAOTAsBlobs(const char* snapshot_filename) {
+  uint8_t* vm_data_buffer = NULL;
+  intptr_t vm_data_size = 0;
+  uint8_t* vm_instructions_buffer = NULL;
+  intptr_t vm_instructions_size = 0;
+  uint8_t* isolate_data_buffer = NULL;
+  intptr_t isolate_data_size = 0;
+  uint8_t* isolate_instructions_buffer = NULL;
+  intptr_t isolate_instructions_size = 0;
+  Dart_Handle result = Dart_CreateAppAOTSnapshotAsBlobs(
+      &vm_data_buffer, &vm_data_size, &vm_instructions_buffer,
+      &vm_instructions_size, &isolate_data_buffer, &isolate_data_size,
+      &isolate_instructions_buffer, &isolate_instructions_size);
+  if (Dart_IsError(result)) {
+    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
+  }
+  WriteAppSnapshot(snapshot_filename, vm_data_buffer, vm_data_size,
+                   vm_instructions_buffer, vm_instructions_size,
+                   isolate_data_buffer, isolate_data_size,
+                   isolate_instructions_buffer, isolate_instructions_size);
+}
+
+
+void Snapshot::GenerateAppAOTAsAssembly(const char* snapshot_filename) {
+  uint8_t* assembly_buffer = NULL;
+  intptr_t assembly_size = 0;
+  Dart_Handle result =
+      Dart_CreateAppAOTSnapshotAsAssembly(&assembly_buffer, &assembly_size);
+  if (Dart_IsError(result)) {
+    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
+  }
+  WriteSnapshotFile(snapshot_filename, false, assembly_buffer, assembly_size);
+}
+
+}  // namespace bin
+}  // namespace dart
diff --git a/runtime/bin/snapshot_utils.h b/runtime/bin/snapshot_utils.h
new file mode 100644
index 0000000..fa66777
--- /dev/null
+++ b/runtime/bin/snapshot_utils.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef RUNTIME_BIN_SNAPSHOT_UTILS_H_
+#define RUNTIME_BIN_SNAPSHOT_UTILS_H_
+
+#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
+class Snapshot {
+ public:
+  static void GenerateScript(const char* snapshot_filename);
+  static void GenerateAppJIT(const char* snapshot_filename);
+  static void GenerateAppAOTAsBlobs(const char* snapshot_filename);
+  static void GenerateAppAOTAsAssembly(const char* snapshot_filename);
+
+  static bool ReadAppSnapshot(const char* script_name,
+                              const uint8_t** vm_data_buffer,
+                              const uint8_t** vm_instructions_buffer,
+                              const uint8_t** isolate_data_buffer,
+                              const uint8_t** isolate_instructions_buffer);
+
+ private:
+  DISALLOW_ALLOCATION();
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot);
+};
+
+}  // namespace bin
+}  // namespace dart
+
+#endif  // RUNTIME_BIN_SNAPSHOT_UTILS_H_
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index cbb9a2c..0eb82be 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -577,10 +577,7 @@
     Dart_ListSetAt(entry, 1, Dart_NewStringFromCString(addr->as_string()));
 
     RawAddr raw = addr->addr();
-    intptr_t data_length = SocketAddress::GetInAddrLength(raw);
-    Dart_Handle data = Dart_NewTypedData(Dart_TypedData_kUint8, data_length);
-    Dart_ListSetAsBytes(data, 0, reinterpret_cast<uint8_t*>(&raw), data_length);
-    Dart_ListSetAt(entry, 2, data);
+    Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(raw));
 
     Dart_ListSetAt(list, 0, entry);
     Dart_ListSetAt(list, 1, Dart_NewInteger(port));
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index b092b21..9937282 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -65,7 +65,11 @@
 
 Future<Uri> createTempDirCallback(String base) async {
   Directory temp = await Directory.systemTemp.createTemp(base);
-  return temp.uri;
+  // Underneath the temporary directory, create a directory with the
+  // same name as the DevFS name [base].
+  var fsUri = temp.uri.resolveUri(new Uri.directory(base));
+  await new Directory.fromUri(fsUri).create();
+  return fsUri;
 }
 
 Future deleteDirCallback(Uri path) async {
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 47ca849..9aff870 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3127,10 +3127,26 @@
  *
  */
 
+typedef enum {
+  Dart_KernelCompilationStatus_Unknown = -1,
+  Dart_KernelCompilationStatus_Ok = 0,
+  Dart_KernelCompilationStatus_Error = 1,
+  Dart_KernelCompilationStatus_Crash = 2,
+} Dart_KernelCompilationStatus;
+
+typedef struct {
+  Dart_KernelCompilationStatus status;
+  char* error;
+
+  uint8_t* kernel;
+  intptr_t kernel_size;
+} Dart_KernelCompilationResult;
+
 DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
 DART_EXPORT bool Dart_KernelIsolateIsRunning();
-DART_EXPORT Dart_Port Dart_ServiceWaitForKernelPort();
 DART_EXPORT Dart_Port Dart_KernelPort();
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernel(const char* script_uri);
 
 #define DART_KERNEL_ISOLATE_NAME "kernel-service"
 
diff --git a/runtime/lib/async_patch.dart b/runtime/lib/async_patch.dart
index 3e22fb0..d41a721 100644
--- a/runtime/lib/async_patch.dart
+++ b/runtime/lib/async_patch.dart
@@ -97,8 +97,8 @@
   // suspend;
   // if (controller.isCancelled) return;
   bool add(event) {
-    if (!onListenReceived) _fatal("yield before stream is listened to!");
-    if (isSuspendedAtYield) _fatal("unexpected yield");
+    if (!onListenReceived) fatal("yield before stream is listened to!");
+    if (isSuspendedAtYield) fatal("unexpected yield");
     // If stream is cancelled, tell caller to exit the async generator.
     if (!controller.hasListener) {
       return true;
@@ -115,7 +115,7 @@
   // Returns true if the caller should terminate
   // execution of the generator.
   bool addStream(Stream stream) {
-    if (!onListenReceived) _fatal("yield before stream is listened to!");
+    if (!onListenReceived) fatal("yield before stream is listened to!");
     // If stream is cancelled, tell caller to exit the async generator.
     if (!controller.hasListener) return true;
     isAdding = true;
@@ -190,3 +190,14 @@
 }
 
 @patch void _rethrow(Object error, StackTrace stackTrace) native "Async_rethrow";
+
+
+/// Returns a [StackTrace] object containing the synchronous prefix for this
+/// asynchronous method.
+Object _asyncStackTraceHelper() native "StackTrace_asyncStackTraceHelper";
+
+void _clearAsyncThreadStackTrace()
+    native "StackTrace_clearAsyncThreadStackTrace";
+
+void _setAsyncThreadStackTrace(StackTrace stackTrace) native
+    "StackTrace_setAsyncThreadStackTrace";
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index fbcfdb9..deed7c9 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -10,9 +10,6 @@
 import "dart:typed_data";
 import 'dart:_internal' as internal;
 
-// Equivalent of calling FATAL from C++ code.
-_fatal(msg) native "DartCore_fatal";
-
 // The members of this class are cloned and added to each class that
 // represents an enum type.
 class _EnumHelper {
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 69ae219..c85a769 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -33,6 +33,12 @@
     native "AssertionError_throwNew";
 
   static _evaluateAssertion(condition) {
+    if (identical(condition, true) || identical(condition, false)) {
+      return condition;
+    }
+    if (condition is _Closure) {
+      return condition();
+    }
     if (condition is Function) {
       condition = condition();
     }
diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart
index 6f8b384..a65ced8 100644
--- a/runtime/lib/integers_patch.dart
+++ b/runtime/lib/integers_patch.dart
@@ -42,7 +42,7 @@
 
   @patch static int parse(String source,
                           { int radix,
-                            int onError(String str) }) {
+                            int onError(String source) }) {
     if (source == null) throw new ArgumentError("The source must not be null");
     if (source.isEmpty) return _throwFormatException(onError, source, 0, radix);
     if (radix == null || radix == 10) {
diff --git a/runtime/lib/internal_patch.dart b/runtime/lib/internal_patch.dart
index 88bff92..681b8db 100644
--- a/runtime/lib/internal_patch.dart
+++ b/runtime/lib/internal_patch.dart
@@ -43,3 +43,6 @@
 bool _classRangeCheckNegative(int cid, int lowerLimit, int upperLimit) {
   return cid < lowerLimit || cid > upperLimit;
 }
+
+// Equivalent of calling FATAL from C++ code.
+fatal(msg) native "DartInternal_fatal";
diff --git a/runtime/lib/libgen_in.cc b/runtime/lib/libgen_in.cc
index ba6f4df..cc74faa 100644
--- a/runtime/lib/libgen_in.cc
+++ b/runtime/lib/libgen_in.cc
@@ -8,6 +8,7 @@
 
 // This file is used to generate the mapping of libraries which have
 // dart:<name> handles to the corresponding files that implement them.
+{{SOURCE_ARRAYS}}
 const char* {{VAR_NAME}}[] = {
 {{LIBRARY_SOURCE_MAP}}
 {{PART_SOURCE_MAP}}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index b67da4f..9c20eeb 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -20,11 +20,11 @@
 // Helper function in stacktrace.cc.
 void _printCurrentStackTrace();
 
-DEFINE_NATIVE_ENTRY(DartCore_fatal, 1) {
-  // The core library code entered an unrecoverable state.
+DEFINE_NATIVE_ENTRY(DartInternal_fatal, 1) {
+  // The SDK library code entered an unrecoverable state.
   const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
   const char* msg = instance.ToCString();
-  OS::PrintErr("Fatal error in dart:core\n");
+  OS::PrintErr("Fatal error in the SDK libraries\n");
   _printCurrentStackTrace();
   FATAL(msg);
   return Object::null();
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index d83ba13..20caf88 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -43,7 +43,7 @@
                 Map<String, dynamic> namedArguments)
       native "Object_noSuchMethod";
 
-  @patch noSuchMethod(Invocation invocation) {
+  @patch dynamic noSuchMethod(Invocation invocation) {
     return _noSuchMethod(invocation.isMethod,
                          internal.Symbol.getName(invocation.memberName),
                          invocation._type,
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index d7dcfe0..7f9c146 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -4,16 +4,134 @@
 
 #include "lib/stacktrace.h"
 #include "vm/bootstrap_natives.h"
+#include "vm/debugger.h"
 #include "vm/exceptions.h"
+#include "vm/native_entry.h"
 #include "vm/object_store.h"
 #include "vm/runtime_entry.h"
 #include "vm/stack_frame.h"
+#include "vm/stack_trace.h"
 
 namespace dart {
 
-static void IterateFrames(const GrowableObjectArray& code_list,
-                          const GrowableObjectArray& pc_offset_list,
-                          int skip_frames) {
+DECLARE_FLAG(bool, show_invisible_frames);
+
+static RawStackTrace* CurrentSyncStackTrace(Thread* thread,
+                                            intptr_t skip_frames = 1) {
+  Zone* zone = thread->zone();
+  const Function& null_function = Function::ZoneHandle(zone);
+
+  // Determine how big the stack trace is.
+  const intptr_t stack_trace_length =
+      StackTraceUtils::CountFrames(thread, skip_frames, null_function);
+
+  // Allocate once.
+  const Array& code_array =
+      Array::ZoneHandle(zone, Array::New(stack_trace_length));
+  const Array& pc_offset_array =
+      Array::ZoneHandle(zone, Array::New(stack_trace_length));
+
+  // Collect the frames.
+  const intptr_t collected_frames_count = StackTraceUtils::CollectFrames(
+      thread, code_array, pc_offset_array, 0, stack_trace_length, skip_frames);
+
+  ASSERT(collected_frames_count == stack_trace_length);
+
+  return StackTrace::New(code_array, pc_offset_array);
+}
+
+
+static RawStackTrace* CurrentStackTrace(
+    Thread* thread,
+    bool for_async_function,
+    intptr_t skip_frames = 1,
+    bool causal_async_stacks = FLAG_causal_async_stacks) {
+  if (!causal_async_stacks) {
+    // Return the synchronous stack trace.
+    return CurrentSyncStackTrace(thread, skip_frames);
+  }
+
+  Zone* zone = thread->zone();
+  Code& code = Code::ZoneHandle(zone);
+  Smi& offset = Smi::ZoneHandle(zone);
+  Function& async_function = Function::ZoneHandle(zone);
+  StackTrace& async_stack_trace = StackTrace::ZoneHandle(zone);
+  Array& async_code_array = Array::ZoneHandle(zone);
+  Array& async_pc_offset_array = Array::ZoneHandle(zone);
+
+  StackTraceUtils::ExtractAsyncStackTraceInfo(
+      thread, &async_function, &async_stack_trace, &async_code_array,
+      &async_pc_offset_array);
+
+  // Determine the size of the stack trace.
+  const intptr_t extra_frames = for_async_function ? 1 : 0;
+  const intptr_t synchronous_stack_trace_length =
+      StackTraceUtils::CountFrames(thread, skip_frames, async_function);
+
+  const intptr_t capacity = synchronous_stack_trace_length +
+                            extra_frames;  // For the asynchronous gap.
+
+  // Allocate memory for the stack trace.
+  const Array& code_array = Array::ZoneHandle(zone, Array::New(capacity));
+  const Array& pc_offset_array = Array::ZoneHandle(zone, Array::New(capacity));
+
+  intptr_t write_cursor = 0;
+  if (for_async_function) {
+    // Place the asynchronous gap marker at the top of the stack trace.
+    code = StubCode::AsynchronousGapMarker_entry()->code();
+    ASSERT(!code.IsNull());
+    offset = Smi::New(0);
+    code_array.SetAt(write_cursor, code);
+    pc_offset_array.SetAt(write_cursor, offset);
+    write_cursor++;
+  }
+
+  // Append the synchronous stack trace.
+  const intptr_t collected_frames_count = StackTraceUtils::CollectFrames(
+      thread, code_array, pc_offset_array, write_cursor,
+      synchronous_stack_trace_length, skip_frames);
+
+  write_cursor += collected_frames_count;
+
+  ASSERT(write_cursor == capacity);
+
+  return StackTrace::New(code_array, pc_offset_array, async_stack_trace);
+}
+
+
+RawStackTrace* GetStackTraceForException() {
+  Thread* thread = Thread::Current();
+  return CurrentStackTrace(thread, false, 0);
+}
+
+
+DEFINE_NATIVE_ENTRY(StackTrace_current, 0) {
+  return CurrentStackTrace(thread, false);
+}
+
+
+DEFINE_NATIVE_ENTRY(StackTrace_asyncStackTraceHelper, 0) {
+  return CurrentStackTrace(thread, true);
+}
+
+
+DEFINE_NATIVE_ENTRY(StackTrace_clearAsyncThreadStackTrace, 0) {
+  thread->clear_async_stack_trace();
+  return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(StackTrace_setAsyncThreadStackTrace, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(StackTrace, stack_trace,
+                               arguments->NativeArgAt(0));
+  thread->set_async_stack_trace(stack_trace);
+  return Object::null();
+}
+
+
+static void AppendFrames(const GrowableObjectArray& code_list,
+                         const GrowableObjectArray& pc_offset_list,
+                         int skip_frames) {
   StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
   StackFrame* frame = frames.NextFrame();
   ASSERT(frame != NULL);  // We expect to find a dart invocation frame.
@@ -34,6 +152,7 @@
   }
 }
 
+
 // Creates a StackTrace object from the current stack.
 //
 // Skips the first skip_frames Dart frames.
@@ -42,7 +161,7 @@
       GrowableObjectArray::Handle(GrowableObjectArray::New());
   const GrowableObjectArray& pc_offset_list =
       GrowableObjectArray::Handle(GrowableObjectArray::New());
-  IterateFrames(code_list, pc_offset_list, skip_frames);
+  AppendFrames(code_list, pc_offset_list, skip_frames);
   const Array& code_array = Array::Handle(Array::MakeArray(code_list));
   const Array& pc_offset_array =
       Array::Handle(Array::MakeArray(pc_offset_list));
@@ -51,6 +170,7 @@
   return stacktrace;
 }
 
+
 // An utility method for convenient printing of dart stack traces when
 // inside 'gdb'. Note: This function will only work when there is a
 // valid exit frame information. It will not work when a breakpoint is
@@ -61,19 +181,15 @@
   OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString());
 }
 
+
 // Like _printCurrentStackTrace, but works in a NoSafepointScope.
 void _printCurrentStackTraceNoSafepoint() {
   StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
   StackFrame* frame = frames.NextFrame();
   while (frame != NULL) {
-    OS::Print("%s\n", frame->ToCString());
+    OS::PrintErr("%s\n", frame->ToCString());
     frame = frames.NextFrame();
   }
 }
 
-DEFINE_NATIVE_ENTRY(StackTrace_current, 0) {
-  const StackTrace& stacktrace = GetCurrentStackTrace(1);
-  return stacktrace.raw();
-}
-
 }  // namespace dart
diff --git a/runtime/lib/stacktrace.h b/runtime/lib/stacktrace.h
index fe67a9d..c482070 100644
--- a/runtime/lib/stacktrace.h
+++ b/runtime/lib/stacktrace.h
@@ -8,6 +8,7 @@
 namespace dart {
 
 class StackTrace;
+class RawStackTrace;
 
 // Creates a StackTrace object from the current stack.  Skips the
 // first skip_frames Dart frames.
@@ -16,6 +17,9 @@
 // assertion failures, etc.
 const StackTrace& GetCurrentStackTrace(int skip_frames);
 
+// Creates a StackTrace object to be attached to an exception.
+RawStackTrace* GetStackTraceForException();
+
 }  // namespace dart
 
 #endif  // RUNTIME_LIB_STACKTRACE_H_
diff --git a/runtime/observatory/lib/src/cli/command.dart b/runtime/observatory/lib/src/cli/command.dart
index 28ffbff..6030aef 100644
--- a/runtime/observatory/lib/src/cli/command.dart
+++ b/runtime/observatory/lib/src/cli/command.dart
@@ -176,13 +176,11 @@
     var args = _splitLine(line);
     var commands = _match(args, true);
     if (commands.isEmpty) {
-      // TODO(turnidge): Add a proper exception class for this.
-      return new Future.error('No such command');
+      return new Future.error(new NoSuchCommandException(line));
     } else if (commands.length == 1) {
       return commands[0].run(args.sublist(commands[0]._depth));
     } else {
-      // TODO(turnidge): Add a proper exception class for this.
-      return new Future.error('Ambiguous command');
+      return new Future.error(new AmbiguousCommandException(line, commands));
     }
   }
 
@@ -254,3 +252,29 @@
 
   toString() => 'Command(${name})';
 }
+
+abstract class CommandException implements Exception {
+}
+
+class AmbiguousCommandException extends CommandException {
+  AmbiguousCommandException(this.command, this.matches);
+
+  final String command;
+  final List<Command> matches;
+
+  @override
+  String toString() {
+    List<String> matchNames = matches.map(
+        (Command command) => '${command.fullName}').toList();
+    return "Command '$command' is ambiguous: $matchNames";
+  }
+}
+
+class NoSuchCommandException extends CommandException {
+  NoSuchCommandException(this.command);
+
+  final String command;
+
+  @override
+  String toString() => "No such command: '$command'";
+}
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index 556d997..3727ddf 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -899,6 +899,9 @@
   box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.16),
                0 2px 5px 0 rgba(0, 0, 0, 0.26);
 }
+debugger-frame.causalFrame {
+  background-color: #D7CCC8;
+}
 debugger-frame.current {
   box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.26),
                0 2px 5px 0 rgba(0, 0, 0, 0.46);
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index b3ca569..94f47ad 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -604,6 +604,11 @@
       _setUpIsDown,
       (debugger, _) => debugger.upIsDown
     ],
+    'causal-async-stacks': [
+      _boolValues,
+      _setSaneAsyncStacks,
+      (debugger, _) => debugger.saneAsyncStacks
+    ],
   };
 
   static Future _setBreakOnException(debugger, name, value) async {
@@ -625,6 +630,16 @@
     debugger.console.print('${name} = ${value}');
   }
 
+  static Future _setSaneAsyncStacks(debugger, name, value) async {
+    if (value == 'true') {
+      debugger.saneAsyncStacks = true;
+    } else {
+      debugger.saneAsyncStacks = false;
+    }
+    debugger.refreshStack();
+    debugger.console.print('${name} = ${value}');
+  }
+
   Future run(List<String> args) async {
     if (args.length == 0) {
       for (var name in _options.keys) {
@@ -1381,6 +1396,17 @@
 
   bool _upIsDown;
 
+  bool get saneAsyncStacks => _saneAsyncStacks;
+  void set saneAsyncStacks(bool value) {
+    settings.set('causal-async-stacks', value);
+    _saneAsyncStacks = value;
+  }
+
+  bool _saneAsyncStacks;
+
+  static const String kAsyncCausalStackFrames = 'asyncCausalFrames';
+  static const String kStackFrames = 'frames';
+
   void upFrame(int count) {
     if (_upIsDown) {
       currentFrame += count;
@@ -1397,7 +1423,33 @@
     }
   }
 
-  int get stackDepth => stack['frames'].length;
+  int get stackDepth {
+    if (saneAsyncStacks) {
+      var asyncCausalStackFrames = stack[kAsyncCausalStackFrames];
+      var stackFrames = stack[kStackFrames];
+      if (asyncCausalStackFrames == null) {
+        // No causal frames.
+        return stackFrames.length;
+      }
+      return asyncCausalStackFrames.length;
+    } else {
+      return stack[kStackFrames].length;
+    }
+  }
+
+  List get stackFrames {
+    if (saneAsyncStacks) {
+      var asyncCausalStackFrames = stack[kAsyncCausalStackFrames];
+      var stackFrames = stack[kStackFrames];
+      if (asyncCausalStackFrames == null) {
+        // No causal frames.
+        return stackFrames ?? [];
+      }
+      return asyncCausalStackFrames;
+    } else {
+      return stack[kStackFrames] ?? [];
+    }
+  }
 
   static final _history = [''];
 
@@ -1434,6 +1486,7 @@
 
   void _loadSettings() {
     _upIsDown = settings.get('up-is-down');
+    _saneAsyncStacks = settings.get('causal-async-stacks') ?? true;
   }
 
   S.VM get vm => page.app.vm;
@@ -1807,18 +1860,24 @@
     console.printBold('\$ $command');
     return cmd.runCommand(command).then((_) {
       lastCommand = command;
-    }).catchError((e, s) {
-      if (e is S.NetworkRpcException) {
+    }).catchError(
+      (e, s) {
         console.printRed('Unable to execute command because the connection '
-            'to the VM has been closed');
-      } else {
+                         'to the VM has been closed');
+      }, test: (e) => e is S.NetworkRpcException
+    ).catchError(
+      (e, s) {
+        console.printRed(e.toString());
+      }, test: (e) => e is CommandException
+    ).catchError(
+      (e, s) {
         if (s != null) {
           console.printRed('Internal error: $e\n$s');
         } else {
           console.printRed('Internal error: $e\n');
         }
       }
-    });
+    );
   }
 
   String historyPrev(String command) {
@@ -2251,7 +2310,13 @@
 
   void updateStackFrames(S.ServiceMap newStack) {
     List frameElements = _frameList.children;
-    List newFrames = newStack['frames'];
+    List newFrames;
+    if (_debugger.saneAsyncStacks &&
+        (newStack[ObservatoryDebugger.kAsyncCausalStackFrames] != null)) {
+      newFrames = newStack[ObservatoryDebugger.kAsyncCausalStackFrames];
+    } else {
+      newFrames = newStack[ObservatoryDebugger.kStackFrames];
+    }
 
     // Remove any frames whose functions don't match, starting from
     // bottom of stack.
@@ -2379,7 +2444,11 @@
   bool _expanded = false;
 
   void setCurrent(bool value) {
-    _frame.function.load().then((func) {
+    Future load =
+        (_frame.function != null) ?
+        _frame.function.load() :
+        new Future.value(null);
+    load.then((func) {
       _current = value;
       if (_current) {
         _expand();
@@ -2432,6 +2501,18 @@
     } else {
       classes.remove('current');
     }
+    if ((_frame.kind == M.FrameKind.asyncSuspensionMarker) ||
+        (_frame.kind == M.FrameKind.asyncCausal)) {
+      classes.add('causalFrame');
+    }
+    if (_frame.kind == M.FrameKind.asyncSuspensionMarker) {
+      final content = <Element>[
+        new SpanElement()
+          ..children = _createMarkerHeader(_frame.marker)
+      ];
+      children = content;
+      return;
+    }
     ButtonElement expandButton;
     final content = <Element>[
       expandButton = new ButtonElement()
@@ -2534,6 +2615,24 @@
     children = content;
   }
 
+  List<Element> _createMarkerHeader(String marker) {
+    final content = [
+      new DivElement()
+        ..classes = ['frameSummaryText']
+        ..children = [
+          new DivElement()
+            ..classes = ['frameId']
+            ..text = 'Frame ${_frame.index}',
+          new SpanElement()..text = '$marker',
+        ]
+    ];
+    return [
+      new DivElement()
+        ..classes = ['frameSummary']
+        ..children = content
+      ];
+  }
+
   List<Element> _createHeader() {
     final content = [
       new DivElement()
@@ -2578,6 +2677,12 @@
   }
 
   bool matchFrame(S.Frame newFrame) {
+    if (newFrame.kind != _frame.kind) {
+      return false;
+    }
+    if (newFrame.function == null) {
+      return frame.function == null;
+    }
     return (newFrame.function.id == _frame.function.id &&
             newFrame.location.script.id ==
             frame.location.script.id);
diff --git a/runtime/observatory/lib/src/elements/sample_buffer_control.dart b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
index ecc7284..c2984b9 100644
--- a/runtime/observatory/lib/src/elements/sample_buffer_control.dart
+++ b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
@@ -142,7 +142,7 @@
                 ..innerHtml = 'Perhaps the <b>profile</b> '
                     'flag has been disabled for this VM.',
               new BRElement(),
-              new SpanElement()..text = 'See all',
+              new SpanElement()..text = 'See all ',
               new AnchorElement(href: Uris.flags())..text = 'vm flags'
             ]
         ]
diff --git a/runtime/observatory/lib/src/elements/vm_view.dart b/runtime/observatory/lib/src/elements/vm_view.dart
index b1ea5ea..b635391 100644
--- a/runtime/observatory/lib/src/elements/vm_view.dart
+++ b/runtime/observatory/lib/src/elements/vm_view.dart
@@ -181,6 +181,39 @@
                     ..classes = ['memberValue']
                     ..text = Utils.formatSize(_vm.maxRSS)
                 ],
+              new DivElement()
+                ..classes = ['memberItem']
+                ..children = [
+                  new DivElement()
+                    ..classes = ['memberName']
+                    ..text = 'native zone memory',
+                  new DivElement()
+                    ..classes = ['memberValue']
+                    ..text = Utils.formatSize(_vm.nativeZoneMemoryUsage)
+                    ..title = '${_vm.nativeZoneMemoryUsage} bytes'
+                ],
+              new DivElement()
+                ..classes = ['memberItem']
+                ..children = [
+                  new DivElement()
+                    ..classes = ['memberName']
+                    ..text = 'native heap memory',
+                  new DivElement()
+                    ..classes = ['memberValue']
+                    ..text = Utils.formatSize(_vm.heapAllocatedMemoryUsage)
+                    ..title = '${_vm.heapAllocatedMemoryUsage} bytes'
+                ],
+              new DivElement()
+                ..classes = ['memberItem']
+                ..children = [
+                  new DivElement()
+                    ..classes = ['memberName']
+                    ..text = 'native heap allocation count',
+                  new DivElement()
+                    ..classes = ['memberValue']
+                    ..text = _vm.heapAllocationCount
+                ],
+ 
               new BRElement(),
               new DivElement()
                 ..classes = ['memberItem']
diff --git a/runtime/observatory/lib/src/models/objects/frame.dart b/runtime/observatory/lib/src/models/objects/frame.dart
index be46bba..d2c4a1a 100644
--- a/runtime/observatory/lib/src/models/objects/frame.dart
+++ b/runtime/observatory/lib/src/models/objects/frame.dart
@@ -4,7 +4,15 @@
 
 part of models;
 
+enum FrameKind {
+  regular,
+  asyncCausal,
+  asyncSuspensionMarker
+}
+
 abstract class Frame {
+  FrameKind get kind;
+  String get marker;
   FunctionRef get function;
   SourceLocation get location;
 }
diff --git a/runtime/observatory/lib/src/models/objects/vm.dart b/runtime/observatory/lib/src/models/objects/vm.dart
index 3c73583..05e1bba 100644
--- a/runtime/observatory/lib/src/models/objects/vm.dart
+++ b/runtime/observatory/lib/src/models/objects/vm.dart
@@ -26,9 +26,18 @@
   /// The Dart VM version string.
   String get version;
 
+  /// The amount of memory currently allocated by native code in zones.
+  int get nativeZoneMemoryUsage;
+
   /// The process id for the VM.
   int get pid;
 
+  /// The current amount of native heap allocated memory within the VM.
+  int get heapAllocatedMemoryUsage;
+
+  /// The current number of allocations on the native heap within the VM.
+  int get heapAllocationCount;
+
   int get maxRSS;
 
   /// The time that the VM started in milliseconds since the epoch.
diff --git a/runtime/observatory/lib/src/models/repositories/target.dart b/runtime/observatory/lib/src/models/repositories/target.dart
index 4d276f6..5d4a559 100644
--- a/runtime/observatory/lib/src/models/repositories/target.dart
+++ b/runtime/observatory/lib/src/models/repositories/target.dart
@@ -16,4 +16,5 @@
   void add(String);
   void setCurrent(Target);
   void delete(Target);
+  Target find(String networkAddress);
 }
diff --git a/runtime/observatory/lib/src/repositories/target.dart b/runtime/observatory/lib/src/repositories/target.dart
index 69290fc..333e00d 100644
--- a/runtime/observatory/lib/src/repositories/target.dart
+++ b/runtime/observatory/lib/src/repositories/target.dart
@@ -101,6 +101,10 @@
   }
 
   static String _networkAddressOfDefaultTarget() {
+    if (!identical(1, 1.0)) {
+      // Dartium, assume we are developing.
+      return 'ws://127.0.0.1:8181/ws';
+    }
     Uri serverAddress = Uri.parse(window.location.toString());
     return 'ws://${serverAddress.authority}${serverAddress.path}ws';
   }
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 74a99ab..7a2780b 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -659,7 +659,10 @@
   int architectureBits;
   bool assertsEnabled = false;
   bool typeChecksEnabled = false;
+  int nativeZoneMemoryUsage = 0;
   int pid = 0;
+  int heapAllocatedMemoryUsage = 0;
+  int heapAllocationCount = 0;
   int maxRSS = 0;
   bool profileVM = false;
   DateTime startTime;
@@ -946,7 +949,16 @@
     int startTimeMillis = map['startTime'];
     startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeMillis);
     refreshTime = new DateTime.now();
+    if (map['_nativeZoneMemoryUsage'] != null) {
+      nativeZoneMemoryUsage = map['_nativeZoneMemoryUsage'];
+    }
     pid = map['pid'];
+    if (map['_heapAllocatedMemoryUsage'] != null) {
+      heapAllocatedMemoryUsage = map['_heapAllocatedMemoryUsage'];
+    }
+    if (map['_heapAllocationCount'] != null) {
+      heapAllocationCount = map['_heapAllocationCount'];
+    }
     maxRSS = map['_maxRSS'];
     profileVM = map['_profilerMode'] == 'VM';
     assertsEnabled = map['_assertsEnabled'];
@@ -4393,11 +4405,13 @@
 }
 
 class Frame extends ServiceObject implements M.Frame {
+  M.FrameKind kind = M.FrameKind.regular;
   int index;
   ServiceFunction function;
   SourceLocation location;
   Code code;
   List<ServiceMap> variables = <ServiceMap>[];
+  String marker;
 
   Frame._empty(ServiceObject owner) : super._empty(owner);
 
@@ -4405,14 +4419,37 @@
     assert(!mapIsRef);
     _loaded = true;
     _upgradeCollection(map, owner);
+    this.kind = _fromString(map['kind']);
+    this.marker = map['marker'];
     this.index = map['index'];
     this.function = map['function'];
     this.location = map['location'];
     this.code = map['code'];
-    this.variables = map['vars'];
+    this.variables = map['vars'] ?? [];
   }
 
-  String toString() => "Frame(${function.qualifiedName} $location)";
+  M.FrameKind _fromString(String frameKind) {
+    if (frameKind == null) {
+      return M.FrameKind.regular;
+    }
+    switch (frameKind) {
+      case 'Regular': return M.FrameKind.regular;
+      case 'AsyncCausal': return M.FrameKind.asyncCausal;
+      case 'AsyncSuspensionMarker': return M.FrameKind.asyncSuspensionMarker;
+      default:
+        throw new UnsupportedError('Unknown FrameKind: $frameKind');
+    }
+  }
+
+  String toString() {
+    if (function != null) {
+      return "Frame([$kind] ${function.qualifiedName} $location)";
+    } else if (location != null) {
+      return "Frame([$kind] $location)";
+    } else {
+      return "Frame([$kind])";
+    }
+  }
 }
 
 class ServiceMessage extends ServiceObject {
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/target.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/target.dart
index 1c7f3ed..4b563ee 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/repositories/target.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/target.dart
@@ -60,6 +60,10 @@
     _onChange.add(new TargetChangeEventMock(repository: this));
   }
 
+  M.Target find(String networkAddress) {
+    return null;
+  }
+
   TargetRepositoryMock({M.Target current, Iterable<M.Target> list : const [],
       TargetRepositoryMockStringCallback add,
       TargetRepositoryMockTargetCallback setCurrent,
diff --git a/runtime/observatory/tests/service/causal_async_stack_contents_test.dart b/runtime/observatory/tests/service/causal_async_stack_contents_test.dart
new file mode 100644
index 0000000..9777993
--- /dev/null
+++ b/runtime/observatory/tests/service/causal_async_stack_contents_test.dart
@@ -0,0 +1,73 @@
+// 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.
+// VMOptions=--error_on_bad_type --error_on_bad_override  --verbose_debug
+
+import 'dart:developer';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+const LINE_C = 19;
+const LINE_A = 24;
+const LINE_B = 30;
+
+foobar() {
+  debugger();
+  print('foobar');  // LINE_C.
+}
+
+helper() async {
+  debugger();
+  print('helper');  // LINE_A.
+  foobar();
+}
+
+testMain() {
+  debugger();
+  helper();  // LINE_B.
+}
+
+var tests = [
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // No causal frames because we are in a completely synchronous stack.
+    expect(stack['asyncCausalFrames'], isNull);
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+    var asyncStack = stack['asyncCausalFrames'];
+    expect(asyncStack[0].toString(), contains('helper'));
+    expect(asyncStack[1].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[2].toString(), contains('testMain'));
+  },
+
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside a function called by an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+    var asyncStack = stack['asyncCausalFrames'];
+    expect(asyncStack[0].toString(), contains('foobar'));
+    expect(asyncStack[1].toString(), contains('helper'));
+    expect(asyncStack[2].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[3].toString(), contains('testMain'));
+  },
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+                                         tests,
+                                         testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/causal_async_stack_presence_test.dart b/runtime/observatory/tests/service/causal_async_stack_presence_test.dart
new file mode 100644
index 0000000..2af9c8f
--- /dev/null
+++ b/runtime/observatory/tests/service/causal_async_stack_presence_test.dart
@@ -0,0 +1,63 @@
+// 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.
+// VMOptions=--error_on_bad_type --error_on_bad_override  --verbose_debug
+
+import 'dart:developer';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+const LINE_C = 18;
+const LINE_A = 23;
+const LINE_B = 29;
+
+foobar() {
+  debugger();
+  print('foobar');  // LINE_C.
+}
+
+helper() async {
+  debugger();
+  print('helper');  // LINE_A.
+  foobar();
+}
+
+testMain() {
+  debugger();
+  helper();  // LINE_B.
+}
+
+var tests = [
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // No causal frames because we are in a completely synchronous stack.
+    expect(stack['asyncCausalFrames'], isNull);
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+  },
+
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside a function called by an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+  },
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+                                         tests,
+                                         testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart b/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart
new file mode 100644
index 0000000..0a32ace
--- /dev/null
+++ b/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart
@@ -0,0 +1,83 @@
+// 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.
+// VMOptions=--error_on_bad_type --error_on_bad_override  --verbose_debug
+
+import 'dart:developer';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+const LINE_A = 26;
+const LINE_B = 19;
+const LINE_C = 21;
+
+foobar() async* {
+  debugger();
+  yield 1;     // LINE_B.
+  debugger();
+  yield 2;     // LINE_C.
+}
+
+helper() async {
+  debugger();
+  print('helper');  // LINE_A.
+  await for (var i in foobar()) {
+    print('helper $i');
+  }
+}
+
+testMain() {
+  helper();
+}
+
+var tests = [
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // No causal frames because we are in a completely synchronous stack.
+    expect(stack['asyncCausalFrames'], isNotNull);
+    var asyncStack = stack['asyncCausalFrames'];
+    expect(asyncStack[0].toString(), contains('helper'));
+    expect(asyncStack[1].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[2].toString(), contains('testMain'));
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+    var asyncStack = stack['asyncCausalFrames'];
+    expect(asyncStack[0].toString(), contains('foobar'));
+    expect(asyncStack[1].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[2].toString(), contains('helper'));
+    expect(asyncStack[3].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[4].toString(), contains('testMain'));
+  },
+
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside a function called by an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+    var asyncStack = stack['asyncCausalFrames'];
+    expect(asyncStack[0].toString(), contains('foobar'));
+    expect(asyncStack[1].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[2].toString(), contains('helper'));
+    expect(asyncStack[3].kind, equals(M.FrameKind.asyncSuspensionMarker));
+    expect(asyncStack[4].toString(), contains('testMain'));
+  },
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+                                         tests,
+                                         testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart b/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart
new file mode 100644
index 0000000..6c8d405
--- /dev/null
+++ b/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart
@@ -0,0 +1,66 @@
+// 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.
+// VMOptions=--error_on_bad_type --error_on_bad_override  --verbose_debug
+
+import 'dart:developer';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+const LINE_A = 25;
+const LINE_B = 18;
+const LINE_C = 20;
+
+foobar() async* {
+  debugger();
+  yield 1;     // LINE_B.
+  debugger();
+  yield 2;     // LINE_C.
+}
+
+helper() async {
+  debugger();
+  print('helper');  // LINE_A.
+  await for (var i in foobar()) {
+    print('helper $i');
+  }
+}
+
+testMain() {
+  helper();
+}
+
+var tests = [
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // No causal frames because we are in a completely synchronous stack.
+    expect(stack['asyncCausalFrames'], isNotNull);
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+  },
+
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+
+  (Isolate isolate) async {
+    ServiceMap stack = await isolate.getStack();
+    // Has causal frames (we are inside a function called by an async function)
+    expect(stack['asyncCausalFrames'], isNotNull);
+  },
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+                                         tests,
+                                         testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/command_test.dart b/runtime/observatory/tests/service/command_test.dart
index 8792d87..90f9d67 100644
--- a/runtime/observatory/tests/service/command_test.dart
+++ b/runtime/observatory/tests/service/command_test.dart
@@ -185,7 +185,7 @@
   RootCommand cmd = new RootCommand([new TestCommand(out, 'alpha', [])]);
 
   cmd.runCommand('goose').catchError(expectAsync((e) {
-      expect(e, equals('No such command'));
+    expect(e.toString(), equals("No such command: 'goose'"));
   }));
 }
 
@@ -196,7 +196,8 @@
                                      new TestCommand(out, 'ankle', [])]);
 
   cmd.runCommand('a 55').catchError(expectAsync((e) {
-      expect(e, equals('Ambiguous command'));
+      expect(e.toString(),
+             equals("Command 'a 55' is ambiguous: [alpha, ankle]"));
       out.clear();
       cmd.runCommand('ankl 55').then(expectAsync((_) {
           expect(out.toString(), equals('executing ankle([55])\n'));
diff --git a/runtime/observatory/tests/service/developer_extension_test.dart b/runtime/observatory/tests/service/developer_extension_test.dart
index 5c8e5cd..3ec6a6c 100644
--- a/runtime/observatory/tests/service/developer_extension_test.dart
+++ b/runtime/observatory/tests/service/developer_extension_test.dart
@@ -145,7 +145,6 @@
     } on ServerRpcException catch (e, st) {
       expect(e.code, equals(ServiceExtensionResponse.extensionError));
       expect(e.message, stringContainsInOrder([
-          'Error in extension `ext..languageError`:',
           'developer_extension_test.dart',
           'semicolon expected']));
     }
diff --git a/runtime/observatory/tests/service/get_isolate_rpc_test.dart b/runtime/observatory/tests/service/get_isolate_rpc_test.dart
index 74940c7..f03ec75 100644
--- a/runtime/observatory/tests/service/get_isolate_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_isolate_rpc_test.dart
@@ -23,8 +23,8 @@
     expect(result['pauseOnExit'], isFalse);
     expect(result['pauseEvent']['type'], equals('Event'));
     expect(result['error'], isNull);
-    expect(result['numZoneHandles'], isPositive);
-    expect(result['numScopedHandles'], isPositive);
+    expect(result['_numZoneHandles'], isPositive);
+    expect(result['_numScopedHandles'], isPositive);
     expect(result['rootLib']['type'], equals('@Library'));
     expect(result['libraries'].length, isPositive);
     expect(result['libraries'][0]['type'], equals('@Library'));
diff --git a/runtime/observatory/tests/service/get_ports_rpc_test.dart b/runtime/observatory/tests/service/get_ports_rpc_test.dart
index 7e977ed..44a04d2 100644
--- a/runtime/observatory/tests/service/get_ports_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_ports_rpc_test.dart
@@ -44,11 +44,11 @@
     expect(result['type'], equals('_Ports'));
     expect(result['ports'], isList);
     var ports = result['ports'];
-    // There are three ports: the two created in warmup and the stdin listener
-    // created by the test harness.
-    expect(ports.length, equals(3));
-    expect(countHandlerMatches(ports, nullMatcher), equals(1));
-    expect(countHandlerMatches(ports, closureMatcher), equals(2));
+    // There are at least two ports: the two created in warm up. Some OSes
+    // will have other ports open but we do not try and test for these.
+    expect(ports.length, greaterThanOrEqualTo(2));
+    expect(countHandlerMatches(ports, nullMatcher), greaterThanOrEqualTo(1));
+    expect(countHandlerMatches(ports, closureMatcher), greaterThanOrEqualTo(1));
   },
 ];
 
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index cee1a67..9a41163 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -3,17 +3,14 @@
 # BSD-style license that can be found in the LICENSE file.
 
 # Flaky failures
-vm_timeline_flags_test: Pass, RuntimeError # Issue 26483
-gc_test: Pass, RuntimeError # Issue 26490
-pause_on_start_and_exit_test: Pass, RuntimeError # Issue 26470
-pause_on_start_then_step_test: Pass, RuntimeError # Issue 26470
 get_allocation_samples_test: Pass, RuntimeError # Inconsistent stack trace
-get_isolate_rpc_test: Pass, RuntimeError # Issue 28185
-set_library_debuggable_test: Pass, RuntimeError # Issue 28091
 reload_sources_test: Pass, Slow # Reload is slow on the bots
-rewind_test: Pass, RuntimeError # Issue 28047
-tcp_socket_service_test: Pass, RuntimeError # Issue 28184
 get_retained_size_rpc_test: Pass, RuntimeError # Issue 28193
+pause_on_start_and_exit_test: Pass, RuntimeError # Issue 28624
+pause_on_start_then_step_test: Pass, RuntimeError # Issue 28624
+
+[$runtime == vm && $compiler == none && $system == fuchsia]
+*: Skip  # Not yet triaged.
 
 [ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) ]
 evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
@@ -43,20 +40,19 @@
 developer_extension_test: SkipByDesign
 get_isolate_after_language_error_test: SkipByDesign
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $arch == arm ]
 process_service_test: Pass, Fail # Issue 24344
 
 [ $compiler == precompiler ]
 *: Skip # Issue 24651
 
-[ $runtime == vm ]
-developer_extension_test: Pass, Fail # Issue 27225
-
 [ $compiler == app_jit ]
 address_mapper_test: CompileTimeError # Issue 27806
 capture_stdio_test: CompileTimeError # Issue 27806
 complex_reload_test: RuntimeError # Issue 27806
-developer_extension_test: RuntimeError # Issue 27806
 evaluate_activation_test/instance: RuntimeError # Issue 27806
 evaluate_activation_test/scope: RuntimeError # Issue 27806
 get_object_rpc_test: RuntimeError # Issue 27806
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index eeb6805..ca1e5af 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -8,7 +8,6 @@
 import 'dart:convert';
 import 'dart:io';
 import 'package:observatory/service_io.dart';
-import 'package:stack_trace/stack_trace.dart';
 import 'service_test_common.dart';
 
 /// Will be set to the http address of the VM's service protocol before
@@ -281,19 +280,20 @@
             bool testeeControlsServer: false,
             bool useAuthToken: false}) {
     var process = new _ServiceTesteeLauncher();
-    process.launch(pause_on_start, pause_on_exit,
+    bool testsDone = false;
+    runZoned(() {
+      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 = new Duration(seconds: 10);
-        print("Testee has pid $pid, waiting $wait before continuing");
-        sleep(wait);
-      }
-      setupAddresses(serverAddress);
-      var name = Platform.script.pathSegments.last;
-      Chain.capture(() async {
+        if (mainArgs.contains("--gdb")) {
+          var pid = process.process.pid;
+          var wait = new Duration(seconds: 10);
+          print("Testee has pid $pid, waiting $wait before continuing");
+          sleep(wait);
+        }
+        setupAddresses(serverAddress);
+        var name = Platform.script.pathSegments.last;
         var vm =
             new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress));
         print('Loading VM...');
@@ -314,7 +314,7 @@
 
         // Run isolate tests.
         if (isolateTests != null) {
-          var isolate = await vm.isolates.first.load();
+          var isolate = await getFirstIsolate(vm);
           var testIndex = 1;
           var totalTests = isolateTests.length;
           for (var test in isolateTests) {
@@ -325,13 +325,63 @@
           }
         }
 
+        print('All service tests completed successfully.');
+        testsDone = true;
         await process.requestExit();
-      }, onError: (error, stackTrace) {
-        process.requestExit();
+      });
+    }, onError: (error, stackTrace) async {
+      print('onERROR FIRED!');
+      if (testsDone) {
+        print('Ignoring late exception during process exit:\n'
+              '$error\n#stackTrace');
+      } else {
+        await process.requestExit();
         print('Unexpected exception in service tests: $error\n$stackTrace');
         throw error;
+      }
+    });
+  }
+
+  Future<Isolate> getFirstIsolate(WebSocketVM vm) async {
+    if (vm.isolates.isNotEmpty) {
+      var isolate = await vm.isolates.first.load();
+      if (isolate is Isolate) {
+        return isolate;
+      }
+    }
+
+    Completer completer = new Completer();
+    vm.getEventStream(VM.kIsolateStream).then((stream) {
+      var subscription;
+      subscription = stream.listen((ServiceEvent event) async {
+        if (completer == null) {
+          subscription.cancel();
+          return;
+        }
+        if (event.kind == ServiceEvent.kIsolateRunnable) {
+          if (vm.isolates.isNotEmpty) {
+            vm.isolates.first.load().then((result) {
+              if (result is Isolate) {
+                subscription.cancel();
+                completer.complete(result);
+                completer = null;
+              }
+            });
+          }
+        }
       });
     });
+
+    // The isolate may have started before we subscribed.
+    if (vm.isolates.isNotEmpty) {
+      vm.isolates.first.reload().then((result) async {
+        if (completer != null && result is Isolate) {
+          completer.complete(result);
+          completer = null;
+        }
+      });
+    }
+    return await completer.future;
   }
 }
 
diff --git a/runtime/observatory/tests/service/vm_timeline_flags_test.dart b/runtime/observatory/tests/service/vm_timeline_flags_test.dart
index 6943874..775e40a 100644
--- a/runtime/observatory/tests/service/vm_timeline_flags_test.dart
+++ b/runtime/observatory/tests/service/vm_timeline_flags_test.dart
@@ -63,6 +63,7 @@
     print(flags);
   },
   resumeIsolate,
+  hasStoppedAtBreakpoint,
   (Isolate isolate) async {
     // Get the timeline.
     Map result = await isolate.vm.invokeRpcNoUpgrade('_getVMTimeline', {});
@@ -96,6 +97,7 @@
     expect(flags['recordedStreams'].length, equals(0));
   },
   resumeIsolate,
+  hasStoppedAtBreakpoint,
   (Isolate isolate) async {
     // Grab the timeline and verify that we haven't added any new Dart events.
     Map result = await isolate.vm.invokeRpcNoUpgrade('_getVMTimeline', {});
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index d862a9e..6372df0e2 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -462,6 +462,7 @@
 const int kFloatSize = sizeof(float);    // NOLINT
 const int kQuadSize = 4 * kFloatSize;
 const int kSimd128Size = sizeof(simd128_value_t);  // NOLINT
+const int kInt64Size = sizeof(int64_t);            // NOLINT
 const int kInt32Size = sizeof(int32_t);            // NOLINT
 const int kInt16Size = sizeof(int16_t);            // NOLINT
 #ifdef ARCH_IS_32_BIT
diff --git a/runtime/tests/vm/dart/inline_stack_frame_test.dart b/runtime/tests/vm/dart/inline_stack_frame_test.dart
index e553855..d397957 100644
--- a/runtime/tests/vm/dart/inline_stack_frame_test.dart
+++ b/runtime/tests/vm/dart/inline_stack_frame_test.dart
@@ -4,8 +4,6 @@
 
 // VMOptions=--optimization_counter_threshold=10 --no-background-compilation
 
-import "package:expect/expect.dart";
-
 // This test tries to verify that we produce the correct stack trace when
 // throwing exceptions even when functions are inlined.
 // The test invokes a bunch of functions and then does a throw. There is a
@@ -26,7 +24,7 @@
       }
       return "";
     } catch (e, stacktrace) {
-      var result = e + stacktrace.toString();
+      var result = e + "\n" + stacktrace.toString();
       return result;
     }
   }
@@ -57,22 +55,33 @@
   }
 }
 
+expectHasSubstring(String string, String substring) {
+  if (!string.contains(substring)) {
+    var sb = new StringBuffer();
+    sb.writeln("Expect string:");
+    sb.writeln(string);
+    sb.writeln("To have substring:");
+    sb.writeln(substring);
+    throw new Exception(sb.toString());
+  }
+}
+
 main() {
   var x = new Test();
   var result = x.func1(100000);
-  Expect.isTrue(result.contains("show me inlined functions"));
-  Expect.isTrue(result.contains("Test.func1"));
-  Expect.isTrue(result.contains("Test.func2"));
-  Expect.isTrue(result.contains("Test.func3"));
-  Expect.isTrue(result.contains("Test.func4"));
-  Expect.isTrue(result.contains("Test.func"));
+  expectHasSubstring(result, "show me inlined functions");
+  expectHasSubstring(result, "Test.func1");
+  expectHasSubstring(result, "Test.func2");
+  expectHasSubstring(result, "Test.func3");
+  expectHasSubstring(result, "Test.func4");
+  expectHasSubstring(result, "Test.func5");
   for (var i = 0; i <= 10; i++) {
     result = x.func1(i);
   }
-  Expect.isTrue(result.contains("show me inlined functions"));
-  Expect.isTrue(result.contains("Test.func1"));
-  Expect.isTrue(result.contains("Test.func2"));
-  Expect.isTrue(result.contains("Test.func3"));
-  Expect.isTrue(result.contains("Test.func4"));
-  Expect.isTrue(result.contains("Test.func5"));
+  expectHasSubstring(result, "show me inlined functions");
+  expectHasSubstring(result, "Test.func1");
+  expectHasSubstring(result, "Test.func2");
+  expectHasSubstring(result, "Test.func3");
+  expectHasSubstring(result, "Test.func4");
+  expectHasSubstring(result, "Test.func5");
 }
diff --git a/runtime/tests/vm/dart/optimized_stacktrace_line_and_column_test.dart b/runtime/tests/vm/dart/optimized_stacktrace_line_and_column_test.dart
new file mode 100644
index 0000000..0460aae
--- /dev/null
+++ b/runtime/tests/vm/dart/optimized_stacktrace_line_and_column_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test correct source positions in stack trace with optimized functions.
+import "package:expect/expect.dart";
+
+// (1) Test normal exception.
+foo(x) => bar(x);
+
+bar(x) {
+  if (x == null) throw 42;  // throw at position 11:18
+  return x + 1;
+}
+
+test1() {
+  // First unoptimized.
+  try {
+    foo(null);
+    Expect.fail("Unreachable");
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isFalse(s.contains("-1:-1"), "A");
+    Expect.isTrue(s.contains("optimized_stacktrace_line_and_column_test.dart:11:18"), "B");
+  }
+
+  // Optimized.
+  for (var i=0; i<10000; i++) foo(42);
+  try {
+    foo(null);
+    Expect.fail("Unreachable");
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isFalse(s.contains("-1:-1"), "C");
+    Expect.isTrue(s.contains("optimized_stacktrace_line_and_column_test.dart:11:18"), "D");
+  }
+}
+
+
+// (2) Test checked mode exceptions.
+maximus(x) => moritz(x);
+
+moritz(x) {
+  if (x == 333)  return 42 ? 0 : 1;  // Throws in checked mode.
+  if (x == 777)   {
+    bool b = x;  // Throws in checked mode.
+    return b;
+  }
+
+  return x + 1;
+}
+
+test2() {
+  for (var i=0; i<100000; i++) maximus(42);
+  try {
+    maximus(333);
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isTrue(s.contains("maximus"), "E");
+    Expect.isTrue(s.contains("moritz"), "F");
+    Expect.isFalse(s.contains("-1:-1"), "G");
+  }
+
+  try {
+    maximus(777);
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isTrue(s.contains("maximus"), "H");
+    Expect.isTrue(s.contains("moritz"), "I");
+    Expect.isFalse(s.contains("-1:-1"), "J");
+  }
+}
+
+main() {
+  test1();
+  test2();
+}
diff --git a/runtime/tests/vm/dart/optimized_stacktrace_line_test.dart b/runtime/tests/vm/dart/optimized_stacktrace_line_test.dart
new file mode 100644
index 0000000..cc7157d
--- /dev/null
+++ b/runtime/tests/vm/dart/optimized_stacktrace_line_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test correct source positions in stack trace with optimized functions.
+import "package:expect/expect.dart";
+
+// (1) Test normal exception.
+foo(x) => bar(x);
+
+bar(x) {
+  if (x == null) throw 42;  // throw at position 11:18
+  return x + 1;
+}
+
+test1() {
+  // First unoptimized.
+  try {
+    foo(null);
+    Expect.fail("Unreachable");
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isFalse(s.contains("-1:-1"), "A");
+    Expect.isTrue(s.contains("optimized_stacktrace_line_test.dart:11"), "B");
+  }
+
+  // Optimized.
+  for (var i=0; i<10000; i++) foo(42);
+  try {
+    foo(null);
+    Expect.fail("Unreachable");
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isFalse(s.contains("-1:-1"), "C");
+    Expect.isTrue(s.contains("optimized_stacktrace_line_test.dart:11"), "D");
+  }
+}
+
+
+// (2) Test checked mode exceptions.
+maximus(x) => moritz(x);
+
+moritz(x) {
+  if (x == 333)  return 42 ? 0 : 1;  // Throws in checked mode.
+  if (x == 777)   {
+    bool b = x;  // Throws in checked mode.
+    return b;
+  }
+
+  return x + 1;
+}
+
+test2() {
+  for (var i=0; i<100000; i++) maximus(42);
+  try {
+    maximus(333);
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isTrue(s.contains("maximus"), "E");
+    Expect.isTrue(s.contains("moritz"), "F");
+    Expect.isFalse(s.contains("-1:-1"), "G");
+  }
+
+  try {
+    maximus(777);
+  } catch (e, stacktrace) {
+    String s = stacktrace.toString();
+    print(s);
+    Expect.isTrue(s.contains("maximus"), "H");
+    Expect.isTrue(s.contains("moritz"), "I");
+    Expect.isFalse(s.contains("-1:-1"), "J");
+  }
+}
+
+main() {
+  test1();
+  test2();
+}
diff --git a/runtime/tests/vm/dart/optimized_stacktrace_test.dart b/runtime/tests/vm/dart/optimized_stacktrace_test.dart
deleted file mode 100644
index d002a2e..0000000
--- a/runtime/tests/vm/dart/optimized_stacktrace_test.dart
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// Test correct source positions in stack trace with optimized functions.
-import "package:expect/expect.dart";
-
-// (1) Test normal exception.
-foo(x) => bar(x);
-
-bar(x) {
-  if (x == null) throw 42;  // throw at position 11:18
-  return x + 1;
-}
-
-test1() {
-  // First unoptimized.
-  try {
-    foo(null);
-    Expect.fail("Unreachable");
-  } catch (e, stacktrace) {
-    String s = stacktrace.toString();
-    Expect.isFalse(s.contains("-1:-1"));
-    Expect.isTrue(s.contains("11:18"));
-  }
-
-  // Optimized.
-  for (var i=0; i<10000; i++) foo(42);
-  try {
-    foo(null);
-    Expect.fail("Unreachable");
-  } catch (e, stacktrace) {
-    String s = stacktrace.toString();
-    Expect.isFalse(s.contains("-1:-1"));
-    Expect.isTrue(s.contains("11:18"));
-  }
-}
-
-
-// (2) Test checked mode exceptions.
-maximus(x) => moritz(x);
-
-moritz(x) {
-  if (x == 333)  return 42 ? 0 : 1;  // Throws in checked mode.
-  if (x == 777)   {
-    bool b = x;  // Throws in checked mode.
-    return b;
-  }
-
-  return x + 1;
-}
-
-test2() {
-  for (var i=0; i<100000; i++) maximus(42);
-  try {
-    maximus(333);
-  } catch (e, stacktrace) {
-    String s = stacktrace.toString();
-    print(s);
-    Expect.isTrue(s.contains("maximus"));
-    Expect.isTrue(s.contains("moritz"));
-    Expect.isFalse(s.contains("-1:-1"));
-  }
-
-  try {
-    maximus(777);
-  } catch (e, stacktrace) {
-    String s = stacktrace.toString();
-    print(s);
-    Expect.isTrue(s.contains("maximus"));
-    Expect.isTrue(s.contains("moritz"));
-    Expect.isFalse(s.contains("-1:-1"));
-  }
-}
-
-main() {
-  test1();
-  test2();
-}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 7ec8b8a..2287727 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -149,7 +149,8 @@
 
 [ $compiler == dart2js ]
 # The source positions do not match with dart2js.
-dart/optimized_stacktrace_test: RuntimeError
+dart/optimized_stacktrace_line_test: RuntimeError
+dart/optimized_stacktrace_line_and_column_test: RuntimeError
 
 # Methods can be missing in dart2js stack traces due to inlining.  Also when
 # minifying they can be renamed, which is issue 7953.
@@ -169,7 +170,11 @@
 cc/FindCodeObject: SkipSlow # Takes more than 8 minutes. Issue 17440
 
 [ $compiler == dart2analyzer ]
-dart/optimized_stacktrace_test: StaticWarning
+dart/optimized_stacktrace_line_test: StaticWarning
+dart/optimized_stacktrace_line_and_column_test: StaticWarning
+
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
 
 [ $compiler == app_jit ]
 dart/snapshot_version_test: Fail,OK # Expects to find script snapshot relative to Dart source.
@@ -187,8 +192,6 @@
 cc/CodeImmutability: Fail,OK # Address Sanitizer turns a crash into a failure.
 
 [ $builder_tag == asan && $arch == x64 ]
-cc/Debug_DeleteBreakpoint: Fail # Issue 28348
-
 cc/IsolateReload_ChangeInstanceFormat7: Fail # Issue 28349
 cc/IsolateReload_ClassAdded: Fail # Issue 28349
 cc/IsolateReload_ComplexInheritanceChange: Fail # Issue 28349
@@ -255,14 +258,12 @@
 cc/CoreSnapshotSize: SkipByDesign # Imports dart:mirrors
 cc/StandaloneSnapshotSize: SkipByDesign # Imports dart:mirrors
 
-[ $runtime == dart_precompiled ]
-# StackTraces in precompilation omit inlined frames.
-dart/inline_stack_frame_test: Pass, RuntimeError
-dart/optimized_stacktrace_test: Pass, RuntimeError
-dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
+[ $compiler == app_jit ]
+dart/optimized_stacktrace_line_and_column_test: RuntimeError,OK # app-jit lacks column information
 
-[ $compiler == app_jit || $compiler == precompiler ]
-dart/optimized_stacktrace_test: SkipByDesign # Requires line numbers
+[ $runtime == dart_precompiled ]
+dart/optimized_stacktrace_line_and_column_test: RuntimeError,OK # AOT lacks column information
+dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
 
 [ $runtime == vm && $mode == product ]
 cc/IsolateSetCheckedMode: Fail,OK  # Expects exact type name.
@@ -295,3 +296,8 @@
 [ $hot_reload || $hot_reload_rollback ]
 dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
 dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
+
+[ $arch == simdbc  || $arch == simdbc64 ]
+cc/Debugger_RewindOneFrame_Unoptimized: Skip # Issue 27878
+cc/Debugger_RewindTwoFrames_Unoptimized: Skip # Issue 27878
+cc/Debugger_Rewind_Optimized: Skip # Issue 27878
diff --git a/runtime/tools/gen_library_src_paths.py b/runtime/tools/gen_library_src_paths.py
index 8a55118..07505c8 100755
--- a/runtime/tools/gen_library_src_paths.py
+++ b/runtime/tools/gen_library_src_paths.py
@@ -16,31 +16,40 @@
 HOST_OS = utils.GuessOS()
 
 
-def makeString(input_file):
-  # TODO(iposva): For now avoid creating overly long strings on Windows.
-  if HOST_OS == 'win32':
-    return 'NULL'
-  result = '"'
+def makeString(input_file, var_name):
+  result = 'static const char ' + var_name + '[] = {\n '
   fileHandle = open(input_file, 'rb')
   lineCounter = 0
   for byte in fileHandle.read():
-    result += '\\x%02x' % ord(byte)
+    result += '\'\\x%02x' % ord(byte) + '\', '
     lineCounter += 1
     if lineCounter == 19:
-      result += '"\n "'
+      result += '\n '
       lineCounter = 0
-  result += '"'
+  result += '0};\n'
   return result
 
+def makeSourceArrays(in_files):
+  result = '';
+  file_count = 0;
+  for string_file in in_files:
+    if string_file.endswith('.dart'):
+      file_count += 1
+      file_string = makeString(string_file, "source_array_" + str(file_count))
+      result += file_string
+  return result
 
 def makeFile(output_file, input_cc_file, include, var_name, lib_name, in_files):
   part_index = [ ]
   bootstrap_cc_text = open(input_cc_file).read()
+  bootstrap_cc_text = bootstrap_cc_text.replace("{{SOURCE_ARRAYS}}", makeSourceArrays(in_files))
   bootstrap_cc_text = bootstrap_cc_text.replace("{{INCLUDE}}", include)
   bootstrap_cc_text = bootstrap_cc_text.replace("{{VAR_NAME}}", var_name)
   main_file_found = False
+  file_count = 0
   for string_file in in_files:
     if string_file.endswith('.dart'):
+      file_count += 1
       if (not main_file_found):
         inpt = open(string_file, 'r')
         for line in inpt:
@@ -51,7 +60,7 @@
                  "{{LIBRARY_SOURCE_MAP}}",
                  ' "' + lib_name + '",\n "' +
                  os.path.abspath(string_file).replace('\\', '\\\\') + '",\n' +
-                 ' ' + makeString(string_file) + ',\n')
+                 ' source_array_' + str(file_count) + ',\n')
         inpt.close()
         if (main_file_found):
           continue
@@ -59,14 +68,13 @@
           os.path.basename(string_file).replace('\\', '\\\\') + '",\n')
       part_index.append(' "' +
           os.path.abspath(string_file).replace('\\', '\\\\') + '",\n')
-      part_index.append(' ' + makeString(string_file) + ',\n\n')
+      part_index.append(' source_array_' + str(file_count) + ',\n\n')
   bootstrap_cc_text = bootstrap_cc_text.replace("{{LIBRARY_SOURCE_MAP}}", '')
   bootstrap_cc_text = bootstrap_cc_text.replace("{{PART_SOURCE_MAP}}",
                                                 ''.join(part_index))
   open(output_file, 'w').write(bootstrap_cc_text)
   return True
 
-
 def main(args):
   try:
     # Parse input.
diff --git a/runtime/tools/kernel-service.dart b/runtime/tools/kernel-service.dart
deleted file mode 100644
index f473c15..0000000
--- a/runtime/tools/kernel-service.dart
+++ /dev/null
@@ -1,95 +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.
-
-// This is an interface to the Dart Kernel parser and Kernel binary generator.
-// It is used by the kernel-isolate to load Dart source code and generate
-// Kernel binary format.
-
-import 'dart:isolate';
-import 'dart:async';
-import 'dart:io';
-import 'dart:typed_data';
-
-import 'package:kernel/binary/ast_to_binary.dart';
-import 'package:kernel/analyzer/loader.dart';
-import 'package:kernel/kernel.dart';
-import 'package:kernel/target/targets.dart';
-
-const verbose = false;
-
-class DataSink implements Sink<List<int>> {
-  final BytesBuilder builder = new BytesBuilder();
-
-  void add(List<int> data) {
-    builder.add(data);
-  }
-
-  void close() {
-    // Nothing to do.
-  }
-}
-
-Future<Uint8List> parseScript(
-    Uri fileName, String packageConfig, String sdkPath) async {
-  if (!FileSystemEntity.isFileSync(fileName.path)) {
-    throw "Input file '${fileName.path}' does not exist.";
-  }
-
-  if (!FileSystemEntity.isDirectorySync(sdkPath)) {
-    throw "Patched sdk directory not found at $sdkPath";
-  }
-
-  Target target = getTarget("vm", new TargetFlags(strongMode: false));
-  DartOptions dartOptions = new DartOptions(
-      strongMode: false,
-      strongModeSdk: false,
-      sdk: sdkPath,
-      packagePath: packageConfig,
-      customUriMappings: const {},
-      declaredVariables: const {});
-  DartLoader loader =
-      await new DartLoaderBatch().getLoader(new Repository(), dartOptions);
-  var program = loader.loadProgram(fileName, target: target);
-
-  var errors = loader.errors;
-  if (errors.isNotEmpty) {
-    throw loader.errors.first;
-  }
-
-  // Link program into one file, cf. --link option in dartk.
-  target.transformProgram(program);
-
-  // Write the program to a list of bytes and return it.
-  var sink = new DataSink();
-  new BinaryPrinter(sink).writeProgramFile(program);
-  return sink.builder.takeBytes();
-}
-
-Future _processLoadRequest(request) async {
-  if (verbose) {
-    print("FROM DART KERNEL: load request: $request");
-    print("FROM DART KERNEL: package: ${Platform.packageConfig}");
-    print("FROM DART KERNEL: exec: ${Platform.resolvedExecutable}");
-  }
-
-  int tag = request[0];
-  SendPort port = request[1];
-  String inputFileUrl = request[2];
-  Uri scriptUri = Uri.parse(inputFileUrl);
-  Uri packagesUri = Uri.parse(Platform.packageConfig ?? ".packages");
-  Uri patchedSdk =
-      Uri.parse(Platform.resolvedExecutable).resolve("patched_sdk");
-
-  var result;
-  try {
-    result = await parseScript(scriptUri, packagesUri.path, patchedSdk.path);
-  } catch (error) {
-    tag = -tag; // Mark reply as an exception.
-    result = error.toString();
-  }
-
-  port.send([tag, inputFileUrl, inputFileUrl, null, result]);
-}
-
-main() => new RawReceivePort()..handler = _processLoadRequest;
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 5683aee..cada113 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -56,22 +56,6 @@
   include_dirs = [ ".." ]
 }
 
-static_library("libdart_vm_noopt") {
-  configs += [
-    "..:dart_config",
-    "..:dart_maybe_product_config",
-    "..:dart_precompiler_config",
-    "..:dart_maybe_precompiled_runtime_config",
-  ]
-  public_configs = [ ":libdart_vm_config" ]
-  set_sources_assignment_filter([
-                                  "*_test.cc",
-                                  "*_test.h",
-                                ])
-  sources = vm_sources_list
-  include_dirs = [ ".." ]
-}
-
 static_library("libdart_vm_precompiled_runtime") {
   configs += [
     "..:dart_config",
diff --git a/runtime/vm/allocation_test.cc b/runtime/vm/allocation_test.cc
index 146f7f6..18c37a3 100644
--- a/runtime/vm/allocation_test.cc
+++ b/runtime/vm/allocation_test.cc
@@ -77,7 +77,7 @@
 }
 
 
-UNIT_TEST_CASE(StackAllocatedDestruction) {
+VM_UNIT_TEST_CASE(StackAllocatedDestruction) {
   int data = 1;
   StackAllocatedDestructionHelper(&data);
   EXPECT_EQ(4, data);
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 713365d..04d8aeae 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2903,26 +2903,54 @@
 
 
 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
-  ASSERT(result != object);
-  static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
+  if (result == object) {
+    Label smi, join;
 
-  // Make a dummy "Object" whose cid is kSmiCid.
-  movl(result, Immediate(reinterpret_cast<int32_t>(&kSmiCidSource) + 1));
+    testl(object, Immediate(kSmiTagMask));
+    j(EQUAL, &smi, Assembler::kNearJump);
+    LoadClassId(result, object);
+    jmp(&join, Assembler::kNearJump);
 
-  // Check if object (in tmp) is a Smi.
-  testl(object, Immediate(kSmiTagMask));
+    Bind(&smi);
+    movl(result, Immediate(kSmiCid));
 
-  // If the object is not a Smi, use the original object to load the cid.
-  // Otherwise, the dummy object is used, and the result is kSmiCid.
-  cmovne(result, object);
-  LoadClassId(result, result);
+    Bind(&join);
+  } else {
+    ASSERT(result != object);
+    static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
+
+    // Make a dummy "Object" whose cid is kSmiCid.
+    movl(result, Immediate(reinterpret_cast<int32_t>(&kSmiCidSource) + 1));
+
+    // Check if object (in tmp) is a Smi.
+    testl(object, Immediate(kSmiTagMask));
+
+    // If the object is not a Smi, use the original object to load the cid.
+    // Otherwise, the dummy object is used, and the result is kSmiCid.
+    cmovne(result, object);
+    LoadClassId(result, result);
+  }
 }
 
 
 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
-  LoadClassIdMayBeSmi(result, object);
-  // Tag the result.
-  SmiTag(result);
+  if (result == object) {
+    Label smi, join;
+
+    testl(object, Immediate(kSmiTagMask));
+    j(EQUAL, &smi, Assembler::kNearJump);
+    LoadClassId(result, object);
+    SmiTag(result);
+    jmp(&join, Assembler::kNearJump);
+
+    Bind(&smi);
+    movl(result, Immediate(Smi::RawValue(kSmiCid)));
+
+    Bind(&join);
+  } else {
+    LoadClassIdMayBeSmi(result, object);
+    SmiTag(result);
+  }
 }
 
 
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 20541ef..7b2f391 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -3676,29 +3676,56 @@
 
 
 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
-  ASSERT(result != object);
+  Label smi;
 
-  // Load up a null object. We only need it so we can use LoadClassId on it in
-  // the case that object is a Smi.
-  LoadObject(result, Object::null_object());
-  // Check if the object is a Smi.
-  testq(object, Immediate(kSmiTagMask));
-  // If the object *is* a Smi, use the null object instead.
-  cmoveq(object, result);
-  // Loads either the cid of the object if it isn't a Smi, or the cid of null
-  // if it is a Smi, which will be ignored.
-  LoadClassId(result, object);
+  if (result == object) {
+    Label join;
 
-  movq(TMP, Immediate(kSmiCid));
-  // If object is a Smi, move the Smi cid into result. o/w leave alone.
-  cmoveq(result, TMP);
+    testq(object, Immediate(kSmiTagMask));
+    j(EQUAL, &smi, Assembler::kNearJump);
+    LoadClassId(result, object);
+    jmp(&join, Assembler::kNearJump);
+
+    Bind(&smi);
+    movq(result, Immediate(kSmiCid));
+
+    Bind(&join);
+  } else {
+    testq(object, Immediate(kSmiTagMask));
+    movq(result, Immediate(kSmiCid));
+    j(EQUAL, &smi, Assembler::kNearJump);
+    LoadClassId(result, object);
+
+    Bind(&smi);
+  }
 }
 
 
 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
-  LoadClassIdMayBeSmi(result, object);
-  // Finally, tag the result.
-  SmiTag(result);
+  Label smi;
+
+  if (result == object) {
+    Label join;
+
+    testq(object, Immediate(kSmiTagMask));
+    j(EQUAL, &smi, Assembler::kNearJump);
+    LoadClassId(result, object);
+    SmiTag(result);
+    jmp(&join, Assembler::kNearJump);
+
+    Bind(&smi);
+    movq(result, Immediate(Smi::RawValue(kSmiCid)));
+
+    Bind(&join);
+  } else {
+    testq(object, Immediate(kSmiTagMask));
+    movq(result, Immediate(kSmiCid));
+    j(EQUAL, &smi, Assembler::kNearJump);
+    LoadClassId(result, object);
+
+    Bind(&smi);
+    SmiTag(result);
+  }
 }
 
 
diff --git a/runtime/vm/assert_test.cc b/runtime/vm/assert_test.cc
index dc935f1..d74b940 100644
--- a/runtime/vm/assert_test.cc
+++ b/runtime/vm/assert_test.cc
@@ -6,14 +6,14 @@
 #include "vm/unit_test.h"
 
 
-UNIT_TEST_CASE(Assert) {
+VM_UNIT_TEST_CASE(Assert) {
   ASSERT(true);
   ASSERT(87 == 87);
   ASSERT(42 != 87);
 }
 
 
-UNIT_TEST_CASE(Expect) {
+VM_UNIT_TEST_CASE(Expect) {
   EXPECT(true);
   EXPECT(87 == 87);
   EXPECT(42 != 87);
@@ -48,16 +48,16 @@
 }
 
 
-UNIT_TEST_CASE(Fail0) {
+VM_UNIT_TEST_CASE(Fail0) {
   FAIL("This test fails");
 }
 
 
-UNIT_TEST_CASE(Fail1) {
+VM_UNIT_TEST_CASE(Fail1) {
   FAIL1("This test fails with one argument: %d", 4);
 }
 
 
-UNIT_TEST_CASE(Fail2) {
+VM_UNIT_TEST_CASE(Fail2) {
   FAIL2("This test fails with two arguments: %d, %d", -100, 42);
 }
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index ca75856..c99b6cb 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -443,8 +443,12 @@
 
 class TypeNode : public AstNode {
  public:
-  TypeNode(TokenPosition token_pos, const AbstractType& type)
-      : AstNode(token_pos), type_(type) {
+  TypeNode(TokenPosition token_pos,
+           const AbstractType& type,
+           bool is_deferred_reference = false)
+      : AstNode(token_pos),
+        type_(type),
+        is_deferred_reference_(is_deferred_reference) {
     ASSERT(type_.IsZoneHandle());
     ASSERT(!type_.IsNull());
     ASSERT(type_.IsFinalized());
@@ -466,10 +470,14 @@
 
   virtual void VisitChildren(AstNodeVisitor* visitor) const {}
 
+  bool is_deferred_reference() const { return is_deferred_reference_; }
+  void set_is_deferred_reference(bool value) { is_deferred_reference_ = value; }
+
   DECLARE_COMMON_NODE_FUNCTIONS(TypeNode);
 
  private:
   const AbstractType& type_;
+  bool is_deferred_reference_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeNode);
 };
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index fa1028d..af1331c 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -119,7 +119,14 @@
 
 
 void AwaitTransformer::VisitTypeNode(TypeNode* node) {
-  result_ = new (Z) TypeNode(node->token_pos(), node->type());
+  if (node->is_deferred_reference()) {
+    // Deferred references must use a temporary even after loading
+    // happened, so that the number of await temps is the same as
+    // before the loading.
+    result_ = MakeName(node);
+  } else {
+    result_ = node;
+  }
 }
 
 
diff --git a/runtime/vm/atomic_test.cc b/runtime/vm/atomic_test.cc
index 3a95a64..9224299 100644
--- a/runtime/vm/atomic_test.cc
+++ b/runtime/vm/atomic_test.cc
@@ -10,7 +10,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(FetchAndIncrement) {
+VM_UNIT_TEST_CASE(FetchAndIncrement) {
   uintptr_t v = 42;
   EXPECT_EQ(static_cast<uintptr_t>(42),
             AtomicOperations::FetchAndIncrement(&v));
@@ -18,7 +18,7 @@
 }
 
 
-UNIT_TEST_CASE(FetchAndDecrement) {
+VM_UNIT_TEST_CASE(FetchAndDecrement) {
   uintptr_t v = 42;
   EXPECT_EQ(static_cast<uintptr_t>(42),
             AtomicOperations::FetchAndDecrement(&v));
@@ -26,7 +26,7 @@
 }
 
 
-UNIT_TEST_CASE(FetchAndIncrementSigned) {
+VM_UNIT_TEST_CASE(FetchAndIncrementSigned) {
   intptr_t v = -42;
   EXPECT_EQ(static_cast<intptr_t>(-42),
             AtomicOperations::FetchAndIncrement(&v));
@@ -34,7 +34,7 @@
 }
 
 
-UNIT_TEST_CASE(FetchAndDecrementSigned) {
+VM_UNIT_TEST_CASE(FetchAndDecrementSigned) {
   intptr_t v = -42;
   EXPECT_EQ(static_cast<intptr_t>(-42),
             AtomicOperations::FetchAndDecrement(&v));
@@ -42,21 +42,21 @@
 }
 
 
-UNIT_TEST_CASE(IncrementBy) {
+VM_UNIT_TEST_CASE(IncrementBy) {
   intptr_t v = 42;
   AtomicOperations::IncrementBy(&v, 100);
   EXPECT_EQ(static_cast<intptr_t>(142), v);
 }
 
 
-UNIT_TEST_CASE(DecrementBy) {
+VM_UNIT_TEST_CASE(DecrementBy) {
   intptr_t v = 42;
   AtomicOperations::DecrementBy(&v, 41);
   EXPECT_EQ(static_cast<intptr_t>(1), v);
 }
 
 
-UNIT_TEST_CASE(LoadRelaxed) {
+VM_UNIT_TEST_CASE(LoadRelaxed) {
   uword v = 42;
   EXPECT_EQ(static_cast<uword>(42), AtomicOperations::LoadRelaxed(&v));
 }
diff --git a/runtime/vm/bitfield_test.cc b/runtime/vm/bitfield_test.cc
index a9d41c9..8404ec9 100644
--- a/runtime/vm/bitfield_test.cc
+++ b/runtime/vm/bitfield_test.cc
@@ -9,7 +9,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(BitFields) {
+VM_UNIT_TEST_CASE(BitFields) {
   class TestBitFields : public BitField<uword, int32_t, 1, 8> {};
   EXPECT(TestBitFields::is_valid(16));
   EXPECT(!TestBitFields::is_valid(256));
diff --git a/runtime/vm/boolfield_test.cc b/runtime/vm/boolfield_test.cc
index 1e21b1b..b13001b 100644
--- a/runtime/vm/boolfield_test.cc
+++ b/runtime/vm/boolfield_test.cc
@@ -8,7 +8,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(BoolField) {
+VM_UNIT_TEST_CASE(BoolField) {
   class TestBoolField : public BoolField<1> {};
   EXPECT(TestBoolField::decode(2));
   EXPECT(!TestBoolField::decode(1));
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 8ef219d..9839c5a 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -22,7 +22,7 @@
 
 DEFINE_FLAG(bool,
             use_corelib_source_files,
-            kDefaultCorelibSourceFlag,
+            false,
             "Attempt to use source files directly when loading in the core "
             "libraries during the bootstrap process");
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 89a1076..2650f45 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -13,7 +13,7 @@
 
 // List of bootstrap native entry points used in the core dart library.
 #define BOOTSTRAP_NATIVE_LIST(V)                                               \
-  V(DartCore_fatal, 1)                                                         \
+  V(DartInternal_fatal, 1)                                                     \
   V(Object_equals, 2)                                                          \
   V(Object_getHash, 1)                                                         \
   V(Object_setHash, 2)                                                         \
@@ -161,6 +161,9 @@
   V(DateTime_localTimeZoneAdjustmentInSeconds, 0)                              \
   V(AssertionError_throwNew, 3)                                                \
   V(Async_rethrow, 2)                                                          \
+  V(StackTrace_asyncStackTraceHelper, 0)                                       \
+  V(StackTrace_clearAsyncThreadStackTrace, 0)                                  \
+  V(StackTrace_setAsyncThreadStackTrace, 1)                                    \
   V(StackTrace_current, 0)                                                     \
   V(TypeError_throwNew, 5)                                                     \
   V(FallThroughError_throwNew, 1)                                              \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index c319f1f..70b782b 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -565,6 +565,16 @@
         ResolveSignature(scope_class, signature);
       } else {
         ResolveSignature(cls, signature);
+        if ((type.arguments() != TypeArguments::null()) &&
+            signature.HasInstantiatedSignature()) {
+          ASSERT(scope_class.IsGeneric());
+          // Although the scope class of this function type is generic,
+          // the signature of this function type does not refer to any
+          // of its type parameters. Reset its scope class to _Closure.
+          Type::Cast(type).set_type_class(Class::Handle(
+              Isolate::Current()->object_store()->closure_class()));
+          type.set_arguments(Object::null_type_arguments());
+        }
       }
       if (signature.IsSignatureFunction()) {
         // Drop fields that are not necessary anymore after resolution.
@@ -706,7 +716,7 @@
 
   // If we are not reifying types, drop type arguments.
   if (!FLAG_reify) {
-    type.set_arguments(TypeArguments::Handle(zone, TypeArguments::null()));
+    type.set_arguments(Object::null_type_arguments());
   }
 
   // Initialize the type argument vector.
@@ -1245,8 +1255,21 @@
 
 void ClassFinalizer::ResolveSignature(const Class& cls,
                                       const Function& function) {
+  AbstractType& type = AbstractType::Handle();
+  // Resolve upper bounds of function type parameters.
+  const intptr_t num_type_params = function.NumTypeParameters();
+  if (num_type_params > 0) {
+    TypeParameter& type_param = TypeParameter::Handle();
+    const TypeArguments& type_params =
+        TypeArguments::Handle(function.type_parameters());
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type_param ^= type_params.TypeAt(i);
+      type = type_param.bound();
+      ResolveType(cls, type);
+    }
+  }
   // Resolve result type.
-  AbstractType& type = AbstractType::Handle(function.result_type());
+  type = function.result_type();
   // It is not a compile time error if this name does not resolve to a class or
   // interface.
   ResolveType(cls, type);
@@ -1261,12 +1284,26 @@
 
 void ClassFinalizer::FinalizeSignature(const Class& cls,
                                        const Function& function) {
+  AbstractType& type = AbstractType::Handle();
+  AbstractType& finalized_type = AbstractType::Handle();
+  // Finalize upper bounds of function type parameters.
+  const intptr_t num_type_params = function.NumTypeParameters();
+  if (num_type_params > 0) {
+    TypeParameter& type_param = TypeParameter::Handle();
+    const TypeArguments& type_params =
+        TypeArguments::Handle(function.type_parameters());
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type_param ^= type_params.TypeAt(i);
+      type = type_param.bound();
+      finalized_type = FinalizeType(cls, type, kCanonicalize);
+      if (finalized_type.raw() != type.raw()) {
+        type_param.set_bound(finalized_type);
+      }
+    }
+  }
   // Finalize result type.
-  AbstractType& type = AbstractType::Handle(function.result_type());
-  // It is not a compile time error if this name does not resolve to a class or
-  // interface.
-  AbstractType& finalized_type =
-      AbstractType::Handle(FinalizeType(cls, type, kCanonicalize));
+  type = function.result_type();
+  finalized_type = FinalizeType(cls, type, kCanonicalize);
   // The result type may be malformed or malbounded.
   if (finalized_type.raw() != type.raw()) {
     function.set_result_type(finalized_type);
@@ -1726,7 +1763,7 @@
         param_name =
             Symbols::FromConcat(thread, param_name, Symbols::Backtick());
         cloned_param =
-            TypeParameter::New(mixin_app_class, null_function, cloned_index,
+            TypeParameter::New(mixin_app_class, null_function, cloned_index, 0,
                                param_name, param_bound, param.token_pos());
         cloned_type_params.SetTypeAt(cloned_index, cloned_param);
         // Change the type arguments of the super type to refer to the
@@ -1764,7 +1801,7 @@
         cloned_param =
             TypeParameter::New(mixin_app_class, null_function,
                                cloned_index,  // Unfinalized index.
-                               param_name, param_bound, param.token_pos());
+                               0, param_name, param_bound, param.token_pos());
         cloned_type_params.SetTypeAt(cloned_index, cloned_param);
         mixin_type_args.SetTypeAt(i, cloned_param);  // Unfinalized length.
         instantiator.SetTypeAt(offset + i, cloned_param);  // Finalized length.
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index f30f7a5..37da9d3 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -35,6 +35,9 @@
                                        FinalizationKind finalization,
                                        PendingTypes* pending_types = NULL);
 
+  // Finalize the types in the functions's signature while parsing class cls.
+  static void FinalizeSignature(const Class& cls, const Function& function);
+
   // Allocate, finalize, and return a new malformed type as if it was declared
   // in class cls at the given token position.
   // If not null, prepend prev_error to the error message built from the format
@@ -152,7 +155,6 @@
   static void FinalizeUpperBounds(const Class& cls,
                                   FinalizationKind finalization);
   static void ResolveSignature(const Class& cls, const Function& function);
-  static void FinalizeSignature(const Class& cls, const Function& function);
   static void ResolveAndFinalizeMemberTypes(const Class& cls);
   static void PrintClassInformation(const Class& cls);
   static void CollectInterfaces(const Class& cls,
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 9929c3d..1735bdc 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1567,11 +1567,12 @@
     s->Push(code->ptr()->exception_handlers_);
     s->Push(code->ptr()->pc_descriptors_);
     s->Push(code->ptr()->stackmaps_);
+    s->Push(code->ptr()->inlined_id_to_function_);
+    s->Push(code->ptr()->code_source_map_);
 
     if (s->kind() == Snapshot::kAppJIT) {
       s->Push(code->ptr()->deopt_info_array_);
       s->Push(code->ptr()->static_calls_target_table_);
-      NOT_IN_PRODUCT(s->Push(code->ptr()->inlined_metadata_));
       NOT_IN_PRODUCT(s->Push(code->ptr()->return_address_metadata_));
     }
   }
@@ -1620,11 +1621,12 @@
       s->WriteRef(code->ptr()->exception_handlers_);
       s->WriteRef(code->ptr()->pc_descriptors_);
       s->WriteRef(code->ptr()->stackmaps_);
+      s->WriteRef(code->ptr()->inlined_id_to_function_);
+      s->WriteRef(code->ptr()->code_source_map_);
 
       if (s->kind() == Snapshot::kAppJIT) {
         s->WriteRef(code->ptr()->deopt_info_array_);
         s->WriteRef(code->ptr()->static_calls_target_table_);
-        NOT_IN_PRODUCT(s->WriteRef(code->ptr()->inlined_metadata_));
         NOT_IN_PRODUCT(s->WriteRef(code->ptr()->return_address_metadata_));
       }
 
@@ -1689,6 +1691,10 @@
       code->ptr()->pc_descriptors_ =
           reinterpret_cast<RawPcDescriptors*>(d->ReadRef());
       code->ptr()->stackmaps_ = reinterpret_cast<RawArray*>(d->ReadRef());
+      code->ptr()->inlined_id_to_function_ =
+          reinterpret_cast<RawArray*>(d->ReadRef());
+      code->ptr()->code_source_map_ =
+          reinterpret_cast<RawCodeSourceMap*>(d->ReadRef());
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
       if (d->kind() == Snapshot::kAppJIT) {
@@ -1697,22 +1703,17 @@
         code->ptr()->static_calls_target_table_ =
             reinterpret_cast<RawArray*>(d->ReadRef());
 #if defined(PRODUCT)
-        code->ptr()->inlined_metadata_ = Array::null();
         code->ptr()->return_address_metadata_ = Object::null();
 #else
-        code->ptr()->inlined_metadata_ =
-            reinterpret_cast<RawArray*>(d->ReadRef());
         code->ptr()->return_address_metadata_ = d->ReadRef();
 #endif
       } else {
         code->ptr()->deopt_info_array_ = Array::null();
         code->ptr()->static_calls_target_table_ = Array::null();
-        code->ptr()->inlined_metadata_ = Array::null();
         code->ptr()->return_address_metadata_ = Object::null();
       }
 
       code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
-      code->ptr()->code_source_map_ = CodeSourceMap::null();
       code->ptr()->comments_ = Array::null();
 
       code->ptr()->compile_timestamp_ = 0;
@@ -1982,8 +1983,7 @@
       s->WriteRef(handlers->ptr()->handled_types_data_);
 
       uint8_t* data = reinterpret_cast<uint8_t*>(handlers->ptr()->data());
-      intptr_t length_in_bytes =
-          length * sizeof(RawExceptionHandlers::HandlerInfo);
+      intptr_t length_in_bytes = length * sizeof(ExceptionHandlerInfo);
       s->WriteBytes(data, length_in_bytes);
     }
   }
@@ -2026,8 +2026,7 @@
           reinterpret_cast<RawArray*>(d->ReadRef());
 
       uint8_t* data = reinterpret_cast<uint8_t*>(handlers->ptr()->data());
-      intptr_t length_in_bytes =
-          length * sizeof(RawExceptionHandlers::HandlerInfo);
+      intptr_t length_in_bytes = length * sizeof(ExceptionHandlerInfo);
       d->ReadBytes(data, length_in_bytes);
     }
   }
@@ -4545,6 +4544,8 @@
       return new (Z) ObjectPoolSerializationCluster();
     case kPcDescriptorsCid:
       return new (Z) RODataSerializationCluster(kPcDescriptorsCid);
+    case kCodeSourceMapCid:
+      return new (Z) RODataSerializationCluster(kCodeSourceMapCid);
     case kStackMapCid:
       return new (Z) RODataSerializationCluster(kStackMapCid);
     case kExceptionHandlersCid:
@@ -4910,6 +4911,7 @@
     case kObjectPoolCid:
       return new (Z) ObjectPoolDeserializationCluster();
     case kPcDescriptorsCid:
+    case kCodeSourceMapCid:
     case kStackMapCid:
       return new (Z) RODataDeserializationCluster();
     case kExceptionHandlersCid:
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 1e6ff22..1eb2092 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -4,6 +4,8 @@
 
 #include "vm/code_descriptors.h"
 
+#include "vm/log.h"
+
 namespace dart {
 
 void DescriptorList::AddDescriptor(RawPcDescriptors::Kind kind,
@@ -41,25 +43,6 @@
 }
 
 
-void CodeSourceMapBuilder::AddEntry(intptr_t pc_offset,
-                                    TokenPosition token_pos) {
-  // Require pc offset to monotonically increase.
-  ASSERT((prev_pc_offset < pc_offset) ||
-         ((prev_pc_offset == 0) && (pc_offset == 0)));
-  CodeSourceMap::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
-  CodeSourceMap::EncodeInteger(&encoded_data_,
-                               token_pos.value() - prev_token_pos);
-
-  prev_pc_offset = pc_offset;
-  prev_token_pos = token_pos.value();
-}
-
-
-RawCodeSourceMap* CodeSourceMapBuilder::Finalize() {
-  return CodeSourceMap::New(&encoded_data_);
-}
-
-
 void StackMapTableBuilder::AddEntry(intptr_t pc_offset,
                                     BitmapBuilder* bitmap,
                                     intptr_t register_bit_count) {
@@ -132,4 +115,436 @@
 }
 
 
+static uint8_t* zone_allocator(uint8_t* ptr,
+                               intptr_t old_size,
+                               intptr_t new_size) {
+  Zone* zone = Thread::Current()->zone();
+  return zone->Realloc<uint8_t>(ptr, old_size, new_size);
+}
+
+
+const TokenPosition CodeSourceMapBuilder::kInitialPosition =
+    TokenPosition::kDartCodePrologue;
+
+
+CodeSourceMapBuilder::CodeSourceMapBuilder(
+    bool stack_traces_only,
+    const GrowableArray<intptr_t>& caller_inline_id,
+    const GrowableArray<TokenPosition>& inline_id_to_token_pos,
+    const GrowableArray<const Function*>& inline_id_to_function)
+    : buffered_pc_offset_(0),
+      buffered_inline_id_stack_(),
+      buffered_token_pos_stack_(),
+      written_pc_offset_(0),
+      written_inline_id_stack_(),
+      written_token_pos_stack_(),
+      caller_inline_id_(caller_inline_id),
+      inline_id_to_token_pos_(inline_id_to_token_pos),
+      inline_id_to_function_(inline_id_to_function),
+      buffer_(NULL),
+      stream_(&buffer_, zone_allocator, 64),
+      stack_traces_only_(stack_traces_only) {
+  buffered_inline_id_stack_.Add(0);
+  buffered_token_pos_stack_.Add(kInitialPosition);
+  written_inline_id_stack_.Add(0);
+  written_token_pos_stack_.Add(kInitialPosition);
+}
+
+
+void CodeSourceMapBuilder::FlushBuffer() {
+  FlushBufferStack();
+  FlushBufferPosition();
+  FlushBufferPC();
+}
+
+
+void CodeSourceMapBuilder::FlushBufferStack() {
+  for (intptr_t i = buffered_inline_id_stack_.length() - 1; i >= 0; i--) {
+    intptr_t buffered_id = buffered_inline_id_stack_[i];
+    if (i < written_inline_id_stack_.length()) {
+      intptr_t written_id = written_inline_id_stack_[i];
+      if (buffered_id == written_id) {
+        // i is the top-most position where the buffered and written stack
+        // match.
+        while (written_inline_id_stack_.length() > i + 1) {
+          WritePop();
+        }
+        for (intptr_t j = i + 1; j < buffered_inline_id_stack_.length(); j++) {
+          TokenPosition buffered_pos = buffered_token_pos_stack_[j - 1];
+          TokenPosition written_pos = written_token_pos_stack_[j - 1];
+          if (buffered_pos != written_pos) {
+            WriteChangePosition(buffered_pos);
+          }
+          WritePush(buffered_inline_id_stack_[j]);
+        }
+        return;
+      }
+    }
+  }
+  UNREACHABLE();
+}
+
+
+void CodeSourceMapBuilder::FlushBufferPosition() {
+  ASSERT(buffered_token_pos_stack_.length() ==
+         written_token_pos_stack_.length());
+
+  intptr_t top = buffered_token_pos_stack_.length() - 1;
+  TokenPosition buffered_pos = buffered_token_pos_stack_[top];
+  TokenPosition written_pos = written_token_pos_stack_[top];
+  if (buffered_pos != written_pos) {
+    WriteChangePosition(buffered_pos);
+  }
+}
+
+
+void CodeSourceMapBuilder::FlushBufferPC() {
+  if (buffered_pc_offset_ != written_pc_offset_) {
+    WriteAdvancePC(buffered_pc_offset_ - written_pc_offset_);
+  }
+}
+
+
+void CodeSourceMapBuilder::StartInliningInterval(int32_t pc_offset,
+                                                 intptr_t inline_id) {
+  if (buffered_inline_id_stack_.Last() == inline_id) {
+    // No change in function stack.
+    return;
+  }
+  if (inline_id == -1) {
+    // Basic blocking missing an inline_id.
+    return;
+  }
+
+  if (!stack_traces_only_) {
+    FlushBuffer();
+  }
+
+  // Find a minimal set of pops and pushes to bring us to the new function
+  // stack.
+
+  // Pop to a common ancestor.
+  intptr_t common_parent = inline_id;
+  while (!IsOnBufferedStack(common_parent)) {
+    common_parent = caller_inline_id_[common_parent];
+  }
+  while (buffered_inline_id_stack_.Last() != common_parent) {
+    BufferPop();
+  }
+
+  // Push to the new top-of-stack function.
+  GrowableArray<intptr_t> to_push;
+  intptr_t id = inline_id;
+  while (id != common_parent) {
+    to_push.Add(id);
+    id = caller_inline_id_[id];
+  }
+  for (intptr_t i = to_push.length() - 1; i >= 0; i--) {
+    intptr_t callee_id = to_push[i];
+    TokenPosition call_token;
+    if (callee_id != 0) {
+      // TODO(rmacnak): Should make this array line up with the others.
+      call_token = inline_id_to_token_pos_[callee_id - 1];
+    } else {
+      UNREACHABLE();
+    }
+
+    // Report caller as at the position of the call.
+    BufferChangePosition(call_token);
+
+    BufferPush(callee_id);
+  }
+}
+
+
+void CodeSourceMapBuilder::BeginCodeSourceRange(int32_t pc_offset) {}
+
+
+void CodeSourceMapBuilder::EndCodeSourceRange(int32_t pc_offset,
+                                              TokenPosition pos) {
+  if (pc_offset == buffered_pc_offset_) {
+    return;  // Empty intermediate instruction.
+  }
+  if (pos != buffered_token_pos_stack_.Last()) {
+    if (!stack_traces_only_) {
+      FlushBuffer();
+    }
+    BufferChangePosition(pos);
+  }
+  BufferAdvancePC(pc_offset - buffered_pc_offset_);
+}
+
+
+void CodeSourceMapBuilder::NoteDescriptor(RawPcDescriptors::Kind kind,
+                                          int32_t pc_offset,
+                                          TokenPosition pos) {
+  const uint8_t kCanThrow =
+      RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall |
+      RawPcDescriptors::kRuntimeCall | RawPcDescriptors::kOther;
+  if (stack_traces_only_ && ((kind & kCanThrow) != 0)) {
+    BufferChangePosition(pos);
+    BufferAdvancePC(pc_offset - buffered_pc_offset_);
+    FlushBuffer();
+  }
+}
+
+
+RawArray* CodeSourceMapBuilder::InliningIdToFunction() {
+  if (inline_id_to_function_.length() <= 1) {
+    // Not optimizing, or optimizing and nothing inlined.
+    return Object::empty_array().raw();
+  }
+  const Array& res =
+      Array::Handle(Array::New(inline_id_to_function_.length(), Heap::kOld));
+  for (intptr_t i = 0; i < inline_id_to_function_.length(); i++) {
+    res.SetAt(i, *inline_id_to_function_[i]);
+  }
+  return res.raw();
+}
+
+
+RawCodeSourceMap* CodeSourceMapBuilder::Finalize() {
+  if (!stack_traces_only_) {
+    FlushBuffer();
+  }
+  intptr_t length = stream_.bytes_written();
+  const CodeSourceMap& map = CodeSourceMap::Handle(CodeSourceMap::New(length));
+  NoSafepointScope no_safepoint;
+  memmove(map.Data(), buffer_, length);
+  return map.raw();
+}
+
+
+void CodeSourceMapBuilder::WriteChangePosition(TokenPosition pos) {
+  stream_.Write<uint8_t>(kChangePosition);
+  if (FLAG_precompiled_mode) {
+    intptr_t line = -1;
+    intptr_t inline_id = buffered_inline_id_stack_.Last();
+    if (inline_id < inline_id_to_function_.length()) {
+      const Function* function = inline_id_to_function_[inline_id];
+      Script& script = Script::Handle(function->script());
+      line = script.GetTokenLineUsingLineStarts(pos);
+    }
+    stream_.Write<int32_t>(static_cast<int32_t>(line));
+  } else {
+    stream_.Write<int32_t>(static_cast<int32_t>(pos.value()));
+  }
+  written_token_pos_stack_.Last() = pos;
+}
+
+
+void CodeSourceMapReader::GetInlinedFunctionsAt(
+    int32_t pc_offset,
+    GrowableArray<const Function*>* function_stack,
+    GrowableArray<TokenPosition>* token_positions) {
+  function_stack->Clear();
+  token_positions->Clear();
+
+  NoSafepointScope no_safepoint;
+  ReadStream stream(map_.Data(), map_.Length());
+
+  int32_t current_pc_offset = 0;
+  function_stack->Add(&root_);
+  token_positions->Add(CodeSourceMapBuilder::kInitialPosition);
+
+  while (stream.PendingBytes() > 0) {
+    uint8_t opcode = stream.Read<uint8_t>();
+    switch (opcode) {
+      case CodeSourceMapBuilder::kChangePosition: {
+        int32_t position = stream.Read<int32_t>();
+        (*token_positions)[token_positions->length() - 1] =
+            TokenPosition(position);
+        break;
+      }
+      case CodeSourceMapBuilder::kAdvancePC: {
+        int32_t delta = stream.Read<int32_t>();
+        current_pc_offset += delta;
+        if (current_pc_offset > pc_offset) {
+          return;
+        }
+        break;
+      }
+      case CodeSourceMapBuilder::kPushFunction: {
+        int32_t func = stream.Read<int32_t>();
+        function_stack->Add(
+            &Function::Handle(Function::RawCast(functions_.At(func))));
+        token_positions->Add(CodeSourceMapBuilder::kInitialPosition);
+        break;
+      }
+      case CodeSourceMapBuilder::kPopFunction: {
+        // We never pop the root function.
+        ASSERT(function_stack->length() > 1);
+        ASSERT(token_positions->length() > 1);
+        function_stack->RemoveLast();
+        token_positions->RemoveLast();
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+
+
+#ifndef PRODUCT
+void CodeSourceMapReader::PrintJSONInlineIntervals(JSONObject* jsobj) {
+  {
+    JSONArray inlined_functions(jsobj, "_inlinedFunctions");
+    Function& function = Function::Handle();
+    for (intptr_t i = 0; i < functions_.Length(); i++) {
+      function ^= functions_.At(i);
+      ASSERT(!function.IsNull());
+      inlined_functions.AddValue(function);
+    }
+  }
+
+  GrowableArray<intptr_t> function_stack;
+  JSONArray inline_intervals(jsobj, "_inlinedIntervals");
+  NoSafepointScope no_safepoint;
+  ReadStream stream(map_.Data(), map_.Length());
+
+  int32_t current_pc_offset = 0;
+  function_stack.Add(0);
+
+  while (stream.PendingBytes() > 0) {
+    uint8_t opcode = stream.Read<uint8_t>();
+    switch (opcode) {
+      case CodeSourceMapBuilder::kChangePosition: {
+        stream.Read<int32_t>();
+        break;
+      }
+      case CodeSourceMapBuilder::kAdvancePC: {
+        int32_t delta = stream.Read<int32_t>();
+        // Format: [start, end, inline functions...]
+        JSONArray inline_interval(&inline_intervals);
+        inline_interval.AddValue(static_cast<intptr_t>(current_pc_offset));
+        inline_interval.AddValue(
+            static_cast<intptr_t>(current_pc_offset + delta - 1));
+        for (intptr_t i = 0; i < function_stack.length(); i++) {
+          inline_interval.AddValue(function_stack[i]);
+        }
+        current_pc_offset += delta;
+        break;
+      }
+      case CodeSourceMapBuilder::kPushFunction: {
+        int32_t func = stream.Read<int32_t>();
+        function_stack.Add(func);
+        break;
+      }
+      case CodeSourceMapBuilder::kPopFunction: {
+        // We never pop the root function.
+        ASSERT(function_stack.length() > 1);
+        function_stack.RemoveLast();
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+#endif  // !PRODUCT
+
+
+void CodeSourceMapReader::DumpInlineIntervals(uword start) {
+  GrowableArray<const Function*> function_stack;
+  LogBlock lb;
+  NoSafepointScope no_safepoint;
+  ReadStream stream(map_.Data(), map_.Length());
+
+  int32_t current_pc_offset = 0;
+  function_stack.Add(&root_);
+
+  THR_Print("Inline intervals {\n");
+  while (stream.PendingBytes() > 0) {
+    uint8_t opcode = stream.Read<uint8_t>();
+    switch (opcode) {
+      case CodeSourceMapBuilder::kChangePosition: {
+        stream.Read<int32_t>();
+        break;
+      }
+      case CodeSourceMapBuilder::kAdvancePC: {
+        int32_t delta = stream.Read<int32_t>();
+        THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
+                  start + current_pc_offset + delta - 1);
+        for (intptr_t i = 0; i < function_stack.length(); i++) {
+          THR_Print("%s ", function_stack[i]->ToCString());
+        }
+        THR_Print("\n");
+        current_pc_offset += delta;
+        break;
+      }
+      case CodeSourceMapBuilder::kPushFunction: {
+        int32_t func = stream.Read<int32_t>();
+        function_stack.Add(
+            &Function::Handle(Function::RawCast(functions_.At(func))));
+        break;
+      }
+      case CodeSourceMapBuilder::kPopFunction: {
+        // We never pop the root function.
+        ASSERT(function_stack.length() > 1);
+        function_stack.RemoveLast();
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+  }
+  THR_Print("}\n");
+}
+
+
+void CodeSourceMapReader::DumpSourcePositions(uword start) {
+  GrowableArray<const Function*> function_stack;
+  GrowableArray<TokenPosition> token_positions;
+  LogBlock lb;
+  NoSafepointScope no_safepoint;
+  ReadStream stream(map_.Data(), map_.Length());
+
+  int32_t current_pc_offset = 0;
+  function_stack.Add(&root_);
+  token_positions.Add(CodeSourceMapBuilder::kInitialPosition);
+
+  THR_Print("Source positions {\n");
+  while (stream.PendingBytes() > 0) {
+    uint8_t opcode = stream.Read<uint8_t>();
+    switch (opcode) {
+      case CodeSourceMapBuilder::kChangePosition: {
+        int32_t position = stream.Read<int32_t>();
+        token_positions[token_positions.length() - 1] = TokenPosition(position);
+        break;
+      }
+      case CodeSourceMapBuilder::kAdvancePC: {
+        int32_t delta = stream.Read<int32_t>();
+        THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
+                  start + current_pc_offset + delta - 1);
+        for (intptr_t i = 0; i < function_stack.length(); i++) {
+          THR_Print("%s@%" Pd " ", function_stack[i]->ToCString(),
+                    token_positions[i].value());
+        }
+        THR_Print("\n");
+        current_pc_offset += delta;
+        break;
+      }
+      case CodeSourceMapBuilder::kPushFunction: {
+        int32_t func = stream.Read<int32_t>();
+        function_stack.Add(
+            &Function::Handle(Function::RawCast(functions_.At(func))));
+        token_positions.Add(CodeSourceMapBuilder::kInitialPosition);
+        break;
+      }
+      case CodeSourceMapBuilder::kPopFunction: {
+        // We never pop the root function.
+        ASSERT(function_stack.length() > 1);
+        ASSERT(token_positions.length() > 1);
+        function_stack.RemoveLast();
+        token_positions.RemoveLast();
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+  }
+  THR_Print("}\n");
+}
+
 }  // namespace dart
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index fa99412..2500ed8 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -10,6 +10,7 @@
 #include "vm/globals.h"
 #include "vm/growable_array.h"
 #include "vm/object.h"
+#include "vm/log.h"
 
 namespace dart {
 
@@ -42,27 +43,6 @@
 };
 
 
-class CodeSourceMapBuilder : public ZoneAllocated {
- public:
-  explicit CodeSourceMapBuilder(intptr_t initial_capacity = 64)
-      : encoded_data_(initial_capacity), prev_pc_offset(0), prev_token_pos(0) {}
-
-  ~CodeSourceMapBuilder() {}
-
-  void AddEntry(intptr_t pc_offset, TokenPosition token_pos);
-
-  RawCodeSourceMap* Finalize();
-
- private:
-  GrowableArray<uint8_t> encoded_data_;
-
-  intptr_t prev_pc_offset;
-  intptr_t prev_token_pos;
-
-  DISALLOW_COPY_AND_ASSIGN(CodeSourceMapBuilder);
-};
-
-
 class StackMapTableBuilder : public ZoneAllocated {
  public:
   StackMapTableBuilder()
@@ -159,6 +139,131 @@
   DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerList);
 };
 
+
+// A CodeSourceMap maps from pc offsets to a stack of inlined functions and
+// their positions. This is encoded as a little bytecode that pushes and pops
+// functions and changes the top function's position as the PC advances.
+// Decoding happens by running this bytecode until we reach the desired PC.
+//
+// The implementation keeps track of two sets of state: one written to the byte
+// stream and one that is buffered. On the JIT, this buffering effectively gives
+// us a peephole optimization that merges adjacent advance PC bytecodes. On AOT,
+// this allows to skip encoding our position until we reach a PC where we might
+// throw.
+class CodeSourceMapBuilder : public ZoneAllocated {
+ public:
+  CodeSourceMapBuilder(
+      bool stack_traces_only,
+      const GrowableArray<intptr_t>& caller_inline_id,
+      const GrowableArray<TokenPosition>& inline_id_to_token_pos,
+      const GrowableArray<const Function*>& inline_id_to_function);
+
+  // The position at which a function implicitly starts, for both the root and
+  // after a push bytecode. We use the classifying position kDartCodePrologue
+  // since it is the most common.
+  static const TokenPosition kInitialPosition;
+
+  static const uint8_t kChangePosition = 0;
+  static const uint8_t kAdvancePC = 1;
+  static const uint8_t kPushFunction = 2;
+  static const uint8_t kPopFunction = 3;
+
+  void StartInliningInterval(int32_t pc_offset, intptr_t inline_id);
+  void BeginCodeSourceRange(int32_t pc_offset);
+  void EndCodeSourceRange(int32_t pc_offset, TokenPosition pos);
+  void NoteDescriptor(RawPcDescriptors::Kind kind,
+                      int32_t pc_offset,
+                      TokenPosition pos);
+
+  RawArray* InliningIdToFunction();
+  RawCodeSourceMap* Finalize();
+
+ private:
+  void BufferChangePosition(TokenPosition pos) {
+    buffered_token_pos_stack_.Last() = pos;
+  }
+  void WriteChangePosition(TokenPosition pos);
+  void BufferAdvancePC(int32_t distance) { buffered_pc_offset_ += distance; }
+  void WriteAdvancePC(int32_t distance) {
+    stream_.Write<uint8_t>(kAdvancePC);
+    stream_.Write<int32_t>(distance);
+    written_pc_offset_ += distance;
+  }
+  void BufferPush(intptr_t inline_id) {
+    buffered_inline_id_stack_.Add(inline_id);
+    buffered_token_pos_stack_.Add(kInitialPosition);
+  }
+  void WritePush(intptr_t inline_id) {
+    stream_.Write<uint8_t>(kPushFunction);
+    stream_.Write<int32_t>(inline_id);
+    written_inline_id_stack_.Add(inline_id);
+    written_token_pos_stack_.Add(kInitialPosition);
+  }
+  void BufferPop() {
+    buffered_inline_id_stack_.RemoveLast();
+    buffered_token_pos_stack_.RemoveLast();
+  }
+  void WritePop() {
+    stream_.Write<uint8_t>(kPopFunction);
+    written_inline_id_stack_.RemoveLast();
+    written_token_pos_stack_.RemoveLast();
+  }
+
+  void FlushBuffer();
+  void FlushBufferStack();
+  void FlushBufferPosition();
+  void FlushBufferPC();
+
+  bool IsOnBufferedStack(intptr_t inline_id) {
+    for (intptr_t i = 0; i < buffered_inline_id_stack_.length(); i++) {
+      if (buffered_inline_id_stack_[i] == inline_id) return true;
+    }
+    return false;
+  }
+
+  intptr_t buffered_pc_offset_;
+  GrowableArray<intptr_t> buffered_inline_id_stack_;
+  GrowableArray<TokenPosition> buffered_token_pos_stack_;
+
+  intptr_t written_pc_offset_;
+  GrowableArray<intptr_t> written_inline_id_stack_;
+  GrowableArray<TokenPosition> written_token_pos_stack_;
+
+  const GrowableArray<intptr_t>& caller_inline_id_;
+  const GrowableArray<TokenPosition>& inline_id_to_token_pos_;
+  const GrowableArray<const Function*>& inline_id_to_function_;
+
+  uint8_t* buffer_;
+  WriteStream stream_;
+
+  const bool stack_traces_only_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeSourceMapBuilder);
+};
+
+
+class CodeSourceMapReader : public ValueObject {
+ public:
+  CodeSourceMapReader(const CodeSourceMap& map,
+                      const Array& functions,
+                      const Function& root)
+      : map_(map), functions_(functions), root_(root) {}
+
+  void GetInlinedFunctionsAt(int32_t pc_offset,
+                             GrowableArray<const Function*>* function_stack,
+                             GrowableArray<TokenPosition>* token_positions);
+  NOT_IN_PRODUCT(void PrintJSONInlineIntervals(JSONObject* jsobj));
+  void DumpInlineIntervals(uword start);
+  void DumpSourcePositions(uword start);
+
+ private:
+  const CodeSourceMap& map_;
+  const Array& functions_;
+  const Function& root_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeSourceMapReader);
+};
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_CODE_DESCRIPTORS_H_
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 0097bb4..3d2b6a1 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -319,52 +319,4 @@
   }
 }
 
-
-TEST_CASE(CodeSourceMap_TokenPositions) {
-  const intptr_t token_positions[] = {
-      kMinInt32,
-      5,
-      13,
-      13,
-      13,
-      13,
-      31,
-      23,
-      23,
-      23,
-      33,
-      33,
-      5,
-      5,
-      TokenPosition::kMinSourcePos,
-      TokenPosition::kMaxSourcePos,
-  };
-  const intptr_t num_token_positions =
-      sizeof(token_positions) / sizeof(token_positions[0]);
-
-  CodeSourceMapBuilder* builder = new CodeSourceMapBuilder();
-  ASSERT(builder != NULL);
-
-  for (intptr_t i = 0; i < num_token_positions; i++) {
-    builder->AddEntry(i, TokenPosition(token_positions[i]));
-  }
-
-  const CodeSourceMap& code_Source_map =
-      CodeSourceMap::Handle(builder->Finalize());
-
-  ASSERT(!code_Source_map.IsNull());
-  CodeSourceMap::Iterator it(code_Source_map);
-
-  uintptr_t i = 0;
-  while (it.MoveNext()) {
-    EXPECT(it.PcOffset() == i);
-    if (token_positions[i] != it.TokenPos().value()) {
-      OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n", i,
-                token_positions[i], it.TokenPos().value());
-    }
-    EXPECT(token_positions[i] == it.TokenPos().value());
-    i++;
-  }
-}
-
 }  // namespace dart
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 6e4cd11..5af05c9 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -931,28 +931,6 @@
 }
 
 
-// Handles inline cache misses by updating the IC data array of the call site.
-//   Arg0: Receiver object.
-//   Arg1: Argument after receiver.
-//   Arg2: Second argument after receiver.
-//   Arg3: IC data object.
-//   Returns: target function with compiled code or null.
-// Modifies the instance call to hold the updated IC data array.
-DEFINE_RUNTIME_ENTRY(InlineCacheMissHandlerThreeArgs, 4) {
-  const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
-  const Instance& arg1 = Instance::CheckedHandle(arguments.ArgAt(1));
-  const Instance& arg2 = Instance::CheckedHandle(arguments.ArgAt(2));
-  const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(3));
-  GrowableArray<const Instance*> args(3);
-  args.Add(&receiver);
-  args.Add(&arg1);
-  args.Add(&arg2);
-  const Function& result =
-      Function::Handle(InlineCacheMissHandler(args, ic_data));
-  arguments.SetReturn(result);
-}
-
-
 // Handles a static call in unoptimized code that has one argument type not
 // seen before. Compile the target if necessary and update the ICData.
 // Arg0: argument.
@@ -1971,7 +1949,7 @@
     }
     const ExceptionHandlers& handlers =
         ExceptionHandlers::Handle(zone, optimized_code.exception_handlers());
-    RawExceptionHandlers::HandlerInfo info;
+    ExceptionHandlerInfo info;
     for (intptr_t i = 0; i < handlers.num_entries(); ++i) {
       handlers.GetHandlerInfo(i, &info);
       const uword patch_pc = instrs.PayloadStart() + info.handler_pc_offset;
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index fee4b89..fae6a67 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -549,28 +549,6 @@
     function.set_usage_counter(INT_MIN);
   }
 
-  const Array& intervals = graph_compiler->inlined_code_intervals();
-  INC_STAT(thread(), total_code_size, intervals.Length() * sizeof(uword));
-  code.SetInlinedIntervals(intervals);
-
-  const Array& inlined_id_array =
-      Array::Handle(zone, graph_compiler->InliningIdToFunction());
-  INC_STAT(thread(), total_code_size,
-           inlined_id_array.Length() * sizeof(uword));
-  code.SetInlinedIdToFunction(inlined_id_array);
-
-  const Array& caller_inlining_id_map_array =
-      Array::Handle(zone, graph_compiler->CallerInliningIdMap());
-  INC_STAT(thread(), total_code_size,
-           caller_inlining_id_map_array.Length() * sizeof(uword));
-  code.SetInlinedCallerIdMap(caller_inlining_id_map_array);
-
-  const Array& inlined_id_to_token_pos =
-      Array::Handle(zone, graph_compiler->InliningIdToTokenPos());
-  INC_STAT(thread(), total_code_size,
-           inlined_id_to_token_pos.Length() * sizeof(uword));
-  code.SetInlinedIdToTokenPos(inlined_id_to_token_pos);
-
   graph_compiler->FinalizePcDescriptors(code);
   code.set_deopt_info_array(deopt_info_array);
 
@@ -578,17 +556,7 @@
   graph_compiler->FinalizeVarDescriptors(code);
   graph_compiler->FinalizeExceptionHandlers(code);
   graph_compiler->FinalizeStaticCallTargetsTable(code);
-
-#if !defined(PRODUCT)
-  // Set the code source map after setting the inlined information because
-  // we use the inlined information when printing.
-  const CodeSourceMap& code_source_map = CodeSourceMap::Handle(
-      zone, graph_compiler->code_source_map_builder()->Finalize());
-  code.set_code_source_map(code_source_map);
-  if (FLAG_print_code_source_map) {
-    CodeSourceMap::Dump(code_source_map, code, function);
-  }
-#endif  // !defined(PRODUCT)
+  graph_compiler->FinalizeCodeSourceMap(code);
 
   if (optimized()) {
     bool code_was_installed = false;
@@ -1203,26 +1171,6 @@
 }
 
 
-#if defined(DEBUG)
-// Verifies that the inliner is always in the list of inlined functions.
-// If this fails run with --trace-inlining-intervals to get more information.
-static void CheckInliningIntervals(const Function& function) {
-  const Code& code = Code::Handle(function.CurrentCode());
-  const Array& intervals = Array::Handle(code.GetInlinedIntervals());
-  if (intervals.IsNull() || (intervals.Length() == 0)) return;
-  Smi& start = Smi::Handle();
-  GrowableArray<Function*> inlined_functions;
-  for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) {
-    start ^= intervals.At(i + Code::kInlIntStart);
-    ASSERT(!start.IsNull());
-    if (start.IsNull()) continue;
-    code.GetInlinedFunctionsAt(start.Value(), &inlined_functions);
-    ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() ==
-           function.raw());
-  }
-}
-#endif  // defined(DEBUG)
-
 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
                                        const Function& function,
                                        bool optimized,
@@ -1361,7 +1309,6 @@
       Disassembler::DisassembleCode(function, true);
     }
 
-    DEBUG_ONLY(CheckInliningIntervals(function));
     return Error::null();
   } else {
     Thread* const thread = Thread::Current();
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index 6e44b6c..8f3c111 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -15,7 +15,7 @@
 
 namespace dart {
 
-VM_TEST_CASE(CompileScript) {
+ISOLATE_UNIT_TEST_CASE(CompileScript) {
   const char* kScriptChars =
       "class A {\n"
       "  static foo() { return 42; }\n"
@@ -29,7 +29,7 @@
 }
 
 
-VM_TEST_CASE(CompileFunction) {
+ISOLATE_UNIT_TEST_CASE(CompileFunction) {
   const char* kScriptChars =
       "class A {\n"
       "  static foo() { return 42; }\n"
@@ -69,7 +69,7 @@
 }
 
 
-VM_TEST_CASE(CompileFunctionOnHelperThread) {
+ISOLATE_UNIT_TEST_CASE(CompileFunctionOnHelperThread) {
   // Create a simple function and compile it without optimization.
   const char* kScriptChars =
       "class A {\n"
@@ -184,7 +184,7 @@
 }
 
 
-VM_TEST_CASE(EvalExpressionWithLazyCompile) {
+ISOLATE_UNIT_TEST_CASE(EvalExpressionWithLazyCompile) {
   Library& lib = Library::Handle(Library::CoreLibrary());
 
   const String& expression = String::Handle(
@@ -199,7 +199,7 @@
 }
 
 
-VM_TEST_CASE(EvalExpressionExhaustCIDs) {
+ISOLATE_UNIT_TEST_CASE(EvalExpressionExhaustCIDs) {
   Library& lib = Library::Handle(Library::CoreLibrary());
 
   const String& expression = String::Handle(String::New("3 + 4"));
diff --git a/runtime/vm/cpu_test.cc b/runtime/vm/cpu_test.cc
index 3b13c0f..1adb748 100644
--- a/runtime/vm/cpu_test.cc
+++ b/runtime/vm/cpu_test.cc
@@ -9,7 +9,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(Id) {
+VM_UNIT_TEST_CASE(Id) {
 #if defined(TARGET_ARCH_IA32)
   EXPECT_STREQ("ia32", CPU::Id());
 #elif defined(TARGET_ARCH_X64)
diff --git a/runtime/vm/cpuinfo_test.cc b/runtime/vm/cpuinfo_test.cc
index 0b6113b..2d8434e 100644
--- a/runtime/vm/cpuinfo_test.cc
+++ b/runtime/vm/cpuinfo_test.cc
@@ -9,7 +9,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(GetCpuModelTest) {
+VM_UNIT_TEST_CASE(GetCpuModelTest) {
   const char* cpumodel = CpuInfo::GetCpuModel();
   EXPECT_NE(strlen(cpumodel), 0UL);
   // caller is responsible for deleting the returned cpumodel string.
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index cf4c8fa..188e6b8 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -315,7 +315,7 @@
 }
 
 
-UNIT_TEST_CASE(CustomIsolates) {
+VM_UNIT_TEST_CASE(CustomIsolates) {
   bool saved_flag = FLAG_trace_shutdown;
   FLAG_trace_shutdown = true;
   FLAG_verify_handles = true;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index c72d431..07cdcdc 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -17,6 +17,7 @@
 #include "vm/heap.h"
 #include "vm/isolate.h"
 #include "vm/kernel_isolate.h"
+#include "vm/malloc_hooks.h"
 #include "vm/message_handler.h"
 #include "vm/metrics.h"
 #include "vm/object.h"
@@ -91,7 +92,7 @@
   // (compiler) and arm (runtime) to agree.
   CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
   CHECK_OFFSET(Thread::stack_limit_offset(), 4);
-  CHECK_OFFSET(Thread::object_null_offset(), 36);
+  CHECK_OFFSET(Thread::object_null_offset(), 40);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 14);
   CHECK_OFFSET(Isolate::object_store_offset(), 28);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 120));
@@ -101,7 +102,7 @@
   // (compiler) and mips (runtime) to agree.
   CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
   CHECK_OFFSET(Thread::stack_limit_offset(), 4);
-  CHECK_OFFSET(Thread::object_null_offset(), 36);
+  CHECK_OFFSET(Thread::object_null_offset(), 40);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 14);
   CHECK_OFFSET(Isolate::object_store_offset(), 28);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 120));
@@ -111,7 +112,7 @@
   // (compiler) and arm64 (runtime) to agree.
   CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
   CHECK_OFFSET(Thread::stack_limit_offset(), 8);
-  CHECK_OFFSET(Thread::object_null_offset(), 72);
+  CHECK_OFFSET(Thread::object_null_offset(), 80);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 28);
   CHECK_OFFSET(Isolate::object_store_offset(), 56);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 208));
@@ -151,6 +152,7 @@
   start_time_micros_ = OS::GetCurrentMonotonicMicros();
   VirtualMemory::InitOnce();
   OSThread::InitOnce();
+  MallocHooks::InitOnce();
   if (FLAG_support_timeline) {
     Timeline::InitOnce();
   }
@@ -477,7 +479,7 @@
   if (FLAG_trace_shutdown) {
     OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done\n", UptimeMillis());
   }
-
+  MallocHooks::TearDown();
   return NULL;
 }
 
@@ -608,15 +610,18 @@
     I->class_table()->Print();
   }
 
+  bool is_kernel_isolate = false;
 #ifndef DART_PRECOMPILED_RUNTIME
   KernelIsolate::InitCallback(I);
+  is_kernel_isolate = KernelIsolate::IsKernelIsolate(I);
 #endif
   ServiceIsolate::MaybeMakeServiceIsolate(I);
-  if (!ServiceIsolate::IsServiceIsolate(I)) {
+  if (!ServiceIsolate::IsServiceIsolate(I) && !is_kernel_isolate) {
     I->message_handler()->set_should_pause_on_start(
         FLAG_pause_isolates_on_start);
     I->message_handler()->set_should_pause_on_exit(FLAG_pause_isolates_on_exit);
   }
+
   ServiceIsolate::SendIsolateStartupMessage();
   if (FLAG_support_debugger) {
     I->debugger()->NotifyIsolateCreated();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 2b4b954..71cef9f 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -536,11 +536,13 @@
 
 bool Api::IsValid(Dart_Handle handle) {
   Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  ASSERT(thread->IsMutatorThread());
   CHECK_ISOLATE(isolate);
 
   // Check against all of the handles in the current isolate as well as the
   // read-only handles.
-  return isolate->thread_registry()->IsValidHandle(handle) ||
+  return thread->IsValidHandle(handle) ||
          isolate->api_state()->IsActivePersistentHandle(
              reinterpret_cast<Dart_PersistentHandle>(handle)) ||
          isolate->api_state()->IsActiveWeakPersistentHandle(
@@ -5112,6 +5114,11 @@
     if (Symbols::DartIsVM().Equals(name)) {
       return Symbols::True().raw();
     }
+    if (FLAG_causal_async_stacks) {
+      if (Symbols::DartDeveloperCausalAsyncStacks().Equals(name)) {
+        return Symbols::True().raw();
+      }
+    }
   }
   return result.raw();
 }
@@ -5408,7 +5415,6 @@
     return Api::NewHandle(T, tmp.raw());
   }
   library ^= tmp.raw();
-  library.set_debuggable(false);
   I->object_store()->set_root_library(library);
   return Api::NewHandle(T, library.raw());
 #endif
@@ -6013,14 +6019,6 @@
 }
 
 
-DART_EXPORT Dart_Port Dart_ServiceWaitForKernelPort() {
-#ifdef DART_PRECOMPILED_RUNTIME
-  return ILLEGAL_PORT;
-#else
-  return KernelIsolate::WaitForKernelPort();
-#endif
-}
-
 DART_EXPORT Dart_Port Dart_KernelPort() {
 #ifdef DART_PRECOMPILED_RUNTIME
   return false;
@@ -6030,6 +6028,18 @@
 }
 
 
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernel(const char* script_uri) {
+#ifdef DART_PRECOMPILED_RUNTIME
+  Dart_KernelCompilationResult result;
+  result.status = Dart_KernelCompilationStatus_Unknown;
+  result.error = strdup("Dart_CompileToKernel is unsupported.");
+  return result;
+#else
+  return KernelIsolate::CompileToKernel(script_uri);
+#endif
+}
+
 // --- Service support ---
 
 DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index eb84645..c17c4d2 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -2486,7 +2486,7 @@
 
 // Unit test for entering a scope, creating a local handle and exiting
 // the scope.
-UNIT_TEST_CASE(EnterExitScope) {
+VM_UNIT_TEST_CASE(EnterExitScope) {
   TestIsolateScope __test_isolate__;
 
   Thread* thread = Thread::Current();
@@ -2508,7 +2508,7 @@
 
 
 // Unit test for creating and deleting persistent handles.
-UNIT_TEST_CASE(PersistentHandles) {
+VM_UNIT_TEST_CASE(PersistentHandles) {
   const char* kTestString1 = "Test String1";
   const char* kTestString2 = "Test String2";
   TestCase::CreateTestIsolate();
@@ -2577,7 +2577,7 @@
 
 // Test that we are able to create a persistent handle from a
 // persistent handle.
-UNIT_TEST_CASE(NewPersistentHandle_FromPersistentHandle) {
+VM_UNIT_TEST_CASE(NewPersistentHandle_FromPersistentHandle) {
   TestIsolateScope __test_isolate__;
 
   Isolate* isolate = Isolate::Current();
@@ -2608,7 +2608,7 @@
 
 
 // Test that we can assign to a persistent handle.
-UNIT_TEST_CASE(AssignToPersistentHandle) {
+VM_UNIT_TEST_CASE(AssignToPersistentHandle) {
   const char* kTestString1 = "Test String1";
   const char* kTestString2 = "Test String2";
   TestIsolateScope __test_isolate__;
@@ -2866,7 +2866,7 @@
 }
 
 
-UNIT_TEST_CASE(WeakPersistentHandlesCallbackShutdown) {
+VM_UNIT_TEST_CASE(WeakPersistentHandlesCallbackShutdown) {
   TestCase::CreateTestIsolate();
   Dart_EnterScope();
   Dart_Handle ref = Dart_True();
@@ -3363,7 +3363,7 @@
 // Unit test for creating multiple scopes and local handles within them.
 // Ensure that the local handles get all cleaned out when exiting the
 // scope.
-UNIT_TEST_CASE(LocalHandles) {
+VM_UNIT_TEST_CASE(LocalHandles) {
   TestCase::CreateTestIsolate();
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
@@ -3427,7 +3427,7 @@
 // Unit test for creating multiple scopes and allocating objects in the
 // zone for the scope. Ensure that the memory is freed when the scope
 // exits.
-UNIT_TEST_CASE(LocalZoneMemory) {
+VM_UNIT_TEST_CASE(LocalZoneMemory) {
   TestCase::CreateTestIsolate();
   Thread* thread = Thread::Current();
   EXPECT(thread != NULL);
@@ -3469,7 +3469,7 @@
 }
 
 
-UNIT_TEST_CASE(Isolates) {
+VM_UNIT_TEST_CASE(Isolates) {
   // This test currently assumes that the Dart_Isolate type is an opaque
   // representation of Isolate*.
   Dart_Isolate iso_1 = TestCase::CreateTestIsolate();
@@ -3493,7 +3493,7 @@
 }
 
 
-UNIT_TEST_CASE(CurrentIsolateData) {
+VM_UNIT_TEST_CASE(CurrentIsolateData) {
   intptr_t mydata = 12345;
   char* err;
   Dart_Isolate isolate =
@@ -3507,7 +3507,7 @@
 }
 
 
-UNIT_TEST_CASE(IsolateSetCheckedMode) {
+VM_UNIT_TEST_CASE(IsolateSetCheckedMode) {
   const char* kScriptChars =
       "int bad1() {\n"
       "  int foo = 'string';\n"
@@ -3574,7 +3574,7 @@
 static void MyMessageNotifyCallback(Dart_Isolate dest_isolate) {}
 
 
-UNIT_TEST_CASE(SetMessageCallbacks) {
+VM_UNIT_TEST_CASE(SetMessageCallbacks) {
   Dart_Isolate dart_isolate = TestCase::CreateTestIsolate();
   Dart_SetMessageNotifyCallback(&MyMessageNotifyCallback);
   Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate);
@@ -7196,7 +7196,7 @@
 }
 
 
-UNIT_TEST_CASE(NewNativePort) {
+VM_UNIT_TEST_CASE(NewNativePort) {
   // Create a port with a bogus handler.
   Dart_Port error_port = Dart_NewNativePort("Foo", NULL, true);
   EXPECT_EQ(ILLEGAL_PORT, error_port);
@@ -7518,12 +7518,12 @@
 }
 
 
-UNIT_TEST_CASE(RunLoop_Success) {
+VM_UNIT_TEST_CASE(RunLoop_Success) {
   RunLoopTest(false);
 }
 
 
-UNIT_TEST_CASE(RunLoop_Exception) {
+VM_UNIT_TEST_CASE(RunLoop_Exception) {
   RunLoopTest(true);
 }
 
@@ -7616,7 +7616,7 @@
   saved_callback_data = callback_data;
 }
 
-UNIT_TEST_CASE(IsolateShutdown) {
+VM_UNIT_TEST_CASE(IsolateShutdown) {
   Dart_IsolateShutdownCallback saved = Isolate::ShutdownCallback();
   Isolate::SetShutdownCallback(IsolateShutdownTestCallback);
 
@@ -7664,7 +7664,7 @@
   Dart_ExitScope();
 }
 
-UNIT_TEST_CASE(IsolateShutdownRunDartCode) {
+VM_UNIT_TEST_CASE(IsolateShutdownRunDartCode) {
   const char* kScriptChars =
       "int add(int a, int b) {\n"
       "  return a + b;\n"
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 4d3687f3..60985b1 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -1284,6 +1284,14 @@
       WriteRawPointerValue(reinterpret_cast<intptr_t>(callback));
       break;
     }
+    case Dart_CObject_kSendPort: {
+      WriteInlinedHeader(object);
+      WriteIndexedObject(kSendPortCid);
+      WriteTags(0);
+      Write<int64_t>(object->value.as_send_port.id);
+      Write<uint64_t>(object->value.as_send_port.origin_id);
+      break;
+    }
     case Dart_CObject_kCapability: {
       WriteInlinedHeader(object);
       WriteIndexedObject(kCapabilityCid);
@@ -1292,7 +1300,7 @@
       break;
     }
     default:
-      UNREACHABLE();
+      FATAL1("Unexpected Dart_CObject_Type %d\n", type);
   }
 
   return true;
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 19a33c4..3e9a6c0 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -92,12 +92,12 @@
     return (end_ - current_);
   }
 
- private:
   template <typename T>
   T Read() {
     return Read<T>(kEndByteMarker);
   }
 
+ private:
   int16_t Read16() { return Read16(kEndByteMarker); }
 
   int32_t Read32() { return Read32(kEndByteMarker); }
@@ -390,7 +390,6 @@
     VPrint(format, args);
   }
 
- private:
   template <typename T>
   void Write(T value) {
     T v = value;
@@ -401,6 +400,7 @@
     WriteByte(static_cast<uint8_t>(v + kEndByteMarker));
   }
 
+ private:
   DART_FORCE_INLINE void WriteByte(uint8_t value) {
     if (current_ >= end_) {
       Resize(1);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 3dce573..0c0edcc 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -26,6 +26,7 @@
 #include "vm/service_isolate.h"
 #include "vm/service.h"
 #include "vm/stack_frame.h"
+#include "vm/stack_trace.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
 #include "vm/thread_interrupter.h"
@@ -195,7 +196,8 @@
 
 
 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) {
-  ASSERT(bpt_location_->IsLatent());  // Only reason to move.
+  // Only latent breakpoints can be moved.
+  ASSERT((new_bpt_location == NULL) || bpt_location_->IsLatent());
   bpt_location_ = new_bpt_location;
 }
 
@@ -249,13 +251,15 @@
                                  uword sp,
                                  const Code& code,
                                  const Array& deopt_frame,
-                                 intptr_t deopt_frame_offset)
+                                 intptr_t deopt_frame_offset,
+                                 ActivationFrame::Kind kind)
     : pc_(pc),
       fp_(fp),
       sp_(sp),
       ctx_(Context::ZoneHandle()),
       code_(Code::ZoneHandle(code.raw())),
       function_(Function::ZoneHandle(code.function())),
+      live_frame_(kind == kRegular),
       token_pos_initialized_(false),
       token_pos_(TokenPosition::kNoSource),
       try_index_(-1),
@@ -264,12 +268,35 @@
       context_level_(-1),
       deopt_frame_(Array::ZoneHandle(deopt_frame.raw())),
       deopt_frame_offset_(deopt_frame_offset),
+      kind_(kind),
       vars_initialized_(false),
       var_descriptors_(LocalVarDescriptors::ZoneHandle()),
       desc_indices_(8),
       pc_desc_(PcDescriptors::ZoneHandle()) {}
 
 
+ActivationFrame::ActivationFrame(Kind kind)
+    : pc_(0),
+      fp_(0),
+      sp_(0),
+      ctx_(Context::ZoneHandle()),
+      code_(Code::ZoneHandle()),
+      function_(Function::ZoneHandle()),
+      live_frame_(kind == kRegular),
+      token_pos_initialized_(false),
+      token_pos_(TokenPosition::kNoSource),
+      try_index_(-1),
+      line_number_(-1),
+      column_number_(-1),
+      context_level_(-1),
+      deopt_frame_(Array::ZoneHandle()),
+      deopt_frame_offset_(0),
+      kind_(kind),
+      vars_initialized_(false),
+      var_descriptors_(LocalVarDescriptors::ZoneHandle()),
+      desc_indices_(8),
+      pc_desc_(PcDescriptors::ZoneHandle()) {}
+
 bool Debugger::NeedsIsolateEvents() {
   return ((isolate_ != Dart::vm_isolate()) &&
           !ServiceIsolate::IsServiceIsolateDescendant(isolate_) &&
@@ -318,12 +345,11 @@
   if (trace->Length() > 0) {
     event.set_top_frame(trace->FrameAt(0));
   }
-  ASSERT(stack_trace_ == NULL);
-  stack_trace_ = trace;
+  CacheStackTraces(trace, CollectAsyncCausalStackTrace());
   resume_action_ = kContinue;
   Pause(&event);
   HandleSteppingRequest(trace);
-  stack_trace_ = NULL;
+  ClearCachedStackTraces();
 
   // If any error occurred while in the debug message loop, return it here.
   const Error& error = Error::Handle(Thread::Current()->sticky_error());
@@ -740,7 +766,7 @@
   GetVarDescriptors();
 
   TokenPosition activation_token_pos = TokenPos();
-  if (!activation_token_pos.IsDebugPause()) {
+  if (!activation_token_pos.IsDebugPause() || !live_frame_) {
     // We don't have a token position for this frame, so can't determine
     // which variables are visible.
     vars_initialized_ = true;
@@ -1086,8 +1112,22 @@
 
 
 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) {
+  if (kind_ == kRegular) {
+    PrintToJSONObjectRegular(jsobj, full);
+  } else if (kind_ == kAsyncCausal) {
+    PrintToJSONObjectAsyncCausal(jsobj, full);
+  } else if (kind_ == kAsyncSuspensionMarker) {
+    PrintToJSONObjectAsyncSuspensionMarker(jsobj, full);
+  } else {
+    UNIMPLEMENTED();
+  }
+}
+
+
+void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj, bool full) {
   const Script& script = Script::Handle(SourceScript());
   jsobj->AddProperty("type", "Frame");
+  jsobj->AddProperty("kind", KindToCString(kind_));
   TokenPosition pos = TokenPos();
   if (pos.IsSynthetic()) {
     pos = pos.FromSynthetic();
@@ -1129,6 +1169,36 @@
   }
 }
 
+
+void ActivationFrame::PrintToJSONObjectAsyncCausal(JSONObject* jsobj,
+                                                   bool full) {
+  jsobj->AddProperty("type", "Frame");
+  jsobj->AddProperty("kind", KindToCString(kind_));
+  const Script& script = Script::Handle(SourceScript());
+  TokenPosition pos = TokenPos();
+  if (pos.IsSynthetic()) {
+    pos = pos.FromSynthetic();
+  }
+  jsobj->AddLocation(script, pos);
+  jsobj->AddProperty("function", function(), !full);
+  jsobj->AddProperty("code", code());
+  if (full) {
+    // TODO(cutch): The old "full" script usage no longer fits
+    // in the world where we pass the script as part of the
+    // location.
+    jsobj->AddProperty("script", script, !full);
+  }
+}
+
+
+void ActivationFrame::PrintToJSONObjectAsyncSuspensionMarker(JSONObject* jsobj,
+                                                             bool full) {
+  jsobj->AddProperty("type", "Frame");
+  jsobj->AddProperty("kind", KindToCString(kind_));
+  jsobj->AddProperty("marker", "AsynchronousSuspension");
+}
+
+
 static bool IsFunctionVisible(const Function& function) {
   return FLAG_show_invisible_frames || function.is_visible();
 }
@@ -1141,6 +1211,19 @@
 }
 
 
+void DebuggerStackTrace::AddMarker(ActivationFrame::Kind marker) {
+  ASSERT((marker >= ActivationFrame::kAsyncSuspensionMarker) &&
+         (marker <= ActivationFrame::kAsyncSuspensionMarker));
+  trace_.Add(new ActivationFrame(marker));
+}
+
+
+void DebuggerStackTrace::AddAsyncCausalFrame(uword pc, const Code& code) {
+  trace_.Add(new ActivationFrame(pc, 0, 0, code, Array::Handle(), 0,
+                                 ActivationFrame::kAsyncCausal));
+}
+
+
 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall |
                                RawPcDescriptors::kUnoptStaticCall |
                                RawPcDescriptors::kRuntimeCall;
@@ -1268,8 +1351,10 @@
       pause_event_(NULL),
       obj_cache_(NULL),
       stack_trace_(NULL),
+      async_causal_stack_trace_(NULL),
       stepping_fp_(0),
       skip_next_step_(false),
+      needs_breakpoint_cleanup_(false),
       synthetic_async_breakpoint_(NULL),
       exc_pause_info_(kNoPauseOnExceptions) {}
 
@@ -1281,6 +1366,7 @@
   ASSERT(breakpoint_locations_ == NULL);
   ASSERT(code_breakpoints_ == NULL);
   ASSERT(stack_trace_ == NULL);
+  ASSERT(async_causal_stack_trace_ == NULL);
   ASSERT(obj_cache_ == NULL);
   ASSERT(synthetic_async_breakpoint_ == NULL);
 }
@@ -1519,32 +1605,128 @@
     }
     if (frame->IsDartFrame()) {
       code = frame->LookupDartCode();
-      if (code.is_optimized() && !FLAG_precompiled_runtime) {
-        deopt_frame = DeoptimizeToArray(thread, frame, code);
-        for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done();
-             it.Advance()) {
-          inlined_code = it.code();
-          if (FLAG_trace_debugger_stacktrace) {
-            const Function& function =
-                Function::Handle(zone, inlined_code.function());
-            ASSERT(!function.IsNull());
-            OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n",
-                         function.ToFullyQualifiedCString());
-          }
-          intptr_t deopt_frame_offset = it.GetDeoptFpOffset();
-          stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame,
-                                                      inlined_code, deopt_frame,
-                                                      deopt_frame_offset));
-        }
-      } else {
-        stack_trace->AddActivation(CollectDartFrame(
-            isolate, frame->pc(), frame, code, Object::null_array(), 0));
-      }
+      AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code,
+                       &inlined_code, &deopt_frame);
     }
   }
   return stack_trace;
 }
 
+void Debugger::AppendCodeFrames(Thread* thread,
+                                Isolate* isolate,
+                                Zone* zone,
+                                DebuggerStackTrace* stack_trace,
+                                StackFrame* frame,
+                                Code* code,
+                                Code* inlined_code,
+                                Array* deopt_frame) {
+  if (code->is_optimized() && !FLAG_precompiled_runtime) {
+    // TODO(rmacnak): Use CodeSourceMap
+    *deopt_frame = DeoptimizeToArray(thread, frame, *code);
+    for (InlinedFunctionsIterator it(*code, frame->pc()); !it.Done();
+         it.Advance()) {
+      *inlined_code = it.code();
+      if (FLAG_trace_debugger_stacktrace) {
+        const Function& function =
+            Function::Handle(zone, inlined_code->function());
+        ASSERT(!function.IsNull());
+        OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n",
+                     function.ToFullyQualifiedCString());
+      }
+      intptr_t deopt_frame_offset = it.GetDeoptFpOffset();
+      stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame,
+                                                  *inlined_code, *deopt_frame,
+                                                  deopt_frame_offset));
+    }
+  } else {
+    stack_trace->AddActivation(CollectDartFrame(
+        isolate, frame->pc(), frame, *code, Object::null_array(), 0));
+  }
+}
+
+
+DebuggerStackTrace* Debugger::CollectAsyncCausalStackTrace() {
+  if (!FLAG_causal_async_stacks) {
+    return NULL;
+  }
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Isolate* isolate = thread->isolate();
+  DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
+
+  Code& code = Code::Handle(zone);
+  Smi& offset = Smi::Handle();
+  Code& inlined_code = Code::Handle(zone);
+  Array& deopt_frame = Array::Handle(zone);
+
+  Function& async_function = Function::Handle(zone);
+  class StackTrace& async_stack_trace = StackTrace::Handle(zone);
+  Array& async_code_array = Array::Handle(zone);
+  Array& async_pc_offset_array = Array::Handle(zone);
+  StackTraceUtils::ExtractAsyncStackTraceInfo(
+      thread, &async_function, &async_stack_trace, &async_code_array,
+      &async_pc_offset_array);
+
+  if (async_function.IsNull()) {
+    return NULL;
+  }
+
+  intptr_t synchronous_stack_trace_length =
+      StackTraceUtils::CountFrames(thread, 0, async_function);
+
+  // Append the top frames from the synchronous stack trace, up until the active
+  // asynchronous function. We truncate the remainder of the synchronous
+  // stack trace because it contains activations that are part of the
+  // asynchronous dispatch mechanisms.
+  StackFrameIterator iterator(false);
+  StackFrame* frame = iterator.NextFrame();
+  while (synchronous_stack_trace_length >= 0) {
+    ASSERT(frame != NULL);
+    if (frame->IsDartFrame()) {
+      code = frame->LookupDartCode();
+      AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code,
+                       &inlined_code, &deopt_frame);
+      synchronous_stack_trace_length--;
+    }
+    frame = iterator.NextFrame();
+  }
+
+  // Now we append the asynchronous causal stack trace. These are not active
+  // frames but a historical record of how this asynchronous function was
+  // activated.
+  while (!async_stack_trace.IsNull()) {
+    for (intptr_t i = 0; i < async_stack_trace.Length(); i++) {
+      if (async_stack_trace.CodeAtFrame(i) == Code::null()) {
+        break;
+      }
+      if (async_stack_trace.CodeAtFrame(i) ==
+          StubCode::AsynchronousGapMarker_entry()->code()) {
+        stack_trace->AddMarker(ActivationFrame::kAsyncSuspensionMarker);
+        // The frame immediately below the asynchronous gap marker is the
+        // identical to the frame above the marker. Skip the frame to enhance
+        // the readability of the trace.
+        i++;
+      } else {
+        code = Code::RawCast(async_stack_trace.CodeAtFrame(i));
+        offset = Smi::RawCast(async_stack_trace.PcOffsetAtFrame(i));
+        uword pc = code.PayloadStart() + offset.Value();
+        if (code.is_optimized()) {
+          for (InlinedFunctionsIterator it(code, pc); !it.Done();
+               it.Advance()) {
+            inlined_code = it.code();
+            stack_trace->AddAsyncCausalFrame(pc, inlined_code);
+          }
+        } else {
+          stack_trace->AddAsyncCausalFrame(pc, code);
+        }
+      }
+    }
+    // Follow the link.
+    async_stack_trace = async_stack_trace.async_link();
+  }
+
+  return stack_trace;
+}
 
 ActivationFrame* Debugger::TopDartFrame() const {
   StackFrameIterator iterator(false);
@@ -1563,10 +1745,23 @@
   return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace();
 }
 
+
 DebuggerStackTrace* Debugger::CurrentStackTrace() {
   return CollectStackTrace();
 }
 
+
+DebuggerStackTrace* Debugger::AsyncCausalStackTrace() {
+  return (async_causal_stack_trace_ != NULL) ? async_causal_stack_trace_
+                                             : CollectAsyncCausalStackTrace();
+}
+
+
+DebuggerStackTrace* Debugger::CurrentAsyncCausalStackTrace() {
+  return CollectAsyncCausalStackTrace();
+}
+
+
 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) {
   DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
   Function& function = Function::Handle();
@@ -1578,35 +1773,41 @@
   const intptr_t deopt_frame_offset = -1;
 
   for (intptr_t i = 0; i < ex_trace.Length(); i++) {
-    function = ex_trace.FunctionAtFrame(i);
+    code = ex_trace.CodeAtFrame(i);
     // Pre-allocated StackTraces may include empty slots, either (a) to indicate
     // where frames were omitted in the case a stack has more frames than the
     // pre-allocated trace (such as a stack overflow) or (b) because a stack has
     // fewer frames that the pre-allocated trace (such as memory exhaustion with
     // a shallow stack).
-    if (!function.IsNull() && function.is_visible()) {
-      code = ex_trace.CodeAtFrame(i);
-      ASSERT(function.raw() == code.function());
-      uword pc = code.PayloadStart() + Smi::Value(ex_trace.PcOffsetAtFrame(i));
-      if (code.is_optimized() && ex_trace.expand_inlined()) {
-        // Traverse inlined frames.
-        for (InlinedFunctionsIterator it(code, pc); !it.Done(); it.Advance()) {
-          function = it.function();
-          code = it.code();
-          ASSERT(function.raw() == code.function());
-          uword pc = it.pc();
-          ASSERT(pc != 0);
-          ASSERT(code.PayloadStart() <= pc);
-          ASSERT(pc < (code.PayloadStart() + code.Size()));
+    if (!code.IsNull()) {
+      ASSERT(code.IsFunctionCode());
+      function = code.function();
+      if (function.is_visible()) {
+        code = ex_trace.CodeAtFrame(i);
+        ASSERT(function.raw() == code.function());
+        uword pc =
+            code.PayloadStart() + Smi::Value(ex_trace.PcOffsetAtFrame(i));
+        if (code.is_optimized() && ex_trace.expand_inlined()) {
+          // Traverse inlined frames.
+          for (InlinedFunctionsIterator it(code, pc); !it.Done();
+               it.Advance()) {
+            function = it.function();
+            code = it.code();
+            ASSERT(function.raw() == code.function());
+            uword pc = it.pc();
+            ASSERT(pc != 0);
+            ASSERT(code.PayloadStart() <= pc);
+            ASSERT(pc < (code.PayloadStart() + code.Size()));
 
+            ActivationFrame* activation = new ActivationFrame(
+                pc, fp, sp, code, deopt_frame, deopt_frame_offset);
+            stack_trace->AddActivation(activation);
+          }
+        } else {
           ActivationFrame* activation = new ActivationFrame(
               pc, fp, sp, code, deopt_frame, deopt_frame_offset);
           stack_trace->AddActivation(activation);
         }
-      } else {
-        ActivationFrame* activation = new ActivationFrame(
-            pc, fp, sp, code, deopt_frame, deopt_frame_offset);
-        stack_trace->AddActivation(activation);
       }
     }
   }
@@ -1667,11 +1868,10 @@
   if (stack_trace->Length() > 0) {
     event.set_top_frame(stack_trace->FrameAt(0));
   }
-  ASSERT(stack_trace_ == NULL);
-  stack_trace_ = stack_trace;
+  CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace());
   Pause(&event);
   HandleSteppingRequest(stack_trace_);  // we may get a rewind request
-  stack_trace_ = NULL;
+  ClearCachedStackTraces();
 }
 
 
@@ -2598,6 +2798,9 @@
     }
   }
 
+  if (needs_breakpoint_cleanup_) {
+    RemoveUnlinkedCodeBreakpoints();
+  }
   pause_event_ = NULL;
   obj_cache_ = NULL;  // Zone allocated
 }
@@ -2668,6 +2871,21 @@
 }
 
 
+void Debugger::CacheStackTraces(DebuggerStackTrace* stack_trace,
+                                DebuggerStackTrace* async_causal_stack_trace) {
+  ASSERT(stack_trace_ == NULL);
+  stack_trace_ = stack_trace;
+  ASSERT(async_causal_stack_trace_ == NULL);
+  async_causal_stack_trace_ = async_causal_stack_trace;
+}
+
+
+void Debugger::ClearCachedStackTraces() {
+  stack_trace_ = NULL;
+  async_causal_stack_trace_ = NULL;
+}
+
+
 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack,
                                          intptr_t frame_index) {
   for (intptr_t i = frame_index + 1; i < stack->Length(); i++) {
@@ -2796,7 +3014,7 @@
 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) {
   // We will be jumping out of the debugger rather than exiting this
   // function, so prepare the debugger state.
-  stack_trace_ = NULL;
+  ClearCachedStackTraces();
   resume_action_ = kContinue;
   resume_frame_index_ = -1;
   EnterSingleStepMode();
@@ -2828,7 +3046,7 @@
 
   // We will be jumping out of the debugger rather than exiting this
   // function, so prepare the debugger state.
-  stack_trace_ = NULL;
+  ClearCachedStackTraces();
   resume_action_ = kContinue;
   resume_frame_index_ = -1;
   EnterSingleStepMode();
@@ -2929,6 +3147,14 @@
     ASSERT(Instance::Cast(closure_or_null).IsClosure());
     const Script& script = Script::Handle(zone, top_frame->SourceScript());
     if (script.kind() == RawScript::kKernelTag) {
+      // Are we at a yield point (previous await)?
+      const Array& yields = Array::Handle(script.yield_positions());
+      intptr_t looking_for = top_frame->TokenPos().value();
+      Smi& value = Smi::Handle(zone);
+      for (int i = 0; i < yields.Length(); i++) {
+        value ^= yields.At(i);
+        if (value.Value() == looking_for) return true;
+      }
       return false;
     }
     const TokenStream& tokens = TokenStream::Handle(zone, script.tokens());
@@ -2996,8 +3222,8 @@
               frame->TokenPos().ToCString());
   }
 
-  ASSERT(stack_trace_ == NULL);
-  stack_trace_ = CollectStackTrace();
+
+  CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace());
   // If this step callback is part of stepping over an await statement,
   // we saved the synthetic async breakpoint in PauseBreakpoint. We report
   // that we are paused at that breakpoint and then delete it after continuing.
@@ -3007,7 +3233,7 @@
     synthetic_async_breakpoint_ = NULL;
   }
   HandleSteppingRequest(stack_trace_);
-  stack_trace_ = NULL;
+  ClearCachedStackTraces();
 
   // If any error occurred while in the debug message loop, return it here.
   const Error& error = Error::Handle(Thread::Current()->sticky_error());
@@ -3030,50 +3256,7 @@
   CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc());
   ASSERT(cbpt != NULL);
 
-  BreakpointLocation* bpt_location = cbpt->bpt_location_;
-  Breakpoint* bpt_hit = NULL;
-
-  // There may be more than one applicable breakpoint at this location, but we
-  // will report only one as reached. If there is a single-shot breakpoint, we
-  // favor it; then a closure-specific breakpoint ; then an general breakpoint.
-  if (bpt_location != NULL) {
-    Breakpoint* bpt = bpt_location->breakpoints();
-    while (bpt != NULL) {
-      if (bpt->IsSingleShot()) {
-        bpt_hit = bpt;
-        break;
-      }
-      bpt = bpt->next();
-    }
-
-    if (bpt_hit == NULL) {
-      bpt = bpt_location->breakpoints();
-      while (bpt != NULL) {
-        if (bpt->IsPerClosure()) {
-          Object& closure = Object::Handle(top_frame->GetClosure());
-          ASSERT(closure.IsInstance());
-          ASSERT(Instance::Cast(closure).IsClosure());
-          if (closure.raw() == bpt->closure()) {
-            bpt_hit = bpt;
-            break;
-          }
-        }
-        bpt = bpt->next();
-      }
-    }
-
-    if (bpt_hit == NULL) {
-      bpt = bpt_location->breakpoints();
-      while (bpt != NULL) {
-        if (bpt->IsRepeated()) {
-          bpt_hit = bpt;
-          break;
-        }
-        bpt = bpt->next();
-      }
-    }
-  }
-
+  Breakpoint* bpt_hit = FindHitBreakpoint(cbpt->bpt_location_, top_frame);
   if (bpt_hit == NULL) {
     return Error::null();
   }
@@ -3081,8 +3264,7 @@
   if (bpt_hit->is_synthetic_async()) {
     DebuggerStackTrace* stack_trace = CollectStackTrace();
     ASSERT(stack_trace->Length() > 0);
-    ASSERT(stack_trace_ == NULL);
-    stack_trace_ = stack_trace;
+    CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace());
 
     // Hit a synthetic async breakpoint.
     if (FLAG_verbose_debug) {
@@ -3104,29 +3286,23 @@
     // When we single step from a user breakpoint, our next stepping
     // point will be at the exact same pc.  Skip it.
     HandleSteppingRequest(stack_trace_, true /* skip next step */);
-    stack_trace_ = NULL;
+    ClearCachedStackTraces();
     return Error::null();
   }
 
   if (FLAG_verbose_debug) {
-    OS::Print(">>> hit %s breakpoint at %s:%" Pd
-              " "
-              "(token %s) (address %#" Px ")\n",
-              cbpt->IsInternal() ? "internal" : "user",
+    OS::Print(">>> hit breakpoint at %s:%" Pd " (token %s) (address %#" Px
+              ")\n",
               String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(),
               cbpt->token_pos().ToCString(), top_frame->pc());
   }
 
-  ASSERT(stack_trace_ == NULL);
-  stack_trace_ = stack_trace;
+  CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace());
   SignalPausedEvent(top_frame, bpt_hit);
   // When we single step from a user breakpoint, our next stepping
   // point will be at the exact same pc.  Skip it.
   HandleSteppingRequest(stack_trace_, true /* skip next step */);
-  stack_trace_ = NULL;
-  if (cbpt->IsInternal()) {
-    RemoveInternalBreakpoints();
-  }
+  ClearCachedStackTraces();
 
   // If any error occurred while in the debug message loop, return it here.
   const Error& error = Error::Handle(Thread::Current()->sticky_error());
@@ -3135,6 +3311,51 @@
 }
 
 
+Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location,
+                                        ActivationFrame* top_frame) {
+  if (location == NULL) {
+    return NULL;
+  }
+  // There may be more than one applicable breakpoint at this location, but we
+  // will report only one as reached. If there is a single-shot breakpoint, we
+  // favor it; then a closure-specific breakpoint ; then an general breakpoint.
+
+  // First check for a single-shot breakpoint.
+  Breakpoint* bpt = location->breakpoints();
+  while (bpt != NULL) {
+    if (bpt->IsSingleShot()) {
+      return bpt;
+    }
+    bpt = bpt->next();
+  }
+
+  // Now check for a closure-specific breakpoint.
+  bpt = location->breakpoints();
+  while (bpt != NULL) {
+    if (bpt->IsPerClosure()) {
+      Object& closure = Object::Handle(top_frame->GetClosure());
+      ASSERT(closure.IsInstance());
+      ASSERT(Instance::Cast(closure).IsClosure());
+      if (closure.raw() == bpt->closure()) {
+        return bpt;
+      }
+    }
+    bpt = bpt->next();
+  }
+
+  // Finally, check for a general breakpoint.
+  bpt = location->breakpoints();
+  while (bpt != NULL) {
+    if (bpt->IsRepeated()) {
+      return bpt;
+    }
+    bpt = bpt->next();
+  }
+
+  return NULL;
+}
+
+
 void Debugger::PauseDeveloper(const String& msg) {
   // We ignore this breakpoint when the VM is executing code invoked
   // by the debugger to evaluate variables values, or when we see a nested
@@ -3145,9 +3366,7 @@
 
   DebuggerStackTrace* stack_trace = CollectStackTrace();
   ASSERT(stack_trace->Length() > 0);
-  ASSERT(stack_trace_ == NULL);
-  stack_trace_ = stack_trace;
-
+  CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace());
   // TODO(johnmccutchan): Send |msg| to Observatory.
 
   // We are in the native call to Developer_debugger.  the developer
@@ -3155,8 +3374,7 @@
   // this, we continue execution until the call exits (step out).
   SetResumeAction(kStepOut);
   HandleSteppingRequest(stack_trace_);
-
-  stack_trace_ = NULL;
+  ClearCachedStackTraces();
 }
 
 
@@ -3461,46 +3679,58 @@
           prev_bpt->set_next(curr_bpt->next());
         }
 
+        // Send event to client before the breakpoint's fields are
+        // poisoned and deleted.
         SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
 
-        // Remove references from the current debugger pause event.
+        curr_bpt->set_next(NULL);
+        curr_bpt->set_bpt_location(NULL);
+        // Remove possible references to the breakpoint.
         if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) {
           pause_event_->set_breakpoint(NULL);
         }
-        break;
+        if (synthetic_async_breakpoint_ == curr_bpt) {
+          synthetic_async_breakpoint_ = NULL;
+        }
+        delete curr_bpt;
+        curr_bpt = NULL;
+
+        // Delete the breakpoint location object if there are no more
+        // breakpoints at that location.
+        if (curr_loc->breakpoints() == NULL) {
+          if (prev_loc == NULL) {
+            breakpoint_locations_ = curr_loc->next();
+          } else {
+            prev_loc->set_next(curr_loc->next());
+          }
+
+          // Remove references from code breakpoints to this breakpoint
+          // location and disable them.
+          UnlinkCodeBreakpoints(curr_loc);
+          BreakpointLocation* next_loc = curr_loc->next();
+          delete curr_loc;
+          curr_loc = next_loc;
+        }
+
+        // The code breakpoints will be deleted when the VM resumes
+        // after the pause event.
+        return;
       }
 
       prev_bpt = curr_bpt;
       curr_bpt = curr_bpt->next();
     }
-
-    if (curr_loc->breakpoints() == NULL) {
-      if (prev_loc == NULL) {
-        breakpoint_locations_ = curr_loc->next();
-      } else {
-        prev_loc->set_next(curr_loc->next());
-      }
-
-      // Remove references from code breakpoints to this source breakpoint,
-      // and disable the code breakpoints.
-      UnlinkCodeBreakpoints(curr_loc);
-      BreakpointLocation* next_loc = curr_loc->next();
-      delete curr_loc;
-      curr_loc = next_loc;
-    } else {
-      prev_loc = curr_loc;
-      curr_loc = curr_loc->next();
-    }
+    prev_loc = curr_loc;
+    curr_loc = curr_loc->next();
   }
-  // bpt is not a registered breakpoint, nothing to do.
+  // breakpoint with bp_id does not exist, nothing to do.
 }
 
 
-// Turn code breakpoints associated with the given source breakpoint into
-// internal breakpoints. They will later be deleted when control
-// returns from the user-defined breakpoint callback. Also, disable the
-// breakpoint so it no longer fires if it should be hit before it gets
-// deleted.
+// Unlink code breakpoints from the the given breakpoint location.
+// They will later be deleted when control returns from the pause event
+// callback. Also, disable the breakpoint so it no longer fires if it
+// should be hit before it gets deleted.
 void Debugger::UnlinkCodeBreakpoints(BreakpointLocation* bpt_location) {
   ASSERT(bpt_location != NULL);
   CodeBreakpoint* curr_bpt = code_breakpoints_;
@@ -3508,15 +3738,16 @@
     if (curr_bpt->bpt_location() == bpt_location) {
       curr_bpt->Disable();
       curr_bpt->set_bpt_location(NULL);
+      needs_breakpoint_cleanup_ = true;
     }
     curr_bpt = curr_bpt->next();
   }
 }
 
 
-// Remove and delete internal breakpoints, i.e. breakpoints that
-// are not associated with a source breakpoint.
-void Debugger::RemoveInternalBreakpoints() {
+// Remove and delete unlinked code breakpoints, i.e. breakpoints that
+// are not associated with a breakpoint location.
+void Debugger::RemoveUnlinkedCodeBreakpoints() {
   CodeBreakpoint* prev_bpt = NULL;
   CodeBreakpoint* curr_bpt = code_breakpoints_;
   while (curr_bpt != NULL) {
@@ -3535,6 +3766,7 @@
       curr_bpt = curr_bpt->next();
     }
   }
+  needs_breakpoint_cleanup_ = false;
 }
 
 
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index fa9c3a6..bf932fe 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -11,6 +11,18 @@
 #include "vm/port.h"
 #include "vm/service_event.h"
 
+DECLARE_FLAG(bool, verbose_debug);
+
+// 'Trace Debugger' TD_Print.
+#if defined(_MSC_VER)
+#define TD_Print(format, ...)                                                  \
+  if (FLAG_verbose_debug) Log::Current()->Print(format, __VA_ARGS__)
+#else
+#define TD_Print(format, ...)                                                  \
+  if (FLAG_verbose_debug) Log::Current()->Print(format, ##__VA_ARGS__)
+#endif
+
+
 namespace dart {
 
 class CodeBreakpoint;
@@ -192,7 +204,6 @@
   RawFunction* function() const;
   uword pc() const { return pc_; }
   TokenPosition token_pos() const { return token_pos_; }
-  bool IsInternal() const { return bpt_location_ == NULL; }
 
   RawScript* SourceCode();
   RawString* SourceUrl();
@@ -245,12 +256,23 @@
 // on the call stack.
 class ActivationFrame : public ZoneAllocated {
  public:
+  enum Kind {
+    kRegular,
+    kAsyncSuspensionMarker,
+    kAsyncCausal,
+  };
+
   ActivationFrame(uword pc,
                   uword fp,
                   uword sp,
                   const Code& code,
                   const Array& deopt_frame,
-                  intptr_t deopt_frame_offset);
+                  intptr_t deopt_frame_offset,
+                  Kind kind = kRegular);
+
+  ActivationFrame(uword pc, const Code& code);
+
+  explicit ActivationFrame(Kind kind);
 
   uword pc() const { return pc_; }
   uword fp() const { return fp_; }
@@ -311,6 +333,10 @@
   void PrintToJSONObject(JSONObject* jsobj, bool full = false);
 
  private:
+  void PrintToJSONObjectRegular(JSONObject* jsobj, bool full);
+  void PrintToJSONObjectAsyncCausal(JSONObject* jsobj, bool full);
+  void PrintToJSONObjectAsyncSuspensionMarker(JSONObject* jsobj, bool full);
+
   void PrintContextMismatchError(intptr_t ctx_slot,
                                  intptr_t frame_ctx_level,
                                  intptr_t var_ctx_level);
@@ -320,6 +346,20 @@
   void GetVarDescriptors();
   void GetDescIndices();
 
+  static const char* KindToCString(Kind kind) {
+    switch (kind) {
+      case kRegular:
+        return "Regular";
+      case kAsyncCausal:
+        return "AsyncCausal";
+      case kAsyncSuspensionMarker:
+        return "AsyncSuspensionMarker";
+      default:
+        UNREACHABLE();
+        return "";
+    }
+  }
+
   RawObject* GetStackVar(intptr_t slot_index);
   RawObject* GetContextVar(intptr_t ctxt_level, intptr_t slot_index);
 
@@ -329,8 +369,9 @@
 
   // The anchor of the context chain for this function.
   Context& ctx_;
-  const Code& code_;
-  const Function& function_;
+  Code& code_;
+  Function& function_;
+  bool live_frame_;  // Is this frame a live frame?
   bool token_pos_initialized_;
   TokenPosition token_pos_;
   intptr_t try_index_;
@@ -343,6 +384,8 @@
   const Array& deopt_frame_;
   const intptr_t deopt_frame_offset_;
 
+  Kind kind_;
+
   bool vars_initialized_;
   LocalVarDescriptors& var_descriptors_;
   ZoneGrowableArray<intptr_t> desc_indices_;
@@ -367,6 +410,9 @@
 
  private:
   void AddActivation(ActivationFrame* frame);
+  void AddMarker(ActivationFrame::Kind marker);
+  void AddAsyncCausalFrame(uword pc, const Code& code);
+
   ZoneGrowableArray<ActivationFrame*> trace_;
 
   friend class Debugger;
@@ -470,6 +516,9 @@
   DebuggerStackTrace* StackTrace();
   DebuggerStackTrace* CurrentStackTrace();
 
+  DebuggerStackTrace* AsyncCausalStackTrace();
+  DebuggerStackTrace* CurrentAsyncCausalStackTrace();
+
   // Returns a debugger stack trace corresponding to a dart.core.StackTrace.
   // Frames corresponding to invisible functions are omitted. It is not valid
   // to query local variables in the returned stack.
@@ -530,6 +579,10 @@
  private:
   RawError* PauseRequest(ServiceEvent::EventKind kind);
 
+  // Finds the breakpoint we hit at |location|.
+  Breakpoint* FindHitBreakpoint(BreakpointLocation* location,
+                                ActivationFrame* top_frame);
+
   // Will return false if we are not at an await.
   bool SetupStepOverAsyncSuspension(const char** error);
 
@@ -557,7 +610,7 @@
                                     TokenPosition last_token_pos,
                                     intptr_t requested_line,
                                     intptr_t requested_column);
-  void RemoveInternalBreakpoints();
+  void RemoveUnlinkedCodeBreakpoints();
   void UnlinkCodeBreakpoints(BreakpointLocation* bpt_location);
   BreakpointLocation* GetLatentBreakpoint(const String& url,
                                           intptr_t line,
@@ -583,7 +636,18 @@
   static RawArray* DeoptimizeToArray(Thread* thread,
                                      StackFrame* frame,
                                      const Code& code);
+  // Appends at least one stack frame. Multiple frames will be appended
+  // if |code| at the frame's pc contains inlined functions.
+  static void AppendCodeFrames(Thread* thread,
+                               Isolate* isolate,
+                               Zone* zone,
+                               DebuggerStackTrace* stack_trace,
+                               StackFrame* frame,
+                               Code* code,
+                               Code* inlined_code,
+                               Array* deopt_frame);
   static DebuggerStackTrace* CollectStackTrace();
+  static DebuggerStackTrace* CollectAsyncCausalStackTrace();
   void SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt);
 
   intptr_t nextId() { return next_id_++; }
@@ -603,6 +667,11 @@
   void HandleSteppingRequest(DebuggerStackTrace* stack_trace,
                              bool skip_next_step = false);
 
+  void CacheStackTraces(DebuggerStackTrace* stack_trace,
+                        DebuggerStackTrace* async_causal_stack_trace);
+  void ClearCachedStackTraces();
+
+
   // Can we rewind to the indicated frame?
   bool CanRewindFrame(intptr_t frame_index, const char** error) const;
 
@@ -644,6 +713,7 @@
 
   // Current stack trace. Valid only while IsPaused().
   DebuggerStackTrace* stack_trace_;
+  DebuggerStackTrace* async_causal_stack_trace_;
 
   // When stepping through code, only pause the program if the top
   // frame corresponds to this fp value, or if the top frame is
@@ -655,6 +725,8 @@
   // breakpoint.
   bool skip_next_step_;
 
+  bool needs_breakpoint_cleanup_;
+
   // We keep this breakpoint alive until after the debugger does the step over
   // async continuation machinery so that we can report that we've stopped
   // at the breakpoint.
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index e48ab54..ee47df9 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1414,7 +1414,7 @@
 }
 
 
-UNIT_TEST_CASE(Debug_IsolateID) {
+VM_UNIT_TEST_CASE(Debug_IsolateID) {
   const char* kScriptChars =
       "void moo(s) { }        \n"
       "class A {              \n"
@@ -1446,6 +1446,7 @@
 static Monitor* sync = NULL;
 static bool isolate_interrupted = false;
 static bool pause_event_handled = false;
+static bool interrupt_thread_stopped = false;
 static Dart_IsolateId interrupt_isolate_id = ILLEGAL_ISOLATE_ID;
 static volatile bool continue_isolate_loop = true;
 
@@ -1533,6 +1534,12 @@
   EXPECT_VALID(retval);
   Dart_ExitScope();
   Dart_ShutdownIsolate();
+  {
+    // Notify the waiting thread that we are done.
+    MonitorLocker ml(sync);
+    interrupt_thread_stopped = true;
+    ml.Notify();
+  }
 }
 
 
@@ -1543,6 +1550,10 @@
   Dart_SetIsolateEventHandler(&TestInterruptIsolate);
   EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
   Dart_SetPausedEventHandler(InterruptIsolateHandler);
+  {
+    MonitorLocker ml(sync);
+    interrupt_thread_stopped = false;
+  }
   int result = OSThread::Start("DebugInterruptIsolate", InterruptIsolateRun, 0);
   EXPECT_EQ(0, result);
 
@@ -1580,6 +1591,17 @@
     }
   }
   EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
+
+  // Wait for the OSThread that we started above, if we do
+  // not wait we end up with a race between the process
+  // exiting and cleaning up while the thread above is cleaning
+  // up stuff from the isolate leading to flaky crashes.
+  {
+    MonitorLocker ml(sync);
+    while (!interrupt_thread_stopped) {
+      ml.Wait();
+    }
+  }
   OS::PrintErr("Complete\n");
   FLAG_trace_shutdown = saved_flag;
 }
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
index 6096965..a660e7a 100644
--- a/runtime/vm/debugger_test.cc
+++ b/runtime/vm/debugger_test.cc
@@ -3,14 +3,21 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "vm/dart_api_impl.h"
+#include "vm/dart_api_message.h"
 #include "vm/debugger.h"
+#include "vm/message.h"
 #include "vm/unit_test.h"
 
 namespace dart {
 
 #ifndef PRODUCT
 
+DECLARE_FLAG(bool, background_compilation);
+DECLARE_FLAG(bool, enable_inlining_annotations);
+DECLARE_FLAG(bool, prune_dead_locals);
 DECLARE_FLAG(bool, remove_script_timestamps_for_test);
+DECLARE_FLAG(bool, trace_rewind);
+DECLARE_FLAG(int, optimization_counter_threshold);
 
 // Search for the formatted string in buffer.
 //
@@ -141,6 +148,293 @@
   EXPECT(saw_paused_event);
 }
 
+
+static uint8_t* malloc_allocator(uint8_t* ptr,
+                                 intptr_t old_size,
+                                 intptr_t new_size) {
+  void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
+  return reinterpret_cast<uint8_t*>(new_ptr);
+}
+
+
+const char* rewind_frame_index = "-1";
+
+
+// Build and send a fake resume OOB message for testing purposes.
+void SendResumeMessage(Isolate* isolate) {
+  // Format is: [ oob_type, port, seq, method_name, [keys], [values] ]
+  Dart_CObject msg;
+  Dart_CObject* list_values[6];
+  msg.type = Dart_CObject_kArray;
+  msg.value.as_array.length = 6;
+  msg.value.as_array.values = list_values;
+
+  Dart_CObject oob;
+  oob.type = Dart_CObject_kInt32;
+  oob.value.as_int32 = Message::kServiceOOBMsg;
+  list_values[0] = &oob;
+
+  Dart_CObject reply_port;
+  reply_port.type = Dart_CObject_kNull;
+  list_values[1] = &reply_port;
+
+  Dart_CObject seq;
+  seq.type = Dart_CObject_kNull;
+  list_values[2] = &seq;
+
+  Dart_CObject method_name;
+  method_name.type = Dart_CObject_kString;
+  method_name.value.as_string = const_cast<char*>("resume");
+  list_values[3] = &method_name;
+
+  const int kParamCount = 3;
+  Dart_CObject param_keys;
+  Dart_CObject* param_keys_list[kParamCount];
+  param_keys.type = Dart_CObject_kArray;
+  param_keys.value.as_array.values = param_keys_list;
+  param_keys.value.as_array.length = kParamCount;
+  list_values[4] = &param_keys;
+
+  Dart_CObject param_values;
+  Dart_CObject* param_values_list[kParamCount];
+  param_values.type = Dart_CObject_kArray;
+  param_values.value.as_array.values = param_values_list;
+  param_values.value.as_array.length = kParamCount;
+  list_values[5] = &param_values;
+
+  Dart_CObject param0_name;
+  param0_name.type = Dart_CObject_kString;
+  param0_name.value.as_string = const_cast<char*>("isolateId");
+  param_keys_list[0] = &param0_name;
+
+  Dart_CObject param0_value;
+  param0_value.type = Dart_CObject_kString;
+  const char* isolate_id = Thread::Current()->zone()->PrintToString(
+      ISOLATE_SERVICE_ID_FORMAT_STRING,
+      static_cast<int64_t>(isolate->main_port()));
+  param0_value.value.as_string = const_cast<char*>(isolate_id);
+  param_values_list[0] = &param0_value;
+
+  Dart_CObject param1_name;
+  param1_name.type = Dart_CObject_kString;
+  param1_name.value.as_string = const_cast<char*>("step");
+  param_keys_list[1] = &param1_name;
+
+  Dart_CObject param1_value;
+  param1_value.type = Dart_CObject_kString;
+  param1_value.value.as_string = const_cast<char*>("Rewind");
+  param_values_list[1] = &param1_value;
+
+  Dart_CObject param2_name;
+  param2_name.type = Dart_CObject_kString;
+  param2_name.value.as_string = const_cast<char*>("frameIndex");
+  param_keys_list[2] = &param2_name;
+
+  Dart_CObject param2_value;
+  param2_value.type = Dart_CObject_kString;
+  param2_value.value.as_string = const_cast<char*>(rewind_frame_index);
+  param_values_list[2] = &param2_value;
+
+  {
+    uint8_t* buffer = NULL;
+    ApiMessageWriter writer(&buffer, &malloc_allocator);
+    bool success = writer.WriteCMessage(&msg);
+    ASSERT(success);
+
+    // Post the message at the given port.
+    success = PortMap::PostMessage(new Message(isolate->main_port(), buffer,
+                                               writer.BytesWritten(),
+                                               Message::kOOBPriority));
+    ASSERT(success);
+  }
+}
+
+
+static void RewindOnce(Dart_IsolateId isolate_id,
+                       intptr_t bp_id,
+                       const Dart_CodeLocation& loc) {
+  bool first_time = !saw_paused_event;
+  saw_paused_event = true;
+  if (first_time) {
+    Thread* T = Thread::Current();
+    Isolate* I = T->isolate();
+    // TODO(turnidge): It is weird that the isolate can get to this
+    // point in our tests without being marked runnable. Clear this up
+    // at some point.
+    I->set_is_runnable(true);
+    SendResumeMessage(I);
+    I->PauseEventHandler();
+  }
+}
+
+
+TEST_CASE(Debugger_RewindOneFrame_Unoptimized) {
+  SetFlagScope<bool> sfs(&FLAG_trace_rewind, true);
+
+  // These variables are global state used by RewindOnce.
+  saw_paused_event = false;
+  rewind_frame_index = "1";
+
+  const char* kScriptChars =
+      "import 'dart:developer';\n"
+      "\n"
+      "var msg = new StringBuffer();\n"
+      "\n"
+      "foo() {\n"
+      "  msg.write('enter(foo) ');\n"
+      "  debugger();\n"
+      "  msg.write('exit(foo) ');\n"
+      "}\n"
+      "\n"
+      "main() {\n"
+      "  msg.write('enter(main) ');\n"
+      "  foo();\n"
+      "  msg.write('exit(main) ');\n"
+      "  return msg.toString();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  EXPECT_VALID(lib);
+
+  Dart_SetPausedEventHandler(RewindOnce);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  const char* result_cstr;
+  EXPECT_VALID(result);
+  EXPECT(Dart_IsString(result));
+  EXPECT_VALID(Dart_StringToCString(result, &result_cstr));
+  EXPECT_STREQ("enter(main) enter(foo) enter(foo) exit(foo) exit(main) ",
+               result_cstr);
+  EXPECT(saw_paused_event);
+}
+
+
+TEST_CASE(Debugger_RewindTwoFrames_Unoptimized) {
+  SetFlagScope<bool> sfs(&FLAG_trace_rewind, true);
+
+  // These variables are global state used by RewindOnce.
+  saw_paused_event = false;
+  rewind_frame_index = "2";
+
+  const char* kScriptChars =
+      "import 'dart:developer';\n"
+      "\n"
+      "var msg = new StringBuffer();\n"
+      "\n"
+      "foo() {\n"
+      "  msg.write('enter(foo) ');\n"
+      "  debugger();\n"
+      "  msg.write('exit(foo) ');\n"
+      "}\n"
+      "\n"
+      "bar() {\n"
+      "  msg.write('enter(bar) ');\n"
+      "  foo();\n"
+      "  msg.write('exit(bar) ');\n"
+      "}\n"
+      "\n"
+      "main() {\n"
+      "  msg.write('enter(main) ');\n"
+      "  bar();\n"
+      "  msg.write('exit(main) ');\n"
+      "  return msg.toString();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  EXPECT_VALID(lib);
+
+  Dart_SetPausedEventHandler(RewindOnce);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  const char* result_cstr;
+  EXPECT_VALID(result);
+  EXPECT(Dart_IsString(result));
+  EXPECT_VALID(Dart_StringToCString(result, &result_cstr));
+  EXPECT_STREQ(
+      "enter(main) enter(bar) enter(foo) enter(bar) enter(foo) "
+      "exit(foo) exit(bar) exit(main) ",
+      result_cstr);
+  EXPECT(saw_paused_event);
+}
+
+
+TEST_CASE(Debugger_Rewind_Optimized) {
+  SetFlagScope<bool> sfs1(&FLAG_trace_rewind, true);
+  SetFlagScope<bool> sfs2(&FLAG_prune_dead_locals, false);
+  SetFlagScope<bool> sfs3(&FLAG_enable_inlining_annotations, true);
+  SetFlagScope<bool> sfs4(&FLAG_background_compilation, false);
+  SetFlagScope<int> sfs5(&FLAG_optimization_counter_threshold, 10);
+
+  // These variables are global state used by RewindOnce.
+  saw_paused_event = false;
+  rewind_frame_index = "2";
+
+  const char* kScriptChars =
+      "import 'dart:developer';\n"
+      "\n"
+      "const alwaysInline = \"AlwaysInline\";\n"
+      "const noInline = \"NeverInline\";\n"
+      "\n"
+      "var msg = new StringBuffer();\n"
+      "int i;\n"
+      "\n"
+      "@noInline\n"
+      "foo() {\n"
+      "  msg.write('enter(foo) ');\n"
+      "  if (i > 15) {\n"
+      "    debugger();\n"
+      "    msg.write('exit(foo) ');\n"
+      "    return true;\n"
+      "  } else {\n"
+      "    msg.write('exit(foo) ');\n"
+      "    return false;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "@alwaysInline\n"
+      "bar3() {\n"
+      "  msg.write('enter(bar3) ');\n"
+      "  var result = foo();\n"
+      "  msg.write('exit(bar3) ');\n"
+      "  return result;\n"
+      "}\n"
+      "\n"
+      "@alwaysInline\n"
+      "bar2() {\n"
+      "  msg.write('enter(bar2) ');\n"
+      "  var result = bar3();\n"
+      "  msg.write('exit(bar2) ');\n"
+      "  return result;\n"
+      "}\n"
+      "\n"
+      "@alwaysInline\n"
+      "bar1() {\n"
+      "  msg.write('enter(bar1) ');\n"
+      "  var result = bar2();\n"
+      "  msg.write('exit(bar1) ');\n"
+      "  return result;\n"
+      "}\n"
+      "\n"
+      "main() {\n"
+      "  for (i = 0; i < 20; i++) {\n"
+      "    msg.clear();\n"
+      "    if (bar1()) break;\n;"
+      "  }\n"
+      "  return msg.toString();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  EXPECT_VALID(lib);
+
+  Dart_SetPausedEventHandler(RewindOnce);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  const char* result_cstr;
+  EXPECT_VALID(result);
+  EXPECT(Dart_IsString(result));
+  EXPECT_VALID(Dart_StringToCString(result, &result_cstr));
+  EXPECT_STREQ(
+      "enter(bar1) enter(bar2) enter(bar3) enter(foo) "
+      "enter(bar3) enter(foo) "
+      "exit(foo) exit(bar3) exit(bar2) exit(bar1) ",
+      result_cstr);
+  EXPECT(saw_paused_event);
+}
+
 #endif  // !PRODUCT
 
 }  // namespace dart
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index b2d20e8..c51f6e4 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -20,6 +20,7 @@
 #ifndef PRODUCT
 
 DECLARE_FLAG(bool, trace_inlining_intervals);
+DEFINE_FLAG(bool, trace_source_positions, false, "Source position diagnostics");
 
 void DisassembleToStdout::ConsumeInstruction(const Code& code,
                                              char* hex_buffer,
@@ -112,7 +113,8 @@
   char human_buffer[kUserReadableBufferSize];  // Human-readable instruction.
   uword pc = start;
   intptr_t comment_finger = 0;
-  GrowableArray<Function*> inlined_functions;
+  GrowableArray<const Function*> inlined_functions;
+  GrowableArray<TokenPosition> token_positions;
   while (pc < end) {
     const intptr_t offset = pc - start;
     const intptr_t old_comment_finger = comment_finger;
@@ -127,10 +129,11 @@
       char str[4000];
       BufferFormatter f(str, sizeof(str));
       // Comment emitted, emit inlining information.
-      code.GetInlinedFunctionsAt(offset, &inlined_functions);
+      code.GetInlinedFunctionsAtInstruction(offset, &inlined_functions,
+                                            &token_positions);
       // Skip top scope function printing (last entry in 'inlined_functions').
       bool first = true;
-      for (intptr_t i = inlined_functions.length() - 2; i >= 0; i--) {
+      for (intptr_t i = 1; i < inlined_functions.length(); i++) {
         const char* name = inlined_functions[i]->ToQualifiedCString();
         if (first) {
           f.Print("        ;; Inlined [%s", name);
@@ -290,7 +293,10 @@
     THR_Print("}\n");
   }
   if (optimized && FLAG_trace_inlining_intervals) {
-    code.DumpInlinedIntervals();
+    code.DumpInlineIntervals();
+  }
+  if (FLAG_trace_source_positions) {
+    code.DumpSourcePositions();
   }
 }
 
diff --git a/runtime/vm/disassembler.h b/runtime/vm/disassembler.h
index 283f16e..8b17c67 100644
--- a/runtime/vm/disassembler.h
+++ b/runtime/vm/disassembler.h
@@ -102,15 +102,23 @@
   }
 
   static void Disassemble(uword start, uword end, const Code& code) {
+#ifndef PRODUCT
     DisassembleToStdout stdout_formatter;
     LogBlock lb;
     Disassemble(start, end, &stdout_formatter, code);
+#else
+    UNREACHABLE();
+#endif
   }
 
   static void Disassemble(uword start, uword end) {
+#ifndef PRODUCT
     DisassembleToStdout stdout_formatter;
     LogBlock lb;
     Disassemble(start, end, &stdout_formatter);
+#else
+    UNREACHABLE();
+#endif
   }
 
   // Decodes one instruction.
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index c2bc393..8823362 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -6,6 +6,8 @@
 
 #include "platform/address_sanitizer.h"
 
+#include "lib/stacktrace.h"
+
 #include "vm/dart_api_impl.h"
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
@@ -19,6 +21,7 @@
 #include "vm/symbols.h"
 #include "vm/tags.h"
 
+
 namespace dart {
 
 DECLARE_FLAG(bool, trace_deoptimization);
@@ -98,7 +101,7 @@
     dropped_frames_++;
     // Add an empty slot to indicate the overflow so that the toString
     // method can account for the overflow.
-    if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) {
+    if (stacktrace_.CodeAtFrame(null_slot) != Code::null()) {
       stacktrace_.SetCodeAtFrame(null_slot, frame_code);
       // We drop an extra frame here too.
       dropped_frames_++;
@@ -369,18 +372,7 @@
 
 
 RawStackTrace* Exceptions::CurrentStackTrace() {
-  Zone* zone = Thread::Current()->zone();
-  RegularStackTraceBuilder frame_builder(zone);
-  BuildStackTrace(&frame_builder);
-
-  // Create arrays for code and pc_offset tuples of each frame.
-  const Array& full_code_array =
-      Array::Handle(zone, Array::MakeArray(frame_builder.code_list()));
-  const Array& full_pc_offset_array =
-      Array::Handle(zone, Array::MakeArray(frame_builder.pc_offset_list()));
-  const StackTrace& full_stacktrace = StackTrace::Handle(
-      StackTrace::New(full_code_array, full_pc_offset_array));
-  return full_stacktrace.raw();
+  return GetStackTraceForException();
 }
 
 
@@ -421,7 +413,10 @@
     }
     stacktrace ^= isolate->object_store()->preallocated_stack_trace();
     PreallocatedStackTraceBuilder frame_builder(stacktrace);
-    if (handler_needs_stacktrace) {
+    ASSERT(existing_stacktrace.IsNull() ||
+           (existing_stacktrace.raw() == stacktrace.raw()));
+    ASSERT(existing_stacktrace.IsNull() || is_rethrow);
+    if (handler_needs_stacktrace && existing_stacktrace.IsNull()) {
       BuildStackTrace(&frame_builder);
     }
   } else {
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 48e0f4a..df4c44c 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -90,6 +90,15 @@
   DISALLOW_COPY_AND_ASSIGN(Exceptions);
 };
 
+// The index into the ExceptionHandlers table corresponds to
+// the try_index of the handler.
+struct ExceptionHandlerInfo {
+  uint32_t handler_pc_offset;  // PC offset value of handler.
+  int16_t outer_try_index;     // Try block index of enclosing try block.
+  int8_t needs_stacktrace;     // True if a stacktrace is needed.
+  int8_t has_catch_all;        // Catches all exceptions.
+};
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_EXCEPTIONS_H_
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index a47129e..f51cae5 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -25,7 +25,7 @@
 #endif
 static char scriptChars[kScriptSize];
 
-VM_TEST_CASE(FindCodeObject) {
+ISOLATE_UNIT_TEST_CASE(FindCodeObject) {
   const int kNumFunctions = 1024;
 
   // Get access to the code index table.
diff --git a/runtime/vm/fixed_cache.h b/runtime/vm/fixed_cache.h
new file mode 100644
index 0000000..eac919d
--- /dev/null
+++ b/runtime/vm/fixed_cache.h
@@ -0,0 +1,93 @@
+// 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.
+
+#ifndef RUNTIME_VM_FIXED_CACHE_H_
+#define RUNTIME_VM_FIXED_CACHE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace dart {
+
+// A simple sorted fixed size Key-Value storage.
+//
+// Assumes both Key and Value are POD-like objects.
+//
+// Keys must be comparable with operator<.
+//
+// Duplicates are not allowed - check with Lookup before insertion.
+//
+// Optionally Values may have cleanup function to delete
+// any resources they point to.
+template <class K, class V, intptr_t kCapacity>
+class FixedCache {
+ public:
+  typedef void (*Deleter)(V*);
+
+  struct Entry {
+    K key;
+    V value;
+  };
+
+  explicit FixedCache(Deleter deleter = NULL) : deleter_(deleter), length_(0) {}
+
+  ~FixedCache() { Clear(); }
+
+  V* Lookup(K key) {
+    intptr_t i = LowerBound(key);
+    if (i != length_ && pairs_[i].key == key) return &pairs_[i].value;
+    return NULL;
+  }
+
+  void Insert(K key, V value) {
+    intptr_t i = LowerBound(key);
+
+    if (length_ == kCapacity) {
+      if (deleter_) deleter_(&pairs_[length_ - 1].value);
+      length_ = kCapacity - 1;
+      if (i == kCapacity) i = kCapacity - 1;
+    }
+
+    for (intptr_t j = length_ - 1; j >= i; j--) {
+      pairs_[j + 1] = pairs_[j];
+    }
+
+    length_ += 1;
+    pairs_[i].key = key;
+    pairs_[i].value = value;
+  }
+
+  void Clear() {
+    if (deleter_) {
+      for (intptr_t i = 0; i < length_; i++) {
+        deleter_(&pairs_[i].value);
+      }
+    }
+    length_ = 0;
+  }
+
+ private:
+  intptr_t LowerBound(K key) {
+    intptr_t low = 0, high = length_;
+    while (low != high) {
+      intptr_t mid = low + (high - low) / 2;
+      if (key < pairs_[mid].key) {
+        high = mid;
+      } else if (key > pairs_[mid].key) {
+        low = mid + 1;
+      } else {
+        low = high = mid;
+      }
+    }
+    return low;
+  }
+
+  Entry pairs_[kCapacity];  // Sorted array of pairs.
+  Deleter deleter_;
+  intptr_t length_;
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_FIXED_CACHE_H_
diff --git a/runtime/vm/fixed_cache_test.cc b/runtime/vm/fixed_cache_test.cc
new file mode 100644
index 0000000..a4fbf28
--- /dev/null
+++ b/runtime/vm/fixed_cache_test.cc
@@ -0,0 +1,84 @@
+// 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.
+
+#include <string.h>
+#include "platform/assert.h"
+#include "vm/fixed_cache.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+UNIT_TEST_CASE(FixedCacheEmpty) {
+  FixedCache<int, int, 2> cache;
+  EXPECT(cache.Lookup(0) == NULL);
+  EXPECT(cache.Lookup(1) == NULL);
+  cache.Insert(1, 2);
+  EXPECT(*cache.Lookup(1) == 2);
+  EXPECT(cache.Lookup(0) == NULL);
+}
+
+
+UNIT_TEST_CASE(FixedCacheHalfFull) {
+  FixedCache<int, const char*, 8> cache;
+  // Insert at end.
+  cache.Insert(10, "a");
+  cache.Insert(20, "b");
+  cache.Insert(40, "c");
+  // Insert in the middle.
+  cache.Insert(15, "ab");
+  cache.Insert(25, "bc");
+  // Insert in front.
+  cache.Insert(5, "_");
+  // Check all items.
+  EXPECT(strcmp(*cache.Lookup(5), "_") == 0);
+  EXPECT(strcmp(*cache.Lookup(10), "a") == 0);
+  EXPECT(strcmp(*cache.Lookup(20), "b") == 0);
+  EXPECT(strcmp(*cache.Lookup(40), "c") == 0);
+  EXPECT(strcmp(*cache.Lookup(25), "bc") == 0);
+  // Non-existent - front, middle, end.
+  EXPECT(cache.Lookup(1) == NULL);
+  EXPECT(cache.Lookup(35) == NULL);
+  EXPECT(cache.Lookup(50) == NULL);
+}
+
+
+struct Resource {
+  Resource() : id(0), stuff(NULL) {}
+  explicit Resource(int id_) : id(id_), stuff(new int) {}
+
+  int id;
+  int* stuff;
+};
+
+static void freeResource(Resource* res) {
+  delete res->stuff;
+}
+
+
+UNIT_TEST_CASE(FixedCacheFullDeleter) {
+  FixedCache<int, Resource, 6> cache(freeResource);
+  cache.Insert(10, Resource(2));
+  cache.Insert(20, Resource(4));
+  cache.Insert(40, Resource(16));
+  cache.Insert(30, Resource(8));
+  EXPECT(cache.Lookup(40)->id == 16);
+  EXPECT(cache.Lookup(5) == NULL);
+  EXPECT(cache.Lookup(0) == NULL);
+  // Insert in the front, middle.
+  cache.Insert(5, Resource(1));
+  cache.Insert(15, Resource(3));
+  cache.Insert(25, Resource(6));
+  // 40 got removed by shifting.
+  EXPECT(cache.Lookup(40) == NULL);
+  EXPECT(cache.Lookup(5)->id == 1);
+  EXPECT(cache.Lookup(15)->id == 3);
+  EXPECT(cache.Lookup(25)->id == 6);
+
+  // Insert at end top - 30 gets replaced by 40.
+  cache.Insert(40, Resource(16));
+  EXPECT(cache.Lookup(40)->id == 16);
+  EXPECT(cache.Lookup(30) == NULL);
+}
+
+}  // namespace dart
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index bd6f464..9ab1c95 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -45,7 +45,7 @@
     "Run optimizing compilation in background")                                \
   R(background_compilation_stop_alot, false, bool, false,                      \
     "Stress test system: stop background compiler often.")                     \
-  P(background_finalization, bool, USING_MULTICORE,                            \
+  P(background_finalization, bool, false,                                      \
     "Run weak handle finalizers in background")                                \
   R(break_at_isolate_spawn, false, bool, false,                                \
     "Insert a one-time breakpoint at the entrypoint for all spawned isolates") \
@@ -122,6 +122,8 @@
   P(precompiled_mode, bool, false, "Precompilation compiler mode")             \
   C(precompiled_runtime, true, false, bool, false, "Precompiled runtime mode") \
   P(print_snapshot_sizes, bool, false, "Print sizes of generated snapshots.")  \
+  P(print_benchmarking_metrics, bool, false,                                   \
+    "Print additional memory and latency metrics for benchmarking.")           \
   R(print_ssa_liveranges, false, bool, false,                                  \
     "Print live ranges after allocation.")                                     \
   C(print_stop_message, false, false, bool, false, "Print stop message.")      \
@@ -130,6 +132,7 @@
   R(profiler, false, bool, !USING_DBC && !USING_FUCHSIA,                       \
     "Enable the profiler.")                                                    \
   P(reorder_basic_blocks, bool, true, "Reorder basic blocks")                  \
+  R(causal_async_stacks, false, bool, true, "Improved async stacks")           \
   R(support_ast_printer, false, bool, true, "Support the AST printer.")        \
   R(support_compiler_stats, false, bool, true, "Support compiler stats.")      \
   C(support_debugger, false, false, bool, true, "Support the debugger.")       \
diff --git a/runtime/vm/flags.h b/runtime/vm/flags.h
index f5cb8f3..db14c24 100644
--- a/runtime/vm/flags.h
+++ b/runtime/vm/flags.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors[.  Please see the AUTHORS file
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/runtime/vm/flags_test.cc b/runtime/vm/flags_test.cc
index d7f95c4..5bef9b0 100644
--- a/runtime/vm/flags_test.cc
+++ b/runtime/vm/flags_test.cc
@@ -13,7 +13,7 @@
 
 DECLARE_FLAG(bool, print_flags);
 
-UNIT_TEST_CASE(BasicFlags) {
+VM_UNIT_TEST_CASE(BasicFlags) {
   EXPECT_EQ(true, FLAG_basic_flag);
   EXPECT_EQ(false, FLAG_verbose_gc);
   EXPECT_EQ(false, FLAG_print_flags);
@@ -25,7 +25,7 @@
 DEFINE_FLAG(charp, entrypoint_test, "main", "Testing: entrypoint");
 DEFINE_FLAG(int, counter, 100, "Testing: int flag");
 
-UNIT_TEST_CASE(ParseFlags) {
+VM_UNIT_TEST_CASE(ParseFlags) {
   EXPECT_EQ(true, FLAG_parse_flag_bool_test);
   Flags::Parse("no_parse_flag_bool_test");
   EXPECT_EQ(false, FLAG_parse_flag_bool_test);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 1bafaa5..a6547d1 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1131,6 +1131,21 @@
     }
   }
 
+  if (FLAG_causal_async_stacks &&
+      (function.IsAsyncClosure() || function.IsAsyncGenClosure())) {
+    // We are returning from an asynchronous closure. Before we do that, be
+    // sure to clear the thread's asynchronous stack trace.
+    const Function& async_clear_thread_stack_trace = Function::ZoneHandle(
+        Z, isolate()->object_store()->async_clear_thread_stack_trace());
+    ZoneGrowableArray<PushArgumentInstr*>* no_arguments =
+        new (Z) ZoneGrowableArray<PushArgumentInstr*>(0);
+    StaticCallInstr* call_async_clear_thread_stack_trace = new (Z)
+        StaticCallInstr(node->token_pos().ToSynthetic(),
+                        async_clear_thread_stack_trace, Object::null_array(),
+                        no_arguments, owner()->ic_data_array());
+    Do(call_async_clear_thread_stack_trace);
+  }
+
   // Async functions contain two types of return statements:
   // 1) Returns that should complete the completer once all finally blocks have
   //    been inlined (call: :async_completer.complete(return_value)). These
@@ -3792,6 +3807,34 @@
     }
   }
 
+  if (FLAG_causal_async_stacks && is_top_level_sequence &&
+      (function.IsAsyncClosure() || function.IsAsyncGenClosure())) {
+    LocalScope* top_scope = node->scope();
+    // Fetch the :async_stack_trace variable and store it into the thread.
+    LocalVariable* async_stack_trace_var =
+        top_scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
+    ASSERT((async_stack_trace_var != NULL) &&
+           async_stack_trace_var->is_captured());
+    // Load :async_stack_trace
+    Value* async_stack_trace_value = Bind(BuildLoadLocal(
+        *async_stack_trace_var, node->token_pos().ToSynthetic()));
+    // Setup arguments for _asyncSetThreadStackTrace.
+    ZoneGrowableArray<PushArgumentInstr*>* arguments =
+        new (Z) ZoneGrowableArray<PushArgumentInstr*>(1);
+    arguments->Add(PushArgument(async_stack_trace_value));
+
+    const Function& async_set_thread_stack_trace = Function::ZoneHandle(
+        Z, isolate()->object_store()->async_set_thread_stack_trace());
+    ASSERT(!async_set_thread_stack_trace.IsNull());
+    // Call _asyncSetThreadStackTrace
+    StaticCallInstr* call_async_set_thread_stack_trace = new (Z)
+        StaticCallInstr(node->token_pos().ToSynthetic(),
+                        async_set_thread_stack_trace, Object::null_array(),
+                        arguments, owner()->ic_data_array());
+    Do(call_async_set_thread_stack_trace);
+  }
+
+
   if (FLAG_support_debugger && is_top_level_sequence &&
       function.is_debuggable()) {
     // Place a debug check at method entry to ensure breaking on a method always
@@ -4300,12 +4343,14 @@
 FlowGraph* FlowGraphBuilder::BuildGraph() {
   VMTagScope tagScope(thread(), VMTag::kCompileFlowGraphBuilderTagId,
                       FLAG_profile_vm);
-  if (FLAG_support_ast_printer && FLAG_print_ast) {
+  if (FLAG_support_ast_printer && FLAG_print_ast &&
+      FlowGraphPrinter::ShouldPrint(parsed_function().function())) {
     // Print the function ast before IL generation.
     AstPrinter ast_printer;
     ast_printer.PrintFunctionNodes(parsed_function());
   }
-  if (FLAG_support_ast_printer && FLAG_print_scopes) {
+  if (FLAG_support_ast_printer && FLAG_print_scopes &&
+      FlowGraphPrinter::ShouldPrint(parsed_function().function())) {
     AstPrinter ast_printer;
     ast_printer.PrintFunctionScope(parsed_function());
   }
diff --git a/runtime/vm/flow_graph_builder_test.cc b/runtime/vm/flow_graph_builder_test.cc
index 9de7a0c..122e6d4 100644
--- a/runtime/vm/flow_graph_builder_test.cc
+++ b/runtime/vm/flow_graph_builder_test.cc
@@ -772,7 +772,7 @@
 }
 
 
-UNIT_TEST_CASE(SourcePosition_SyntheticTokens) {
+VM_UNIT_TEST_CASE(SourcePosition_SyntheticTokens) {
   EXPECT(TokenPosition::kNoSourcePos == -1);
   EXPECT(TokenPosition::kMinSourcePos == 0);
   EXPECT(TokenPosition::kMaxSourcePos > 0);
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 2ab89c1..4388c18 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -196,7 +196,6 @@
       pc_descriptors_list_(NULL),
       stackmap_table_builder_(NULL),
       code_source_map_builder_(NULL),
-      saved_code_size_(0),
       block_info_(block_order_.length()),
       deopt_infos_(),
       static_calls_target_table_(),
@@ -217,11 +216,7 @@
       parallel_move_resolver_(this),
       pending_deoptimization_env_(NULL),
       deopt_id_to_ic_data_(NULL),
-      edge_counters_array_(Array::ZoneHandle()),
-      inlined_code_intervals_(Array::ZoneHandle(Object::empty_array().raw())),
-      inline_id_to_function_(inline_id_to_function),
-      inline_id_to_token_pos_(inline_id_to_token_pos),
-      caller_inline_id_(caller_inline_id) {
+      edge_counters_array_(Array::ZoneHandle()) {
   ASSERT(flow_graph->parsed_function().function().raw() ==
          parsed_function.function().raw());
   if (!is_optimizing) {
@@ -244,6 +239,11 @@
   }
   ASSERT(assembler != NULL);
   ASSERT(!list_class_.IsNull());
+
+  bool stack_traces_only = !FLAG_profiler;
+  code_source_map_builder_ = new (zone_)
+      CodeSourceMapBuilder(stack_traces_only, caller_inline_id,
+                           inline_id_to_token_pos, inline_id_to_function);
 }
 
 
@@ -463,22 +463,6 @@
 }
 
 
-// We collect intervals while generating code.
-struct IntervalStruct {
-  // 'start' is the pc-offsets where the inlined code started.
-  // 'pos' is the token position where the inlined call occured.
-  intptr_t start;
-  TokenPosition pos;
-  intptr_t inlining_id;
-  IntervalStruct(intptr_t s, TokenPosition tp, intptr_t id)
-      : start(s), pos(tp), inlining_id(id) {}
-  void Dump() {
-    THR_Print("start: 0x%" Px " iid: %" Pd " pos: %s", start, inlining_id,
-              pos.ToCString());
-  }
-};
-
-
 void FlowGraphCompiler::VisitBlocks() {
   CompactBlocks();
   const ZoneGrowableArray<BlockEntryInstr*>* loop_headers = NULL;
@@ -488,12 +472,6 @@
     ASSERT(loop_headers != NULL);
   }
 
-  // For collecting intervals of inlined code.
-  GrowableArray<IntervalStruct> intervals;
-  intptr_t prev_offset = 0;
-  intptr_t prev_inlining_id = 0;
-  TokenPosition prev_inlining_pos = parsed_function_.function().token_pos();
-  intptr_t max_inlining_id = 0;
   for (intptr_t i = 0; i < block_order().length(); ++i) {
     // Compile the block entry.
     BlockEntryInstr* entry = block_order()[i];
@@ -523,24 +501,8 @@
     for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
       Instruction* instr = it.Current();
       // Compose intervals.
-      if (instr->has_inlining_id() && is_optimizing()) {
-        if (prev_inlining_id != instr->inlining_id()) {
-          intervals.Add(
-              IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id));
-          prev_offset = assembler()->CodeSize();
-          prev_inlining_id = instr->inlining_id();
-          if (prev_inlining_id < inline_id_to_token_pos_.length()) {
-            prev_inlining_pos = inline_id_to_token_pos_[prev_inlining_id];
-          } else {
-            // We will add this token position later when generating the
-            // profile.
-            prev_inlining_pos = TokenPosition::kNoSource;
-          }
-          if (prev_inlining_id > max_inlining_id) {
-            max_inlining_id = prev_inlining_id;
-          }
-        }
-      }
+      code_source_map_builder_->StartInliningInterval(assembler()->CodeSize(),
+                                                      instr->inlining_id());
       if (FLAG_code_comments || FLAG_disassemble ||
           FLAG_disassemble_optimized) {
         if (FLAG_source_lines) {
@@ -573,53 +535,7 @@
 #endif
   }
 
-  if (is_optimizing()) {
-    LogBlock lb;
-    intervals.Add(
-        IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id));
-    inlined_code_intervals_ =
-        Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld);
-    Smi& start_h = Smi::Handle();
-    Smi& caller_inline_id = Smi::Handle();
-    Smi& inline_id = Smi::Handle();
-    for (intptr_t i = 0; i < intervals.length(); i++) {
-      if (FLAG_trace_inlining_intervals && is_optimizing()) {
-        const Function& function =
-            *inline_id_to_function_.At(intervals[i].inlining_id);
-        intervals[i].Dump();
-        THR_Print(" parent iid %" Pd " %s\n",
-                  caller_inline_id_[intervals[i].inlining_id],
-                  function.ToQualifiedCString());
-      }
-
-      const intptr_t id = intervals[i].inlining_id;
-      start_h = Smi::New(intervals[i].start);
-      inline_id = Smi::New(id);
-      caller_inline_id = Smi::New(caller_inline_id_[intervals[i].inlining_id]);
-
-      const intptr_t p = i * Code::kInlIntNumEntries;
-      inlined_code_intervals_.SetAt(p + Code::kInlIntStart, start_h);
-      inlined_code_intervals_.SetAt(p + Code::kInlIntInliningId, inline_id);
-    }
-  }
   set_current_block(NULL);
-  if (FLAG_trace_inlining_intervals && is_optimizing()) {
-    LogBlock lb;
-    THR_Print("Intervals:\n");
-    for (intptr_t cc = 0; cc < caller_inline_id_.length(); cc++) {
-      THR_Print("  iid: %" Pd " caller iid: %" Pd "\n", cc,
-                caller_inline_id_[cc]);
-    }
-    Smi& temp = Smi::Handle();
-    for (intptr_t i = 0; i < inlined_code_intervals_.Length();
-         i += Code::kInlIntNumEntries) {
-      temp ^= inlined_code_intervals_.At(i + Code::kInlIntStart);
-      ASSERT(!temp.IsNull());
-      THR_Print("% " Pd " start: 0x%" Px " ", i, temp.Value());
-      temp ^= inlined_code_intervals_.At(i + Code::kInlIntInliningId);
-      THR_Print("iid: %" Pd " ", temp.Value());
-    }
-  }
 }
 
 
@@ -767,14 +683,25 @@
 }
 
 
+void FlowGraphCompiler::AddDescriptor(RawPcDescriptors::Kind kind,
+                                      intptr_t pc_offset,
+                                      intptr_t deopt_id,
+                                      TokenPosition token_pos,
+                                      intptr_t try_index) {
+  code_source_map_builder_->NoteDescriptor(kind, pc_offset, token_pos);
+  // When running with optimizations disabled, don't emit deopt-descriptors.
+  if (!CanOptimize() && (kind == RawPcDescriptors::kDeopt)) return;
+  pc_descriptors_list_->AddDescriptor(kind, pc_offset, deopt_id, token_pos,
+                                      try_index);
+}
+
+
 // Uses current pc position and try-index.
 void FlowGraphCompiler::AddCurrentDescriptor(RawPcDescriptors::Kind kind,
                                              intptr_t deopt_id,
                                              TokenPosition token_pos) {
-  // When running with optimizations disabled, don't emit deopt-descriptors.
-  if (!CanOptimize() && (kind == RawPcDescriptors::kDeopt)) return;
-  pc_descriptors_list()->AddDescriptor(kind, assembler()->CodeSize(), deopt_id,
-                                       token_pos, CurrentTryIndex());
+  AddDescriptor(kind, assembler()->CodeSize(), deopt_id, token_pos,
+                CurrentTryIndex());
 }
 
 
@@ -1112,6 +1039,29 @@
 }
 
 
+void FlowGraphCompiler::FinalizeCodeSourceMap(const Code& code) {
+  const Array& inlined_id_array =
+      Array::Handle(zone(), code_source_map_builder_->InliningIdToFunction());
+  INC_STAT(Thread::Current(), total_code_size,
+           inlined_id_array.Length() * sizeof(uword));
+  code.set_inlined_id_to_function(inlined_id_array);
+
+  const CodeSourceMap& map =
+      CodeSourceMap::Handle(code_source_map_builder_->Finalize());
+  INC_STAT(Thread::Current(), total_code_size, map.Length() * sizeof(uint8_t));
+  code.set_code_source_map(map);
+
+#if defined(DEBUG)
+  // Force simulation through the last pc offset. This checks we can decode
+  // the whole CodeSourceMap without hitting an unknown opcode, stack underflow,
+  // etc.
+  GrowableArray<const Function*> fs;
+  GrowableArray<TokenPosition> tokens;
+  code.GetInlinedFunctionsAtInstruction(code.Size() - 1, &fs, &tokens);
+#endif
+}
+
+
 // Returns 'true' if regular code generation should be skipped.
 bool FlowGraphCompiler::TryIntrinsify() {
   // Intrinsification skips arguments checks, therefore disable if in checked
@@ -1788,70 +1738,14 @@
 }
 
 
-RawArray* FlowGraphCompiler::InliningIdToFunction() const {
-  if (inline_id_to_function_.length() == 0) {
-    return Object::empty_array().raw();
-  }
-  const Array& res =
-      Array::Handle(Array::New(inline_id_to_function_.length(), Heap::kOld));
-  for (intptr_t i = 0; i < inline_id_to_function_.length(); i++) {
-    res.SetAt(i, *inline_id_to_function_[i]);
-  }
-  return res.raw();
-}
-
-
-RawArray* FlowGraphCompiler::InliningIdToTokenPos() const {
-  if (inline_id_to_token_pos_.length() == 0) {
-    return Object::empty_array().raw();
-  }
-  const Array& res = Array::Handle(
-      zone(), Array::New(inline_id_to_token_pos_.length(), Heap::kOld));
-  Smi& smi = Smi::Handle(zone());
-  for (intptr_t i = 0; i < inline_id_to_token_pos_.length(); i++) {
-    smi = Smi::New(inline_id_to_token_pos_[i].value());
-    res.SetAt(i, smi);
-  }
-  return res.raw();
-}
-
-
-RawArray* FlowGraphCompiler::CallerInliningIdMap() const {
-  if (caller_inline_id_.length() == 0) {
-    return Object::empty_array().raw();
-  }
-  const Array& res =
-      Array::Handle(Array::New(caller_inline_id_.length(), Heap::kOld));
-  Smi& smi = Smi::Handle();
-  for (intptr_t i = 0; i < caller_inline_id_.length(); i++) {
-    smi = Smi::New(caller_inline_id_[i]);
-    res.SetAt(i, smi);
-  }
-  return res.raw();
-}
-
-
 void FlowGraphCompiler::BeginCodeSourceRange() {
-#if !defined(PRODUCT)
-  // Remember how many bytes of code we emitted so far. This function
-  // is called before we call into an instruction's EmitNativeCode.
-  saved_code_size_ = assembler()->CodeSize();
-#endif  // !defined(PRODUCT)
+  code_source_map_builder_->BeginCodeSourceRange(assembler()->CodeSize());
 }
 
 
-bool FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) {
-#if !defined(PRODUCT)
-  // This function is called after each instructions' EmitNativeCode.
-  if (saved_code_size_ < assembler()->CodeSize()) {
-    // We emitted more code, now associate the emitted code chunk with
-    // |token_pos|.
-    code_source_map_builder()->AddEntry(saved_code_size_, token_pos);
-    BeginCodeSourceRange();
-    return true;
-  }
-#endif  // !defined(PRODUCT)
-  return false;
+void FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) {
+  code_source_map_builder_->EndCodeSourceRange(assembler()->CodeSize(),
+                                               token_pos);
 }
 
 
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 9e5b784..d51002f 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -23,7 +23,6 @@
 class GrowableArray;
 class ParsedFunction;
 
-
 class ParallelMoveResolver : public ValueObject {
  public:
   explicit ParallelMoveResolver(FlowGraphCompiler* compiler);
@@ -308,7 +307,6 @@
 
   const FlowGraph& flow_graph() const { return flow_graph_; }
 
-  DescriptorList* pc_descriptors_list() const { return pc_descriptors_list_; }
   BlockEntryInstr* current_block() const { return current_block_; }
   void set_current_block(BlockEntryInstr* value) { current_block_ = value; }
   static bool CanOptimize();
@@ -499,6 +497,11 @@
   void AddCurrentDescriptor(RawPcDescriptors::Kind kind,
                             intptr_t deopt_id,
                             TokenPosition token_pos);
+  void AddDescriptor(RawPcDescriptors::Kind kind,
+                     intptr_t pc_offset,
+                     intptr_t deopt_id,
+                     TokenPosition token_pos,
+                     intptr_t try_index);
 
   void RecordSafepoint(LocationSummary* locs,
                        intptr_t slow_path_argument_count = 0);
@@ -526,6 +529,7 @@
   void FinalizeStackMaps(const Code& code);
   void FinalizeVarDescriptors(const Code& code);
   void FinalizeStaticCallTargetsTable(const Code& code);
+  void FinalizeCodeSourceMap(const Code& code);
 
   const Class& double_class() const { return double_class_; }
   const Class& mint_class() const { return mint_class_; }
@@ -578,26 +582,12 @@
 
   void AddStubCallTarget(const Code& code);
 
-  const Array& inlined_code_intervals() const {
-    return inlined_code_intervals_;
-  }
-
   RawArray* edge_counters_array() const { return edge_counters_array_.raw(); }
 
   RawArray* InliningIdToFunction() const;
-  RawArray* InliningIdToTokenPos() const;
-  RawArray* CallerInliningIdMap() const;
-
-  CodeSourceMapBuilder* code_source_map_builder() {
-    if (code_source_map_builder_ == NULL) {
-      code_source_map_builder_ = new CodeSourceMapBuilder();
-    }
-    ASSERT(code_source_map_builder_ != NULL);
-    return code_source_map_builder_;
-  }
 
   void BeginCodeSourceRange();
-  bool EndCodeSourceRange(TokenPosition token_pos);
+  void EndCodeSourceRange(TokenPosition token_pos);
 
 #if defined(TARGET_ARCH_DBC)
   enum CallResult {
@@ -776,7 +766,6 @@
   DescriptorList* pc_descriptors_list_;
   StackMapTableBuilder* stackmap_table_builder_;
   CodeSourceMapBuilder* code_source_map_builder_;
-  intptr_t saved_code_size_;
   GrowableArray<BlockInfo*> block_info_;
   GrowableArray<CompilerDeoptInfo*> deopt_infos_;
   GrowableArray<SlowPathCode*> slow_path_code_;
@@ -810,11 +799,6 @@
 
   Array& edge_counters_array_;
 
-  Array& inlined_code_intervals_;
-  const GrowableArray<const Function*>& inline_id_to_function_;
-  const GrowableArray<TokenPosition>& inline_id_to_token_pos_;
-  const GrowableArray<intptr_t>& caller_inline_id_;
-
   DISALLOW_COPY_AND_ASSIGN(FlowGraphCompiler);
 };
 
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index e16256c..700935b 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1282,9 +1282,8 @@
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
       try_index = CurrentTryIndex();
     }
-    pc_descriptors_list()->AddDescriptor(
-        RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId,
-        token_pos, try_index);
+    AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),
+                  Thread::kNoDeoptId, token_pos, try_index);
   } else if (is_optimizing()) {
     AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId,
                          token_pos);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 8534b1f..d320028 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1270,9 +1270,8 @@
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
       try_index = CurrentTryIndex();
     }
-    pc_descriptors_list()->AddDescriptor(
-        RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId,
-        token_pos, try_index);
+    AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),
+                  Thread::kNoDeoptId, token_pos, try_index);
   } else if (is_optimizing()) {
     AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId,
                          token_pos);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index b6914ad..7854b08 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1287,9 +1287,8 @@
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
       try_index = CurrentTryIndex();
     }
-    pc_descriptors_list()->AddDescriptor(
-        RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId,
-        token_pos, try_index);
+    AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),
+                  Thread::kNoDeoptId, token_pos, try_index);
   } else if (is_optimizing()) {
     AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId,
                          token_pos);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index fa35f47..6c69c80 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1279,9 +1279,8 @@
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
       try_index = CurrentTryIndex();
     }
-    pc_descriptors_list()->AddDescriptor(
-        RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId,
-        token_pos, try_index);
+    AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),
+                  Thread::kNoDeoptId, token_pos, try_index);
   } else if (is_optimizing()) {
     AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId,
                          token_pos);
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index 39743c5..04240d9 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -135,16 +135,8 @@
 #error Unknown host architecture.
 #endif
 
-
 #endif  // !defined(TARGET_OS_WINDOWS))
 
-// Default value for flag --use-corelib-source-files.
-#if defined(TARGET_OS_WINDOWS)
-static const bool kDefaultCorelibSourceFlag = true;
-#else
-static const bool kDefaultCorelibSourceFlag = false;
-#endif  // defined(TARGET_OS_WINDOWS)
-
 }  // namespace dart
 
 #endif  // RUNTIME_VM_GLOBALS_H_
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 5aa5343..6526aca 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -33,6 +33,7 @@
   }
 
   void Insert(typename KeyValueTrait::Pair kv);
+  bool Remove(typename KeyValueTrait::Key key);
 
   typename KeyValueTrait::Value LookupValue(
       typename KeyValueTrait::Key key) const;
@@ -308,6 +309,68 @@
 }
 
 
+template <typename KeyValueTrait, typename B, typename Allocator>
+bool BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Remove(
+    typename KeyValueTrait::Key key) {
+  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 (array_[pos].next == kNil) {
+      array_[pos] = HashMapListElement();
+    } else {
+      intptr_t next = array_[pos].next;
+      array_[pos] = lists_[next];
+      lists_[next] = HashMapListElement();
+      lists_[next].next = free_list_head_;
+      free_list_head_ = next;
+    }
+    count_--;
+    return true;
+  }
+
+  intptr_t current = array_[pos].next;
+
+  // If there's only the single element in the bucket and it does not match the
+  // key to be removed, just return.
+  if (current == kNil) {
+    return false;
+  }
+
+  // Check the case where the second element in the bucket is the one to be
+  // removed.
+  if (KeyValueTrait::KeyOf(lists_[current].kv) == key) {
+    array_[pos].next = lists_[current].next;
+    lists_[current] = HashMapListElement();
+    lists_[current].next = free_list_head_;
+    free_list_head_ = current;
+    count_--;
+    return true;
+  }
+
+  // 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) {
+    previous = current;
+    current = lists_[current].next;
+
+    if (current == kNil) {
+      // Could not find entry with provided key to remove.
+      return false;
+    }
+  }
+
+  lists_[previous].next = lists_[current].next;
+  lists_[current] = HashMapListElement();
+  lists_[current].next = free_list_head_;
+  free_list_head_ = current;
+  count_--;
+  return true;
+}
+
+
 template <typename KeyValueTrait>
 class DirectChainedHashMap
     : public BaseDirectChainedHashMap<KeyValueTrait, ValueObject> {
diff --git a/runtime/vm/hash_map_test.cc b/runtime/vm/hash_map_test.cc
index b3afdde..2f49b36 100644
--- a/runtime/vm/hash_map_test.cc
+++ b/runtime/vm/hash_map_test.cc
@@ -31,6 +31,9 @@
   EXPECT(map.LookupValue(&v1) == &v1);
   EXPECT(map.LookupValue(&v2) == &v2);
   EXPECT(map.LookupValue(&v3) == &v1);
+  EXPECT(map.Remove(&v1));
+  EXPECT(map.Lookup(&v1) == NULL);
+  map.Insert(&v1);
   DirectChainedHashMap<PointerKeyValueTrait<TestValue> > map2(map);
   EXPECT(map2.LookupValue(&v1) == &v1);
   EXPECT(map2.LookupValue(&v2) == &v2);
@@ -38,6 +41,64 @@
 }
 
 
+TEST_CASE(DirectChainedHashMapInsertRemove) {
+  DirectChainedHashMap<PointerKeyValueTrait<TestValue> > map;
+  EXPECT(map.IsEmpty());
+  TestValue v1(1);
+  TestValue v2(3);  // Note: v1, v2, v3 should have the same hash.
+  TestValue v3(5);
+
+  // Start with adding and removing the same element.
+  map.Insert(&v1);
+  EXPECT(map.LookupValue(&v1) == &v1);
+  EXPECT(map.Remove(&v1));
+  EXPECT(map.Lookup(&v1) == NULL);
+
+  // Inserting v2 first should put it at the head of the list.
+  map.Insert(&v2);
+  map.Insert(&v1);
+  EXPECT(map.LookupValue(&v2) == &v2);
+  EXPECT(map.LookupValue(&v1) == &v1);
+
+  // Check to see if removing the head of the list causes issues.
+  EXPECT(map.Remove(&v2));
+  EXPECT(map.Lookup(&v2) == NULL);
+  EXPECT(map.LookupValue(&v1) == &v1);
+
+  // Reinsert v2, which will place it at the back of the hash map list.
+  map.Insert(&v2);
+  EXPECT(map.LookupValue(&v2) == &v2);
+
+  // Remove from the back of the hash map list.
+  EXPECT(map.Remove(&v2));
+  EXPECT(map.Lookup(&v2) == NULL);
+  EXPECT(map.Remove(&v1));
+  EXPECT(map.Lookup(&v1) == NULL);
+
+  // Check to see that removing an invalid element returns false.
+  EXPECT(!map.Remove(&v1));
+
+  // One last case: remove from the middle of a hash map list.
+  map.Insert(&v1);
+  map.Insert(&v2);
+  map.Insert(&v3);
+
+  EXPECT(map.LookupValue(&v1) == &v1);
+  EXPECT(map.LookupValue(&v2) == &v2);
+  EXPECT(map.LookupValue(&v3) == &v3);
+
+  EXPECT(map.Remove(&v2));
+  EXPECT(map.LookupValue(&v1) == &v1);
+  EXPECT(map.Lookup(&v2) == NULL);
+  EXPECT(map.LookupValue(&v3) == &v3);
+
+  EXPECT(map.Remove(&v1));
+  EXPECT(map.Remove(&v3));
+
+  EXPECT(map.IsEmpty());
+}
+
+
 TEST_CASE(MallocDirectChainedHashMap) {
   MallocDirectChainedHashMap<PointerKeyValueTrait<TestValue> > map;
   EXPECT(map.IsEmpty());
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index d8ce157..d75ad9d3 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -17,6 +17,7 @@
 #include "vm/scavenger.h"
 #include "vm/service.h"
 #include "vm/service_event.h"
+#include "vm/service_isolate.h"
 #include "vm/stack_frame.h"
 #include "vm/tags.h"
 #include "vm/timeline.h"
@@ -402,6 +403,8 @@
     RecordAfterGC(kOld);
     PrintStats();
     NOT_IN_PRODUCT(PrintStatsToTimeline(&tds));
+    // Some Code objects may have been collected so invalidate handler cache.
+    thread->isolate()->handler_info_cache()->Clear();
     EndOldSpaceGC();
   }
 }
@@ -722,7 +725,8 @@
   ASSERT((space == kNew && gc_new_space_in_progress_) ||
          (space == kOld && gc_old_space_in_progress_));
 #ifndef PRODUCT
-  if (FLAG_support_service && Service::gc_stream.enabled()) {
+  if (FLAG_support_service && Service::gc_stream.enabled() &&
+      !ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())) {
     ServiceEvent event(Isolate::Current(), ServiceEvent::kGC);
     event.set_gc_stats(&stats_);
     Service::HandleEvent(&event);
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index 939225f..b594807 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -313,27 +313,27 @@
 }
 
 
-VM_TEST_CASE(BecomeFowardOldToOld) {
+ISOLATE_UNIT_TEST_CASE(BecomeFowardOldToOld) {
   TestBecomeForward(Heap::kOld, Heap::kOld);
 }
 
 
-VM_TEST_CASE(BecomeFowardNewToNew) {
+ISOLATE_UNIT_TEST_CASE(BecomeFowardNewToNew) {
   TestBecomeForward(Heap::kNew, Heap::kNew);
 }
 
 
-VM_TEST_CASE(BecomeFowardOldToNew) {
+ISOLATE_UNIT_TEST_CASE(BecomeFowardOldToNew) {
   TestBecomeForward(Heap::kOld, Heap::kNew);
 }
 
 
-VM_TEST_CASE(BecomeFowardNewToOld) {
+ISOLATE_UNIT_TEST_CASE(BecomeFowardNewToOld) {
   TestBecomeForward(Heap::kNew, Heap::kOld);
 }
 
 
-VM_TEST_CASE(BecomeForwardRememberedObject) {
+ISOLATE_UNIT_TEST_CASE(BecomeForwardRememberedObject) {
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index afe7d11..093970f 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -6400,7 +6400,7 @@
     __ Push(locs->in(0).reg());
     __ Push(locs->in(1).reg());
     __ CallRuntime(kRangeErrorRuntimeEntry, 2);
-    compiler->pc_descriptors_list()->AddDescriptor(
+    compiler->AddDescriptor(
         RawPcDescriptors::kOther, compiler->assembler()->CodeSize(),
         instruction_->deopt_id(), instruction_->token_pos(), try_index_);
     compiler->RecordSafepoint(locs, 2);
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 006dd3b..fa44b58 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -5547,7 +5547,7 @@
     __ Push(locs->in(0).reg());
     __ Push(locs->in(1).reg());
     __ CallRuntime(kRangeErrorRuntimeEntry, 2);
-    compiler->pc_descriptors_list()->AddDescriptor(
+    compiler->AddDescriptor(
         RawPcDescriptors::kOther, compiler->assembler()->CodeSize(),
         instruction_->deopt_id(), instruction_->token_pos(), try_index_);
     compiler->RecordSafepoint(locs, 2);
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 5494f62..fec6937 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -5132,7 +5132,7 @@
     __ Push(locs->in(0).reg());
     __ Push(locs->in(1).reg());
     __ CallRuntime(kRangeErrorRuntimeEntry, 2);
-    compiler->pc_descriptors_list()->AddDescriptor(
+    compiler->AddDescriptor(
         RawPcDescriptors::kOther, compiler->assembler()->CodeSize(),
         instruction_->deopt_id(), instruction_->token_pos(), try_index_);
     __ break_(0);
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 7cebfd7..a835e4c 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -5908,7 +5908,7 @@
     __ pushq(locs->in(0).reg());
     __ pushq(locs->in(1).reg());
     __ CallRuntime(kRangeErrorRuntimeEntry, 2);
-    compiler->pc_descriptors_list()->AddDescriptor(
+    compiler->AddDescriptor(
         RawPcDescriptors::kOther, compiler->assembler()->CodeSize(),
         instruction_->deopt_id(), instruction_->token_pos(), try_index_);
     compiler->RecordSafepoint(locs, 2);
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 99205a7..4c5009b 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -2300,6 +2300,20 @@
   __ Ret();
 }
 
+
+void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) {
+  __ LoadObject(R0, Object::null_object());
+  __ str(R0, Address(THR, Thread::async_stack_trace_offset()));
+  __ Ret();
+}
+
+
+void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) {
+  __ ldr(R0, Address(THR, Thread::async_stack_trace_offset()));
+  __ LoadObject(R0, Object::null_object());
+  __ Ret();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 06f623e..f580138 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -2367,6 +2367,20 @@
   __ ret();
 }
 
+
+void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) {
+  __ LoadObject(R0, Object::null_object());
+  __ str(R0, Address(THR, Thread::async_stack_trace_offset()));
+  __ ret();
+}
+
+
+void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) {
+  __ ldr(R0, Address(THR, Thread::async_stack_trace_offset()));
+  __ LoadObject(R0, Object::null_object());
+  __ ret();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 6c0f6a1..13e47bd 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -2316,6 +2316,20 @@
   __ ret();
 }
 
+
+void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) {
+  __ LoadObject(EAX, Object::null_object());
+  __ movl(Address(THR, Thread::async_stack_trace_offset()), EAX);
+  __ ret();
+}
+
+
+void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) {
+  __ movl(Address(THR, Thread::async_stack_trace_offset()), EAX);
+  __ LoadObject(EAX, Object::null_object());
+  __ ret();
+}
+
 #undef __
 
 }  // namespace dart
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 04707c7..ca95bb5 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -2423,6 +2423,20 @@
   __ delay_slot()->movz(V0, V1, T0);  // V0 = (T0 == 0) ? V1 : V0.
 }
 
+
+void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) {
+  __ LoadObject(V0, Object::null_object());
+  __ sw(V0, Address(THR, Thread::async_stack_trace_offset()));
+  __ Ret();
+}
+
+
+void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) {
+  __ lw(V0, Address(THR, Thread::async_stack_trace_offset()));
+  __ LoadObject(V0, Object::null_object());
+  __ Ret();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index fa250d4..47deca1 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -2279,6 +2279,20 @@
   __ ret();
 }
 
+
+void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) {
+  __ LoadObject(RAX, Object::null_object());
+  __ movq(Address(THR, Thread::async_stack_trace_offset()), RAX);
+  __ ret();
+}
+
+
+void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) {
+  __ movq(Address(THR, Thread::async_stack_trace_offset()), RAX);
+  __ LoadObject(RAX, Object::null_object());
+  __ ret();
+}
+
 #undef __
 
 }  // namespace dart
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index c2a4e54..4cee118 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -845,7 +845,8 @@
       reload_every_n_stack_overflow_checks_(FLAG_reload_every),
       reload_context_(NULL),
       last_reload_timestamp_(OS::GetCurrentTimeMillis()),
-      should_pause_post_service_request_(false) {
+      should_pause_post_service_request_(false),
+      handler_info_cache_() {
   NOT_IN_PRODUCT(FlagsCopyFrom(api_flags));
   // TODO(asiva): A Thread is not available here, need to figure out
   // how the vm_tag (kEmbedderTagId) can be set, these tags need to
@@ -1168,6 +1169,16 @@
     Service::HandleEvent(&runnableEvent);
   }
 #endif  // !PRODUCT
+  GetRunnableLatencyMetric()->set_value(UptimeMicros());
+  if (FLAG_print_benchmarking_metrics) {
+    {
+      StartIsolateScope scope(this);
+      heap()->CollectAllGarbage();
+    }
+    int64_t heap_size = (heap()->UsedInWords(Heap::kNew) * kWordSize) +
+                        (heap()->UsedInWords(Heap::kOld) * kWordSize);
+    GetRunnableHeapSizeMetric()->set_value(heap_size);
+  }
   return true;
 }
 
@@ -1665,13 +1676,12 @@
         "\tisolate:    %s\n",
         name());
   }
-  if (FLAG_print_metrics) {
+  if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) {
     LogBlock lb;
     OS::PrintErr("Printing metrics for %s\n", name());
 #define ISOLATE_METRIC_PRINT(type, variable, name, unit)                       \
   OS::PrintErr("%s\n", metric_##variable##_.ToString());
-
-    ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT);
+    ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT)
 #undef ISOLATE_METRIC_PRINT
     OS::PrintErr("\n");
   }
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index fe4da08..72abde6 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -10,6 +10,8 @@
 #include "vm/atomic.h"
 #include "vm/base_isolate.h"
 #include "vm/class_table.h"
+#include "vm/exceptions.h"
+#include "vm/fixed_cache.h"
 #include "vm/handles.h"
 #include "vm/megamorphic_cache_table.h"
 #include "vm/metrics.h"
@@ -124,6 +126,10 @@
 };
 
 
+// Fixed cache for exception handler lookup.
+typedef FixedCache<intptr_t, ExceptionHandlerInfo, 16> HandlerInfoCache;
+
+
 class Isolate : public BaseIsolate {
  public:
   // Keep both these enums in sync with isolate_patch.dart.
@@ -642,6 +648,8 @@
     return reload_every_n_stack_overflow_checks_;
   }
 
+  HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; }
+
   void MaybeIncreaseReloadEveryNStackOverflowChecks();
 
  private:
@@ -696,7 +704,12 @@
     return mutator_thread()->zone();
   }
 
-  // Accessed from generated code:
+  // Accessed from generated code.
+  // ** This block of fields must come first! **
+  // For AOT cross-compilation, we rely on these members having the same offsets
+  // in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64.
+  // We use only word-sized fields to avoid differences in struct packing on the
+  // different architectures. See also CheckOffsets in dart.cc.
   StoreBuffer* store_buffer_;
   Heap* heap_;
   uword user_tag_;
@@ -831,6 +844,8 @@
   // Should we pause in the debug message loop after this request?
   bool should_pause_post_service_request_;
 
+  HandlerInfoCache handler_info_cache_;
+
   static Dart_IsolateCreateCallback create_callback_;
   static Dart_IsolateShutdownCallback shutdown_callback_;
 
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 43bbd09..53b63e6 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -13,7 +13,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(IsolateCurrent) {
+VM_UNIT_TEST_CASE(IsolateCurrent) {
   Dart_Isolate isolate = Dart_CreateIsolate(
       NULL, NULL, bin::core_isolate_snapshot_data,
       bin::core_isolate_snapshot_instructions, NULL, NULL, NULL);
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index f098998..0f04117 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -210,10 +210,9 @@
 
 
 void JSONStream::PostReply() {
-  Dart_Port port = reply_port();
-  ASSERT(port != ILLEGAL_PORT);
-  set_reply_port(ILLEGAL_PORT);  // Prevent double replies.
   ASSERT(seq_ != NULL);
+  Dart_Port port = reply_port();
+  set_reply_port(ILLEGAL_PORT);  // Prevent double replies.
   if (seq_->IsString()) {
     const String& str = String::Cast(*seq_);
     PrintProperty("id", str.ToCString());
@@ -224,12 +223,22 @@
     const Double& dbl = Double::Cast(*seq_);
     PrintProperty("id", dbl.value());
   } else if (seq_->IsNull()) {
+    if (port == ILLEGAL_PORT) {
+      // This path is only used in tests.
+      buffer_.AddChar('}');  // Finish our message.
+      char* cstr;
+      intptr_t length;
+      Steal(&cstr, &length);
+      OS::PrintErr("-----\nDropping reply:\n%s\n-----\n", cstr);
+      free(cstr);
+    }
     // JSON-RPC 2.0 says that a request with a null ID shouldn't get a reply.
     PostNullReply(port);
     return;
   }
-  buffer_.AddChar('}');
+  ASSERT(port != ILLEGAL_PORT);
 
+  buffer_.AddChar('}');  // Finish our message.
   char* cstr;
   intptr_t length;
   Steal(&cstr, &length);
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index 48dcbde..80ffe1d 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -1177,7 +1177,14 @@
 }
 
 
-Program::~Program() {}
+Program::~Program() {
+  while (valid_token_positions.length() > 0) {
+    delete valid_token_positions.RemoveLast();
+  }
+  while (yield_token_positions.length() > 0) {
+    delete yield_token_positions.RemoveLast();
+  }
+}
 
 
 void Program::AcceptTreeVisitor(TreeVisitor* visitor) {
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index ebdac48..b3450f6 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -9,6 +9,7 @@
 #include "platform/assert.h"
 #include "vm/allocation.h"
 #include "vm/globals.h"
+#include "vm/growable_array.h"
 #include "vm/token_position.h"
 
 
@@ -2727,6 +2728,8 @@
   SourceTable& source_table() { return source_table_; }
   List<Library>& libraries() { return libraries_; }
   Procedure* main_method() { return main_method_; }
+  MallocGrowableArray<MallocGrowableArray<intptr_t>*> valid_token_positions;
+  MallocGrowableArray<MallocGrowableArray<intptr_t>*> yield_token_positions;
 
  private:
   Program() {}
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index a90ad37..c2b8512 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -369,10 +369,36 @@
     }
   }
 
+  void add_token_position(
+      MallocGrowableArray<MallocGrowableArray<intptr_t>*>* list,
+      TokenPosition position) {
+    intptr_t size = list->length();
+    while (size <= current_script_id_) {
+      MallocGrowableArray<intptr_t>* tmp = new MallocGrowableArray<intptr_t>();
+      list->Add(tmp);
+      size = list->length();
+    }
+    list->At(current_script_id_)->Add(position.value());
+  }
+
+  void record_token_position(TokenPosition position) {
+    if (position.IsReal()) {
+      add_token_position(&helper()->program()->valid_token_positions, position);
+    }
+  }
+
+  void record_yield_token_position(TokenPosition position) {
+    add_token_position(&helper()->program()->yield_token_positions, position);
+  }
+
   /**
    * Read and return a TokenPosition from this reader.
+   * @param record specifies whether or not the read position is saved as a
+   * valid token position in the current script.
+   * If not be sure to record it later by calling record_token_position (after
+   * setting the correct current_script_id).
    */
-  TokenPosition ReadPosition() {
+  TokenPosition ReadPosition(bool record = true) {
     // Position is saved as unsigned,
     // but actually ranges from -1 and up (thus the -1)
     intptr_t value = ReadUInt() - 1;
@@ -384,6 +410,9 @@
       min_position_ = Utils::Minimum(min_position_, result);
     }
 
+    if (record) {
+      record_token_position(result);
+    }
     return result;
   }
 
@@ -649,6 +678,10 @@
   source_uri_index_ = reader->ReadUInt();
   reader->set_current_script_id(source_uri_index_);
 
+  int num_imports = reader->ReadUInt();
+  if (num_imports != 0) {
+    FATAL("Deferred imports not implemented in VM");
+  }
   int num_classes = reader->ReadUInt();
   classes().EnsureInitialized(num_classes);
   for (int i = 0; i < num_classes; i++) {
@@ -672,11 +705,12 @@
 Class* Class::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
 
-  position_ = reader->ReadPosition();
+  position_ = reader->ReadPosition(false);
   is_abstract_ = reader->ReadBool();
   name_ = Reference::ReadStringFrom(reader);
   source_uri_index_ = reader->ReadUInt();
   reader->set_current_script_id(source_uri_index_);
+  reader->record_token_position(position_);
   annotations_.ReadFromStatic<Expression>(reader);
 
   return this;
@@ -807,12 +841,14 @@
   Tag tag = reader->ReadTag();
   ASSERT(tag == kField);
 
-  position_ = reader->ReadPosition();
-  end_position_ = reader->ReadPosition();
+  position_ = reader->ReadPosition(false);
+  end_position_ = reader->ReadPosition(false);
   flags_ = reader->ReadFlags();
   name_ = Name::ReadFrom(reader);
   source_uri_index_ = reader->ReadUInt();
   reader->set_current_script_id(source_uri_index_);
+  reader->record_token_position(position_);
+  reader->record_token_position(end_position_);
   annotations_.ReadFromStatic<Expression>(reader);
   type_ = DartType::ReadFrom(reader);
   inferred_value_ = reader->ReadOptional<InferredValue>();
@@ -844,13 +880,15 @@
   ASSERT(tag == kProcedure);
 
   VariableScope<ReaderHelper> parameters(reader->helper());
-  position_ = reader->ReadPosition();
-  end_position_ = reader->ReadPosition();
+  position_ = reader->ReadPosition(false);
+  end_position_ = reader->ReadPosition(false);
   kind_ = static_cast<ProcedureKind>(reader->ReadByte());
   flags_ = reader->ReadFlags();
   name_ = Name::ReadFrom(reader);
   source_uri_index_ = reader->ReadUInt();
   reader->set_current_script_id(source_uri_index_);
+  reader->record_token_position(position_);
+  reader->record_token_position(end_position_);
   annotations_.ReadFromStatic<Expression>(reader);
   function_ = reader->ReadOptional<FunctionNode>();
   return this;
@@ -1660,6 +1698,7 @@
   TRACE_READ_OFFSET();
   YieldStatement* stmt = new YieldStatement();
   stmt->position_ = reader->ReadPosition();
+  reader->record_yield_token_position(stmt->position_);
   stmt->flags_ = reader->ReadByte();
   stmt->expression_ = Expression::ReadFrom(reader);
   return stmt;
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 8d682ab..e10391c 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -5,6 +5,7 @@
 #include "vm/kernel_isolate.h"
 
 #include "vm/compiler.h"
+#include "include/dart_native_api.h"
 #include "vm/dart_api_impl.h"
 #include "vm/dart_entry.h"
 #include "vm/isolate.h"
@@ -33,7 +34,7 @@
             false,
             "Parse scripts with Dart-to-Kernel parser");
 
-const char* KernelIsolate::kName = "kernel-service";
+const char* KernelIsolate::kName = DART_KERNEL_ISOLATE_NAME;
 Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL;
 Monitor* KernelIsolate::monitor_ = new Monitor();
 Isolate* KernelIsolate::isolate_ = NULL;
@@ -73,9 +74,8 @@
     isolate = reinterpret_cast<Isolate*>(create_callback(
         KernelIsolate::kName, NULL, NULL, NULL, &api_flags, NULL, &error));
     if (isolate == NULL) {
-      if (FLAG_trace_kernel) {
-        OS::PrintErr("kernel-service: Isolate creation error: %s\n", error);
-      }
+      OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n",
+                   error);
       KernelIsolate::SetKernelIsolate(NULL);
       KernelIsolate::FinishedInitializing();
       return;
@@ -104,7 +104,7 @@
  protected:
   static void ShutdownIsolate(uword parameter) {
     if (FLAG_trace_kernel) {
-      OS::Print("kernel-service: ShutdownIsolate\n");
+      OS::Print(DART_KERNEL_ISOLATE_NAME ": ShutdownIsolate\n");
     }
     Isolate* I = reinterpret_cast<Isolate*>(parameter);
     ASSERT(KernelIsolate::IsKernelIsolate(I));
@@ -123,18 +123,20 @@
       Error& error = Error::Handle(Z);
       error = T->sticky_error();
       if (!error.IsNull() && !error.IsUnwindError()) {
-        OS::PrintErr("kernel-service: Error: %s\n", error.ToErrorCString());
+        OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n",
+                     error.ToErrorCString());
       }
       error = I->sticky_error();
       if (!error.IsNull() && !error.IsUnwindError()) {
-        OS::PrintErr("kernel-service: Error: %s\n", error.ToErrorCString());
+        OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n",
+                     error.ToErrorCString());
       }
       Dart::RunShutdownCallback();
     }
     // Shut the isolate down.
     Dart::ShutdownIsolate(I);
     if (FLAG_trace_kernel) {
-      OS::Print("kernel-service: Shutdown.\n");
+      OS::Print(DART_KERNEL_ISOLATE_NAME ": Shutdown.\n");
     }
   }
 
@@ -147,9 +149,8 @@
     const Library& root_library =
         Library::Handle(Z, I->object_store()->root_library());
     if (root_library.IsNull()) {
-      if (FLAG_trace_kernel) {
-        OS::Print("kernel-service: Embedder did not install a script.");
-      }
+      OS::Print(DART_KERNEL_ISOLATE_NAME
+                ": Embedder did not install a script.");
       // Kernel isolate is not supported by embedder.
       return false;
     }
@@ -160,9 +161,8 @@
         Z, root_library.LookupFunctionAllowPrivate(entry_name));
     if (entry.IsNull()) {
       // Kernel isolate is not supported by embedder.
-      if (FLAG_trace_kernel) {
-        OS::Print("kernel-service: Embedder did not provide a main function.");
-      }
+      OS::Print(DART_KERNEL_ISOLATE_NAME
+                ": Embedder did not provide a main function.");
       return false;
     }
     ASSERT(!entry.IsNull());
@@ -171,11 +171,10 @@
     ASSERT(!result.IsNull());
     if (result.IsError()) {
       // Kernel isolate did not initialize properly.
-      if (FLAG_trace_kernel) {
-        const Error& error = Error::Cast(result);
-        OS::Print("kernel-service: Calling main resulted in an error: %s",
-                  error.ToErrorCString());
-      }
+      const Error& error = Error::Cast(result);
+      OS::Print(DART_KERNEL_ISOLATE_NAME
+                ": Calling main resulted in an error: %s",
+                error.ToErrorCString());
       return false;
     }
     ASSERT(result.IsReceivePort());
@@ -203,13 +202,13 @@
   ASSERT(I != NULL);
   ASSERT(I->name() != NULL);
   if (!FLAG_use_dart_frontend ||
-      (strstr(I->name(), "kernel-service") == NULL)) {
+      (strstr(I->name(), DART_KERNEL_ISOLATE_NAME) == NULL)) {
     // Not kernel isolate.
     return;
   }
   ASSERT(!Exists());
   if (FLAG_trace_kernel) {
-    OS::Print("kernel-service: InitCallback for %s.\n", I->name());
+    OS::Print(DART_KERNEL_ISOLATE_NAME ": InitCallback for %s.\n", I->name());
   }
   SetKernelIsolate(I);
 }
@@ -238,11 +237,13 @@
   isolate_ = isolate;
 }
 
+
 void KernelIsolate::SetLoadPort(Dart_Port port) {
   MonitorLocker ml(monitor_);
   kernel_port_ = port;
 }
 
+
 void KernelIsolate::FinishedInitializing() {
   MonitorLocker ml(monitor_);
   initializing_ = false;
@@ -261,6 +262,181 @@
   return kernel_port_;
 }
 
+
+class KernelCompilationRequest : public ValueObject {
+ public:
+  KernelCompilationRequest()
+      : monitor_(new Monitor()),
+        port_(Dart_NewNativePort("kernel-compilation-port",
+                                 &HandleResponse,
+                                 false)),
+        next_(NULL),
+        prev_(NULL) {
+    ASSERT(port_ != ILLEGAL_PORT);
+    RegisterRequest(this);
+    result_.status = Dart_KernelCompilationStatus_Unknown;
+    result_.error = NULL;
+    result_.kernel = NULL;
+    result_.kernel_size = 0;
+  }
+
+  ~KernelCompilationRequest() {
+    UnregisterRequest(this);
+    Dart_CloseNativePort(port_);
+    delete monitor_;
+  }
+
+  Dart_KernelCompilationResult SendAndWaitForResponse(Dart_Port kernel_port,
+                                                      const char* script_uri) {
+    // Build the [null, send_port, script_uri] message for the Kernel isolate:
+    // null tag tells it that request came from this code, instead of Loader
+    // so that it can given a more informative response.
+    Dart_CObject tag;
+    tag.type = Dart_CObject_kNull;
+
+    Dart_CObject send_port;
+    send_port.type = Dart_CObject_kSendPort;
+    send_port.value.as_send_port.id = port_;
+    send_port.value.as_send_port.origin_id = ILLEGAL_PORT;
+
+    Dart_CObject uri;
+    uri.type = Dart_CObject_kString;
+    uri.value.as_string = const_cast<char*>(script_uri);
+
+    static const intptr_t kMessageLen = 3;
+    Dart_CObject* message_arr[kMessageLen] = {&tag, &send_port, &uri};
+
+    Dart_CObject message;
+    message.type = Dart_CObject_kArray;
+    message.value.as_array.length = kMessageLen;
+    message.value.as_array.values = message_arr;
+
+    // Send the message.
+    Dart_PostCObject(kernel_port, &message);
+
+    // Wait for reply to arrive.
+    MonitorLocker ml(monitor_);
+    while (result_.status == Dart_KernelCompilationStatus_Unknown) {
+      ml.Wait();
+    }
+
+    return result_;
+  }
+
+ private:
+  // Possible responses from the Kernel isolate:
+  //
+  //     [Ok, Uint8List KernelBinary]
+  //     [Error, String error]
+  //     [Crash, String error]
+  //
+  void HandleResponseImpl(Dart_CObject* message) {
+    ASSERT(message->type == Dart_CObject_kArray);
+    ASSERT(message->value.as_array.length >= 1);
+
+    Dart_CObject** response = message->value.as_array.values;
+
+    MonitorLocker ml(monitor_);
+
+    ASSERT(response[0]->type == Dart_CObject_kInt32);
+    result_.status = static_cast<Dart_KernelCompilationStatus>(
+        message->value.as_array.values[0]->value.as_int32);
+
+    if (result_.status == Dart_KernelCompilationStatus_Ok) {
+      ASSERT(response[1]->type == Dart_CObject_kTypedData);
+      ASSERT(response[1]->value.as_typed_data.type == Dart_TypedData_kUint8);
+
+      result_.kernel_size = response[1]->value.as_typed_data.length;
+      result_.kernel = static_cast<uint8_t*>(malloc(result_.kernel_size));
+      memmove(result_.kernel, response[1]->value.as_typed_data.values,
+              result_.kernel_size);
+    } else {
+      ASSERT(result_.status == Dart_KernelCompilationStatus_Crash ||
+             result_.status == Dart_KernelCompilationStatus_Error);
+      // This is an error.
+      ASSERT(response[1]->type == Dart_CObject_kString);
+      result_.error = strdup(response[1]->value.as_string);
+    }
+    ml.Notify();
+  }
+
+  static void HandleResponse(Dart_Port port, Dart_CObject* message) {
+    MonitorLocker locker(requests_monitor_);
+    KernelCompilationRequest* rq = FindRequestLocked(port);
+    if (rq == NULL) {
+      return;
+    }
+    rq->HandleResponseImpl(message);
+  }
+
+  static void RegisterRequest(KernelCompilationRequest* rq) {
+    MonitorLocker locker(requests_monitor_);
+    rq->next_ = requests_;
+    if (requests_ != NULL) {
+      requests_->prev_ = rq;
+    }
+    requests_ = rq;
+  }
+
+  static void UnregisterRequest(KernelCompilationRequest* rq) {
+    MonitorLocker locker(requests_monitor_);
+    if (rq->next_ != NULL) {
+      rq->next_->prev_ = rq->prev_;
+    }
+    if (rq->prev_ != NULL) {
+      rq->prev_->next_ = rq->next_;
+    } else {
+      requests_ = rq->next_;
+    }
+  }
+
+  // Note: Caller must hold requests_monitor_.
+  static KernelCompilationRequest* FindRequestLocked(Dart_Port port) {
+    for (KernelCompilationRequest* rq = requests_; rq != NULL; rq = rq->next_) {
+      if (rq->port_ == port) {
+        return rq;
+      }
+    }
+    return NULL;
+  }
+
+  // This monitor must be held whenever linked list of requests is accessed.
+  static Monitor* requests_monitor_;
+
+  // Linked list of all active requests. Used to find a request by port number.
+  // Guarded by requests_monitor_ lock.
+  static KernelCompilationRequest* requests_;
+
+  Monitor* monitor_;
+  Dart_Port port_;
+
+  // Linked list of active requests. Guarded by requests_monitor_ lock.
+  KernelCompilationRequest* next_;
+  KernelCompilationRequest* prev_;
+
+  Dart_KernelCompilationResult result_;
+};
+
+Monitor* KernelCompilationRequest::requests_monitor_ = new Monitor();
+KernelCompilationRequest* KernelCompilationRequest::requests_ = NULL;
+
+Dart_KernelCompilationResult KernelIsolate::CompileToKernel(
+    const char* script_uri) {
+  // This must be the main script to be loaded. Wait for Kernel isolate
+  // to finish initialization.
+  Dart_Port kernel_port = WaitForKernelPort();
+  if (kernel_port == ILLEGAL_PORT) {
+    Dart_KernelCompilationResult result;
+    result.status = Dart_KernelCompilationStatus_Unknown;
+    result.error = strdup("Error while initializing Kernel isolate");
+    return result;
+  }
+
+  KernelCompilationRequest request;
+  return request.SendAndWaitForResponse(kernel_port, script_uri);
+}
+
+
 #endif  // DART_PRECOMPILED_RUNTIME
 
 }  // namespace dart
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index 8f54c34..2cbb5f9 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -27,7 +27,7 @@
   static Dart_Port WaitForKernelPort();
   static Dart_Port KernelPort() { return kernel_port_; }
 
-  static bool LoadScript(const String& url, const String& source);
+  static Dart_KernelCompilationResult CompileToKernel(const char* script_uri);
 
  protected:
   static Monitor* monitor_;
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index f0be6f6..b694077 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -227,7 +227,7 @@
     type_parameters = TypeArguments::New(num_type_parameters);
     for (intptr_t i = 0; i < num_type_parameters; i++) {
       parameter = dart::TypeParameter::New(
-          *klass, Function::Handle(Z), i,
+          *klass, Function::Handle(Z), i, 0,
           H.DartSymbol(kernel_klass->type_parameters()[i]->name()), null_bound,
           TokenPosition::kNoSource);
       type_parameters.SetTypeAt(i, parameter);
@@ -450,6 +450,45 @@
   return klass;
 }
 
+static int LowestFirst(const intptr_t* a, const intptr_t* b) {
+  return *a - *b;
+}
+
+/**
+ * If index exists as sublist in list, sort the sublist from lowest to highest,
+ * then copy it, as Smis and without duplicates,
+ * to a new Array in Heap::kOld which is returned.
+ * Note that the source list is both sorted and de-duplicated as well, but will
+ * possibly contain duplicate and unsorted data at the end.
+ * Otherwise (when sublist doesn't exist in list) return new empty array.
+ */
+static RawArray* AsSortedDuplicateFreeArray(
+    intptr_t index,
+    MallocGrowableArray<MallocGrowableArray<intptr_t>*>* list) {
+  if ((index < list->length()) && (list->At(index)->length() > 0)) {
+    MallocGrowableArray<intptr_t>* source = list->At(index);
+    source->Sort(LowestFirst);
+
+    intptr_t size = source->length();
+    intptr_t last = 0;
+    for (intptr_t current = 1; current < size; ++current) {
+      if (source->At(last) != source->At(current)) {
+        (*source)[++last] = source->At(current);
+      }
+    }
+    Array& array_object = Array::Handle();
+    array_object ^= Array::New(last + 1, Heap::kOld);
+    Smi& smi_value = Smi::Handle();
+    for (intptr_t i = 0; i <= last; ++i) {
+      smi_value = Smi::New(source->At(i));
+      array_object.SetAt(i, smi_value);
+    }
+    return array_object.raw();
+  } else {
+    return Array::New(0);
+  }
+}
+
 Script& KernelReader::ScriptAt(intptr_t source_uri_index, String* import_uri) {
   Script& script = Script::ZoneHandle(Z);
   script ^= scripts_.At(source_uri_index);
@@ -477,6 +516,16 @@
       array_object.SetAt(i, value);
     }
     script.set_line_starts(array_object);
+
+    // Create tokens_seen array for the script.
+    array_object ^= AsSortedDuplicateFreeArray(
+        source_uri_index, &program_->valid_token_positions);
+    script.set_debug_positions(array_object);
+
+    // Create yield_positions array for the script.
+    array_object ^= AsSortedDuplicateFreeArray(
+        source_uri_index, &program_->yield_token_positions);
+    script.set_yield_positions(array_object);
   }
   return script;
 }
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 11a84e2..984de1d 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -366,6 +366,20 @@
       // will forward the call to the real function.
       //     -> see BuildGraphOfImplicitClosureFunction
       if (!function.IsImplicitClosureFunction()) {
+        // TODO(jensj): HACK: Push the begin token to after any parameters to
+        // avoid crash when breaking on definition line of async method in
+        // debugger. It seems that another scope needs to be added
+        // in which captures are made, but I can't make that work.
+        // This 'solution' doesn't crash, but I cannot see the parameters at
+        // that particular breakpoint either.
+        // Also push the end token to after the "}" to avoid crashing on
+        // stepping past the last line (to the "}" character).
+        if (node->body() != NULL && node->body()->position().IsReal()) {
+          scope_->set_begin_token_pos(node->body()->position());
+        }
+        if (scope_->end_token_pos().IsReal()) {
+          scope_->set_end_token_pos(scope_->end_token_pos().Next());
+        }
         node_->AcceptVisitor(this);
       }
       break;
@@ -1769,8 +1783,7 @@
 
 void ConstantEvaluator::VisitConditionalExpression(
     ConditionalExpression* node) {
-  EvaluateExpression(node->condition());
-  if (Bool::Cast(result_).value()) {
+  if (EvaluateBooleanExpression(node->condition())) {
     EvaluateExpression(node->then());
   } else {
     EvaluateExpression(node->otherwise());
@@ -1780,34 +1793,29 @@
 
 void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) {
   if (node->op() == LogicalExpression::kAnd) {
-    EvaluateExpression(node->left());
-    if (Bool::Cast(result_).value()) {
-      EvaluateExpression(node->right());
+    if (EvaluateBooleanExpression(node->left())) {
+      EvaluateBooleanExpression(node->right());
     }
   } else {
     ASSERT(node->op() == LogicalExpression::kOr);
-    EvaluateExpression(node->left());
-    if (!Bool::Cast(result_).value()) {
-      EvaluateExpression(node->right());
+    if (!EvaluateBooleanExpression(node->left())) {
+      EvaluateBooleanExpression(node->right());
     }
   }
 }
 
 
 void ConstantEvaluator::VisitNot(Not* node) {
-  EvaluateExpression(node->expression());
-  ASSERT(result_.IsBool());
-  result_ =
-      Bool::Cast(result_).value() ? Bool::False().raw() : Bool::True().raw();
+  result_ ^= Bool::Get(!EvaluateBooleanExpression(node->expression())).raw();
 }
 
 
 void ConstantEvaluator::VisitPropertyGet(PropertyGet* node) {
-  const size_t kLengthLen = strlen("length");
+  const intptr_t kLengthLen = strlen("length");
 
   String* string = node->name()->string();
-  if (string->size() == kLengthLen &&
-      memcmp(string->buffer(), "length", kLengthLen) == 0) {
+  if ((string->size() == kLengthLen) &&
+      (memcmp(string->buffer(), "length", kLengthLen) == 0)) {
     node->receiver()->AcceptExpressionVisitor(this);
     if (result_.IsString()) {
       const dart::String& str =
@@ -2533,12 +2541,26 @@
 
 
 Fragment FlowGraphBuilder::Return(TokenPosition position) {
+  Fragment instructions;
+
+  instructions += CheckReturnTypeInCheckedMode();
+
   Value* value = Pop();
   ASSERT(stack_ == NULL);
-  ReturnInstr* return_instr =
-      new (Z) ReturnInstr(TokenPosition::kNoSource, value);
+
+  const Function& function = parsed_function_->function();
+  if (FLAG_support_debugger && position.IsDebugPause() &&
+      !function.is_native()) {
+    instructions <<=
+        new (Z) DebugStepCheckInstr(position, RawPcDescriptors::kRuntimeCall);
+  }
+
+  ReturnInstr* return_instr = new (Z) ReturnInstr(position, value);
   if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr);
-  return Fragment(return_instr).closed();
+
+  instructions <<= return_instr;
+
+  return instructions.closed();
 }
 
 
@@ -2609,15 +2631,24 @@
     const dart::Field& field,
     bool is_initialization_store,
     StoreBarrierType emit_store_barrier) {
+  Fragment instructions;
+
+  const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
+  instructions += CheckAssignableInCheckedMode(
+      dst_type, dart::String::ZoneHandle(Z, field.name()));
+
   Value* value = Pop();
   if (value->BindsToConstant()) {
     emit_store_barrier = kNoStoreBarrier;
   }
+
   StoreInstanceFieldInstr* store = new (Z)
       StoreInstanceFieldInstr(MayCloneField(Z, field), Pop(), value,
                               emit_store_barrier, TokenPosition::kNoSource);
   store->set_is_initialization(is_initialization_store);
-  return Fragment(store);
+  instructions <<= store;
+
+  return instructions;
 }
 
 
@@ -2662,6 +2693,17 @@
         StoreInstanceField(Context::variable_offset(variable->index()));
   } else {
     Value* value = Pop();
+    if (FLAG_support_debugger && position.IsDebugPause() &&
+        !variable->IsInternal()) {
+      if (value->definition()->IsConstant() ||
+          value->definition()->IsAllocateObject() ||
+          (value->definition()->IsLoadLocal() &&
+           !value->definition()->AsLoadLocal()->local().IsInternal())) {
+        instructions <<= new (Z)
+            DebugStepCheckInstr(position, RawPcDescriptors::kRuntimeCall);
+      }
+    }
+
     StoreLocalInstr* store =
         new (Z) StoreLocalInstr(*variable, value, position);
     instructions <<= store;
@@ -3093,6 +3135,26 @@
     body = Fragment(body.entry, non_null_entry);
   }
 
+  // If we run in checked mode, we have to check the type of the passed
+  // arguments.
+  if (I->type_checks()) {
+    List<VariableDeclaration>& positional = function->positional_parameters();
+    List<VariableDeclaration>& named = function->named_parameters();
+
+    for (intptr_t i = 0; i < positional.length(); i++) {
+      VariableDeclaration* variable = positional[i];
+      body += LoadLocal(LookupVariable(variable));
+      body += CheckVariableTypeInCheckedMode(variable);
+      body += Drop();
+    }
+    for (intptr_t i = 0; i < named.length(); i++) {
+      VariableDeclaration* variable = named[i];
+      body += LoadLocal(LookupVariable(variable));
+      body += CheckVariableTypeInCheckedMode(variable);
+      body += Drop();
+    }
+  }
+
   if (dart_function.is_native()) {
     body += NativeFunctionBody(function, dart_function);
   } else if (function->body() != NULL) {
@@ -3175,6 +3237,32 @@
     context_depth_ = current_context_depth;
   }
 
+  if (FLAG_support_debugger && function->position().IsDebugPause() &&
+      !dart_function.is_native() && dart_function.is_debuggable()) {
+    // If a switch was added above: Start the switch by injecting a debugable
+    // safepoint so stepping over an await works.
+    // If not, still start the body with a debugable safepoint to ensure
+    // breaking on a method always happens, even if there are no
+    // assignments/calls/runtimecalls in the first basic block.
+    // Place this check at the last parameter to ensure parameters
+    // are in scope in the debugger at method entry.
+    const int num_params = dart_function.NumParameters();
+    TokenPosition check_pos = TokenPosition::kNoSource;
+    if (num_params > 0) {
+      LocalScope* scope = parsed_function_->node_sequence()->scope();
+      const LocalVariable& parameter = *scope->VariableAt(num_params - 1);
+      check_pos = parameter.token_pos();
+    }
+    if (!check_pos.IsDebugPause()) {
+      // No parameters or synthetic parameters.
+      check_pos = function->position();
+      ASSERT(check_pos.IsDebugPause());
+    }
+    Fragment check(
+        new (Z) DebugStepCheckInstr(check_pos, RawPcDescriptors::kRuntimeCall));
+    body = check + body;
+  }
+
   normal_entry->LinkTo(body.entry);
 
   // When compiling for OSR, use a depth first search to prune instructions
@@ -3465,6 +3553,97 @@
 }
 
 
+Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
+    VariableDeclaration* variable) {
+  if (I->type_checks()) {
+    const AbstractType& dst_type = T.TranslateType(variable->type());
+    if (dst_type.IsMalformed()) {
+      return ThrowTypeError();
+    }
+    return CheckAssignableInCheckedMode(dst_type,
+                                        H.DartSymbol(variable->name()));
+  }
+  return Fragment();
+}
+
+
+Fragment FlowGraphBuilder::EvaluateAssertion() {
+  const dart::Class& klass = dart::Class::ZoneHandle(
+      Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
+  ASSERT(!klass.IsNull());
+  const dart::Function& target =
+      dart::Function::ZoneHandle(Z, klass.LookupStaticFunctionAllowPrivate(
+                                        H.DartSymbol("_evaluateAssertion")));
+  ASSERT(!target.IsNull());
+  return StaticCall(TokenPosition::kNoSource, target, 1);
+}
+
+
+Fragment FlowGraphBuilder::CheckReturnTypeInCheckedMode() {
+  if (I->type_checks()) {
+    const AbstractType& return_type =
+        AbstractType::Handle(Z, parsed_function_->function().result_type());
+    return CheckAssignableInCheckedMode(return_type, Symbols::FunctionResult());
+  }
+  return Fragment();
+}
+
+
+Fragment FlowGraphBuilder::CheckBooleanInCheckedMode() {
+  Fragment instructions;
+  if (I->type_checks()) {
+    LocalVariable* top_of_stack = MakeTemporary();
+    instructions += LoadLocal(top_of_stack);
+    instructions += AssertBool();
+    instructions += Drop();
+  }
+  return instructions;
+}
+
+
+Fragment FlowGraphBuilder::CheckAssignableInCheckedMode(
+    const dart::AbstractType& dst_type,
+    const dart::String& dst_name) {
+  Fragment instructions;
+  if (I->type_checks() && !dst_type.IsDynamicType() &&
+      !dst_type.IsObjectType()) {
+    LocalVariable* top_of_stack = MakeTemporary();
+    instructions += LoadLocal(top_of_stack);
+    instructions += AssertAssignable(dst_type, dst_name);
+    instructions += Drop();
+  }
+  return instructions;
+}
+
+
+Fragment FlowGraphBuilder::AssertBool() {
+  Value* value = Pop();
+  AssertBooleanInstr* instr =
+      new (Z) AssertBooleanInstr(TokenPosition::kNoSource, value);
+  Push(instr);
+  return Fragment(instr);
+}
+
+
+Fragment FlowGraphBuilder::AssertAssignable(const dart::AbstractType& dst_type,
+                                            const dart::String& dst_name) {
+  Fragment instructions;
+  Value* value = Pop();
+
+  instructions += LoadInstantiatorTypeArguments();
+  Value* type_args = Pop();
+
+  AssertAssignableInstr* instr = new (Z)
+      AssertAssignableInstr(TokenPosition::kNoSource, value, type_args,
+                            dst_type, dst_name, H.thread()->GetNextDeoptId());
+  Push(instr);
+
+  instructions += Fragment(instr);
+
+  return instructions;
+}
+
+
 FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
     const Function& method) {
   // A method extractor is the implicit getter for a method.
@@ -3906,10 +4085,14 @@
 Fragment FlowGraphBuilder::TranslateCondition(Expression* expression,
                                               bool* negate) {
   *negate = expression->IsNot();
+  Fragment instructions;
   if (*negate) {
-    return TranslateExpression(Not::Cast(expression)->expression());
+    instructions += TranslateExpression(Not::Cast(expression)->expression());
+  } else {
+    instructions += TranslateExpression(expression);
   }
-  return TranslateExpression(expression);
+  instructions += CheckBooleanInCheckedMode();
+  return instructions;
 }
 
 
@@ -4300,6 +4483,7 @@
 
 void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
   Fragment instructions = TranslateExpression(node->expression());
+  instructions += CheckVariableTypeInCheckedMode(node->variable());
   instructions +=
       StoreLocal(node->position(), LookupVariable(node->variable()));
   fragment_ = instructions;
@@ -4349,7 +4533,10 @@
     Field* kernel_field = Field::Cast(target);
     const dart::Field& field =
         dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
+    const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
     Fragment instructions = TranslateExpression(node->expression());
+    instructions += CheckAssignableInCheckedMode(
+        dst_type, dart::String::ZoneHandle(Z, field.name()));
     LocalVariable* variable = MakeTemporary();
     instructions += LoadLocal(variable);
     fragment_ = instructions + StoreStaticField(field);
@@ -4620,6 +4807,41 @@
       dart::Class::ZoneHandle(Z, H.LookupClassByKernelClass(kernel_class));
 
   Fragment instructions;
+
+  // Check for malbounded-ness of type.
+  if (I->type_checks()) {
+    List<DartType>& kernel_type_arguments = node->arguments()->types();
+    const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
+        klass, kernel_type_arguments.raw_array(),
+        kernel_type_arguments.length());
+
+    AbstractType& type = AbstractType::Handle(
+        Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
+    type = ClassFinalizer::FinalizeType(klass, type,
+                                        ClassFinalizer::kCanonicalize);
+
+    if (type.IsMalbounded()) {
+      // Evaluate expressions for correctness.
+      List<Expression>& positional = node->arguments()->positional();
+      List<NamedExpression>& named = node->arguments()->named();
+      for (intptr_t i = 0; i < positional.length(); ++i) {
+        instructions += TranslateExpression(positional[i]);
+        instructions += Drop();
+      }
+      for (intptr_t i = 0; i < named.length(); ++i) {
+        instructions += TranslateExpression(named[i]->expression());
+        instructions += Drop();
+      }
+
+      // Throw an error & keep the [Value] on the stack.
+      instructions += ThrowTypeError();
+
+      // Bail out early.
+      fragment_ = instructions;
+      return;
+    }
+  }
+
   if (klass.NumTypeArguments() > 0) {
     List<DartType>& kernel_type_arguments = node->arguments()->types();
     const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
@@ -4824,7 +5046,9 @@
 
 void FlowGraphBuilder::VisitNot(Not* node) {
   Fragment instructions = TranslateExpression(node->expression());
-  fragment_ = instructions + BooleanNegate();
+  instructions += CheckBooleanInCheckedMode();
+  instructions += BooleanNegate();
+  fragment_ = instructions;
 }
 
 
@@ -5084,6 +5308,7 @@
       instructions += Constant(constant_value);
     } else {
       instructions += TranslateExpression(initializer);
+      instructions += CheckVariableTypeInCheckedMode(node);
     }
   }
   instructions += StoreLocal(variable->token_pos(), variable);
@@ -5548,10 +5773,20 @@
   TargetEntryInstr* then;
   TargetEntryInstr* otherwise;
 
-  bool negate;
   Fragment instructions;
-  instructions += TranslateCondition(node->condition(), &negate);
-  instructions += BranchIfTrue(&then, &otherwise, negate);
+  // Asserts can be of the following two kinds:
+  //
+  //    * `assert(expr)`
+  //    * `assert(() { ... })`
+  //
+  // The call to `_AssertionError._evaluateAssertion()` will take care of both
+  // and returns a boolean.
+  instructions += TranslateExpression(node->condition());
+  instructions += PushArgument();
+  instructions += EvaluateAssertion();
+  instructions += CheckBooleanInCheckedMode();
+  instructions += Constant(Bool::True());
+  instructions += BranchIfEqual(&then, &otherwise, false);
 
   const dart::Class& klass = dart::Class::ZoneHandle(
       Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
@@ -5574,10 +5809,7 @@
   otherwise_fragment += LoadLocal(instance);
   otherwise_fragment += PushArgument();  // this
 
-  otherwise_fragment +=
-      node->message() != NULL
-          ? TranslateExpression(node->message())
-          : Constant(H.DartString("<no message>", Heap::kOld));
+  otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
   otherwise_fragment += PushArgument();  // failedAssertion
 
   otherwise_fragment += Constant(url);
@@ -5589,7 +5821,10 @@
   otherwise_fragment += IntConstant(0);
   otherwise_fragment += PushArgument();  // column
 
-  otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
+  otherwise_fragment +=
+      node->message() != NULL
+          ? TranslateExpression(node->message())
+          : Constant(H.DartString("<no message>", Heap::kOld));
   otherwise_fragment += PushArgument();  // message
 
   otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6);
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index 1f374f5..211a61b 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -474,6 +474,18 @@
                                           const Function& constructor,
                                           const Object& argument);
 
+  void AssertBoolInCheckedMode() {
+    if (isolate_->type_checks() && !result_.IsBool()) {
+      translation_helper_.ReportError("Expected boolean expression.");
+    }
+  }
+
+  bool EvaluateBooleanExpression(Expression* expression) {
+    EvaluateExpression(expression);
+    AssertBoolInCheckedMode();
+    return result_.raw() == Bool::True().raw();
+  }
+
   // TODO(27590): Instead of using [dart::kernel::TreeNode]s as keys we
   // should use [TokenPosition]s as well as the existing functionality in
   // `Parser::CacheConstantValue`.
@@ -628,7 +640,6 @@
   void LookupCapturedVariableByName(LocalVariable** variable,
                                     const dart::String& name);
 
-
   struct DepthState {
     explicit DepthState(intptr_t function)
         : loop_(0),
@@ -868,6 +879,17 @@
   Fragment GuardFieldLength(const dart::Field& field, intptr_t deopt_id);
   Fragment GuardFieldClass(const dart::Field& field, intptr_t deopt_id);
 
+  Fragment EvaluateAssertion();
+  Fragment CheckReturnTypeInCheckedMode();
+  Fragment CheckVariableTypeInCheckedMode(VariableDeclaration* variable);
+  Fragment CheckBooleanInCheckedMode();
+  Fragment CheckAssignableInCheckedMode(const dart::AbstractType& dst_type,
+                                        const dart::String& dst_name);
+
+  Fragment AssertBool();
+  Fragment AssertAssignable(const dart::AbstractType& dst_type,
+                            const dart::String& dst_name);
+
   dart::RawFunction* LookupMethodByMember(Member* target,
                                           const dart::String& method_name);
 
diff --git a/runtime/vm/malloc_hooks.cc b/runtime/vm/malloc_hooks.cc
index 65edca7..9e5c658 100644
--- a/runtime/vm/malloc_hooks.cc
+++ b/runtime/vm/malloc_hooks.cc
@@ -2,16 +2,303 @@
 // for 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_USE_TCMALLOC)
+#include "platform/globals.h"
+
+#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
 
 #include "vm/malloc_hooks.h"
 
+#include "gperftools/malloc_hook.h"
+
+#include "platform/assert.h"
+#include "vm/hash_map.h"
+#include "vm/json_stream.h"
+#include "vm/lockers.h"
+
 namespace dart {
 
-void MallocHooks::Init() {
-  // TODO(bkonyi): Implement
+// A locker-type class to automatically grab and release the
+// in_malloc_hook_flag_.
+class MallocHookScope {
+ public:
+  static void InitMallocHookFlag() {
+    ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey);
+    in_malloc_hook_flag_ = OSThread::CreateThreadLocal();
+    OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
+  }
+
+  static void DestroyMallocHookFlag() {
+    ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
+    OSThread::DeleteThreadLocal(in_malloc_hook_flag_);
+    in_malloc_hook_flag_ = kUnsetThreadLocalKey;
+  }
+
+  MallocHookScope() {
+    ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
+    OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
+  }
+
+  ~MallocHookScope() {
+    ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
+    OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
+  }
+
+  static bool IsInHook() {
+    ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
+    return OSThread::GetThreadLocal(in_malloc_hook_flag_);
+  }
+
+ private:
+  static ThreadLocalKey in_malloc_hook_flag_;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
+};
+
+
+// Custom key/value trait specifically for address/size pairs. Unlike
+// RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
+class AddressKeyValueTrait {
+ public:
+  typedef const void* Key;
+  typedef intptr_t Value;
+
+  struct Pair {
+    Key key;
+    Value value;
+    Pair() : key(NULL), value(-1) {}
+    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) { return reinterpret_cast<intptr_t>(key); }
+  static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
+};
+
+
+// Map class that will be used to store mappings between ptr -> allocation size.
+class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
+ public:
+  typedef AddressKeyValueTrait::Key Key;
+  typedef AddressKeyValueTrait::Value Value;
+  typedef AddressKeyValueTrait::Pair Pair;
+
+  inline void Insert(const Key& key, const Value& value) {
+    Pair pair(key, value);
+    MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
+  }
+
+  inline bool Lookup(const Key& key, Value* value) {
+    ASSERT(value != NULL);
+    Pair* pair = MallocDirectChainedHashMap<AddressKeyValueTrait>::Lookup(key);
+    if (pair == NULL) {
+      return false;
+    } else {
+      *value = pair->value;
+      return true;
+    }
+  }
+};
+
+
+class MallocHooksState : public AllStatic {
+ public:
+  static void RecordAllocHook(const void* ptr, size_t size);
+  static void RecordFreeHook(const void* ptr);
+
+  static bool Active() { return active_; }
+  static void Init() {
+    address_map_ = new AddressMap();
+    active_ = true;
+    original_pid_ = OS::ProcessId();
+  }
+
+  static bool IsOriginalProcess() {
+    ASSERT(original_pid_ != kInvalidPid);
+    return original_pid_ == OS::ProcessId();
+  }
+
+  static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; }
+
+  static intptr_t allocation_count() { return allocation_count_; }
+
+  static intptr_t heap_allocated_memory_in_bytes() {
+    return heap_allocated_memory_in_bytes_;
+  }
+
+  static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) {
+    ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+    ASSERT(size >= 0);
+    heap_allocated_memory_in_bytes_ += size;
+    ++allocation_count_;
+  }
+
+  static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) {
+    ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+    ASSERT(size >= 0);
+    ASSERT(heap_allocated_memory_in_bytes_ >= size);
+    heap_allocated_memory_in_bytes_ -= size;
+    --allocation_count_;
+    ASSERT(allocation_count_ >= 0);
+  }
+
+  static AddressMap* address_map() { return address_map_; }
+
+  static void ResetStats() {
+    ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+    allocation_count_ = 0;
+    heap_allocated_memory_in_bytes_ = 0;
+    address_map_->Clear();
+  }
+
+  static void TearDown() {
+    ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
+    active_ = false;
+    original_pid_ = kInvalidPid;
+    ResetStats();
+    delete address_map_;
+  }
+
+ private:
+  static bool active_;
+  static intptr_t original_pid_;
+  static Mutex* malloc_hook_mutex_;
+  static intptr_t allocation_count_;
+  static intptr_t heap_allocated_memory_in_bytes_;
+  static AddressMap* address_map_;
+
+  static const intptr_t kInvalidPid = -1;
+};
+
+
+// MallocHooks state / locks.
+ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
+bool MallocHooksState::active_ = false;
+intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
+Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
+
+// Memory allocation state information.
+intptr_t MallocHooksState::allocation_count_ = 0;
+intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
+AddressMap* MallocHooksState::address_map_ = NULL;
+
+
+void MallocHooks::InitOnce() {
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  ASSERT(!MallocHooksState::Active());
+
+  MallocHookScope::InitMallocHookFlag();
+  MallocHooksState::Init();
+
+  // Register malloc hooks.
+  bool success = false;
+  success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
+  ASSERT(success);
+  success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
+  ASSERT(success);
+}
+
+
+void MallocHooks::TearDown() {
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  ASSERT(MallocHooksState::Active());
+
+  // Remove malloc hooks.
+  bool success = false;
+  success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
+  ASSERT(success);
+  success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
+  ASSERT(success);
+
+  MallocHooksState::TearDown();
+  MallocHookScope::DestroyMallocHookFlag();
+}
+
+
+void MallocHooks::ResetStats() {
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  if (MallocHooksState::Active()) {
+    MallocHooksState::ResetStats();
+  }
+}
+
+
+bool MallocHooks::Active() {
+  ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread());
+  return MallocHooksState::Active();
+}
+
+
+void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
+  intptr_t allocated_memory = 0;
+  intptr_t allocation_count = 0;
+  bool add_usage = false;
+  // AddProperty may call malloc which would result in an attempt
+  // to acquire the lock recursively so we extract the values first
+  // and then add the JSON properties.
+  {
+    MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+    if (Active()) {
+      allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
+      allocation_count = MallocHooksState::allocation_count();
+      add_usage = true;
+    }
+  }
+  if (add_usage) {
+    jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory);
+    jsobj->AddProperty("_heapAllocationCount", allocation_count);
+  }
+}
+
+
+intptr_t MallocHooks::allocation_count() {
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  return MallocHooksState::allocation_count();
+}
+
+
+intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  return MallocHooksState::heap_allocated_memory_in_bytes();
+}
+
+
+void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
+  if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
+    return;
+  }
+
+  // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
+  // again.
+  MallocHookScope mhs;
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  if ((ptr != NULL) && MallocHooksState::Active()) {
+    MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
+    MallocHooksState::address_map()->Insert(ptr, size);
+  }
+}
+
+
+void MallocHooksState::RecordFreeHook(const void* ptr) {
+  if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
+    return;
+  }
+
+  // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
+  // again.
+  MallocHookScope mhs;
+  MutexLocker ml(MallocHooksState::malloc_hook_mutex());
+  if ((ptr != NULL) && MallocHooksState::Active()) {
+    intptr_t size = 0;
+    if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
+      MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
+      MallocHooksState::address_map()->Remove(ptr);
+    }
+  }
 }
 
 }  // namespace dart
 
-#endif  // defined(DART_USE_TCMALLOC)
+#endif  // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
diff --git a/runtime/vm/malloc_hooks.h b/runtime/vm/malloc_hooks.h
index ae09402..78132c7 100644
--- a/runtime/vm/malloc_hooks.h
+++ b/runtime/vm/malloc_hooks.h
@@ -5,16 +5,23 @@
 #ifndef RUNTIME_VM_MALLOC_HOOKS_H_
 #define RUNTIME_VM_MALLOC_HOOKS_H_
 
+#include "vm/allocation.h"
 #include "vm/globals.h"
 
 namespace dart {
 
-class MallocHooks {
-  static void Init();
+class JSONObject;
 
- private:
-  DISALLOW_ALLOCATION();
-  DISALLOW_IMPLICIT_CONSTRUCTORS(MallocHooks);
+class MallocHooks : public AllStatic {
+ public:
+  static void InitOnce();
+  static void TearDown();
+  static void ResetStats();
+  static bool Active();
+  static void PrintToJSONObject(JSONObject* jsobj);
+
+  static intptr_t allocation_count();
+  static intptr_t heap_allocated_memory_in_bytes();
 };
 
 }  // namespace dart
diff --git a/runtime/vm/malloc_hooks_test.cc b/runtime/vm/malloc_hooks_test.cc
new file mode 100644
index 0000000..5054a50
--- /dev/null
+++ b/runtime/vm/malloc_hooks_test.cc
@@ -0,0 +1,80 @@
+// 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.
+
+#include "platform/globals.h"
+
+#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
+
+#include "platform/assert.h"
+#include "vm/class_finalizer.h"
+#include "vm/globals.h"
+#include "vm/malloc_hooks.h"
+#include "vm/symbols.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+static void MallocHookTestBufferInitializer(volatile char* buffer,
+                                            uintptr_t size) {
+  // Run through the buffer and do something. If we don't do this and the memory
+  // in buffer isn't touched, the tcmalloc hooks won't be called.
+  for (uintptr_t i = 0; i < size; ++i) {
+    buffer[i] = i;
+  }
+}
+
+
+UNIT_TEST_CASE(BasicMallocHookTest) {
+  MallocHooks::InitOnce();
+  MallocHooks::ResetStats();
+  EXPECT_EQ(0L, MallocHooks::allocation_count());
+  EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
+  const intptr_t buffer_size = 10;
+  char* buffer = new char[buffer_size];
+  MallocHookTestBufferInitializer(buffer, buffer_size);
+
+  EXPECT_EQ(1L, MallocHooks::allocation_count());
+  EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size),
+            MallocHooks::heap_allocated_memory_in_bytes());
+
+  delete[] buffer;
+  EXPECT_EQ(0L, MallocHooks::allocation_count());
+  EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
+  MallocHooks::TearDown();
+}
+
+
+UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) {
+  MallocHooks::InitOnce();
+  const intptr_t pre_hook_buffer_size = 3;
+  char* pre_hook_buffer = new char[pre_hook_buffer_size];
+  MallocHookTestBufferInitializer(pre_hook_buffer, pre_hook_buffer_size);
+
+  MallocHooks::ResetStats();
+  EXPECT_EQ(0L, MallocHooks::allocation_count());
+  EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
+
+  const intptr_t buffer_size = 10;
+  volatile char* buffer = new char[buffer_size];
+  MallocHookTestBufferInitializer(buffer, buffer_size);
+
+  EXPECT_EQ(1L, MallocHooks::allocation_count());
+  EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size),
+            MallocHooks::heap_allocated_memory_in_bytes());
+
+  delete[] pre_hook_buffer;
+  EXPECT_EQ(1L, MallocHooks::allocation_count());
+  EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size),
+            MallocHooks::heap_allocated_memory_in_bytes());
+
+
+  delete[] buffer;
+  EXPECT_EQ(0L, MallocHooks::allocation_count());
+  EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
+  MallocHooks::TearDown();
+}
+
+};  // namespace dart
+
+#endif  // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
diff --git a/runtime/vm/malloc_hooks_unsupported.cc b/runtime/vm/malloc_hooks_unsupported.cc
index 65edca7..733e3de 100644
--- a/runtime/vm/malloc_hooks_unsupported.cc
+++ b/runtime/vm/malloc_hooks_unsupported.cc
@@ -2,16 +2,48 @@
 // for 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_USE_TCMALLOC)
+#include "platform/globals.h"
+
+#if !defined(DART_USE_TCMALLOC) || defined(PRODUCT)
 
 #include "vm/malloc_hooks.h"
 
 namespace dart {
 
-void MallocHooks::Init() {
-  // TODO(bkonyi): Implement
+void MallocHooks::InitOnce() {
+  // Do nothing.
+}
+
+
+void MallocHooks::TearDown() {
+  // Do nothing.
+}
+
+
+void MallocHooks::ResetStats() {
+  // Do nothing.
+}
+
+
+bool MallocHooks::Active() {
+  return false;
+}
+
+
+void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
+  // Do nothing.
+}
+
+
+intptr_t MallocHooks::allocation_count() {
+  return 0;
+}
+
+
+intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
+  return 0;
 }
 
 }  // namespace dart
 
-#endif  // defined(DART_USE_TCMALLOC)
+#endif  // defined(DART_USE_TCMALLOC) || defined(PRODUCT)
diff --git a/runtime/vm/memory_region_test.cc b/runtime/vm/memory_region_test.cc
index 1f46b18..b0134a2 100644
--- a/runtime/vm/memory_region_test.cc
+++ b/runtime/vm/memory_region_test.cc
@@ -19,7 +19,7 @@
 }
 
 
-UNIT_TEST_CASE(NullRegion) {
+VM_UNIT_TEST_CASE(NullRegion) {
   static const uword kSize = 512;
   MemoryRegion region(NULL, kSize);
   EXPECT(region.pointer() == NULL);
@@ -27,7 +27,7 @@
 }
 
 
-UNIT_TEST_CASE(NewRegion) {
+VM_UNIT_TEST_CASE(NewRegion) {
   static const uword kSize = 1024;
   MemoryRegion region(NewRegion(kSize), kSize);
   EXPECT_EQ(kSize, region.size());
@@ -40,7 +40,7 @@
 }
 
 
-UNIT_TEST_CASE(Subregion) {
+VM_UNIT_TEST_CASE(Subregion) {
   static const uword kSize = 1024;
   static const uword kSubOffset = 128;
   static const uword kSubSize = 512;
@@ -60,7 +60,7 @@
 }
 
 
-UNIT_TEST_CASE(ExtendedRegion) {
+VM_UNIT_TEST_CASE(ExtendedRegion) {
   static const uword kSize = 1024;
   static const uword kSubSize = 512;
   static const uword kExtendSize = 512;
diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc
index 0e636d7..926344b 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -117,7 +117,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_PostMessage) {
+VM_UNIT_TEST_CASE(MessageHandler_PostMessage) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
   EXPECT_EQ(0, handler.notify_count());
@@ -148,7 +148,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_HasOOBMessages) {
+VM_UNIT_TEST_CASE(MessageHandler_HasOOBMessages) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
 
@@ -181,7 +181,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_ClosePort) {
+VM_UNIT_TEST_CASE(MessageHandler_ClosePort) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
   Message* message1 = new Message(1, NULL, 0, Message::kNormalPriority);
@@ -199,7 +199,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_CloseAllPorts) {
+VM_UNIT_TEST_CASE(MessageHandler_CloseAllPorts) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
   Message* message1 = new Message(1, NULL, 0, Message::kNormalPriority);
@@ -214,7 +214,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_HandleNextMessage) {
+VM_UNIT_TEST_CASE(MessageHandler_HandleNextMessage) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
   Dart_Port port1 = PortMap::CreatePort(&handler);
@@ -240,7 +240,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_HandleNextMessage_ProcessOOBAfterError) {
+VM_UNIT_TEST_CASE(MessageHandler_HandleNextMessage_ProcessOOBAfterError) {
   TestMessageHandler handler;
   MessageHandler::MessageStatus results[] = {
       MessageHandler::kError,  // oob_message1
@@ -270,7 +270,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_HandleNextMessage_Shutdown) {
+VM_UNIT_TEST_CASE(MessageHandler_HandleNextMessage_Shutdown) {
   TestMessageHandler handler;
   MessageHandler::MessageStatus results[] = {
       MessageHandler::kOK,        // oob_message1
@@ -308,7 +308,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_HandleOOBMessages) {
+VM_UNIT_TEST_CASE(MessageHandler_HandleOOBMessages) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
   Dart_Port port1 = PortMap::CreatePort(&handler);
@@ -353,7 +353,7 @@
 }
 
 
-UNIT_TEST_CASE(MessageHandler_Run) {
+VM_UNIT_TEST_CASE(MessageHandler_Run) {
   ThreadPool pool;
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
diff --git a/runtime/vm/method_recognizer.cc b/runtime/vm/method_recognizer.cc
index 12694a8..16d25bb 100644
--- a/runtime/vm/method_recognizer.cc
+++ b/runtime/vm/method_recognizer.cc
@@ -141,6 +141,7 @@
   libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
   libs.Add(&Library::ZoneHandle(Library::InternalLibrary()));
   libs.Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
+  libs.Add(&Library::ZoneHandle(Library::AsyncLibrary()));
   Function& func = Function::Handle();
 
 #define SET_RECOGNIZED_KIND(class_name, function_name, enum_name, type, fp)    \
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 1e0a4bc..a744c9b 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -346,7 +346,14 @@
   V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, Dynamic,           \
     0x72f13f7a)                                                                \
 
+#define ASYNC_LIB_INTRINSIC_LIST(V)                                            \
+  V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace,               \
+    Dynamic, 0x2d287286)                                                       \
+  V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace,                   \
+    Dynamic, 0x1d12fcc8)
+
 #define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V)                                  \
+  ASYNC_LIB_INTRINSIC_LIST(V)                                                  \
   CORE_LIB_INTRINSIC_LIST(V)                                                   \
   DEVELOPER_LIB_INTRINSIC_LIST(V)                                              \
   MATH_LIB_INTRINSIC_LIST(V)                                                   \
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index 5a2f5a7..3cf35f6 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -75,6 +75,8 @@
       return "counter";
     case Metric::kByte:
       return "byte";
+    case Metric::kMicrosecond:
+      return "us";
     default:
       UNREACHABLE();
   }
@@ -113,19 +115,32 @@
     case kCounter:
       return zone->PrintToString("%" Pd64 "", value);
     case kByte: {
-      const char* scaled_suffix = "b";
+      const char* scaled_suffix = "B";
       double scaled_value = static_cast<double>(value);
-      if (value > KB) {
-        scaled_suffix = "kb";
-        scaled_value /= KB;
-      } else if (value > MB) {
-        scaled_suffix = "mb";
-        scaled_value /= MB;
-      } else if (value > GB) {
-        scaled_suffix = "gb";
+      if (value > GB) {
+        scaled_suffix = "GB";
         scaled_value /= GB;
+      } else if (value > MB) {
+        scaled_suffix = "MB";
+        scaled_value /= MB;
+      } else if (value > KB) {
+        scaled_suffix = "kB";
+        scaled_value /= KB;
       }
-      return zone->PrintToString("%.3f %s (%" Pd64 ")", scaled_value,
+      return zone->PrintToString("%.3f %s (%" Pd64 " B)", scaled_value,
+                                 scaled_suffix, value);
+    }
+    case kMicrosecond: {
+      const char* scaled_suffix = "us";
+      double scaled_value = static_cast<double>(value);
+      if (value > kMicrosecondsPerSecond) {
+        scaled_suffix = "s";
+        scaled_value /= kMicrosecondsPerSecond;
+      } else if (value > kMicrosecondsPerMillisecond) {
+        scaled_suffix = "ms";
+        scaled_value /= kMicrosecondsPerMillisecond;
+      }
+      return zone->PrintToString("%.3f %s (%" Pd64 " us)", scaled_value,
                                  scaled_suffix, value);
     }
     default:
@@ -140,7 +155,7 @@
   ASSERT(thread != NULL);
   Zone* zone = thread->zone();
   ASSERT(zone != NULL);
-  return zone->PrintToString("%s %s", name(), ValueToString(value(), unit()));
+  return zone->PrintToString("%s %s", name(), ValueToString(Value(), unit()));
 }
 
 
@@ -291,6 +306,11 @@
   return Isolate::IsolateListLength();
 }
 
+
+int64_t MetricPeakRSS::Value() const {
+  return OS::MaxRSS();
+}
+
 #define VM_METRIC_VARIABLE(type, variable, name, unit)                         \
   static type vm_metric_##variable##_;
 VM_METRIC_LIST(VM_METRIC_VARIABLE);
@@ -305,7 +325,7 @@
 }
 
 void Metric::Cleanup() {
-  if (FLAG_print_metrics) {
+  if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) {
     // Create a zone to allocate temporary strings in.
     StackZone sz(Thread::Current());
     OS::PrintErr("Printing metrics for VM\n");
diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h
index fd4449b..6e96170 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -25,16 +25,20 @@
   V(MaxMetric, HeapNewCapacityMax, "heap.new.capacity.max", kByte)             \
   V(MetricHeapNewExternal, HeapNewExternal, "heap.new.external", kByte)        \
   V(MetricHeapUsed, HeapGlobalUsed, "heap.global.used", kByte)                 \
-  V(MaxMetric, HeapGlobalUsedMax, "heap.global.used.max", kByte)
+  V(MaxMetric, HeapGlobalUsedMax, "heap.global.used.max", kByte)               \
+  V(Metric, RunnableLatency, "isolate.runnable.latency", kMicrosecond)         \
+  V(Metric, RunnableHeapSize, "isolate.runnable.heap", kByte)
 
 #define VM_METRIC_LIST(V)                                                      \
-  V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter)
+  V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter)            \
+  V(MetricPeakRSS, PeakRSS, "vm.memory.max", kByte)
 
 class Metric {
  public:
   enum Unit {
     kCounter,
     kByte,
+    kMicrosecond,
   };
 
   Metric();
@@ -168,6 +172,12 @@
 };
 
 
+class MetricPeakRSS : public Metric {
+ protected:
+  virtual int64_t Value() const;
+};
+
+
 class MetricHeapUsed : public Metric {
  protected:
   virtual int64_t Value() const;
diff --git a/runtime/vm/metrics_test.cc b/runtime/vm/metrics_test.cc
index 3892372..6d2e69c 100644
--- a/runtime/vm/metrics_test.cc
+++ b/runtime/vm/metrics_test.cc
@@ -15,7 +15,7 @@
 
 #ifndef PRODUCT
 
-UNIT_TEST_CASE(Metric_Simple) {
+VM_UNIT_TEST_CASE(Metric_Simple) {
   Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data,
                      bin::core_isolate_snapshot_instructions, NULL, NULL, NULL);
   {
@@ -44,7 +44,7 @@
   int64_t LeakyValue() const { return Value(); }
 };
 
-UNIT_TEST_CASE(Metric_OnDemand) {
+VM_UNIT_TEST_CASE(Metric_OnDemand) {
   Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data,
                      bin::core_isolate_snapshot_instructions, NULL, NULL, NULL);
   {
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 865e67f..b8da116 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -47,6 +47,7 @@
 #include "vm/type_table.h"
 #include "vm/unicode.h"
 #include "vm/weak_code.h"
+#include "vm/zone_text_buffer.h"
 
 namespace dart {
 
@@ -4544,7 +4545,10 @@
   hash += hash << 3;
   hash ^= hash >> 11;  // Logical shift, unsigned hash.
   hash += hash << 15;
-  hash &= ((static_cast<uintptr_t>(1) << hashbits) - 1);
+  // FinalizeHash gets called with values for hashbits that are bigger than 31
+  // (like kBitsPerWord - 1).  Therefore we are careful to use a type
+  // (uintptr_t) big enough to avoid undefined behavior with the left shift.
+  hash &= (static_cast<uintptr_t>(1) << hashbits) - 1;
   return (hash == 0) ? 1 : hash;
 }
 
@@ -5158,7 +5162,7 @@
 
 const char* TypeArguments::ToCString() const {
   if (IsNull()) {
-    return "NULL TypeArguments";
+    return "TypeArguments: null";
   }
   Zone* zone = Thread::Current()->zone();
   const char* prev_cstr = OS::SCreate(zone, "TypeArguments: (%" Pd ")",
@@ -5559,16 +5563,25 @@
     // class, then the signature type is not parameterized, although the owner
     // class may be. In this case, the scope class of the function type is reset
     // to _Closure class as well as the owner of the signature function.
+    // With the introduction of generic functions, we may reach here before the
+    // function type parameters have been resolved. Therefore, we cannot yet
+    // check whether the function type has an instantiated signature.
+    // We will do it later when resolving the type.
     Class& scope_class = Class::Handle(Owner());
     if (!scope_class.IsTypedefClass() &&
-        (is_static() || !scope_class.IsGeneric() ||
-         HasInstantiatedSignature())) {
+        (is_static() || !scope_class.IsGeneric())) {
       scope_class = Isolate::Current()->object_store()->closure_class();
       if (IsSignatureFunction()) {
         set_owner(scope_class);
         set_token_pos(TokenPosition::kNoSource);
       }
     }
+    // TODO(regis): With generic functions, this type is not only parameterized
+    // with the type parameters of the scope class, but also with those of all
+    // enclosing generic functions, which may not even have been parsed at this
+    // point. What actually matters is that a signature type can be expressed in
+    // a right-hand side type test by name. This is only possible with a typedef
+    // and the free variables are only the type parameters of the typedef.
     const TypeArguments& signature_type_arguments =
         TypeArguments::Handle(scope_class.type_parameters());
     // Return the still unfinalized signature type.
@@ -5812,6 +5825,13 @@
 void Function::set_result_type(const AbstractType& value) const {
   ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->result_type_, value.raw());
+  if (value.IsFunctionType() && !value.IsResolved()) {
+    // The unresolved function result type may refer to this
+    // function's type parameters. Change its parent function.
+    const Function& result_signature_function =
+        Function::Handle(Type::Cast(value).signature());
+    result_signature_function.set_parent_function(*this);
+  }
 }
 
 
@@ -5885,24 +5905,28 @@
   Function& function = thread->FunctionHandle();
 
   function ^= this->raw();
-  intptr_t parent_level = -1;
+  intptr_t parent_level = 0;
   while (!function.IsNull()) {
     type_params ^= function.type_parameters();
     if (!type_params.IsNull()) {
-      parent_level++;
       const intptr_t num_type_params = type_params.Length();
       for (intptr_t i = 0; i < num_type_params; i++) {
         type_param ^= type_params.TypeAt(i);
         type_param_name = type_param.name();
         if (type_param_name.Equals(type_name)) {
           if (parent_level > 0) {
-            // TODO(regis): Clone type parameter and set parent_level.
+            // Clone type parameter and set parent_level.
+            return TypeParameter::New(
+                Class::Handle(), function, type_param.index(), parent_level,
+                type_param_name, AbstractType::Handle(type_param.bound()),
+                TokenPosition::kNoSource);
           }
           return type_param.raw();
         }
       }
     }
     function ^= function.parent_function();
+    parent_level++;
     if (function_level != NULL) {
       (*function_level)--;
     }
@@ -7040,12 +7064,31 @@
 
 RawString* Function::QualifiedName(NameVisibility name_visibility) const {
   ASSERT(name_visibility != kInternalName);  // We never request it.
+  // If |this| is the generated asynchronous body closure, use the
+  // name of the parent function.
+  Function& fun = Function::Handle(raw());
+  if (fun.IsClosureFunction()) {
+    // Sniff the parent function.
+    fun = fun.parent_function();
+    ASSERT(!fun.IsNull());
+    if (!fun.IsAsyncGenerator() && !fun.IsAsyncFunction() &&
+        !fun.IsSyncGenerator()) {
+      // Parent function is not the generator of an asynchronous body closure,
+      // start at |this|.
+      fun = raw();
+    }
+  }
   // A function's scrubbed name and its user visible name are identical.
-  String& result = String::Handle(UserVisibleName());
+  String& result = String::Handle(fun.UserVisibleName());
   if (IsClosureFunction()) {
-    Function& fun = Function::Handle(raw());
     while (fun.IsLocalFunction() && !fun.IsImplicitClosureFunction()) {
       fun = fun.parent_function();
+      if (fun.IsAsyncClosure() || fun.IsSyncGenClosure() ||
+          fun.IsAsyncGenClosure()) {
+        // Skip the closure and use the real function name found in
+        // the parent.
+        fun = fun.parent_function();
+      }
       result = String::Concat(Symbols::Dot(), result, Heap::kOld);
       result = String::Concat(String::Handle(fun.UserVisibleName()), result,
                               Heap::kOld);
@@ -7227,6 +7270,9 @@
 
 
 const char* Function::ToCString() const {
+  if (IsNull()) {
+    return "Function: null";
+  }
   const char* static_str = is_static() ? " static" : "";
   const char* abstract_str = is_abstract() ? " abstract" : "";
   const char* kind_str = NULL;
@@ -8847,15 +8893,38 @@
     }
     intptr_t line_count = line_starts_array.Length();
     ASSERT(line_count > 0);
+    const Array& debug_positions_array = Array::Handle(debug_positions());
+    intptr_t token_count = debug_positions_array.Length();
+    int token_index = 0;
 
-    for (int i = 0; i < line_count; i++) {
-      info.Add(line_separator);  // New line.
-      value = Smi::New(i + 1);
-      info.Add(value);  // Line number.
-      value ^= line_starts_array.At(i);
-      info.Add(value);  // Token position.
-      value = Smi::New(1);
-      info.Add(value);  // Column.
+    for (int line_index = 0; line_index < line_count; ++line_index) {
+      value ^= line_starts_array.At(line_index);
+      intptr_t start = value.Value();
+      // Output the rest of the tokens if we have no next line.
+      intptr_t end = TokenPosition::kMaxSourcePos;
+      if (line_index + 1 < line_count) {
+        value ^= line_starts_array.At(line_index + 1);
+        end = value.Value();
+      }
+      bool first = true;
+      while (token_index < token_count) {
+        value ^= debug_positions_array.At(token_index);
+        intptr_t debug_position = value.Value();
+        if (debug_position >= end) break;
+
+        if (first) {
+          info.Add(line_separator);          // New line.
+          value = Smi::New(line_index + 1);  // Line number.
+          info.Add(value);
+          first = false;
+        }
+
+        value ^= debug_positions_array.At(token_index);
+        info.Add(value);                               // Token position.
+        value = Smi::New(debug_position - start + 1);  // Column.
+        info.Add(value);
+        ++token_index;
+      }
     }
     return info.raw();
   }
@@ -8976,6 +9045,14 @@
 }
 
 
+void Script::set_debug_positions(const Array& value) const {
+  StorePointer(&raw_ptr()->debug_positions_, value.raw());
+}
+
+void Script::set_yield_positions(const Array& value) const {
+  StorePointer(&raw_ptr()->yield_positions_, value.raw());
+}
+
 void Script::set_kind(RawScript::Kind value) const {
   StoreNonPointer(&raw_ptr()->kind_, value);
 }
@@ -9023,6 +9100,54 @@
 }
 
 
+// Specialized for AOT compilation, which does this lookup for every token
+// position that could be part of a stack trace.
+intptr_t Script::GetTokenLineUsingLineStarts(
+    TokenPosition target_token_pos) const {
+  Zone* zone = Thread::Current()->zone();
+  Array& line_starts_array = Array::Handle(zone, line_starts());
+  Smi& token_pos = Smi::Handle(zone);
+  if (line_starts_array.IsNull()) {
+    ASSERT(kind() != RawScript::kKernelTag);
+    GrowableObjectArray& line_starts_list =
+        GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
+    const TokenStream& tkns = TokenStream::Handle(zone, tokens());
+    TokenStream::Iterator tkit(zone, tkns, TokenPosition::kMinSource,
+                               TokenStream::Iterator::kAllTokens);
+    intptr_t cur_line = line_offset() + 1;
+    token_pos = Smi::New(0);
+    line_starts_list.Add(token_pos);
+    while (tkit.CurrentTokenKind() != Token::kEOS) {
+      if (tkit.CurrentTokenKind() == Token::kNEWLINE) {
+        cur_line++;
+        token_pos = Smi::New(tkit.CurrentPosition().value() + 1);
+        line_starts_list.Add(token_pos);
+      }
+      tkit.Advance();
+    }
+    line_starts_array = Array::MakeArray(line_starts_list);
+    set_line_starts(line_starts_array);
+  }
+
+  ASSERT(line_starts_array.Length() > 0);
+  intptr_t offset = target_token_pos.value();
+  intptr_t min = 0;
+  intptr_t max = line_starts_array.Length() - 1;
+
+  // Binary search to find the line containing this offset.
+  while (min < max) {
+    int midpoint = (max - min + 1) / 2 + min;
+    token_pos ^= line_starts_array.At(midpoint);
+    if (token_pos.Value() > offset) {
+      max = midpoint - 1;
+    } else {
+      min = midpoint;
+    }
+  }
+  return min + 1;  // Line numbers start at 1.
+}
+
+
 void Script::GetTokenLocation(TokenPosition token_pos,
                               intptr_t* line,
                               intptr_t* column,
@@ -9031,7 +9156,7 @@
   Zone* zone = Thread::Current()->zone();
 
   if (kind() == RawScript::kKernelTag) {
-    const Array& line_starts_array = Array::Handle(line_starts());
+    const Array& line_starts_array = Array::Handle(zone, line_starts());
     if (line_starts_array.IsNull()) {
       // Scripts in the AOT snapshot do not have a line starts array.
       *line = -1;
@@ -9045,13 +9170,13 @@
     }
     ASSERT(line_starts_array.Length() > 0);
     intptr_t offset = token_pos.value();
-    int min = 0;
-    int max = line_starts_array.Length() - 1;
+    intptr_t min = 0;
+    intptr_t max = line_starts_array.Length() - 1;
 
     // Binary search to find the line containing this offset.
-    Smi& smi = Smi::Handle();
+    Smi& smi = Smi::Handle(zone);
     while (min < max) {
-      int midpoint = (max - min + 1) / 2 + min;
+      intptr_t midpoint = (max - min + 1) / 2 + min;
 
       smi ^= line_starts_array.At(midpoint);
       if (smi.Value() > offset) {
@@ -9060,12 +9185,14 @@
         min = midpoint;
       }
     }
-    *line = min + 1;
+    *line = min + 1;  // Line numbers start at 1.
     smi ^= line_starts_array.At(min);
     if (column != NULL) {
       *column = offset - smi.Value() + 1;
     }
     if (token_len != NULL) {
+      // We don't explicitly save this data.
+      // TODO(jensj): Load the source and attempt to find it from there.
       *token_len = 1;
     }
     return;
@@ -12041,117 +12168,11 @@
 }
 
 
-TokenPosition CodeSourceMap::TokenPositionForPCOffset(uword pc_offset) const {
-  Iterator iterator(*this);
-
-  TokenPosition result = TokenPosition::kNoSource;
-
-  while (iterator.MoveNext()) {
-    if (iterator.PcOffset() > pc_offset) {
-      break;
-    }
-    result = iterator.TokenPos();
-  }
-
-  return result;
-}
-
-
-RawFunction* CodeSourceMap::FunctionForPCOffset(const Code& code,
-                                                const Function& function,
-                                                uword pc_offset) const {
-  GrowableArray<Function*> inlined_functions;
-  code.GetInlinedFunctionsAt(pc_offset, &inlined_functions);
-  if (inlined_functions.length() > 0) {
-    Function* inlined_function = inlined_functions[0];
-    return inlined_function->raw();
-  } else {
-    return function.raw();
-  }
-}
-
-
-RawScript* CodeSourceMap::ScriptForPCOffset(const Code& code,
-                                            const Function& function,
-                                            uword pc_offset) const {
-  const Function& func =
-      Function::Handle(FunctionForPCOffset(code, function, pc_offset));
-  return func.script();
-}
-
-
-void CodeSourceMap::Dump(const CodeSourceMap& code_source_map,
-                         const Code& code,
-                         const Function& function) {
-  const char* code_name = code.QualifiedName();
-  THR_Print("Dumping Code Source Map for %s\n", code_name);
-  if (code_source_map.Length() == 0) {
-    THR_Print("<empty>\n");
-    return;
-  }
-
-  const int addr_width = kBitsPerWord / 4;
-
-  Iterator iterator(code_source_map);
-  Function& current_function = Function::Handle();
-  Script& current_script = Script::Handle();
-  TokenPosition tp;
-  while (iterator.MoveNext()) {
-    const uword pc_offset = iterator.PcOffset();
-    tp = code_source_map.TokenPositionForPCOffset(pc_offset);
-    current_function ^=
-        code_source_map.FunctionForPCOffset(code, function, pc_offset);
-    current_script ^=
-        code_source_map.ScriptForPCOffset(code, function, pc_offset);
-    if (current_function.IsNull() || current_script.IsNull()) {
-      THR_Print("%#-*" Px "\t%s\t%s\n", addr_width, pc_offset, tp.ToCString(),
-                code_name);
-      continue;
-    }
-    const String& uri = String::Handle(current_script.url());
-    ASSERT(!uri.IsNull());
-    THR_Print("%#-*" Px "\t%s\t%s\t%s\n", addr_width, pc_offset, tp.ToCString(),
-              current_function.ToQualifiedCString(), uri.ToCString());
-  }
-}
-
-
-intptr_t CodeSourceMap::Length() const {
-  return raw_ptr()->length_;
-}
-
-
 void CodeSourceMap::SetLength(intptr_t value) const {
   StoreNonPointer(&raw_ptr()->length_, value);
 }
 
 
-void CodeSourceMap::CopyData(GrowableArray<uint8_t>* delta_encoded_data) {
-  NoSafepointScope no_safepoint;
-  uint8_t* data = UnsafeMutableNonPointer(&raw_ptr()->data()[0]);
-  for (intptr_t i = 0; i < delta_encoded_data->length(); ++i) {
-    data[i] = (*delta_encoded_data)[i];
-  }
-}
-
-
-RawCodeSourceMap* CodeSourceMap::New(GrowableArray<uint8_t>* data) {
-  ASSERT(Object::code_source_map_class() != Class::null());
-  Thread* thread = Thread::Current();
-  CodeSourceMap& result = CodeSourceMap::Handle(thread->zone());
-  {
-    uword size = CodeSourceMap::InstanceSize(data->length());
-    RawObject* raw =
-        Object::Allocate(CodeSourceMap::kClassId, size, Heap::kOld);
-    NoSafepointScope no_safepoint;
-    result ^= raw;
-    result.SetLength(data->length());
-    result.CopyData(data);
-  }
-  return result.raw();
-}
-
-
 RawCodeSourceMap* CodeSourceMap::New(intptr_t length) {
   ASSERT(Object::code_source_map_class() != Class::null());
   Thread* thread = Thread::Current();
@@ -12169,49 +12190,7 @@
 
 
 const char* CodeSourceMap::ToCString() const {
-// "*" in a printf format specifier tells it to read the field width from
-// the printf argument list.
-#define FORMAT "%#-*" Px "\t%s\n"
-  if (Length() == 0) {
-    return "empty CodeSourceMap\n";
-  }
-  // 4 bits per hex digit.
-  const int addr_width = kBitsPerWord / 4;
-  // First compute the buffer size required.
-  intptr_t len = 1;  // Trailing '\0'.
-  {
-    Iterator iter(*this);
-    while (iter.MoveNext()) {
-      len += OS::SNPrint(NULL, 0, FORMAT, addr_width, iter.PcOffset(),
-                         iter.TokenPos().ToCString());
-    }
-  }
-  // Allocate the buffer.
-  char* buffer = Thread::Current()->zone()->Alloc<char>(len);
-  // Layout the fields in the buffer.
-  intptr_t index = 0;
-  Iterator iter(*this);
-  while (iter.MoveNext()) {
-    index += OS::SNPrint((buffer + index), (len - index), FORMAT, addr_width,
-                         iter.PcOffset(), iter.TokenPos().ToCString());
-  }
-  return buffer;
-#undef FORMAT
-}
-
-
-// Encode integer in SLEB128 format.
-void CodeSourceMap::EncodeInteger(GrowableArray<uint8_t>* data,
-                                  intptr_t value) {
-  return EncodeSLEB128(data, value);
-}
-
-
-// Decode SLEB128 encoded integer. Update byte_index to the next integer.
-intptr_t CodeSourceMap::DecodeInteger(intptr_t* byte_index) const {
-  NoSafepointScope no_safepoint;
-  const uint8_t* data = raw_ptr()->data();
-  return DecodeSLEB128(data, Length(), byte_index);
+  return "CodeSourceMap";
 }
 
 
@@ -12392,7 +12371,7 @@
 
 const char* LocalVarDescriptors::ToCString() const {
   if (IsNull()) {
-    return "LocalVarDescriptors(NULL)";
+    return "LocalVarDescriptors: null";
   }
   if (Length() == 0) {
     return "empty LocalVarDescriptors";
@@ -12477,7 +12456,7 @@
                                        bool has_catch_all) const {
   ASSERT((try_index >= 0) && (try_index < num_entries()));
   NoSafepointScope no_safepoint;
-  RawExceptionHandlers::HandlerInfo* info =
+  ExceptionHandlerInfo* info =
       UnsafeMutableNonPointer(&raw_ptr()->data()[try_index]);
   info->outer_try_index = outer_try_index;
   // Some C compilers warn about the comparison always being true when using <=
@@ -12489,9 +12468,8 @@
   info->has_catch_all = has_catch_all;
 }
 
-void ExceptionHandlers::GetHandlerInfo(
-    intptr_t try_index,
-    RawExceptionHandlers::HandlerInfo* info) const {
+void ExceptionHandlers::GetHandlerInfo(intptr_t try_index,
+                                       ExceptionHandlerInfo* info) const {
   ASSERT((try_index >= 0) && (try_index < num_entries()));
   ASSERT(info != NULL);
   *info = raw_ptr()->data()[try_index];
@@ -12601,7 +12579,7 @@
   }
   Array& handled_types = Array::Handle();
   Type& type = Type::Handle();
-  RawExceptionHandlers::HandlerInfo info;
+  ExceptionHandlerInfo info;
   // First compute the buffer size required.
   intptr_t len = 1;  // Trailing '\0'.
   for (intptr_t i = 0; i < num_entries(); i++) {
@@ -13466,7 +13444,13 @@
   const Array& data = Array::Handle(ic_data());
   const intptr_t data_pos =
       index * TestEntryLength() + CountIndexFor(NumArgsTested());
-  return Smi::Value(Smi::RawCast(data.At(data_pos)));
+  intptr_t value = Smi::Value(Smi::RawCast(data.At(data_pos)));
+  if (value >= 0) return value;
+
+  // The counter very rarely overflows to a negative value, but if it does, we
+  // would rather just reset it to zero.
+  SetCountAt(index, 0);
+  return 0;
 }
 
 
@@ -13986,15 +13970,6 @@
 }
 
 
-TokenPosition Code::GetTokenPositionAt(intptr_t offset) const {
-  const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
-  if (map.IsNull()) {
-    return TokenPosition::kNoSource;
-  }
-  return map.TokenPositionForPCOffset(offset);
-}
-
-
 RawTypedData* Code::GetDeoptInfoAtPc(uword pc,
                                      ICData::DeoptReasonId* deopt_reason,
                                      uint32_t* deopt_flags) const {
@@ -14182,127 +14157,14 @@
 }
 
 
-RawArray* Code::GetInlinedIntervals() const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  return Array::null();
-#else
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  if (metadata.IsNull()) {
-    return metadata.raw();
-  }
-  return reinterpret_cast<RawArray*>(
-      metadata.At(RawCode::kInlinedIntervalsIndex));
-#endif
+RawArray* Code::inlined_id_to_function() const {
+  return raw_ptr()->inlined_id_to_function_;
 }
 
 
-void Code::SetInlinedIntervals(const Array& value) const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  UNREACHABLE();
-#else
-  if (raw_ptr()->inlined_metadata_ == Array::null()) {
-    StorePointer(&raw_ptr()->inlined_metadata_,
-                 Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
-  }
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  ASSERT(!metadata.IsNull());
-  ASSERT(metadata.IsOld());
+void Code::set_inlined_id_to_function(const Array& value) const {
   ASSERT(value.IsOld());
-  metadata.SetAt(RawCode::kInlinedIntervalsIndex, value);
-#endif
-}
-
-
-RawArray* Code::GetInlinedIdToFunction() const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  return Array::null();
-#else
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  if (metadata.IsNull()) {
-    return metadata.raw();
-  }
-  return reinterpret_cast<RawArray*>(
-      metadata.At(RawCode::kInlinedIdToFunctionIndex));
-#endif
-}
-
-
-void Code::SetInlinedIdToFunction(const Array& value) const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  UNREACHABLE();
-#else
-  if (raw_ptr()->inlined_metadata_ == Array::null()) {
-    StorePointer(&raw_ptr()->inlined_metadata_,
-                 Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
-  }
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  ASSERT(!metadata.IsNull());
-  ASSERT(metadata.IsOld());
-  ASSERT(value.IsOld());
-  metadata.SetAt(RawCode::kInlinedIdToFunctionIndex, value);
-#endif
-}
-
-
-RawArray* Code::GetInlinedIdToTokenPos() const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  return Array::null();
-#else
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  if (metadata.IsNull()) {
-    return metadata.raw();
-  }
-  return reinterpret_cast<RawArray*>(
-      metadata.At(RawCode::kInlinedIdToTokenPosIndex));
-#endif
-}
-
-
-void Code::SetInlinedIdToTokenPos(const Array& value) const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  UNREACHABLE();
-#else
-  if (raw_ptr()->inlined_metadata_ == Array::null()) {
-    StorePointer(&raw_ptr()->inlined_metadata_,
-                 Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
-  }
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  ASSERT(!metadata.IsNull());
-  ASSERT(metadata.IsOld());
-  ASSERT(value.IsOld());
-  metadata.SetAt(RawCode::kInlinedIdToTokenPosIndex, value);
-#endif
-}
-
-
-RawArray* Code::GetInlinedCallerIdMap() const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  return Array::null();
-#else
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  if (metadata.IsNull()) {
-    return metadata.raw();
-  }
-  return reinterpret_cast<RawArray*>(
-      metadata.At(RawCode::kInlinedCallerIdMapIndex));
-#endif
-}
-
-
-void Code::SetInlinedCallerIdMap(const Array& value) const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  UNREACHABLE();
-#else
-  if (raw_ptr()->inlined_metadata_ == Array::null()) {
-    StorePointer(&raw_ptr()->inlined_metadata_,
-                 Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
-  }
-  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
-  ASSERT(!metadata.IsNull());
-  ASSERT(metadata.IsOld());
-  ASSERT(value.IsOld());
-  metadata.SetAt(RawCode::kInlinedCallerIdMapIndex, value);
-#endif
+  StorePointer(&raw_ptr()->inlined_id_to_function_, value.raw());
 }
 
 
@@ -14661,126 +14523,59 @@
 }
 
 
-intptr_t Code::GetCallerId(intptr_t inlined_id) const {
-  if (inlined_id < 0) {
-    return -1;
+void Code::GetInlinedFunctionsAtInstruction(
+    intptr_t pc_offset,
+    GrowableArray<const Function*>* functions,
+    GrowableArray<TokenPosition>* token_positions) const {
+  const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
+  if (map.IsNull()) {
+    ASSERT(!IsFunctionCode());
+    return;  // VM stub or allocation stub.
   }
-  const Array& map = Array::Handle(GetInlinedCallerIdMap());
-  if (map.IsNull() || (map.Length() == 0)) {
-    return -1;
-  }
-  Smi& smi = Smi::Handle();
-  smi ^= map.At(inlined_id);
-  return smi.Value();
+  const Array& id_map = Array::Handle(inlined_id_to_function());
+  const Function& root = Function::Handle(function());
+  CodeSourceMapReader reader(map, id_map, root);
+  reader.GetInlinedFunctionsAt(pc_offset, functions, token_positions);
 }
 
 
-void Code::GetInlinedFunctionsAt(
-    intptr_t offset,
-    GrowableArray<Function*>* fs,
-    GrowableArray<TokenPosition>* token_positions) const {
-  fs->Clear();
-  if (token_positions != NULL) {
-    token_positions->Clear();
+#ifndef PRODUCT
+void Code::PrintJSONInlineIntervals(JSONObject* jsobj) const {
+  if (!is_optimized()) {
+    return;  // No inlining.
   }
-  const Array& intervals = Array::Handle(GetInlinedIntervals());
-  if (intervals.IsNull() || (intervals.Length() == 0)) {
-    // E.g., for code stubs.
+  const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
+  const Array& id_map = Array::Handle(inlined_id_to_function());
+  const Function& root = Function::Handle(function());
+  CodeSourceMapReader reader(map, id_map, root);
+  reader.PrintJSONInlineIntervals(jsobj);
+}
+#endif
+
+
+void Code::DumpInlineIntervals() const {
+  const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
+  if (map.IsNull()) {
+    // Stub code.
     return;
   }
-  // First find the right interval. TODO(srdjan): use binary search since
-  // intervals are sorted.
-  Smi& start = Smi::Handle();
-  Smi& end = Smi::Handle();
-  intptr_t found_interval_ix = intervals.Length() - Code::kInlIntNumEntries;
-  for (intptr_t i = 0; i < intervals.Length() - Code::kInlIntNumEntries;
-       i += Code::kInlIntNumEntries) {
-    start ^= intervals.At(i + Code::kInlIntStart);
-    if (!start.IsNull()) {
-      end ^= intervals.At(i + Code::kInlIntNumEntries + Code::kInlIntStart);
-      if ((start.Value() <= offset) && (offset < end.Value())) {
-        found_interval_ix = i;
-        break;
-      }
-    }
-  }
-
-  // Find all functions.
-  const Array& id_map = Array::Handle(GetInlinedIdToFunction());
-  const Array& token_pos_map = Array::Handle(GetInlinedIdToTokenPos());
-  Smi& temp_smi = Smi::Handle();
-  temp_smi ^= intervals.At(found_interval_ix + Code::kInlIntInliningId);
-  intptr_t inlining_id = temp_smi.Value();
-  ASSERT(inlining_id >= 0);
-  intptr_t caller_id = GetCallerId(inlining_id);
-  while (inlining_id >= 0) {
-    Function& function = Function::ZoneHandle();
-    function ^= id_map.At(inlining_id);
-    fs->Add(&function);
-    if ((token_positions != NULL) && (inlining_id < token_pos_map.Length())) {
-      temp_smi ^= token_pos_map.At(inlining_id);
-      token_positions->Add(TokenPosition(temp_smi.Value()));
-    }
-    inlining_id = caller_id;
-    caller_id = GetCallerId(inlining_id);
-  }
+  const Array& id_map = Array::Handle(inlined_id_to_function());
+  const Function& root = Function::Handle(function());
+  CodeSourceMapReader reader(map, id_map, root);
+  reader.DumpInlineIntervals(PayloadStart());
 }
 
 
-void Code::DumpInlinedIntervals() const {
-  LogBlock lb;
-  THR_Print("Inlined intervals:\n");
-  const Array& intervals = Array::Handle(GetInlinedIntervals());
-  if (intervals.IsNull() || (intervals.Length() == 0)) return;
-  Smi& start = Smi::Handle();
-  Smi& inlining_id = Smi::Handle();
-  GrowableArray<Function*> inlined_functions;
-  const Function& inliner = Function::Handle(function());
-  for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) {
-    start ^= intervals.At(i + Code::kInlIntStart);
-    ASSERT(!start.IsNull());
-    if (start.IsNull()) continue;
-    inlining_id ^= intervals.At(i + Code::kInlIntInliningId);
-    THR_Print("  %" Px " iid: %" Pd " ; ", start.Value(), inlining_id.Value());
-    inlined_functions.Clear();
-
-    THR_Print("inlined: ");
-    GetInlinedFunctionsAt(start.Value(), &inlined_functions);
-
-    for (intptr_t j = 0; j < inlined_functions.length(); j++) {
-      const char* name = inlined_functions[j]->ToQualifiedCString();
-      THR_Print("  %s <-", name);
-    }
-    if (inlined_functions[inlined_functions.length() - 1]->raw() !=
-        inliner.raw()) {
-      THR_Print(" (ERROR, missing inliner)\n");
-    } else {
-      THR_Print("\n");
-    }
+void Code::DumpSourcePositions() const {
+  const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
+  if (map.IsNull()) {
+    // Stub code.
+    return;
   }
-  THR_Print("Inlined ids:\n");
-  const Array& id_map = Array::Handle(GetInlinedIdToFunction());
-  Function& function = Function::Handle();
-  for (intptr_t i = 0; i < id_map.Length(); i++) {
-    function ^= id_map.At(i);
-    if (!function.IsNull()) {
-      THR_Print("  %" Pd ": %s\n", i, function.ToQualifiedCString());
-    }
-  }
-  THR_Print("Inlined token pos:\n");
-  const Array& token_pos_map = Array::Handle(GetInlinedIdToTokenPos());
-  Smi& smi = Smi::Handle();
-  for (intptr_t i = 0; i < token_pos_map.Length(); i++) {
-    smi ^= token_pos_map.At(i);
-    TokenPosition tp = TokenPosition(smi.Value());
-    THR_Print("  %" Pd ": %s\n", i, tp.ToCString());
-  }
-  THR_Print("Caller Inlining Ids:\n");
-  const Array& caller_map = Array::Handle(GetInlinedCallerIdMap());
-  for (intptr_t i = 0; i < caller_map.Length(); i++) {
-    smi ^= caller_map.At(i);
-    THR_Print("  iid: %" Pd " caller iid: %" Pd "\n", i, smi.Value());
-  }
+  const Array& id_map = Array::Handle(inlined_id_to_function());
+  const Function& root = Function::Handle(function());
+  CodeSourceMapReader reader(map, id_map, root);
+  reader.DumpSourcePositions(PayloadStart());
 }
 
 
@@ -14807,7 +14602,7 @@
 
 const char* Context::ToCString() const {
   if (IsNull()) {
-    return "Context (Null)";
+    return "Context: null";
   }
   Zone* zone = Thread::Current()->zone();
   const Context& parent_ctx = Context::Handle(parent());
@@ -15220,12 +15015,18 @@
 
 
 const char* Error::ToErrorCString() const {
+  if (IsNull()) {
+    return "Error: null";
+  }
   UNREACHABLE();
-  return "Internal Error";
+  return "Error";
 }
 
 
 const char* Error::ToCString() const {
+  if (IsNull()) {
+    return "Error: null";
+  }
   // Error is an abstract class.  We should never reach here.
   UNREACHABLE();
   return "Error";
@@ -15823,6 +15624,9 @@
         Function::Handle(zone, Closure::Cast(*this).function());
     const TypeArguments& type_arguments =
         TypeArguments::Handle(zone, GetTypeArguments());
+    // TODO(regis): If signature function is generic, pass its type parameters
+    // as function instantiator, otherwise pass null.
+    // Pass the closure context as well to the the IsSubtypeOf call.
     return signature.IsSubtypeOf(type_arguments, other_signature,
                                  other_type_arguments, bound_error, Heap::kOld);
   }
@@ -16721,6 +16525,9 @@
 
 
 const char* AbstractType::ToCString() const {
+  if (IsNull()) {
+    return "AbstractType: null";
+  }
   // AbstractType is an abstract class.
   UNREACHABLE();
   return "AbstractType";
@@ -16980,9 +16787,6 @@
   // arguments and not just at the type parameters.
   if (HasResolvedTypeClass()) {
     const Class& cls = Class::Handle(type_class());
-    len = cls.NumTypeArguments();
-    ASSERT(num_type_args >= len);  // The vector may be longer than necessary.
-    num_type_args = len;
     len = cls.NumTypeParameters();  // Check the type parameters only.
   }
   return (len == 0) || args.IsSubvectorInstantiated(num_type_args - len, len);
@@ -17398,7 +17202,7 @@
     SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
     CanonicalTypeSet table(zone, object_store->canonical_types());
     type ^= table.GetOrNull(CanonicalTypeKey(*this));
-    object_store->set_canonical_types(table.Release());
+    ASSERT(object_store->canonical_types() == table.Release().raw());
   }
   if (type.IsNull()) {
     // The type was not found in the table. It is not canonical yet.
@@ -17631,6 +17435,9 @@
 
 
 const char* Type::ToCString() const {
+  if (IsNull()) {
+    return "Type: null";
+  }
   Zone* zone = Thread::Current()->zone();
   const char* unresolved = IsResolved() ? "" : "Unresolved ";
   const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
@@ -17994,7 +17801,7 @@
   // No need to clone bound, as it is not part of the finalization state.
   return TypeParameter::New(Class::Handle(parameterized_class()),
                             Function::Handle(parameterized_function()), index(),
-                            String::Handle(name()),
+                            parent_level(), String::Handle(name()),
                             AbstractType::Handle(bound()), token_pos());
 }
 
@@ -18008,11 +17815,16 @@
     return clone.raw();
   }
   const Class& old_owner = Class::Handle(parameterized_class());
+  if (old_owner.IsNull()) {
+    ASSERT(IsFunctionTypeParameter());
+    // Function type parameters do not need cloning.
+    return raw();
+  }
   const intptr_t new_index =
       index() + new_owner.NumTypeArguments() - old_owner.NumTypeArguments();
   AbstractType& upper_bound = AbstractType::Handle(bound());
   ASSERT(parameterized_function() == Function::null());
-  clone = TypeParameter::New(new_owner, Function::Handle(), new_index,
+  clone = TypeParameter::New(new_owner, Function::Handle(), new_index, 0,
                              String::Handle(name()),
                              upper_bound,  // Not cloned yet.
                              token_pos());
@@ -18063,6 +17875,7 @@
 RawTypeParameter* TypeParameter::New(const Class& parameterized_class,
                                      const Function& parameterized_function,
                                      intptr_t index,
+                                     intptr_t parent_level,
                                      const String& name,
                                      const AbstractType& bound,
                                      TokenPosition token_pos) {
@@ -18071,6 +17884,7 @@
   result.set_parameterized_class(parameterized_class);
   result.set_parameterized_function(parameterized_function);
   result.set_index(index);
+  result.set_parent_level(parent_level);
   result.set_name(name);
   result.set_bound(bound);
   result.SetHash(0);
@@ -18087,7 +17901,9 @@
 }
 
 
-void TypeParameter::set_parent_level(uint8_t value) const {
+void TypeParameter::set_parent_level(intptr_t value) const {
+  // TODO(regis): Report error in caller if not uint8.
+  ASSERT(Utils::IsUint(8, value));
   StoreNonPointer(&raw_ptr()->parent_level_, value);
 }
 
@@ -21917,7 +21733,7 @@
 
 const char* GrowableObjectArray::ToCString() const {
   if (IsNull()) {
-    return "_GrowableList NULL";
+    return "_GrowableList: null";
   }
   return OS::SCreate(Thread::Current()->zone(),
                      "Instance(length:%" Pd ") of '_GrowableList'", Length());
@@ -22522,12 +22338,6 @@
 }
 
 
-RawFunction* StackTrace::FunctionAtFrame(intptr_t frame_index) const {
-  const Code& code = Code::Handle(CodeAtFrame(frame_index));
-  return code.IsNull() ? Function::null() : code.function();
-}
-
-
 RawCode* StackTrace::CodeAtFrame(intptr_t frame_index) const {
   const Array& code_array = Array::Handle(raw_ptr()->code_array_);
   return reinterpret_cast<RawCode*>(code_array.At(frame_index));
@@ -22553,6 +22363,11 @@
 }
 
 
+void StackTrace::set_async_link(const StackTrace& async_link) const {
+  StorePointer(&raw_ptr()->async_link_, async_link.raw());
+}
+
+
 void StackTrace::set_code_array(const Array& code_array) const {
   StorePointer(&raw_ptr()->code_array_, code_array.raw());
 }
@@ -22590,19 +22405,36 @@
 }
 
 
-const char* StackTrace::ToCString() const {
-  intptr_t idx = 0;
-  return ToCStringInternal(&idx);
+RawStackTrace* StackTrace::New(const Array& code_array,
+                               const Array& pc_offset_array,
+                               const StackTrace& async_link,
+                               Heap::Space space) {
+  StackTrace& result = StackTrace::Handle();
+  {
+    RawObject* raw = Object::Allocate(StackTrace::kClassId,
+                                      StackTrace::InstanceSize(), space);
+    NoSafepointScope no_safepoint;
+    result ^= raw;
+  }
+  result.set_async_link(async_link);
+  result.set_code_array(code_array);
+  result.set_pc_offset_array(pc_offset_array);
+  result.set_expand_inlined(true);  // default.
+  return result.raw();
 }
 
 
-static intptr_t PrintOneStackTrace(Zone* zone,
-                                   GrowableArray<char*>* frame_strings,
-                                   uword pc,
-                                   const Function& function,
-                                   const Code& code,
-                                   intptr_t frame_index) {
-  const TokenPosition token_pos = code.GetTokenIndexOfPC(pc);
+const char* StackTrace::ToCString() const {
+  intptr_t idx = 0;
+  return ToCStringInternal(*this, &idx);
+}
+
+
+static void PrintStackTraceFrame(Zone* zone,
+                                 ZoneTextBuffer* buffer,
+                                 const Function& function,
+                                 TokenPosition token_pos,
+                                 intptr_t frame_index) {
   const Script& script = Script::Handle(zone, function.script());
   const String& function_name =
       String::Handle(zone, function.QualifiedUserVisibleName());
@@ -22610,97 +22442,96 @@
       zone, script.IsNull() ? String::New("Kernel") : script.url());
   intptr_t line = -1;
   intptr_t column = -1;
-  if (!script.IsNull() && token_pos.IsReal()) {
-    if (script.HasSource() || script.kind() == RawScript::kKernelTag) {
-      script.GetTokenLocation(token_pos, &line, &column);
-    } else {
-      script.GetTokenLocation(token_pos, &line, NULL);
+  if (FLAG_precompiled_mode) {
+    line = token_pos.value();
+  } else {
+    if (!script.IsNull() && token_pos.IsReal()) {
+      if (script.HasSource() || script.kind() == RawScript::kKernelTag) {
+        script.GetTokenLocation(token_pos, &line, &column);
+      } else {
+        script.GetTokenLocation(token_pos, &line, NULL);
+      }
     }
   }
-  char* chars = NULL;
   if (column >= 0) {
-    chars =
-        OS::SCreate(zone, "#%-6" Pd " %s (%s:%" Pd ":%" Pd ")\n", frame_index,
-                    function_name.ToCString(), url.ToCString(), line, column);
+    buffer->Printf("#%-6" Pd " %s (%s:%" Pd ":%" Pd ")\n", frame_index,
+                   function_name.ToCString(), url.ToCString(), line, column);
   } else if (line >= 0) {
-    chars = OS::SCreate(zone, "#%-6" Pd " %s (%s:%" Pd ")\n", frame_index,
-                        function_name.ToCString(), url.ToCString(), line);
+    buffer->Printf("#%-6" Pd " %s (%s:%" Pd ")\n", frame_index,
+                   function_name.ToCString(), url.ToCString(), line);
   } else {
-    chars = OS::SCreate(zone, "#%-6" Pd " %s (%s)\n", frame_index,
-                        function_name.ToCString(), url.ToCString());
+    buffer->Printf("#%-6" Pd " %s (%s)\n", frame_index,
+                   function_name.ToCString(), url.ToCString());
   }
-  frame_strings->Add(chars);
-  return strlen(chars);
 }
 
 
-const char* StackTrace::ToCStringInternal(intptr_t* frame_index,
-                                          intptr_t max_frames) const {
+const char* StackTrace::ToCStringInternal(const StackTrace& stack_trace_in,
+                                          intptr_t* frame_index,
+                                          intptr_t max_frames) {
   Zone* zone = Thread::Current()->zone();
-  Function& function = Function::Handle();
-  Code& code = Code::Handle();
+  StackTrace& stack_trace = StackTrace::Handle(zone, stack_trace_in.raw());
+  Function& function = Function::Handle(zone);
+  Code& code = Code::Handle(zone);
+  GrowableArray<const Function*> inlined_functions;
+  GrowableArray<TokenPosition> inlined_token_positions;
+  ZoneTextBuffer buffer(zone, 1024);
+
   // Iterate through the stack frames and create C string description
   // for each frame.
-  intptr_t total_len = 0;
-  GrowableArray<char*> frame_strings;
-  for (intptr_t i = 0; (i < Length()) && (*frame_index < max_frames); i++) {
-    function = FunctionAtFrame(i);
-    if (function.IsNull()) {
-      // Check for a null function, which indicates a gap in a StackOverflow or
-      // OutOfMemory trace.
-      if ((i < (Length() - 1)) &&
-          (FunctionAtFrame(i + 1) != Function::null())) {
-        const char* kTruncated = "...\n...\n";
-        intptr_t truncated_len = strlen(kTruncated) + 1;
-        char* chars = zone->Alloc<char>(truncated_len);
-        OS::SNPrint(chars, truncated_len, "%s", kTruncated);
-        frame_strings.Add(chars);
-        total_len += truncated_len;
-        ASSERT(PcOffsetAtFrame(i) != Smi::null());
-        // To account for gap frames.
-        (*frame_index) += Smi::Value(PcOffsetAtFrame(i));
-      }
-    } else {
-      code = CodeAtFrame(i);
-      ASSERT(function.raw() == code.function());
-      uword pc = code.PayloadStart() + Smi::Value(PcOffsetAtFrame(i));
-      if (code.is_optimized() && expand_inlined() &&
-          !FLAG_precompiled_runtime) {
-        // Traverse inlined frames.
-        for (InlinedFunctionsIterator it(code, pc);
-             !it.Done() && (*frame_index < max_frames); it.Advance()) {
-          function = it.function();
-          if (function.is_visible() || FLAG_show_invisible_frames) {
-            code = it.code();
-            ASSERT(function.raw() == code.function());
-            uword pc = it.pc();
-            ASSERT(pc != 0);
-            ASSERT(code.PayloadStart() <= pc);
-            ASSERT(pc < (code.PayloadStart() + code.Size()));
-            total_len += PrintOneStackTrace(zone, &frame_strings, pc, function,
-                                            code, *frame_index);
-            (*frame_index)++;  // To account for inlined frames.
-          }
+  do {
+    for (intptr_t i = 0;
+         (i < stack_trace.Length()) && (*frame_index < max_frames); i++) {
+      code = stack_trace.CodeAtFrame(i);
+      if (code.IsNull()) {
+        // Check for a null function, which indicates a gap in a StackOverflow
+        // or OutOfMemory trace.
+        if ((i < (stack_trace.Length() - 1)) &&
+            (stack_trace.CodeAtFrame(i + 1) != Code::null())) {
+          buffer.AddString("...\n...\n");
+          ASSERT(stack_trace.PcOffsetAtFrame(i) != Smi::null());
+          // To account for gap frames.
+          (*frame_index) += Smi::Value(stack_trace.PcOffsetAtFrame(i));
         }
+      } else if (code.raw() ==
+                 StubCode::AsynchronousGapMarker_entry()->code()) {
+        buffer.AddString("<asynchronous suspension>\n");
+        // The frame immediately after the asynchronous gap marker is the
+        // identical to the frame above the marker. Skip the frame to enhance
+        // the readability of the trace.
+        i++;
       } else {
-        if (function.is_visible() || FLAG_show_invisible_frames) {
-          total_len += PrintOneStackTrace(zone, &frame_strings, pc, function,
-                                          code, *frame_index);
-          (*frame_index)++;
+        ASSERT(code.IsFunctionCode());
+        intptr_t pc_offset = Smi::Value(stack_trace.PcOffsetAtFrame(i));
+        if (code.is_optimized() && stack_trace.expand_inlined()) {
+          code.GetInlinedFunctionsAtReturnAddress(pc_offset, &inlined_functions,
+                                                  &inlined_token_positions);
+          ASSERT(inlined_functions.length() >= 1);
+          for (intptr_t j = inlined_functions.length() - 1; j >= 0; j--) {
+            if (inlined_functions[j]->is_visible() ||
+                FLAG_show_invisible_frames) {
+              PrintStackTraceFrame(zone, &buffer, *inlined_functions[j],
+                                   inlined_token_positions[j], *frame_index);
+              (*frame_index)++;
+            }
+          }
+        } else {
+          function = code.function();
+          if (function.is_visible() || FLAG_show_invisible_frames) {
+            uword pc = code.PayloadStart() + pc_offset;
+            const TokenPosition token_pos = code.GetTokenIndexOfPC(pc);
+            PrintStackTraceFrame(zone, &buffer, function, token_pos,
+                                 *frame_index);
+            (*frame_index)++;
+          }
         }
       }
     }
-  }
+    // Follow the link.
+    stack_trace ^= stack_trace.async_link();
+  } while (!stack_trace.IsNull());
 
-  // Now concatenate the frame descriptions into a single C string.
-  char* chars = zone->Alloc<char>(total_len + 1);
-  intptr_t index = 0;
-  for (intptr_t i = 0; i < frame_strings.length(); i++) {
-    index += OS::SNPrint((chars + index), (total_len + 1 - index), "%s",
-                         frame_strings[i]);
-  }
-  chars[total_len] = '\0';
-  return chars;
+  return buffer.buffer();
 }
 
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index d010ec3..9265649 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2252,6 +2252,9 @@
   }
   void set_type_parameters(const TypeArguments& value) const;
   intptr_t NumTypeParameters(Thread* thread) const;
+  intptr_t NumTypeParameters() const {
+    return NumTypeParameters(Thread::Current());
+  }
 
   // Return a TypeParameter if the type_name is a type parameter of this
   // function or of one of its parent functions.
@@ -3557,6 +3560,12 @@
 
   void set_line_starts(const Array& value) const;
 
+  void set_debug_positions(const Array& value) const;
+
+  void set_yield_positions(const Array& value) const;
+
+  RawArray* yield_positions() const { return raw_ptr()->yield_positions_; }
+
   void Tokenize(const String& private_key, bool use_shared_tokens = true) const;
 
   RawLibrary* FindLibrary() const;
@@ -3570,6 +3579,7 @@
 
   void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const;
 
+  intptr_t GetTokenLineUsingLineStarts(TokenPosition token_pos) const;
   void GetTokenLocation(TokenPosition token_pos,
                         intptr_t* line,
                         intptr_t* column,
@@ -3607,6 +3617,7 @@
   void set_load_timestamp(int64_t value) const;
   void set_tokens(const TokenStream& value) const;
   RawArray* line_starts() const { return raw_ptr()->line_starts_; }
+  RawArray* debug_positions() const { return raw_ptr()->debug_positions_; }
 
   static RawScript* New();
 
@@ -4394,66 +4405,25 @@
     return RoundedAllocationSize(sizeof(RawCodeSourceMap) + len);
   }
 
-  static RawCodeSourceMap* New(GrowableArray<uint8_t>* delta_encoded_data);
+  static RawCodeSourceMap* New(intptr_t length);
+
+  intptr_t Length() const { return raw_ptr()->length_; }
+  uint8_t* Data() const {
+    return UnsafeMutableNonPointer(&raw_ptr()->data()[0]);
+  }
+
+  bool Equals(const CodeSourceMap& other) const {
+    if (Length() != other.Length()) {
+      return false;
+    }
+    NoSafepointScope no_safepoint;
+    return memcmp(raw_ptr(), other.raw_ptr(), InstanceSize(Length())) == 0;
+  }
 
   void PrintToJSONObject(JSONObject* jsobj, bool ref) const;
 
-  // Encode integer in SLEB128 format.
-  static void EncodeInteger(GrowableArray<uint8_t>* data, intptr_t value);
-
-  // Decode SLEB128 encoded integer. Update byte_index to the next integer.
-  intptr_t DecodeInteger(intptr_t* byte_index) const;
-
-  TokenPosition TokenPositionForPCOffset(uword pc_offset) const;
-  RawFunction* FunctionForPCOffset(const Code& code,
-                                   const Function& function,
-                                   uword pc_offset) const;
-  RawScript* ScriptForPCOffset(const Code& code,
-                               const Function& function,
-                               uword pc_offset) const;
-
-  static void Dump(const CodeSourceMap& code_source_map,
-                   const Code& code,
-                   const Function& function);
-
-  class Iterator : ValueObject {
-   public:
-    explicit Iterator(const CodeSourceMap& code_source_map)
-        : code_source_map_(code_source_map),
-          byte_index_(0),
-          cur_pc_offset_(0),
-          cur_token_pos_(0) {}
-
-    bool MoveNext() {
-      // Moves to the next record.
-      while (byte_index_ < code_source_map_.Length()) {
-        cur_pc_offset_ += code_source_map_.DecodeInteger(&byte_index_);
-        cur_token_pos_ += code_source_map_.DecodeInteger(&byte_index_);
-
-        return true;
-      }
-      return false;
-    }
-
-    uword PcOffset() const { return cur_pc_offset_; }
-    TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
-
-   private:
-    friend class CodeSourceMap;
-
-    const CodeSourceMap& code_source_map_;
-    intptr_t byte_index_;
-
-    intptr_t cur_pc_offset_;
-    intptr_t cur_token_pos_;
-  };
-
  private:
-  static RawCodeSourceMap* New(intptr_t length);
-
-  intptr_t Length() const;
   void SetLength(intptr_t value) const;
-  void CopyData(GrowableArray<uint8_t>* data);
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(CodeSourceMap, Object);
   friend class Class;
@@ -4535,8 +4505,7 @@
 
   intptr_t num_entries() const;
 
-  void GetHandlerInfo(intptr_t try_index,
-                      RawExceptionHandlers::HandlerInfo* info) const;
+  void GetHandlerInfo(intptr_t try_index, ExceptionHandlerInfo* info) const;
 
   uword HandlerPCOffset(intptr_t try_index) const;
   intptr_t OuterTryIndex(intptr_t try_index) const;
@@ -4558,9 +4527,8 @@
     return 0;
   }
   static intptr_t InstanceSize(intptr_t len) {
-    return RoundedAllocationSize(
-        sizeof(RawExceptionHandlers) +
-        (len * sizeof(RawExceptionHandlers::HandlerInfo)));
+    return RoundedAllocationSize(sizeof(RawExceptionHandlers) +
+                                 (len * sizeof(ExceptionHandlerInfo)));
   }
 
   static RawExceptionHandlers* New(intptr_t num_handlers);
@@ -4703,28 +4671,18 @@
   }
 
   RawCodeSourceMap* code_source_map() const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-    return CodeSourceMap::null();
-#else
     return raw_ptr()->code_source_map_;
-#endif
   }
 
   void set_code_source_map(const CodeSourceMap& code_source_map) const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-    UNREACHABLE();
-#else
     ASSERT(code_source_map.IsOld());
     StorePointer(&raw_ptr()->code_source_map_, code_source_map.raw());
-#endif
   }
 
   // Used during reloading (see object_reload.cc). Calls Reset on all ICDatas
   // that are embedded inside the Code object.
   void ResetICDatas(Zone* zone) const;
 
-  TokenPosition GetTokenPositionAt(intptr_t offset) const;
-
   // Array of DeoptInfo objects.
   RawArray* deopt_info_array() const {
 #if defined(DART_PRECOMPILED_RUNTIME)
@@ -4819,32 +4777,33 @@
   // Returns -1 if no prologue offset is available.
   intptr_t GetPrologueOffset() const;
 
-  enum InlinedIntervalEntries {
-    kInlIntStart = 0,
-    kInlIntInliningId = 1,
-    kInlIntNumEntries = 2,
-  };
+  RawArray* inlined_id_to_function() const;
+  void set_inlined_id_to_function(const Array& value) const;
 
-  RawArray* GetInlinedIntervals() const;
-  void SetInlinedIntervals(const Array& value) const;
+  // Provides the call stack at the given pc offset, with the top-of-stack in
+  // the last element and the root function (this) as the first element, along
+  // with the corresponding source positions. Note the token position for each
+  // function except the top-of-stack is the position of the call to the next
+  // function. The stack will be empty if we lack the metadata to produce it,
+  // which happens for stub code.
+  // The pc offset is interpreted as an instruction address (as needed by the
+  // disassembler or the top frame of a profiler sample).
+  void GetInlinedFunctionsAtInstruction(
+      intptr_t pc_offset,
+      GrowableArray<const Function*>* functions,
+      GrowableArray<TokenPosition>* token_positions) const;
+  // Same as above, expect the pc is intepreted as a return address (as needed
+  // for a stack trace or the bottom frames of a profiler sample).
+  void GetInlinedFunctionsAtReturnAddress(
+      intptr_t pc_offset,
+      GrowableArray<const Function*>* functions,
+      GrowableArray<TokenPosition>* token_positions) const {
+    GetInlinedFunctionsAtInstruction(pc_offset - 1, functions, token_positions);
+  }
 
-  RawArray* GetInlinedIdToFunction() const;
-  void SetInlinedIdToFunction(const Array& value) const;
-
-  RawArray* GetInlinedIdToTokenPos() const;
-  void SetInlinedIdToTokenPos(const Array& value) const;
-
-  RawArray* GetInlinedCallerIdMap() const;
-  void SetInlinedCallerIdMap(const Array& value) const;
-
-  // If |token_positions| is not NULL it will be populated with the token
-  // positions of the inlined calls.
-  void GetInlinedFunctionsAt(
-      intptr_t offset,
-      GrowableArray<Function*>* fs,
-      GrowableArray<TokenPosition>* token_positions = NULL) const;
-
-  void DumpInlinedIntervals() const;
+  NOT_IN_PRODUCT(void PrintJSONInlineIntervals(JSONObject* object) const);
+  void DumpInlineIntervals() const;
+  void DumpSourcePositions() const;
 
   RawLocalVarDescriptors* var_descriptors() const {
 #if defined(DART_PRECOMPILED_RUNTIME)
@@ -5029,9 +4988,6 @@
     *PointerOffsetAddrAt(index) = offset_in_instructions;
   }
 
-  // Currently slow, as it searches linearly through inlined_intervals().
-  intptr_t GetCallerId(intptr_t inlined_id) const;
-
   intptr_t BinarySearchInSCallTable(uword pc) const;
   static RawCode* LookupCodeInIsolate(Isolate* isolate, uword pc);
 
@@ -6168,6 +6124,7 @@
   static RawTypeParameter* New(const Class& parameterized_class,
                                const Function& parameterized_function,
                                intptr_t index,
+                               intptr_t parent_level,
                                const String& name,
                                const AbstractType& bound,
                                TokenPosition token_pos);
@@ -6180,7 +6137,7 @@
   void set_parameterized_function(const Function& value) const;
   void set_name(const String& value) const;
   void set_token_pos(TokenPosition token_pos) const;
-  void set_parent_level(uint8_t value) const;
+  void set_parent_level(intptr_t value) const;
   void set_type_state(int8_t state) const;
 
   static RawTypeParameter* New();
@@ -8444,14 +8401,17 @@
 
   intptr_t Length() const;
 
-  RawFunction* FunctionAtFrame(intptr_t frame_index) const;
+  RawStackTrace* async_link() const { return raw_ptr()->async_link_; }
+  void set_async_link(const StackTrace& async_link) const;
+  void set_expand_inlined(bool value) const;
 
+  RawArray* code_array() const { return raw_ptr()->code_array_; }
   RawCode* CodeAtFrame(intptr_t frame_index) const;
   void SetCodeAtFrame(intptr_t frame_index, const Code& code) const;
 
+  RawArray* pc_offset_array() const { return raw_ptr()->pc_offset_array_; }
   RawSmi* PcOffsetAtFrame(intptr_t frame_index) const;
   void SetPcOffsetAtFrame(intptr_t frame_index, const Smi& pc_offset) const;
-  void set_expand_inlined(bool value) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawStackTrace));
@@ -8460,9 +8420,15 @@
                             const Array& pc_offset_array,
                             Heap::Space space = Heap::kNew);
 
+  static RawStackTrace* New(const Array& code_array,
+                            const Array& pc_offset_array,
+                            const StackTrace& async_link,
+                            Heap::Space space = Heap::kNew);
+
   // The argument 'max_frames' limits the number of printed frames.
-  const char* ToCStringInternal(intptr_t* frame_index,
-                                intptr_t max_frames = kMaxInt32) const;
+  static const char* ToCStringInternal(const StackTrace& stack_trace,
+                                       intptr_t* frame_index,
+                                       intptr_t max_frames = kMaxInt32);
 
  private:
   void set_code_array(const Array& code_array) const;
diff --git a/runtime/vm/object_graph_test.cc b/runtime/vm/object_graph_test.cc
index f840284..0056bee 100644
--- a/runtime/vm/object_graph_test.cc
+++ b/runtime/vm/object_graph_test.cc
@@ -38,7 +38,7 @@
 };
 
 
-VM_TEST_CASE(ObjectGraph) {
+ISOLATE_UNIT_TEST_CASE(ObjectGraph) {
   Isolate* isolate = thread->isolate();
   // Create a simple object graph with objects a, b, c, d:
   //  a+->b+->c
diff --git a/runtime/vm/object_id_ring_test.cc b/runtime/vm/object_id_ring_test.cc
index cbd3407..f3081b4 100644
--- a/runtime/vm/object_id_ring_test.cc
+++ b/runtime/vm/object_id_ring_test.cc
@@ -50,7 +50,7 @@
 
 
 // Test that serial number wrapping works.
-VM_TEST_CASE(ObjectIdRingSerialWrapTest) {
+ISOLATE_UNIT_TEST_CASE(ObjectIdRingSerialWrapTest) {
   Isolate* isolate = Isolate::Current();
   ObjectIdRing* ring = isolate->object_id_ring();
   ObjectIdRingTestHelper::SetCapacityAndMaxSerial(ring, 2, 4);
@@ -190,7 +190,7 @@
 
 
 // Test that the ring table is updated with nulls when the old GC collects.
-VM_TEST_CASE(ObjectIdRingOldGCTest) {
+ISOLATE_UNIT_TEST_CASE(ObjectIdRingOldGCTest) {
   Isolate* isolate = thread->isolate();
   Heap* heap = isolate->heap();
   ObjectIdRing* ring = isolate->object_id_ring();
@@ -244,7 +244,7 @@
 
 // Test that the ring table correctly reports an entry as expired when it is
 // overridden by new entries.
-VM_TEST_CASE(ObjectIdRingExpiredEntryTest) {
+ISOLATE_UNIT_TEST_CASE(ObjectIdRingExpiredEntryTest) {
   Isolate* isolate = Isolate::Current();
   ObjectIdRing* ring = isolate->object_id_ring();
 
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index d4fc827..31c46cd 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -408,8 +408,7 @@
   } else {
     jsobj.AddProperty("_guardLength", guarded_list_length());
   }
-  const Class& origin_cls = Class::Handle(Origin());
-  const class Script& script = Script::Handle(origin_cls.script());
+  const class Script& script = Script::Handle(Script());
   if (!script.IsNull()) {
     jsobj.AddLocation(script, token_pos());
   }
@@ -865,47 +864,8 @@
     JSONObject desc(&jsobj, "_descriptors");
     descriptors.PrintToJSONObject(&desc, false);
   }
-  const Array& inlined_function_table = Array::Handle(GetInlinedIdToFunction());
-  if (!inlined_function_table.IsNull() &&
-      (inlined_function_table.Length() > 0)) {
-    JSONArray inlined_functions(&jsobj, "_inlinedFunctions");
-    Function& function = Function::Handle();
-    for (intptr_t i = 0; i < inlined_function_table.Length(); i++) {
-      function ^= inlined_function_table.At(i);
-      ASSERT(!function.IsNull());
-      inlined_functions.AddValue(function);
-    }
-  }
-  const Array& intervals = Array::Handle(GetInlinedIntervals());
-  if (!intervals.IsNull() && (intervals.Length() > 0)) {
-    Smi& start = Smi::Handle();
-    Smi& end = Smi::Handle();
-    Smi& temp_smi = Smi::Handle();
-    JSONArray inline_intervals(&jsobj, "_inlinedIntervals");
-    for (intptr_t i = 0; i < intervals.Length() - Code::kInlIntNumEntries;
-         i += Code::kInlIntNumEntries) {
-      start ^= intervals.At(i + Code::kInlIntStart);
-      if (start.IsNull()) {
-        continue;
-      }
-      end ^= intervals.At(i + Code::kInlIntNumEntries + Code::kInlIntStart);
 
-      // Format: [start, end, inline functions...]
-      JSONArray inline_interval(&inline_intervals);
-      inline_interval.AddValue(start.Value());
-      inline_interval.AddValue(end.Value());
-
-      temp_smi ^= intervals.At(i + Code::kInlIntInliningId);
-      intptr_t inlining_id = temp_smi.Value();
-      ASSERT(inlining_id >= 0);
-      intptr_t caller_id = GetCallerId(inlining_id);
-      while (inlining_id >= 0) {
-        inline_interval.AddValue(inlining_id);
-        inlining_id = caller_id;
-        caller_id = GetCallerId(inlining_id);
-      }
-    }
-  }
+  PrintJSONInlineIntervals(&jsobj);
 }
 
 
@@ -1509,7 +1469,7 @@
   jsobj.AddProperty("kind", "StackTrace");
   jsobj.AddServiceId(*this);
   intptr_t idx = 0;
-  jsobj.AddProperty("valueAsString", ToCStringInternal(&idx));
+  jsobj.AddProperty("valueAsString", ToCStringInternal(*this, &idx));
 }
 
 
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index e35ed7a..27c92eb 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -9,6 +9,7 @@
 #include "vm/isolate.h"
 #include "vm/object.h"
 #include "vm/raw_object.h"
+#include "vm/resolver.h"
 #include "vm/symbols.h"
 #include "vm/visitor.h"
 
@@ -93,6 +94,8 @@
       simple_instance_of_function_(Function::null()),
       simple_instance_of_true_function_(Function::null()),
       simple_instance_of_false_function_(Function::null()),
+      async_clear_thread_stack_trace_(Function::null()),
+      async_set_thread_stack_trace_(Function::null()),
       library_load_error_table_(Array::null()),
       unique_dynamic_targets_(Array::null()),
       token_objects_(GrowableObjectArray::null()),
@@ -237,6 +240,21 @@
   ASSERT(!cls.IsNull());
   set_stream_iterator_class(cls);
 
+  String& function_name = String::Handle(zone);
+  Function& function = Function::Handle(zone);
+  function_name ^= async_lib.PrivateName(Symbols::SetAsyncThreadStackTrace());
+  ASSERT(!function_name.IsNull());
+  function ^= Resolver::ResolveStatic(async_lib, Object::null_string(),
+                                      function_name, 1, Object::null_array());
+  set_async_set_thread_stack_trace(function);
+
+  function_name ^= async_lib.PrivateName(Symbols::ClearAsyncThreadStackTrace());
+  ASSERT(!function_name.IsNull());
+  function ^= Resolver::ResolveStatic(async_lib, Object::null_string(),
+                                      function_name, 0, Object::null_array());
+  ASSERT(!function.IsNull());
+  set_async_clear_thread_stack_trace(function);
+
   const Library& internal_lib = Library::Handle(_internal_library());
   cls = internal_lib.LookupClass(Symbols::Symbol());
   set_symbol_class(cls);
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index ab0a384..a144e56 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -438,6 +438,20 @@
   RawFunction* simple_instance_of_false_function() const {
     return simple_instance_of_false_function_;
   }
+  RawFunction* async_clear_thread_stack_trace() const {
+    return async_clear_thread_stack_trace_;
+  }
+  void set_async_clear_thread_stack_trace(const Function& func) {
+    async_clear_thread_stack_trace_ = func.raw();
+    ASSERT(async_clear_thread_stack_trace_ != Object::null());
+  }
+  RawFunction* async_set_thread_stack_trace() const {
+    return async_set_thread_stack_trace_;
+  }
+  void set_async_set_thread_stack_trace(const Function& func) {
+    async_set_thread_stack_trace_ = func.raw();
+    ASSERT(async_set_thread_stack_trace_ != Object::null());
+  }
 
   // Visit all object pointers.
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -540,6 +554,8 @@
   V(RawFunction*, simple_instance_of_function_)                                \
   V(RawFunction*, simple_instance_of_true_function_)                           \
   V(RawFunction*, simple_instance_of_false_function_)                          \
+  V(RawFunction*, async_clear_thread_stack_trace_)                             \
+  V(RawFunction*, async_set_thread_stack_trace_)                               \
   V(RawArray*, library_load_error_table_)                                      \
   V(RawArray*, unique_dynamic_targets_)                                        \
   V(RawGrowableObjectArray*, token_objects_)                                   \
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index f0e9b3f..c435602 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -31,7 +31,7 @@
 }
 
 
-VM_TEST_CASE(Class) {
+ISOLATE_UNIT_TEST_CASE(Class) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
   const Script& script = Script::Handle();
@@ -139,7 +139,7 @@
 }
 
 
-VM_TEST_CASE(TypeArguments) {
+ISOLATE_UNIT_TEST_CASE(TypeArguments) {
   const Type& type1 = Type::Handle(Type::Double());
   const Type& type2 = Type::Handle(Type::StringType());
   const TypeArguments& type_arguments1 =
@@ -161,7 +161,7 @@
 }
 
 
-VM_TEST_CASE(TokenStream) {
+ISOLATE_UNIT_TEST_CASE(TokenStream) {
   Zone* zone = Thread::Current()->zone();
   String& source = String::Handle(zone, String::New("= ( 9 , ."));
   String& private_key = String::Handle(zone, String::New(""));
@@ -179,7 +179,7 @@
 }
 
 
-VM_TEST_CASE(GenerateExactSource) {
+ISOLATE_UNIT_TEST_CASE(GenerateExactSource) {
   // Verify the exact formatting of generated sources.
   const char* kScriptChars =
       "\n"
@@ -247,7 +247,7 @@
 }
 
 
-VM_TEST_CASE(InstanceClass) {
+ISOLATE_UNIT_TEST_CASE(InstanceClass) {
   // Allocate the class first.
   String& class_name = String::Handle(Symbols::New(thread, "EmptyClass"));
   Script& script = Script::Handle();
@@ -293,7 +293,7 @@
 }
 
 
-VM_TEST_CASE(Smi) {
+ISOLATE_UNIT_TEST_CASE(Smi) {
   const Smi& smi = Smi::Handle(Smi::New(5));
   Object& smi_object = Object::Handle(smi.raw());
   EXPECT(smi.IsSmi());
@@ -354,7 +354,7 @@
 }
 
 
-VM_TEST_CASE(StringCompareTo) {
+ISOLATE_UNIT_TEST_CASE(StringCompareTo) {
   const String& abcd = String::Handle(String::New("abcd"));
   const String& abce = String::Handle(String::New("abce"));
   EXPECT_EQ(0, abcd.CompareTo(abcd));
@@ -397,7 +397,7 @@
 }
 
 
-VM_TEST_CASE(StringEncodeIRI) {
+ISOLATE_UNIT_TEST_CASE(StringEncodeIRI) {
   const char* kInput =
       "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
   const char* kOutput =
@@ -409,7 +409,7 @@
 }
 
 
-VM_TEST_CASE(StringDecodeIRI) {
+ISOLATE_UNIT_TEST_CASE(StringDecodeIRI) {
   const char* kOutput =
       "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
   const char* kInput =
@@ -422,7 +422,7 @@
 }
 
 
-VM_TEST_CASE(StringDecodeIRIInvalid) {
+ISOLATE_UNIT_TEST_CASE(StringDecodeIRIInvalid) {
   String& input = String::Handle();
   input = String::New("file%");
   String& decoded = String::Handle();
@@ -437,7 +437,7 @@
 }
 
 
-VM_TEST_CASE(StringIRITwoByte) {
+ISOLATE_UNIT_TEST_CASE(StringIRITwoByte) {
   const intptr_t kInputLen = 3;
   const uint16_t kInput[kInputLen] = {'x', '/', 256};
   const String& input = String::Handle(String::FromUTF16(kInput, kInputLen));
@@ -452,7 +452,7 @@
 }
 
 
-VM_TEST_CASE(Mint) {
+ISOLATE_UNIT_TEST_CASE(Mint) {
 // On 64-bit architectures a Smi is stored in a 64 bit word. A Midint cannot
 // be allocated if it does fit into a Smi.
 #if !defined(ARCH_IS_64_BIT)
@@ -526,7 +526,7 @@
 }
 
 
-VM_TEST_CASE(Double) {
+ISOLATE_UNIT_TEST_CASE(Double) {
   {
     const double dbl_const = 5.0;
     const Double& dbl = Double::Handle(Double::New(dbl_const));
@@ -610,7 +610,7 @@
 }
 
 
-VM_TEST_CASE(Bigint) {
+ISOLATE_UNIT_TEST_CASE(Bigint) {
   Bigint& b = Bigint::Handle();
   EXPECT(b.IsNull());
   const char* cstr = "18446744073709551615000";
@@ -649,7 +649,7 @@
 }
 
 
-VM_TEST_CASE(Integer) {
+ISOLATE_UNIT_TEST_CASE(Integer) {
   Integer& i = Integer::Handle();
   i = Integer::NewCanonical(String::Handle(String::New("12")));
   EXPECT(i.IsSmi());
@@ -666,7 +666,7 @@
 }
 
 
-VM_TEST_CASE(String) {
+ISOLATE_UNIT_TEST_CASE(String) {
   const char* kHello = "Hello World!";
   int32_t hello_len = strlen(kHello);
   const String& str = String::Handle(String::New(kHello));
@@ -813,7 +813,7 @@
 }
 
 
-VM_TEST_CASE(StringFormat) {
+ISOLATE_UNIT_TEST_CASE(StringFormat) {
   const char* hello_str = "Hello World!";
   const String& str =
       String::Handle(String::NewFormatted("Hello %s!", "World"));
@@ -826,7 +826,7 @@
 }
 
 
-VM_TEST_CASE(StringConcat) {
+ISOLATE_UNIT_TEST_CASE(StringConcat) {
   // Create strings from concatenated 1-byte empty strings.
   {
     const String& empty1 = String::Handle(String::New(""));
@@ -1357,7 +1357,7 @@
 }
 
 
-VM_TEST_CASE(StringHashConcat) {
+ISOLATE_UNIT_TEST_CASE(StringHashConcat) {
   EXPECT_EQ(String::Handle(String::New("onebyte")).Hash(),
             String::HashConcat(String::Handle(String::New("one")),
                                String::Handle(String::New("byte"))));
@@ -1373,7 +1373,7 @@
 }
 
 
-VM_TEST_CASE(StringSubStringDifferentWidth) {
+ISOLATE_UNIT_TEST_CASE(StringSubStringDifferentWidth) {
   // Create 1-byte substring from a 1-byte source string.
   const char* onechars = "\xC3\xB6\xC3\xB1\xC3\xA9";
 
@@ -1434,7 +1434,7 @@
 }
 
 
-VM_TEST_CASE(StringFromUtf8Literal) {
+ISOLATE_UNIT_TEST_CASE(StringFromUtf8Literal) {
   // Create a 1-byte string from a UTF-8 encoded string literal.
   {
     const char* src =
@@ -1594,7 +1594,7 @@
 }
 
 
-VM_TEST_CASE(StringEqualsUtf8) {
+ISOLATE_UNIT_TEST_CASE(StringEqualsUtf8) {
   const char* onesrc = "abc";
   const String& onestr = String::Handle(String::New(onesrc));
   EXPECT(onestr.IsOneByteString());
@@ -1626,7 +1626,7 @@
 }
 
 
-VM_TEST_CASE(StringEqualsUTF32) {
+ISOLATE_UNIT_TEST_CASE(StringEqualsUTF32) {
   const String& empty = String::Handle(String::New(""));
   const String& t_str = String::Handle(String::New("t"));
   const String& th_str = String::Handle(String::New("th"));
@@ -1643,7 +1643,7 @@
 }
 
 
-VM_TEST_CASE(ExternalOneByteString) {
+ISOLATE_UNIT_TEST_CASE(ExternalOneByteString) {
   uint8_t characters[] = {0xF6, 0xF1, 0xE9};
   intptr_t len = ARRAY_SIZE(characters);
 
@@ -1674,7 +1674,7 @@
 }
 
 
-VM_TEST_CASE(EscapeSpecialCharactersOneByteString) {
+ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersOneByteString) {
   uint8_t characters[] = {'a',  '\n', '\f', '\b', '\t',
                           '\v', '\r', '\\', '$',  'z'};
   intptr_t len = ARRAY_SIZE(characters);
@@ -1694,7 +1694,7 @@
 }
 
 
-VM_TEST_CASE(EscapeSpecialCharactersExternalOneByteString) {
+ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersExternalOneByteString) {
   uint8_t characters[] = {'a',  '\n', '\f', '\b', '\t',
                           '\v', '\r', '\\', '$',  'z'};
   intptr_t len = ARRAY_SIZE(characters);
@@ -1717,7 +1717,7 @@
   EXPECT_EQ(escaped_empty_str.Length(), 0);
 }
 
-VM_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
+ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
   uint16_t characters[] = {'a',  '\n', '\f', '\b', '\t',
                            '\v', '\r', '\\', '$',  'z'};
   intptr_t len = ARRAY_SIZE(characters);
@@ -1740,7 +1740,7 @@
 }
 
 
-VM_TEST_CASE(EscapeSpecialCharactersExternalTwoByteString) {
+ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersExternalTwoByteString) {
   uint16_t characters[] = {'a',  '\n', '\f', '\b', '\t',
                            '\v', '\r', '\\', '$',  'z'};
   intptr_t len = ARRAY_SIZE(characters);
@@ -1763,7 +1763,7 @@
 }
 
 
-VM_TEST_CASE(ExternalTwoByteString) {
+ISOLATE_UNIT_TEST_CASE(ExternalTwoByteString) {
   uint16_t characters[] = {0x1E6B, 0x1E85, 0x1E53};
   intptr_t len = ARRAY_SIZE(characters);
 
@@ -1796,7 +1796,7 @@
 }
 
 
-VM_TEST_CASE(Symbol) {
+ISOLATE_UNIT_TEST_CASE(Symbol) {
   const String& one = String::Handle(Symbols::New(thread, "Eins"));
   EXPECT(one.IsSymbol());
   const String& two = String::Handle(Symbols::New(thread, "Zwei"));
@@ -1858,7 +1858,7 @@
 }
 
 
-VM_TEST_CASE(SymbolUnicode) {
+ISOLATE_UNIT_TEST_CASE(SymbolUnicode) {
   uint16_t monkey_utf16[] = {0xd83d, 0xdc35};  // Unicode Monkey Face.
   String& monkey = String::Handle(Symbols::FromUTF16(thread, monkey_utf16, 2));
   EXPECT(monkey.IsSymbol());
@@ -1881,13 +1881,13 @@
 }
 
 
-VM_TEST_CASE(Bool) {
+ISOLATE_UNIT_TEST_CASE(Bool) {
   EXPECT(Bool::True().value());
   EXPECT(!Bool::False().value());
 }
 
 
-VM_TEST_CASE(Array) {
+ISOLATE_UNIT_TEST_CASE(Array) {
   const int kArrayLen = 5;
   const Array& array = Array::Handle(Array::New(kArrayLen));
   EXPECT_EQ(kArrayLen, array.Length());
@@ -2042,7 +2042,7 @@
 }
 
 
-VM_TEST_CASE(StringCodePointIterator) {
+ISOLATE_UNIT_TEST_CASE(StringCodePointIterator) {
   const String& str0 = String::Handle(String::New(""));
   String::CodePointIterator it0(str0);
   EXPECT(!it0.Next());
@@ -2099,7 +2099,7 @@
 }
 
 
-VM_TEST_CASE(StringCodePointIteratorRange) {
+ISOLATE_UNIT_TEST_CASE(StringCodePointIteratorRange) {
   const String& str = String::Handle(String::New("foo bar baz"));
 
   String::CodePointIterator it0(str, 3, 0);
@@ -2116,7 +2116,7 @@
 }
 
 
-VM_TEST_CASE(GrowableObjectArray) {
+ISOLATE_UNIT_TEST_CASE(GrowableObjectArray) {
   const int kArrayLen = 5;
   Smi& value = Smi::Handle();
   Smi& expected_value = Smi::Handle();
@@ -2238,7 +2238,7 @@
 }
 
 
-VM_TEST_CASE(InternalTypedData) {
+ISOLATE_UNIT_TEST_CASE(InternalTypedData) {
   uint8_t data[] = {253, 254, 255, 0, 1, 2, 3, 4};
   intptr_t data_length = ARRAY_SIZE(data);
 
@@ -2294,7 +2294,7 @@
 }
 
 
-VM_TEST_CASE(ExternalTypedData) {
+ISOLATE_UNIT_TEST_CASE(ExternalTypedData) {
   uint8_t data[] = {253, 254, 255, 0, 1, 2, 3, 4};
   intptr_t data_length = ARRAY_SIZE(data);
 
@@ -2388,7 +2388,7 @@
 }
 
 
-VM_TEST_CASE(EmbeddedScript) {
+ISOLATE_UNIT_TEST_CASE(EmbeddedScript) {
   const char* url_chars = "builtin:test-case";
   const char* text =
       /* 1 */
@@ -2490,7 +2490,7 @@
 }
 
 
-VM_TEST_CASE(Context) {
+ISOLATE_UNIT_TEST_CASE(Context) {
   const int kNumVariables = 5;
   const Context& parent_context = Context::Handle(Context::New(0));
   const Context& context = Context::Handle(Context::New(kNumVariables));
@@ -2513,7 +2513,7 @@
 }
 
 
-VM_TEST_CASE(ContextScope) {
+ISOLATE_UNIT_TEST_CASE(ContextScope) {
   const intptr_t parent_scope_function_level = 0;
   LocalScope* parent_scope =
       new LocalScope(NULL, parent_scope_function_level, 0);
@@ -2598,7 +2598,7 @@
 }
 
 
-VM_TEST_CASE(Closure) {
+ISOLATE_UNIT_TEST_CASE(Closure) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
   const Script& script = Script::Handle();
@@ -2628,7 +2628,7 @@
 }
 
 
-VM_TEST_CASE(ObjectPrinting) {
+ISOLATE_UNIT_TEST_CASE(ObjectPrinting) {
   // Simple Smis.
   EXPECT_STREQ("2", Smi::Handle(Smi::New(2)).ToCString());
   EXPECT_STREQ("-15", Smi::Handle(Smi::New(-15)).ToCString());
@@ -2646,7 +2646,7 @@
 }
 
 
-VM_TEST_CASE(CheckedHandle) {
+ISOLATE_UNIT_TEST_CASE(CheckedHandle) {
   // Ensure that null handles have the correct C++ vtable setup.
   const String& str1 = String::Handle();
   EXPECT(str1.IsString());
@@ -2690,7 +2690,7 @@
 
 
 // Test for Code and Instruction object creation.
-VM_TEST_CASE(Code) {
+ISOLATE_UNIT_TEST_CASE(Code) {
   extern void GenerateIncrement(Assembler * assembler);
   Assembler _assembler_;
   GenerateIncrement(&_assembler_);
@@ -2708,7 +2708,7 @@
 
 // Test for immutability of generated instructions. The test crashes with a
 // segmentation fault when writing into it.
-VM_TEST_CASE(CodeImmutability) {
+ISOLATE_UNIT_TEST_CASE(CodeImmutability) {
   extern void GenerateIncrement(Assembler * assembler);
   Assembler _assembler_;
   GenerateIncrement(&_assembler_);
@@ -2730,7 +2730,7 @@
 
 
 // Test for Embedded String object in the instructions.
-VM_TEST_CASE(EmbedStringInCode) {
+ISOLATE_UNIT_TEST_CASE(EmbedStringInCode) {
   extern void GenerateEmbedStringInCode(Assembler * assembler, const char* str);
   const char* kHello = "Hello World!";
   word expected_length = static_cast<word>(strlen(kHello));
@@ -2753,7 +2753,7 @@
 
 
 // Test for Embedded Smi object in the instructions.
-VM_TEST_CASE(EmbedSmiInCode) {
+ISOLATE_UNIT_TEST_CASE(EmbedSmiInCode) {
   extern void GenerateEmbedSmiInCode(Assembler * assembler, intptr_t value);
   const intptr_t kSmiTestValue = 5;
   Assembler _assembler_;
@@ -2770,7 +2770,7 @@
 
 #if defined(ARCH_IS_64_BIT)
 // Test for Embedded Smi object in the instructions.
-VM_TEST_CASE(EmbedSmiIn64BitCode) {
+ISOLATE_UNIT_TEST_CASE(EmbedSmiIn64BitCode) {
   extern void GenerateEmbedSmiInCode(Assembler * assembler, intptr_t value);
   const intptr_t kSmiTestValue = DART_INT64_C(5) << 32;
   Assembler _assembler_;
@@ -2786,7 +2786,7 @@
 #endif  // ARCH_IS_64_BIT
 
 
-VM_TEST_CASE(ExceptionHandlers) {
+ISOLATE_UNIT_TEST_CASE(ExceptionHandlers) {
   const int kNumEntries = 4;
   // Add an exception handler table to the code.
   ExceptionHandlers& exception_handlers = ExceptionHandlers::Handle();
@@ -2809,7 +2809,7 @@
   const ExceptionHandlers& handlers =
       ExceptionHandlers::Handle(code.exception_handlers());
   EXPECT_EQ(kNumEntries, handlers.num_entries());
-  RawExceptionHandlers::HandlerInfo info;
+  ExceptionHandlerInfo info;
   handlers.GetHandlerInfo(0, &info);
   EXPECT_EQ(-1, handlers.OuterTryIndex(0));
   EXPECT_EQ(-1, info.outer_try_index);
@@ -2824,7 +2824,7 @@
 }
 
 
-VM_TEST_CASE(PcDescriptors) {
+ISOLATE_UNIT_TEST_CASE(PcDescriptors) {
   DescriptorList* builder = new DescriptorList(0);
 
   // kind, pc_offset, deopt_id, token_pos, try_index
@@ -2882,7 +2882,7 @@
 }
 
 
-VM_TEST_CASE(PcDescriptorsLargeDeltas) {
+ISOLATE_UNIT_TEST_CASE(PcDescriptorsLargeDeltas) {
   DescriptorList* builder = new DescriptorList(0);
 
   // kind, pc_offset, deopt_id, token_pos, try_index
@@ -2964,7 +2964,7 @@
 }
 
 
-VM_TEST_CASE(ClassDictionaryIterator) {
+ISOLATE_UNIT_TEST_CASE(ClassDictionaryIterator) {
   Class& ae66 = Class::ZoneHandle(CreateTestClass("Ae6/6"));
   Class& re44 = Class::ZoneHandle(CreateTestClass("Re4/4"));
   Field& ce68 = Field::ZoneHandle(CreateTestField("Ce6/8"));
@@ -3003,7 +3003,7 @@
 }
 
 
-VM_TEST_CASE(ICData) {
+ISOLATE_UNIT_TEST_CASE(ICData) {
   Function& function = Function::Handle(GetDummyTarget("Bern"));
   const intptr_t id = 12;
   const intptr_t num_args_tested = 1;
@@ -3076,7 +3076,7 @@
 }
 
 
-VM_TEST_CASE(SubtypeTestCache) {
+ISOLATE_UNIT_TEST_CASE(SubtypeTestCache) {
   String& class_name = String::Handle(Symbols::New(thread, "EmptyClass"));
   Script& script = Script::Handle();
   const Class& empty_class =
@@ -3102,7 +3102,7 @@
 }
 
 
-VM_TEST_CASE(FieldTests) {
+ISOLATE_UNIT_TEST_CASE(FieldTests) {
   const String& f = String::Handle(String::New("oneField"));
   const String& getter_f = String::Handle(Field::GetterName(f));
   const String& setter_f = String::Handle(Field::SetterName(f));
@@ -3123,7 +3123,7 @@
 bool EqualsIgnoringPrivate(const String& name, const String& private_name);
 
 
-VM_TEST_CASE(EqualsIgnoringPrivate) {
+ISOLATE_UNIT_TEST_CASE(EqualsIgnoringPrivate) {
   String& mangled_name = String::Handle();
   String& bare_name = String::Handle();
 
@@ -3256,7 +3256,7 @@
 }
 
 
-VM_TEST_CASE(ArrayNew_Overflow_Crash) {
+ISOLATE_UNIT_TEST_CASE(ArrayNew_Overflow_Crash) {
   Array::Handle(Array::New(Array::kMaxElements + 1));
 }
 
@@ -3321,7 +3321,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveCrossGen) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveCrossGen) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
@@ -3433,7 +3433,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveRecurse) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveRecurse) {
   // This used to end in an infinite recursion. Caused by scavenging the weak
   // property before scavenging the key.
   Isolate* isolate = Isolate::Current();
@@ -3456,7 +3456,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   String& key = String::Handle();
@@ -3475,7 +3475,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   String& key1 = String::Handle();
@@ -3504,7 +3504,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3531,7 +3531,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   String& key = String::Handle();
@@ -3550,7 +3550,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   String& key1 = String::Handle();
@@ -3579,7 +3579,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3606,7 +3606,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_ClearOne_NewSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
@@ -3627,7 +3627,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3654,7 +3654,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_ClearOne_OldSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
@@ -3675,7 +3675,7 @@
 }
 
 
-VM_TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
+ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3702,7 +3702,7 @@
 }
 
 
-VM_TEST_CASE(MirrorReference) {
+ISOLATE_UNIT_TEST_CASE(MirrorReference) {
   const MirrorReference& reference =
       MirrorReference::Handle(MirrorReference::New(Object::Handle()));
   Object& initial_referent = Object::Handle(reference.referent());
@@ -3760,7 +3760,7 @@
 }
 
 
-VM_TEST_CASE(FindClosureIndex) {
+ISOLATE_UNIT_TEST_CASE(FindClosureIndex) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
   const Script& script = Script::Handle();
@@ -3798,7 +3798,7 @@
 }
 
 
-VM_TEST_CASE(FindInvocationDispatcherFunctionIndex) {
+ISOLATE_UNIT_TEST_CASE(FindInvocationDispatcherFunctionIndex) {
   const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
   const Script& script = Script::Handle();
   const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
@@ -4051,7 +4051,7 @@
 }
 
 
-VM_TEST_CASE(SpecialClassesHaveEmptyArrays) {
+ISOLATE_UNIT_TEST_CASE(SpecialClassesHaveEmptyArrays) {
   ObjectStore* object_store = Isolate::Current()->object_store();
   Class& cls = Class::Handle();
   Object& array = Object::Handle();
@@ -4107,7 +4107,7 @@
 };
 
 
-VM_TEST_CASE(PrintJSON) {
+ISOLATE_UNIT_TEST_CASE(PrintJSON) {
   Heap* heap = Isolate::Current()->heap();
   heap->CollectAllGarbage();
   GrowableArray<Object*> objects;
@@ -4121,7 +4121,7 @@
 }
 
 
-VM_TEST_CASE(PrintJSONPrimitives) {
+ISOLATE_UNIT_TEST_CASE(PrintJSONPrimitives) {
   char buffer[1024];
   Isolate* isolate = Isolate::Current();
 
@@ -4591,7 +4591,7 @@
 }
 
 
-VM_TEST_CASE(Symbols_FromConcatAll) {
+ISOLATE_UNIT_TEST_CASE(Symbols_FromConcatAll) {
   {
     const String* data[3] = {&Symbols::FallThroughError(), &Symbols::Dot(),
                              &Symbols::isPaused()};
@@ -4661,7 +4661,7 @@
 };
 
 
-VM_TEST_CASE(String_ScrubName) {
+ISOLATE_UNIT_TEST_CASE(String_ScrubName) {
   TestResult tests[] = {
       {"(dynamic, dynamic) => void", "(dynamic, dynamic) => void"},
       {"_List@915557746", "_List"},
@@ -4688,7 +4688,7 @@
 }
 
 
-VM_TEST_CASE(String_EqualsUTF32) {
+ISOLATE_UNIT_TEST_CASE(String_EqualsUTF32) {
   // Regression test for Issue 27433. Checks that comparisons between Strings
   // and utf32 arrays happens after conversion to utf16 instead of utf32, as
   // required for proper canonicalization of string literals with a lossy
diff --git a/runtime/vm/os_test.cc b/runtime/vm/os_test.cc
index 2ecc36b..2c31417 100644
--- a/runtime/vm/os_test.cc
+++ b/runtime/vm/os_test.cc
@@ -10,7 +10,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(Sleep) {
+VM_UNIT_TEST_CASE(Sleep) {
   // All times measured in microseconds.
   int64_t start_time = OS::GetCurrentMonotonicMicros();
   int64_t sleep_time = 702000;
@@ -22,7 +22,7 @@
 }
 
 
-UNIT_TEST_CASE(SNPrint) {
+VM_UNIT_TEST_CASE(SNPrint) {
   char buffer[256];
   int length;
   length = OS::SNPrint(buffer, 10, "%s", "foo");
@@ -40,14 +40,14 @@
 
 
 // This test is expected to crash when it runs.
-UNIT_TEST_CASE(SNPrint_BadArgs) {
+VM_UNIT_TEST_CASE(SNPrint_BadArgs) {
   int width = kMaxInt32;
   int num = 7;
   OS::SNPrint(NULL, 0, "%*d%*d", width, num, width, num);
 }
 
 
-UNIT_TEST_CASE(OsFuncs) {
+VM_UNIT_TEST_CASE(OsFuncs) {
   EXPECT(Utils::IsPowerOfTwo(OS::ActivationFrameAlignment()));
   EXPECT(Utils::IsPowerOfTwo(OS::PreferredCodeAlignment()));
   int procs = OS::NumberOfAvailableProcessors();
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index da29831..41e7718 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -108,6 +108,8 @@
     return true;
   }
 
+  static bool GetCurrentStackBounds(uword* lower, uword* upper);
+
   // Used to temporarily disable or enable thread interrupts.
   void DisableThreadInterrupts();
   void EnableThreadInterrupts();
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index 29823b8..3ad2a89 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -234,6 +234,26 @@
 }
 
 
+bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
+  pthread_attr_t attr;
+  if (pthread_getattr_np(pthread_self(), &attr)) {
+    return false;
+  }
+
+  void* base;
+  size_t size;
+  int error = pthread_attr_getstack(&attr, &base, &size);
+  pthread_attr_destroy(&attr);
+  if (error) {
+    return false;
+  }
+
+  *lower = reinterpret_cast<uword>(base);
+  *upper = *lower + size;
+  return true;
+}
+
+
 Mutex::Mutex() {
   pthread_mutexattr_t attr;
   int result = pthread_mutexattr_init(&attr);
diff --git a/runtime/vm/os_thread_fuchsia.cc b/runtime/vm/os_thread_fuchsia.cc
index c57c2a1..0426532 100644
--- a/runtime/vm/os_thread_fuchsia.cc
+++ b/runtime/vm/os_thread_fuchsia.cc
@@ -203,6 +203,11 @@
 }
 
 
+bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
+  return false;
+}
+
+
 Mutex::Mutex() {
   pthread_mutexattr_t attr;
   int result = pthread_mutexattr_init(&attr);
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index 438fb17..11ce109 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -234,6 +234,26 @@
 }
 
 
+bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
+  pthread_attr_t attr;
+  if (pthread_getattr_np(pthread_self(), &attr)) {
+    return false;
+  }
+
+  void* base;
+  size_t size;
+  int error = pthread_attr_getstack(&attr, &base, &size);
+  pthread_attr_destroy(&attr);
+  if (error) {
+    return false;
+  }
+
+  *lower = reinterpret_cast<uword>(base);
+  *upper = *lower + size;
+  return true;
+}
+
+
 Mutex::Mutex() {
   pthread_mutexattr_t attr;
   int result = pthread_mutexattr_init(&attr);
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 23fe4d7..bc33dc1d 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -209,6 +209,13 @@
 }
 
 
+bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
+  *upper = reinterpret_cast<uword>(pthread_get_stackaddr_np(pthread_self()));
+  *lower = *upper - pthread_get_stacksize_np(pthread_self());
+  return true;
+}
+
+
 Mutex::Mutex() {
   pthread_mutexattr_t attr;
   int result = pthread_mutexattr_init(&attr);
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index 7599195..7d80d4d 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -173,6 +173,21 @@
 }
 
 
+bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
+// On Windows stack limits for the current thread are available in
+// the thread information block (TIB). Its fields can be accessed through
+// FS segment register on x86 and GS segment register on x86_64.
+#ifdef _WIN64
+  *upper = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackBase)));
+  *lower = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackLimit)));
+#else
+  *upper = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackBase)));
+  *lower = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackLimit)));
+#endif
+  return true;
+}
+
+
 void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
   ASSERT(key != kUnsetThreadLocalKey);
   BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value));
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index 1134ce7..87d2247 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -189,7 +189,11 @@
 
 
 intptr_t OS::ActivationFrameAlignment() {
-#ifdef _WIN64
+#if defined(TARGET_ARCH_ARM64)
+  return 16;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+  return 8;
+#elif defined(_WIN64)
   // Windows 64-bit ABI requires the stack to be 16-byte aligned.
   return 16;
 #else
@@ -201,7 +205,14 @@
 
 intptr_t OS::PreferredCodeAlignment() {
   ASSERT(32 <= OS::kMaxPreferredCodeAlignment);
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) ||                   \
+    defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_DBC)
   return 32;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+  return 16;
+#else
+#error Unsupported architecture.
+#endif
 }
 
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index e75d86d..bc6740c 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -54,7 +54,14 @@
             conditional_directives,
             true,
             "Enable conditional directives");
-DEFINE_FLAG(bool, generic_method_syntax, true, "Enable generic functions.");
+DEFINE_FLAG(bool,
+            generic_method_syntax,
+            true,
+            "Enable generic function syntax.");
+DEFINE_FLAG(bool,
+            generic_method_semantics,
+            true,
+            "Enable generic function semantics (not yet supported).");
 DEFINE_FLAG(bool,
             initializing_formal_access,
             true,
@@ -63,7 +70,6 @@
             warn_super,
             false,
             "Warning if super initializer not last in initializer list.");
-DEFINE_FLAG(bool, warn_patch, false, "Warn on old-style patch syntax.");
 DEFINE_FLAG(
     bool,
     await_is_keyword,
@@ -995,8 +1001,13 @@
         new ParsedFunction(thread, Function::ZoneHandle(zone, func.raw()));
     Parser parser(script, parsed_function, func.token_pos());
     parser.SkipFunctionPreamble();
+    const bool use_function_type_syntax = false;
+    const bool allow_explicit_default_values = true;
+    const bool evaluate_metadata = true;
     ParamList params;
-    parser.ParseFormalParameterList(true, true, &params);
+    parser.ParseFormalParameterList(use_function_type_syntax,
+                                    allow_explicit_default_values,
+                                    evaluate_metadata, &params);
     ParamDesc* param = params.parameters->data();
     const int param_cnt =
         params.num_fixed_parameters + params.num_optional_parameters;
@@ -1051,7 +1062,12 @@
         new ParsedFunction(Thread::Current(), Function::ZoneHandle(func.raw()));
     Parser parser(script, parsed_function, func.token_pos());
     parser.SkipFunctionPreamble();
-    parser.ParseFormalParameterList(true, true, params);
+    const bool use_function_type_syntax = false;
+    const bool allow_explicit_default_values = true;
+    const bool evaluate_metadata = true;
+    parser.ParseFormalParameterList(use_function_type_syntax,
+                                    allow_explicit_default_values,
+                                    evaluate_metadata, params);
     return true;
   } else {
     Thread::Current()->clear_sticky_error();
@@ -1358,15 +1374,10 @@
 
 SequenceNode* Parser::ParseStaticFinalGetter(const Function& func) {
   TRACE_PARSER("ParseStaticFinalGetter");
-  ParamList params;
   ASSERT(func.num_fixed_parameters() == 0);  // static.
   ASSERT(!func.HasOptionalParameters());
   ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
-
-  // Build local scope for function and populate with the formal parameters.
   OpenFunctionBlock(func);
-  AddFormalParamsToScope(&params, current_block_->scope);
-
   TokenPosition ident_pos = TokenPos();
   const String& field_name = *ExpectIdentifier("field name expected");
   const Class& field_class = Class::Handle(Z, func.Owner());
@@ -1560,9 +1571,14 @@
   } else if (!parent.IsGetterFunction() && !parent.IsImplicitGetterFunction()) {
     // NOTE: For the `kernel -> flowgraph` we don't use the parser.
     if (parent.kernel_function() == NULL) {
-      const bool allow_explicit_default_values = true;
       SkipFunctionPreamble();
-      ParseFormalParameterList(allow_explicit_default_values, false, &params);
+      const bool use_function_type_syntax = false;
+      const bool allow_explicit_default_values = true;
+      const bool evaluate_metadata = false;
+      ParseFormalParameterList(use_function_type_syntax,
+                               allow_explicit_default_values, evaluate_metadata,
+                               &params);
+      FinalizeFormalParameterTypes(&params);
       SetupDefaultsForOptionalParams(params);
     }
   }
@@ -1937,6 +1953,78 @@
 }
 
 
+// Parses a parameter type as defined by the 'parameterTypeList' production.
+void Parser::ParseParameterType(ParamList* params) {
+  TRACE_PARSER("ParseParameterType");
+  ParamDesc parameter;
+
+  parameter.has_explicit_type = true;  // The type is required by the syntax.
+  // It is too early to resolve the type here, since it can be a result type
+  // referring to a not yet declared function type parameter.
+  parameter.type = &AbstractType::ZoneHandle(
+      Z, ParseTypeOrFunctionType(false, ClassFinalizer::kDoNotResolve));
+
+  // At this point, we must see an identifier for the parameter name, unless
+  // we are using the function type syntax (in which case the name is optional,
+  // unless we expect optional named parameters).
+  if (IsIdentifier()) {
+    parameter.name_pos = TokenPos();
+    parameter.name = CurrentLiteral();
+    ConsumeToken();
+
+    if (params->has_optional_named_parameters &&
+        (parameter.name->CharAt(0) == Library::kPrivateIdentifierStart)) {
+      ReportError(parameter.name_pos, "named parameter must not be private");
+    }
+
+    // Check for duplicate formal parameters.
+    const intptr_t num_existing_parameters =
+        params->num_fixed_parameters + params->num_optional_parameters;
+    for (intptr_t i = 0; i < num_existing_parameters; i++) {
+      ParamDesc& existing_parameter = (*params->parameters)[i];
+      if (existing_parameter.name->Equals(*parameter.name)) {
+        ReportError(parameter.name_pos, "duplicate formal parameter '%s'",
+                    parameter.name->ToCString());
+      }
+    }
+  } else if (params->has_optional_named_parameters) {
+    ExpectIdentifier("parameter name expected");
+  } else {
+    parameter.name_pos = TokenPos();
+    parameter.name = &Symbols::NotNamed();
+  }
+
+  // The function type syntax does not allow the signature type syntax.
+  // No need to check for IsParameterPart().
+
+  if ((CurrentToken() == Token::kASSIGN) || (CurrentToken() == Token::kCOLON)) {
+    ReportError("parameter must not specify a default value");
+  } else {
+    if (params->has_optional_positional_parameters ||
+        params->has_optional_named_parameters) {
+      // Implicit default value is null.
+      params->num_optional_parameters++;
+      parameter.default_value = &Object::null_instance();
+    } else {
+      params->num_fixed_parameters++;
+      ASSERT(params->num_optional_parameters == 0);
+    }
+  }
+  if (parameter.type->IsVoidType()) {
+    ReportError("parameter '%s' may not be 'void'",
+                parameter.name->ToCString());
+  }
+  if (params->implicitly_final) {
+    parameter.is_final = true;
+  }
+  params->parameters->Add(parameter);
+  if (parameter.is_covariant) {
+    params->has_covariant = true;
+  }
+}
+
+
+// Parses a formal parameter as defined by the 'formalParameterList' production.
 void Parser::ParseFormalParameter(bool allow_explicit_default_value,
                                   bool evaluate_metadata,
                                   ParamList* params) {
@@ -1988,7 +2076,7 @@
   }
   if (parameter.type == NULL) {
     // At this point, we must see an identifier for the type or the
-    // function parameter.
+    // function parameter. The identifier may be 'Function'.
     if (!IsIdentifier()) {
       ReportError("parameter name or type expected");
     }
@@ -1998,7 +2086,7 @@
     bool found_type = false;
     {
       TokenPosScope saved_pos(this);
-      if (TryParseReturnType()) {
+      if (TryParseType(true)) {
         if (IsIdentifier() || (CurrentToken() == Token::kTHIS)) {
           found_type = true;
         }
@@ -2009,13 +2097,13 @@
       // mode, because they are part of the function type of closurized
       // functions appearing in type tests with typedefs.
       parameter.has_explicit_type = true;
-      // It is too early to resolve the type here, since it can be a result type
-      // referring to a not yet declared function type parameter.
+      // It is too early to resolve the type here, since it can be a result
+      // type referring to a not yet declared function type parameter.
       parameter.type = &AbstractType::ZoneHandle(
-          Z, ParseType(ClassFinalizer::kDoNotResolve));
+          Z, ParseTypeOrFunctionType(true, ClassFinalizer::kDoNotResolve));
     } else {
-      // If this is an initializing formal, its type will be set to the type of
-      // the respective field when the constructor is fully parsed.
+      // If this is an initializing formal, its type will be set to the type
+      // of the respective field when the constructor is fully parsed.
       parameter.type = &Object::dynamic_type();
     }
   }
@@ -2084,11 +2172,6 @@
         ParseTypeParameters(false);  // Not parameterizing class, but function.
       }
 
-      // Now that type parameters are declared, the result type can be resolved.
-      ResolveType(is_top_level_ ? ClassFinalizer::kResolveTypeParameters
-                                : ClassFinalizer::kCanonicalize,
-                  &result_type);
-
       ASSERT(CurrentToken() == Token::kLPAREN);
       ParamList func_params;
 
@@ -2096,8 +2179,12 @@
       func_params.AddFinalParameter(TokenPos(), &Symbols::ClosureParameter(),
                                     &Object::dynamic_type());
 
-      const bool no_explicit_default_values = false;
-      ParseFormalParameterList(no_explicit_default_values, false, &func_params);
+      const bool use_function_type_syntax = false;
+      const bool allow_explicit_default_values = false;
+      const bool evaluate_metadata = false;
+      ParseFormalParameterList(use_function_type_syntax,
+                               allow_explicit_default_values, evaluate_metadata,
+                               &func_params);
 
       signature_function.set_result_type(result_type);
       AddFormalParamsToFunction(&func_params, signature_function);
@@ -2107,14 +2194,7 @@
 
       Type& signature_type =
           Type::ZoneHandle(Z, signature_function.SignatureType());
-      if (!is_top_level_) {
-        signature_type ^= ClassFinalizer::FinalizeType(
-            current_class(), signature_type, ClassFinalizer::kCanonicalize);
-        // Do not refer to signature_function anymore, since it may have been
-        // replaced during canonicalization.
-        signature_function = Function::null();
-      }
-      ASSERT(is_top_level_ || signature_type.IsFinalized());
+
       // A signature type itself cannot be malformed or malbounded, only its
       // signature function's result type or parameter types may be.
       ASSERT(!signature_type.IsMalformed());
@@ -2122,18 +2202,6 @@
       // The type of the parameter is now the signature type.
       parameter.type = &signature_type;
     }
-  } else {
-    if (!parameter.type->IsFinalized()) {
-      AbstractType& type = AbstractType::ZoneHandle(Z, parameter.type->raw());
-      if (is_top_level_) {
-        ResolveType(ClassFinalizer::kResolveTypeParameters, &type);
-      } else {
-        ResolveType(ClassFinalizer::kCanonicalize, &type);
-        type = ClassFinalizer::FinalizeType(current_class(), type,
-                                            ClassFinalizer::kCanonicalize);
-      }
-      parameter.type = &type;
-    }
   }
 
   if ((CurrentToken() == Token::kASSIGN) || (CurrentToken() == Token::kCOLON)) {
@@ -2182,7 +2250,8 @@
 
 
 // Parses a sequence of normal or optional formal parameters.
-void Parser::ParseFormalParameters(bool allow_explicit_default_values,
+void Parser::ParseFormalParameters(bool use_function_type_syntax,
+                                   bool allow_explicit_default_values,
                                    bool evaluate_metadata,
                                    ParamList* params) {
   TRACE_PARSER("ParseFormalParameters");
@@ -2214,14 +2283,20 @@
       // Allow a trailing comma.
       break;
     }
-    ParseFormalParameter(allow_explicit_default_values, evaluate_metadata,
-                         params);
+    if (use_function_type_syntax) {
+      ASSERT(!allow_explicit_default_values && !evaluate_metadata);
+      ParseParameterType(params);
+    } else {
+      ParseFormalParameter(allow_explicit_default_values, evaluate_metadata,
+                           params);
+    }
     has_seen_parameter = true;
   } while (CurrentToken() == Token::kCOMMA);
 }
 
 
-void Parser::ParseFormalParameterList(bool allow_explicit_default_values,
+void Parser::ParseFormalParameterList(bool use_function_type_syntax,
+                                      bool allow_explicit_default_values,
                                       bool evaluate_metadata,
                                       ParamList* params) {
   TRACE_PARSER("ParseFormalParameterList");
@@ -2229,12 +2304,14 @@
 
   if (LookaheadToken(1) != Token::kRPAREN) {
     // Parse fixed parameters.
-    ParseFormalParameters(allow_explicit_default_values, evaluate_metadata,
+    ParseFormalParameters(use_function_type_syntax,
+                          allow_explicit_default_values, evaluate_metadata,
                           params);
     if (params->has_optional_positional_parameters ||
         params->has_optional_named_parameters) {
       // Parse optional parameters.
-      ParseFormalParameters(allow_explicit_default_values, evaluate_metadata,
+      ParseFormalParameters(use_function_type_syntax,
+                            allow_explicit_default_values, evaluate_metadata,
                             params);
       if (params->has_optional_positional_parameters) {
         CheckToken(Token::kRBRACK, "',' or ']' expected");
@@ -2287,10 +2364,13 @@
                                     NULL)) {
     super_func = Function::null();
   } else if (super_func.IsNull() && resolve_getter) {
-    const String& getter_name = String::ZoneHandle(Z, Field::GetterName(name));
-    super_func = Resolver::ResolveDynamicAnyArgs(Z, super_class, getter_name);
-    ASSERT(super_func.IsNull() ||
-           (super_func.kind() != RawFunction::kImplicitStaticFinalGetter));
+    const String& getter_name =
+        String::ZoneHandle(Z, Field::LookupGetterSymbol(name));
+    if (!getter_name.IsNull()) {
+      super_func = Resolver::ResolveDynamicAnyArgs(Z, super_class, getter_name);
+      ASSERT(super_func.IsNull() ||
+             (super_func.kind() != RawFunction::kImplicitStaticFinalGetter));
+    }
   }
   if (super_func.IsNull()) {
     super_func = Resolver::ResolveDynamicAnyArgs(Z, super_class,
@@ -2593,6 +2673,11 @@
   const Function& super_ctor =
       Function::ZoneHandle(Z, super_class.LookupConstructor(super_ctor_name));
   if (super_ctor.IsNull()) {
+    if (super_class.LookupFactory(super_ctor_name) != Function::null()) {
+      ReportError(supercall_pos,
+                  "illegal implicit call to factory '%s()' in super class",
+                  String::Handle(Z, super_class.Name()).ToCString());
+    }
     ReportError(supercall_pos,
                 "unresolved implicit call to super constructor '%s()'",
                 String::Handle(Z, super_class.Name()).ToCString());
@@ -2644,6 +2729,12 @@
   const Function& super_ctor =
       Function::ZoneHandle(Z, super_class.LookupConstructor(ctor_name));
   if (super_ctor.IsNull()) {
+    if (super_class.LookupFactory(ctor_name) != Function::null()) {
+      ReportError(supercall_pos,
+                  "super class constructor '%s' "
+                  "must not be a factory constructor",
+                  ctor_name.ToCString());
+    }
     ReportError(supercall_pos, "super class constructor '%s' not found",
                 ctor_name.ToCString());
   }
@@ -3029,6 +3120,11 @@
   const Function& redirect_ctor =
       Function::ZoneHandle(Z, cls.LookupConstructor(ctor_name));
   if (redirect_ctor.IsNull()) {
+    if (cls.LookupFactory(ctor_name) != Function::null()) {
+      ReportError(
+          call_pos, "redirection constructor '%s' must not be a factory",
+          String::Handle(Z, redirect_ctor.UserVisibleName()).ToCString());
+    }
     ReportError(call_pos, "constructor '%s' not found",
                 String::Handle(Z, redirect_ctor.UserVisibleName()).ToCString());
   }
@@ -3190,7 +3286,6 @@
 
   OpenFunctionBlock(func);
   ParamList params;
-  const bool allow_explicit_default_values = true;
   ASSERT(CurrentToken() == Token::kLPAREN);
 
   // Add implicit receiver parameter which is passed the allocated
@@ -3201,11 +3296,16 @@
   if (func.is_const()) {
     params.SetImplicitlyFinal();
   }
-  ParseFormalParameterList(allow_explicit_default_values, false, &params);
+  const bool use_function_type_syntax = false;
+  const bool allow_explicit_default_values = true;
+  const bool evaluate_metadata = false;
+  ParseFormalParameterList(use_function_type_syntax,
+                           allow_explicit_default_values, evaluate_metadata,
+                           &params);
+  FinalizeFormalParameterTypes(&params);
 
   SetupDefaultsForOptionalParams(params);
   ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
-  ASSERT(func.NumParameters() == params.parameters->length());
 
   // Now populate function scope with the formal parameters.
   AddFormalParamsToScope(&params, current_block_->scope);
@@ -3383,7 +3483,6 @@
   ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction() ||
          (func.is_generated_body() &&
           Function::Handle(func.parent_function()).IsGetterFunction()));
-  const bool allow_explicit_default_values = true;
   if (func.IsGetterFunction()) {
     // Populate function scope with the formal parameters. Since in this case
     // we are compiling a getter this will at most populate the receiver.
@@ -3424,7 +3523,15 @@
       SkipToMatchingParenthesis();
     }
   } else {
-    ParseFormalParameterList(allow_explicit_default_values, false, &params);
+    const bool use_function_type_syntax = false;
+    const bool allow_explicit_default_values = true;
+    const bool evaluate_metadata = false;
+    ParseFormalParameterList(use_function_type_syntax,
+                             allow_explicit_default_values, evaluate_metadata,
+                             &params);
+    if (!is_top_level_) {
+      FinalizeFormalParameterTypes(&params);
+    }
 
     // The number of parameters and their type are not yet set in local
     // functions, since they are not 'top-level' parsed.
@@ -3433,9 +3540,12 @@
     if (func.parameter_types() == Object::empty_array().raw()) {
       AddFormalParamsToFunction(&params, func);
     }
+    ResolveSignature(func);
+    if (!is_top_level_) {
+      ClassFinalizer::FinalizeSignature(Class::Handle(Z, func.origin()), func);
+    }
     SetupDefaultsForOptionalParams(params);
     ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
-    ASSERT(func.NumParameters() == params.parameters->length());
 
     // Populate function scope with the formal parameters.
     AddFormalParamsToScope(&params, current_block_->scope);
@@ -3468,10 +3578,16 @@
     ASSERT(!func.is_generated_body());
     // The code of an async function is synthesized. Disable debugging.
     func.set_is_debuggable(false);
+    // In order to collect causal asynchronous stacks efficiently we rely on
+    // this function not being inlined.
+    func.set_is_inlinable(!FLAG_causal_async_stacks);
     generated_body_closure = OpenAsyncFunction(func.token_pos());
   } else if (func.IsAsyncClosure()) {
     // The closure containing the body of an async function is debuggable.
     ASSERT(func.is_debuggable());
+    // In order to collect causal asynchronous stacks efficiently we rely on
+    // this function not being inlined.
+    func.set_is_inlinable(!FLAG_causal_async_stacks);
     OpenAsyncClosure();
   } else if (func.IsSyncGenerator()) {
     // The code of a sync generator is synthesized. Disable debugging.
@@ -3483,10 +3599,16 @@
     async_temp_scope_ = current_block_->scope;
   } else if (func.IsAsyncGenerator()) {
     func.set_is_debuggable(false);
+    // In order to collect causal asynchronous stacks efficiently we rely on
+    // this function not being inlined.
+    func.set_is_inlinable(!FLAG_causal_async_stacks);
     generated_body_closure = OpenAsyncGeneratorFunction(func.token_pos());
   } else if (func.IsAsyncGenClosure()) {
     // The closure containing the body of an async* function is debuggable.
     ASSERT(func.is_debuggable());
+    // In order to collect causal asynchronous stacks efficiently we rely on
+    // this function not being inlined.
+    func.set_is_inlinable(!FLAG_causal_async_stacks);
     OpenAsyncGeneratorClosure();
   }
 
@@ -3740,16 +3862,7 @@
     ParseTypeParameters(false);  // Not parameterizing class, but function.
   }
 
-  // Now that type parameters are declared, the result type can be resolved.
-  if (!method->type->IsResolved()) {
-    AbstractType& type = AbstractType::ZoneHandle(Z, method->type->raw());
-    ResolveType(ClassFinalizer::kResolveTypeParameters, &type);
-    method->type = &type;
-  }
-
   // Parse the formal parameters.
-  const bool are_implicitly_final = method->has_const;
-  const bool allow_explicit_default_values = true;
   const TokenPosition formal_param_pos = TokenPos();
   method->params.Clear();
   // Static functions do not have a receiver.
@@ -3762,11 +3875,15 @@
                                      &Symbols::TypeArgumentsParameter(),
                                      &Object::dynamic_type());
   }
-  if (are_implicitly_final) {
+  if (method->has_const) {
     method->params.SetImplicitlyFinal();
   }
   if (!method->IsGetter()) {
-    ParseFormalParameterList(allow_explicit_default_values, false,
+    const bool use_function_type_syntax = false;
+    const bool allow_explicit_default_values = true;
+    const bool evaluate_metadata = false;
+    ParseFormalParameterList(use_function_type_syntax,
+                             allow_explicit_default_values, evaluate_metadata,
                              &method->params);
   }
 
@@ -4010,7 +4127,7 @@
   func.set_name(*method->name);
   func.set_is_abstract(method->has_abstract);
   func.set_is_native(method->has_native);
-  func.set_result_type(*method->type);
+  func.set_result_type(*method->type);  // May set parent_function in type.
   func.set_end_token_pos(method_end_pos);
   func.set_is_redirecting(is_redirecting);
   func.set_modifier(async_modifier);
@@ -4039,11 +4156,11 @@
     }
   }
 
-  // No need to resolve parameter types yet, or add parameters to local scope.
   ASSERT(is_top_level_);
   AddFormalParamsToFunction(&method->params, func);
   ASSERT(innermost_function().raw() == func.raw());
   innermost_function_ = Function::null();
+  ResolveSignature(func);
   members->AddFunction(func);
 }
 
@@ -4183,6 +4300,7 @@
       getter.set_result_type(*field->type);
       getter.set_is_debuggable(false);
       AddFormalParamsToFunction(&params, getter);
+      ResolveSignature(getter);
       members->AddFunction(getter);
       if (!field->has_final) {
         // Build a setter accessor for non-const fields.
@@ -4204,6 +4322,7 @@
           setter.set_is_reflectable(false);
         }
         AddFormalParamsToFunction(&params, setter);
+        ResolveSignature(setter);
         members->AddFunction(setter);
       }
     }
@@ -4324,7 +4443,7 @@
     {
       // Lookahead to determine whether the next tokens are a return type.
       TokenPosScope saved_pos(this);
-      if (TryParseReturnType()) {
+      if (TryParseType(true)) {
         if (IsIdentifier() || (CurrentToken() == Token::kGET) ||
             (CurrentToken() == Token::kSET) ||
             (CurrentToken() == Token::kOPERATOR)) {
@@ -4336,7 +4455,7 @@
       // It is too early to resolve the type here, since it can be a result type
       // referring to a not yet declared function type parameter.
       member.type = &AbstractType::ZoneHandle(
-          Z, ParseType(ClassFinalizer::kDoNotResolve));
+          Z, ParseTypeOrFunctionType(false, ClassFinalizer::kDoNotResolve));
     }
   }
 
@@ -4449,7 +4568,8 @@
       member.type = &Object::dynamic_type();
     }
     ASSERT(member.IsFactory() == member.has_factory);
-    // Note that member.type may still be unresolved.
+    // Note that member.type may still be unresolved and may refer to not yet
+    // parsed function type parameters.
     ParseMethodOrConstructor(members, &member);
   } else if (CurrentToken() == Token::kSEMICOLON ||
              CurrentToken() == Token::kCOMMA ||
@@ -4472,7 +4592,7 @@
     }
     if (!member.type->IsResolved()) {
       AbstractType& type = AbstractType::ZoneHandle(Z, member.type->raw());
-      ResolveType(ClassFinalizer::kResolveTypeParameters, &type);
+      ResolveType(&type);
       member.type = &type;
     }
     ParseFieldDefinition(members, &member);
@@ -4791,7 +4911,7 @@
 void Parser::ParseEnumDefinition(const Class& cls) {
   TRACE_PARSER("ParseEnumDefinition");
   INC_STAT(thread(), num_classes_parsed, 1);
-
+  set_current_class(cls);
   const Class& helper_class =
       Class::Handle(Z, Library::LookupCoreClass(Symbols::_EnumHelper()));
   ASSERT(!helper_class.IsNull());
@@ -4828,6 +4948,7 @@
   ParamList params;
   params.AddReceiver(&Object::dynamic_type(), cls.token_pos());
   AddFormalParamsToFunction(&params, getter);
+  ResolveSignature(getter);
   enum_members.AddFunction(getter);
 
   ASSERT(IsIdentifier());
@@ -4900,8 +5021,7 @@
   values_type_args.SetTypeAt(0, enum_type);
   Type& values_type = Type::ZoneHandle(
       Z, Type::New(array_class, values_type_args, cls.token_pos(), Heap::kOld));
-  values_type ^= ClassFinalizer::FinalizeType(cls, values_type,
-                                              ClassFinalizer::kCanonicalize);
+  values_type ^= CanonicalizeType(values_type);
   values_type_args = values_type.arguments();  // Get canonical type arguments.
   // Add static field 'const List<E> values'.
   Field& values_field = Field::ZoneHandle(Z);
@@ -4956,6 +5076,7 @@
   ParamList name_params;
   name_params.AddReceiver(&Object::dynamic_type(), cls.token_pos());
   AddFormalParamsToFunction(&name_params, name_getter);
+  ResolveSignature(name_getter);
   enum_members.AddFunction(name_getter);
 
   // Clone the toString() function from the helper class.
@@ -5005,6 +5126,8 @@
   params.AddReceiver(receiver_type, cls.token_pos());
 
   AddFormalParamsToFunction(&params, ctor);
+  ctor.set_result_type(Object::dynamic_type());
+  ResolveSignature(ctor);
   // The body of the constructor cannot modify the type of the constructed
   // instance, which is passed in as the receiver.
   ctor.set_result_type(*receiver_type);
@@ -5101,21 +5224,30 @@
 }
 
 
-// Look ahead to detect if we are seeing ident [ TypeParameters ] "(".
+// Look ahead to detect if we are seeing ident [ TypeParameters ] ("(" | "=").
 // We need this lookahead to distinguish between the optional return type
 // and the alias name of a function type alias.
 // Token position remains unchanged.
-bool Parser::IsFunctionTypeAliasName() {
-  if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
-    return true;
+bool Parser::IsFunctionTypeAliasName(bool* use_function_type_syntax) {
+  if (IsIdentifier()) {
+    const Token::Kind ahead = LookaheadToken(1);
+    if ((ahead == Token::kLPAREN) || (ahead == Token::kASSIGN)) {
+      *use_function_type_syntax = (ahead == Token::kASSIGN);
+      return true;
+    }
   }
   const TokenPosScope saved_pos(this);
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
     ConsumeToken();
-    if (TryParseTypeParameters() && (CurrentToken() == Token::kLPAREN)) {
-      return true;
+    if (TryParseTypeParameters()) {
+      const Token::Kind current = CurrentToken();
+      if ((current == Token::kLPAREN) || (current == Token::kASSIGN)) {
+        *use_function_type_syntax = (current == Token::kASSIGN);
+        return true;
+      }
     }
   }
+  *use_function_type_syntax = false;
   return false;
 }
 
@@ -5128,15 +5260,23 @@
       metadata_pos.IsReal() ? metadata_pos : TokenPos();
   ExpectToken(Token::kTYPEDEF);
 
-  // Parse the result type of the function type.
-  AbstractType& result_type = Type::Handle(Z, Type::DynamicType());
+  // Distinguish between two possible typedef forms:
+  // 1) returnType? identifier typeParameters? formalParameterList ’;’
+  // 2) identifier typeParameters? '=' functionType ’;’
+
+  bool use_function_type_syntax;  // Set to false for form 1, true for form 2.
+
+  // If present, parse the result type of the function type.
+  AbstractType& result_type = Type::Handle(Z);
   if (CurrentToken() == Token::kVOID) {
     ConsumeToken();
     result_type = Type::VoidType();
-  } else if (!IsFunctionTypeAliasName()) {
+    use_function_type_syntax = false;
+  } else if (!IsFunctionTypeAliasName(&use_function_type_syntax)) {
     // Type annotations in typedef are never ignored, even in production mode.
     // Wait until we have an owner class before resolving the result type.
     result_type = ParseType(ClassFinalizer::kDoNotResolve);
+    ASSERT(!use_function_type_syntax);
   }
 
   const TokenPosition alias_name_pos = TokenPos();
@@ -5162,41 +5302,59 @@
   function_type_alias.set_is_abstract();
   function_type_alias.set_is_prefinalized();
   library_.AddClass(function_type_alias);
+  ASSERT(current_class().IsTopLevel());
   set_current_class(function_type_alias);
   // Parse the type parameters of the typedef class.
   ParseTypeParameters(true);  // Parameterizing current class.
-  // At this point, the type parameters have been parsed, so we can resolve the
-  // result type.
-  if (!result_type.IsNull()) {
-    ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type);
-  }
-  // Parse the formal parameters of the function type.
-  CheckToken(Token::kLPAREN, "formal parameter list expected");
-  ParamList func_params;
-
-  // Add implicit closure object parameter.
-  func_params.AddFinalParameter(TokenPos(), &Symbols::ClosureParameter(),
-                                &Object::dynamic_type());
-
-  // Mark the current class as a typedef class (by setting its signature
-  // function field to a non-null function) before parsing its formal parameters
-  // so that parsed function types are aware that their owner class is a
-  // typedef class.
-  Function& signature_function = Function::Handle(
-      Z, Function::NewSignatureFunction(function_type_alias, alias_name_pos));
+  Function& signature_function = Function::Handle(Z);
   ASSERT(innermost_function().IsNull());
-  innermost_function_ = signature_function.raw();
+  if (use_function_type_syntax) {
+    ExpectToken(Token::kASSIGN);
+    ASSERT(result_type.IsNull());  // Not parsed yet.
+    // Do not resolve types before the function type alias can be recognized as
+    // a typedef class, so that correct promotion of function types can occur.
+    const Type& function_type = Type::Handle(
+        Z, ParseFunctionType(result_type, ClassFinalizer::kDoNotResolve));
+    signature_function = function_type.signature();
+  } else {
+    signature_function =
+        Function::NewSignatureFunction(function_type_alias, alias_name_pos);
+    innermost_function_ = signature_function.raw();
+    ParamList params;
+    // Parse the formal parameters of the function type.
+    CheckToken(Token::kLPAREN, "formal parameter list expected");
+    // Add implicit closure object parameter.
+    params.AddFinalParameter(TokenPos(), &Symbols::ClosureParameter(),
+                             &Object::dynamic_type());
+    const bool allow_explicit_default_values = false;
+    const bool evaluate_metadata = false;
+    ParseFormalParameterList(use_function_type_syntax,
+                             allow_explicit_default_values, evaluate_metadata,
+                             &params);
+    if (result_type.IsNull()) {
+      result_type = Type::DynamicType();
+    }
+    signature_function.set_result_type(result_type);
+    AddFormalParamsToFunction(&params, signature_function);
+    ASSERT(innermost_function().raw() == signature_function.raw());
+    innermost_function_ = Function::null();
+  }
+  ExpectSemicolon();
+  ASSERT(innermost_function().IsNull());
+
   // Set the signature function in the function type alias class.
   function_type_alias.set_signature_function(signature_function);
 
-  const bool no_explicit_default_values = false;
-  ParseFormalParameterList(no_explicit_default_values, false, &func_params);
-  ExpectSemicolon();
-  signature_function.set_result_type(result_type);
-  AddFormalParamsToFunction(&func_params, signature_function);
-
-  ASSERT(innermost_function().raw() == signature_function.raw());
-  innermost_function_ = Function::null();
+  // At this point, all function type parameters have been parsed and the class
+  // function_type_alias is recognized as a typedef, so we can resolve all type
+  // parameters in the signature type defined by the typedef.
+  AbstractType& function_type =
+      Type::Handle(Z, signature_function.SignatureType());
+  ASSERT(current_class().raw() == function_type_alias.raw());
+  ResolveType(&function_type);
+  // Resolving does not replace type or signature.
+  ASSERT(function_type_alias.signature_function() ==
+         Type::Cast(function_type).signature());
 
   if (FLAG_trace_parser) {
     OS::Print("TopLevel parsing function type alias '%s'\n",
@@ -5266,7 +5424,7 @@
   if (CurrentToken() == Token::kLT) {
     do {
       ConsumeToken();
-      SkipType(false);
+      SkipTypeOrFunctionType(false);
     } while (CurrentToken() == Token::kCOMMA);
     Token::Kind token = CurrentToken();
     if ((token == Token::kGT) || (token == Token::kSHR)) {
@@ -5295,6 +5453,30 @@
 }
 
 
+void Parser::SkipTypeOrFunctionType(bool allow_void) {
+  if (CurrentToken() == Token::kVOID) {
+    TokenPosition void_pos = TokenPos();
+    ConsumeToken();
+    // 'void' is always allowed as result type of a function type.
+    if (!allow_void && !IsFunctionTypeSymbol()) {
+      ReportError(void_pos, "'void' not allowed here");
+    }
+  } else if (!IsFunctionTypeSymbol()) {
+    // Including 'Function' not followed by '(' or '<'.
+    SkipType(false);
+  }
+  while (IsFunctionTypeSymbol()) {
+    ConsumeToken();
+    SkipTypeArguments();
+    if (CurrentToken() == Token::kLPAREN) {
+      SkipToMatchingParenthesis();
+    } else {
+      ReportError("'(' expected");
+    }
+  }
+}
+
+
 void Parser::ParseTypeParameters(bool parameterizing_class) {
   TRACE_PARSER("ParseTypeParameters");
   if (CurrentToken() == Token::kLT) {
@@ -5330,24 +5512,13 @@
         // Postpone resolution in order to avoid resolving the owner and its
         // type parameters, as they are not fully parsed yet.
         type_parameter_bound = ParseType(ClassFinalizer::kDoNotResolve);
-        if (!parameterizing_class) {
-          // TODO(regis): Resolve and finalize function type parameter bounds in
-          // class finalizer. For now, ignore parsed bounds to avoid unresolved
-          // bounds while writing snapshots.
-          type_parameter_bound = I->object_store()->object_type();
-        }
       } else {
         type_parameter_bound = I->object_store()->object_type();
       }
       type_parameter = TypeParameter::New(
           parameterizing_class ? current_class() : Class::Handle(Z),
           parameterizing_class ? Function::Handle(Z) : innermost_function(),
-          index, type_parameter_name, type_parameter_bound, declaration_pos);
-      if (!parameterizing_class) {
-        // TODO(regis): Resolve and finalize function type parameter in
-        // class finalizer. For now, already mark as finalized.
-        type_parameter.SetIsFinalized();
-      }
+          index, 0, type_parameter_name, type_parameter_bound, declaration_pos);
       type_parameters_array.Add(
           &AbstractType::ZoneHandle(Z, type_parameter.raw()));
       if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
@@ -5368,14 +5539,12 @@
     } else {
       innermost_function().set_type_parameters(type_parameters);
     }
-    // Try to resolve the upper bounds, which will at least resolve the
-    // referenced type parameters.
+    // Resolve type parameters referenced by upper bounds.
     const intptr_t num_types = type_parameters.Length();
     for (intptr_t i = 0; i < num_types; i++) {
       type_parameter ^= type_parameters.TypeAt(i);
       type_parameter_bound = type_parameter.bound();
-      ResolveType(ClassFinalizer::kResolveTypeParameters,
-                  &type_parameter_bound);
+      ResolveType(&type_parameter_bound);
       type_parameter.set_bound(type_parameter_bound);
     }
   }
@@ -5390,7 +5559,7 @@
     AbstractType& type = AbstractType::Handle(Z);
     do {
       ConsumeToken();
-      type = ParseType(finalization);
+      type = ParseTypeOrFunctionType(false, finalization);
       // Map a malformed type argument to dynamic.
       if (type.IsMalformed()) {
         type = Type::DynamicType();
@@ -5491,13 +5660,16 @@
     // or final field implies a setter which throws a NoSuchMethodError,
     // thus we need to check for conflicts with existing setters and
     // getters.
-    String& accessor_name = String::Handle(Z, Field::GetterName(var_name));
-    if (library_.LookupLocalObject(accessor_name) != Object::null()) {
+    String& accessor_name =
+        String::Handle(Z, Field::LookupGetterSymbol(var_name));
+    if (!accessor_name.IsNull() &&
+        library_.LookupLocalObject(accessor_name) != Object::null()) {
       ReportError(name_pos, "getter for '%s' is already defined",
                   var_name.ToCString());
     }
-    accessor_name = Field::SetterName(var_name);
-    if (library_.LookupLocalObject(accessor_name) != Object::null()) {
+    accessor_name = Field::LookupSetterSymbol(var_name);
+    if (!accessor_name.IsNull() &&
+        library_.LookupLocalObject(accessor_name) != Object::null()) {
       ReportError(name_pos, "setter for '%s' is already defined",
                   var_name.ToCString());
     }
@@ -5596,16 +5768,11 @@
     ConsumeToken();
     is_external = true;
   }
-  if (CurrentToken() == Token::kVOID) {
-    ConsumeToken();
-    result_type = Type::VoidType();
-  } else {
-    // Parse optional type.
-    if (IsFunctionReturnType()) {
-      // It is too early to resolve the type here, since it can be a result type
-      // referring to a not yet declared function type parameter.
-      result_type = ParseType(ClassFinalizer::kDoNotResolve);
-    }
+  // Parse optional result type.
+  if (IsFunctionReturnType()) {
+    // It is too early to resolve the type here, since it can be a result type
+    // referring to a not yet declared function type parameter.
+    result_type = ParseTypeOrFunctionType(true, ClassFinalizer::kDoNotResolve);
   }
   const TokenPosition name_pos = TokenPos();
   const String& func_name = *ExpectIdentifier("function name expected");
@@ -5617,8 +5784,10 @@
     ReportError(name_pos, "missing '%s' cannot be patched",
                 func_name.ToCString());
   }
-  String& accessor_name = String::Handle(Z, Field::GetterName(func_name));
-  if (library_.LookupLocalObject(accessor_name) != Object::null()) {
+  const String& accessor_name =
+      String::Handle(Z, Field::LookupGetterSymbol(func_name));
+  if (!accessor_name.IsNull() &&
+      library_.LookupLocalObject(accessor_name) != Object::null()) {
     ReportError(name_pos, "'%s' is already defined as getter",
                 func_name.ToCString());
   }
@@ -5642,17 +5811,16 @@
     }
     ParseTypeParameters(false);  // Not parameterizing class, but function.
   }
-  // At this point, the type parameters have been parsed, so we can resolve the
-  // result type.
-  if (!result_type.IsNull()) {
-    ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type);
-  }
 
   CheckToken(Token::kLPAREN);
   const TokenPosition function_pos = TokenPos();
   ParamList params;
+  const bool use_function_type_syntax = false;
   const bool allow_explicit_default_values = true;
-  ParseFormalParameterList(allow_explicit_default_values, false, &params);
+  const bool evaluate_metadata = false;
+  ParseFormalParameterList(use_function_type_syntax,
+                           allow_explicit_default_values, evaluate_metadata,
+                           &params);
 
   const TokenPosition modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
@@ -5699,6 +5867,7 @@
   AddFormalParamsToFunction(&params, func);
   ASSERT(innermost_function().raw() == func.raw());
   innermost_function_ = Function::null();
+  ResolveSignature(func);
   top_level->AddFunction(func);
   if (!is_patch) {
     library_.AddObject(func, func_name);
@@ -5738,12 +5907,8 @@
     ConsumeToken();
     result_type = Type::DynamicType();
   } else {
-    if (CurrentToken() == Token::kVOID) {
-      ConsumeToken();
-      result_type = Type::VoidType();
-    } else {
-      result_type = ParseType(ClassFinalizer::kResolveTypeParameters);
-    }
+    result_type =
+        ParseTypeOrFunctionType(true, ClassFinalizer::kResolveTypeParameters);
     is_getter = (CurrentToken() == Token::kGET);
     if (CurrentToken() == Token::kGET || CurrentToken() == Token::kSET) {
       ConsumeToken();
@@ -5758,8 +5923,12 @@
   ParamList params;
 
   if (!is_getter) {
+    const bool use_function_type_syntax = false;
     const bool allow_explicit_default_values = true;
-    ParseFormalParameterList(allow_explicit_default_values, false, &params);
+    const bool evaluate_metadata = false;
+    ParseFormalParameterList(use_function_type_syntax,
+                             allow_explicit_default_values, evaluate_metadata,
+                             &params);
   }
   String& accessor_name = String::ZoneHandle(Z);
   int expected_num_parameters = -1;
@@ -5853,6 +6022,7 @@
     func.set_is_reflectable(false);
   }
   AddFormalParamsToFunction(&params, func);
+  ResolveSignature(func);
   top_level->AddFunction(func);
   if (!is_patch) {
     library_.AddObject(func, accessor_name);
@@ -6703,11 +6873,10 @@
   if (is_new_closure) {
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, body);
-
+    ResolveSignature(body);
     // Finalize function type.
     Type& signature_type = Type::Handle(Z, body.SignatureType());
-    signature_type ^= ClassFinalizer::FinalizeType(
-        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    signature_type ^= CanonicalizeType(signature_type);
     body.SetSignatureType(signature_type);
     ASSERT(AbstractType::Handle(Z, body.result_type()).IsResolved());
     ASSERT(body.NumParameters() == closure_params.parameters->length());
@@ -6831,11 +7000,11 @@
   if (is_new_closure) {
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, closure);
+    ResolveSignature(closure);
 
     // Finalize function type.
     Type& signature_type = Type::Handle(Z, closure.SignatureType());
-    signature_type ^= ClassFinalizer::FinalizeType(
-        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    signature_type ^= CanonicalizeType(signature_type);
     closure.SetSignatureType(signature_type);
     ASSERT(AbstractType::Handle(Z, closure.result_type()).IsResolved());
     ASSERT(closure.NumParameters() == closure_params.parameters->length());
@@ -6875,6 +7044,7 @@
   //   var :async_then_callback;
   //   var :async_catch_error_callback;
   //   var :async_completer;
+  //   var :async_stack_trace;
   LocalVariable* async_op_var =
       new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
                             Symbols::AsyncOperation(), Object::dynamic_type());
@@ -6891,6 +7061,10 @@
       new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
                             Symbols::AsyncCompleter(), Object::dynamic_type());
   current_block_->scope->AddVariable(async_completer);
+  LocalVariable* async_stack_trace = new (Z)
+      LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+                    Symbols::AsyncStackTraceVar(), Object::dynamic_type());
+  current_block_->scope->AddVariable(async_stack_trace);
 }
 
 
@@ -6903,6 +7077,7 @@
   //   var :async_op;
   //   var :async_then_callback;
   //   var :async_catch_error_callback;
+  //   var :async_stack_trace;
   // These variables are used to store the async generator closure containing
   // the body of the async* function. They are used by the await operator.
   LocalVariable* controller_var =
@@ -6921,6 +7096,10 @@
       LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
                     Symbols::AsyncCatchErrorCallback(), Object::dynamic_type());
   current_block_->scope->AddVariable(async_catch_error_callback_var);
+  LocalVariable* async_stack_trace = new (Z)
+      LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+                    Symbols::AsyncStackTraceVar(), Object::dynamic_type());
+  current_block_->scope->AddVariable(async_stack_trace);
 }
 
 
@@ -6960,11 +7139,11 @@
   if (is_new_closure) {
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, closure);
+    ResolveSignature(closure);
 
     // Finalize function type.
     Type& signature_type = Type::Handle(Z, closure.SignatureType());
-    signature_type ^= ClassFinalizer::FinalizeType(
-        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    signature_type ^= CanonicalizeType(signature_type);
     closure.SetSignatureType(signature_type);
     ASSERT(AbstractType::Handle(Z, closure.result_type()).IsResolved());
     ASSERT(closure.NumParameters() == closure_params.parameters->length());
@@ -7018,6 +7197,9 @@
   existing_var = closure_body->scope()->LookupVariable(
       Symbols::AsyncCatchErrorCallback(), false);
   ASSERT((existing_var != NULL) && existing_var->is_captured());
+  existing_var = closure_body->scope()->LookupVariable(
+      Symbols::AsyncStackTraceVar(), false);
+  ASSERT((existing_var != NULL) && existing_var->is_captured());
 
   const Library& async_lib = Library::Handle(Library::AsyncLibrary());
 
@@ -7037,6 +7219,28 @@
   current_block_->statements->Add(
       new (Z) StoreLocalNode(TokenPosition::kNoSource, jump_var, init_value));
 
+  TokenPosition token_pos = TokenPosition::kNoSource;
+
+  if (FLAG_causal_async_stacks) {
+    // Add to AST:
+    //   :async_stack_trace = _asyncStackTraceHelper();
+    const Function& async_stack_trace_helper = Function::ZoneHandle(
+        Z,
+        async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper()));
+    ASSERT(!async_stack_trace_helper.IsNull());
+    ArgumentListNode* async_stack_trace_helper_args =
+        new (Z) ArgumentListNode(TokenPosition::kNoSource);
+    StaticCallNode* async_stack_trace_helper_call = new (Z) StaticCallNode(
+        token_pos, async_stack_trace_helper, async_stack_trace_helper_args);
+    LocalVariable* async_stack_trace_var =
+        current_block_->scope->LookupVariable(Symbols::AsyncStackTraceVar(),
+                                              false);
+    StoreLocalNode* store_async_stack_trace = new (Z) StoreLocalNode(
+        token_pos, async_stack_trace_var, async_stack_trace_helper_call);
+    current_block_->statements->Add(store_async_stack_trace);
+  }
+
+
   // Add to AST:
   //   :async_op = <closure>;  (containing the original body)
   LocalVariable* async_op_var =
@@ -7180,6 +7384,9 @@
   existing_var =
       closure_body->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
   ASSERT((existing_var != NULL) && existing_var->is_captured());
+  existing_var = closure_body->scope()->LookupVariable(
+      Symbols::AsyncStackTraceVar(), false);
+  ASSERT((existing_var != NULL) && existing_var->is_captured());
 
   // Create and return a new future that executes a closure with the current
   // body.
@@ -7232,6 +7439,26 @@
   current_block_->statements->Add(store_async_op);
 
   const Library& async_lib = Library::Handle(Library::AsyncLibrary());
+
+  if (FLAG_causal_async_stacks) {
+    // Add to AST:
+    //   :async_stack_trace = _asyncStackTraceHelper();
+    const Function& async_stack_trace_helper = Function::ZoneHandle(
+        Z,
+        async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper()));
+    ASSERT(!async_stack_trace_helper.IsNull());
+    ArgumentListNode* async_stack_trace_helper_args =
+        new (Z) ArgumentListNode(token_pos);
+    StaticCallNode* async_stack_trace_helper_call = new (Z) StaticCallNode(
+        token_pos, async_stack_trace_helper, async_stack_trace_helper_args);
+    LocalVariable* async_stack_trace_var =
+        current_block_->scope->LookupVariable(Symbols::AsyncStackTraceVar(),
+                                              false);
+    StoreLocalNode* store_async_stack_trace = new (Z) StoreLocalNode(
+        token_pos, async_stack_trace_var, async_stack_trace_helper_call);
+    current_block_->statements->Add(store_async_stack_trace);
+  }
+
   // :async_then_callback = _asyncThenWrapperHelper(:async_op)
   const Function& async_then_wrapper_helper = Function::ZoneHandle(
       Z,
@@ -7322,6 +7549,22 @@
 }
 
 
+void Parser::FinalizeFormalParameterTypes(const ParamList* params) {
+  ASSERT((params != NULL) && (params->parameters != NULL));
+  const int num_parameters = params->parameters->length();
+  AbstractType& type = AbstractType::Handle(Z);
+  for (int i = 0; i < num_parameters; i++) {
+    ParamDesc& param_desc = (*params->parameters)[i];
+    type = param_desc.type->raw();
+    ResolveType(&type);
+    type = CanonicalizeType(type);
+    if (type.raw() != param_desc.type->raw()) {
+      param_desc.type = &AbstractType::ZoneHandle(Z, type.raw());
+    }
+  }
+}
+
+
 // Populate the parameter type array and parameter name array of the function
 // with the formal parameter types and names.
 void Parser::AddFormalParamsToFunction(const ParamList* params,
@@ -7376,7 +7619,6 @@
   const int num_parameters = params->parameters->length();
   for (int i = 0; i < num_parameters; i++) {
     ParamDesc& param_desc = (*params->parameters)[i];
-    ASSERT(!is_top_level_ || param_desc.type->IsResolved());
     const String* name = param_desc.name;
     LocalVariable* parameter = new (Z) LocalVariable(
         param_desc.name_pos, param_desc.name_pos, *name, *param_desc.type);
@@ -7555,6 +7797,9 @@
     ConsumeToken();
     type_is_optional = true;
   }
+  if ((CurrentToken() == Token::kVOID) || IsFunctionTypeSymbol()) {
+    return ParseFunctionType(AbstractType::Handle(Z), finalization);
+  }
   if (CurrentToken() != Token::kIDENT) {
     if (type_is_optional) {
       return Type::DynamicType();
@@ -7573,7 +7818,7 @@
       return Type::DynamicType();
     }
   }
-  return ParseType(finalization);
+  return ParseTypeOrFunctionType(false, finalization);
 }
 
 
@@ -7625,11 +7870,8 @@
 
 AstNode* Parser::ParseFunctionStatement(bool is_literal) {
   TRACE_PARSER("ParseFunctionStatement");
-  AbstractType& result_type = AbstractType::Handle(Z);
+  AbstractType& result_type = AbstractType::Handle(Z, Type::DynamicType());
   const String* function_name = NULL;
-
-  result_type = Type::DynamicType();
-
   const TokenPosition function_pos = TokenPos();
   TokenPosition function_name_pos = TokenPosition::kNoSource;
   TokenPosition metadata_pos = TokenPosition::kNoSource;
@@ -7638,13 +7880,12 @@
     function_name = &Symbols::AnonymousClosure();
   } else {
     metadata_pos = SkipMetadata();
-    if (CurrentToken() == Token::kVOID) {
-      ConsumeToken();
-      result_type = Type::VoidType();
-    } else if (IsFunctionReturnType()) {
+    // Parse optional result type.
+    if (IsFunctionReturnType()) {
       // It is too early to resolve the type here, since it can be a result type
       // referring to a not yet declared function type parameter.
-      result_type = ParseType(ClassFinalizer::kDoNotResolve);
+      result_type =
+          ParseTypeOrFunctionType(true, ClassFinalizer::kDoNotResolve);
     }
     function_name_pos = TokenPos();
     function_name = ExpectIdentifier("function name expected");
@@ -7705,9 +7946,8 @@
   if (!found_func && !result_type.IsFinalized()) {
     // Now that type parameters are declared, the result type can be resolved
     // and finalized.
-    ResolveType(ClassFinalizer::kCanonicalize, &result_type);
-    result_type = ClassFinalizer::FinalizeType(current_class(), result_type,
-                                               ClassFinalizer::kCanonicalize);
+    ResolveType(&result_type);
+    result_type = CanonicalizeType(result_type);
     function.set_result_type(result_type);
   }
 
@@ -7763,8 +8003,7 @@
 
     // Now that the local function has formal parameters, lookup the signature
     signature_type = function.SignatureType();
-    signature_type ^= ClassFinalizer::FinalizeType(
-        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    signature_type ^= CanonicalizeType(signature_type);
     function.SetSignatureType(signature_type);
   } else {
     // The local function was parsed before. The captured variables are
@@ -8014,6 +8253,15 @@
 }
 
 
+// Returns true if the current token is 'Function' followed by '<' or '('.
+// 'Function' not followed by '<' or '(' denotes the Function class.
+bool Parser::IsFunctionTypeSymbol() {
+  return IsSymbol(Symbols::Function()) &&
+         ((LookaheadToken(1) == Token::kLPAREN) ||
+          (LookaheadToken(1) == Token::kLT));
+}
+
+
 // Returns true if the next tokens can be parsed as a an optionally
 // qualified identifier: [ident '.'] ident.
 // Current token position is not restored.
@@ -8035,30 +8283,41 @@
 
 // Returns true if the next tokens can be parsed as a type with optional
 // type parameters. Current token position is not restored.
-bool Parser::TryParseOptionalType() {
-  if (CurrentToken() == Token::kIDENT) {
+// Allow 'void' as type if 'allow_void' is true.
+// Note that 'void Function()' is always allowed, since it is a function type
+// and not the void type.
+bool Parser::TryParseType(bool allow_void) {
+  bool found = false;
+  if (CurrentToken() == Token::kVOID) {
+    ConsumeToken();
+    if (allow_void) {
+      found = true;
+    } else if (!IsFunctionTypeSymbol()) {
+      return false;
+    }
+  } else if ((CurrentToken() == Token::kIDENT) && !IsFunctionTypeSymbol()) {
+    // 'Function' not followed by '(' or '<' means the Function class.
     if (!TryParseQualIdent()) {
       return false;
     }
     if ((CurrentToken() == Token::kLT) && !TryParseTypeParameters()) {
       return false;
     }
+    found = true;
   }
-  return true;
-}
-
-
-// Returns true if the next tokens can be parsed as a type with optional
-// type parameters, or keyword "void".
-// Current token position is not restored.
-bool Parser::TryParseReturnType() {
-  if (CurrentToken() == Token::kVOID) {
+  while (IsFunctionTypeSymbol()) {
     ConsumeToken();
-    return true;
-  } else if (CurrentToken() == Token::kIDENT) {
-    return TryParseOptionalType();
+    if ((CurrentToken() == Token::kLT) && !TryParseTypeParameters()) {
+      return false;
+    }
+    if (CurrentToken() == Token::kLPAREN) {
+      SkipToMatchingParenthesis();
+    } else {
+      return false;
+    }
+    found = true;
   }
-  return false;
+  return found;
 }
 
 
@@ -8082,8 +8341,10 @@
     SetPosition(saved_pos);
     return is_var_decl;
   }
-  if ((CurrentToken() != Token::kIDENT) && (CurrentToken() != Token::kCONST)) {
-    // Not a legal type identifier or const keyword or metadata.
+  if ((CurrentToken() != Token::kIDENT) && (CurrentToken() != Token::kVOID) &&
+      (CurrentToken() != Token::kCONST)) {
+    // Not a legal type identifier or void (result type of function type)
+    // or const keyword or metadata.
     return false;
   }
   const TokenPosition saved_pos = TokenPos();
@@ -8091,28 +8352,32 @@
   bool have_type = false;
   if (CurrentToken() == Token::kCONST) {
     ConsumeToken();
-    have_type = true;  // Type is dynamic.
+    have_type = true;  // Type is dynamic if 'const' is not followed by a type.
   }
-  if (IsIdentifier()) {  // Type or variable name.
+  if ((CurrentToken() == Token::kVOID) || IsFunctionTypeSymbol()) {
+    if (TryParseType(false)) {
+      have_type = true;
+    }
+  } else if (IsIdentifier()) {  // Type or variable name.
     Token::Kind follower = LookaheadToken(1);
     if ((follower == Token::kLT) ||       // Parameterized type.
         (follower == Token::kPERIOD) ||   // Qualified class name of type.
         Token::IsIdentifier(follower)) {  // Variable name following a type.
       // We see the beginning of something that could be a type.
       const TokenPosition type_pos = TokenPos();
-      if (TryParseOptionalType()) {
+      if (TryParseType(false)) {
         have_type = true;
       } else {
         SetPosition(type_pos);
       }
     }
-    if (have_type && IsIdentifier()) {
-      ConsumeToken();
-      if ((CurrentToken() == Token::kSEMICOLON) ||
-          (CurrentToken() == Token::kCOMMA) ||
-          (CurrentToken() == Token::kASSIGN)) {
-        is_var_decl = true;
-      }
+  }
+  if (have_type && IsIdentifier()) {
+    ConsumeToken();
+    if ((CurrentToken() == Token::kSEMICOLON) ||
+        (CurrentToken() == Token::kCOMMA) ||
+        (CurrentToken() == Token::kASSIGN)) {
+      is_var_decl = true;
     }
   }
   SetPosition(saved_pos);
@@ -8124,7 +8389,7 @@
 // by an identifier.
 bool Parser::IsFunctionReturnType() {
   TokenPosScope decl_pos(this);
-  if (TryParseReturnType()) {
+  if (TryParseType(true)) {
     if (IsIdentifier()) {
       // Return type followed by function name.
       return true;
@@ -8146,7 +8411,7 @@
     ConsumeToken();
   }
   const TokenPosition type_or_name_pos = TokenPos();
-  if (TryParseReturnType()) {
+  if (TryParseType(true)) {
     if (!IsIdentifier()) {
       SetPosition(type_or_name_pos);
     }
@@ -8186,7 +8451,7 @@
   if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) {
     return true;
   }
-  if (TryParseReturnType()) {
+  if (TryParseType(true)) {
     if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) {
       if (Token::IsIdentifier(LookaheadToken(1))) {  // Accessor name.
         return true;
@@ -8235,7 +8500,7 @@
   if (IsIdentifier()) {
     if (LookaheadToken(1) == Token::kIN) {
       return true;
-    } else if (TryParseOptionalType()) {
+    } else if (TryParseType(false)) {
       if (IsIdentifier()) {
         ConsumeToken();
       }
@@ -9534,7 +9799,7 @@
     if (IsSymbol(Symbols::On())) {
       ConsumeToken();
       exception_param.type = &AbstractType::ZoneHandle(
-          Z, ParseType(ClassFinalizer::kCanonicalize));
+          Z, ParseTypeOrFunctionType(false, ClassFinalizer::kCanonicalize));
     } else {
       exception_param.type = &Object::dynamic_type();
     }
@@ -10548,8 +10813,7 @@
   } else {
     AbstractType& type = AbstractType::ZoneHandle(Z);
     type ^= Type::New(cls, TypeArguments::Handle(Z), call_pos, Heap::kOld);
-    type ^= ClassFinalizer::FinalizeType(current_class(), type,
-                                         ClassFinalizer::kCanonicalize);
+    type ^= CanonicalizeType(type);
     arguments->Add(new (Z) LiteralNode(call_pos, type));
   }
   // String memberName.
@@ -10640,7 +10904,7 @@
         }
         const TokenPosition type_pos = TokenPos();
         const AbstractType& type = AbstractType::ZoneHandle(
-            Z, ParseType(ClassFinalizer::kCanonicalize));
+            Z, ParseTypeOrFunctionType(false, ClassFinalizer::kCanonicalize));
         if (!type.IsInstantiated() && (FunctionLevel() > 0)) {
           // Make sure that the instantiator is captured.
           CaptureInstantiator();
@@ -10918,13 +11182,13 @@
     ArgumentListNode* error_arguments =
         new (Z) ArgumentListNode(rhs->token_pos());
     error_arguments->Add(rhs);
-    result = ThrowNoSuchMethodError(original->token_pos(), *target_cls,
-                                    String::Handle(Z, Field::SetterName(name)),
-                                    error_arguments, InvocationMirror::kStatic,
-                                    original->IsLoadLocalNode()
-                                        ? InvocationMirror::kLocalVar
-                                        : InvocationMirror::kSetter,
-                                    NULL);  // No existing function.
+    result = ThrowNoSuchMethodError(
+        original->token_pos(), *target_cls,
+        String::Handle(Z, Field::SetterSymbol(name)), error_arguments,
+        InvocationMirror::kStatic,
+        original->IsLoadLocalNode() ? InvocationMirror::kLocalVar
+                                    : InvocationMirror::kSetter,
+        NULL);  // No existing function.
   }
   // The compound assignment operator a ??= b is different from other
   // a op= b assignments. If a is non-null, the assignment to a must be
@@ -11289,15 +11553,17 @@
     if (field.IsNull()) {
       // No field, check if we have an explicit getter function.
       const String& getter_name =
-          String::ZoneHandle(Z, Field::GetterName(func_name));
-      const int kNumArguments = 0;  // no arguments.
-      func = Resolver::ResolveStatic(cls, getter_name, kNumArguments,
-                                     Object::empty_array());
-      if (!func.IsNull()) {
-        ASSERT(func.kind() != RawFunction::kImplicitStaticFinalGetter);
-        closure = new (Z) StaticGetterNode(
-            call_pos, NULL, Class::ZoneHandle(Z, cls.raw()), func_name);
-        return BuildClosureCall(call_pos, closure, arguments);
+          String::ZoneHandle(Z, Field::LookupGetterSymbol(func_name));
+      if (!getter_name.IsNull()) {
+        const int kNumArguments = 0;  // no arguments.
+        func = Resolver::ResolveStatic(cls, getter_name, kNumArguments,
+                                       Object::empty_array());
+        if (!func.IsNull()) {
+          ASSERT(func.kind() != RawFunction::kImplicitStaticFinalGetter);
+          closure = new (Z) StaticGetterNode(
+              call_pos, NULL, Class::ZoneHandle(Z, cls.raw()), func_name);
+          return BuildClosureCall(call_pos, closure, arguments);
+        }
       }
     } else {
       closure = GenerateStaticFieldLookup(field, call_pos);
@@ -11514,8 +11780,7 @@
       // Make sure that the class instantiator is captured.
       CaptureInstantiator();
     }
-    type_parameter ^= ClassFinalizer::FinalizeType(
-        current_class(), type_parameter, ClassFinalizer::kCanonicalize);
+    type_parameter ^= CanonicalizeType(type_parameter);
     ASSERT(!type_parameter.IsMalformed());
     return new (Z) TypeNode(primary_pos, type_parameter);
   } else {
@@ -11634,11 +11899,11 @@
           AbstractType& type = Type::ZoneHandle(
               Z, Type::New(type_class, TypeArguments::Handle(Z), primary_pos,
                            Heap::kOld));
-          type ^= ClassFinalizer::FinalizeType(current_class(), type,
-                                               ClassFinalizer::kCanonicalize);
+          type ^= CanonicalizeType(type);
           // Type may be malbounded, but not malformed.
           ASSERT(!type.IsMalformed());
-          array = new (Z) TypeNode(primary_pos, type);
+          array = new (Z) TypeNode(primary_pos, type,
+                                   primary_node->is_deferred_reference());
         } else if (primary_node->primary().IsTypeParameter()) {
           array = LoadTypeParameter(primary_node);
         } else {
@@ -11729,11 +11994,11 @@
           AbstractType& type = Type::ZoneHandle(
               Z, Type::New(type_class, TypeArguments::Handle(Z), primary_pos,
                            Heap::kOld));
-          type ^= ClassFinalizer::FinalizeType(current_class(), type,
-                                               ClassFinalizer::kCanonicalize);
+          type ^= CanonicalizeType(type);
           // Type may be malbounded, but not malformed.
           ASSERT(!type.IsMalformed());
-          selector = new (Z) TypeNode(primary_pos, type);
+          selector = new (Z) TypeNode(primary_pos, type,
+                                      primary_node->is_deferred_reference());
         } else {
           UNREACHABLE();  // Internal parser error.
         }
@@ -11756,11 +12021,11 @@
           AbstractType& type = Type::ZoneHandle(
               Z, Type::New(type_class, TypeArguments::Handle(Z), primary_pos,
                            Heap::kOld));
-          type = ClassFinalizer::FinalizeType(current_class(), type,
-                                              ClassFinalizer::kCanonicalize);
+          type = CanonicalizeType(type);
           // Type may be malbounded, but not malformed.
           ASSERT(!type.IsMalformed());
-          left = new (Z) TypeNode(primary_pos, type);
+          left = new (Z) TypeNode(primary_pos, type,
+                                  primary_node->is_deferred_reference());
         } else if (primary_node->primary().IsTypeParameter()) {
           left = LoadTypeParameter(primary_node);
         } else if (primary_node->IsSuper()) {
@@ -11827,8 +12092,10 @@
       // name, so we explicitly prevent lookup of private names here.
       if (is_setter_name) {
         const String& setter_name =
-            String::Handle(Z, Field::SetterName(extractor_name));
-        obj = prefix.LookupObject(setter_name);
+            String::Handle(Z, Field::LookupSetterSymbol(extractor_name));
+        if (!setter_name.IsNull()) {
+          obj = prefix.LookupObject(setter_name);
+        }
       }
       if (obj.IsNull()) {
         obj = prefix.LookupObject(extractor_name);
@@ -11875,7 +12142,6 @@
         Field::Handle(Z, cls.LookupStaticField(extractor_name));
     if (!field.IsNull()) {
       if (is_setter_name) {
-        extractor_name = Field::SetterName(extractor_name);
         if (!field.is_final()) {
           const Instance& setter_closure =
               Instance::ZoneHandle(Z, field.SetterClosure());
@@ -11885,6 +12151,7 @@
           // be invoked here. The same applies for getters below.
           return new (Z) LiteralNode(property_pos, setter_closure);
         }
+        extractor_name = Field::SetterSymbol(extractor_name);
       } else {
         const Instance& getter_closure =
             Instance::ZoneHandle(Z, field.GetterClosure());
@@ -11894,14 +12161,20 @@
     } else {
       Function& func = Function::Handle(Z);
       if (is_setter_name) {
-        extractor_name = Field::SetterName(extractor_name);
-        func = cls.LookupStaticFunction(extractor_name);
+        extractor_name = Field::LookupSetterSymbol(extractor_name);
+        if (!extractor_name.IsNull()) {
+          func = cls.LookupStaticFunction(extractor_name);
+        } else {
+          extractor_name = Field::SetterSymbol(extractor_name);
+        }
       } else {
         func = cls.LookupStaticFunction(extractor_name);
         if (func.IsNull()) {
           const String& getter_name =
-              String::Handle(Z, Field::GetterName(extractor_name));
-          func = cls.LookupStaticFunction(getter_name);
+              String::Handle(Z, Field::LookupGetterSymbol(extractor_name));
+          if (!getter_name.IsNull()) {
+            func = cls.LookupStaticFunction(getter_name);
+          }
         }
       }
       if (!func.IsNull()) {
@@ -11969,36 +12242,79 @@
 }
 
 
-// Resolve the given type and its type arguments from the current function and
-// current class according to the given type finalization mode.
-// Not all involved type classes may get resolved yet, but at least type
-// parameters will get resolved, thereby relieving the class
-// finalizer from resolving type parameters out of context.
-// TODO(regis): Refactor this code which is partially duplicated in the class
-// finalizer, paying attention to type parameter resolution and mixin library.
-void Parser::ResolveType(ClassFinalizer::FinalizationKind finalization,
-                         AbstractType* type) {
-  ASSERT(finalization >= ClassFinalizer::kResolveTypeParameters);
+// Resolve the type parameters that may appear in the given signature from the
+// signature function and current class.
+// Unresolved type classes get resolved later by the class finalizer.
+void Parser::ResolveSignature(const Function& signature) {
+  const Function& saved_innermost_function =
+      Function::Handle(Z, innermost_function().raw());
+  innermost_function_ = signature.raw();
+  AbstractType& type = AbstractType::Handle();
+  // Resolve upper bounds of function type parameters.
+  const intptr_t num_type_params = signature.NumTypeParameters();
+  if (num_type_params > 0) {
+    TypeParameter& type_param = TypeParameter::Handle();
+    const TypeArguments& type_params =
+        TypeArguments::Handle(signature.type_parameters());
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type_param ^= type_params.TypeAt(i);
+      type = type_param.bound();
+      ResolveType(&type);
+      type_param.set_bound(type);
+    }
+  }
+  // Resolve result type.
+  type = signature.result_type();
+  ResolveType(&type);
+  signature.set_result_type(type);
+  // Resolve formal parameter types.
+  const intptr_t num_parameters = signature.NumParameters();
+  for (intptr_t i = 0; i < num_parameters; i++) {
+    type = signature.ParameterTypeAt(i);
+    ResolveType(&type);
+    signature.SetParameterTypeAt(i, type);
+  }
+  innermost_function_ = saved_innermost_function.raw();
+}
+
+
+// Resolve the type parameters that may appear in the given type and in its type
+// arguments from the current function and current class.
+// Unresolved type classes get resolved later by the class finalizer.
+void Parser::ResolveType(AbstractType* type) {
   ASSERT(type != NULL);
   if (type->IsResolved()) {
+    // Some types are resolved by definition, such as a TypeParameter.
     return;
   }
-  // Resolve class.
+  // Resolve type class.
   if (!type->HasResolvedTypeClass()) {
     const UnresolvedClass& unresolved_class =
         UnresolvedClass::Handle(Z, type->unresolved_class());
     const String& unresolved_class_name =
         String::Handle(Z, unresolved_class.ident());
-    Class& resolved_type_class = Class::Handle(Z);
     if (unresolved_class.library_or_library_prefix() == Object::null()) {
       // First check if the type is a function type parameter.
       if (!innermost_function().IsNull()) {
         // TODO(regis): Shortcut this lookup if no generic functions in scope.
+        // A bit has_generic_parent() would be useful on Function.
+        // Unfortunately, all 32 kind bits are used in Function.
         TypeParameter& type_parameter = TypeParameter::ZoneHandle(
             Z, innermost_function().LookupTypeParameter(unresolved_class_name,
                                                         NULL));
         if (!type_parameter.IsNull()) {
-          // TODO(regis): Check for absence of type arguments.
+          // A type parameter cannot be parameterized, so make the type
+          // malformed if type arguments have previously been parsed.
+          if (type->arguments() != TypeArguments::null()) {
+            *type = ClassFinalizer::NewFinalizedMalformedType(
+                Error::Handle(Z),  // No previous error.
+                script_, type_parameter.token_pos(),
+                "type parameter '%s' cannot be parameterized",
+                String::Handle(Z, type_parameter.name()).ToCString());
+            return;
+          }
+          // TODO(regis): Mark function type parameter as finalized (its index
+          // does not need adjustment upon finalization) and return it.
           // For now, resolve the function type parameter to dynamic.
           *type = Type::DynamicType();
           return;
@@ -12032,50 +12348,7 @@
         *type = type_parameter.raw();
         return;
       }
-      // The referenced class may not have been parsed yet. It would be wrong
-      // to resolve it too early to an imported class of the same name. Only
-      // resolve the class when a finalized type is requested.
-      // Note that when compiling a cloned mixin function, library_ may be
-      // different than current_class's library.
-      if (finalization > ClassFinalizer::kResolveTypeParameters) {
-        resolved_type_class = library_.LookupClass(unresolved_class_name);
-      }
-    } else {
-      // Resolve class name in the scope of the library prefix.
-      const Object& prefix =
-          Object::Handle(Z, unresolved_class.library_or_library_prefix());
-      ASSERT(prefix.IsLibraryPrefix());
-      resolved_type_class =
-          LibraryPrefix::Cast(prefix).LookupClass(unresolved_class_name);
     }
-    // At this point, we can only have a parameterized_type.
-    const Type& parameterized_type = Type::Cast(*type);
-    if (!resolved_type_class.IsNull()) {
-      // Replace unresolved class with resolved type class.
-      parameterized_type.set_type_class(resolved_type_class);
-      // Promote type to a function type in case its type class is a typedef.
-      if (resolved_type_class.IsTypedefClass()) {
-        ASSERT(!parameterized_type.IsFunctionType());
-        parameterized_type.set_signature(
-            Function::Handle(Z, resolved_type_class.signature_function()));
-      }
-      // Replace FutureOr<T> type of async library with dynamic.
-      if ((resolved_type_class.library() == Library::AsyncLibrary()) &&
-          (resolved_type_class.Name() == Symbols::FutureOr().raw())) {
-        parameterized_type.set_type_class(
-            Class::Handle(Object::dynamic_class()));
-        parameterized_type.set_arguments(Object::null_type_arguments());
-      }
-    } else if (finalization >= ClassFinalizer::kCanonicalize) {
-      ClassFinalizer::FinalizeMalformedType(
-          Error::Handle(Z),  // No previous error.
-          script_, parameterized_type, "type '%s' is not loaded",
-          String::Handle(Z, parameterized_type.UserVisibleName()).ToCString());
-      return;
-    }
-  }
-  if (finalization > ClassFinalizer::kResolveTypeParameters) {
-    type->SetIsResolved();
   }
   // Resolve type arguments, if any.
   if (type->arguments() != TypeArguments::null()) {
@@ -12084,8 +12357,8 @@
     const intptr_t num_arguments = arguments.Length();
     AbstractType& type_argument = AbstractType::Handle(Z);
     for (intptr_t i = 0; i < num_arguments; i++) {
-      type_argument ^= arguments.TypeAt(i);
-      ResolveType(finalization, &type_argument);
+      type_argument = arguments.TypeAt(i);
+      ResolveType(&type_argument);
       arguments.SetTypeAt(i, type_argument);
     }
   }
@@ -12094,43 +12367,27 @@
         Function::Handle(Z, Type::Cast(*type).signature());
     Type& signature_type = Type::Handle(Z, signature.SignatureType());
     if (signature_type.raw() != type->raw()) {
-      ResolveType(finalization, &signature_type);
+      ResolveType(&signature_type);
     } else {
-      AbstractType& type = AbstractType::Handle(signature.result_type());
-      ResolveType(finalization, &type);
-      signature.set_result_type(type);
-      const intptr_t num_parameters = signature.NumParameters();
-      for (intptr_t i = 0; i < num_parameters; i++) {
-        type = signature.ParameterTypeAt(i);
-        ResolveType(finalization, &type);
-        signature.SetParameterTypeAt(i, type);
-      }
-      if (signature.IsSignatureFunction()) {
-        // Drop fields that are not necessary anymore after resolution.
-        // The parent function, owner, and token position of a shared
-        // canonical function type are meaningless, since the canonical
-        // representent is picked arbitrarily.
-        signature.set_parent_function(Function::Handle(Z));
-        // TODO(regis): As long as we support metadata in typedef signatures,
-        // we cannot reset these fields used to reparse a typedef.
-        // Note that the scope class of a typedef function type is always
-        // preserved as the typedef class (not reset to _Closure class), thereby
-        // preventing sharing of canonical function types between typedefs.
-        // Not being shared, these fields are therefore always meaningful for
-        // typedefs.
-        if (type.HasResolvedTypeClass()) {
-          const Class& scope_class = Class::Handle(Z, type.type_class());
-          if (!scope_class.IsTypedefClass()) {
-            signature.set_owner(Object::Handle(Z));
-            signature.set_token_pos(TokenPosition::kNoSource);
-          }
-        }
-      }
+      ResolveSignature(signature);
     }
   }
 }
 
 
+RawAbstractType* Parser::CanonicalizeType(const AbstractType& type) {
+  // If the current class is the result of a mixin application, we must
+  // use the class scope of the class from which the function originates.
+  if (current_class().IsMixinApplication()) {
+    return ClassFinalizer::FinalizeType(
+        Class::Handle(Z, parsed_function()->function().origin()), type,
+        ClassFinalizer::kCanonicalize);
+  }
+  return ClassFinalizer::FinalizeType(current_class(), type,
+                                      ClassFinalizer::kCanonicalize);
+}
+
+
 LocalVariable* Parser::LookupLocalScope(const String& ident) {
   if (current_block_ == NULL) {
     return NULL;
@@ -12652,12 +12909,14 @@
       if ((resolved == NULL) || (resolved_func_level < type_param_func_level)) {
         // The identifier is a function type parameter, possibly shadowing
         // 'resolved'.
-        if (type_param_func_level < FunctionLevel()) {
+        if ((FunctionLevel() > 0) &&
+            (type_param_func_level < FunctionLevel())) {
           // Make sure that the function instantiator is captured.
           CaptureFunctionInstantiator();
         }
-        // TODO(regis): Finalize type parameter and return as type node.
-        // For now, map to dynamic type.
+        // TODO(regis): Mark function type parameter as finalized (its index
+        // does not need adjustment upon finalization) and return as type node.
+        // For now, resolve the function type parameter to dynamic.
         Type& type = Type::ZoneHandle(Z, Type::DynamicType());
         return new (Z) TypeNode(ident_pos, type);
       }
@@ -12673,8 +12932,7 @@
           // Make sure that the class instantiator is captured.
           CaptureInstantiator();
         }
-        type_parameter ^= ClassFinalizer::FinalizeType(
-            current_class(), type_parameter, ClassFinalizer::kCanonicalize);
+        type_parameter ^= CanonicalizeType(type_parameter);
         ASSERT(!type_parameter.IsMalformed());
         return new (Z) TypeNode(ident_pos, type_parameter);
       }
@@ -12715,11 +12973,11 @@
       AbstractType& type =
           Type::ZoneHandle(Z, Type::New(type_class, TypeArguments::Handle(Z),
                                         primary_pos, Heap::kOld));
-      type ^= ClassFinalizer::FinalizeType(current_class(), type,
-                                           ClassFinalizer::kCanonicalize);
+      type ^= CanonicalizeType(type);
       // Type may be malbounded, but not malformed.
       ASSERT(!type.IsMalformed());
-      resolved = new (Z) TypeNode(primary_pos, type);
+      resolved =
+          new (Z) TypeNode(primary_pos, type, primary->is_deferred_reference());
     }
   }
   return resolved;
@@ -12735,8 +12993,123 @@
                    &prefix);
 }
 
+
+// Parses and returns a type or a function type.
+RawAbstractType* Parser::ParseTypeOrFunctionType(
+    bool allow_void,
+    ClassFinalizer::FinalizationKind finalization) {
+  TRACE_PARSER("ParseTypeOrFunctionType");
+  AbstractType& type = AbstractType::Handle(Z);
+  if (CurrentToken() == Token::kVOID) {
+    TokenPosition void_pos = TokenPos();
+    type = Type::VoidType();
+    ConsumeToken();
+    // 'void' is always allowed as result type of a function type.
+    if (!allow_void && !IsFunctionTypeSymbol()) {
+      ReportError(void_pos, "'void' not allowed here");
+    }
+  } else if (!IsFunctionTypeSymbol()) {
+    // Including 'Function' not followed by '(' or '<'.
+    // It is too early to resolve the type here, since it can
+    // refer to a not yet declared function type parameter.
+    type = ParseType(ClassFinalizer::kDoNotResolve);
+  }
+  while (IsFunctionTypeSymbol()) {
+    if (type.IsNull()) {
+      type = Type::DynamicType();
+    }
+    // 'type' is the result type of the function type.
+    type = ParseFunctionType(type, ClassFinalizer::kDoNotResolve);
+  }
+  // At this point, all type parameters have been parsed, resolve the type.
+  if (finalization == ClassFinalizer::kIgnore) {
+    return Type::DynamicType();
+  }
+  if (finalization >= ClassFinalizer::kResolveTypeParameters) {
+    ResolveType(&type);
+    if (finalization >= ClassFinalizer::kCanonicalize) {
+      type ^= CanonicalizeType(type);
+    }
+  }
+  return type.raw();
+}
+
+
+// Parses and returns a function type.
+// If 'result_type' is not null, parsing of the result type is skipped.
+RawType* Parser::ParseFunctionType(
+    const AbstractType& result_type,
+    ClassFinalizer::FinalizationKind finalization) {
+  TRACE_PARSER("ParseFunctionType");
+  AbstractType& type = AbstractType::Handle(Z, result_type.raw());
+  if (type.IsNull()) {
+    if (CurrentToken() == Token::kVOID) {
+      ConsumeToken();
+      type = Type::VoidType();
+    } else if (IsFunctionTypeSymbol()) {
+      type = Type::DynamicType();
+    } else {
+      // Including 'Function' not followed by '(' or '<'.
+      // It is too early to resolve the type here, since it can
+      // refer to a not yet declared function type parameter.
+      type = ParseType(ClassFinalizer::kDoNotResolve);
+    }
+  }
+  if (!IsSymbol(Symbols::Function())) {
+    ReportError("'Function' expected");
+  }
+  do {
+    ConsumeToken();
+    const Function& signature_function =
+        Function::Handle(Z, Function::NewSignatureFunction(
+                                current_class(), TokenPosition::kNoSource));
+    signature_function.set_parent_function(innermost_function());
+    innermost_function_ = signature_function.raw();
+    signature_function.set_result_type(type);
+    // Parse optional type parameters.
+    if (CurrentToken() == Token::kLT) {
+      if (!FLAG_generic_method_syntax) {
+        ReportError("generic type arguments not supported.");
+      }
+      ParseTypeParameters(false);  // Not parameterizing class, but function.
+    }
+    ParamList params;
+    // We do not yet allow Function of any arity, so expect parameter list.
+    CheckToken(Token::kLPAREN, "formal parameter list expected");
+
+    // Add implicit closure object parameter. Do not specify a token position,
+    // since it would make no sense after function type canonicalization.
+    params.AddFinalParameter(TokenPosition::kNoSource,
+                             &Symbols::ClosureParameter(),
+                             &Object::dynamic_type());
+
+    const bool use_function_type_syntax = true;
+    const bool allow_explicit_default_values = false;
+    const bool evaluate_metadata = false;
+    ParseFormalParameterList(use_function_type_syntax,
+                             allow_explicit_default_values, evaluate_metadata,
+                             &params);
+    AddFormalParamsToFunction(&params, signature_function);
+    innermost_function_ = innermost_function_.parent_function();
+    type = signature_function.SignatureType();
+  } while (IsFunctionTypeSymbol());
+  // At this point, all type parameters have been parsed, resolve the type.
+  if (finalization == ClassFinalizer::kIgnore) {
+    return Type::DynamicType();
+  }
+  if (finalization >= ClassFinalizer::kResolveTypeParameters) {
+    ResolveType(&type);
+    if (finalization >= ClassFinalizer::kCanonicalize) {
+      type ^= CanonicalizeType(type);
+    }
+  }
+  return Type::RawCast(type.raw());
+}
+
+
 // Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
-// finalize it according to the given type finalization mode. Returns prefix.
+// finalize it according to the given type finalization mode.
+// Returns type and sets prefix.
 RawAbstractType* Parser::ParseType(
     ClassFinalizer::FinalizationKind finalization,
     bool allow_deferred_type,
@@ -12839,9 +13212,9 @@
   AbstractType& type = AbstractType::Handle(
       Z, Type::New(type_class, type_arguments, ident_pos, Heap::kOld));
   if (finalization >= ClassFinalizer::kResolveTypeParameters) {
-    ResolveType(finalization, &type);
+    ResolveType(&type);
     if (finalization >= ClassFinalizer::kCanonicalize) {
-      type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization);
+      type ^= CanonicalizeType(type);
     }
   }
   return type.raw();
@@ -12922,8 +13295,7 @@
   const Class& array_class = Class::Handle(Z, I->object_store()->array_class());
   Type& type = Type::ZoneHandle(
       Z, Type::New(array_class, list_type_arguments, type_pos, Heap::kOld));
-  type ^= ClassFinalizer::FinalizeType(current_class(), type,
-                                       ClassFinalizer::kCanonicalize);
+  type ^= CanonicalizeType(type);
   GrowableArray<AstNode*> element_list;
   // Parse the list elements. Note: there may be an optional extra
   // comma after the last element.
@@ -13005,12 +13377,15 @@
       ASSERT(factory_type_args.Length() == 1);
       Type& factory_type = Type::Handle(
           Z, Type::New(factory_class, factory_type_args, type_pos, Heap::kOld));
-      factory_type ^= ClassFinalizer::FinalizeType(
-          current_class(), factory_type, ClassFinalizer::kFinalize);
+      // It is not strictly necessary to canonicalize factory_type, but only its
+      // type argument vector.
+      factory_type ^= CanonicalizeType(factory_type);
       factory_type_args = factory_type.arguments();
       ASSERT(factory_type_args.Length() == factory_class.NumTypeArguments());
+      ASSERT(factory_type_args.IsCanonical());
+    } else {
+      factory_type_args = factory_type_args.Canonicalize();
     }
-    factory_type_args = factory_type_args.Canonicalize();
     ArgumentListNode* factory_param = new (Z) ArgumentListNode(literal_pos);
     if (element_list.length() == 0) {
       LiteralNode* empty_array_literal =
@@ -13252,12 +13627,15 @@
       ASSERT(factory_type_args.Length() == 2);
       Type& factory_type = Type::Handle(
           Z, Type::New(factory_class, factory_type_args, type_pos, Heap::kOld));
-      factory_type ^= ClassFinalizer::FinalizeType(
-          current_class(), factory_type, ClassFinalizer::kFinalize);
+      // It is not strictly necessary to canonicalize factory_type, but only its
+      // type argument vector.
+      factory_type ^= CanonicalizeType(factory_type);
       factory_type_args = factory_type.arguments();
       ASSERT(factory_type_args.Length() == factory_class.NumTypeArguments());
+      ASSERT(factory_type_args.IsCanonical());
+    } else {
+      factory_type_args = factory_type_args.Canonicalize();
     }
-    factory_type_args = factory_type_args.Canonicalize();
     ArgumentListNode* factory_param = new (Z) ArgumentListNode(literal_pos);
     // The kv_pair array is temporary and of element type dynamic. It is passed
     // to the factory to initialize a properly typed map. Pass a pre-allocated
@@ -13386,11 +13764,11 @@
   closure.set_is_visible(false);
   closure.set_result_type(Object::dynamic_type());
   AddFormalParamsToFunction(&params, closure);
+  ResolveSignature(closure);
 
   // Finalize function type.
   Type& signature_type = Type::Handle(Z, closure.SignatureType());
-  signature_type ^= ClassFinalizer::FinalizeType(
-      current_class(), signature_type, ClassFinalizer::kCanonicalize);
+  signature_type ^= CanonicalizeType(signature_type);
   closure.SetSignatureType(signature_type);
   // Finalization would be premature when top-level parsing.
   ASSERT(!is_top_level_);
@@ -14007,7 +14385,8 @@
               (primary_func_level < type_param_func_level)) {
             // The identifier is a function type parameter, possibly shadowing
             // already resolved 'primary'.
-            if (type_param_func_level < FunctionLevel()) {
+            if ((FunctionLevel() > 0) &&
+                (type_param_func_level < FunctionLevel())) {
               // Make sure that the function instantiator is captured.
               CaptureFunctionInstantiator();
             }
@@ -14230,7 +14609,7 @@
 void Parser::SkipFunctionLiteral() {
   if (IsIdentifier()) {
     if (LookaheadToken(1) != Token::kLPAREN) {
-      SkipType(true);
+      SkipTypeOrFunctionType(true);
     }
     ExpectIdentifier("function name expected");
   }
@@ -14256,6 +14635,12 @@
 void Parser::SkipFunctionPreamble() {
   while (true) {
     const Token::Kind token = CurrentToken();
+    if (IsFunctionTypeSymbol()) {
+      ConsumeToken();
+      SkipTypeArguments();
+      SkipToMatchingParenthesis();
+      continue;
+    }
     if (token == Token::kLPAREN) {
       return;
     }
@@ -14530,10 +14915,10 @@
       if (CurrentToken() == Token::kNOT) {
         ConsumeToken();
       }
-      SkipType(false);
+      SkipTypeOrFunctionType(false);
     } else if (CurrentToken() == Token::kAS) {
       ConsumeToken();
-      SkipType(false);
+      SkipTypeOrFunctionType(false);
     } else {
       ConsumeToken();
       SkipUnaryExpr();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 7f11efe..539435b 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -403,6 +403,7 @@
   bool IsPatchAnnotation(TokenPosition pos);
   void SkipTypeArguments();
   void SkipType(bool allow_void);
+  void SkipTypeOrFunctionType(bool allow_void);
   void SkipInitializers();
   void SkipExpr();
   void SkipNestedExpr();
@@ -513,8 +514,9 @@
   void ParseLibraryImportObsoleteSyntax();
   void ParseLibraryIncludeObsoleteSyntax();
 
-  void ResolveType(ClassFinalizer::FinalizationKind finalization,
-                   AbstractType* type);
+  void ResolveSignature(const Function& signature);
+  void ResolveType(AbstractType* type);
+  RawAbstractType* CanonicalizeType(const AbstractType& type);
   RawAbstractType* ParseType(ClassFinalizer::FinalizationKind finalization,
                              bool allow_deferred_type = false,
                              bool consume_unresolved_prefix = true);
@@ -522,7 +524,11 @@
                              bool allow_deferred_type,
                              bool consume_unresolved_prefix,
                              LibraryPrefix* prefix);
-
+  RawType* ParseFunctionType(const AbstractType& result_type,
+                             ClassFinalizer::FinalizationKind finalization);
+  RawAbstractType* ParseTypeOrFunctionType(
+      bool allow_void,
+      ClassFinalizer::FinalizationKind finalization);
   void ParseTypeParameters(bool parameterizing_class);
   RawTypeArguments* ParseTypeArguments(
       ClassFinalizer::FinalizationKind finalization);
@@ -531,13 +537,16 @@
   void CheckMemberNameConflict(ClassDesc* members, MemberDesc* member);
   void ParseClassMemberDefinition(ClassDesc* members,
                                   TokenPosition metadata_pos);
+  void ParseParameterType(ParamList* params);
   void ParseFormalParameter(bool allow_explicit_default_value,
                             bool evaluate_metadata,
                             ParamList* params);
-  void ParseFormalParameters(bool allow_explicit_default_values,
+  void ParseFormalParameters(bool use_function_type_syntax,
+                             bool allow_explicit_default_values,
                              bool evaluate_metadata,
                              ParamList* params);
-  void ParseFormalParameterList(bool allow_explicit_default_values,
+  void ParseFormalParameterList(bool use_function_type_syntax,
+                                bool allow_explicit_default_values,
                                 bool evaluate_metadata,
                                 ParamList* params);
   void CheckFieldsInitialized(const Class& cls);
@@ -601,6 +610,7 @@
   ClosureNode* CreateImplicitClosureNode(const Function& func,
                                          TokenPosition token_pos,
                                          AstNode* receiver);
+  void FinalizeFormalParameterTypes(const ParamList* params);
   void AddFormalParamsToFunction(const ParamList* params, const Function& func);
   void AddFormalParamsToScope(const ParamList* params, LocalScope* scope);
 
@@ -749,15 +759,15 @@
   bool IsIdentifier();
   bool IsSymbol(const String& symbol);
   bool IsSimpleLiteral(const AbstractType& type, Instance* value);
-  bool IsFunctionTypeAliasName();
+  bool IsFunctionTypeSymbol();
+  bool IsFunctionTypeAliasName(bool* use_function_type_syntax);
   bool TryParseQualIdent();
   bool TryParseTypeParameters();
   bool TryParseTypeArguments();
   bool IsTypeParameters();
   bool IsArgumentPart();
   bool IsParameterPart();
-  bool TryParseOptionalType();
-  bool TryParseReturnType();
+  bool TryParseType(bool allow_void);
   bool IsVariableDeclaration();
   bool IsFunctionReturnType();
   bool IsFunctionDeclaration();
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 13c2b68..a053603 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -495,6 +495,7 @@
 
     ShareMegamorphicBuckets();
     DedupStackMaps();
+    DedupCodeSourceMaps();
     DedupLists();
 
     if (FLAG_dedup_instructions) {
@@ -984,6 +985,13 @@
       }
     }
   }
+
+  const Array& inlined_functions =
+      Array::Handle(Z, code.inlined_id_to_function());
+  for (intptr_t i = 0; i < inlined_functions.Length(); i++) {
+    target ^= inlined_functions.At(i);
+    AddTypesOf(target);
+  }
 }
 
 
@@ -2341,6 +2349,50 @@
 }
 
 
+void Precompiler::DedupCodeSourceMaps() {
+  class DedupCodeSourceMapsVisitor : public FunctionVisitor {
+   public:
+    explicit DedupCodeSourceMapsVisitor(Zone* zone)
+        : zone_(zone),
+          canonical_code_source_maps_(),
+          code_(Code::Handle(zone)),
+          code_source_map_(CodeSourceMap::Handle(zone)) {}
+
+    void Visit(const Function& function) {
+      if (!function.HasCode()) {
+        return;
+      }
+      code_ = function.CurrentCode();
+      code_source_map_ = code_.code_source_map();
+      ASSERT(!code_source_map_.IsNull());
+      code_source_map_ = DedupCodeSourceMap(code_source_map_);
+      code_.set_code_source_map(code_source_map_);
+    }
+
+    RawCodeSourceMap* DedupCodeSourceMap(const CodeSourceMap& code_source_map) {
+      const CodeSourceMap* canonical_code_source_map =
+          canonical_code_source_maps_.LookupValue(&code_source_map);
+      if (canonical_code_source_map == NULL) {
+        canonical_code_source_maps_.Insert(
+            &CodeSourceMap::ZoneHandle(zone_, code_source_map.raw()));
+        return code_source_map.raw();
+      } else {
+        return canonical_code_source_map->raw();
+      }
+    }
+
+   private:
+    Zone* zone_;
+    CodeSourceMapSet canonical_code_source_maps_;
+    Code& code_;
+    CodeSourceMap& code_source_map_;
+  };
+
+  DedupCodeSourceMapsVisitor visitor(Z);
+  ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
 void Precompiler::DedupLists() {
   class DedupListsVisitor : public FunctionVisitor {
    public:
@@ -2358,6 +2410,11 @@
           list_ = DedupList(list_);
           code_.set_stackmaps(list_);
         }
+        list_ = code_.inlined_id_to_function();
+        if (!list_.IsNull()) {
+          list_ = DedupList(list_);
+          code_.set_inlined_id_to_function(list_);
+        }
       }
 
       list_ = function.parameter_types();
@@ -2677,7 +2734,7 @@
   {
     CanonicalTypeSet types_table(Z, object_store->canonical_types());
     types_array = HashTables::ToArray(types_table, false);
-    for (intptr_t i = 0; i < (types_array.Length() - 1); i++) {
+    for (intptr_t i = 0; i < types_array.Length(); i++) {
       type ^= types_array.At(i);
       types.Add(type);
     }
@@ -2690,7 +2747,7 @@
   for (intptr_t i = 0; i < types.Length(); i++) {
     type ^= types.At(i);
     bool present = types_table.Insert(type);
-    ASSERT(!present);
+    ASSERT(!present || type.IsRecursive());
   }
   object_store->set_canonical_types(types_table.Release());
 
@@ -2703,7 +2760,7 @@
     CanonicalTypeArgumentsSet typeargs_table(
         Z, object_store->canonical_type_arguments());
     typeargs_array = HashTables::ToArray(typeargs_table, false);
-    for (intptr_t i = 0; i < (typeargs_array.Length() - 1); i++) {
+    for (intptr_t i = 0; i < typeargs_array.Length(); i++) {
       typearg ^= typeargs_array.At(i);
       typeargs.Add(typearg);
     }
@@ -2717,7 +2774,7 @@
   for (intptr_t i = 0; i < typeargs.Length(); i++) {
     typearg ^= typeargs.At(i);
     bool present = typeargs_table.Insert(typearg);
-    ASSERT(!present);
+    ASSERT(!present || typearg.IsRecursive());
   }
   object_store->set_canonical_type_arguments(typeargs_table.Release());
 }
@@ -3120,22 +3177,6 @@
     function.set_usage_counter(INT_MIN);
   }
 
-  const Array& intervals = graph_compiler->inlined_code_intervals();
-  INC_STAT(thread(), total_code_size, intervals.Length() * sizeof(uword));
-  code.SetInlinedIntervals(intervals);
-
-  const Array& inlined_id_array =
-      Array::Handle(zone, graph_compiler->InliningIdToFunction());
-  INC_STAT(thread(), total_code_size,
-           inlined_id_array.Length() * sizeof(uword));
-  code.SetInlinedIdToFunction(inlined_id_array);
-
-  const Array& caller_inlining_id_map_array =
-      Array::Handle(zone, graph_compiler->CallerInliningIdMap());
-  INC_STAT(thread(), total_code_size,
-           caller_inlining_id_map_array.Length() * sizeof(uword));
-  code.SetInlinedCallerIdMap(caller_inlining_id_map_array);
-
   graph_compiler->FinalizePcDescriptors(code);
   code.set_deopt_info_array(deopt_info_array);
 
@@ -3143,6 +3184,7 @@
   graph_compiler->FinalizeVarDescriptors(code);
   graph_compiler->FinalizeExceptionHandlers(code);
   graph_compiler->FinalizeStaticCallTargetsTable(code);
+  graph_compiler->FinalizeCodeSourceMap(code);
 
   if (optimized()) {
     // Installs code while at safepoint.
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 6f504f1..e47674c 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -87,6 +87,27 @@
 typedef DirectChainedHashMap<StackMapKeyValueTrait> StackMapSet;
 
 
+class CodeSourceMapKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const CodeSourceMap* Key;
+  typedef const CodeSourceMap* Value;
+  typedef const CodeSourceMap* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) { return key->Length(); }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->Equals(*key);
+  }
+};
+
+typedef DirectChainedHashMap<CodeSourceMapKeyValueTrait> CodeSourceMapSet;
+
+
 class ArrayKeyValueTrait {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
@@ -461,6 +482,7 @@
   void SwitchICCalls();
   void ShareMegamorphicBuckets();
   void DedupStackMaps();
+  void DedupCodeSourceMaps();
   void DedupLists();
   void DedupInstructions();
   void ResetPrecompilerState();
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 9db93ae..e637be3 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -330,6 +330,20 @@
 
 
 static void DumpStackFrame(intptr_t frame_index, uword pc) {
+  Isolate* isolate = Isolate::Current();
+  if ((isolate != NULL) && isolate->is_runnable()) {
+    Code& code = Code::Handle(Code::LookupCodeInVmIsolate(pc));
+    if (!code.IsNull()) {
+      OS::PrintErr("  [0x%" Pp "] %s\n", pc, code.QualifiedName());
+      return;
+    }
+    code = Code::LookupCode(pc);
+    if (!code.IsNull()) {
+      OS::PrintErr("  [0x%" Pp "] %s\n", pc, code.QualifiedName());
+      return;
+    }
+  }
+
   uintptr_t start = 0;
   char* native_symbol_name = NativeSymbolResolver::LookupSymbolName(pc, &start);
   if (native_symbol_name == NULL) {
@@ -341,16 +355,6 @@
 }
 
 
-static void DumpStackFrame(intptr_t frame_index, uword pc, const Code& code) {
-  if (code.IsNull()) {
-    DumpStackFrame(frame_index, pc);
-  } else {
-    OS::PrintErr("Frame[%" Pd "] = Dart:`%s` [0x%" Px "]\n", frame_index,
-                 code.ToCString(), pc);
-  }
-}
-
-
 class ProfilerStackWalker : public ValueObject {
  public:
   ProfilerStackWalker(Isolate* isolate,
@@ -370,16 +374,6 @@
     }
   }
 
-  bool Append(uword pc, const Code& code) {
-    if (sample_ == NULL) {
-      DumpStackFrame(frame_index_, pc, code);
-      frame_index_++;
-      total_frames_++;
-      return true;
-    }
-    return Append(pc);
-  }
-
   bool Append(uword pc) {
     if (sample_ == NULL) {
       DumpStackFrame(frame_index_, pc);
@@ -803,51 +797,52 @@
 
 
 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within
-// it. Return |false| if anything looks suspicious.
-static bool GetAndValidateIsolateStackBounds(Thread* thread,
-                                             uintptr_t fp,
-                                             uintptr_t sp,
-                                             uword* stack_lower,
-                                             uword* stack_upper) {
+// it. If |get_os_thread_bounds| is true then if |isolate| stackbounds are
+// not available we fallback to using underlying OS thread bounds. This only
+// works for the current thread.
+// Return |false| if anything looks suspicious.
+static bool GetAndValidateThreadStackBounds(Thread* thread,
+                                            uintptr_t fp,
+                                            uintptr_t sp,
+                                            uword* stack_lower,
+                                            uword* stack_upper,
+                                            bool get_os_thread_bounds = false) {
   ASSERT(thread != NULL);
   OSThread* os_thread = thread->os_thread();
   ASSERT(os_thread != NULL);
   ASSERT(stack_lower != NULL);
   ASSERT(stack_upper != NULL);
+  ASSERT(!get_os_thread_bounds || (Thread::Current() == thread));
+
 #if defined(USING_SIMULATOR)
-  const bool in_dart_code = thread->IsExecutingDartCode();
-  if (in_dart_code) {
+  const bool use_simulator_stack_bounds = thread->IsExecutingDartCode();
+  if (use_simulator_stack_bounds) {
     Isolate* isolate = thread->isolate();
     ASSERT(isolate != NULL);
     Simulator* simulator = isolate->simulator();
     *stack_lower = simulator->StackBase();
     *stack_upper = simulator->StackTop();
-  } else if (!os_thread->GetProfilerStackBounds(stack_lower, stack_upper)) {
+  }
+#else
+  const bool use_simulator_stack_bounds = false;
+#endif
+
+  if (!use_simulator_stack_bounds &&
+      !os_thread->GetProfilerStackBounds(stack_lower, stack_upper) &&
+      !(get_os_thread_bounds &&
+        OSThread::GetCurrentStackBounds(stack_lower, stack_upper))) {
     // Could not get stack boundary.
     return false;
   }
+
   if ((*stack_lower == 0) || (*stack_upper == 0)) {
     return false;
   }
-#else
-  if (!os_thread->GetProfilerStackBounds(stack_lower, stack_upper) ||
-      (*stack_lower == 0) || (*stack_upper == 0)) {
-    // Could not get stack boundary.
-    return false;
-  }
-#endif
 
-#if defined(TARGET_ARCH_DBC)
-  if (!in_dart_code && (sp > *stack_lower)) {
+  if (!use_simulator_stack_bounds && (sp > *stack_lower)) {
     // The stack pointer gives us a tighter lower bound.
     *stack_lower = sp;
   }
-#else
-  if (sp > *stack_lower) {
-    // The stack pointer gives us a tighter lower bound.
-    *stack_lower = sp;
-  }
-#endif
 
   if (*stack_lower >= *stack_upper) {
     // Stack boundary is invalid.
@@ -988,10 +983,11 @@
     return;
   }
 
-  if (!GetAndValidateIsolateStackBounds(thread, fp, sp, &stack_lower,
-                                        &stack_upper)) {
+  if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower,
+                                       &stack_upper,
+                                       /*get_os_thread_bounds=*/true)) {
     OS::PrintErr(
-        "Stack dump aborted because GetAndValidateIsolateStackBounds.\n");
+        "Stack dump aborted because GetAndValidateThreadStackBounds.\n");
     return;
   }
 
@@ -1032,8 +1028,8 @@
     return;
   }
 
-  if (!GetAndValidateIsolateStackBounds(thread, fp, sp, &stack_lower,
-                                        &stack_upper)) {
+  if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower,
+                                       &stack_upper)) {
     // Could not get stack boundary.
     return;
   }
@@ -1158,8 +1154,8 @@
 
   uword stack_lower = 0;
   uword stack_upper = 0;
-  if (!GetAndValidateIsolateStackBounds(thread, fp, sp, &stack_lower,
-                                        &stack_upper)) {
+  if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower,
+                                       &stack_upper)) {
     AtomicOperations::IncrementInt64By(
         &counters_.single_frame_sample_get_and_validate_stack_bounds, 1);
     // Could not get stack boundary.
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 6731e2d..5290e06 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1049,7 +1049,7 @@
            ProcessedSample* sample,
            intptr_t frame_index,
            // Outputs:
-           GrowableArray<Function*>** inlined_functions,
+           GrowableArray<const Function*>** inlined_functions,
            GrowableArray<TokenPosition>** inlined_token_positions,
            TokenPosition* token_position) {
     const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
@@ -1065,7 +1065,7 @@
  private:
   bool FindInCache(uword pc,
                    intptr_t offset,
-                   GrowableArray<Function*>** inlined_functions,
+                   GrowableArray<const Function*>** inlined_functions,
                    GrowableArray<TokenPosition>** inlined_token_positions,
                    TokenPosition* token_position) {
     // Simple linear scan.
@@ -1096,31 +1096,28 @@
            ProcessedSample* sample,
            intptr_t frame_index,
            // Outputs:
-           GrowableArray<Function*>** inlined_functions,
+           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->pc = pc;
     cache_entry->offset = offset;
-    code.GetInlinedFunctionsAt(offset, &(cache_entry->inlined_functions),
-                               &(cache_entry->inlined_token_positions));
-    cache_entry->token_position = code.GetTokenPositionAt(offset);
-    *token_position = (cache_entry->token_position);
+    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;
     }
-    // The inlined token position table does not include the token position
-    // of the final call. Insert it at the beginning because the table.
-    // is reversed.
-    cache_entry->inlined_token_positions.InsertAt(0,
-                                                  cache_entry->token_position);
 
     // 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() {
@@ -1157,7 +1154,7 @@
     }
     uword pc;
     intptr_t offset;
-    GrowableArray<Function*> inlined_functions;
+    GrowableArray<const Function*> inlined_functions;
     GrowableArray<TokenPosition> inlined_token_positions;
     TokenPosition token_position;
   };
@@ -1592,7 +1589,7 @@
     const intptr_t code_index = profile_code->code_table_index();
     ASSERT(profile_code != NULL);
     const Code& code = Code::ZoneHandle(profile_code->code());
-    GrowableArray<Function*>* inlined_functions = NULL;
+    GrowableArray<const Function*>* inlined_functions = NULL;
     GrowableArray<TokenPosition>* inlined_token_positions = NULL;
     TokenPosition token_position = TokenPosition::kNoSource;
     if (!code.IsNull()) {
@@ -1609,8 +1606,9 @@
         }
       }
     }
+
     if (code.IsNull() || (inlined_functions == NULL) ||
-        (inlined_functions->length() == 0)) {
+        (inlined_functions->length() <= 1)) {
       // No inlined functions.
       if (inclusive_tree_) {
         current = AppendKind(code, current);
@@ -1626,12 +1624,12 @@
     ASSERT(code.is_optimized());
 
     if (inclusive_tree_) {
-      for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
-        Function* inlined_function = (*inlined_functions)[i];
+      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 == (inlined_functions->length() - 1);
+        const bool inliner = i == 0;
         if (inliner) {
           current = AppendKind(code, current);
         }
@@ -1646,12 +1644,12 @@
     } else {
       // Append the inlined children.
       current = AppendKind(kInlineFinish, current);
-      for (intptr_t i = 0; i < inlined_functions->length(); i++) {
-        Function* inlined_function = (*inlined_functions)[i];
+      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 == (inlined_functions->length() - 1);
+        const bool inliner = i == 0;
         if (inliner) {
           current = AppendKind(kInlineStart, current);
         }
@@ -1672,7 +1670,7 @@
       intptr_t sample_index,
       ProcessedSample* sample,
       intptr_t frame_index,
-      Function* inlined_function,
+      const Function* inlined_function,
       TokenPosition inlined_token_position,
       intptr_t code_index) {
     ProfileFunctionTable* function_table = profile_->functions_;
@@ -2419,6 +2417,8 @@
       ProcessedSample* sample = samples_->At(sample_index);
       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());
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 8e3af78..bcb3261 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -2449,13 +2449,14 @@
 
 
 static uword FindPCForTokenPosition(const Code& code,
-                                    const CodeSourceMap& code_source_map,
                                     TokenPosition tp) {
-  CodeSourceMap::Iterator it(code_source_map);
-
-  while (it.MoveNext()) {
-    if (it.TokenPos() == tp) {
-      return it.PcOffset() + code.PayloadStart();
+  GrowableArray<const Function*> functions;
+  GrowableArray<TokenPosition> token_positions;
+  for (intptr_t pc_offset = 0; pc_offset < code.Size(); pc_offset++) {
+    code.GetInlinedFunctionsAtInstruction(pc_offset, &functions,
+                                          &token_positions);
+    if (token_positions[0] == tp) {
+      return code.PayloadStart() + pc_offset;
     }
   }
 
@@ -2522,34 +2523,24 @@
   const Code& do_work_code = Code::Handle(do_work.CurrentCode());
   EXPECT(!do_work_code.IsNull());
 
-  const CodeSourceMap& main_code_source_map =
-      CodeSourceMap::Handle(main_code.code_source_map());
-  EXPECT(!main_code_source_map.IsNull());
-
-  const CodeSourceMap& do_work_code_source_map =
-      CodeSourceMap::Handle(do_work_code.code_source_map());
-  EXPECT(!do_work_code_source_map.IsNull());
-
   // Dump code source map.
-  CodeSourceMap::Dump(do_work_code_source_map, do_work_code, main);
-  CodeSourceMap::Dump(main_code_source_map, main_code, main);
+  do_work_code.DumpSourcePositions();
+  main_code.DumpSourcePositions();
 
   // Look up some source token position's pc.
-  uword squarePositionPc = FindPCForTokenPosition(
-      do_work_code, do_work_code_source_map, squarePosition);
+  uword squarePositionPc = FindPCForTokenPosition(do_work_code, squarePosition);
   EXPECT(squarePositionPc != 0);
 
-  uword callPositionPc =
-      FindPCForTokenPosition(main_code, main_code_source_map, callPosition);
+  uword callPositionPc = FindPCForTokenPosition(main_code, callPosition);
   EXPECT(callPositionPc != 0);
 
   // Look up some classifying token position's pc.
-  uword controlFlowPc = FindPCForTokenPosition(
-      do_work_code, do_work_code_source_map, TokenPosition::kControlFlow);
+  uword controlFlowPc =
+      FindPCForTokenPosition(do_work_code, TokenPosition::kControlFlow);
   EXPECT(controlFlowPc != 0);
 
-  uword tempMovePc = FindPCForTokenPosition(main_code, main_code_source_map,
-                                            TokenPosition::kTempMove);
+  uword tempMovePc =
+      FindPCForTokenPosition(main_code, TokenPosition::kTempMove);
   EXPECT(tempMovePc != 0);
 
   // Insert fake samples.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b694518..e0f6f10 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -435,7 +435,19 @@
     uword tags = ptr()->tags_;
     intptr_t result = SizeTag::decode(tags);
     if (result != 0) {
-      ASSERT(result == SizeFromClass());
+#if defined(DEBUG)
+      // TODO(22501) Array::MakeArray has a race with this code: we might have
+      // loaded tags field and then MakeArray could have updated it leading
+      // to inconsistency between SizeFromClass() and SizeTag::decode(tags).
+      // We are working around it by reloading tags_ and recomputing
+      // size from tags.
+      const intptr_t size_from_class = SizeFromClass();
+      if ((result > size_from_class) && (GetClassId() == kArrayCid) &&
+          (ptr()->tags_ != tags)) {
+        result = SizeTag::decode(ptr()->tags_);
+      }
+      ASSERT(result == size_from_class);
+#endif
       return result;
     }
     result = SizeFromClass();
@@ -1010,6 +1022,8 @@
   RawString* resolved_url_;
   RawArray* compile_time_constants_;
   RawArray* line_starts_;
+  RawArray* debug_positions_;
+  RawArray* yield_positions_;
   RawTokenStream* tokens_;
   RawString* source_;
   RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->source_); }
@@ -1125,16 +1139,16 @@
   RawExceptionHandlers* exception_handlers_;
   RawPcDescriptors* pc_descriptors_;
   RawArray* stackmaps_;
+  RawArray* inlined_id_to_function_;
+  RawCodeSourceMap* code_source_map_;
   NOT_IN_PRECOMPILED(RawInstructions* active_instructions_);
   NOT_IN_PRECOMPILED(RawArray* deopt_info_array_);
   // (code-offset, function, code) triples.
   NOT_IN_PRECOMPILED(RawArray* static_calls_target_table_);
-  NOT_IN_PRECOMPILED(RawArray* inlined_metadata_);
   // If return_address_metadata_ is a Smi, it is the offset to the prologue.
   // Else, return_address_metadata_ is null.
   NOT_IN_PRECOMPILED(RawObject* return_address_metadata_);
   NOT_IN_PRECOMPILED(RawLocalVarDescriptors* var_descriptors_);
-  NOT_IN_PRECOMPILED(RawCodeSourceMap* code_source_map_);
   NOT_IN_PRECOMPILED(RawArray* comments_);
   RawObject** to() {
 #if defined(DART_PRECOMPILED_RUNTIME)
@@ -1276,13 +1290,13 @@
 };
 
 
-// CodeSourceMap stores a mapping between code PC ranges and source token
-// positions.
+// CodeSourceMap encodes a mapping from code PC ranges to source token
+// positions and the stack of inlined functions.
 class RawCodeSourceMap : public RawObject {
  private:
   RAW_HEAP_OBJECT_IMPLEMENTATION(CodeSourceMap);
 
-  int32_t length_;  // Number of entries.
+  int32_t length_;  // Length in bytes.
 
   // Variable length data follows here.
   uint8_t* data() { OPEN_ARRAY_START(uint8_t, intptr_t); }
@@ -1389,16 +1403,6 @@
 
 
 class RawExceptionHandlers : public RawObject {
- public:
-  // The index into the ExceptionHandlers table corresponds to
-  // the try_index of the handler.
-  struct HandlerInfo {
-    uint32_t handler_pc_offset;  // PC offset value of handler.
-    int16_t outer_try_index;     // Try block index of enclosing try block.
-    int8_t needs_stacktrace;     // True if a stacktrace is needed.
-    int8_t has_catch_all;        // Catches all exceptions.
-  };
-
  private:
   RAW_HEAP_OBJECT_IMPLEMENTATION(ExceptionHandlers);
 
@@ -1410,8 +1414,12 @@
   RawArray* handled_types_data_;
 
   // Exception handler info of length [num_entries_].
-  const HandlerInfo* data() const { OPEN_ARRAY_START(HandlerInfo, intptr_t); }
-  HandlerInfo* data() { OPEN_ARRAY_START(HandlerInfo, intptr_t); }
+  const ExceptionHandlerInfo* data() const {
+    OPEN_ARRAY_START(ExceptionHandlerInfo, intptr_t);
+  }
+  ExceptionHandlerInfo* data() {
+    OPEN_ARRAY_START(ExceptionHandlerInfo, intptr_t);
+  }
 
   friend class Object;
 };
@@ -2127,8 +2135,9 @@
   RAW_HEAP_OBJECT_IMPLEMENTATION(StackTrace);
 
   RawObject** from() {
-    return reinterpret_cast<RawObject**>(&ptr()->code_array_);
+    return reinterpret_cast<RawObject**>(&ptr()->async_link_);
   }
+  RawStackTrace* async_link_;  // Link to parent async stack trace.
   RawArray* code_array_;       // Code object for each frame in the stack trace.
   RawArray* pc_offset_array_;  // Offset of PC for each frame.
   RawObject** to() {
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
index edc0e41..7f7cfbc 100644
--- a/runtime/vm/runtime_entry_list.h
+++ b/runtime/vm/runtime_entry_list.h
@@ -18,7 +18,6 @@
   V(FixAllocationStubTarget)                                                   \
   V(InlineCacheMissHandlerOneArg)                                              \
   V(InlineCacheMissHandlerTwoArgs)                                             \
-  V(InlineCacheMissHandlerThreeArgs)                                           \
   V(StaticCallMissHandlerOneArg)                                               \
   V(StaticCallMissHandlerTwoArgs)                                              \
   V(Instanceof)                                                                \
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index ee64a06..9bffb21 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -254,8 +254,12 @@
 
   intptr_t NewSizeInWords(intptr_t old_size_in_words) const;
 
-  // Current allocation top and end. These values are being accessed directly
-  // from generated code.
+  // Accessed from generated code.
+  // ** This block of fields must come first! **
+  // For AOT cross-compilation, we rely on these members having the same offsets
+  // in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64.
+  // We use only word-sized fields to avoid differences in struct packing on the
+  // different architectures. See also CheckOffsets in dart.cc.
   uword top_;
   uword end_;
 
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index bdc71e9..c456fee 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -16,6 +16,7 @@
 #include "vm/debugger.h"
 #include "vm/isolate.h"
 #include "vm/lockers.h"
+#include "vm/malloc_hooks.h"
 #include "vm/message.h"
 #include "vm/message_handler.h"
 #include "vm/native_entry.h"
@@ -840,13 +841,18 @@
     ASSERT(!param_values.IsNull());
     ASSERT(param_keys.Length() == param_values.Length());
 
-    if (!reply_port.IsSendPort()) {
+    // We expect a reply port unless there is a null sequence id,
+    // which indicates that no reply should be sent.  We use this in
+    // tests.
+    if (!seq.IsNull() && !reply_port.IsSendPort()) {
       FATAL("SendPort expected.");
     }
 
     JSONStream js;
-    js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(), seq, method_name,
-             param_keys, param_values, parameters_are_dart_objects);
+    Dart_Port reply_port_id =
+        (reply_port.IsNull() ? ILLEGAL_PORT : SendPort::Cast(reply_port).Id());
+    js.Setup(zone.GetZone(), reply_port_id, seq, method_name, param_keys,
+             param_values, parameters_are_dart_objects);
 
     // RPC came in with a custom service id zone.
     const char* id_zone_param = js.LookupParam("_idZone");
@@ -1334,6 +1340,8 @@
   }
   ASSERT(isolate->compilation_allowed());
   DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
+  DebuggerStackTrace* async_causal_stack =
+      isolate->debugger()->AsyncCausalStackTrace();
   // Do we want the complete script object and complete local variable objects?
   // This is true for dump requests.
   const bool full = BoolParameter::Parse(js->LookupParam("_full"), false);
@@ -1351,6 +1359,17 @@
     }
   }
 
+  if (async_causal_stack != NULL) {
+    JSONArray jsarr(&jsobj, "asyncCausalFrames");
+    intptr_t num_frames = async_causal_stack->Length();
+    for (intptr_t i = 0; i < num_frames; i++) {
+      ActivationFrame* frame = async_causal_stack->FrameAt(i);
+      JSONObject jsobj(&jsarr);
+      frame->PrintToJSONObject(&jsobj, full);
+      jsobj.AddProperty("index", i);
+    }
+  }
+
   {
     MessageHandler::AcquiredQueues aq(isolate->message_handler());
     jsobj.AddProperty("messages", aq.queue());
@@ -3790,10 +3809,13 @@
   jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
   jsobj.AddProperty("version", Version::String());
   jsobj.AddProperty("_profilerMode", FLAG_profile_vm ? "VM" : "Dart");
+  jsobj.AddProperty("_nativeZoneMemoryUsage",
+                    ApiNativeScope::current_memory_usage());
   jsobj.AddProperty64("pid", OS::ProcessId());
   jsobj.AddProperty64("_maxRSS", OS::MaxRSS());
   jsobj.AddPropertyTimeMillis(
       "startTime", OS::GetCurrentTimeMillis() - Dart::UptimeMillis());
+  MallocHooks::PrintToJSONObject(&jsobj);
   // Construct the isolate list.
   {
     JSONArray jsarr(&jsobj, "isolates");
diff --git a/runtime/vm/service/service_dev.md b/runtime/vm/service/service_dev.md
new file mode 100644
index 0000000..6065b6d
--- /dev/null
+++ b/runtime/vm/service/service_dev.md
@@ -0,0 +1,2618 @@
+Note: this dev version of the protocol contains not yet released functionality,
+and is subject to change.
+
+# Dart VM Service Protocol 3.6-dev
+
+> Please post feedback to the [observatory-discuss group][discuss-list]
+
+This document describes of _version 3.5_ 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.
+The VM will start a webserver which services protocol requests via WebSocket.
+It is possible to make HTTP (non-WebSocket) requests,
+but this does not allow access to VM _events_ and is not documented
+here.
+
+The Service Protocol uses [JSON-RPC 2.0][].
+
+[JSON-RPC 2.0]: http://www.jsonrpc.org/specification
+
+**Table of Contents**
+
+- [RPCs, Requests, and Responses](#rpcs-requests-and-responses)
+- [Events](#events)
+- [Types](#types)
+- [IDs and Names](#ids-and-names)
+- [Versioning](#versioning)
+- [Private RPCs, Types, and Properties](#private-rpcs-types-and-properties)
+- [Public RPCs](#public-rpcs)
+	- [addBreakpoint](#addbreakpoint)
+	- [addBreakpointWithScriptUri](#addbreakpointwithscripturi)
+	- [addBreakpointAtEntry](#addbreakpointatentry)
+	- [evaluate](#evaluate)
+	- [evaluateInFrame](#evaluateinframe)
+	- [getFlagList](#getflaglist)
+	- [getIsolate](#getisolate)
+	- [getObject](#getobject)
+	- [getSourceReport](#getsourcereport)
+	- [getStack](#getstack)
+	- [getVersion](#getversion)
+	- [getVM](#getvm)
+	- [pause](#pause)
+	- [reloadSources](#reloadsources)
+	- [removeBreakpoint](#removebreakpoint)
+	- [resume](#resume)
+	- [setExceptionPauseMode](#setexceptionpausemode)
+	- [setLibraryDebuggable](#setlibrarydebuggable)
+	- [setName](#setname)
+	- [setVMName](#setvmname)
+	- [streamCancel](#streamcancel)
+	- [streamListen](#streamlisten)
+- [Public Types](#public-types)
+	- [BoundField](#boundfield)
+	- [BoundVariable](#boundvariable)
+	- [Breakpoint](#breakpoint)
+	- [Class](#class)
+	- [ClassList](#classlist)
+	- [Code](#code)
+	- [CodeKind](#codekind)
+	- [Context](#context)
+	- [ContextElement](#contextelement)
+	- [Error](#error)
+	- [ErrorKind](#errorkind)
+	- [Event](#event)
+	- [EventKind](#eventkind)
+	- [ExtensionData](#extensiondata)
+	- [Field](#field)
+	- [Flag](#flag)
+	- [FlagList](#flaglist)
+	- [Frame](#frame)
+	- [Function](#function)
+	- [Instance](#instance)
+	- [Isolate](#isolate)
+	- [Library](#library)
+	- [LibraryDependency](#librarydependency)
+	- [MapAssociation](#mapassociation)
+	- [Message](#message)
+	- [Null](#null)
+	- [Object](#object)
+	- [ReloadReport](#reloadreport)
+	- [Response](#response)
+	- [Sentinel](#sentinel)
+	- [SentinelKind](#sentinelkind)
+	- [Script](#script)
+	- [SourceLocation](#sourcelocation)
+	- [SourceReport](#sourcereport)
+	- [SourceReportCoverage](#sourcereportcoverage)
+	- [SourceReportKind](#sourcereportkind)
+	- [SourceReportRange](#sourcereportrange)
+	- [Stack](#stack)
+	- [StepOption](#stepoption)
+	- [Success](#success)
+	- [TypeArguments](#typearguments)
+	- [UresolvedSourceLocation](#unresolvedsourcelocation)
+	- [Version](#version)
+	- [VM](#vm)
+- [Revision History](#revision-history)
+
+## RPCs, Requests, and Responses
+
+An RPC request is a JSON object sent to the server. Here is an
+example [getVersion](#getversion) request:
+
+```
+{
+  "jsonrpc": "2.0",
+  "method": "getVersion",
+  "params": {},
+  "id": "1"
+}
+```
+
+The _id_ property must be a string, number, or `null`. The Service Protocol
+optionally accepts requests without the _jsonprc_ property.
+
+An RPC response is a JSON object (http://json.org/). The response always specifies an
+_id_ property to pair it with the corresponding request. If the RPC
+was successful, the _result_ property provides the result.
+
+Here is an example response for our [getVersion](#getversion) request above:
+
+```
+{
+  "jsonrpc": "2.0",
+  "result": {
+    "type": "Version",
+    "major": 3,
+    "minor": 5
+  }
+  "id": "1"
+}
+```
+
+Parameters for RPC requests are always provided as _named_ parameters.
+The JSON-RPC spec provides for _positional_ parameters as well, but they
+are not supported by the Dart VM.
+
+By convention, every response returned by the Service Protocol is a subtype
+of [Response](#response) and provides a _type_ parameter which can be used
+to distinguish the exact return type. In the example above, the
+[Version](#version) type is returned.
+
+Here is an example [streamListen](#streamlisten) request which provides
+a parameter:
+
+```
+{
+  "jsonrpc": "2.0",
+  "method": "streamListen",
+  "params": {
+    "streamId": "GC",
+  },
+  "id": "2"
+}
+```
+
+<a name="rpc-error"></a>
+When an RPC encounters an error, it is provided in the _error_
+property of the response object. JSON-RPC errors always provide
+_code_, _message_, and _data_ properties.
+
+Here is an example error response for our [streamListen](#streamlisten)
+request above. This error would be generated if we were attempting to
+subscribe to the _GC_ stream multiple times from the same client.
+
+```
+{
+  "jsonrpc": "2.0",
+  "error": {
+    "code": 103,
+    "message": "Stream already subscribed",
+    "data": {
+      "details": "The stream 'GC' is already subscribed"
+    }
+  }
+  "id": "2"
+}
+```
+
+In addition to the [error codes](http://www.jsonrpc.org/specification#error_object) specified in the JSON-RPC spec, we use the following application specific error codes:
+
+code | message | meaning
+---- | ------- | -------
+100 | Feature is disabled | The operation is unable to complete because a feature is disabled
+101 | VM must be paused | This operation is only valid when the VM is paused
+102 | Cannot add breakpoint | The VM is unable to add a breakpoint at the specified line or function
+103 | Stream already subscribed | The client is already subscribed to the specified _streamId_
+104 | Stream not subscribed | The client is not subscribed to the specified _streamId_
+105 | Isolate must be runnable | This operation cannot happen until the isolate is runnable
+106 | Isolate must be paused | This operation is only valid when the isolate is paused
+107 | Cannot resume execution | The isolate could not be resumed
+108 | Isolate is reloading | The isolate is currently processing another reload request
+109 | Isolate cannot be reloaded | The isolate has an unhandled exception and can no longer be reloaded
+
+
+
+## Events
+
+By using the [streamListen](#streamlisten) and [streamCancel](#streamcancel) RPCs, a client may
+request to be notified when an _event_ is posted to a specific
+_stream_ in the VM. Every stream has an associated _stream id_ which
+is used to name that stream.
+
+Each stream provides access to certain kinds of events. For example the _Isolate_ stream provides
+access to events pertaining to isolate births, deaths, and name changes. See [streamListen](#streamlisten)
+for a list of the well-known stream ids and their associated events.
+
+Stream events arrive asynchronously over the WebSocket. They're structured as
+JSON-RPC 2.0 requests with no _id_ property. The _method_ property will be
+_streamNotify_, and the _params_ will have _streamId_ and _event_ properties:
+
+```json
+{
+  "json-rpc": "2.0",
+  "method": "streamNotify",
+  "params": {
+    "streamId": "Isolate",
+    "event": {
+      "type": "Event",
+      "kind": "IsolateExit",
+      "isolate": {
+        "type": "@Isolate",
+        "id": "isolates/33",
+        "number": "51048743613",
+        "name": "worker-isolate"
+      }
+    }
+  }
+}
+```
+
+It is considered a _backwards compatible_ change to add a new type of event to an existing stream.
+Clients should be written to handle this gracefully.
+
+
+
+## Types
+
+By convention, every result and event provided by the Service Protocol
+is a subtype of [Response](#response) and has the _type_ property.
+This allows the client to distinguish different kinds of responses. For example,
+information about a Dart function is returned using the [Function](#function) type.
+
+If the type of a response begins with the _@_ character, then that
+response is a _reference_. If the type name of a response does not
+begin with the _@_ character, it is the an _object_. A reference is
+intended to be a subset of an object which provides enough information
+to generate a reasonable looking reference to the object.
+
+For example, an [@Isolate](#isolate) reference has the _type_, _id_, _name_ and
+_number_ properties:
+
+```
+  "result": {
+    "type": "@Isolate",
+    "id": "isolates/33",
+    "number": "51048743613"
+    "name": "worker-isolate"
+  }
+```
+
+But an [Isolate](#isolate) object has more information:
+
+```
+  "result": {
+    "type": "Isolate",
+    "id": "isolates/33",
+    "number": "51048743613"
+    "name": "worker-isolate"
+    "rootLib": { ... }
+    "entry": ...
+    "heaps": ...
+     ...
+  }
+```
+
+## IDs and Names
+
+Many responses returned by the Service Protocol have an _id_ property.
+This is an identifier used to request an object from an isolate using
+the [getObject](#getobject) RPC. If two responses have the same _id_ then they
+refer to the same object. The converse is not true: the same object
+may sometimes be returned with two different values for _id_.
+
+The _id_ property should be treated as an opaque string by the client:
+it is not meant to be parsed.
+
+An id can be either _temporary_ or _fixed_:
+
+* A _temporary_ id can expire over time. The VM allocates certain ids
+  in a ring which evicts old ids over time.
+
+* A _fixed_ id will never expire, but the object it refers to may
+  be collected. The VM uses fixed ids for objects like scripts,
+  libraries, and classes.
+
+If an id is fixed, the _fixedId_ property will be true. If an id is temporary
+the _fixedId_ property will be omitted.
+
+Sometimes a temporary id may expire. In this case, some RPCs may return
+an _Expired_ [Sentinel](#sentinel) to indicate this.
+
+The object referred to by an id may be collected by the VM's garbage
+collector. In this case, some RPCs may return a _Collected_ [Sentinel](#sentinel)
+to indicate this.
+
+Many objects also have a _name_ property. This is provided so that
+objects can be displayed in a way that a Dart language programmer
+would find familiar. Names are not unique.
+
+## Versioning
+
+The [getVersion](#getversion) RPC can be used to find the version of the protocol
+returned by a VM. The _Version_ response has a major and a minor
+version number:
+
+```
+  "result": {
+    "type": "Version",
+    "major": 3,
+    "minor": 5
+  }
+```
+
+The major version number is incremented when the protocol is changed
+in a potentially _incompatible_ way. An example of an incompatible
+change is removing a non-optional property from a result.
+
+The minor version number is incremented when the protocol is changed
+in a _backwards compatible_ way. An example of a backwards compatible
+change is adding a property to a result.
+
+Certain changes that would normally not be backwards compatible are
+considered backwards compatible for the purposes of versioning.
+Specifically, additions can be made to the [EventKind](#eventkind) and
+[InstanceKind](#instancekind) enumerated types and the client must
+handle this gracefully. See the notes on these enumerated types for more
+information.
+
+## Private RPCs, Types, and Properties
+
+Any RPC, type, or property which begins with an underscore is said to
+be _private_. These RPCs, types, and fields can be changed at any
+time without changing major or minor version numbers.
+
+The intention is that the Service Protocol will evolve by adding
+private RPCs which may, over time, migrate to the public api as they
+become stable. Some private types and properties expose VM specific
+implementation state and will never be appropriate to add to
+the public api.
+
+## Public RPCs
+
+The following is a list of all public RPCs supported by the Service Protocol.
+
+An RPC is described using the following format:
+
+```
+ReturnType methodName(parameterType1 parameterName1,
+                      parameterType2, parameterName2,
+                      ...)
+```
+
+If an RPC says it returns type _T_ it may actually return _T_ or any
+[subtype](#public-types) of _T_. For example, an
+RPC which is declared to return [@Object](#object) may actually
+return [@Instance](#instance).
+
+If an RPC can return one or more independent types, this is indicated
+with the vertical bar:
+
+```
+ReturnType1|ReturnType2
+```
+
+Any RPC may return an _error_ response as [described above](#rpc-error).
+
+Some parameters are optional. This is indicated by the text
+_[optional]_ following the parameter name:
+
+```
+ReturnType methodName(parameterType parameterName [optional)
+```
+
+A description of the return types and parameter types is provided
+in the section on [public types](#public-types).
+
+### addBreakpoint
+
+```
+Breakpoint addBreakpoint(string isolateId,
+                         string scriptId,
+                         int line,
+                         int column [optional])
+```
+
+The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
+of some script.
+
+The _scriptId_ parameter is used to specify the target script.
+
+The _line_ parameter is used to specify the target line for the
+breakpoint. If there are multiple possible breakpoints on the target
+line, then the VM will place the breakpoint at the location which
+would execute soonest. If it is not possible to set a breakpoint at
+the target line, the breakpoint will be added at the next possible
+breakpoint location within the same function.
+
+The _column_ parameter may be optionally specified.  This is useful
+for targeting a specific breakpoint on a line with multiple possible
+breakpoints.
+
+If no breakpoint is possible at that line, the _102_ (Cannot add
+breakpoint) error code is returned.
+
+Note that breakpoints are added and removed on a per-isolate basis.
+
+See [Breakpoint](#breakpoint).
+
+### addBreakpointWithScriptUri
+
+```
+Breakpoint addBreakpointWithScriptUri(string isolateId,
+                                      string scriptUri,
+                                      int line,
+                                      int column [optional])
+```
+
+The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
+of some script.  This RPC is useful when a script has not yet been
+assigned an id, for example, if a script is in a deferred library
+which has not yet been loaded.
+
+The _scriptUri_ parameter is used to specify the target script.
+
+The _line_ parameter is used to specify the target line for the
+breakpoint. If there are multiple possible breakpoints on the target
+line, then the VM will place the breakpoint at the location which
+would execute soonest. If it is not possible to set a breakpoint at
+the target line, the breakpoint will be added at the next possible
+breakpoint location within the same function.
+
+The _column_ parameter may be optionally specified.  This is useful
+for targeting a specific breakpoint on a line with multiple possible
+breakpoints.
+
+If no breakpoint is possible at that line, the _102_ (Cannot add
+breakpoint) error code is returned.
+
+Note that breakpoints are added and removed on a per-isolate basis.
+
+See [Breakpoint](#breakpoint).
+
+### addBreakpointAtEntry
+
+```
+Breakpoint addBreakpointAtEntry(string isolateId,
+                                string functionId)
+```
+The _addBreakpointAtEntry_ RPC is used to add a breakpoint at the
+entrypoint of some function.
+
+If no breakpoint is possible at the function entry, the _102_ (Cannot add
+breakpoint) error code is returned.
+
+See [Breakpoint](#breakpoint).
+
+Note that breakpoints are added and removed on a per-isolate basis.
+
+### evaluate
+
+```
+@Instance|@Error|Sentinel evaluate(string isolateId,
+                                   string targetId,
+                                   string expression)
+```
+
+The _evaluate_ RPC is used to evaluate an expression in the context of
+some target.
+
+_targetId_ may refer to a [Library](#library), [Class](#class), or
+[Instance](#instance).
+
+If _targetId_ is a temporary id which has expired, then the _Expired_
+[Sentinel](#sentinel) is returned.
+
+If _targetId_ refers to an object which has been collected by the VM's
+garbage collector, then the _Collected_ [Sentinel](#sentinel) is
+returned.
+
+If an error occurs while evaluating the expression, an [@Error](#error)
+reference will be returned.
+
+If the expression is evaluated successfully, an [@Instance](#instance)
+reference will be returned.
+
+### evaluateInFrame
+
+```
+@Instance|@Error evaluateInFrame(string isolateId,
+                                 int frameIndex,
+                                 string expression)
+```
+
+The _evaluateInFrame_ RPC is used to evaluate an expression in the
+context of a particular stack frame. _frameIndex_ is the index of the
+desired [Frame](#frame), with an index of _0_ indicating the top (most
+recent) frame.
+
+If an error occurs while evaluating the expression, an [@Error](#error)
+reference will be returned.
+
+If the expression is evaluated successfully, an [@Instance](#instance)
+reference will be returned.
+
+### getFlagList
+
+```
+FlagList getFlagList()
+```
+
+The _getFlagList_ RPC returns a list of all command line flags in the
+VM along with their current values.
+
+See [FlagList](#flaglist).
+
+### getIsolate
+
+```
+Isolate|Sentinel getIsolate(string isolateId)
+```
+
+The _getIsolate_ RPC is used to lookup an _Isolate_ object by its _id_.
+
+If _isolateId_ refers to an isolate which has exited, then the
+_Collected_ [Sentinel](#sentinel) is returned.
+
+See [Isolate](#isolate).
+
+### getObject
+
+```
+Object|Sentinel getObject(string isolateId,
+                          string objectId,
+                          int offset [optional],
+                          int count [optional])
+```
+
+The _getObject_ RPC is used to lookup an _object_ from some isolate by
+its _id_.
+
+If _objectId_ is a temporary id which has expired, then the _Expired_
+[Sentinel](#sentinel) is returned.
+
+If _objectId_ refers to a heap object which has been collected by the VM's
+garbage collector, then the _Collected_ [Sentinel](#sentinel) is
+returned.
+
+If _objectId_ refers to a non-heap object which has been deleted, then
+the _Collected_ [Sentinel](#sentinel) is returned.
+
+If the object handle has not expired and the object has not been
+collected, then an [Object](#object) will be returned.
+
+The _offset_ and _count_ parameters are used to request subranges of
+Instance objects with the kinds: String, List, Map, Uint8ClampedList,
+Uint8List, Uint16List, Uint32List, Uint64List, Int8List, Int16List,
+Int32List, Int64List, Flooat32List, Float64List, Inst32x3List,
+Float32x4List, and Float64x2List.  These parameters are otherwise
+ignored.
+
+### getStack
+
+```
+Stack getStack(string isolateId)
+```
+
+The _getStack_ RPC is used to retrieve the current execution stack and
+message queue for an isolate. The isolate does not need to be paused.
+
+See [Stack](#stack).
+
+### getSourceReport
+
+```
+SourceReport getSourceReport(string isolateId,
+                             SourceReportKind[] reports,
+                             string scriptId [optional],
+                             int tokenPos [optional],
+                             int endTokenPos [optional],
+                             bool forceCompile [optional])
+```
+
+The _getSourceReport_ RPC is used to generate a set of reports tied to
+source locations in an isolate.
+
+The _reports_ parameter is used to specify which reports should be
+generated.  The _reports_ parameter is a list, which allows multiple
+reports to be generated simultaneously from a consistent isolate
+state.  The _reports_ parameter is allowed to be empty (this might be
+used to force compilation of a particular subrange of some script).
+
+The available report kinds are:
+
+report kind | meaning
+----------- | -------
+Coverage | Provide code coverage information
+PossibleBreakpoints | Provide a list of token positions which correspond to possible breakpoints.
+
+The _scriptId_ parameter is used to restrict the report to a
+particular script.  When analyzing a particular script, either or both
+of the _tokenPos_ and _endTokenPos_ parameters may be provided to
+restrict the analysis to a subrange of a script (for example, these
+can be used to restrict the report to the range of a particular class
+or function).
+
+If the _scriptId_ parameter is not provided then the reports are
+generated for all loaded scripts and the _tokenPos_ and _endTokenPos_
+parameters are disallowed.
+
+The _forceCompilation_ parameter can be used to force compilation of
+all functions in the range of the report.  Forcing compilation can
+cause a compilation error, which could terminate the running Dart
+program.  If this parameter is not provided, it is considered to have
+the value _false_.
+
+See [SourceReport](#sourcereport).
+
+### getVersion
+
+```
+Version getVersion()
+```
+
+The _getVersion_ RPC is used to determine what version of the Service Protocol is served by a VM.
+
+See [Version](#version).
+
+### getVM
+
+```
+VM getVM()
+```
+
+The _getVM_ RPC returns global information about a Dart virtual machine.
+
+See [VM](#vm).
+
+### pause
+
+```
+Success pause(string isolateId)
+```
+
+The _pause_ RPC is used to interrupt a running isolate. The RPC enqueues the interrupt request and potentially returns before the isolate is paused.
+
+When the isolate is paused an event will be sent on the _Debug_ stream.
+
+See [Success](#success).
+
+### reloadSources
+
+
+```
+ReloadReport reloadSources(string isolateId,
+                           bool force [optional],
+                           bool pause [optional],
+                           string rootLibUri [optional],
+                           string packagesUri [optional])
+```
+
+The _reloadSources_ RPC is used to perform a hot reload of an Isolate's sources.
+
+if the _force_ parameter is provided, it indicates that all of the Isolate's
+sources should be reloaded regardless of modification time.
+
+if the _pause_ parameter is provided, the isolate will pause immediately
+after the reload.
+
+if the _rootLibUri_ parameter is provided, it indicates the new uri to the
+Isolate's root library.
+
+if the _packagesUri_ parameter is provided, it indicates the new uri to the
+Isolate's package map (.packages) file.
+
+### removeBreakpoint
+
+```
+Success removeBreakpoint(string isolateId,
+                         string breakpointId)
+```
+
+The _removeBreakpoint_ RPC is used to remove a breakpoint by its _id_.
+
+Note that breakpoints are added and removed on a per-isolate basis.
+
+See [Success](#success).
+
+### resume
+
+```
+Success resume(string isolateId,
+               StepOption step [optional],
+               int frameIndex [optional])
+```
+
+The _resume_ RPC is used to resume execution of a paused isolate.
+
+If the _step_ parameter is not provided, the program will resume
+regular execution.
+
+If the _step_ parameter is provided, it indicates what form of
+single-stepping to use.
+
+step | meaning
+---- | -------
+Into | Single step, entering function calls
+Over | Single step, skipping over function calls
+Out | Single step until the current function exits
+Rewind | Immediately exit the top frame(s) without executing any code. Isolate will be paused at the call of the last exited function.
+
+The _frameIndex_ parameter is only used when the _step_ parameter is Rewind. It
+specifies the stack frame to rewind to. Stack frame 0 is the currently executing
+function, so _frameIndex_ must be at least 1.
+
+If the _frameIndex_ parameter is not provided, it defaults to 1.
+
+See [Success](#success), [StepOption](#StepOption).
+
+### setExceptionPauseMode
+
+```
+Success setExceptionPauseMode(string isolateId,
+                              ExceptionPauseMode mode)
+```
+
+The _setExceptionPauseMode_ RPC is used to control if an isolate pauses when
+an exception is thrown.
+
+mode | meaning
+---- | -------
+None | Do not pause isolate on thrown exceptions
+Unhandled | Pause isolate on unhandled exceptions
+All  | Pause isolate on all thrown exceptions
+
+
+### setLibraryDebuggable
+
+```
+Success setLibraryDebuggable(string isolateId,
+                             string libraryId,
+                             bool isDebuggable)
+```
+
+The _setLibraryDebuggable_ RPC is used to enable or disable whether
+breakpoints and stepping work for a given library.
+
+See [Success](#success).
+
+### setName
+
+```
+Success setName(string isolateId,
+                string name)
+```
+
+The _setName_ RPC is used to change the debugging name for an isolate.
+
+See [Success](#success).
+
+### setVMName
+
+```
+Success setVMName(string name)
+```
+
+The _setVMName_ RPC is used to change the debugging name for the vm.
+
+See [Success](#success).
+
+### streamCancel
+
+```
+Success streamCancel(string streamId)
+```
+
+The _streamCancel_ RPC cancels a stream subscription in the VM.
+
+If the client is not subscribed to the stream, the _104_ (Stream not
+subscribed) error code is returned.
+
+See [Success](#success).
+
+### streamListen
+
+```
+Success streamListen(string streamId)
+```
+
+The _streamListen_ RPC subscribes to a stream in the VM. Once
+subscribed, the client will begin receiving events from the stream.
+
+If the client is not subscribed to the stream, the _103_ (Stream already
+subscribed) error code is returned.
+
+The _streamId_ parameter may have the following published values:
+
+streamId | event types provided
+-------- | -----------
+VM | VMUpdate
+Isolate | IsolateStart, IsolateRunnable, IsolateExit, IsolateUpdate, IsolateReload, ServiceExtensionAdded
+Debug | PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, Inspect, None
+GC | GC
+Extension | Extension
+Timeline | TimelineEvents
+
+Additionally, some embedders provide the _Stdout_ and _Stderr_
+streams.  These streams allow the client to subscribe to writes to
+stdout and stderr.
+
+streamId | event types provided
+-------- | -----------
+Stdout | WriteEvent
+Stderr | WriteEvent
+
+It is considered a _backwards compatible_ change to add a new type of event to an existing stream.
+Clients should be written to handle this gracefully, perhaps by warning and ignoring.
+
+See [Success](#success).
+
+## Public Types
+
+The following is a list of all public types produced by the Service Protocol.
+
+We define a small set of primitive types, based on JSON equivalents.
+
+type | meaning
+---- | -------
+string | JSON string values
+bool | JSON _true_, _false_
+int | JSON numbers without fractions or exponents
+float | any JSON number
+
+Note that the Service Protocol does not use JSON _null_.
+
+We describe the format of our JSON objects with the following class format:
+
+```
+class T {
+  string name;
+  int count;
+  ...
+}
+```
+
+This describes a JSON object type _T_ with some set of expected properties.
+
+Types are organized into an inheritance hierarchy. If type _T_
+extends type _S_...
+
+```
+class S {
+  string a;
+}
+
+class T extends S {
+  string b;
+}
+```
+
+...then that means that all properties of _S_ are also present in type
+_T_. In the example above, type _T_ would have the expected
+properties _a_ and _b_.
+
+If a property has an _Array_ type, it is written with brackets:
+
+```
+  PropertyType[] arrayProperty;
+```
+
+If a property is optional, it is suffixed with the text _[optional]_:
+
+```
+  PropertyType optionalProperty [optional];
+```
+
+If a property can have multiple independent types, we denote this with
+a vertical bar:
+
+```
+  PropertyType1|PropertyType2 complexProperty;
+```
+
+We also allow parenthesis on type expressions.  This is useful when a property
+is an _Array_ of multiple independent types:
+
+```
+  (PropertyType1|PropertyType2)[]
+```
+
+When a string is only permitted to take one of a certain set of values,
+we indicate this by the use of the _enum_ format:
+
+```
+enum PermittedValues {
+  Value1,
+  Value2
+}
+```
+
+This means that _PermittedValues_ is a _string_ with two potential values,
+_Value1_ and _Value2_.
+
+### BoundField
+
+```
+class BoundField {
+  @Field decl;
+  @Instance|Sentinel value;
+}
+```
+
+A _BoundField_ represents a field bound to a particular value in an
+_Instance_.
+
+If the field is uninitialized, the _value_ will be the
+_NotInitialized_ [Sentinel](#sentinel).
+
+If the field is being initialized, the _value_ will be the
+_BeingInitialized_ [Sentinel](#sentinel).
+
+### BoundVariable
+
+```
+class BoundVariable {
+  string name;
+  @Instance|Sentinel value;
+
+  // The token position where this variable was declared.
+  int declarationTokenPos;
+
+  // The first token position where this variable is visible to the scope.
+  int scopeStartTokenPos;
+
+  // The last token position where this variable is visible to the scope.
+  int scopeEndTokenPos;
+}
+```
+
+A _BoundVariable_ represents a local variable bound to a particular value
+in a _Frame_.
+
+If the variable is uninitialized, the _value_ will be the
+_NotInitialized_ [Sentinel](#sentinel).
+
+If the variable is being initialized, the _value_ will be the
+_BeingInitialized_ [Sentinel](#sentinel).
+
+If the variable has been optimized out by the compiler, the _value_
+will be the _OptimizedOut_ [Sentinel](#sentinel).
+
+### Breakpoint
+
+```
+class Breakpoint extends Object {
+  // A number identifying this breakpoint to the user.
+  int breakpointNumber;
+
+  // Has this breakpoint been assigned to a specific program location?
+  bool resolved;
+
+  // Is this a breakpoint that was added synthetically as part of a step
+  // OverAsyncSuspension resume command?
+  bool isSyntheticAsyncContinuation [optional];
+
+  // SourceLocation when breakpoint is resolved, UnresolvedSourceLocation
+  // when a breakpoint is not resolved.
+  SourceLocation|UnresolvedSourceLocation location;
+}
+```
+
+A _Breakpoint_ describes a debugger breakpoint.
+
+A breakpoint is _resolved_ when it has been assigned to a specific
+program location.  A breakpoint my remain unresolved when it is in
+code which has not yet been compiled or in a library which has not
+been loaded (i.e. a deferred library).
+
+### Class
+
+```
+class @Class extends @Object {
+  // The name of this class.
+  string name;
+}
+```
+
+_@Class_ is a reference to a _Class_.
+
+```
+class Class extends Object {
+  // The name of this class.
+  string name;
+
+  // The error which occurred during class finalization, if it exists.
+  @Error error [optional];
+
+  // Is this an abstract class?
+  bool abstract;
+
+  // Is this a const class?
+  bool const;
+
+  // The library which contains this class.
+  @Library library;
+
+  // The location of this class in the source code.
+  SourceLocation location [optional];
+
+  // The superclass of this class, if any.
+  @Class super [optional];
+
+  // The supertype for this class, if any.
+  //
+  // The value will be of the kind: Type.
+  @Instance superType [optional];
+
+  // A list of interface types for this class.
+  //
+  // The values will be of the kind: Type.
+  @Instance[] interfaces;
+
+  // The mixin type for this class, if any.
+  //
+  // The value will be of the kind: Type.
+  @Instance mixin [optional];
+
+  // A list of fields in this class. Does not include fields from
+  // superclasses.
+  @Field[] fields;
+
+  // A list of functions in this class. Does not include functions
+  // from superclasses.
+  @Function[] functions;
+
+  // A list of subclasses of this class.
+  @Class[] subclasses;
+}
+```
+
+A _Class_ provides information about a Dart language class.
+
+### ClassList
+
+```
+class ClassList extends Response {
+  @Class[] classes;
+}
+```
+
+### Code
+
+```
+class @Code extends @Object {
+  // A name for this code object.
+  string name;
+
+  // What kind of code object is this?
+  CodeKind kind;
+}
+```
+
+_@Code_ is a reference to a _Code_ object.
+
+```
+class Code extends @Object {
+  // A name for this code object.
+  string name;
+
+  // What kind of code object is this?
+  CodeKind kind;
+}
+```
+
+A _Code_ object represents compiled code in the Dart VM.
+
+### CodeKind
+
+```
+enum CodeKind {
+  Dart,
+  Native,
+  Stub,
+  Tag,
+  Collected
+}
+```
+
+### Context
+
+```
+class @Context extends @Object {
+  // The number of variables in this context.
+  int length;
+}
+```
+
+```
+class Context extends Object {
+  // The number of variables in this context.
+  int length;
+
+  // The enclosing context for this context.
+  Context parent [optional];
+
+  // The variables in this context object.
+  ContextElement[] variables;
+}
+```
+
+A _Context_ is a data structure which holds the captured variables for
+some closure.
+
+### ContextElement
+
+```
+class ContextElement {
+  @Instance|Sentinel value;
+}
+```
+
+### Error
+
+```
+class @Error extends @Object {
+  // What kind of error is this?
+  ErrorKind kind;
+
+  // A description of the error.
+  string message;
+}
+```
+
+_@Error_ is a reference to an _Error_.
+
+```
+class Error extends Object {
+  // What kind of error is this?
+  ErrorKind kind;
+
+  // A description of the error.
+  string message;
+
+  // If this error is due to an unhandled exception, this
+  // is the exception thrown.
+  @Instance exception [optional];
+
+  // If this error is due to an unhandled exception, this
+  // is the stacktrace object.
+  @Instance stacktrace [optional];
+}
+```
+
+An _Error_ represents a Dart language level error. This is distinct from an
+[rpc error](#rpc-error).
+
+### ErrorKind
+
+```
+enum ErrorKind {
+  // The isolate has encountered an unhandled Dart exception.
+  UnhandledException,
+
+  // The isolate has encountered a Dart language error in the program.
+  LanguageError,
+
+  // The isolate has encounted an internal error. These errors should be
+  // reported as bugs.
+  InternalError,
+
+  // The isolate has been terminated by an external source.
+  TerminationError
+}
+```
+
+### Event
+
+```
+class Event extends Response {
+  // What kind of event is this?
+  EventKind kind;
+
+  // The isolate with which this event is associated.
+  //
+  // This is provided for all event kinds except for:
+  //   VMUpdate
+  @Isolate isolate [optional];
+
+  // The vm with which this event is associated.
+  //
+  // This is provided for the event kind:
+  //   VMUpdate
+  @VM vm [optional];
+
+  // The timestamp (in milliseconds since the epoch) associated with this event.
+  // For some isolate pause events, the timestamp is from when the isolate was
+  // paused. For other events, the timestamp is from when the event was created.
+  int timestamp;
+
+  // The breakpoint which was added, removed, or resolved.
+  //
+  // This is provided for the event kinds:
+  //   PauseBreakpoint
+  //   BreakpointAdded
+  //   BreakpointRemoved
+  //   BreakpointResolved
+  Breakpoint breakpoint [optional];
+
+  // The list of breakpoints at which we are currently paused
+  // for a PauseBreakpoint event.
+  //
+  // This list may be empty. For example, while single-stepping, the
+  // VM sends a PauseBreakpoint event with no breakpoints.
+  //
+  // If there is more than one breakpoint set at the program position,
+  // then all of them will be provided.
+  //
+  // This is provided for the event kinds:
+  //   PauseBreakpoint
+  Breakpoint[] pauseBreakpoints [optional];
+
+  // The top stack frame associated with this event, if applicable.
+  //
+  // This is provided for the event kinds:
+  //   PauseBreakpoint
+  //   PauseInterrupted
+  //   PauseException
+  //
+  // For PauseInterrupted events, there will be no top frame if the
+  // isolate is idle (waiting in the message loop).
+  //
+  // For the Resume event, the top frame is provided at
+  // all times except for the initial resume event that is delivered
+  // when an isolate begins execution.
+  Frame topFrame [optional];
+
+  // The exception associated with this event, if this is a
+  // PauseException event.
+  @Instance exception [optional];
+
+  // An array of bytes, encoded as a base64 string.
+  //
+  // This is provided for the WriteEvent event.
+  string bytes [optional];
+
+  // The argument passed to dart:developer.inspect.
+  //
+  // This is provided for the Inspect event.
+  @Instance inspectee [optional];
+
+  // The RPC name of the extension that was added.
+  //
+  // This is provided for the ServiceExtensionAdded event.
+  string extensionRPC [optional];
+
+  // The extension event kind.
+  //
+  // This is provided for the Extension event.
+  string extensionKind [optional];
+
+  // The extension event data.
+  //
+  // This is provided for the Extension event.
+  ExtensionData extensionData [optional];
+
+  // An array of TimelineEvents
+  //
+  // This is provided for the TimelineEvents event.
+  TimelineEvent[] timelineEvents [optional];
+
+  // Is the isolate paused at an await, yield, or yield* statement?
+  //
+  // This is provided for the event kinds:
+  //   PauseBreakpoint
+  //   PauseInterrupted
+  bool atAsyncSuspension [optional];
+
+  // The status (success or failure) related to the event.
+  // This is provided for the event kinds:
+  //   IsolateReloaded
+  //   IsolateSpawn
+  string status [optional];
+}
+```
+
+An _Event_ is an asynchronous notification from the VM. It is delivered
+only when the client has subscribed to an event stream using the
+[streamListen](#streamListen) RPC.
+
+For more information, see [events](#events).
+
+### EventKind
+
+```
+enum EventKind {
+  // Notification that VM identifying information has changed. Currently used
+  // to notify of changes to the VM debugging name via setVMName.
+  VMUpdate,
+
+  // Notification that a new isolate has started.
+  IsolateStart,
+
+  // Notification that an isolate is ready to run.
+  IsolateRunnable,
+
+  // Notification that an isolate has exited.
+  IsolateExit,
+
+  // Notification that isolate identifying information has changed.
+  // Currently used to notify of changes to the isolate debugging name
+  // via setName.
+  IsolateUpdate,
+
+  // Notification that an isolate has been reloaded.
+  IsolateReload,
+
+  // Notification that an extension RPC was registered on an isolate.
+  ServiceExtensionAdded,
+
+  // An isolate has paused at start, before executing code.
+  PauseStart,
+
+  // An isolate has paused at exit, before terminating.
+  PauseExit,
+
+  // An isolate has paused at a breakpoint or due to stepping.
+  PauseBreakpoint,
+
+  // An isolate has paused due to interruption via pause.
+  PauseInterrupted,
+
+  // An isolate has paused due to an exception.
+  PauseException,
+
+  // An isolate has paused after a service request.
+  PausePostRequest,
+
+  // An isolate has started or resumed execution.
+  Resume,
+
+  // Indicates an isolate is not yet runnable. Only appears in an Isolate's
+  // pauseEvent. Never sent over a stream.
+  None,
+
+  // A breakpoint has been added for an isolate.
+  BreakpointAdded,
+
+  // An unresolved breakpoint has been resolved for an isolate.
+  BreakpointResolved,
+
+  // A breakpoint has been removed.
+  BreakpointRemoved,
+
+  // A garbage collection event.
+  GC,
+
+  // Notification of bytes written, for example, to stdout/stderr.
+  WriteEvent,
+
+  // Notification from dart:developer.inspect.
+  Inspect,
+
+  // Event from dart:developer.postEvent.
+  Extension
+}
+```
+
+Adding new values to _EventKind_ is considered a backwards compatible
+change. Clients should ignore unrecognized events.
+
+### ExtensionData
+
+```
+class ExtensionData {
+}
+```
+
+An _ExtensionData_ is an arbitrary map that can have any contents.
+
+### Field
+
+```
+class @Field extends @Object {
+  // The name of this field.
+  string name;
+
+  // The owner of this field, which can be either a Library or a
+  // Class.
+  @Object owner;
+
+  // The declared type of this field.
+  //
+  // The value will always be of one of the kinds:
+  // Type, TypeRef, TypeParameter, BoundedType.
+  @Instance declaredType;
+
+  // Is this field const?
+  bool const;
+
+  // Is this field final?
+  bool final;
+
+  // Is this field static?
+  bool static;
+}
+```
+
+An _@Field_ is a reference to a _Field_.
+
+```
+class Field extends Object {
+  // The name of this field.
+  string name;
+
+  // The owner of this field, which can be either a Library or a
+  // Class.
+  @Object owner;
+
+  // The declared type of this field.
+  //
+  // The value will always be of one of the kinds:
+  // Type, TypeRef, TypeParameter, BoundedType.
+  @Instance declaredType;
+
+  // Is this field const?
+  bool const;
+
+  // Is this field final?
+  bool final;
+
+  // Is this field static?
+  bool static;
+
+  // The value of this field, if the field is static.
+  @Instance staticValue [optional];
+
+  // The location of this field in the source code.
+  SourceLocation location [optional];
+}
+```
+
+A _Field_ provides information about a Dart language field or
+variable.
+
+
+### Flag
+
+```
+class Flag {
+  // The name of the flag.
+  string name;
+
+  // A description of the flag.
+  string comment;
+
+  // Has this flag been modified from its default setting?
+  bool modified;
+
+  // The value of this flag as a string.
+  //
+  // If this property is absent, then the value of the flag was NULL.
+  string valueAsString [optional];
+}
+```
+
+A _Flag_ represents a single VM command line flag.
+
+### FlagList
+
+```
+class FlagList extends Response {
+  // A list of all flags in the VM.
+  Flag[] flags;
+}
+```
+
+A _FlagList_ represents the complete set of VM command line flags.
+
+### Frame
+
+```
+class Frame extends Response {
+  int index;
+  @Function function;
+  @Code code;
+  SourceLocation location [optional];
+  BoundVariable[] vars [optional];
+  FrameKind kind [optional];
+}
+```
+
+### Function
+
+```
+class @Function extends @Object {
+  // The name of this function.
+  string name;
+
+  // The owner of this function, which can be a Library, Class, or a Function.
+  @Library|@Class|@Function owner;
+
+  // Is this function static?
+  bool static;
+
+  // Is this function const?
+  bool const;
+}
+```
+
+An _@Function_ is a reference to a _Function_.
+
+
+```
+class Function extends Object {
+  // The name of this function.
+  string name;
+
+  // The owner of this function, which can be a Library, Class, or a Function.
+  @Library|@Class|@Function owner;
+
+  // The location of this function in the source code.
+  SourceLocation location [optional];
+
+  // The compiled code associated with this function.
+  @Code code [optional];
+}
+```
+
+A _Function_ represents a Dart language function.
+
+### Instance
+
+```
+class @Instance extends @Object {
+  // What kind of instance is this?
+  InstanceKind kind;
+
+  // Instance references always include their class.
+  @Class class;
+
+  // The value of this instance as a string.
+  //
+  // Provided for the instance kinds:
+  //   Null (null)
+  //   Bool (true or false)
+  //   Double (suitable for passing to Double.parse())
+  //   Int (suitable for passing to int.parse())
+  //   String (value may be truncated)
+  //   Float32x4
+  //   Float64x2
+  //   Int32x4
+  //   StackTrace
+  string valueAsString [optional];
+
+  // The valueAsString for String references may be truncated. If so,
+  // this property is added with the value 'true'.
+  //
+  // New code should use 'length' and 'count' instead.
+  bool valueAsStringIsTruncated [optional];
+
+  // The length of a List or the number of associations in a Map or the
+  // number of codeunits in a String.
+  //
+  // Provided for instance kinds:
+  //   String
+  //   List
+  //   Map
+  //   Uint8ClampedList
+  //   Uint8List
+  //   Uint16List
+  //   Uint32List
+  //   Uint64List
+  //   Int8List
+  //   Int16List
+  //   Int32List
+  //   Int64List
+  //   Float32List
+  //   Float64List
+  //   Int32x4List
+  //   Float32x4List
+  //   Float64x2List
+  int length [optional];
+
+  // The name of a Type instance.
+  //
+  // Provided for instance kinds:
+  //   Type
+  string name [optional];
+
+  // The corresponding Class if this Type has a resolved typeClass.
+  //
+  // Provided for instance kinds:
+  //   Type
+  @Class typeClass [optional];
+
+  // The parameterized class of a type parameter:
+  //
+  // Provided for instance kinds:
+  //   TypeParameter
+  @Class parameterizedClass [optional];
+
+
+  // The pattern of a RegExp instance.
+  //
+  // The pattern is always an instance of kind String.
+  //
+  // Provided for instance kinds:
+  //   RegExp
+  @Instance pattern [optional];
+}
+```
+
+_@Instance_ is a reference to an _Instance_.
+
+```
+class Instance extends Object {
+  // What kind of instance is this?
+  InstanceKind kind;
+
+  // Instance references always include their class.
+  @Class class;
+
+  // The value of this instance as a string.
+  //
+  // Provided for the instance kinds:
+  //   Bool (true or false)
+  //   Double (suitable for passing to Double.parse())
+  //   Int (suitable for passing to int.parse())
+  //   String (value may be truncated)
+  string valueAsString [optional];
+
+  // The valueAsString for String references may be truncated. If so,
+  // this property is added with the value 'true'.
+  //
+  // New code should use 'length' and 'count' instead.
+  bool valueAsStringIsTruncated [optional];
+
+  // The length of a List or the number of associations in a Map or the
+  // number of codeunits in a String.
+  //
+  // Provided for instance kinds:
+  //   String
+  //   List
+  //   Map
+  //   Uint8ClampedList
+  //   Uint8List
+  //   Uint16List
+  //   Uint32List
+  //   Uint64List
+  //   Int8List
+  //   Int16List
+  //   Int32List
+  //   Int64List
+  //   Float32List
+  //   Float64List
+  //   Int32x4List
+  //   Float32x4List
+  //   Float64x2List
+  int length [optional];
+
+  // The index of the first element or association or codeunit returned.
+  // This is only provided when it is non-zero.
+  //
+  // Provided for instance kinds:
+  //   String
+  //   List
+  //   Map
+  //   Uint8ClampedList
+  //   Uint8List
+  //   Uint16List
+  //   Uint32List
+  //   Uint64List
+  //   Int8List
+  //   Int16List
+  //   Int32List
+  //   Int64List
+  //   Float32List
+  //   Float64List
+  //   Int32x4List
+  //   Float32x4List
+  //   Float64x2List
+  int offset [optional];
+
+  // The number of elements or associations or codeunits returned.
+  // This is only provided when it is less than length.
+  //
+  // Provided for instance kinds:
+  //   String
+  //   List
+  //   Map
+  //   Uint8ClampedList
+  //   Uint8List
+  //   Uint16List
+  //   Uint32List
+  //   Uint64List
+  //   Int8List
+  //   Int16List
+  //   Int32List
+  //   Int64List
+  //   Float32List
+  //   Float64List
+  //   Int32x4List
+  //   Float32x4List
+  //   Float64x2List
+  int count [optional];
+
+  // The name of a Type instance.
+  //
+  // Provided for instance kinds:
+  //   Type
+  string name [optional];
+
+  // The corresponding Class if this Type is canonical.
+  //
+  // Provided for instance kinds:
+  //   Type
+  @Class typeClass [optional];
+
+  // The parameterized class of a type parameter:
+  //
+  // Provided for instance kinds:
+  //   TypeParameter
+  @Class parameterizedClass [optional];
+
+  // The fields of this Instance.
+  BoundField[] fields [optional];
+
+  // The elements of a List instance.
+  //
+  // Provided for instance kinds:
+  //   List
+  (@Instance|Sentinel)[] elements [optional];
+
+  // The elements of a Map instance.
+  //
+  // Provided for instance kinds:
+  //   Map
+  MapAssociation[] associations [optional];
+
+  // The bytes of a TypedData instance.
+  //
+  // The data is provided as a Base64 encoded string.
+  //
+  // Provided for instance kinds:
+  //   Uint8ClampedList
+  //   Uint8List
+  //   Uint16List
+  //   Uint32List
+  //   Uint64List
+  //   Int8List
+  //   Int16List
+  //   Int32List
+  //   Int64List
+  //   Float32List
+  //   Float64List
+  //   Int32x4List
+  //   Float32x4List
+  //   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:
+  //   MirrorReference
+  @Instance mirrorReferent [optional];
+
+  // The pattern of a RegExp instance.
+  //
+  // Provided for instance kinds:
+  //   RegExp
+  String pattern [optional];
+
+  // Whether this regular expression is case sensitive.
+  //
+  // Provided for instance kinds:
+  //   RegExp
+  bool isCaseSensitive [optional];
+
+  // Whether this regular expression matches multiple lines.
+  //
+  // Provided for instance kinds:
+  //   RegExp
+  bool isMultiLine [optional];
+
+  // The key for a WeakProperty instance.
+  //
+  // Provided for instance kinds:
+  //   WeakProperty
+  @Instance propertyKey [optional];
+
+  // The key for a WeakProperty instance.
+  //
+  // Provided for instance kinds:
+  //   WeakProperty
+  @Instance propertyValue [optional];
+
+  // The type arguments for this type.
+  //
+  // Provided for instance kinds:
+  //   Type
+  @TypeArguments typeArguments [optional];
+
+  // The index of a TypeParameter instance.
+  //
+  // Provided for instance kinds:
+  //   TypeParameter
+  int parameterIndex [optional];
+
+  // The type bounded by a BoundedType instance
+  // - or -
+  // the referent of a TypeRef instance.
+  //
+  // The value will always be of one of the kinds:
+  // Type, TypeRef, TypeParameter, BoundedType.
+  //
+  // Provided for instance kinds:
+  //   BoundedType
+  //   TypeRef
+  @Instance targetType [optional];
+
+  // The bound of a TypeParameter or BoundedType.
+  //
+  // The value will always be of one of the kinds:
+  // Type, TypeRef, TypeParameter, BoundedType.
+  //
+  // Provided for instance kinds:
+  //   BoundedType
+  //   TypeParameter
+  @Instance bound [optional];
+}
+```
+
+An _Instance_ represents an instance of the Dart language class _Object_.
+
+### InstanceKind
+
+```
+enum InstanceKind {
+  // A general instance of the Dart class Object.
+  PlainInstance,
+
+  // null instance.
+  Null,
+
+  // true or false.
+  Bool,
+
+  // An instance of the Dart class double.
+  Double,
+
+  // An instance of the Dart class int.
+  Int,
+
+  // An instance of the Dart class String.
+  String,
+
+  // An instance of the built-in VM List implementation. User-defined
+  // Lists will be PlainInstance.
+  List,
+
+  // An instance of the built-in VM Map implementation. User-defined
+  // Maps will be PlainInstance.
+  Map,
+
+  // Vector instance kinds.
+  Float32x4,
+  Float64x2,
+  Int32x4
+
+  // An instance of the built-in VM TypedData implementations. User-defined
+  // TypedDatas will be PlainInstance.
+  Uint8ClampedList,
+  Uint8List,
+  Uint16List,
+  Uint32List,
+  Uint64List,
+  Int8List,
+  Int16List,
+  Int32List,
+  Int64List,
+  Float32List,
+  Float64List,
+  Int32x4List,
+  Float32x4List,
+  Float64x2List,
+
+  // An instance of the Dart class StackTrace.
+  StackTrace,
+
+  // An instance of the built-in VM Closure implementation. User-defined
+  // Closures will be PlainInstance.
+  Closure,
+
+  // An instance of the Dart class MirrorReference.
+  MirrorReference,
+
+  // An instance of the Dart class RegExp.
+  RegExp,
+
+  // An instance of the Dart class WeakProperty.
+  WeakProperty,
+
+  // An instance of the Dart class Type.
+  Type,
+
+  // An instance of the Dart class TypeParameter.
+  TypeParameter,
+
+  // An instance of the Dart class TypeRef.
+  TypeRef,
+
+  // An instance of the Dart class BoundedType.
+  BoundedType,
+}
+```
+
+Adding new values to _InstanceKind_ is considered a backwards
+compatible change. Clients should treat unrecognized instance kinds
+as _PlainInstance_.
+
+### Isolate
+
+```
+class @Isolate extends Response {
+  // The id which is passed to the getIsolate RPC to load this isolate.
+  string id;
+
+  // A numeric id for this isolate, represented as a string. Unique.
+  string number;
+
+  // A name identifying this isolate. Not guaranteed to be unique.
+  string name;
+}
+```
+
+_@Isolate_ is a reference to an _Isolate_ object.
+
+```
+class Isolate extends Response {
+  // The id which is passed to the getIsolate RPC to reload this
+  // isolate.
+  string id;
+
+  // A numeric id for this isolate, represented as a string. Unique.
+  string number;
+
+  // A name identifying this isolate. Not guaranteed to be unique.
+  string name;
+
+  // The time that the VM started in milliseconds since the epoch.
+  //
+  // Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
+  int startTime;
+
+  // Is the isolate in a runnable state?
+  bool runnable;
+
+  // The number of live ports for this isolate.
+  int livePorts;
+
+  // Will this isolate pause when exiting?
+  bool pauseOnExit;
+
+  // The last pause event delivered to the isolate. If the isolate is
+  // running, this will be a resume event.
+  Event pauseEvent;
+
+  // The root library for this isolate.
+  //
+  // Guaranteed to be initialized when the IsolateRunnable event fires.
+  @Library rootLib [optional];
+
+  // A list of all libraries for this isolate.
+  //
+  // Guaranteed to be initialized when the IsolateRunnable event fires.
+  @Library[] libraries;
+
+  // A list of all breakpoints for this isolate.
+  Breakpoint[] breakpoints;
+
+  // The error that is causing this isolate to exit, if applicable.
+  Error error [optional];
+
+  // The current pause on exception mode for this isolate.
+  ExceptionPauseMode exceptionPauseMode;
+
+  // The list of service extension RPCs that are registered for this isolate,
+  // if any.
+  string[] extensionRPCs [optional];
+}
+```
+
+An _Isolate_ object provides information about one isolate in the VM.
+
+### Library
+
+```
+class @Library extends @Object {
+  // The name of this library.
+  string name;
+
+  // The uri of this library.
+  string uri;
+}
+```
+
+_@Library_ is a reference to a _Library_.
+
+```
+class Library extends Object {
+  // The name of this library.
+  string name;
+
+  // The uri of this library.
+  string uri;
+
+  // Is this library debuggable? Default true.
+  bool debuggable;
+
+  // A list of the imports for this library.
+  LibraryDependency[] dependencies;
+
+  // A list of the scripts which constitute this library.
+  @Script[] scripts;
+
+  // A list of the top-level variables in this library.
+  @Field[] variables;
+
+  // A list of the top-level functions in this library.
+  @Function[] functions;
+
+  // A list of all classes in this library.
+  @Class[] classes;
+}
+```
+
+A _Library_ provides information about a Dart language library.
+
+See [setLibraryDebuggable](#setlibrarydebuggable).
+
+### LibraryDependency
+
+```
+class LibraryDependency {
+  // Is this dependency an import (rather than an export)?
+  bool isImport;
+
+  // Is this dependency deferred?
+  bool isDeferred;
+
+  // The prefix of an 'as' import, or null.
+  String prefix;
+
+  // The library being imported or exported.
+  @Library target;
+}
+```
+
+A _LibraryDependency_ provides information about an import or export.
+
+### MapAssociation
+
+```
+class MapAssociation {
+  @Instance|Sentinel key;
+  @Instance|Sentinel value;
+}
+```
+
+### Message
+
+```
+class Message extends Response {
+  // The index in the isolate's message queue. The 0th message being the next
+  // message to be processed.
+  int index;
+
+  // An advisory name describing this message.
+  string name;
+
+  // An instance id for the decoded message. This id can be passed to other
+  // RPCs, for example, getObject or evaluate.
+  string messageObjectId;
+
+  // The size (bytes) of the encoded message.
+  int size;
+
+  // A reference to the function that will be invoked to handle this message.
+  @Function handler [optional];
+
+  // The source location of handler.
+  SourceLocation location [optional];
+}
+```
+
+A _Message_ provides information about a pending isolate message and the
+function that will be invoked to handle it.
+
+
+### Null
+
+```
+class @Null extends @Instance {
+  // Always 'null'.
+  string valueAsString;
+}
+```
+
+_@Null_ is a reference to an a _Null_.
+
+```
+class Null extends Instance {
+  // Always 'null'.
+  string valueAsString;
+}
+```
+
+A _Null_ object represents the Dart language value null.
+
+### Object
+
+```
+class @Object extends Response {
+  // A unique identifier for an Object. Passed to the
+  // getObject RPC to load this Object.
+  string id;
+}
+```
+
+_@Object_ is a reference to a _Object_.
+
+```
+class Object extends Response {
+  // A unique identifier for an Object. Passed to the
+  // getObject RPC to reload this Object.
+  //
+  // Some objects may get a new id when they are reloaded.
+  string id;
+
+  // If an object is allocated in the Dart heap, it will have
+  // a corresponding class object.
+  //
+  // The class of a non-instance is not a Dart class, but is instead
+  // an internal vm object.
+  //
+  // Moving an Object into or out of the heap is considered a
+  // backwards compatible change for types other than Instance.
+  @Class class [optional];
+
+  // The size of this object in the heap.
+  //
+  // If an object is not heap-allocated, then this field is omitted.
+  //
+  // Note that the size can be zero for some objects. In the current
+  // VM implementation, this occurs for small integers, which are
+  // stored entirely within their object pointers.
+  int size [optional];
+}
+```
+
+An _Object_ is a  persistent object that is owned by some isolate.
+
+### ReloadReport
+
+```
+class ReloadReport extends Response {
+  // Did the reload succeed or fail?
+  bool success;
+}
+```
+
+### Response
+
+```
+class Response {
+  // Every response returned by the VM Service has the
+  // type property. This allows the client distinguish
+  // between different kinds of responses.
+  string type;
+}
+```
+
+Every non-error response returned by the Service Protocol extends _Response_.
+By using the _type_ property, the client can determine which [type](#types)
+of response has been provided.
+
+### Sentinel
+
+```
+class Sentinel extends Response {
+  // What kind of sentinel is this?
+  SentinelKind kind;
+
+  // A reasonable string representation of this sentinel.
+  string valueAsString;
+}
+```
+
+A _Sentinel_ is used to indicate that the normal response is not available.
+
+We use a _Sentinel_ instead of an [error](#errors) for these cases because
+they do not represent a problematic condition. They are normal.
+
+### SentinelKind
+
+```
+enum SentinelKind {
+  // Indicates that the object referred to has been collected by the GC.
+  Collected,
+
+  // Indicates that an object id has expired.
+  Expired,
+
+  // Indicates that a variable or field has not been initialized.
+  NotInitialized,
+
+  // Indicates that a variable or field is in the process of being initialized.
+  BeingInitialized,
+
+  // Indicates that a variable has been eliminated by the optimizing compiler.
+  OptimizedOut,
+
+  // Reserved for future use.
+  Free,
+}
+```
+
+A _SentinelKind_ is used to distinguish different kinds of _Sentinel_ objects.
+
+Adding new values to _SentinelKind_ is considered a backwards
+compatible change. Clients must handle this gracefully.
+
+
+### FrameKind
+```
+enum FrameKind {
+  Regular,
+  AsyncCausal,
+  AsyncSuspensionMarker,
+}
+```
+
+A _FrameKind_ is used to distinguish different kinds of _Frame_ objects.
+
+### Script
+
+```
+class @Script extends @Object {
+  // The uri from which this script was loaded.
+  string uri;
+}
+```
+
+_@Script_ is a reference to a _Script_.
+
+```
+class Script extends Object {
+  // The uri from which this script was loaded.
+  string uri;
+
+  // The library which owns this script.
+  @Library library;
+
+  // The source code for this script. For certain built-in scripts,
+  // this may be reconstructed without source comments.
+  string source;
+
+  // A table encoding a mapping from token position to line and column.
+  int[][] tokenPosTable;
+}
+```
+
+A _Script_ provides information about a Dart language script.
+
+The _tokenPosTable_ is an array of int arrays. Each subarray
+consists of a line number followed by _(tokenPos, columnNumber)_ pairs:
+
+> [lineNumber, (tokenPos, columnNumber)*]
+
+The _tokenPos_ is an arbitrary integer value that is used to represent
+a location in the source code.  A _tokenPos_ value is not meaningful
+in itself and code should not rely on the exact values returned.
+
+For example, a _tokenPosTable_ with the value...
+
+> [[1, 100, 5, 101, 8],[2, 102, 7]]
+
+...encodes the mapping:
+
+tokenPos | line | column
+-------- | ---- | ------
+100 | 1 | 5
+101 | 1 | 8
+102 | 2 | 7
+
+### SourceLocation
+
+```
+class SourceLocation extends Response {
+  // The script containing the source location.
+  @Script script;
+
+  // The first token of the location.
+  int tokenPos;
+
+  // The last token of the location if this is a range.
+  int endTokenPos [optional];
+}
+```
+
+The _SourceLocation_ class is used to designate a position or range in
+some script.
+
+### SourceReport
+
+```
+class SourceReport extends Response {
+  // A list of ranges in the program source.  These ranges correspond
+  // to ranges of executable code in the user's program (functions,
+  // methods, constructors, etc.)
+  //
+  // Note that ranges may nest in other ranges, in the case of nested
+  // functions.
+  //
+  // Note that ranges may be duplicated, in the case of mixins.
+  SourceReportRange[] ranges;
+
+  // A list of scripts, referenced by index in the report's ranges.
+  ScriptRef[] scripts;
+}
+```
+
+The _SourceReport_ class represents a set of reports tied to source
+locations in an isolate.
+
+### SourceReportCoverage
+
+```
+class SourceReportCoverage {
+  // A list of token positions in a SourceReportRange which have been
+  // executed.  The list is sorted.
+  int[] hits;
+
+  // A list of token positions in a SourceReportRange which have not been
+  // executed.  The list is sorted.
+  int[] misses;
+}
+```
+
+The _SourceReportCoverage_ class represents coverage information for
+one [SourceReportRange](#sourcereportrange).
+
+Note that _SourceReportCoverage_ does not extend [Response](#response)
+and therefore will not contain a _type_ property.
+
+### SourceReportKind
+
+```
+enum SourceReportKind {
+  // Used to request a code coverage information.
+  Coverage,
+
+  // Used to request a list of token positions of possible breakpoints.
+  PossibleBreakpoints
+}
+```
+
+### SourceReportRange
+
+```
+class SourceReportRange {
+  // An index into the script table of the SourceReport, indicating
+  // which script contains this range of code.
+  int scriptIndex;
+
+  // The token position at which this range begins.
+  int startPos;
+
+  // The token position at which this range ends.  Inclusive.
+  int endPos;
+
+  // Has this range been compiled by the Dart VM?
+  bool compiled;
+
+  // The error while attempting to compile this range, if this
+  // report was generated with forceCompile=true.
+  @Error error [optional];
+
+  // Code coverage information for this range.  Provided only when the
+  // Coverage report has been requested and the range has been
+  // compiled.
+  SourceReportCoverage coverage [optional];
+
+  // Possible breakpoint information for this range, represented as a
+  // sorted list of token positions.  Provided only when the when the
+  // PossibleBreakpoint report has been requested and the range has been
+  // compiled.
+  int[] possibleBreakpoints [optional];
+}
+```
+
+The _SourceReportRange_ class represents a range of executable code
+(function, method, constructor, etc) in the running program.  It is
+part of a [SourceReport](#sourcereport).
+
+Note that _SourceReportRange_ does not extend [Response](#response)
+and therefore will not contain a _type_ property.
+
+### Stack
+
+```
+class Stack extends Response {
+  Frame[] frames;
+  Frame[] asyncCausalFrames [optional];
+  Message[] messages;
+}
+```
+
+### ExceptionPauseMode
+
+```
+enum ExceptionPauseMode {
+  None,
+  Unhandled,
+  All,
+}
+```
+
+An _ExceptionPauseMode_ indicates how the isolate pauses when an exception
+is thrown.
+
+### StepOption
+
+```
+enum StepOption {
+  Into,
+  Over,
+  OverAsyncSuspension,
+  Out,
+  Rewind
+}
+```
+
+A _StepOption_ indicates which form of stepping is requested in a [resume](#resume) RPC.
+
+### Success
+
+```
+class Success extends Response {
+}
+```
+
+The _Success_ type is used to indicate that an operation completed successfully.
+
+### TimelineEvent
+
+```
+class TimelineEvent {
+}
+```
+
+An _TimelineEvent_ is an arbitrary map that contains a [Trace Event Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview) event.
+
+### TypeArguments
+
+```
+class @TypeArguments extends @Object {
+  // A name for this type argument list.
+  string name;
+}
+```
+
+_@TypeArguments_ is a reference to a _TypeArguments_ object.
+
+```
+class TypeArguments extends Object {
+  // A name for this type argument list.
+  string name;
+
+  // A list of types.
+  //
+  // The value will always be one of the kinds:
+  // Type, TypeRef, TypeParameter, BoundedType.
+  @Instance[] types;
+}
+```
+
+A _TypeArguments_ object represents the type argument vector for some
+instantiated generic type.
+
+### UnresolvedSourceLocation
+
+```
+class UnresolvedSourceLocation extends Response {
+  // The script containing the source location if the script has been loaded.
+  @Script script [optional];
+
+  // The uri of the script containing the source location if the script
+  // has yet to be loaded.
+  string scriptUri [optional];
+
+  // An approximate token position for the source location. This may
+  // change when the location is resolved.
+  int tokenPos [optional];
+
+  // An approximate line number for the source location. This may
+  // change when the location is resolved.
+  int line [optional];
+
+  // An approximate column number for the source location. This may
+  // change when the location is resolved.
+  int column [optional];
+
+}
+```
+
+The _UnresolvedSourceLocation_ class is used to refer to an unresolved
+breakpoint location.  As such, it is meant to approximate the final
+location of the breakpoint but it is not exact.
+
+Either the _script_ or the _scriptUri_ field will be present.
+
+Either the _tokenPos_ or the _line_ field will be present.
+
+The _column_ field will only be present when the breakpoint was
+specified with a specific column number.
+
+### Version
+
+```
+class Version extends Response {
+  // The major version number is incremented when the protocol is changed
+  // in a potentially incompatible way.
+  int major;
+
+  // The minor version number is incremented when the protocol is changed
+  // in a backwards compatible way.
+  int minor;
+}
+```
+
+See [Versioning](#versioning).
+
+### VM
+
+```
+class @VM extends Response {
+  // A name identifying this vm. Not guaranteed to be unique.
+  string name;
+}
+```
+
+_@VM_ is a reference to a _VM_ object.
+
+```
+class VM extends Response {
+  // Word length on target architecture (e.g. 32, 64).
+  int architectureBits;
+
+  // The CPU we are generating code for.
+  string targetCPU;
+
+  // The CPU we are actually running on.
+  string hostCPU;
+
+  // The Dart VM version string.
+  string version;
+
+  // The process id for the VM.
+  int pid;
+
+  // The time that the VM started in milliseconds since the epoch.
+  //
+  // Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
+  int startTime;
+
+  // A list of isolates running in the VM.
+  @Isolate[] isolates;
+}
+```
+
+## Revision History
+
+version | comments
+------- | --------
+1.0 | initial revision
+2.0 | Describe protocol version 2.0.
+3.0 | Describe protocol version 3.0.  Added UnresolvedSourceLocation.  Added Sentinel return to getIsolate.  Add AddedBreakpointWithScriptUri.  Removed Isolate.entry. The type of VM.pid was changed from string to int.  Added VMUpdate events.  Add offset and count parameters to getObject() and offset and count fields to Instance. Added ServiceExtensionAdded event.
+3.1 | Add the getSourceReport RPC.  The getObject RPC now accepts offset and count for string objects.  String objects now contain length, offset, and count properties.
+3.2 | Isolate objects now include the runnable bit and many debugger related RPCs will return an error if executed on an isolate before it is runnable.
+3.3 | Pause event now indicates if the isolate is paused at an await, yield, or yield* suspension point via the 'atAsyncSuspension' field. Resume command now supports the step parameter 'OverAsyncSuspension'. A Breakpoint added synthetically by an 'OverAsyncSuspension' resume command identifies itself as such via the 'isSyntheticAsyncContinuation' field.
+3.4 | Add the superType and mixin fields to Class. Added new pause event 'None'.
+3.5 | Add the error field to SourceReportRange.  Clarify definition of token position.  Add "Isolate must be paused" error code.
+3.6 (unreleased) | Add 'scopeStartTokenPos', 'scopeEndTokenPos', and 'declarationTokenPos' to BoundVariable. Add 'PausePostRequest' event kind. Add 'Rewind' StepOption. Add error code 107 (isolate cannot resume). Add 'reloadSources' RPC and related error codes.
+
+[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 3350583..0cb3cd2 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -102,7 +102,7 @@
 Dart_IsolateCreateCallback ServiceIsolate::create_callback_ = NULL;
 uint8_t* ServiceIsolate::exit_message_ = NULL;
 intptr_t ServiceIsolate::exit_message_length_ = 0;
-Monitor* ServiceIsolate::monitor_ = NULL;
+Monitor* ServiceIsolate::monitor_ = new Monitor();
 bool ServiceIsolate::initializing_ = true;
 bool ServiceIsolate::shutting_down_ = false;
 char* ServiceIsolate::server_address_ = NULL;
@@ -483,9 +483,6 @@
 
 
 void ServiceIsolate::Run() {
-  ASSERT(monitor_ == NULL);
-  monitor_ = new Monitor();
-  ASSERT(monitor_ != NULL);
   // Grab the isolate create callback here to avoid race conditions with tests
   // that change this after Dart_Initialize returns.
   create_callback_ = Isolate::CreateCallback();
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index b114dc6..d42e97c 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -434,6 +434,24 @@
     return true;
   }
 
+  static bool ClearAsyncThreadStack(Thread* thread,
+                                    RawObject** FP,
+                                    RawObject** result) {
+    thread->clear_async_stack_trace();
+    *result = Object::null();
+    return true;
+  }
+
+  static bool SetAsyncThreadStackTrace(Thread* thread,
+                                       RawObject** FP,
+                                       RawObject** result) {
+    RawObject** args = FrameArguments(FP, 1);
+    thread->set_raw_async_stack_trace(
+        reinterpret_cast<RawStackTrace*>(args[0]));
+    *result = Object::null();
+    return true;
+  }
+
   DART_FORCE_INLINE static RawCode* FrameCode(RawObject** FP) {
     ASSERT(GetClassId(FP[kPcMarkerSlotFromFp]) == kCodeCid);
     return static_cast<RawCode*>(FP[kPcMarkerSlotFromFp]);
@@ -504,6 +522,10 @@
   intrinsics_[kDouble_equalIntrinsic] = SimulatorHelpers::Double_equal;
   intrinsics_[kDouble_lessEqualThanIntrinsic] =
       SimulatorHelpers::Double_lessEqualThan;
+  intrinsics_[kClearAsyncThreadStackTraceIntrinsic] =
+      SimulatorHelpers::ClearAsyncThreadStack;
+  intrinsics_[kSetAsyncThreadStackTraceIntrinsic] =
+      SimulatorHelpers::SetAsyncThreadStackTrace;
 }
 
 
@@ -787,9 +809,6 @@
     case 2:
       handler = DRT_InlineCacheMissHandlerTwoArgs;
       break;
-    case 3:
-      handler = DRT_InlineCacheMissHandlerThreeArgs;
-      break;
     default:
       UNREACHABLE();
       break;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 6d5b6e6..a910b54 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1002,7 +1002,7 @@
 
 
 #if !defined(PRODUCT)  // Uses deferred loading.
-UNIT_TEST_CASE(CanonicalizationInScriptSnapshots) {
+VM_UNIT_TEST_CASE(CanonicalizationInScriptSnapshots) {
   const char* kScriptChars =
       "\n"
       "import 'dart:mirrors';"
@@ -1121,7 +1121,7 @@
   }
 }
 
-VM_TEST_CASE(GenerateSource) {
+ISOLATE_UNIT_TEST_CASE(GenerateSource) {
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
   const GrowableObjectArray& libs =
@@ -1138,7 +1138,7 @@
 }
 
 
-UNIT_TEST_CASE(FullSnapshot) {
+VM_UNIT_TEST_CASE(FullSnapshot) {
   const char* kScriptChars =
       "class Fields  {\n"
       "  Fields(int i, int j) : fld1 = i, fld2 = j {}\n"
@@ -1212,7 +1212,7 @@
 }
 
 
-UNIT_TEST_CASE(FullSnapshot1) {
+VM_UNIT_TEST_CASE(FullSnapshot1) {
   // This buffer has to be static for this to compile with Visual Studio.
   // If it is not static compilation of this file with Visual Studio takes
   // more than 30 minutes!
@@ -1281,7 +1281,7 @@
 #ifndef PRODUCT
 
 
-UNIT_TEST_CASE(ScriptSnapshot) {
+VM_UNIT_TEST_CASE(ScriptSnapshot) {
   const char* kLibScriptChars =
       "library dart_import_lib;"
       "class LibFields  {"
@@ -1416,7 +1416,7 @@
 }
 
 
-UNIT_TEST_CASE(ScriptSnapshot1) {
+VM_UNIT_TEST_CASE(ScriptSnapshot1) {
   const char* kScriptChars =
       "class _SimpleNumEnumerable<T extends num> {"
       "final Iterable<T> _source;"
@@ -1489,7 +1489,7 @@
 }
 
 
-UNIT_TEST_CASE(ScriptSnapshot2) {
+VM_UNIT_TEST_CASE(ScriptSnapshot2) {
   // The snapshot of this library is always created in production mode, but
   // loaded and executed in both production and checked modes.
   // This test verifies that type information is still contained in the snapshot
@@ -1605,7 +1605,7 @@
 }
 
 
-UNIT_TEST_CASE(MismatchedSnapshotKinds) {
+VM_UNIT_TEST_CASE(MismatchedSnapshotKinds) {
   const char* kScriptChars = "main() { print('Hello, world!'); }";
   Dart_Handle result;
 
@@ -1781,7 +1781,7 @@
 }
 
 
-UNIT_TEST_CASE(DartGeneratedMessages) {
+VM_UNIT_TEST_CASE(DartGeneratedMessages) {
   static const char* kCustomIsolateScriptChars =
       "getSmi() {\n"
       "  return 42;\n"
@@ -1929,7 +1929,7 @@
 }
 
 
-UNIT_TEST_CASE(DartGeneratedListMessages) {
+VM_UNIT_TEST_CASE(DartGeneratedListMessages) {
   const int kArrayLength = 10;
   static const char* kScriptChars =
       "final int kArrayLength = 10;\n"
@@ -2040,7 +2040,7 @@
 }
 
 
-UNIT_TEST_CASE(DartGeneratedArrayLiteralMessages) {
+VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessages) {
   const int kArrayLength = 10;
   static const char* kScriptChars =
       "final int kArrayLength = 10;\n"
@@ -2261,7 +2261,7 @@
 }
 
 
-UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) {
+VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) {
   const int kArrayLength = 10;
   static const char* kScriptChars =
       "import 'dart:typed_data';\n"
@@ -2481,7 +2481,7 @@
 }
 
 
-UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) {
+VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) {
   const int kArrayLength = 10;
   static const char* kScriptChars =
       "import 'dart:typed_data';\n"
@@ -2716,7 +2716,7 @@
   EXPECT_EQ(len, object->value.as_typed_data.length);
 }
 
-UNIT_TEST_CASE(DartGeneratedListMessagesWithTypedData) {
+VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithTypedData) {
   static const char* kScriptChars =
       "import 'dart:typed_data';\n"
       "getTypedDataList() {\n"
@@ -2903,7 +2903,7 @@
 }
 
 
-UNIT_TEST_CASE(PostCObject) {
+VM_UNIT_TEST_CASE(PostCObject) {
   // Create a native port for posting from C to Dart
   TestIsolateScope __test_isolate__;
   const char* kScriptChars =
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 500e1ea..c84811a 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -257,6 +257,14 @@
   if (code.IsNull()) {
     return false;  // Stub frames do not have exception handlers.
   }
+  HandlerInfoCache* cache = thread->isolate()->handler_info_cache();
+  ExceptionHandlerInfo* info = cache->Lookup(pc());
+  if (info != NULL) {
+    *handler_pc = code.PayloadStart() + info->handler_pc_offset;
+    *needs_stacktrace = info->needs_stacktrace;
+    *has_catch_all = info->has_catch_all;
+    return true;
+  }
   uword pc_offset = pc() - code.PayloadStart();
 
   REUSABLE_EXCEPTION_HANDLERS_HANDLESCOPE(thread);
@@ -274,11 +282,12 @@
   while (iter.MoveNext()) {
     const intptr_t current_try_index = iter.TryIndex();
     if ((iter.PcOffset() == pc_offset) && (current_try_index != -1)) {
-      RawExceptionHandlers::HandlerInfo handler_info;
+      ExceptionHandlerInfo handler_info;
       handlers.GetHandlerInfo(current_try_index, &handler_info);
       *handler_pc = code.PayloadStart() + handler_info.handler_pc_offset;
       *needs_stacktrace = handler_info.needs_stacktrace;
       *has_catch_all = handler_info.has_catch_all;
+      cache->Insert(pc(), handler_info);
       return true;
     }
   }
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index d1ebde6..907e945 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -17,7 +17,7 @@
 namespace dart {
 
 // Unit test for empty stack frame iteration.
-VM_TEST_CASE(EmptyStackFrameIteration) {
+ISOLATE_UNIT_TEST_CASE(EmptyStackFrameIteration) {
   StackFrameIterator iterator(StackFrameIterator::kValidateFrames);
   EXPECT(!iterator.HasNextFrame());
   EXPECT(iterator.NextFrame() == NULL);
@@ -26,7 +26,7 @@
 
 
 // Unit test for empty dart stack frame iteration.
-VM_TEST_CASE(EmptyDartStackFrameIteration) {
+ISOLATE_UNIT_TEST_CASE(EmptyDartStackFrameIteration) {
   DartFrameIterator iterator;
   EXPECT(iterator.NextFrame() == NULL);
   VerifyPointersVisitor::VerifyPointers();
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
new file mode 100644
index 0000000..c746d50
--- /dev/null
+++ b/runtime/vm/stack_trace.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/stack_frame.h"
+#include "vm/stack_trace.h"
+
+namespace dart {
+
+// Count the number of frames that are on the stack.
+intptr_t StackTraceUtils::CountFrames(Thread* thread,
+                                      int skip_frames,
+                                      const Function& async_function) {
+  Zone* zone = thread->zone();
+  intptr_t frame_count = 0;
+  StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
+  StackFrame* frame = frames.NextFrame();
+  ASSERT(frame != NULL);  // We expect to find a dart invocation frame.
+  Code& code = Code::Handle(zone);
+  Function& function = Function::Handle(zone);
+  const bool async_function_is_null = async_function.IsNull();
+  while (frame != NULL) {
+    if (frame->IsDartFrame()) {
+      if (skip_frames > 0) {
+        skip_frames--;
+      } else {
+        code = frame->LookupDartCode();
+        function = code.function();
+        frame_count++;
+        if (!async_function_is_null &&
+            (async_function.raw() == function.parent_function())) {
+          return frame_count;
+        }
+      }
+    }
+    frame = frames.NextFrame();
+  }
+  // We hit the sentinel.
+  ASSERT(async_function_is_null);
+  return frame_count;
+}
+
+
+intptr_t StackTraceUtils::CollectFrames(Thread* thread,
+                                        const Array& code_array,
+                                        const Array& pc_offset_array,
+                                        intptr_t array_offset,
+                                        intptr_t count,
+                                        int skip_frames) {
+  Zone* zone = thread->zone();
+  StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
+  StackFrame* frame = frames.NextFrame();
+  ASSERT(frame != NULL);  // We expect to find a dart invocation frame.
+  Function& function = Function::Handle(zone);
+  Code& code = Code::Handle(zone);
+  Smi& offset = Smi::Handle(zone);
+  intptr_t collected_frames_count = 0;
+  while ((frame != NULL) && (collected_frames_count < count)) {
+    if (frame->IsDartFrame()) {
+      if (skip_frames > 0) {
+        skip_frames--;
+      } else {
+        code = frame->LookupDartCode();
+        function = code.function();
+        offset = Smi::New(frame->pc() - code.PayloadStart());
+        code_array.SetAt(array_offset, code);
+        pc_offset_array.SetAt(array_offset, offset);
+        array_offset++;
+        collected_frames_count++;
+      }
+    }
+    frame = frames.NextFrame();
+  }
+  return collected_frames_count;
+}
+
+
+intptr_t StackTraceUtils::ExtractAsyncStackTraceInfo(
+    Thread* thread,
+    Function* async_function,
+    StackTrace* async_stack_trace_out,
+    Array* async_code_array,
+    Array* async_pc_offset_array) {
+  if (thread->async_stack_trace() == StackTrace::null()) {
+    return 0;
+  }
+  *async_stack_trace_out = thread->async_stack_trace();
+  ASSERT(!async_stack_trace_out->IsNull());
+  const StackTrace& async_stack_trace =
+      StackTrace::Handle(thread->async_stack_trace());
+  const intptr_t async_stack_trace_length = async_stack_trace.Length();
+  // At least two entries (0: gap marker, 1: async function).
+  ASSERT(async_stack_trace_length >= 2);
+  // Validate the structure of this stack trace.
+  *async_code_array = async_stack_trace.code_array();
+  ASSERT(!async_code_array->IsNull());
+  *async_pc_offset_array = async_stack_trace.pc_offset_array();
+  ASSERT(!async_pc_offset_array->IsNull());
+  // We start with the asynchronous gap marker.
+  ASSERT(async_code_array->At(0) != Code::null());
+  ASSERT(async_code_array->At(0) ==
+         StubCode::AsynchronousGapMarker_entry()->code());
+  const Code& code = Code::Handle(Code::RawCast(async_code_array->At(1)));
+  *async_function = code.function();
+  ASSERT(!async_function->IsNull());
+  ASSERT(async_function->IsAsyncFunction() ||
+         async_function->IsAsyncGenerator());
+  return async_stack_trace_length;
+}
+
+}  // namespace dart
diff --git a/runtime/vm/stack_trace.h b/runtime/vm/stack_trace.h
new file mode 100644
index 0000000..5a89221
--- /dev/null
+++ b/runtime/vm/stack_trace.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef RUNTIME_VM_STACK_TRACE_H_
+#define RUNTIME_VM_STACK_TRACE_H_
+
+#include "vm/allocation.h"
+#include "vm/flag_list.h"
+#include "vm/object.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, show_invisible_frames);
+
+class StackTraceUtils : public AllStatic {
+ public:
+  /// Counts the number of stack frames.
+  /// Skips over the first |skip_frames|.
+  /// If |async_function| is not null, stops at the function that has
+  /// |async_function| as its parent.
+  static intptr_t CountFrames(Thread* thread,
+                              int skip_frames,
+                              const Function& async_function);
+
+  /// Collects |count| frames into |code_array| and |pc_offset_array|.
+  /// Writing begins at |array_offset|.
+  /// Skips over the first |skip_frames|.
+  /// Returns the number of frames collected.
+  static intptr_t CollectFrames(Thread* thread,
+                                const Array& code_array,
+                                const Array& pc_offset_array,
+                                intptr_t array_offset,
+                                intptr_t count,
+                                int skip_frames);
+
+  /// If |thread| has no async_stack_trace, does nothing.
+  /// Populates |async_function| with the top function of the async stack
+  /// trace. Populates |async_stack_trace|, |async_code_array|, and
+  /// |async_pc_offset_array| with the thread's async_stack_trace.
+  /// Returns the length of the asynchronous stack trace.
+  static intptr_t ExtractAsyncStackTraceInfo(Thread* thread,
+                                             Function* async_function,
+                                             StackTrace* async_stack_trace,
+                                             Array* async_code_array,
+                                             Array* async_pc_offset_array);
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_STACK_TRACE_H_
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index cba3cdf..3f65633 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -67,7 +67,8 @@
   V(Subtype2TestCache)                                                         \
   V(Subtype3TestCache)                                                         \
   V(CallClosureNoSuchMethod)                                                   \
-  V(FrameAwaitingMaterialization)
+  V(FrameAwaitingMaterialization)                                              \
+  V(AsynchronousGapMarker)
 
 #else
 #define VM_STUB_CODE_LIST(V)                                                   \
@@ -79,7 +80,8 @@
   V(Deoptimize)                                                                \
   V(DeoptimizeLazyFromReturn)                                                  \
   V(DeoptimizeLazyFromThrow)                                                   \
-  V(FrameAwaitingMaterialization)
+  V(FrameAwaitingMaterialization)                                              \
+  V(AsynchronousGapMarker)
 
 #endif  // !defined(TARGET_ARCH_DBC)
 
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 8b8d8e2..e74d38a 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1339,11 +1339,10 @@
   __ Bind(&ok);
 #endif
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Update counter.
+    // Update counter, ignore overflow.
     const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
     __ LoadFromOffset(kWord, R1, R8, count_offset);
     __ adds(R1, R1, Operand(Smi::RawValue(1)));
-    __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS);  // Overflow.
     __ StoreIntoSmiField(Address(R8, count_offset), R1);
   }
   __ Ret();
@@ -1367,7 +1366,7 @@
     Token::Kind kind,
     bool optimized) {
   __ CheckCodePointer();
-  ASSERT(num_args > 0);
+  ASSERT(num_args == 1 || num_args == 2);
 #if defined(DEBUG)
   {
     Label ok;
@@ -1403,59 +1402,60 @@
   // Load arguments descriptor into R4.
   __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
   // Loop that checks if there is an IC data match.
-  Label loop, update, test, found;
+  Label loop, found, miss;
   // R9: IC data object (preserved).
   __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
   // R8: ic_data_array with check entries: classes and target functions.
-  __ AddImmediate(R8, R8, Array::data_offset() - kHeapObjectTag);
-  // R8: points directly to the first ic data array element.
+  const int kIcDataOffset = Array::data_offset() - kHeapObjectTag;
+  // R8: points at the IC data array.
 
   // Get the receiver's class ID (first read number of arguments from
   // arguments descriptor array and then access the receiver from the stack).
   __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
   __ sub(NOTFP, NOTFP, Operand(Smi::RawValue(1)));
-  __ ldr(R0, Address(SP, NOTFP, LSL, 1));  // NOTFP (argument_count - 1) is smi.
-  __ LoadTaggedClassIdMayBeSmi(R0, R0);
   // NOTFP: argument_count - 1 (smi).
-  // R0: receiver's class ID (smi).
-  __ ldr(R1, Address(R8, 0));  // First class id (smi) to check.
-  __ b(&test);
 
   __ Comment("ICData loop");
+
+  __ ldr(R0, Address(SP, NOTFP, LSL, 1));  // NOTFP (argument_count - 1) is Smi.
+  __ LoadTaggedClassIdMayBeSmi(R0, R0);
+  if (num_args == 2) {
+    __ sub(R1, NOTFP, Operand(Smi::RawValue(1)));
+    __ ldr(R1, Address(SP, R1, LSL, 1));  // R1 (argument_count - 2) is Smi.
+    __ LoadTaggedClassIdMayBeSmi(R1, R1);
+  }
+
+  // We unroll the generic one that is generated once more than the others.
+  const bool optimize = kind == Token::kILLEGAL;
+
   __ Bind(&loop);
-  for (int i = 0; i < num_args; i++) {
-    if (i > 0) {
-      // If not the first, load the next argument's class ID.
-      __ AddImmediate(R0, NOTFP, Smi::RawValue(-i));
-      __ ldr(R0, Address(SP, R0, LSL, 1));
-      __ LoadTaggedClassIdMayBeSmi(R0, R0);
-      // R0: next argument class ID (smi).
-      __ LoadFromOffset(kWord, R1, R8, i * kWordSize);
-      // R1: next class ID to check (smi).
-    }
-    __ cmp(R0, Operand(R1));  // Class id match?
-    if (i < (num_args - 1)) {
+  for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
+    Label update;
+
+    __ ldr(R2, Address(R8, kIcDataOffset));
+    __ cmp(R0, Operand(R2));  // Class id match?
+    if (num_args == 2) {
       __ b(&update, NE);  // Continue.
+      __ ldr(R2, Address(R8, kIcDataOffset + kWordSize));
+      __ cmp(R1, Operand(R2));  // Class id match?
+    }
+    __ b(&found, EQ);  // Break.
+
+    __ Bind(&update);
+
+    const intptr_t entry_size =
+        ICData::TestEntryLengthFor(num_args) * kWordSize;
+    __ AddImmediate(R8, entry_size);  // Next entry.
+
+    __ CompareImmediate(R2, Smi::RawValue(kIllegalCid));  // Done?
+    if (unroll == 0) {
+      __ b(&loop, NE);
     } else {
-      // Last check, all checks before matched.
-      __ b(&found, EQ);  // Break.
+      __ b(&miss, EQ);
     }
   }
-  __ Bind(&update);
-  // Reload receiver class ID.  It has not been destroyed when num_args == 1.
-  if (num_args > 1) {
-    __ ldr(R0, Address(SP, NOTFP, LSL, 1));
-    __ LoadTaggedClassIdMayBeSmi(R0, R0);
-  }
 
-  const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
-  __ AddImmediate(R8, entry_size);  // Next entry.
-  __ ldr(R1, Address(R8, 0));       // Next class ID.
-
-  __ Bind(&test);
-  __ CompareImmediate(R1, Smi::RawValue(kIllegalCid));  // Done?
-  __ b(&loop, NE);
-
+  __ Bind(&miss);
   __ Comment("IC miss");
   // Compute address of arguments.
   // NOTFP: argument_count - 1 (smi).
@@ -1494,14 +1494,14 @@
   // R8: pointer to an IC data check group.
   const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
   const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
-  __ LoadFromOffset(kWord, R0, R8, target_offset);
+  __ LoadFromOffset(kWord, R0, R8, kIcDataOffset + target_offset);
 
   if (FLAG_optimization_counter_threshold >= 0) {
     __ Comment("Update caller's counter");
-    __ LoadFromOffset(kWord, R1, R8, count_offset);
+    __ LoadFromOffset(kWord, R1, R8, kIcDataOffset + count_offset);
+    // Ignore overflow.
     __ adds(R1, R1, Operand(Smi::RawValue(1)));
-    __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS);  // Overflow.
-    __ StoreIntoSmiField(Address(R8, count_offset), R1);
+    __ StoreIntoSmiField(Address(R8, kIcDataOffset + count_offset), R1);
   }
 
   __ Comment("Call target");
@@ -1627,10 +1627,9 @@
   const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Increment count for this call.
+    // Increment count for this call, ignore overflow.
     __ LoadFromOffset(kWord, R1, R8, count_offset);
     __ adds(R1, R1, Operand(Smi::RawValue(1)));
-    __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS);  // Overflow.
     __ StoreIntoSmiField(Address(R8, count_offset), R1);
   }
 
@@ -2285,6 +2284,11 @@
   __ bkpt(0);
 }
 
+
+void StubCode::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
+  __ bkpt(0);
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 4b852a7..63ceedd 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1380,11 +1380,9 @@
 #endif
   if (FLAG_optimization_counter_threshold >= 0) {
     const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
-    // Update counter.
+    // Update counter, ignore overflow.
     __ LoadFromOffset(R1, R6, count_offset);
     __ adds(R1, R1, Operand(Smi::RawValue(1)));
-    __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue));
-    __ csel(R1, R2, R1, VS);  // Overflow.
     __ StoreToOffset(R1, R6, count_offset);
   }
 
@@ -1408,7 +1406,7 @@
     const RuntimeEntry& handle_ic_miss,
     Token::Kind kind,
     bool optimized) {
-  ASSERT(num_args > 0);
+  ASSERT(num_args == 1 || num_args == 2);
 #if defined(DEBUG)
   {
     Label ok;
@@ -1445,7 +1443,7 @@
   // Load arguments descriptor into R4.
   __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset());
   // Loop that checks if there is an IC data match.
-  Label loop, update, test, found;
+  Label loop, found, miss;
   // R5: IC data object (preserved).
   __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset());
   // R6: ic_data_array with check entries: classes and target functions.
@@ -1462,47 +1460,45 @@
   __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled));
   __ LoadTaggedClassIdMayBeSmi(R0, R0);
 
-  // R7: argument_count - 1 (untagged).
-  // R0: receiver's class ID (smi).
-  __ ldr(R1, Address(R6));  // First class id (smi) to check.
-  __ b(&test);
+  if (num_args == 2) {
+    __ AddImmediate(R1, R7, -1);
+    // R1 <- [SP + (R1 << 3)]
+    __ ldr(R1, Address(SP, R1, UXTX, Address::Scaled));
+    __ LoadTaggedClassIdMayBeSmi(R1, R1);
+  }
+
+  // We unroll the generic one that is generated once more than the others.
+  const bool optimize = kind == Token::kILLEGAL;
 
   __ Comment("ICData loop");
   __ Bind(&loop);
-  for (int i = 0; i < num_args; i++) {
-    if (i > 0) {
-      // If not the first, load the next argument's class ID.
-      __ AddImmediate(R0, R7, -i);
-      // R0 <- [SP + (R0 << 3)]
-      __ ldr(R0, Address(SP, R0, UXTX, Address::Scaled));
-      __ LoadTaggedClassIdMayBeSmi(R0, R0);
-      // R0: next argument class ID (smi).
-      __ LoadFromOffset(R1, R6, i * kWordSize);
-      // R1: next class ID to check (smi).
-    }
-    __ CompareRegisters(R0, R1);  // Class id match?
-    if (i < (num_args - 1)) {
+  for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
+    Label update;
+
+    __ LoadFromOffset(R2, R6, 0);
+    __ CompareRegisters(R0, R2);  // Class id match?
+    if (num_args == 2) {
       __ b(&update, NE);  // Continue.
+      __ LoadFromOffset(R2, R6, kWordSize);
+      __ CompareRegisters(R1, R2);  // Class id match?
+    }
+    __ b(&found, EQ);  // Break.
+
+    __ Bind(&update);
+
+    const intptr_t entry_size =
+        ICData::TestEntryLengthFor(num_args) * kWordSize;
+    __ AddImmediate(R6, R6, entry_size);  // Next entry.
+
+    __ CompareImmediate(R2, Smi::RawValue(kIllegalCid));  // Done?
+    if (unroll == 0) {
+      __ b(&loop, NE);
     } else {
-      // Last check, all checks before matched.
-      __ b(&found, EQ);  // Break.
+      __ b(&miss, EQ);
     }
   }
-  __ Bind(&update);
-  // Reload receiver class ID.  It has not been destroyed when num_args == 1.
-  if (num_args > 1) {
-    __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled));
-    __ LoadTaggedClassIdMayBeSmi(R0, R0);
-  }
 
-  const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
-  __ AddImmediate(R6, R6, entry_size);  // Next entry.
-  __ ldr(R1, Address(R6));              // Next class ID.
-
-  __ Bind(&test);
-  __ CompareImmediate(R1, Smi::RawValue(kIllegalCid));  // Done?
-  __ b(&loop, NE);
-
+  __ Bind(&miss);
   __ Comment("IC miss");
   // Compute address of arguments.
   // R7: argument_count - 1 (untagged).
@@ -1550,11 +1546,9 @@
   __ LoadFromOffset(R0, R6, target_offset);
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Update counter.
+    // Update counter, ignore overflow.
     __ LoadFromOffset(R1, R6, count_offset);
     __ adds(R1, R1, Operand(Smi::RawValue(1)));
-    __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue));
-    __ csel(R1, R2, R1, VS);  // Overflow.
     __ StoreToOffset(R1, R6, count_offset);
   }
 
@@ -1679,11 +1673,9 @@
   const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Increment count for this call.
+    // Increment count for this call, ignore overflow.
     __ LoadFromOffset(R1, R6, count_offset);
     __ adds(R1, R1, Operand(Smi::RawValue(1)));
-    __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue));
-    __ csel(R1, R2, R1, VS);  // Overflow.
     __ StoreToOffset(R1, R6, count_offset);
   }
 
@@ -2341,6 +2333,11 @@
   __ brk(0);
 }
 
+
+void StubCode::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
+  __ brk(0);
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/stub_code_dbc.cc b/runtime/vm/stub_code_dbc.cc
index ef41182..545a70e 100644
--- a/runtime/vm/stub_code_dbc.cc
+++ b/runtime/vm/stub_code_dbc.cc
@@ -95,6 +95,11 @@
 }
 
 
+void StubCode::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
+  __ Trap();
+}
+
+
 // Print the stop message.
 DEFINE_LEAF_RUNTIME_ENTRY(void, PrintStopMessage, 1, const char* message) {
   OS::Print("Stop message: %s\n", message);
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index ce6521d..812af17 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1259,13 +1259,9 @@
   __ Bind(&ok);
 #endif
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Update counter.
     const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
-    __ movl(ECX, Address(EBX, count_offset));
-    __ addl(ECX, Immediate(Smi::RawValue(1)));
-    __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
-    __ cmovno(EDI, ECX);
-    __ StoreIntoSmiField(Address(EBX, count_offset), EDI);
+    // Update counter, ignore overflow.
+    __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
   }
   __ ret();
 }
@@ -1287,7 +1283,7 @@
     const RuntimeEntry& handle_ic_miss,
     Token::Kind kind,
     bool optimized) {
-  ASSERT(num_args > 0);
+  ASSERT(num_args == 1 || num_args == 2);
 #if defined(DEBUG)
   {
     Label ok;
@@ -1322,60 +1318,71 @@
   // Load arguments descriptor into EDX.
   __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset()));
   // Loop that checks if there is an IC data match.
+  Label loop, found, miss;
   // ECX: IC data object (preserved).
   __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset()));
   // EBX: ic_data_array with check entries: classes and target functions.
   __ leal(EBX, FieldAddress(EBX, Array::data_offset()));
   // EBX: points directly to the first ic data array element.
 
-  // Get the receiver's class ID (first read number of arguments from
-  // arguments descriptor array and then access the receiver from the stack).
+  // Get argument descriptor into EAX.  In the 1-argument case this is the
+  // last time we need the argument descriptor, and we reuse EAX for the
+  // class IDs from the IC descriptor.  In the 2-argument case we preserve
+  // the argument descriptor in EAX.
   __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
-  __ movl(EDI, Address(ESP, EAX, TIMES_2, 0));  // EAX (argument_count) is smi.
-  __ LoadTaggedClassIdMayBeSmi(EAX, EDI);
-
-  // EAX: receiver's class ID (smi).
-  __ movl(EDI, Address(EBX, 0));  // First class id (smi) to check.
-  Label loop, update, test, found;
-  __ jmp(&test);
+  if (num_args == 1) {
+    // Load receiver into EDI.
+    __ movl(EDI,
+            Address(ESP, EAX, TIMES_2, 0));  // EAX (argument count) is Smi.
+    __ LoadTaggedClassIdMayBeSmi(EAX, EDI);
+    // EAX: receiver class ID as Smi.
+  }
 
   __ Comment("ICData loop");
-  __ Bind(&loop);
-  for (int i = 0; i < num_args; i++) {
-    if (i > 0) {
-      // If not the first, load the next argument's class ID.
-      __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
-      __ movl(EDI, Address(ESP, EAX, TIMES_2, -i * kWordSize));
-      __ LoadTaggedClassIdMayBeSmi(EAX, EDI);
 
-      // EAX: next argument class ID (smi).
-      __ movl(EDI, Address(EBX, i * kWordSize));
-      // EDI: next class ID to check (smi).
-    }
-    __ cmpl(EAX, EDI);  // Class id match?
-    if (i < (num_args - 1)) {
-      __ j(NOT_EQUAL, &update);  // Continue.
-    } else {
-      // Last check, all checks before matched.
-      __ j(EQUAL, &found);  // Break.
-    }
-  }
-  __ Bind(&update);
-  // Reload receiver class ID.  It has not been destroyed when num_args == 1.
-  if (num_args > 1) {
-    __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
-    __ movl(EDI, Address(ESP, EAX, TIMES_2, 0));
-    __ LoadTaggedClassIdMayBeSmi(EAX, EDI);
-  }
-
+  // We unroll the generic one that is generated once more than the others.
+  bool optimize = kind == Token::kILLEGAL;
+  const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
+  const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
   const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
-  __ addl(EBX, Immediate(entry_size));  // Next entry.
-  __ movl(EDI, Address(EBX, 0));        // Next class ID.
 
-  __ Bind(&test);
-  __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid)));  // Done?
-  __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+  __ Bind(&loop);
+  for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
+    Label update;
+    if (num_args == 1) {
+      __ movl(EDI, Address(EBX, 0));
+      __ cmpl(EDI, EAX);                                    // Class id match?
+      __ j(EQUAL, &found);                                  // Break.
+      __ addl(EBX, Immediate(entry_size));                  // Next entry.
+      __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid)));  // Done?
+    } else {
+      ASSERT(num_args == 2);
+      // Load receiver into EDI.
+      __ movl(EDI, Address(ESP, EAX, TIMES_2, 0));
+      __ LoadTaggedClassIdMayBeSmi(EDI, EDI);
+      __ cmpl(EDI, Address(EBX, 0));  // Class id match?
+      __ j(NOT_EQUAL, &update);       // Continue.
 
+      // Load second argument into EDI.
+      __ movl(EDI, Address(ESP, EAX, TIMES_2, -kWordSize));
+      __ LoadTaggedClassIdMayBeSmi(EDI, EDI);
+      __ cmpl(EDI, Address(EBX, kWordSize));  // Class id match?
+      __ j(EQUAL, &found);  // Break.
+
+      __ Bind(&update);
+      __ addl(EBX, Immediate(entry_size));  // Next entry.
+      __ cmpl(Address(EBX, -entry_size),
+              Immediate(Smi::RawValue(kIllegalCid)));  // Done?
+    }
+
+    if (unroll == 0) {
+      __ j(NOT_EQUAL, &loop);
+    } else {
+      __ j(EQUAL, &miss);
+    }
+  }
+
+  __ Bind(&miss);
   __ Comment("IC miss");
   // Compute address of arguments (first read number of arguments from
   // arguments descriptor array and then compute address on the stack).
@@ -1412,15 +1419,10 @@
   __ Bind(&found);
 
   // EBX: Pointer to an IC data check group.
-  const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
-  const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
   if (FLAG_optimization_counter_threshold >= 0) {
     __ Comment("Update caller's counter");
-    __ movl(EAX, Address(EBX, count_offset));
-    __ addl(EAX, Immediate(Smi::RawValue(1)));
-    __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
-    __ cmovno(EDI, EAX);
-    __ StoreIntoSmiField(Address(EBX, count_offset), EDI);
+    // Ignore overflow.
+    __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
   }
 
   __ movl(EAX, Address(EBX, target_offset));
@@ -1555,12 +1557,8 @@
   const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Increment count for this call.
-    __ movl(EAX, Address(EBX, count_offset));
-    __ addl(EAX, Immediate(Smi::RawValue(1)));
-    __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
-    __ cmovno(EDI, EAX);
-    __ StoreIntoSmiField(Address(EBX, count_offset), EDI);
+    // Increment count for this call, ignore overflow.
+    __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
   }
 
   // Load arguments descriptor into EDX.
@@ -2091,6 +2089,11 @@
   __ int3();
 }
 
+
+void StubCode::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
+  __ int3();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 53394cf..d93cb8b 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -1403,13 +1403,10 @@
   __ Bind(&ok);
 #endif
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Update counter.
+    // Update counter, ignore overflow.
     const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
     __ lw(T4, Address(T0, count_offset));
-    __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6);
-    __ slt(CMPRES1, T5, ZR);  // T5 is < 0 if there was overflow.
-    __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue));
-    __ movz(T4, T7, CMPRES1);
+    __ AddImmediate(T4, T4, Smi::RawValue(1));
     __ sw(T4, Address(T0, count_offset));
   }
 
@@ -1434,7 +1431,7 @@
     Token::Kind kind,
     bool optimized) {
   __ Comment("NArgsCheckInlineCacheStub");
-  ASSERT(num_args > 0);
+  ASSERT(num_args == 1 || num_args == 2);
 #if defined(DEBUG)
   {
     Label ok;
@@ -1471,7 +1468,7 @@
   // Preserve return address, since RA is needed for subroutine call.
   __ mov(T2, RA);
   // Loop that checks if there is an IC data match.
-  Label loop, update, test, found;
+  Label loop, found, miss;
   // S5: IC data object (preserved).
   __ lw(T0, FieldAddress(S5, ICData::ic_data_offset()));
   // T0: ic_data_array with check entries: classes and target functions.
@@ -1481,67 +1478,58 @@
   // Get the receiver's class ID (first read number of arguments from
   // arguments descriptor array and then access the receiver from the stack).
   __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
-  __ LoadImmediate(TMP, Smi::RawValue(1));
-  __ subu(T1, T1, TMP);
-  __ sll(T3, T1, 1);  // T1 (argument_count - 1) is smi.
-  __ addu(T3, T3, SP);
-  __ lw(T3, Address(T3));
+  __ sll(T5, T1, 1);  // T1 (argument_count - 1) is smi.
+  __ addu(T5, T5, SP);
+  __ lw(T3, Address(T5, -kWordSize));
   __ LoadTaggedClassIdMayBeSmi(T3, T3);
 
-  // T1: argument_count - 1 (smi).
-  // T3: receiver's class ID (smi).
-  __ b(&test);
-  __ delay_slot()->lw(T4, Address(T0));  // First class id (smi) to check.
-
-  __ Comment("ICData loop");
-  __ Bind(&loop);
-  for (int i = 0; i < num_args; i++) {
-    if (i > 0) {
-      // If not the first, load the next argument's class ID.
-      __ LoadImmediate(T3, Smi::RawValue(-i));
-      __ addu(T3, T1, T3);
-      __ sll(T3, T3, 1);
-      __ addu(T3, SP, T3);
-      __ lw(T3, Address(T3));
-      __ LoadTaggedClassIdMayBeSmi(T3, T3);
-      // T3: next argument class ID (smi).
-      __ lw(T4, Address(T0, i * kWordSize));
-      // T4: next class ID to check (smi).
-    }
-    if (i < (num_args - 1)) {
-      __ bne(T3, T4, &update);  // Continue.
-    } else {
-      // Last check, all checks before matched.
-      Label skip;
-      __ bne(T3, T4, &skip);
-      __ b(&found);                  // Break.
-      __ delay_slot()->mov(RA, T2);  // Restore return address if found.
-      __ Bind(&skip);
-    }
-  }
-  __ Bind(&update);
-  // Reload receiver class ID.  It has not been destroyed when num_args == 1.
-  if (num_args > 1) {
-    __ sll(T3, T1, 1);
-    __ addu(T3, T3, SP);
-    __ lw(T3, Address(T3));
-    __ LoadTaggedClassIdMayBeSmi(T3, T3);
+  if (num_args == 2) {
+    __ lw(T5, Address(T5, -2 * kWordSize));
+    __ LoadTaggedClassIdMayBeSmi(T5, T5);
   }
 
   const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
-  __ AddImmediate(T0, entry_size);  // Next entry.
-  __ lw(T4, Address(T0));           // Next class ID.
+  // T1: argument_count (smi).
+  // T3: receiver's class ID (smi).
+  // T5: first argument's class ID (smi).
 
-  __ Bind(&test);
-  __ BranchNotEqual(T4, Immediate(Smi::RawValue(kIllegalCid)), &loop);  // Done?
+  // We unroll the generic one that is generated once more than the others.
+  const bool optimize = kind == Token::kILLEGAL;
 
+  __ Comment("ICData loop");
+  __ Bind(&loop);
+  for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
+    __ lw(T4, Address(T0, 0));
+    if (num_args == 1) {
+      __ beq(T3, T4, &found);  // IC hit.
+    } else {
+      ASSERT(num_args == 2);
+      Label update;
+      __ bne(T3, T4, &update);  // Continue.
+      __ lw(T4, Address(T0, kWordSize));
+      __ beq(T5, T4, &found);  // IC hit.
+      __ Bind(&update);
+    }
+
+    __ AddImmediate(T0, entry_size);  // Next entry.
+    if (unroll == 0) {
+      __ BranchNotEqual(T4, Immediate(Smi::RawValue(kIllegalCid)),
+                        &loop);  // Done?
+    } else {
+      __ BranchEqual(T4, Immediate(Smi::RawValue(kIllegalCid)),
+                     &miss);  // Done?
+    }
+  }
+
+  __ Bind(&miss);
   __ Comment("IC miss");
   // Restore return address.
   __ mov(RA, T2);
 
   // Compute address of arguments (first read number of arguments from
   // arguments descriptor array and then compute address on the stack).
-  // T1: argument_count - 1 (smi).
+  // T1: argument_count (smi).
+  __ addiu(T1, T1, Immediate(Smi::RawValue(-1)));
   __ sll(T1, T1, 1);  // T1 is Smi.
   __ addu(T1, SP, T1);
   // T1: address of receiver.
@@ -1584,6 +1572,7 @@
   }
 
   __ Bind(&found);
+  __ mov(RA, T2);  // Restore return address if found.
   __ Comment("Update caller's counter");
   // T0: Pointer to an IC data check group.
   const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
@@ -1591,12 +1580,9 @@
   __ lw(T3, Address(T0, target_offset));
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Update counter.
+    // Update counter, ignore overflow.
     __ lw(T4, Address(T0, count_offset));
-    __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6);
-    __ slt(CMPRES1, T5, ZR);  // T5 is < 0 if there was overflow.
-    __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue));
-    __ movz(T4, T7, CMPRES1);
+    __ AddImmediate(T4, T4, Smi::RawValue(1));
     __ sw(T4, Address(T0, count_offset));
   }
 
@@ -1729,12 +1715,9 @@
   const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Increment count for this call.
+    // Increment count for this call, ignore overflow.
     __ lw(T4, Address(T0, count_offset));
-    __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6);
-    __ slt(CMPRES1, T5, ZR);  // T5 is < 0 if there was overflow.
-    __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue));
-    __ movz(T4, T7, CMPRES1);
+    __ AddImmediate(T4, T4, Smi::RawValue(1));
     __ sw(T4, Address(T0, count_offset));
   }
 
@@ -2425,6 +2408,11 @@
   __ break_(0);
 }
 
+
+void StubCode::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
+  __ break_(0);
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index b3b18da..a2f123e 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -1308,12 +1308,8 @@
 
   if (FLAG_optimization_counter_threshold >= 0) {
     const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
-    // Update counter.
-    __ movq(R8, Address(R13, count_offset));
-    __ addq(R8, Immediate(Smi::RawValue(1)));
-    __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
-    __ cmovnoq(R9, R8);
-    __ StoreIntoSmiField(Address(R13, count_offset), R9);
+    // Update counter, ignore overflow.
+    __ addq(Address(R13, count_offset), Immediate(Smi::RawValue(1)));
   }
 
   __ ret();
@@ -1336,7 +1332,7 @@
     const RuntimeEntry& handle_ic_miss,
     Token::Kind kind,
     bool optimized) {
-  ASSERT(num_args > 0);
+  ASSERT(num_args == 1 || num_args == 2);
 #if defined(DEBUG)
   {
     Label ok;
@@ -1371,58 +1367,61 @@
   // Load arguments descriptor into R10.
   __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
   // Loop that checks if there is an IC data match.
-  Label loop, update, test, found;
+  Label loop, found, miss;
   // RBX: IC data object (preserved).
   __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
   // R13: ic_data_array with check entries: classes and target functions.
   __ leaq(R13, FieldAddress(R13, Array::data_offset()));
   // R13: points directly to the first ic data array element.
 
-  // Get the receiver's class ID (first read number of arguments from
-  // arguments descriptor array and then access the receiver from the stack).
-  __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
-  __ movq(R9, Address(RSP, RAX, TIMES_4, 0));  // RAX (argument count) is Smi.
+  // Get argument descriptor into RCX.
+  __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
+  // Load first argument into R9.
+  __ movq(R9, Address(RSP, RCX, TIMES_4, 0));
   __ LoadTaggedClassIdMayBeSmi(RAX, R9);
-  // RAX: receiver's class ID as smi.
-  __ movq(R9, Address(R13, 0));  // First class ID (Smi) to check.
-  __ jmp(&test);
+  // RAX: first argument class ID as Smi.
+  if (num_args == 2) {
+    // Load second argument into R9.
+    __ movq(R9, Address(RSP, RCX, TIMES_4, -kWordSize));
+    __ LoadTaggedClassIdMayBeSmi(RCX, R9);
+    // RCX: second argument class ID (smi).
+  }
 
   __ Comment("ICData loop");
+
+  // We unroll the generic one that is generated once more than the others.
+  const bool optimize = kind == Token::kILLEGAL;
+  const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
+  const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
+
   __ Bind(&loop);
-  for (int i = 0; i < num_args; i++) {
-    if (i > 0) {
-      // If not the first, load the next argument's class ID.
-      __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
-      __ movq(R9, Address(RSP, RAX, TIMES_4, -i * kWordSize));
-      __ LoadTaggedClassIdMayBeSmi(RAX, R9);
-      // RAX: next argument class ID (smi).
-      __ movq(R9, Address(R13, i * kWordSize));
-      // R9: next class ID to check (smi).
-    }
+  for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
+    Label update;
+    __ movq(R9, Address(R13, 0));
     __ cmpq(RAX, R9);  // Class id match?
-    if (i < (num_args - 1)) {
+    if (num_args == 2) {
       __ j(NOT_EQUAL, &update);  // Continue.
+      __ movq(R9, Address(R13, kWordSize));
+      // R9: next class ID to check (smi).
+      __ cmpq(RCX, R9);  // Class id match?
+    }
+    __ j(EQUAL, &found);  // Break.
+
+    __ Bind(&update);
+
+    const intptr_t entry_size =
+        ICData::TestEntryLengthFor(num_args) * kWordSize;
+    __ addq(R13, Immediate(entry_size));  // Next entry.
+
+    __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid)));  // Done?
+    if (unroll == 0) {
+      __ j(NOT_EQUAL, &loop);
     } else {
-      // Last check, all checks before matched.
-      __ j(EQUAL, &found);  // Break.
+      __ j(EQUAL, &miss);
     }
   }
-  __ Bind(&update);
-  // Reload receiver class ID.  It has not been destroyed when num_args == 1.
-  if (num_args > 1) {
-    __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
-    __ movq(R9, Address(RSP, RAX, TIMES_4, 0));
-    __ LoadTaggedClassIdMayBeSmi(RAX, R9);
-  }
 
-  const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
-  __ addq(R13, Immediate(entry_size));  // Next entry.
-  __ movq(R9, Address(R13, 0));         // Next class ID.
-
-  __ Bind(&test);
-  __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid)));  // Done?
-  __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
-
+  __ Bind(&miss);
   __ Comment("IC miss");
   // Compute address of arguments (first read number of arguments from
   // arguments descriptor array and then compute address on the stack).
@@ -1457,24 +1456,17 @@
 
   __ Bind(&found);
   // R13: Pointer to an IC data check group.
-  const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
-  const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
   __ movq(RAX, Address(R13, target_offset));
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Update counter.
     __ Comment("Update caller's counter");
-    __ movq(R8, Address(R13, count_offset));
-    __ addq(R8, Immediate(Smi::RawValue(1)));
-    __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
-    __ cmovnoq(R9, R8);
-    __ StoreIntoSmiField(Address(R13, count_offset), R9);
+    // Ignore overflow.
+    __ addq(Address(R13, count_offset), Immediate(Smi::RawValue(1)));
   }
 
   __ Comment("Call target");
   __ Bind(&call_target_function);
   // RAX: Target function.
-  Label is_compiled;
   __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
   __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
   __ jmp(RCX);
@@ -1611,12 +1603,8 @@
   const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
 
   if (FLAG_optimization_counter_threshold >= 0) {
-    // Increment count for this call.
-    __ movq(R8, Address(R12, count_offset));
-    __ addq(R8, Immediate(Smi::RawValue(1)));
-    __ movq(R13, Immediate(Smi::RawValue(Smi::kMaxValue)));
-    __ cmovnoq(R13, R8);
-    __ StoreIntoSmiField(Address(R12, count_offset), R13);
+    // Increment count for this call, ignore overflow.
+    __ addq(Address(R12, count_offset), Immediate(Smi::RawValue(1)));
   }
 
   // Load arguments descriptor into R10.
@@ -2280,6 +2268,11 @@
   __ int3();
 }
 
+
+void StubCode::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
+  __ int3();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_X64
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index cbc0bf2..828a7de 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -118,9 +118,13 @@
   V(AsyncOperationErrorParam, ":async_error_param")                            \
   V(AsyncOperationStackTraceParam, ":async_stack_trace_param")                 \
   V(AsyncSavedTryCtxVarPrefix, ":async_saved_try_ctx_var_")                    \
+  V(AsyncStackTraceVar, ":async_stack_trace")                                  \
+  V(ClearAsyncThreadStackTrace, "_clearAsyncThreadStackTrace")                 \
+  V(SetAsyncThreadStackTrace, "_setAsyncThreadStackTrace")                     \
   V(AsyncCatchHelper, "_asyncCatchHelper")                                     \
   V(AsyncThenWrapperHelper, "_asyncThenWrapperHelper")                         \
   V(AsyncErrorWrapperHelper, "_asyncErrorWrapperHelper")                       \
+  V(AsyncStackTraceHelper, "_asyncStackTraceHelper")                           \
   V(AsyncAwaitHelper, "_awaitHelper")                                          \
   V(Await, "await")                                                            \
   V(AwaitTempVarPrefix, ":await_temp_var_")                                    \
@@ -386,6 +390,7 @@
   V(hashCode, "get:hashCode")                                                  \
   V(OptimizedOut, "<optimized out>")                                           \
   V(NotInitialized, "<not initialized>")                                       \
+  V(NotNamed, "<not named>")                                                   \
   V(TempParam, ":temp_param")                                                  \
   V(_UserTag, "_UserTag")                                                      \
   V(Default, "Default")                                                        \
@@ -423,7 +428,8 @@
   V(_classRangeCheck, "_classRangeCheck")                                      \
   V(_classRangeCheckNegative, "_classRangeCheckNegative")                      \
   V(GetRuntimeType, "get:runtimeType")                                         \
-  V(HaveSameRuntimeType, "_haveSameRuntimeType")
+  V(HaveSameRuntimeType, "_haveSameRuntimeType")                               \
+  V(DartDeveloperCausalAsyncStacks, "dart.developer.causal_async_stacks")
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 3ff121d..dc54d6a 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -38,8 +38,6 @@
     delete compiler_stats_;
     compiler_stats_ = NULL;
   }
-  // All zone allocated memory should be free by this point.
-  ASSERT(current_thread_memory_ == 0);
   // There should be no top api scopes at this point.
   ASSERT(api_top_scope() == NULL);
   // Delete the resusable api scope if there is one.
@@ -72,6 +70,7 @@
       store_buffer_block_(NULL),
       vm_tag_(0),
       task_kind_(kUnknownTask),
+      async_stack_trace_(StackTrace::null()),
       dart_stream_(NULL),
       os_thread_(NULL),
       thread_lock_(new Monitor()),
@@ -135,6 +134,19 @@
       compiler_stats_->EnableBenchmark();
     }
   }
+  // This thread should not yet own any zones. If it does, we need to make sure
+  // we've accounted for any memory it has already allocated.
+  if (zone_ == NULL) {
+    ASSERT(current_thread_memory_ == 0);
+  } else {
+    Zone* current = zone_;
+    uintptr_t total_zone_capacity = 0;
+    while (current != NULL) {
+      total_zone_capacity += static_cast<uintptr_t>(current->CapacityInBytes());
+      current = current->previous();
+    }
+    ASSERT(current_thread_memory_ == total_zone_capacity);
+  }
 }
 
 
@@ -292,6 +304,27 @@
 }
 
 
+RawStackTrace* Thread::async_stack_trace() const {
+  return async_stack_trace_;
+}
+
+
+void Thread::set_async_stack_trace(const StackTrace& stack_trace) {
+  ASSERT(!stack_trace.IsNull());
+  async_stack_trace_ = stack_trace.raw();
+}
+
+
+void Thread::set_raw_async_stack_trace(RawStackTrace* raw_stack_trace) {
+  async_stack_trace_ = raw_stack_trace;
+}
+
+
+void Thread::clear_async_stack_trace() {
+  async_stack_trace_ = StackTrace::null();
+}
+
+
 bool Thread::EnterIsolate(Isolate* isolate) {
   const bool kIsMutatorThread = true;
   Thread* thread = isolate->ScheduleThread(kIsMutatorThread);
@@ -670,6 +703,7 @@
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_exception_));
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_stacktrace_));
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
+  visitor->VisitPointer(reinterpret_cast<RawObject**>(&async_stack_trace_));
 
   // Visit the api local scope as it has all the api local handles.
   ApiLocalScope* scope = api_top_scope_;
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 76a72ad..fe245a6 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -44,10 +44,12 @@
 class RawCode;
 class RawError;
 class RawGrowableObjectArray;
+class RawStackTrace;
 class RawString;
 class RuntimeEntry;
 class Smi;
 class StackResource;
+class StackTrace;
 class String;
 class TimelineStream;
 class TypeArguments;
@@ -505,6 +507,14 @@
   void set_sticky_error(const Error& value);
   void clear_sticky_error();
 
+  RawStackTrace* async_stack_trace() const;
+  void set_async_stack_trace(const StackTrace& stack_trace);
+  void set_raw_async_stack_trace(RawStackTrace* raw_stack_trace);
+  void clear_async_stack_trace();
+  static intptr_t async_stack_trace_offset() {
+    return OFFSET_OF(Thread, async_stack_trace_);
+  }
+
   CompilerStats* compiler_stats() { return compiler_stats_; }
 
 #if defined(DEBUG)
@@ -673,7 +683,12 @@
   template <class T>
   T* AllocateReusableHandle();
 
-  // Accessed from generated code:
+  // Accessed from generated code.
+  // ** This block of fields must come first! **
+  // For AOT cross-compilation, we rely on these members having the same offsets
+  // in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64.
+  // We use only word-sized fields to avoid differences in struct packing on the
+  // different architectures. See also CheckOffsets in dart.cc.
   uword stack_limit_;
   uword stack_overflow_flags_;
   Isolate* isolate_;
@@ -682,6 +697,7 @@
   StoreBufferBlock* store_buffer_block_;
   uword vm_tag_;
   TaskKind task_kind_;
+  RawStackTrace* async_stack_trace_;
 // State that is cached in the TLS for fast access in generated code.
 #define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value)      \
   type_name member_name;
diff --git a/runtime/vm/thread_barrier_test.cc b/runtime/vm/thread_barrier_test.cc
index 9fcdc1c..d907df1 100644
--- a/runtime/vm/thread_barrier_test.cc
+++ b/runtime/vm/thread_barrier_test.cc
@@ -37,7 +37,7 @@
 };
 
 
-UNIT_TEST_CASE(ThreadBarrier) {
+VM_UNIT_TEST_CASE(ThreadBarrier) {
   static const intptr_t kNumTasks = 5;
   static const intptr_t kNumRounds = 500;
 
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 0ad9ead..0372f68 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -70,8 +70,17 @@
 
 void ThreadInterrupter::Startup() {
   ASSERT(initialized_);
+  if (IsDebuggerAttached()) {
+    MonitorLocker shutdown_ml(monitor_);
+    shutdown_ = true;
+    if (FLAG_trace_thread_interrupter) {
+      OS::PrintErr(
+          "ThreadInterrupter disabled because a debugger is attached.\n");
+    }
+    return;
+  }
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter starting up.\n");
+    OS::PrintErr("ThreadInterrupter starting up.\n");
   }
   ASSERT(interrupter_thread_id_ == OSThread::kInvalidThreadJoinId);
   {
@@ -83,7 +92,7 @@
   }
   ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadJoinId);
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter running.\n");
+    OS::PrintErr("ThreadInterrupter running.\n");
   }
 }
 
@@ -100,7 +109,7 @@
     shutdown_ml.Notify();
     ASSERT(initialized_);
     if (FLAG_trace_thread_interrupter) {
-      OS::Print("ThreadInterrupter shutting down.\n");
+      OS::PrintErr("ThreadInterrupter shutting down.\n");
     }
   }
 
@@ -110,7 +119,7 @@
   interrupter_thread_id_ = OSThread::kInvalidThreadJoinId;
 
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter shut down.\n");
+    OS::PrintErr("ThreadInterrupter shut down.\n");
   }
 }
 
@@ -149,7 +158,7 @@
   ASSERT(initialized_);
   InstallSignalHandler();
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter thread running.\n");
+    OS::PrintErr("ThreadInterrupter thread running.\n");
   }
   {
     // Signal to main thread we are ready.
@@ -215,7 +224,7 @@
   }
   RemoveSignalHandler();
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter thread exiting.\n");
+    OS::PrintErr("ThreadInterrupter thread exiting.\n");
   }
   {
     // Signal to main thread we are exiting.
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
index c425c39..a2e54ad 100644
--- a/runtime/vm/thread_interrupter.h
+++ b/runtime/vm/thread_interrupter.h
@@ -48,6 +48,8 @@
   static intptr_t interrupt_period_;
   static intptr_t current_wait_time_;
 
+  static bool IsDebuggerAttached();
+
   static bool InDeepSleep() {
     return current_wait_time_ == Monitor::kNoTimeout;
   }
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
index 30bd440..af066c3 100644
--- a/runtime/vm/thread_interrupter_android.cc
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -47,10 +47,15 @@
 };
 
 
+bool ThreadInterrupter::IsDebuggerAttached() {
+  return false;
+}
+
+
 void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter interrupting %p\n",
-              reinterpret_cast<void*>(thread->id()));
+    OS::PrintErr("ThreadInterrupter interrupting %p\n",
+                 reinterpret_cast<void*>(thread->id()));
   }
   int result = syscall(__NR_tgkill, getpid(), thread->id(), SIGPROF);
   ASSERT((result == 0) || (result == ESRCH));
diff --git a/runtime/vm/thread_interrupter_fuchsia.cc b/runtime/vm/thread_interrupter_fuchsia.cc
index d089211..23fb826 100644
--- a/runtime/vm/thread_interrupter_fuchsia.cc
+++ b/runtime/vm/thread_interrupter_fuchsia.cc
@@ -11,6 +11,10 @@
 
 namespace dart {
 
+bool ThreadInterrupter::IsDebuggerAttached() {
+  return false;
+}
+
 void ThreadInterrupter::InterruptThread(OSThread* thread) {
   UNIMPLEMENTED();
 }
diff --git a/runtime/vm/thread_interrupter_linux.cc b/runtime/vm/thread_interrupter_linux.cc
index 167581e..6c4fdb2 100644
--- a/runtime/vm/thread_interrupter_linux.cc
+++ b/runtime/vm/thread_interrupter_linux.cc
@@ -44,10 +44,15 @@
 };
 
 
+bool ThreadInterrupter::IsDebuggerAttached() {
+  return false;
+}
+
+
 void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter interrupting %p\n",
-              reinterpret_cast<void*>(thread->id()));
+    OS::PrintErr("ThreadInterrupter interrupting %p\n",
+                 reinterpret_cast<void*>(thread->id()));
   }
   int result = pthread_kill(thread->id(), SIGPROF);
   ASSERT((result == 0) || (result == ESRCH));
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
index fb9e145..e37580d 100644
--- a/runtime/vm/thread_interrupter_macos.cc
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -6,6 +6,11 @@
 #if defined(TARGET_OS_MACOS)
 
 #include <errno.h>  // NOLINT
+#include <assert.h>      // NOLINT
+#include <stdbool.h>     // NOLINT
+#include <sys/types.h>   // NOLINT
+#include <unistd.h>      // NOLINT
+#include <sys/sysctl.h>  // NOLINT
 
 #include "vm/flags.h"
 #include "vm/os.h"
@@ -20,6 +25,27 @@
 DECLARE_FLAG(bool, thread_interrupter);
 DECLARE_FLAG(bool, trace_thread_interrupter);
 
+// Returns true if the current process is being debugged (either
+// running under the debugger or has a debugger attached post facto).
+// Code from https://developer.apple.com/library/content/qa/qa1361/_index.html
+bool ThreadInterrupter::IsDebuggerAttached() {
+  struct kinfo_proc info;
+  // Initialize the flags so that, if sysctl fails for some bizarre
+  // reason, we get a predictable result.
+  info.kp_proc.p_flag = 0;
+  // Initialize mib, which tells sysctl the info we want, in this case
+  // we're looking for information about a specific process ID.
+  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
+  size_t size = sizeof(info);
+
+  // Call sysctl.
+  size = sizeof(info);
+  int junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
+  ASSERT(junk == 0);
+  // We're being debugged if the P_TRACED flag is set.
+  return ((info.kp_proc.p_flag & P_TRACED) != 0);
+}
+
 class ThreadInterrupterMacOS : public AllStatic {
  public:
   static void ThreadInterruptSignalHandler(int signal,
@@ -48,7 +74,7 @@
 
 void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter interrupting %p\n", thread->id());
+    OS::PrintErr("ThreadInterrupter interrupting %p\n", thread->id());
   }
   int result = pthread_kill(thread->id(), SIGPROF);
   ASSERT((result == 0) || (result == ESRCH));
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index bcbcc77..964a405 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -63,8 +63,8 @@
     DWORD result = SuspendThread(handle);
     if (result == kThreadError) {
       if (FLAG_trace_thread_interrupter) {
-        OS::Print("ThreadInterrupter failed to suspend thread %p\n",
-                  reinterpret_cast<void*>(os_thread->id()));
+        OS::PrintErr("ThreadInterrupter failed to suspend thread %p\n",
+                     reinterpret_cast<void*>(os_thread->id()));
       }
       CloseHandle(handle);
       return;
@@ -74,8 +74,8 @@
       // Failed to get thread registers.
       ResumeThread(handle);
       if (FLAG_trace_thread_interrupter) {
-        OS::Print("ThreadInterrupter failed to get registers for %p\n",
-                  reinterpret_cast<void*>(os_thread->id()));
+        OS::PrintErr("ThreadInterrupter failed to get registers for %p\n",
+                     reinterpret_cast<void*>(os_thread->id()));
       }
       CloseHandle(handle);
       return;
@@ -93,15 +93,20 @@
 };
 
 
+bool ThreadInterrupter::IsDebuggerAttached() {
+  return false;
+}
+
+
 void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter suspending %p\n",
-              reinterpret_cast<void*>(thread->id()));
+    OS::PrintErr("ThreadInterrupter suspending %p\n",
+                 reinterpret_cast<void*>(thread->id()));
   }
   ThreadInterrupterWin::Interrupt(thread);
   if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter resuming %p\n",
-              reinterpret_cast<void*>(thread->id()));
+    OS::PrintErr("ThreadInterrupter resuming %p\n",
+                 reinterpret_cast<void*>(thread->id()));
   }
 }
 
diff --git a/runtime/vm/thread_pool_test.cc b/runtime/vm/thread_pool_test.cc
index 23d6140..7d5e82f 100644
--- a/runtime/vm/thread_pool_test.cc
+++ b/runtime/vm/thread_pool_test.cc
@@ -12,7 +12,7 @@
 DECLARE_FLAG(int, worker_timeout_millis);
 
 
-UNIT_TEST_CASE(ThreadPool_Create) {
+VM_UNIT_TEST_CASE(ThreadPool_Create) {
   ThreadPool thread_pool;
 }
 
@@ -43,7 +43,7 @@
 };
 
 
-UNIT_TEST_CASE(ThreadPool_RunOne) {
+VM_UNIT_TEST_CASE(ThreadPool_RunOne) {
   ThreadPool thread_pool;
   Monitor sync;
   bool done = true;
@@ -64,7 +64,7 @@
 }
 
 
-UNIT_TEST_CASE(ThreadPool_RunMany) {
+VM_UNIT_TEST_CASE(ThreadPool_RunMany) {
   const int kTaskCount = 100;
   ThreadPool thread_pool;
   Monitor sync[kTaskCount];
@@ -119,7 +119,7 @@
 };
 
 
-UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
+VM_UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
   const int kTaskCount = 10;
   Monitor sync;
   int slept_count = 0;
@@ -157,7 +157,7 @@
 }
 
 
-UNIT_TEST_CASE(ThreadPool_WorkerTimeout) {
+VM_UNIT_TEST_CASE(ThreadPool_WorkerTimeout) {
   // Adjust the worker timeout so that we timeout quickly.
   int saved_timeout = FLAG_worker_timeout_millis;
   FLAG_worker_timeout_millis = 1;
@@ -230,7 +230,7 @@
 };
 
 
-UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) {
+VM_UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) {
   ThreadPool thread_pool;
   Monitor sync;
   const int kTotalTasks = 500;
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
index 32d48a4..5085642 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -105,19 +105,6 @@
 #endif
 
 
-bool ThreadRegistry::IsValidHandle(Dart_Handle handle) const {
-  MonitorLocker ml(threads_lock());
-  Thread* current = active_list_;
-  while (current != NULL) {
-    if (current->IsValidHandle(handle)) {
-      return true;
-    }
-    current = current->next_;
-  }
-  return false;
-}
-
-
 intptr_t ThreadRegistry::CountZoneHandles() const {
   MonitorLocker ml(threads_lock());
   intptr_t count = 0;
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index 878479f..12af120 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -40,7 +40,6 @@
   // Calculates the sum of the max memory usage in bytes of each thread.
   uintptr_t ThreadHighWatermarksTotalLocked() const;
 
-  bool IsValidHandle(Dart_Handle handle) const;
   intptr_t CountZoneHandles() const;
   intptr_t CountScopedHandles() const;
 
@@ -69,6 +68,8 @@
   // - Dart_RunLoop()
   // - IsolateSaver in Dart_NewNativePort
   // - Isolate spawn (function/uri) under FLAG_i_like_slow_isolate_spawn
+  // Similarly, tracking async_stack_trace requires that we always reschedule
+  // on the same thread.
   // We probably need a mechanism to return to the specific thread only
   // for these specific cases. We should also determine if the embedder
   // should allow exiting an isolate with live state in zones/handles in
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index b2b8d39..74a97fd 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -13,7 +13,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(Mutex) {
+VM_UNIT_TEST_CASE(Mutex) {
   // This unit test case needs a running isolate.
   Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data,
                      bin::core_isolate_snapshot_instructions, NULL, NULL, NULL);
@@ -35,7 +35,7 @@
 }
 
 
-UNIT_TEST_CASE(Monitor) {
+VM_UNIT_TEST_CASE(Monitor) {
   // This unit test case needs a running isolate.
   Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data,
                      bin::core_isolate_snapshot_instructions, NULL, NULL, NULL);
@@ -173,7 +173,7 @@
 };
 
 
-VM_TEST_CASE(ManyTasksWithZones) {
+ISOLATE_UNIT_TEST_CASE(ManyTasksWithZones) {
   const int kTaskCount = 100;
   Monitor sync[kTaskCount];
   bool done[kTaskCount];
@@ -554,7 +554,7 @@
 // - main thread in VM code,
 // organized by
 // - helpers.
-VM_TEST_CASE(SafepointTestVM) {
+ISOLATE_UNIT_TEST_CASE(SafepointTestVM) {
   Isolate* isolate = thread->isolate();
   Monitor monitor;
   intptr_t expected_count = 0;
@@ -575,7 +575,7 @@
 
 
 // Test case for recursive safepoint operations.
-VM_TEST_CASE(RecursiveSafepointTest1) {
+ISOLATE_UNIT_TEST_CASE(RecursiveSafepointTest1) {
   intptr_t count = 0;
   {
     SafepointOperationScope safepoint_scope(thread);
@@ -593,7 +593,7 @@
 }
 
 
-VM_TEST_CASE(ThreadIterator_Count) {
+ISOLATE_UNIT_TEST_CASE(ThreadIterator_Count) {
   intptr_t thread_count_0 = 0;
   intptr_t thread_count_1 = 0;
 
@@ -621,7 +621,7 @@
 }
 
 
-VM_TEST_CASE(ThreadIterator_FindSelf) {
+ISOLATE_UNIT_TEST_CASE(ThreadIterator_FindSelf) {
   OSThread* current = OSThread::Current();
   EXPECT(OSThread::IsThreadInList(current->id()));
 }
@@ -682,7 +682,7 @@
 // organized by
 // - main thread, and
 // - helpers.
-VM_TEST_CASE(SafepointTestVM2) {
+ISOLATE_UNIT_TEST_CASE(SafepointTestVM2) {
   Isolate* isolate = thread->isolate();
   Monitor monitor;
   intptr_t expected_count = 0;
@@ -714,7 +714,7 @@
 
 // Test recursive safepoint operation scopes with other threads trying
 // to also start a safepoint operation scope.
-VM_TEST_CASE(RecursiveSafepointTest2) {
+ISOLATE_UNIT_TEST_CASE(RecursiveSafepointTest2) {
   Isolate* isolate = thread->isolate();
   Monitor monitor;
   intptr_t expected_count = 0;
@@ -785,7 +785,7 @@
 };
 
 
-VM_TEST_CASE(HelperAllocAndGC) {
+ISOLATE_UNIT_TEST_CASE(HelperAllocAndGC) {
   Monitor done_monitor;
   bool done = false;
   Isolate* isolate = thread->isolate();
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index cec6268..6a9c5f5 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -32,7 +32,8 @@
 TestCaseBase* TestCaseBase::tail_ = NULL;
 
 
-TestCaseBase::TestCaseBase(const char* name) : next_(NULL), name_(name) {
+TestCaseBase::TestCaseBase(const char* name)
+    : raw_test_(false), next_(NULL), name_(name) {
   if (first_ == NULL) {
     first_ = this;
   } else {
@@ -42,10 +43,23 @@
 }
 
 
+void TestCaseBase::RunAllRaw() {
+  TestCaseBase* test = first_;
+  while (test != NULL) {
+    if (test->raw_test_) {
+      test->RunTest();
+    }
+    test = test->next_;
+  }
+}
+
+
 void TestCaseBase::RunAll() {
   TestCaseBase* test = first_;
   while (test != NULL) {
-    test->RunTest();
+    if (!test->raw_test_) {
+      test->RunTest();
+    }
     test = test->next_;
   }
 }
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 945fd6e..40b8ada 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -21,21 +21,29 @@
 #include "vm/simulator.h"
 #include "vm/zone.h"
 
-// The UNIT_TEST_CASE macro is used for tests that do not need any
+// The VM_UNIT_TEST_CASE macro is used for tests that do not need any
 // default isolate or zone functionality.
-#define UNIT_TEST_CASE(name)                                                   \
+#define VM_UNIT_TEST_CASE(name)                                                \
   void Dart_Test##name();                                                      \
   static const dart::TestCase kRegister##name(Dart_Test##name, #name);         \
   void Dart_Test##name()
 
-// The VM_TEST_CASE macro is used for tests that need an isolate and zone
-// in order to test its functionality. This macro is used for tests that
+// The UNIT_TEST_CASE macro is used for tests that do not require any
+// functionality provided by the VM. Tests declared using this macro will be run
+// after the VM is cleaned up.
+#define UNIT_TEST_CASE(name)                                                   \
+  void Dart_Test##name();                                                      \
+  static const dart::RawTestCase kRegister##name(Dart_Test##name, #name);      \
+  void Dart_Test##name()
+
+// The ISOLATE_UNIT_TEST_CASE macro is used for tests that need an isolate and
+// zone in order to test its functionality. This macro is used for tests that
 // are implemented using the VM code directly and do not use the Dart API
 // for calling into the VM. The safepoint execution state of threads using
 // this macro is transitioned from kThreadInNative to kThreadInVM.
-#define VM_TEST_CASE(name)                                                     \
+#define ISOLATE_UNIT_TEST_CASE(name)                                           \
   static void Dart_TestHelper##name(Thread* thread);                           \
-  UNIT_TEST_CASE(name) {                                                       \
+  VM_UNIT_TEST_CASE(name) {                                                    \
     TestIsolateScope __test_isolate__;                                         \
     Thread* __thread__ = Thread::Current();                                    \
     ASSERT(__thread__->isolate() == __test_isolate__.isolate());               \
@@ -52,7 +60,7 @@
 // execution state of threads using this macro remains kThreadNative.
 #define TEST_CASE(name)                                                        \
   static void Dart_TestHelper##name(Thread* thread);                           \
-  UNIT_TEST_CASE(name) {                                                       \
+  VM_UNIT_TEST_CASE(name) {                                                    \
     TestIsolateScope __test_isolate__;                                         \
     Thread* __thread__ = Thread::Current();                                    \
     ASSERT(__thread__->isolate() == __test_isolate__.isolate());               \
@@ -77,7 +85,7 @@
 // C++ callee-saved registers are not preserved. Arguments may be passed in.
 #define ASSEMBLER_TEST_RUN(name, test)                                         \
   static void AssemblerTestRun##name(AssemblerTest* test);                     \
-  VM_TEST_CASE(name) {                                                         \
+  ISOLATE_UNIT_TEST_CASE(name) {                                               \
     Assembler __assembler__;                                                   \
     AssemblerTest test("" #name, &__assembler__);                              \
     AssemblerTestGenerate##name(test.assembler());                             \
@@ -100,7 +108,7 @@
 // Pass the name of test and the expected results as RawObject.
 #define CODEGEN_TEST_RUN(name, expected)                                       \
   static void CodeGenTestRun##name(const Function& function);                  \
-  VM_TEST_CASE(name) {                                                         \
+  ISOLATE_UNIT_TEST_CASE(name) {                                               \
     CodeGenTest __test__("" #name);                                            \
     CodeGenTestGenerate##name(&__test__);                                      \
     __test__.Compile();                                                        \
@@ -120,7 +128,7 @@
 // and evaluate its result.
 #define CODEGEN_TEST_RAW_RUN(name, function)                                   \
   static void CodeGenTestRun##name(const Function& function);                  \
-  VM_TEST_CASE(name) {                                                         \
+  ISOLATE_UNIT_TEST_CASE(name) {                                               \
     CodeGenTest __test__("" #name);                                            \
     CodeGenTestGenerate##name(&__test__);                                      \
     __test__.Compile();                                                        \
@@ -133,7 +141,7 @@
 // The first one may reference the Function object generated by the second one.
 #define CODEGEN_TEST2_RUN(name1, name2, expected)                              \
   static void CodeGenTestRun##name1(const Function& function);                 \
-  VM_TEST_CASE(name1) {                                                        \
+  ISOLATE_UNIT_TEST_CASE(name1) {                                              \
     /* Generate code for name2 */                                              \
     CodeGenTest __test2__("" #name2);                                          \
     CodeGenTestGenerate##name2(&__test2__);                                    \
@@ -261,6 +269,10 @@
   void RunTest();
 
   static void RunAll();
+  static void RunAllRaw();
+
+ protected:
+  bool raw_test_;
 
  private:
   static TestCaseBase* first_;
@@ -323,6 +335,20 @@
 };
 
 
+class RawTestCase : TestCaseBase {
+ public:
+  typedef void(RunEntry)();
+
+  RawTestCase(RunEntry* run, const char* name) : TestCaseBase(name), run_(run) {
+    raw_test_ = true;
+  }
+  virtual void Run();
+
+ private:
+  RunEntry* const run_;
+};
+
+
 class TestIsolateScope {
  public:
   TestIsolateScope() {
diff --git a/runtime/vm/utils_test.cc b/runtime/vm/utils_test.cc
index 9d5b20e..7a90388 100644
--- a/runtime/vm/utils_test.cc
+++ b/runtime/vm/utils_test.cc
@@ -8,7 +8,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(Minimum) {
+VM_UNIT_TEST_CASE(Minimum) {
   EXPECT_EQ(0, Utils::Minimum(0, 1));
   EXPECT_EQ(0, Utils::Minimum(1, 0));
 
@@ -23,7 +23,7 @@
 }
 
 
-UNIT_TEST_CASE(Maximum) {
+VM_UNIT_TEST_CASE(Maximum) {
   EXPECT_EQ(1, Utils::Maximum(0, 1));
   EXPECT_EQ(1, Utils::Maximum(1, 0));
 
@@ -38,7 +38,7 @@
 }
 
 
-UNIT_TEST_CASE(IsPowerOfTwo) {
+VM_UNIT_TEST_CASE(IsPowerOfTwo) {
   EXPECT(!Utils::IsPowerOfTwo(0));
   EXPECT(Utils::IsPowerOfTwo(1));
   EXPECT(Utils::IsPowerOfTwo(2));
@@ -51,14 +51,14 @@
 }
 
 
-UNIT_TEST_CASE(ShiftForPowerOfTwo) {
+VM_UNIT_TEST_CASE(ShiftForPowerOfTwo) {
   EXPECT_EQ(1, Utils::ShiftForPowerOfTwo(2));
   EXPECT_EQ(2, Utils::ShiftForPowerOfTwo(4));
   EXPECT_EQ(8, Utils::ShiftForPowerOfTwo(256));
 }
 
 
-UNIT_TEST_CASE(IsAligned) {
+VM_UNIT_TEST_CASE(IsAligned) {
   EXPECT(Utils::IsAligned(0, 1));
   EXPECT(Utils::IsAligned(1, 1));
 
@@ -72,7 +72,7 @@
 }
 
 
-UNIT_TEST_CASE(RoundDown) {
+VM_UNIT_TEST_CASE(RoundDown) {
   EXPECT_EQ(0, Utils::RoundDown(22, 32));
   EXPECT_EQ(32, Utils::RoundDown(33, 32));
   EXPECT_EQ(32, Utils::RoundDown(63, 32));
@@ -82,7 +82,7 @@
 }
 
 
-UNIT_TEST_CASE(RoundUp) {
+VM_UNIT_TEST_CASE(RoundUp) {
   EXPECT_EQ(32, Utils::RoundUp(22, 32));
   EXPECT_EQ(64, Utils::RoundUp(33, 32));
   EXPECT_EQ(64, Utils::RoundUp(63, 32));
@@ -92,7 +92,7 @@
 }
 
 
-UNIT_TEST_CASE(RoundUpToPowerOfTwo) {
+VM_UNIT_TEST_CASE(RoundUpToPowerOfTwo) {
   EXPECT_EQ(0U, Utils::RoundUpToPowerOfTwo(0));
   EXPECT_EQ(1U, Utils::RoundUpToPowerOfTwo(1));
   EXPECT_EQ(2U, Utils::RoundUpToPowerOfTwo(2));
@@ -106,7 +106,7 @@
 }
 
 
-UNIT_TEST_CASE(CountOneBits) {
+VM_UNIT_TEST_CASE(CountOneBits) {
   EXPECT_EQ(0, Utils::CountOneBits(0));
   EXPECT_EQ(1, Utils::CountOneBits(0x00000010));
   EXPECT_EQ(1, Utils::CountOneBits(0x00010000));
@@ -117,7 +117,7 @@
 }
 
 
-UNIT_TEST_CASE(CountZeros) {
+VM_UNIT_TEST_CASE(CountZeros) {
   EXPECT_EQ(0, Utils::CountTrailingZeros(0x1));
   EXPECT_EQ(kBitsPerWord - 1, Utils::CountLeadingZeros(0x1));
   EXPECT_EQ(1, Utils::CountTrailingZeros(0x2));
@@ -134,7 +134,7 @@
 }
 
 
-UNIT_TEST_CASE(IsInt) {
+VM_UNIT_TEST_CASE(IsInt) {
   EXPECT(Utils::IsInt(8, 16));
   EXPECT(Utils::IsInt(8, 127));
   EXPECT(Utils::IsInt(8, -128));
@@ -150,7 +150,7 @@
 }
 
 
-UNIT_TEST_CASE(IsUint) {
+VM_UNIT_TEST_CASE(IsUint) {
   EXPECT(Utils::IsUint(8, 16));
   EXPECT(Utils::IsUint(8, 0));
   EXPECT(Utils::IsUint(8, 255));
@@ -166,7 +166,7 @@
 }
 
 
-UNIT_TEST_CASE(IsAbsoluteUint) {
+VM_UNIT_TEST_CASE(IsAbsoluteUint) {
   EXPECT(Utils::IsAbsoluteUint(8, 16));
   EXPECT(Utils::IsAbsoluteUint(8, 0));
   EXPECT(Utils::IsAbsoluteUint(8, -128));
@@ -185,7 +185,7 @@
 }
 
 
-UNIT_TEST_CASE(LowBits) {
+VM_UNIT_TEST_CASE(LowBits) {
   EXPECT_EQ(0xff00, Utils::Low16Bits(0xffff00));
   EXPECT_EQ(0xff, Utils::High16Bits(0xffff00));
   EXPECT_EQ(0xff00, Utils::Low32Bits(0xff0000ff00LL));
@@ -194,7 +194,7 @@
 }
 
 
-UNIT_TEST_CASE(Endianity) {
+VM_UNIT_TEST_CASE(Endianity) {
   uint16_t value16be = Utils::HostToBigEndian16(0xf1);
   EXPECT_EQ(0x0, reinterpret_cast<uint8_t*>(&value16be)[0]);
   EXPECT_EQ(0xf1, reinterpret_cast<uint8_t*>(&value16be)[1]);
@@ -237,7 +237,7 @@
 }
 
 
-UNIT_TEST_CASE(DoublesBitEqual) {
+VM_UNIT_TEST_CASE(DoublesBitEqual) {
   EXPECT(Utils::DoublesBitEqual(1.0, 1.0));
   EXPECT(!Utils::DoublesBitEqual(1.0, -1.0));
   EXPECT(Utils::DoublesBitEqual(0.0, 0.0));
diff --git a/runtime/vm/verified_memory_test.cc b/runtime/vm/verified_memory_test.cc
index 21978e7..4ba1bdf 100644
--- a/runtime/vm/verified_memory_test.cc
+++ b/runtime/vm/verified_memory_test.cc
@@ -24,7 +24,7 @@
 }
 
 
-UNIT_TEST_CASE(VerifiedMemoryReserve) {
+VM_UNIT_TEST_CASE(VerifiedMemoryReserve) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
@@ -34,7 +34,7 @@
 }
 
 
-UNIT_TEST_CASE(VerifiedMemoryCommit) {
+VM_UNIT_TEST_CASE(VerifiedMemoryCommit) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
@@ -45,7 +45,7 @@
 }
 
 
-UNIT_TEST_CASE(VerifiedMemoryBasic) {
+VM_UNIT_TEST_CASE(VerifiedMemoryBasic) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
@@ -68,7 +68,7 @@
 }
 
 
-UNIT_TEST_CASE(VerifiedMemoryAccept) {
+VM_UNIT_TEST_CASE(VerifiedMemoryAccept) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
@@ -90,7 +90,7 @@
 
 // Negative tests below.
 
-UNIT_TEST_CASE(VerifyImplicit_Crash) {
+VM_UNIT_TEST_CASE(VerifyImplicit_Crash) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
@@ -103,7 +103,7 @@
 }
 
 
-UNIT_TEST_CASE(VerifyExplicit_Crash) {
+VM_UNIT_TEST_CASE(VerifyExplicit_Crash) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
diff --git a/runtime/vm/virtual_memory_test.cc b/runtime/vm/virtual_memory_test.cc
index cc98c03..c652f8c 100644
--- a/runtime/vm/virtual_memory_test.cc
+++ b/runtime/vm/virtual_memory_test.cc
@@ -18,7 +18,7 @@
 }
 
 
-UNIT_TEST_CASE(AllocateVirtualMemory) {
+VM_UNIT_TEST_CASE(AllocateVirtualMemory) {
   const intptr_t kVirtualMemoryBlockSize = 64 * KB;
   VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
   EXPECT(vm != NULL);
@@ -52,7 +52,7 @@
 }
 
 
-UNIT_TEST_CASE(FreeVirtualMemory) {
+VM_UNIT_TEST_CASE(FreeVirtualMemory) {
   // Reservations should always be handed back to OS upon destruction.
   const intptr_t kVirtualMemoryBlockSize = 10 * MB;
   const intptr_t kIterations = 900;  // Enough to exhaust 32-bit address space.
@@ -89,7 +89,7 @@
 }
 
 
-UNIT_TEST_CASE(VirtualMemoryCommitPartial) {
+VM_UNIT_TEST_CASE(VirtualMemoryCommitPartial) {
   const intptr_t kVirtualMemoryBlockSize = 3 * MB;
   VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
   EXPECT(vm != NULL);
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 1371285..a8c0e74 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -61,13 +61,6 @@
             ],
           },
         }],
-        # The following condition should be kept in sync with the corresponding
-        # configurations in runtime/bin/bin.gypi.
-	['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', {
-          'defines': [
-            'DART_USE_TCMALLOC'
-          ],
-        }],
         ['OS=="android" and _toolset=="host"', {
           'link_settings': {
             'libraries': [
@@ -112,13 +105,6 @@
             ],
           },
         }],
-        # The following condition should be kept in sync with the corresponding
-        # configurations in runtime/bin/bin.gypi.
-        ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', {
-          'defines': [
-            'DART_USE_TCMALLOC'
-          ],
-        }],
         ['OS=="android" and _toolset=="host"', {
           'link_settings': {
             'libraries': [
@@ -163,13 +149,6 @@
             ],
           },
         }],
-        # The following condition should be kept in sync with the corresponding
-        # configurations in runtime/bin/bin.gypi.
-        ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', {
-          'defines': [
-            'DART_USE_TCMALLOC'
-          ],
-        }],
         ['OS=="android" and _toolset=="host"', {
           'link_settings': {
             'libraries': [
@@ -215,13 +194,6 @@
             ],
           },
         }],
-        # The following condition should be kept in sync with the corresponding
-        # configurations in runtime/bin/bin.gypi.
-        ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', {
-          'defines': [
-            'DART_USE_TCMALLOC'
-          ],
-        }],
         ['OS=="android" and _toolset=="host"', {
           'link_settings': {
             'libraries': [
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index e75af23..9cf44b5 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -176,6 +176,8 @@
     'exceptions.h',
     'exceptions_test.cc',
     'find_code_object_test.cc',
+    'fixed_cache.h',
+    'fixed_cache_test.cc',
     'flag_list.h',
     'flags.cc',
     'flags.h',
@@ -286,8 +288,9 @@
     'longjump.h',
     'longjump_test.cc',
     'malloc_hooks.cc',
-    'malloc_hooks_unsupported.cc',
     'malloc_hooks.h',
+    'malloc_hooks_test.cc',
+    'malloc_hooks_unsupported.cc',
     'megamorphic_cache_table.cc',
     'megamorphic_cache_table.h',
     'memory_region.cc',
@@ -475,6 +478,8 @@
     'stack_frame_mips.h',
     'stack_frame_test.cc',
     'stack_frame_x64.h',
+    'stack_trace.cc',
+    'stack_trace.h',
     'store_buffer.cc',
     'store_buffer.h',
     'stub_code.cc',
@@ -554,5 +559,7 @@
     'zone.cc',
     'zone.h',
     'zone_test.cc',
+    'zone_text_buffer.cc',
+    'zone_text_buffer.h',
   ],
 }
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index b4c8e31..fc988a7 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -98,6 +98,10 @@
       handles_(),
       previous_(NULL) {
   ASSERT(Utils::IsAligned(position_, kAlignment));
+  Thread* current = Thread::Current();
+  if (current != NULL) {
+    current->IncrementMemoryUsage(kInitialChunkSize);
+  }
 #ifdef DEBUG
   // Zap the entire initial buffer.
   memset(initial_buffer_.pointer(), kZapUninitializedByte,
@@ -110,6 +114,10 @@
   if (FLAG_trace_zones) {
     DumpZoneSizes();
   }
+  Thread* current = Thread::Current();
+  if (current != NULL) {
+    current->DecrementMemoryUsage(kInitialChunkSize);
+  }
   DeleteAll();
 }
 
diff --git a/runtime/vm/zone_test.cc b/runtime/vm/zone_test.cc
index 21b50c0..d491e1f 100644
--- a/runtime/vm/zone_test.cc
+++ b/runtime/vm/zone_test.cc
@@ -10,7 +10,7 @@
 
 namespace dart {
 
-UNIT_TEST_CASE(AllocateZone) {
+VM_UNIT_TEST_CASE(AllocateZone) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;
 #endif
@@ -72,7 +72,7 @@
 }
 
 
-UNIT_TEST_CASE(AllocGeneric_Success) {
+VM_UNIT_TEST_CASE(AllocGeneric_Success) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;
 #endif
@@ -96,7 +96,7 @@
 
 
 // This test is expected to crash.
-UNIT_TEST_CASE(AllocGeneric_Overflow) {
+VM_UNIT_TEST_CASE(AllocGeneric_Overflow) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;
 #endif
@@ -115,7 +115,7 @@
 }
 
 
-UNIT_TEST_CASE(ZoneAllocated) {
+VM_UNIT_TEST_CASE(ZoneAllocated) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;
 #endif
@@ -171,7 +171,7 @@
 
 
 #ifndef PRODUCT
-UNIT_TEST_CASE(PrintZoneMemoryInfoToJSON) {
+VM_UNIT_TEST_CASE(PrintZoneMemoryInfoToJSON) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;
 #endif
@@ -229,7 +229,7 @@
 #endif
 
 
-UNIT_TEST_CASE(NativeScopeZoneAllocation) {
+VM_UNIT_TEST_CASE(NativeScopeZoneAllocation) {
   ASSERT(ApiNativeScope::Current() == NULL);
   ASSERT(Thread::Current() == NULL);
   EXPECT_EQ(0, ApiNativeScope::current_memory_usage());
diff --git a/runtime/vm/zone_text_buffer.cc b/runtime/vm/zone_text_buffer.cc
new file mode 100644
index 0000000..1729403
--- /dev/null
+++ b/runtime/vm/zone_text_buffer.cc
@@ -0,0 +1,66 @@
+// 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.
+
+#include "vm/zone_text_buffer.h"
+
+#include "platform/assert.h"
+#include "platform/globals.h"
+#include "platform/utils.h"
+#include "vm/os.h"
+#include "vm/zone.h"
+
+namespace dart {
+
+ZoneTextBuffer::ZoneTextBuffer(Zone* zone, intptr_t initial_capacity)
+    : zone_(zone), buffer_(NULL), length_(0), capacity_(0) {
+  ASSERT(initial_capacity > 0);
+  buffer_ = reinterpret_cast<char*>(zone->Alloc<char>(initial_capacity));
+  capacity_ = initial_capacity;
+  buffer_[length_] = '\0';
+}
+
+
+intptr_t ZoneTextBuffer::Printf(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  intptr_t remaining = capacity_ - length_;
+  ASSERT(remaining >= 0);
+  intptr_t len = OS::VSNPrint(buffer_ + length_, remaining, format, args);
+  va_end(args);
+  if (len >= remaining) {
+    EnsureCapacity(len);
+    remaining = capacity_ - length_;
+    ASSERT(remaining > len);
+    va_list args2;
+    va_start(args2, format);
+    intptr_t len2 = OS::VSNPrint(buffer_ + length_, remaining, format, args2);
+    va_end(args2);
+    ASSERT(len == len2);
+  }
+  length_ += len;
+  buffer_[length_] = '\0';
+  return len;
+}
+
+
+void ZoneTextBuffer::AddString(const char* s) {
+  Printf("%s", s);
+}
+
+
+void ZoneTextBuffer::EnsureCapacity(intptr_t len) {
+  intptr_t remaining = capacity_ - length_;
+  if (remaining <= len) {
+    const int kBufferSpareCapacity = 64;  // Somewhat arbitrary.
+    // TODO(turnidge): do we need to guard against overflow or other
+    // security issues here? Text buffers are used by the debugger
+    // to send user-controlled data (e.g. values of string variables) to
+    // the debugger front-end.
+    intptr_t new_capacity = capacity_ + len + kBufferSpareCapacity;
+    buffer_ = zone_->Realloc<char>(buffer_, capacity_, new_capacity);
+    capacity_ = new_capacity;
+  }
+}
+
+}  // namespace dart
diff --git a/runtime/vm/zone_text_buffer.h b/runtime/vm/zone_text_buffer.h
new file mode 100644
index 0000000..8d6ae11
--- /dev/null
+++ b/runtime/vm/zone_text_buffer.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef RUNTIME_VM_ZONE_TEXT_BUFFER_H_
+#define RUNTIME_VM_ZONE_TEXT_BUFFER_H_
+
+#include "vm/allocation.h"
+#include "vm/globals.h"
+
+namespace dart {
+
+class Zone;
+
+// TextBuffer maintains a dynamic character buffer with a printf-style way to
+// append text.
+class ZoneTextBuffer : ValueObject {
+ public:
+  ZoneTextBuffer(Zone* zone, intptr_t initial_capacity);
+  ~ZoneTextBuffer() {}
+
+  intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+  void AddString(const char* s);
+
+  char* buffer() { return buffer_; }
+  intptr_t length() { return length_; }
+
+ private:
+  void EnsureCapacity(intptr_t len);
+  Zone* zone_;
+  char* buffer_;
+  intptr_t length_;
+  intptr_t capacity_;
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_ZONE_TEXT_BUFFER_H_
diff --git a/samples/samples.status b/samples/samples.status
index caf91ca..5fabf51 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -2,6 +2,9 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
+[$runtime == vm && $compiler == none && $system == fuchsia]
+*: Skip  # Not yet triaged.
+
 [ $browser ]
 # Skip tests that uses dart:io
 build_dart: Skip
@@ -17,6 +20,9 @@
 [ $compiler == dart2analyzer ]
 build_dart: Skip
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $arch == arm ]
 sample_extension/test/*: Skip # Issue 14705
 
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index af96764..e5e76bf 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -687,17 +687,18 @@
   return resolved;
 }
 
+bool _hasErrorStackProperty = JS('bool', 'new Error().stack != void 0');
+
 @patch
 class StackTrace {
   @patch
   @NoInline()
   static StackTrace get current {
-    if (JS('', 'Error.captureStackTrace') != null) {
-      var error = JS('', 'new Error()');
-      JS('void', 'Error.captureStackTrace(#)', error);
-      return getTraceFromException(error);
+    if (_hasErrorStackProperty) {
+      return getTraceFromException(JS('', 'new Error()'));
     }
-    // Fallback if Error.captureStackTrace does not exist.
+    // Fallback if new Error().stack does not exist.
+    // Currently only required for IE 11.
     try {
       throw '';
     } catch (_, stackTrace) {
diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
index d941bb2..f79da5c 100644
--- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
@@ -135,6 +135,18 @@
     throw new UnsupportedError("File._lastModified");
   }
   @patch
+  static _lastAccessed(String path) {
+    throw new UnsupportedError("File._lastAccessed");
+  }
+  @patch
+  static _setLastModified(String path, int millis) {
+    throw new UnsupportedError("File._setLastModified");
+  }
+  @patch
+  static _setLastAccessed(String path, int millis) {
+    throw new UnsupportedError("File._setLastAccessed");
+  }
+  @patch
   static _open(String path, int mode) {
     throw new UnsupportedError("File._open");
   }
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 49b2460..5b570c6 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -418,8 +418,8 @@
    * If [f] returns a non-[Future], iteration continues immediately. Otherwise
    * it waits for the returned [Future] to complete.
    */
-  static Future forEach(Iterable input, f(element)) {
-    Iterator iterator = input.iterator;
+  static Future forEach<T>(Iterable<T> input, f(T element)) {
+    var iterator = input.iterator;
     return doWhile(() {
       if (!iterator.moveNext()) return false;
       return new Future.sync(() => f(iterator.current)).then((_) => true);
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index f484cfb..b2a7a21 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -1761,6 +1761,8 @@
  * This wraps a [Stream] and a subscription on the stream. It listens
  * on the stream, and completes the future returned by [moveNext] when the
  * next value becomes available.
+ *
+ * The stream may be paused between calls to [moveNext].
  */
 abstract class StreamIterator<T> {
 
@@ -1776,7 +1778,7 @@
    * Returns a future which will complete with either `true` or `false`.
    * Completing with `true` means that another event has been received and
    * can be read as [current].
-   * Completing with `false` means that the stream itearation is done and
+   * Completing with `false` means that the stream iteration is done and
    * no further events will ever be available.
    * The future may complete with an error, if the stream produces an error,
    * which also ends iteration.
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index e9a716f..0454491 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -133,7 +133,7 @@
    *
    * ```
    * // http://example.org/path?q=dart.
-   * new Uri.http("google.com", "/search", { "q" : "dart" });
+   * new Uri.http("example.org", "/path", { "q" : "dart" });
    *
    * // http://user:pass@localhost:8080
    * new Uri.http("user:pass@localhost:8080", "");
@@ -181,23 +181,24 @@
    * This path is interpreted using either Windows or non-Windows
    * semantics.
    *
-   * With non-Windows semantics the slash ("/") is used to separate
-   * path segments.
+   * With non-Windows semantics the slash (`/`) is used to separate
+   * path segments in the input [path].
    *
-   * With Windows semantics, backslash ("\\") and forward-slash ("/")
-   * are used to separate path segments, except if the path starts
-   * with "\\\\?\\" in which case, only backslash ("\\") separates path
-   * segments.
+   * With Windows semantics, backslash (`\`) and forward-slash (`/`)
+   * are used to separate path segments in the input [path],
+   * except if the path starts with `\\?\` in which case
+   * only backslash (`\`) separates path segments in [path].
    *
-   * If the path starts with a path separator an absolute URI is
-   * created. Otherwise a relative URI is created. One exception from
-   * this rule is that when Windows semantics is used and the path
-   * starts with a drive letter followed by a colon (":") and a
-   * path separator then an absolute URI is created.
+   * If the path starts with a path separator, an absolute URI (with the
+   * `file` scheme and an empty authority) is created.
+   * Otherwise a relative URI reference with no scheme or authority is created.
+   * One exception from this rule is that when Windows semantics is used
+   * and the path starts with a drive letter followed by a colon (":") and a
+   * path separator, then an absolute URI is created.
    *
    * The default for whether to use Windows or non-Windows semantics
    * determined from the platform Dart is running on. When running in
-   * the standalone VM this is detected by the VM based on the
+   * the standalone VM, this is detected by the VM based on the
    * operating system. When running in a browser non-Windows semantics
    * is always used.
    *
@@ -220,7 +221,7 @@
    * // file:///xxx/yyy/
    * new Uri.file("/xxx/yyy/", windows: false);
    *
-   * // C:
+   * // C%3A
    * new Uri.file("C:", windows: false);
    * ```
    *
@@ -242,7 +243,8 @@
    * // file:///C:/xxx/yyy
    * new Uri.file(r"C:\xxx\yyy", windows: true);
    *
-   * // This throws an error. A path with a drive letter is not absolute.
+   * // This throws an error. A path with a drive letter, but no following
+   * // path, is not allowed.
    * new Uri.file(r"C:", windows: true);
    *
    * // This throws an error. A path with a drive letter is not absolute.
@@ -252,7 +254,7 @@
    * new Uri.file(r"\\server\share\file", windows: true);
    * ```
    *
-   * If the path passed is not a legal file path [ArgumentError] is thrown.
+   * If the path passed is not a valid file path, an error is thrown.
    */
   factory Uri.file(String path, {bool windows}) = _Uri.file;
 
@@ -512,6 +514,21 @@
    */
   String get origin;
 
+  /// Whether the scheme of this [Uri] is [scheme].
+  ///
+  /// The [scheme] should be the same as the one returned by [Uri.scheme],
+  /// but doesn't have to be case-normalized to lower-case characters.
+  ///
+  /// Example:
+  /// ```dart
+  /// var uri = Uri.parse("http://example.com/");
+  /// print(uri.isScheme("HTTP"));  // Prints true.
+  /// ```
+  ///
+  /// A `null` or empty [scheme] string matches a URI with no scheme
+  /// (one where [hasScheme] returns false).
+  bool isScheme(String scheme);
+
   /**
    * Returns the file path from a file URI.
    *
@@ -563,7 +580,7 @@
    *     Uri.parse("xxx/yyy");  // xxx\yyy
    *     Uri.parse("xxx/yyy/");  // xxx\yyy\
    *     Uri.parse("file:///xxx/yyy");  // \xxx\yyy
-   *     Uri.parse("file:///xxx/yyy/");  // \xxx\yyy/
+   *     Uri.parse("file:///xxx/yyy/");  // \xxx\yyy\
    *     Uri.parse("file:///C:/xxx/yyy");  // C:\xxx\yyy
    *     Uri.parse("file:C:xxx/yyy");  // Throws as a path segment
    *                                   // cannot contain colon on Windows.
@@ -620,10 +637,10 @@
    *
    *     Uri uri1 = Uri.parse("a://b@c:4/d/e?f#g");
    *     Uri uri2 = uri1.replace(scheme: "A", path: "D/E/E", fragment: "G");
-   *     print(uri2);  // prints "A://b@c:4/D/E/E/?f#G"
+   *     print(uri2);  // prints "a://b@c:4/D/E/E?f#G"
    *
    * This method acts similarly to using the `new Uri` constructor with
-   * some of the arguments taken from this `Uri` . Example:
+   * some of the arguments taken from this `Uri`. Example:
    *
    *     Uri uri3 = new Uri(
    *         scheme: "A",
@@ -633,7 +650,7 @@
    *         path: "D/E/E",
    *         query: uri1.query,
    *         fragment: "G");
-   *     print(uri3);  // prints "A://b@c:4/D/E/E/?f#G"
+   *     print(uri3);  // prints "a://b@c:4/D/E/E?f#G"
    *     print(uri2 == uri3);  // prints true.
    *
    * Using this method can be seen as a shorthand for the `Uri` constructor
@@ -1532,6 +1549,44 @@
 
   String get fragment => _fragment ?? "";
 
+  bool isScheme(String scheme) {
+    String thisScheme = this.scheme;
+    if (scheme == null) return thisScheme.isEmpty;
+    if (scheme.length != thisScheme.length) return false;
+    return _compareScheme(scheme, thisScheme);
+  }
+
+  /// Compares scheme characters in [scheme] and at the start of [uri].
+  ///
+  /// Returns `true` if [scheme] represents the same scheme as the start of
+  /// [uri]. That means having the same characters, but possibly different case
+  /// for letters.
+  ///
+  /// This function doesn't check that the characters are valid URI scheme
+  /// characters. The [uri] is assumed to be valid, so if [scheme] matches
+  /// it, it has to be valid too.
+  ///
+  /// The length should be tested before calling this function,
+  /// so the scheme part of [uri] is known to have the same length as [scheme].
+  static bool _compareScheme(String scheme, String uri) {
+    for (int i = 0; i < scheme.length; i++) {
+      int schemeChar = scheme.codeUnitAt(i);
+      int uriChar = uri.codeUnitAt(i);
+      int delta = schemeChar ^ uriChar;
+      if (delta != 0) {
+        if (delta == 0x20) {
+          // Might be a case difference.
+          int lowerChar = uriChar | delta;
+          if (0x61 /*a*/ <= lowerChar && lowerChar <= 0x7a /*z*/) {
+            continue;
+          }
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+
   // Report a parse failure.
   static void _fail(String uri, int index, String message) {
     throw new FormatException(message, uri, index);
@@ -4071,6 +4126,7 @@
   bool get _isHttp => _schemeEnd == 4 && _uri.startsWith("http");
   bool get _isHttps => _schemeEnd == 5 && _uri.startsWith("https");
   bool get _isPackage => _schemeEnd == 7 && _uri.startsWith("package");
+  /// Like [isScheme] but expects argument to be case normalized.
   bool _isScheme(String scheme) =>
     _schemeEnd == scheme.length && _uri.startsWith(scheme);
 
@@ -4079,6 +4135,12 @@
 
   bool get isAbsolute => hasScheme && !hasFragment;
 
+  bool isScheme(String scheme) {
+    if (scheme == null || scheme.isEmpty) return _schemeEnd < 0;
+    if (scheme.length != _schemeEnd) return false;
+    return _Uri._compareScheme(scheme, _uri);
+  }
+
   String get scheme {
     if (_schemeEnd <= 0) return "";
     if (_schemeCache != null) return _schemeCache;
diff --git a/sdk/lib/dart_client.platform b/sdk/lib/dart_client.platform
index 38442ef..16c91ca 100644
--- a/sdk/lib/dart_client.platform
+++ b/sdk/lib/dart_client.platform
@@ -5,7 +5,11 @@
 # The platform for running dart on the web with dart2js.
 #
 # Includes dart:html and associated libraries.
-# Does not include dart:io.
+#
+# This configuration used to exclude dart:io, but we made it OK to import it.
+# This is allowed as a stopgap measure until config-specific imports are
+# supported in the language.  The returned library is an implementation of
+# dart:io that throws at runtime.
 
 [dart-spec]
 spec: 3rd edition.
@@ -23,7 +27,7 @@
 html: html/dart2js/html_dart2js.dart
 html_common: html/html_common/html_common_dart2js.dart
 indexed_db: indexed_db/dart2js/indexed_db_dart2js.dart
-io: unsupported:
+io: unsupported:io/io.dart
 isolate: isolate/isolate.dart
 js: js/dart2js/js_dart2js.dart
 js_util: js_util/dart2js/js_util_dart2js.dart
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 112f7fb..a1e5a4c 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -4056,6 +4056,11 @@
     return style;
   }
 
+  /// Returns the value of the property if the provided *CSS* property
+  /// name is supported on this element and if the value is set. Otherwise
+  /// returns an empty string.
+  ///
+  /// Please note the property name uses camelCase, not-hyphens.
   String getPropertyValue(String propertyName) {
     var propValue = _getPropertyValueHelper(propertyName);
     return propValue != null ? propValue : '';
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index afa40c5..e4f8fe3 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -5638,6 +5638,11 @@
     return style;
   }
 
+  /// Returns the value of the property if the provided *CSS* property
+  /// name is supported on this element and if the value is set. Otherwise
+  /// returns an empty string.
+  ///
+  /// Please note the property name uses camelCase, not-hyphens.
   String getPropertyValue(String propertyName) {
     var propValue = _getPropertyValueHelper(propertyName);
     return propValue != null ? propValue : '';
@@ -37662,10 +37667,10 @@
     if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaStream)) {
+    if ((blob_OR_source_OR_stream is MediaSource)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaSource)) {
+    if ((blob_OR_source_OR_stream is MediaStream)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
     throw new ArgumentError("Incorrect number or type of arguments");
diff --git a/sdk/lib/io/bytes_builder.dart b/sdk/lib/io/bytes_builder.dart
index 2dca39d..1b61d30 100644
--- a/sdk/lib/io/bytes_builder.dart
+++ b/sdk/lib/io/bytes_builder.dart
@@ -83,24 +83,22 @@
   // Start with 1024 bytes.
   static const int _INIT_SIZE = 1024;
 
+  static final _emptyList = new Uint8List(0);
+
   int _length = 0;
   Uint8List _buffer;
 
+  _CopyingBytesBuilder([int initialCapacity = 0])
+      : _buffer = (initialCapacity <= 0)
+                      ? _emptyList
+                      : new Uint8List(_pow2roundup(initialCapacity));
+
   void add(List<int> bytes) {
     int bytesLength = bytes.length;
     if (bytesLength == 0) return;
     int required = _length + bytesLength;
-    if (_buffer == null) {
-      int size = _pow2roundup(required);
-      size = max(size, _INIT_SIZE);
-      _buffer = new Uint8List(size);
-    } else if (_buffer.length < required) {
-      // We will create a list in the range of 2-4 times larger than
-      // required.
-      int size = _pow2roundup(required) * 2;
-      var newBuffer = new Uint8List(size);
-      newBuffer.setRange(0, _buffer.length, _buffer);
-      _buffer = newBuffer;
+    if (_buffer.length < required) {
+      _grow(required);
     }
     assert(_buffer.length >= required);
     if (bytes is Uint8List) {
@@ -113,17 +111,40 @@
     _length = required;
   }
 
-  void addByte(int byte) { add([byte]); }
+  void addByte(int byte) {
+    if (_buffer.length == _length) {
+      // The grow algorithm always at least doubles.
+      // If we added one to _length it would quadruple unnecessarily.
+      _grow(_length);
+    }
+    assert(_buffer.length > _length);
+    _buffer[_length] = byte;
+    _length++;
+  }
+
+  void _grow(int required) {
+    // We will create a list in the range of 2-4 times larger than
+    // required.
+    int newSize = required * 2;
+    if (newSize < _INIT_SIZE) {
+      newSize = _INIT_SIZE;
+    } else {
+      newSize = _pow2roundup(newSize);
+    }
+    var newBuffer = new Uint8List(newSize);
+    newBuffer.setRange(0, _buffer.length, _buffer);
+    _buffer = newBuffer;
+  }
 
   List<int> takeBytes() {
-    if (_buffer == null) return new Uint8List(0);
+    if (_length == 0) return _emptyList;
     var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
     clear();
     return buffer;
   }
 
   List<int> toBytes() {
-    if (_buffer == null) return new Uint8List(0);
+    if (_length == 0) return _emptyList;
     return new Uint8List.fromList(
         new Uint8List.view(_buffer.buffer, 0, _length));
   }
@@ -136,10 +157,11 @@
 
   void clear() {
     _length = 0;
-    _buffer = null;
+    _buffer = _emptyList;
   }
 
-  int _pow2roundup(int x) {
+  static int _pow2roundup(int x) {
+    assert(x > 0);
     --x;
     x |= x >> 1;
     x |= x >> 2;
@@ -166,12 +188,15 @@
     _length += typedBytes.length;
   }
 
-  void addByte(int byte) { add([byte]); }
+  void addByte(int byte) {
+    _chunks.add(new Uint8List(1)..[0] = byte);
+    _length++;
+  }
 
   List<int> takeBytes() {
-    if (_chunks.length == 0) return new Uint8List(0);
+    if (_length == 0) return _CopyingBytesBuilder._emptyList;
     if (_chunks.length == 1) {
-      var buffer = _chunks.single;
+      var buffer = _chunks[0];
       clear();
       return buffer;
     }
@@ -186,7 +211,7 @@
   }
 
   List<int> toBytes() {
-    if (_chunks.length == 0) return new Uint8List(0);
+    if (_length == 0) return _CopyingBytesBuilder._emptyList;
     var buffer = new Uint8List(_length);
     int offset = 0;
     for (var chunk in _chunks) {
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index 6258bcf..5ef4594 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -26,7 +26,7 @@
   assert(_isErrorResponse(response));
   switch (response[_ERROR_RESPONSE_ERROR_TYPE]) {
     case _ILLEGAL_ARGUMENT_RESPONSE:
-      return new ArgumentError();
+      return new ArgumentError("$message: $path");
     case _OSERROR_RESPONSE:
       var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
                             response[_OSERROR_RESPONSE_ERROR_CODE]);
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index c1fc540..fcbeccb 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -68,10 +68,6 @@
 
   Directory get absolute => new Directory(_absolutePath);
 
-  Future<FileStat> stat() => FileStat.stat(path);
-
-  FileStat statSync() => FileStat.statSync(path);
-
   Future<Directory> create({bool recursive: false}) {
     if (recursive) {
       return exists().then((exists) {
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index cb9cdcc..6137c76 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -219,7 +219,7 @@
   factory File.fromUri(Uri uri) => new File(uri.toFilePath());
 
   /**
-   * Create the file. Returns a [:Future<File>:] that completes with
+   * Create the file. Returns a `Future<File>` that completes with
    * the file when it has been created.
    *
    * If [recursive] is false, the default, the file is created only if
@@ -288,7 +288,7 @@
   File copySync(String newPath);
 
   /**
-   * Get the length of the file. Returns a [:Future<int>:] that
+   * Get the length of the file. Returns a `Future<int>` that
    * completes with the length in bytes.
    */
   Future<int> length();
@@ -309,24 +309,79 @@
    */
   File get absolute;
 
-  /**
-   * Get the last-modified time of the file. Returns a
-   * [:Future<DateTime>:] that completes with a [DateTime] object for the
-   * modification date.
-   */
-  Future<DateTime> lastModified();
+/**
+ * Get the last-accessed time of the file.
+ *
+ * Returns the date and time when the file was last accessed, if the
+ * information is available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  Future<DateTime> lastAccessed();
+
+/**
+ * Get the last-accessed time of the file.
+ *
+ * Returns the date and time when the file was last accessed,
+ * if the information is available. Blocks until the information can be returned
+ * or it is determined that the information is not available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  DateTime lastAccessedSync();
 
   /**
-   * Get the last-modified time of the file. Throws an exception
-   * if the file does not exist.
+   * Modifies the time the file was last accessed.
    *
-   * Throws a [FileSystemException] if the operation fails.
+   * Throws a [FilsSystemException] if the time cannot be set.
    */
+  Future setLastAccessed(DateTime time);
+
+  /**
+   * Synchronously modifies the time the file was last accessed.
+   *
+   * Throws a [FilsSystemException] if the time cannot be set.
+   */
+  void setLastAccessedSync(DateTime time);
+
+/**
+ * Get the last-modified time of the file.
+ *
+ * Returns the date and time when the file was last modified, if the
+ * information is available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  Future<DateTime> lastModified();
+
+/**
+ * Get the last-modified time of the file.
+ *
+ * Returns the date and time when the file was last modified,
+ * if the information is available. Blocks until the information can be returned
+ * or it is determined that the information is not available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
   DateTime lastModifiedSync();
 
   /**
+   * Modifies the time the file was last modified.
+   *
+   * Throws a [FilsSystemException] if the time cannot be set.
+   */
+  Future setLastModified(DateTime time);
+
+  /**
+   * Synchronously modifies the time the file was last modified.
+   *
+   * If the attributes cannot be set, throws a [FileSystemException].
+   */
+  void setLastModifiedSync(DateTime time);
+
+  /**
    * Open the file for random access operations. Returns a
-   * [:Future<RandomAccessFile>:] that completes with the opened
+   * `Future<RandomAccessFile>` that completes with the opened
    * random access file. [RandomAccessFile]s must be closed using the
    * [RandomAccessFile.close] method.
    *
@@ -383,7 +438,7 @@
    *
    *  When writing strings through the returned [IOSink] the encoding
    *  specified using [encoding] will be used. The returned [IOSink]
-   *  has an [:encoding:] property which can be changed after the
+   *  has an `encoding` property which can be changed after the
    *  [IOSink] has been created.
    */
   IOSink openWrite({FileMode mode: FileMode.WRITE,
@@ -391,7 +446,7 @@
 
   /**
    * Read the entire file contents as a list of bytes. Returns a
-   * [:Future<List<int>>:] that completes with the list of bytes that
+   * `Future<List<int>>` that completes with the list of bytes that
    * is the contents of the file.
    */
   Future<List<int>> readAsBytes();
@@ -407,7 +462,7 @@
    * Read the entire file contents as a string using the given
    * [Encoding].
    *
-   * Returns a [:Future<String>:] that completes with the string once
+   * Returns a `Future<String>` that completes with the string once
    * the file contents has been read.
    */
   Future<String> readAsString({Encoding encoding: UTF8});
@@ -424,7 +479,7 @@
    * Read the entire file contents as lines of text using the given
    * [Encoding].
    *
-   * Returns a [:Future<List<String>>:] that completes with the lines
+   * Returns a `Future<List<String>>` that completes with the lines
    * once the file contents has been read.
    */
   Future<List<String>> readAsLines({Encoding encoding: UTF8});
@@ -441,7 +496,7 @@
    * Write a list of bytes to a file.
    *
    * Opens the file, writes the list of bytes to it, and closes the file.
-   * Returns a [:Future<File>:] that completes with this [File] object once
+   * Returns a `Future<File>` that completes with this [File] object once
    * the entire operation has completed.
    *
    * By default [writeAsBytes] creates the file for writing and truncates the
@@ -477,7 +532,7 @@
    * Write a string to a file.
    *
    * Opens the file, writes the string in the given encoding, and closes the
-   * file. Returns a [:Future<File>:] that completes with this [File] object
+   * file. Returns a `Future<File>` that completes with this [File] object
    * once the entire operation has completed.
    *
    * By default [writeAsString] creates the file for writing and truncates the
@@ -526,7 +581,7 @@
  * file.
  *
  * `RandomAccessFile` objects are obtained by calling the
- * [:open:] method on a [File] object.
+ * `open` method on a [File] object.
  *
  * A `RandomAccessFile` have both asynchronous and synchronous
  * methods. The asynchronous methods all return a `Future`
@@ -542,7 +597,7 @@
  */
 abstract class RandomAccessFile {
   /**
-   * Closes the file. Returns a [:Future<RandomAccessFile>:] that
+   * Closes the file. Returns a `Future<RandomAccessFile>` that
    * completes with this RandomAccessFile when it has been closed.
    */
   Future<RandomAccessFile> close();
@@ -555,7 +610,7 @@
   void closeSync();
 
   /**
-   * Reads a byte from the file. Returns a [:Future<int>:] that
+   * Reads a byte from the file. Returns a `Future<int>` that
    * completes with the byte, or with -1 if end-of-file has been reached.
    */
   Future<int> readByte();
@@ -588,7 +643,7 @@
    * [buffer], otherwise up to [buffer.length]. If [end] == [start] nothing
    * happens.
    *
-   * Returns a [:Future<int>:] that completes with the number of bytes read.
+   * Returns a `Future<int>` that completes with the number of bytes read.
    */
   Future<int> readInto(List<int> buffer, [int start = 0, int end]);
 
@@ -605,7 +660,7 @@
 
   /**
    * Writes a single byte to the file. Returns a
-   * [:Future<RandomAccessFile>:] that completes with this
+   * `Future<RandomAccessFile>` that completes with this
    * RandomAccessFile when the write completes.
    */
   Future<RandomAccessFile> writeByte(int value);
@@ -623,7 +678,7 @@
    * [start] to index [end]. If [start] is omitted, it'll start from index 0.
    * If [end] is omitted, it will write to end of [buffer].
    *
-   * Returns a [:Future<RandomAccessFile>:] that completes with this
+   * Returns a `Future<RandomAccessFile>` that completes with this
    * [RandomAccessFile] when the write completes.
    */
   Future<RandomAccessFile> writeFrom(
@@ -641,7 +696,7 @@
 
   /**
    * Writes a string to the file using the given [Encoding]. Returns a
-   * [:Future<RandomAccessFile>:] that completes with this
+   * `Future<RandomAccessFile>` that completes with this
    * RandomAccessFile when the write completes.
    */
   Future<RandomAccessFile> writeString(String string,
@@ -658,7 +713,7 @@
 
   /**
    * Gets the current byte position in the file. Returns a
-   * [:Future<int>:] that completes with the position.
+   * `Future<int>` that completes with the position.
    */
   Future<int> position();
 
@@ -671,7 +726,7 @@
 
   /**
    * Sets the byte position in the file. Returns a
-   * [:Future<RandomAccessFile>:] that completes with this
+   * `Future<RandomAccessFile>` that completes with this
    * RandomAccessFile when the position has been set.
    */
   Future<RandomAccessFile> setPosition(int position);
@@ -685,7 +740,7 @@
 
   /**
    * Truncates (or extends) the file to [length] bytes. Returns a
-   * [:Future<RandomAccessFile>:] that completes with this
+   * `Future<RandomAccessFile>` that completes with this
    * RandomAccessFile when the truncation has been performed.
    */
   Future<RandomAccessFile> truncate(int length);
@@ -698,7 +753,7 @@
   void truncateSync(int length);
 
   /**
-   * Gets the length of the file. Returns a [:Future<int>:] that
+   * Gets the length of the file. Returns a `Future<int>` that
    * completes with the length in bytes.
    */
   Future<int> length();
@@ -712,7 +767,7 @@
 
   /**
    * Flushes the contents of the file to disk. Returns a
-   * [:Future<RandomAccessFile>:] that completes with this
+   * `Future<RandomAccessFile>` that completes with this
    * RandomAccessFile when the flush operation completes.
    */
   Future<RandomAccessFile> flush();
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index dce4cbc..0e879b1 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -248,10 +248,6 @@
 
   File get absolute => new File(_absolutePath);
 
-  Future<FileStat> stat() => FileStat.stat(path);
-
-  FileStat statSync() => FileStat.statSync(path);
-
   Future<File> create({bool recursive: false}) {
     var result = recursive ? parent.create(recursive: true)
                            : new Future.value(null);
@@ -380,6 +376,49 @@
     return result;
   }
 
+  Future<DateTime> lastAccessed() {
+    return _IOService._dispatch(_FILE_LAST_ACCESSED, [path]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response,
+                                     "Cannot retrieve access time",
+                                     path);
+      }
+      return new DateTime.fromMillisecondsSinceEpoch(response);
+    });
+  }
+
+  external static _lastAccessed(String path);
+
+  DateTime lastAccessedSync() {
+    var ms = _lastAccessed(path);
+    throwIfError(ms, "Cannot retrieve access time", path);
+    return new DateTime.fromMillisecondsSinceEpoch(ms);
+  }
+
+  Future setLastAccessed(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    return _IOService._dispatch(_FILE_SET_LAST_ACCESSED, [path, millis])
+                     .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response,
+                                     "Cannot set access time",
+                                     path);
+      }
+      return null;
+    });
+  }
+
+  external static _setLastAccessed(String path, int millis);
+
+  void setLastAccessedSync(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    var result = _setLastAccessed(path, millis);
+    if (result is OSError) {
+      throw new FileSystemException("Failed to set file access time",
+          path, result);
+    }
+  }
+
   Future<DateTime> lastModified() {
     return _IOService._dispatch(_FILE_LAST_MODIFIED, [path]).then((response) {
       if (_isErrorResponse(response)) {
@@ -399,6 +438,30 @@
     return new DateTime.fromMillisecondsSinceEpoch(ms);
   }
 
+  Future setLastModified(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    return _IOService._dispatch(_FILE_SET_LAST_MODIFIED, [path, millis])
+                     .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response,
+                                     "Cannot set modification time",
+                                     path);
+      }
+      return null;
+    });
+  }
+
+  external static _setLastModified(String path, int millis);
+
+  void setLastModifiedSync(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    var result = _setLastModified(path, millis);
+    if (result is OSError) {
+      throw new FileSystemException("Failed to set file modification time",
+          path, result);
+    }
+  }
+
   external static _open(String path, int mode);
 
   RandomAccessFile openSync({FileMode mode: FileMode.READ}) {
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 41bee01..2bfc1d8 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -359,7 +359,7 @@
    * with .type set to
    * FileSystemEntityType.NOT_FOUND and the other fields invalid.
    */
-  Future<FileStat> stat();
+  Future<FileStat> stat() => FileStat.stat(path);
 
   /**
    * Synchronously calls the operating system's stat() function on the
@@ -371,7 +371,7 @@
    * If the call fails, returns a [FileStat] object with .type set to
    * FileSystemEntityType.NOT_FOUND and the other fields invalid.
    */
-  FileStat statSync();
+  FileStat statSync() => FileStat.statSync(path);
 
   /**
    * Deletes this [FileSystemEntity].
@@ -433,7 +433,7 @@
    * being listened to, not when the call to [watch] is issued.
    *
    * The returned value is an endless broadcast [Stream], that only stops when
-   * one of the following happends:
+   * one of the following happens:
    *
    *   * The [Stream] is canceled, e.g. by calling `cancel` on the
    *      [StreamSubscription].
@@ -653,8 +653,7 @@
   }
 
   /**
-   * The directory containing [this].  If [this] is a root
-   * directory, returns [this].
+   * The directory containing [this].
    */
   Directory get parent => new Directory(parentOf(path));
 
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 3769b3f..40df48a 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -465,42 +465,32 @@
     _mutable = false;
   }
 
-  int _write(Uint8List buffer, int offset) {
-    void write(List<int> bytes) {
-      int len = bytes.length;
-      for (int i = 0; i < len; i++) {
-        buffer[offset + i] = bytes[i];
-      }
-      offset += len;
-    }
-
-    // Format headers.
+  void _build(BytesBuilder builder) {
     for (String name in _headers.keys) {
       List<String> values = _headers[name];
       bool fold = _foldHeader(name);
       var nameData = name.codeUnits;
-      write(nameData);
-      buffer[offset++] = _CharCode.COLON;
-      buffer[offset++] = _CharCode.SP;
+      builder.add(nameData);
+      builder.addByte(_CharCode.COLON);
+      builder.addByte(_CharCode.SP);
       for (int i = 0; i < values.length; i++) {
         if (i > 0) {
           if (fold) {
-            buffer[offset++] = _CharCode.COMMA;
-            buffer[offset++] = _CharCode.SP;
+            builder.addByte(_CharCode.COMMA);
+            builder.addByte(_CharCode.SP);
           } else {
-            buffer[offset++] = _CharCode.CR;
-            buffer[offset++] = _CharCode.LF;
-            write(nameData);
-            buffer[offset++] = _CharCode.COLON;
-            buffer[offset++] = _CharCode.SP;
+            builder.addByte(_CharCode.CR);
+            builder.addByte(_CharCode.LF);
+            builder.add(nameData);
+            builder.addByte(_CharCode.COLON);
+            builder.addByte(_CharCode.SP);
           }
         }
-        write(values[i].codeUnits);
+        builder.add(values[i].codeUnits);
       }
-      buffer[offset++] = _CharCode.CR;
-      buffer[offset++] = _CharCode.LF;
+      builder.addByte(_CharCode.CR);
+      builder.addByte(_CharCode.LF);
     }
-    return offset;
   }
 
   String toString() {
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index a965afa..ac7d67a 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -574,29 +574,20 @@
   }
 
   void _writeHeader() {
-    Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
-    int offset = 0;
-
-    void write(List<int> bytes) {
-      int len = bytes.length;
-      for (int i = 0; i < len; i++) {
-        buffer[offset + i] = bytes[i];
-      }
-      offset += len;
-    }
+    BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
 
     // Write status line.
     if (headers.protocolVersion == "1.1") {
-      write(_Const.HTTP11);
+      buffer.add(_Const.HTTP11);
     } else {
-      write(_Const.HTTP10);
+      buffer.add(_Const.HTTP10);
     }
-    buffer[offset++] = _CharCode.SP;
-    write(statusCode.toString().codeUnits);
-    buffer[offset++] = _CharCode.SP;
-    write(reasonPhrase.codeUnits);
-    buffer[offset++] = _CharCode.CR;
-    buffer[offset++] = _CharCode.LF;
+    buffer.addByte(_CharCode.SP);
+    buffer.add(statusCode.toString().codeUnits);
+    buffer.addByte(_CharCode.SP);
+    buffer.add(reasonPhrase.codeUnits);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
 
     var session = _httpRequest._session;
     if (session != null && !session._destroyed) {
@@ -630,10 +621,11 @@
     headers._finalize();
 
     // Write headers.
-    offset = headers._write(buffer, offset);
-    buffer[offset++] = _CharCode.CR;
-    buffer[offset++] = _CharCode.LF;
-    _outgoing.setHeader(buffer, offset);
+    headers._build(buffer);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
+    Uint8List headerBytes = buffer.takeBytes();
+    _outgoing.setHeader(headerBytes, headerBytes.length);
   }
 
   String _findReasonPhrase(int statusCode) {
@@ -821,27 +813,18 @@
   }
 
   void _writeHeader() {
-    Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
-    int offset = 0;
-
-    void write(List<int> bytes) {
-      int len = bytes.length;
-      for (int i = 0; i < len; i++) {
-        buffer[offset + i] = bytes[i];
-      }
-      offset += len;
-    }
+    BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
 
     // Write the request method.
-    write(method.codeUnits);
-    buffer[offset++] = _CharCode.SP;
+    buffer.add(method.codeUnits);
+    buffer.addByte(_CharCode.SP);
     // Write the request URI.
-    write(_requestUri().codeUnits);
-    buffer[offset++] = _CharCode.SP;
+    buffer.add(_requestUri().codeUnits);
+    buffer.addByte(_CharCode.SP);
     // Write HTTP/1.1.
-    write(_Const.HTTP11);
-    buffer[offset++] = _CharCode.CR;
-    buffer[offset++] = _CharCode.LF;
+    buffer.add(_Const.HTTP11);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
 
     // Add the cookies to the headers.
     if (!cookies.isEmpty) {
@@ -856,10 +839,11 @@
     headers._finalize();
 
     // Write headers.
-    offset = headers._write(buffer, offset);
-    buffer[offset++] = _CharCode.CR;
-    buffer[offset++] = _CharCode.LF;
-    _outgoing.setHeader(buffer, offset);
+    headers._build(buffer);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
+    Uint8List headerBytes = buffer.takeBytes();
+    _outgoing.setHeader(headerBytes, headerBytes.length);
   }
 }
 
@@ -935,18 +919,6 @@
   // Returns either a future or 'null', if it was able to write headers
   // immediately.
   Future writeHeaders({bool drainRequest: true, bool setOutgoing: true}) {
-    Future write() {
-      try {
-        outbound._writeHeader();
-      } catch (_) {
-        // Headers too large.
-        return new Future.error(new HttpException(
-            "Headers size exceeded the of '$_OUTGOING_BUFFER_SIZE'"
-            " bytes"));
-      }
-      return null;
-    }
-
     if (headersWritten) return null;
     headersWritten = true;
     Future drainFuture;
@@ -975,22 +947,22 @@
     } else {
       drainRequest = false;
     }
-    if (ignoreBody) {
-      return write();
-    }
-    if (setOutgoing) {
-      int contentLength = outbound.headers.contentLength;
-      if (outbound.headers.chunkedTransferEncoding) {
-        chunked = true;
-        if (gzip) this.gzip = true;
-      } else if (contentLength >= 0) {
-        this.contentLength = contentLength;
+    if (!ignoreBody) {
+      if (setOutgoing) {
+        int contentLength = outbound.headers.contentLength;
+        if (outbound.headers.chunkedTransferEncoding) {
+          chunked = true;
+          if (gzip) this.gzip = true;
+        } else if (contentLength >= 0) {
+          this.contentLength = contentLength;
+        }
+      }
+      if (drainFuture != null) {
+        return drainFuture.then((_) => outbound._writeHeader());
       }
     }
-    if (drainFuture != null) {
-      return drainFuture.then((_) => write());
-    }
-    return write();
+    outbound._writeHeader();
+    return null;
   }
 
 
@@ -1160,7 +1132,6 @@
 
   void setHeader(List<int> data, int length) {
     assert(_length == 0);
-    assert(data.length == _OUTGOING_BUFFER_SIZE);
     _buffer = data;
     _length = length;
   }
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index a52c4b6..c2bc9a8 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -1039,7 +1039,7 @@
   }
 
   void _closeIncoming([bool closing = false]) {
-    // Ignore multiple close (can happend in re-entrance).
+    // Ignore multiple close (can happen in re-entrance).
     if (_incoming == null) return;
     var tmp = _incoming;
     tmp.close(closing);
diff --git a/sdk/lib/io/io_service.dart b/sdk/lib/io/io_service.dart
index cabba54..0ed4439 100644
--- a/sdk/lib/io/io_service.dart
+++ b/sdk/lib/io/io_service.dart
@@ -18,33 +18,36 @@
 const int _FILE_TRUNCATE = 10;
 const int _FILE_LENGTH = 11;
 const int _FILE_LENGTH_FROM_PATH = 12;
-const int _FILE_LAST_MODIFIED = 13;
-const int _FILE_FLUSH = 14;
-const int _FILE_READ_BYTE = 15;
-const int _FILE_WRITE_BYTE = 16;
-const int _FILE_READ = 17;
-const int _FILE_READ_INTO = 18;
-const int _FILE_WRITE_FROM = 19;
-const int _FILE_CREATE_LINK = 20;
-const int _FILE_DELETE_LINK = 21;
-const int _FILE_RENAME_LINK = 22;
-const int _FILE_LINK_TARGET = 23;
-const int _FILE_TYPE = 24;
-const int _FILE_IDENTICAL = 25;
-const int _FILE_STAT = 26;
-const int _FILE_LOCK = 27;
-const int _SOCKET_LOOKUP = 28;
-const int _SOCKET_LIST_INTERFACES = 29;
-const int _SOCKET_REVERSE_LOOKUP = 30;
-const int _DIRECTORY_CREATE = 31;
-const int _DIRECTORY_DELETE = 32;
-const int _DIRECTORY_EXISTS = 33;
-const int _DIRECTORY_CREATE_TEMP = 34;
-const int _DIRECTORY_LIST_START = 35;
-const int _DIRECTORY_LIST_NEXT = 36;
-const int _DIRECTORY_LIST_STOP = 37;
-const int _DIRECTORY_RENAME = 38;
-const int _SSL_PROCESS_FILTER = 39;
+const int _FILE_LAST_ACCESSED = 13;
+const int _FILE_SET_LAST_ACCESSED = 14;
+const int _FILE_LAST_MODIFIED = 15;
+const int _FILE_SET_LAST_MODIFIED = 16;
+const int _FILE_FLUSH = 17;
+const int _FILE_READ_BYTE = 18;
+const int _FILE_WRITE_BYTE = 19;
+const int _FILE_READ = 20;
+const int _FILE_READ_INTO = 21;
+const int _FILE_WRITE_FROM = 22;
+const int _FILE_CREATE_LINK = 23;
+const int _FILE_DELETE_LINK = 24;
+const int _FILE_RENAME_LINK = 25;
+const int _FILE_LINK_TARGET = 26;
+const int _FILE_TYPE = 27;
+const int _FILE_IDENTICAL = 28;
+const int _FILE_STAT = 29;
+const int _FILE_LOCK = 30;
+const int _SOCKET_LOOKUP = 31;
+const int _SOCKET_LIST_INTERFACES = 32;
+const int _SOCKET_REVERSE_LOOKUP = 33;
+const int _DIRECTORY_CREATE = 34;
+const int _DIRECTORY_DELETE = 35;
+const int _DIRECTORY_EXISTS = 36;
+const int _DIRECTORY_CREATE_TEMP = 37;
+const int _DIRECTORY_LIST_START = 38;
+const int _DIRECTORY_LIST_NEXT = 39;
+const int _DIRECTORY_LIST_STOP = 40;
+const int _DIRECTORY_RENAME = 41;
+const int _SSL_PROCESS_FILTER = 42;
 
 class _IOService {
   external static Future _dispatch(int request, List data);
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index b1c05a0..b1e1fca 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.dart
@@ -123,6 +123,10 @@
 
   /**
    * Close the target consumer.
+   *
+   * NOTE: Writes to the [IOSink] may be buffered, and may not be flushed by
+   * a call to `close()`. To flush all buffered writes, call `flush()` before
+   * calling `close()`.
    */
   Future close();
 
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 83940b4..99b72c8 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -162,10 +162,6 @@
 
   Link get absolute => new Link(_absolutePath);
 
-  Future<FileStat> stat() => FileStat.stat(path);
-
-  FileStat statSync() => FileStat.statSync(path);
-
   Future<Link> create(String target, {bool recursive: false}) {
     if (Platform.isWindows) {
       target = _makeWindowsLinkTarget(target);
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index 2a87848..86a0f8f 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -120,6 +120,8 @@
    * If disabled, input from to console will not be echoed.
    *
    * Default depends on the parent process, but usually enabled.
+   *
+   * On Windows this mode can only be enabled if [lineMode] is enabled as well.
    */
   external void set echoMode(bool enabled);
 
@@ -135,6 +137,8 @@
    * If disabled, characters will be available as typed.
    *
    * Default depends on the parent process, but usually enabled.
+   *
+   * On Windows this mode can only be disabled if [echoMode] is disabled as well.
    */
   external void set lineMode(bool enabled);
 
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index b398e53..8627be5 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -94,7 +94,7 @@
    * then calls to [pause] will have no effect.
    *
    * If the isolate is spawned in a paused state, use this capability as
-   * argument to [resume] to resume the isolate.
+   * argument to the [resume] method in order to resume the paused isolate.
    */
   final Capability pauseCapability;
 
@@ -379,16 +379,18 @@
   external void resume(Capability resumeCapability);
 
   /**
-   * Asks the isolate to send [response] on [responsePort] when it terminates.
+   * Requests an exist message on [responsePort] when the isolate terminates.
    *
-   * The isolate will send a `response` message on `responsePort` as the last
+   * The isolate will send [response] as a message on [responsePort] as the last
    * thing before it terminates. It will run no further code after the message
    * has been sent.
    *
-   * Adding the same port more than once will only cause it to receive one
-   * message, using the last response value that was added.
+   * Adding the same port more than once will only cause it to receive one exit
+   * message, using the last response value that was added,
+   * and it only needs to be removed once using [removeOnExitListener].
    *
-   * If the isolate is already dead, no message will be sent.
+   * If the isolate has terminated before it can receive this request,
+   * no exit message will be sent.
    *
    * The [response] object must follow the same restrictions as enforced by
    * [SendPort.send].
@@ -408,13 +410,22 @@
   external void addOnExitListener(SendPort responsePort, {Object response});
 
   /**
-   * Stop listening on exit messages from the isolate.
+   * Stop listening for exit messages from the isolate.
    *
-   * If a call has previously been made to [addOnExitListener] with the same
-   * send-port, this will unregister the port, and it will no longer receive
-   * a message when the isolate terminates.
-   * A response may still be sent until this operation is fully processed by
-   * the isolate.
+   * Requests for the isolate to not send exit messages on [responsePort].
+   * If the isolate isn't expecting to send exit messages on [responsePort],
+   * because the port hasn't been added using [addOnExitListener],
+   * or because it has already been removed, the request is ignored.
+   *
+   * If the same port has been passed via [addOnExitListener] more than once,
+   * only one call to `removeOnExitListener` is needed to stop it from receiving
+   * exit messagees.
+   *
+   * Closing the receive port at the end of the send port will not stop the
+   * isolate from sending exit messages, they are just going to be lost.
+   *
+   * An exit message may still be sent if the isolate terminates
+   * before this request is received and processed.
    */
   external void removeOnExitListener(SendPort responsePort);
 
@@ -425,7 +436,7 @@
    * event loop and shut down the isolate.
    *
    * This call requires the [terminateCapability] for the isolate.
-   * If the capability absent or wrong, no change is made.
+   * If the capability is absent or incorrect, no change is made.
    *
    * Since isolates run concurrently, it's possible for it to exit due to an
    * error before errors are set non-fatal.
@@ -479,8 +490,8 @@
    *
    * * `IMMEDIATE`: The isolate responds as soon as it receives the
    *     control message. This is after any previous control message
-   *     from the same isolate has been received, but may be during
-   *     execution of another event.
+   *     from the same isolate has been received and processed,
+   *     but may be during execution of another event.
    * * `BEFORE_NEXT_EVENT`: The response is scheduled for the next time
    *     control returns to the event loop of the receiving isolate,
    *     after the current event, and any already scheduled control events,
@@ -499,8 +510,9 @@
    * stack trace, or `null` if no stack trace was provided.
    * To convert this back to a [StackTrace] object, use [StackTrace.fromString].
    *
-   * Listening using the same port more than once does nothing. It will only
-   * get each error once.
+   * Listening using the same port more than once does nothing.
+   * A port will only receive each error once,
+   * and will only need to be removed once using [removeErrorListener].
    *
    * Since isolates run concurrently, it's possible for it to exit before the
    * error listener is established. To avoid this, start the isolate paused,
@@ -509,18 +521,22 @@
   external void addErrorListener(SendPort port);
 
   /**
-   * Stop listening for uncaught errors through [port].
+   * Stop listening for uncaught errors from the isolate.
    *
-   * The `port` should be a port that is listening for errors through
-   * [addErrorListener]. This call requests that the isolate stops sending
-   * errors on the port.
+   * Requests for the isolate to not send uncaught errors on [responsePort].
+   * If the isolate isn't expecting to send uncaught errors on [responsePort],
+   * because the port hasn't been added using [addErrorListener],
+   * or because it has already been removed, the request is ignored.
    *
-   * If the same port has been passed via `addErrorListener` more than once,
+   * If the same port has been passed via [addErrorListener] more than once,
    * only one call to `removeErrorListener` is needed to stop it from receiving
-   * errors.
+   * unaught errors.
    *
    * Closing the receive port at the end of the send port will not stop the
-   * isolate from sending errors, they are just going to be lost.
+   * isolate from sending uncaught errors, they are just going to be lost.
+   *
+   * Uncaught errors message may still be sent by the isolate
+   * until this request is received and processed.
    */
   external void removeErrorListener(SendPort port);
 
diff --git a/tests/benchmark_smoke/benchmark_smoke.status b/tests/benchmark_smoke/benchmark_smoke.status
index de17765..30d525a 100644
--- a/tests/benchmark_smoke/benchmark_smoke.status
+++ b/tests/benchmark_smoke/benchmark_smoke.status
@@ -10,3 +10,6 @@
 
 [ $compiler == dart2js && $cps_ir && $checked ]
 *: Skip # Issue 25761
+
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index 618fb0e..58406e6 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -67,6 +67,19 @@
 Language/Expressions/Method_Invocation/Super_Invocation/accessible_instance_member_t03: StaticWarning # Please triage this failure.
 Language/Expressions/Method_Invocation/Super_Invocation/accessible_instance_member_t04: StaticWarning # Please triage this failure.
 Language/Expressions/Method_Invocation/Super_Invocation/accessible_instance_member_t05: StaticWarning # Please triage this failure.
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t01: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t02: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t03: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t04: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t05: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t06: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t07: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t08: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/no_such_method_t01: StaticWarning # co19 issue 88
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/proxy_annotation_t05: StaticWarning # co19 issue 88
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/proxy_annotation_t06: StaticWarning # co19 issue 88
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/proxy_annotation_t07: StaticWarning # co19 issue 88
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/proxy_annotation_t08: StaticWarning # co19 issue 88
 Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t03: StaticWarning # Please triage this failure.
 Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t01: CompileTimeError # Please triage this failure.
 Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t02: CompileTimeError # Please triage this failure.
@@ -436,3 +449,6 @@
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-007_t01: StaticWarning # Please triage this failure.
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-009_t01: StaticWarning # Please triage this failure.
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-011_t01: StaticWarning # Please triage this failure.
+
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 491c274..4fbe0ff 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -80,6 +80,16 @@
 Language/Expressions/Object_Identity/double_t02: RuntimeError # Please triage this failure
 Language/Expressions/Object_Identity/double_t03: RuntimeError # Please triage this failure
 Language/Expressions/Object_Identity/object_t02: RuntimeError # Issue 1533 (int/double related)
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t01: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t02: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t03: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t04: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t05: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t06: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t07: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t08: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/no_such_method_t01: RuntimeError # co19 issue 87
+Language/Expressions/Property_Extraction/Super_Getter_Access_and_Method_Closurization/no_such_method_t01: RuntimeError # co19 issue 87
 Language/Expressions/Shift/syntax_t01/14: MissingRuntimeError # Please triage this failure
 Language/Functions/External_Functions/not_connected_to_a_body_t01: CompileTimeError, OK # Issue 5021
 Language/Generics/syntax_t17: fail # Issue 21203
@@ -114,8 +124,6 @@
 Language/Mixins/deferred_t01: MissingCompileTimeError # Please triage this failure
 Language/Mixins/not_object_superclass_t01: MissingCompileTimeError # Please triage this failure
 Language/Mixins/reference_to_super_t01: MissingCompileTimeError # Please triage this failure
-Language/Reference/Lexical_Rules/Reserved_Words/whitespace_t04: MissingCompileTimeError # Checks that other Unicode whitespaces are not allowed:  check NO-BREAK SPACE (U+00A0)
-Language/Reference/Lexical_Rules/whitespace_t06: MissingCompileTimeError # Checks that Unicode whitespaces other than WHITESPACE are not permitted in the source code. Checks symbol U+00a0.
 Language/Reference/Operator_Precedence/precedence_15_unary_prefix_t08: RuntimeError # Please triage this failure
 Language/Statements/Assert/syntax_t04: MissingCompileTimeError # This is legal Dart
 Language/Statements/Continue/async_loops_t09: Crash # Please triage this failure
@@ -136,6 +144,7 @@
 Language/Variables/local_variable_t01: MissingCompileTimeError # Issue 21050
 LayoutTests/fast/dom/css-innerHTML_t01: SkipByDesign # Test is incorrect.
 LayoutTests/fast/loader/loadInProgress_t01: Skip # Issue 23466
+LayoutTests/fast/forms/input-implicit-length-limit_t01: SkipByDesign # Test is not about Dart, but about a DOM-only webkit bug that has been fixed.
 LibTest/collection/LinkedHashSet/LinkedHashSet.from_A03_t01: RuntimeError # Please triage this failure.
 LibTest/collection/LinkedList/add_A01_t01: Pass, Slow # Slow tests that needs extra time to finish.
 LibTest/collection/ListBase/ListBase_class_A01_t01: RuntimeError # Please triage this failure
@@ -304,6 +313,7 @@
 WebPlatformTest/dom/nodes/Document-createElement_t01: CompileTimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/dom/nodes/Element-childElementCount-nochild_t01: CompileTimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/webstorage/storage_session_setitem_quotaexceedederr_t01: Pass, Slow
+WebPlatformTest/webstorage/storage_local_setitem_quotaexceedederr_t01: Pass, Slow
 
 [ $compiler == dart2js && $checked ]
 Language/Errors_and_Warnings/static_warning_t02: RuntimeError # Please triage this failure
@@ -938,7 +948,7 @@
 LayoutTests/fast/css/font-face-unicode-range-overlap-load_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-family-trailing-bracket-gunk_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-shorthand-from-longhands_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/fontfaceset-download-error_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/fontfaceset-download-error_t01: RuntimeError, Timeout # Timeout: issue 28722. Runtime error not triaged
 LayoutTests/fast/css/fontfaceset-events_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/fontfaceset-loadingdone_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/getComputedStyle/computed-style-border-image_t01: RuntimeError # co19 issue 14
@@ -973,7 +983,6 @@
 LayoutTests/fast/css/readonly-pseudoclass-opera-005_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/selector-text-escape_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/shadow-current-color_t01: Skip # Times out. Please triage this failure
-LayoutTests/fast/css/sticky/parsing-position-sticky_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/style-element-process-crash_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/css/style-scoped/style-scoped-nested_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/style-scoped/style-scoped-with-dom-operation_t01: RuntimeError # Please triage this failure
@@ -1514,7 +1523,6 @@
 WebPlatformTest/dom/nodes/Node-isEqualNode_t01: RuntimeError # Please triage this failure
 WebPlatformTest/dom/nodes/Node-nodeName_t01: RuntimeError # Please triage this failure
 WebPlatformTest/dom/nodes/Node-replaceChild_t01: RuntimeError # Please triage this failure
-WebPlatformTest/dom/nodes/Node-textContent_t01: RuntimeError # Please triage this failure
 WebPlatformTest/dom/nodes/attributes/setAttributeNS_A05_t01: RuntimeError # Please triage this failure
 WebPlatformTest/dom/nodes/attributes/setAttributeNS_A06_t03: RuntimeError # Please triage this failure
 WebPlatformTest/dom/nodes/attributes/setAttributeNS_A07_t02: RuntimeError # Please triage this failure
@@ -1535,7 +1543,6 @@
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.body-setter_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.getElementsByName-namespace_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t05: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t07: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/nameditem_t02: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/elements/global-attributes/dataset-delete_t01: RuntimeError # Please triage this failure
@@ -1734,6 +1741,7 @@
 LayoutTests/fast/canvas/webgl/draw-webgl-to-canvas-2d_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: Skip # Times out flakily.
+LayoutTests/fast/css/sticky/parsing-position-sticky_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLOutputElement/htmloutputelement_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/MutationObserver/observe-attributes_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/forms/percent-height-auto-width-form-controls_t01: RuntimeError # Please triage this failure
@@ -1745,6 +1753,8 @@
 LayoutTests/fast/text/text-combine-shrink-to-fit_t01: RuntimeError # Please triage this failure
 LibTest/async/Timer/Timer.periodic_A01_t01: Skip # Times out. Please triage this failure
 LibTest/isolate/Isolate/spawn_A01_t05: Skip # Times out. Please triage this failure
+WebPlatformTest/dom/nodes/Node-textContent_t01: RuntimeError # Please triage this failure
+WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t05: RuntimeError # Please triage this failure
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-002_t01: Skip # Times out. Please triage this failure
 
 [ $compiler == dart2js && $runtime == chrome && $system == windows ]
@@ -1845,6 +1855,13 @@
 LayoutTests/fast/canvas/webgl/webgl-texture-binding-preserved_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/webgl-unprefixed-context-id_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/webgl-viewport-parameters-preserved_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/insertRule-media_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/Document/document-title-get_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/mediastream/RTCPeerConnection_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/replaced/table-percent-height-text-controls_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/text/zero-width-characters-complex-script_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/text/zero-width-characters_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/events/retargeting-relatedtarget/test-003_t01: RuntimeError # Please triage this failure
 
 [ $compiler == dart2js && $runtime == chrome && $system == linux]
 LayoutTests/fast/multicol/newmulticol/balance_t04: RuntimeError # Please triage this failure
@@ -2648,12 +2665,12 @@
 LayoutTests/fast/canvas/alpha_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-arc-negative-radius_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blend-solid_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/canvas-blending-text_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-canvas_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-image_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-text-alpha_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-currentColor_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-currentTransform_t01: RuntimeError # Feature is not implemented.
-LayoutTests/fast/canvas/canvas-drawImage-incomplete_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-ellipse-zero-lineto_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-empty-image-pattern_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-fill-zeroSizeGradient_t01: RuntimeError # Please triage this failure
@@ -2665,7 +2682,6 @@
 LayoutTests/fast/canvas/canvas-getImageData-large-crash_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-getImageData-rounding_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-imageSmoothingEnabled-repaint_t01: Skip # Times out. Please triage this failure
-LayoutTests/fast/canvas/canvas-imageSmoothingEnabled_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-large-dimensions_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-large-fills_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-lineDash_t01: RuntimeError # Please triage this failure
@@ -2684,17 +2700,22 @@
 LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-toDataURL-crash_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/draw-custom-focus-ring_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/drawImage-with-valid-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/getPutImageDataPairTest_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/rgba-parsing_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: Pass, RuntimeError # Issue 26898
 LayoutTests/fast/canvas/webgl/context-lost-restored_t01: Pass, RuntimeError # Issue 26898
 LayoutTests/fast/canvas/webgl/context-lost_t01: Pass, RuntimeError # Issue 26898
+LayoutTests/fast/canvas/webgl/error-reporting_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/get-active-test_t01: RuntimeError # Issue 28593
 LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/gl-get-calls_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/null-object-behaviour_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/renderer-and-vendor-strings_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-array-buffer-view_t01: Skip # Times out.
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Please triage this failure
@@ -2935,6 +2956,7 @@
 LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-hash_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-host_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-hostname_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-pathname_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-port_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-protocol_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-search_t01: RuntimeError # Please triage this failure
@@ -3080,12 +3102,12 @@
 LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/containerNode_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/dom/createElementNS-namespace-errors_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/css-delete-doc_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/css-rule-functions_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/css-selectorText_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/css-shortHands_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/css-shorthand-common-value_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/createElementNS-namespace-errors_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/custom/attribute-changed-callback_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/custom/constructor-calls-created-synchronously_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/custom/created-callback_t01: RuntimeError # Please triage this failure
@@ -3300,7 +3322,6 @@
 LayoutTests/fast/flexbox/box-orient-button_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/flexbox/box-size-integer-overflow_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/11423_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/forms/4628409_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/8250_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/ValidityState-customError_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/ValidityState-patternMismatch_t01: RuntimeError # Please triage this failure
@@ -3363,10 +3384,8 @@
 LayoutTests/fast/forms/input-appearance-maxlength_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-changing-value_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-file-set-value_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/forms/input-implicit-length-limit_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-inputmode_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-maxlength-unsupported_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/forms/input-setvalue-selection_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-text-paste-maxlength_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-value-sanitization_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-width-height-attributes_t01: RuntimeError # Please triage this failure
@@ -3402,6 +3421,7 @@
 LayoutTests/fast/forms/submit-form-with-dirname-attribute-with-ancestor-dir-attribute_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/forms/submit-form-with-dirname-attribute_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/forms/text-control-select-blurred_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/forms/textarea-initial-caret-position_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/textarea-maxlength_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/textarea-no-scroll-on-blur_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/textarea-paste-newline_t01: RuntimeError # Please triage this failure
@@ -3611,7 +3631,6 @@
 LayoutTests/fast/writing-mode/positionForPoint_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/table-hit-test_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/vertical-inline-block-hittest_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/xmlhttprequest/xmlhttprequest-responseXML-invalid-xml_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xmlhttprequest/xmlhttprequest-responseXML-xml-text-responsetype_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-abort_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-arraybuffer_t01: RuntimeError # Please triage this failure
@@ -4023,12 +4042,11 @@
 WebPlatformTest/html/dom/elements/global-attributes/dataset-enumeration_t01: RuntimeError # Please triage this failure
 
 [ $compiler == dart2js && $runtime == ff && $system == windows ]
-Language/Classes/Getters/type_object_t02: RuntimeError, Slow # Issue 25940
 Language/Classes/Abstract_Instance_Members/override_no_named_parameters_t06: Pass, Slow # Issue 25940
 Language/Classes/Constructors/Factories/return_type_t03: Pass, Slow # Issue 25940
-Language/Classes/Constructors/Factories/return_wrong_type_t02: Pass, Slow # Issue 25940
 Language/Classes/Constructors/Factories/return_type_t05: Pass, Slow # Issue 25940
-LayoutTests/fast/canvas/canvas-blending-text_t01: RuntimeError # Please triage this failure
+Language/Classes/Constructors/Factories/return_wrong_type_t02: Pass, Slow # Issue 25940
+Language/Classes/Getters/type_object_t02: RuntimeError, Slow # Issue 25940
 LayoutTests/fast/canvas/webgl/draw-webgl-to-canvas-2d_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/drawingbuffer-test_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/syntax/parsing/math-parse_t03: RuntimeError # Issue 22564
@@ -4123,6 +4141,7 @@
 LayoutTests/fast/canvas/setWidthResetAfterForcedRender_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-lost_t01: Skip
+LayoutTests/fast/canvas/webgl/context-lost-restored_t01: Skip # Issue 28640
 LayoutTests/fast/canvas/webgl/glsl-conformance_t01: Skip # Times out 1 out of 20.
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba4444_t01: RuntimeError # Please triage this failure
@@ -7576,7 +7595,6 @@
 LayoutTests/fast/forms/input-appearance-maxlength_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-changing-value_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-file-set-value_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/forms/input-implicit-length-limit_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-inputmode_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-maxlength-unsupported_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-maxlength_t01: RuntimeError # Please triage this failure
@@ -9476,7 +9494,7 @@
 LayoutTests/fast/forms/autofocus-focus-only-once_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/forms/autofocus-opera-007_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/button-baseline-and-collapsing_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/forms/button/button-disabled-blur_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/forms/button/button-disabled-blur_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/forms/checkValidity-001_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/checkValidity-002_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/checkValidity-handler-updates-dom_t01: RuntimeError # Please triage this failure
@@ -9529,7 +9547,6 @@
 LayoutTests/fast/forms/input-appearance-maxlength_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-changing-value_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-file-set-value_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/forms/input-implicit-length-limit_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-inputmode_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-maxlength-unsupported_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/input-maxlength_t01: RuntimeError # Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 76d0c26..fbc3ce6 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -543,6 +543,7 @@
 LayoutTests/fast/forms/formmethod-attribute-input-html_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/formmethod-attribute-input-html_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/forms/HTMLOptionElement_selected2_t01: Skip # Times out. co19-roll r801: Please triage this failure.
+LayoutTests/fast/forms/input-appearance-elementFromPoint_t01: Pass, RuntimeError # Issue 28710
 LayoutTests/fast/forms/input-hit-test-border_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/input-inputmode_t01: RuntimeError # Experimental feature not exposed in Chrome yet
 LayoutTests/fast/forms/input-value-sanitization_t01: RuntimeError # 45 roll issue
@@ -1211,12 +1212,13 @@
 [ $compiler == none && $runtime == dartium && $system == windows ]
 LayoutTests/fast/css/MarqueeLayoutTest_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/vertical-inline-block-hittest_t01: Pass, RuntimeError # Issue 21605
+LayoutTests/fast/dom/shadow/shadowhost-keyframes_t01: Pass, RuntimeError # Gardening: please triage this failure.
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t01: Skip # Timesout Issue 26134
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-002_t01: Skip # Timesout sporadically
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-003_t01: Skip # Timesout sporadically
 
-[ $compiler == none && $runtime == dartium && $system != windows ]
-LayoutTests/fast/css/font-face-unicode-range-monospace_t01: RuntimeError # co19-roll r761: Please triage this failure.
+[ $compiler == none && $runtime == dartium ]
+LayoutTests/fast/css/font-face-unicode-range-monospace_t01: Pass, RuntimeError # Issue 28724
 
 [ $compiler == none && $runtime == dartium && $system == linux ]
 language/mixin_illegal_constructor_test/01: Skip # Issue 43
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 894669a..e517286 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -6,7 +6,7 @@
 [ $compiler == dartk || $compiler == dartkp ]
 Language/Libraries_and_Scripts/Imports/static_type_t01: Skip # No support for deferred libraries.
 LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: Skip # No support for deferred libraries.
-LibTest/isolate/*: Skip # No support for isolates ATM.
+LibTest/isolate/Isolate/spawnUri_A01_t06: Skip
 
 Language/Metadata/before_export_t01: RuntimeError  # Issue 28434: Kernel IR misses these annotations.
 Language/Metadata/before_import_t01: RuntimeError  # Issue 28434: Kernel IR misses these annotations.
@@ -36,7 +36,7 @@
 ###############################################################################
 
 [ $compiler == dartk || $compiler == dartkp ]
-Language/Classes/Getters/static_getter_t02: DartkCompileTimeError
+Language/Classes/Getters/static_getter_t02: CompileTimeError
 Language/Enums/syntax_t08: MissingCompileTimeError
 Language/Enums/syntax_t09: MissingCompileTimeError
 Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t03: MissingCompileTimeError
@@ -55,13 +55,13 @@
 Language/Expressions/Identifier_Reference/built_in_not_dynamic_t30: MissingCompileTimeError
 Language/Expressions/Identifier_Reference/built_in_not_dynamic_t31: MissingCompileTimeError
 Language/Expressions/Identifier_Reference/built_in_not_dynamic_t32: MissingCompileTimeError
-Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t01: DartkCompileTimeError
-Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t02: DartkCompileTimeError
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t01: CompileTimeError
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t02: CompileTimeError
 Language/Libraries_and_Scripts/Exports/syntax_t01: MissingCompileTimeError
 Language/Libraries_and_Scripts/Exports/syntax_t04: MissingCompileTimeError
 Language/Libraries_and_Scripts/Exports/syntax_t05: MissingCompileTimeError
 Language/Libraries_and_Scripts/Exports/syntax_t06: MissingCompileTimeError
-Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t02: DartkCompileTimeError
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t02: CompileTimeError
 Language/Libraries_and_Scripts/definition_syntax_t01: MissingCompileTimeError
 Language/Libraries_and_Scripts/definition_syntax_t03: MissingCompileTimeError
 Language/Libraries_and_Scripts/definition_syntax_t04: MissingCompileTimeError
@@ -113,18 +113,17 @@
 Language/Variables/final_t05: MissingCompileTimeError
 Language/Variables/final_t06: MissingCompileTimeError
 Language/Variables/final_t07: MissingCompileTimeError
-Language/Mixins/Mixin_Application/error_t01: MissingCompileTimeError # Missing compile-time error from analyzer
-Language/Mixins/Mixin_Application/error_t02: MissingCompileTimeError
 
 # dartk: JIT failures
 [ $compiler == dartk && $runtime == vm ]
-Language/Expressions/Constants/exception_t01: MissingCompileTimeError
-Language/Expressions/Constants/exception_t02: MissingCompileTimeError
-Language/Expressions/Identifier_Reference/evaluation_type_parameter_t02: MissingCompileTimeError
+Language/Expressions/Constants/exception_t01: Crash
+Language/Expressions/Constants/exception_t02: Crash
 Language/Mixins/Mixin_Application/syntax_t16: DartkCrash
 
 # dartk: precompilation failures
 [ $compiler == dartkp && $runtime == dart_precompiled ]
+Language/Mixins/Mixin_Application/error_t01: MissingCompileTimeError
+Language/Mixins/Mixin_Application/error_t02: MissingCompileTimeError
 
 ###############################################################################
 # VM Entries
@@ -132,39 +131,39 @@
 
 # dartk: Shared JIT & Precompiled failures
 [ ($compiler == dartk && $runtime == vm) || ($compiler == dartkp && $runtime == dart_precompiled) ]
-Language/Classes/Constructors/Generative_Constructors/execution_of_an_initializer_t02: RuntimeError
-Language/Classes/Constructors/Generative_Constructors/initializing_formals_execution_t02: RuntimeError
-Language/Classes/definition_t23: CompileTimeError
-Language/Expressions/Function_Invocation/Function_Expression_Invocation/not_a_function_expression_t01: RuntimeError
-Language/Expressions/Function_Invocation/Unqualified_Invocation/function_expr_invocation_t03: RuntimeError
-Language/Expressions/Function_Invocation/Unqualified_Invocation/function_expr_invocation_t04: RuntimeError
-Language/Expressions/Function_Invocation/Unqualified_Invocation/static_method_invocation_t02: RuntimeError
-Language/Expressions/Identifier_Reference/built_in_identifier_t35: Pass
-Language/Expressions/Identifier_Reference/built_in_identifier_t36: Pass
-Language/Expressions/Identifier_Reference/built_in_identifier_t37: Pass
-Language/Expressions/Identifier_Reference/built_in_not_dynamic_t14: Pass
-Language/Expressions/Identifier_Reference/evaluation_property_extraction_t03: RuntimeError
-Language/Expressions/Instance_Creation/New/evaluation_t12: RuntimeError
-Language/Expressions/Instance_Creation/New/evaluation_t19: RuntimeError
-Language/Expressions/Instance_Creation/New/evaluation_t20: RuntimeError
-Language/Expressions/Lookup/Method_Lookup/superclass_t08: RuntimeError
-Language/Expressions/Method_Invocation/Ordinary_Invocation/accessible_instance_member_t05: RuntimeError
-Language/Expressions/Method_Invocation/Ordinary_Invocation/evaluation_t07: RuntimeError
-Language/Expressions/Method_Invocation/Ordinary_Invocation/method_lookup_failed_t18: RuntimeError
-Language/Expressions/Type_Test/evaluation_t10: RuntimeError
-Language/Functions/External_Functions/not_connected_to_a_body_t01: RuntimeError
-Language/Libraries_and_Scripts/Exports/invalid_uri_t02: Pass
-Language/Libraries_and_Scripts/Imports/deferred_import_t01: RuntimeError
-Language/Libraries_and_Scripts/Imports/deferred_import_t02: RuntimeError
-Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t01/01: MissingRuntimeError
-Language/Libraries_and_Scripts/Imports/invalid_uri_t02: Pass
-Language/Libraries_and_Scripts/Parts/syntax_t06: Pass
-Language/Statements/Labels/syntax_t03: Pass
-Language/Statements/Switch/syntax_t02: Pass
-Language/Statements/Try/catch_scope_t01: RuntimeError
-Language/Types/Static_Types/deferred_type_t01: RuntimeError
-Language/Variables/final_t01/01: MissingRuntimeError
-Language/Variables/final_t02/01: MissingRuntimeError
+Language/Classes/Constructors/Generative_Constructors/execution_of_an_initializer_t02: RuntimeError # Dartk Issue 28566
+Language/Classes/Constructors/Generative_Constructors/initializing_formals_execution_t02: RuntimeError # Dartk Issue 28566
+Language/Classes/definition_t23: CompileTimeError # Dartk Issue 28567
+Language/Expressions/Function_Invocation/Function_Expression_Invocation/not_a_function_expression_t01: RuntimeError # Dartk Issue 28562
+Language/Expressions/Function_Invocation/Unqualified_Invocation/function_expr_invocation_t03: RuntimeError # Dartk Issue 28562
+Language/Expressions/Function_Invocation/Unqualified_Invocation/function_expr_invocation_t04: RuntimeError # Dartk Issue 28562
+Language/Expressions/Function_Invocation/Unqualified_Invocation/static_method_invocation_t02: RuntimeError # Dartk Issue 28563
+Language/Expressions/Identifier_Reference/evaluation_property_extraction_t03: RuntimeError # Dartk Issue 28563
+Language/Expressions/Instance_Creation/New/evaluation_t12: RuntimeError # Dartk Issue 28564
+Language/Expressions/Instance_Creation/New/evaluation_t19: RuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Expressions/Instance_Creation/New/evaluation_t20: RuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Expressions/Lookup/Method_Lookup/superclass_t08: RuntimeError # Dartk Issue 28563
+Language/Expressions/Method_Invocation/Ordinary_Invocation/accessible_instance_member_t05: RuntimeError # Dartk Issue 28562
+Language/Expressions/Method_Invocation/Ordinary_Invocation/evaluation_t07: RuntimeError # Dartk Issue 28562
+Language/Expressions/Method_Invocation/Ordinary_Invocation/method_lookup_failed_t18: RuntimeError # Dartk Issue 28562
+Language/Expressions/Type_Test/evaluation_t10: RuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Functions/External_Functions/not_connected_to_a_body_t01: RuntimeError # Dartk Issue 28565
+Language/Libraries_and_Scripts/Imports/deferred_import_t01: RuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Libraries_and_Scripts/Imports/deferred_import_t02: RuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t01/01: MissingRuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Statements/Try/catch_scope_t01: RuntimeError # Dartk Issue 28410
+Language/Types/Static_Types/deferred_type_t01: RuntimeError # Kernel Issue 28335 (deferred libraries)
+Language/Variables/final_t01/01: MissingRuntimeError # Dartk Issue 28566
+Language/Variables/final_t02/01: MissingRuntimeError # Dartk Issue 28566
+Language/Libraries_and_Scripts/Exports/invalid_uri_t02: Pass # OK
+Language/Libraries_and_Scripts/Imports/invalid_uri_t02: Pass # OK
+Language/Libraries_and_Scripts/Parts/syntax_t06: Pass # OK
+Language/Statements/Labels/syntax_t03: Pass # OK
+Language/Statements/Switch/syntax_t02: Pass # OK
+Language/Expressions/Identifier_Reference/built_in_identifier_t35: Pass # OK, Issue 25732
+Language/Expressions/Identifier_Reference/built_in_identifier_t36: Pass # OK, Issue 25732
+Language/Expressions/Identifier_Reference/built_in_identifier_t37: Pass # OK, Issue 25732
+Language/Expressions/Identifier_Reference/built_in_not_dynamic_t14: Pass # OK, Issue 25732
 
 # dartk: JIT failures
 [ $compiler == dartk && $runtime == vm ]
@@ -191,4 +190,4 @@
 Language/Expressions/Constants/exception_t02: Crash
 
 # dartk: precompilation failures (debug)
-[ $compiler == dartkp && $runtime == dart_precompiled && $mode == debug ]
\ No newline at end of file
+[ $compiler == dartkp && $runtime == dart_precompiled && $mode == debug ]
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 05b9fe2..1d9ebc0 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -2,6 +2,9 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
+[$runtime == vm && $compiler == none && $system == fuchsia]
+*: Skip  # Tests not included in the image.
+
 [ $runtime == vm || $runtime == dart_precompiled ]
 
 # Failures ok in tests below. VM moves super initializer to end of list.
@@ -37,6 +40,9 @@
 LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Issue 13596
 LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Issue 13596
 
+[ $compiler == precompiler && $runtime == dart_precompiled && $mode == debug ]
+Language/Expressions/Function_Invocation/async_invokation_t06: Crash # Issue 28759
+
 [ $runtime == vm || $runtime == dart_precompiled ]
 LibTest/typed_data/Float32x4/reciprocalSqrt_A01_t01: Pass, Fail # co19 issue 599
 LibTest/typed_data/Float32x4/reciprocal_A01_t01: Pass, Fail # co19 issue 599
@@ -116,6 +122,14 @@
 Language/Expressions/Assignment/super_assignment_failed_t05: RuntimeError # Issue 25671
 Language/Expressions/Function_Invocation/async_generator_invokation_t08: Fail # Issue 25967
 Language/Expressions/Function_Invocation/async_generator_invokation_t10: Fail # Issue 25967
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t01: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t02: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t03: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t04: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t05: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t06: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t07: MissingCompileTimeError # Issue 24332
+Language/Expressions/Property_Extraction/Getter_Access_and_Method_Extraction/class_object_member_t08: MissingCompileTimeError # Issue 24332
 Language/Mixins/Mixin_Application/syntax_t16: CompileTimeError # Issue 25765
 Language/Mixins/declaring_constructor_t05: MissingCompileTimeError # Issue 24767
 Language/Mixins/declaring_constructor_t06: MissingCompileTimeError # Issue 24767
diff --git a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
index fe8672b..22f6cca 100644
--- a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
+++ b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
@@ -211,6 +211,7 @@
   @override
   void visitConstConstructorInvoke(
       NewExpression node, ConstructedConstantExpression constant, _) {
-    checkAccess(node, constant.target);
+    ConstructorElement constructor = constant.target;
+    checkAccess(node, constructor);
   }
 }
diff --git a/tests/compiler/dart2js/annotated_code_helper.dart b/tests/compiler/dart2js/annotated_code_helper.dart
index 4d6f8ec..5156e3c 100644
--- a/tests/compiler/dart2js/annotated_code_helper.dart
+++ b/tests/compiler/dart2js/annotated_code_helper.dart
@@ -44,24 +44,31 @@
   /// The annotations for the source code.
   final List<Annotation> annotations;
 
-  AnnotatedCode.internal(this.sourceCode, this.annotations);
+  List<int> _lineStarts;
+
+  AnnotatedCode(this.sourceCode, this.annotations);
+
+  AnnotatedCode.internal(this.sourceCode, this.annotations, this._lineStarts);
 
   /// Creates an [AnnotatedCode] by processing [annotatedCode]. Annotation of
   /// the form `@{...}` are converted into [Annotation]s and removed from the
   /// [annotatedCode] to process the source code.
-  factory AnnotatedCode(String annotatedCode) {
+  factory AnnotatedCode.fromText(String annotatedCode) {
     StringBuffer codeBuffer = new StringBuffer();
     List<Annotation> annotations = <Annotation>[];
     int index = 0;
     int offset = 0;
     int lineNo = 1;
     int columnNo = 1;
+    List<int> lineStarts = <int>[];
+    lineStarts.add(offset);
     while (index < annotatedCode.length) {
       int charCode = annotatedCode.codeUnitAt(index);
       switch (charCode) {
         case _LF:
           codeBuffer.write('\n');
           offset++;
+          lineStarts.add(offset);
           lineNo++;
           columnNo = 1;
           break;
@@ -72,6 +79,7 @@
           }
           codeBuffer.write('\n');
           offset++;
+          lineStarts.add(offset);
           lineNo++;
           columnNo = 1;
           break;
@@ -95,6 +103,58 @@
       }
       index++;
     }
-    return new AnnotatedCode.internal(codeBuffer.toString(), annotations);
+    lineStarts.add(offset);
+    return new AnnotatedCode.internal(
+        codeBuffer.toString(), annotations, lineStarts);
+  }
+
+  void _ensureLineStarts() {
+    if (_lineStarts == null) {
+      int index = 0;
+      int offset = 0;
+      _lineStarts = <int>[];
+      _lineStarts.add(offset);
+      while (index < sourceCode.length) {
+        int charCode = sourceCode.codeUnitAt(index);
+        switch (charCode) {
+          case _LF:
+            offset++;
+            _lineStarts.add(offset);
+            break;
+          case _CR:
+            if (index + 1 < sourceCode.length &&
+                sourceCode.codeUnitAt(index + 1) == _LF) {
+              index++;
+            }
+            offset++;
+            _lineStarts.add(offset);
+            break;
+          default:
+            offset++;
+        }
+        index++;
+      }
+      _lineStarts.add(offset);
+    }
+  }
+
+  void addAnnotation(int lineNo, int columnNo, String text) {
+    _ensureLineStarts();
+    int offset = _lineStarts[lineNo - 1] + (columnNo - 1);
+    annotations.add(new Annotation(lineNo, columnNo, offset, text));
+  }
+
+  String toText() {
+    StringBuffer sb = new StringBuffer();
+    List<Annotation> list = annotations.toList()
+      ..sort((a, b) => a.offset.compareTo(b.offset));
+    int offset = 0;
+    for (Annotation annotation in list) {
+      sb.write(sourceCode.substring(offset, annotation.offset));
+      sb.write('@{${annotation.text}}');
+      offset = annotation.offset;
+    }
+    sb.write(sourceCode.substring(offset));
+    return sb.toString();
   }
 }
diff --git a/tests/compiler/dart2js/categories_test.dart b/tests/compiler/dart2js/categories_test.dart
index 48fef4c..552fd49 100644
--- a/tests/compiler/dart2js/categories_test.dart
+++ b/tests/compiler/dart2js/categories_test.dart
@@ -23,7 +23,10 @@
     await runTest("import 'dart:async'; main() {}", "Server", 0);
     await runTest("import 'dart:html'; main() {}", "Client", 0);
     await runTest("import 'dart:html'; main() {}", "Server", 1);
-    await runTest("import 'dart:io'; main() {}", "Client", 1);
+    // Importing dart:io is temporarily allowed as a stopgap measure for the
+    // lack of config specific imports. Once that is added, this will be
+    // disallowed again.
+    await runTest("import 'dart:io'; main() {}", "Client", 0);
     await runTest("import 'dart:io'; main() {}", "Server", 0);
   });
 }
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index c21397e..38884fe 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -259,3 +259,40 @@
     }
   });
 }
+
+/// Returns a 'check' function that uses comments in [test] to drive checking.
+///
+/// The comments contains one or more 'present:' or 'absent:' tags, each
+/// followed by a quoted string. For example, the returned checker for the
+/// following text will ensure that the argument contains the three characters
+/// 'foo' and does not contain the two characters '""':
+///
+///    // present: "foo"
+///    // absent:  '""'
+checkerForAbsentPresent(String test) {
+  var matches = _directivePattern.allMatches(test).toList();
+  checker(String generated) {
+    if (matches.isEmpty) {
+      Expect.fail("No 'absent:' or 'present:' directives in '$test'");
+    }
+    for (Match match in matches) {
+      String directive = match.group(1);
+      String pattern = match.groups([2, 3]).where((s) => s != null).single;
+      if (directive == 'present') {
+        Expect.isTrue(generated.contains(pattern),
+            "Cannot find '$pattern' in:\n$generated");
+      } else {
+        assert(directive == 'absent');
+        Expect.isFalse(generated.contains(pattern),
+            "Must not find '$pattern' in:\n$generated");
+      }
+    }
+  }
+
+  return checker;
+}
+
+RegExp _directivePattern = new RegExp(
+    //      \1                     \2        \3
+    r'''// *(present|absent): *(?:"([^"]*)"|'([^'']*)')''',
+    multiLine: true);
diff --git a/tests/compiler/dart2js/constant_expression_evaluate_test.dart b/tests/compiler/dart2js/constant_expression_evaluate_test.dart
index a3ab7e2..3a3a685 100644
--- a/tests/compiler/dart2js/constant_expression_evaluate_test.dart
+++ b/tests/compiler/dart2js/constant_expression_evaluate_test.dart
@@ -7,12 +7,16 @@
 import 'dart:async';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/common/backend_api.dart';
+import 'package:compiler/src/constants/constructors.dart';
 import 'package:compiler/src/constants/evaluation.dart';
 import 'package:compiler/src/constants/expressions.dart';
 import 'package:compiler/src/constants/values.dart';
 import 'package:compiler/src/constant_system_dart.dart';
 import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/core_types.dart';
 import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/elements/resolution_types.dart';
 import 'memory_compiler.dart';
 
 class TestData {
@@ -36,13 +40,40 @@
 }
 
 class MemoryEnvironment implements Environment {
-  final Compiler compiler;
+  final Compiler _compiler;
   final Map<String, String> env;
 
-  MemoryEnvironment(this.compiler, [this.env = const <String, String>{}]);
+  MemoryEnvironment(this._compiler, [this.env = const <String, String>{}]);
 
   @override
   String readFromEnvironment(String name) => env[name];
+
+  @override
+  ResolutionInterfaceType substByContext(
+      ResolutionInterfaceType base, ResolutionInterfaceType target) {
+    return base.substByContext(target);
+  }
+
+  @override
+  ConstantConstructor getConstructorConstant(ConstructorElement constructor) {
+    return constructor.constantConstructor;
+  }
+
+  @override
+  ConstantExpression getFieldConstant(FieldElement field) {
+    return field.constant;
+  }
+
+  @override
+  ConstantExpression getLocalConstant(LocalVariableElement local) {
+    return local.constant;
+  }
+
+  @override
+  CommonElements get commonElements => _compiler.commonElements;
+
+  @override
+  BackendClasses get backendClasses => _compiler.backend.backendClasses;
 }
 
 const List<TestData> DATA = const [
diff --git a/tests/compiler/dart2js/constant_expression_test.dart b/tests/compiler/dart2js/constant_expression_test.dart
index d0cefd8..7d24703 100644
--- a/tests/compiler/dart2js/constant_expression_test.dart
+++ b/tests/compiler/dart2js/constant_expression_test.dart
@@ -11,6 +11,7 @@
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/elements.dart';
 import 'memory_compiler.dart';
+import 'constant_expression_evaluate_test.dart' show MemoryEnvironment;
 
 class TestData {
   /// Declarations needed for the [constants].
@@ -63,7 +64,7 @@
         text: '"ab"'),
     const ConstantData('identical', ConstantExpressionKind.FUNCTION),
     const ConstantData('true ? 0 : 1', ConstantExpressionKind.CONDITIONAL),
-    const ConstantData('proxy', ConstantExpressionKind.VARIABLE),
+    const ConstantData('proxy', ConstantExpressionKind.FIELD),
     const ConstantData('Object', ConstantExpressionKind.TYPE),
     const ConstantData('#name', ConstantExpressionKind.SYMBOL),
     const ConstantData('const [0, 1]', ConstantExpressionKind.LIST),
@@ -208,6 +209,7 @@
   CompilationResult result = await runCompiler(
       memorySourceFiles: {'main.dart': source}, options: ['--analyze-all']);
   Compiler compiler = result.compiler;
+  MemoryEnvironment environment = new MemoryEnvironment(compiler);
   var library = compiler.mainApp;
   constants.forEach((String name, ConstantData data) {
     FieldElement field = library.localLookup(name);
@@ -223,7 +225,8 @@
         "Unexpected text '${constant.toDartText()}' for contant, "
         "expected '${data.text}'.");
     if (data.type != null) {
-      String instanceType = constant.computeInstanceType().toString();
+      String instanceType =
+          constant.computeInstanceType(environment).toString();
       Expect.equals(
           data.type,
           instanceType,
@@ -231,7 +234,7 @@
           "`${constant.toDartText()}`, expected '${data.type}'.");
     }
     if (data.fields != null) {
-      Map instanceFields = constant.computeInstanceFields();
+      Map instanceFields = constant.computeInstanceFields(environment);
       Expect.equals(
           data.fields.length,
           instanceFields.length,
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 22d2c68..44bc108 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -40,7 +40,6 @@
 
 quarantined/http_test: Pass, Slow
 
-# Source information is not correct due to inlining.
 sourcemaps/source_mapping_operators_test: Pass, Slow
 sourcemaps/source_mapping_invokes_test: Pass, Slow
 
@@ -69,6 +68,7 @@
 value_range_test: Pass, Slow
 jsinterop/world_test: Pass, Slow
 sourcemaps/stacktrace_test: Pass, Slow
+kernel/visitor_test: Pass, Slow
 
 [ $mode == debug ]
 check_elements_invariants_test: Skip # Slow and only needs to be run in one
diff --git a/tests/compiler/dart2js/diagnostic_reporter_helper.dart b/tests/compiler/dart2js/diagnostic_reporter_helper.dart
index 679ef8c..0a706f7 100644
--- a/tests/compiler/dart2js/diagnostic_reporter_helper.dart
+++ b/tests/compiler/dart2js/diagnostic_reporter_helper.dart
@@ -6,9 +6,10 @@
 
 import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 import 'package:compiler/src/diagnostics/messages.dart';
-import 'package:compiler/src/diagnostics/spannable.dart';
 import 'package:compiler/src/diagnostics/source_span.dart';
+import 'package:compiler/src/diagnostics/spannable.dart';
 import 'package:compiler/src/elements/elements.dart';
+import 'package:front_end/src/fasta/scanner.dart';
 import 'options_helper.dart';
 
 abstract class DiagnosticReporterWrapper extends DiagnosticReporter {
@@ -63,6 +64,9 @@
   }
 
   @override
+  SourceSpan spanFromToken(Token token) => reporter.spanFromToken(token);
+
+  @override
   withCurrentElement(Element element, f()) {
     return reporter.withCurrentElement(element, f);
   }
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index dfca8b34..431fd4f 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -54,7 +54,7 @@
   }
 
   @override
-  Backend createBackend() {
+  JavaScriptBackend createBackend() {
     return new TestBackend(this);
   }
 
diff --git a/tests/compiler/dart2js/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
index 98defee..2d64709 100644
--- a/tests/compiler/dart2js/field_type_simple_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
@@ -550,7 +550,7 @@
   });
   runTest(TEST_15, <String, TestCallback>{
     'f': (closedWorld) {
-      ClassElement cls = closedWorld.backendClasses.indexableImplementation;
+      ClassElement cls = closedWorld.backendClasses.indexableClass;
       return new TypeMask.nonNullSubtype(cls, closedWorld);
     }
   });
diff --git a/tests/compiler/dart2js/incremental/compile_all.dart b/tests/compiler/dart2js/incremental/compile_all.dart
deleted file mode 100644
index ca1321a..0000000
--- a/tests/compiler/dart2js/incremental/compile_all.dart
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Helper file that can be used to manually test the stability of incremental
-// compilation.  Currently this test is not run automatically.
-
-import 'dart:async';
-
-import 'dart:io';
-
-import 'dart:developer' show UserTag;
-
-import 'package:dart2js_incremental/dart2js_incremental.dart'
-    show IncrementalCompiler;
-import 'package:compiler/src/source_file_provider.dart'
-    show FormattingDiagnosticHandler;
-
-import '../memory_source_file_helper.dart' show CompilerImpl;
-
-import '../memory_compiler.dart' show compilerFor;
-
-const bool verbose = false;
-
-main(List<String> arguments) {
-  Stopwatch sw = new Stopwatch()..start();
-  Map<String, String> sources = <String, String>{};
-  for (String argument in arguments) {
-    Uri uri = new Uri(scheme: 'memory', path: argument);
-    String source =
-        new File.fromUri(Uri.base.resolve(argument)).readAsStringSync();
-    sources['${uri.path}'] = source;
-  }
-  sw.stop();
-  print(sw.elapsedMilliseconds);
-  compileTests(sources);
-}
-
-void compileTests(Map<String, String> sources) {
-  int testCount = 0;
-  int skipCount = 0;
-  Set<String> crashes = new Set<String>();
-  CompilerImpl memoryCompiler = compilerFor(memorySourceFiles: sources);
-  FormattingDiagnosticHandler handler = memoryCompiler.handler;
-  handler.verbose = verbose;
-  var options = ['--analyze-main'];
-  if (true || verbose) options.add('--verbose');
-  IncrementalCompiler compiler = new IncrementalCompiler(
-      libraryRoot: memoryCompiler.libraryRoot,
-      inputProvider: memoryCompiler.provider,
-      outputProvider: memoryCompiler.userOutputProvider,
-      diagnosticHandler: memoryCompiler.handler,
-      packageRoot: memoryCompiler.options.packageRoot,
-      options: options);
-  Future.forEach(sources.keys, (String path) {
-    UserTag.defaultTag.makeCurrent();
-    if (!path.endsWith('_test.dart')) return new Future.value(null);
-    testCount++;
-    for (String brokenTest in brokenTests) {
-      if (path.endsWith(brokenTest)) {
-        print('Skipped broken test $path');
-        skipCount++;
-        return new Future.value(null);
-      }
-    }
-    Stopwatch sw = new Stopwatch()..start();
-    return compiler.compile(Uri.parse('memory:$path')).then((bool success) {
-      UserTag.defaultTag.makeCurrent();
-      sw.stop();
-      print('Compiled $path in ${sw.elapsedMilliseconds}');
-      sw
-        ..reset()
-        ..start();
-    }).catchError((error, trace) {
-      sw.stop();
-      print('$error\n$trace');
-      print('Crash when compiling $path after ${sw.elapsedMilliseconds}');
-      sw
-        ..reset()
-        ..start();
-      crashes.add(path);
-    });
-  }).then((_) {
-    percent(i) => '${(i/testCount*100).toStringAsFixed(3)}%';
-    print('''
-
-Total: $testCount tests
- * ${crashes.length} tests (${percent(crashes.length)}) crashed the compiler
- * $skipCount tests (${percent(skipCount)}) were skipped
-''');
-    for (String crash in crashes) {
-      print('Crashed: $crash');
-    }
-    if (!crashes.isEmpty) {
-      throw 'Test had crashes';
-    }
-  });
-}
-
-Set<String> brokenTests = new Set<String>.from([
-  // TODO(ahe): Fix the outputProvider to not throw an error.
-  "/dart2js_extra/deferred/deferred_class_library.dart",
-  "/dart2js_extra/deferred/deferred_class_library2.dart",
-  "/dart2js_extra/deferred/deferred_class_test.dart",
-  "/dart2js_extra/deferred/deferred_constant2_test.dart",
-  "/dart2js_extra/deferred/deferred_constant3_test.dart",
-  "/dart2js_extra/deferred/deferred_constant4_test.dart",
-  "/dart2js_extra/deferred/deferred_constant_test.dart",
-  "/dart2js_extra/deferred/deferred_function_library.dart",
-  "/dart2js_extra/deferred/deferred_function_test.dart",
-  "/dart2js_extra/deferred/deferred_overlapping_lib1.dart",
-  "/dart2js_extra/deferred/deferred_overlapping_lib2.dart",
-  "/dart2js_extra/deferred/deferred_overlapping_lib3.dart",
-  "/dart2js_extra/deferred/deferred_overlapping_test.dart",
-  "/dart2js_extra/deferred/deferred_unused_classes_test.dart",
-  "/language/deferred_closurize_load_library_lib.dart",
-  "/language/deferred_closurize_load_library_test.dart",
-  "/language/deferred_constraints_constants_lib.dart",
-  "/language/deferred_constraints_constants_old_syntax_lib.dart",
-  "/language/deferred_constraints_constants_old_syntax_test.dart",
-  "/language/deferred_constraints_constants_test.dart",
-  "/language/deferred_constraints_lib.dart",
-  "/language/deferred_constraints_lib2.dart",
-  "/language/deferred_constraints_old_syntax_lib.dart",
-  "/language/deferred_constraints_type_annotation_old_syntax_test.dart",
-  "/language/deferred_constraints_type_annotation_test.dart",
-  "/language/deferred_duplicate_prefix1_test.dart",
-  "/language/deferred_duplicate_prefix2_test.dart",
-  "/language/deferred_duplicate_prefix3_test.dart",
-  "/language/deferred_load_inval_code_lib.dart",
-  "/language/deferred_load_inval_code_test.dart",
-  "/language/deferred_load_library_wrong_args_lib.dart",
-  "/language/deferred_load_library_wrong_args_test.dart",
-  "/language/deferred_no_prefix_test.dart",
-  "/language/deferred_no_such_method_lib.dart",
-  "/language/deferred_no_such_method_test.dart",
-  "/language/deferred_not_loaded_check_lib.dart",
-  "/language/deferred_not_loaded_check_test.dart",
-  "/language/deferred_prefix_constraints_lib.dart",
-  "/language/deferred_prefix_constraints_lib2.dart",
-  "/language/deferred_shadow_load_library_lib.dart",
-  "/language/deferred_shadow_load_library_test.dart",
-
-  "/language/bad_constructor_test.dart",
-  "/language/black_listed_test.dart",
-  "/language/built_in_identifier_illegal_test.dart",
-  "/language/built_in_identifier_prefix_test.dart",
-  "/language/built_in_identifier_test.dart",
-  "/language/class_cycle2_test.dart",
-  "/language/class_syntax_test.dart",
-  "/language/cyclic_typedef_test.dart",
-  "/language/external_test.dart",
-  "/language/factory3_negative_test.dart",
-  "/language/generic_field_mixin4_test.dart",
-  "/language/generic_field_mixin5_test.dart",
-  "/language/interface_cycle_test.dart",
-  "/language/interface_injection1_negative_test.dart",
-  "/language/interface_injection2_negative_test.dart",
-  "/language/internal_library_test.dart",
-  "/language/malformed_inheritance_test.dart",
-  "/language/metadata_test.dart",
-  "/language/method_override2_test.dart",
-  "/language/mixin_illegal_syntax_test.dart",
-  "/language/mixin_invalid_inheritance1_test.dart",
-  "/language/null_test.dart",
-  "/language/override_inheritance_generic_test.dart",
-  "/language/prefix18_negative_test.dart",
-  "/language/prefix3_negative_test.dart",
-  "/language/script2_negative_test.dart",
-  "/language/setter_declaration2_negative_test.dart",
-  "/language/source_self_negative_test.dart",
-  "/language/syntax_test.dart",
-  "/language/type_variable_bounds2_test.dart",
-  "/language/type_variable_conflict2_test.dart",
-  "/language/type_variable_field_initializer_test.dart",
-  "/language/type_variable_nested_test.dart",
-  "/language/vm/reflect_core_vm_test.dart",
-  "/language/vm/regress_14903_test.dart",
-]);
diff --git a/tests/compiler/dart2js/incremental/hello_test.dart b/tests/compiler/dart2js/incremental/hello_test.dart
deleted file mode 100644
index c034e05..0000000
--- a/tests/compiler/dart2js/incremental/hello_test.dart
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test a sequence of modifications to hello-world which used to cause problems
-// on Try Dart.
-
-import 'dart:io' show Platform;
-
-import 'dart:async' show Future;
-
-import 'package:dart2js_incremental/dart2js_incremental.dart'
-    show IncrementalCompiler;
-
-import 'package:compiler/compiler.dart' show Diagnostic;
-
-import 'package:compiler/src/null_compiler_output.dart' show NullCompilerOutput;
-
-import 'package:compiler/src/old_to_new_api.dart'
-    show LegacyCompilerDiagnostics;
-
-import 'package:async_helper/async_helper.dart' show asyncTest;
-
-import 'package:expect/expect.dart' show Expect;
-
-import '../memory_source_file_helper.dart' show MemorySourceFileProvider;
-
-var tests = {
-  '/test1.dart': '''
-var greeting = "Hello, World!";
-
-void main() {
-  print(greeting);
-}
-''',
-  '/test2.dart': '''
-va greeting = "Hello, World!";
-
-void main() {
-  print(greeting);
-}
-''',
-  '/test3.dart': '''
- greeting = "Hello, World!";
-
-void main() {
-  print(greeting);
-}
-''',
-  '/test4.dart': '''
-in greeting = "Hello, World!";
-
-void main() {
-  print(greeting);
-}
-''',
-  '/test5.dart': '''
-int greeting = "Hello, World!";
-
-void main() {
-  print(greeting);
-}
-''',
-};
-
-var testResults = {
-  '/test1.dart': true,
-  '/test2.dart': true,
-  '/test3.dart': false,
-  '/test4.dart': false,
-  '/test5.dart': true,
-};
-
-main() {
-  Uri libraryRoot = Uri.base.resolve('sdk/');
-  Uri packageConfig = Uri.base.resolve('.packages');
-  MemorySourceFileProvider provider = new MemorySourceFileProvider(tests);
-  asyncTest(() => runTests(libraryRoot, packageConfig, provider));
-}
-
-Future runTests(
-    Uri libraryRoot, Uri packageConfig, MemorySourceFileProvider provider) {
-  IncrementalCompiler compiler = new IncrementalCompiler(
-      diagnosticHandler: new LegacyCompilerDiagnostics(handler),
-      inputProvider: provider,
-      outputProvider: const NullCompilerOutput(),
-      options: ['--analyze-main'],
-      libraryRoot: libraryRoot,
-      packageConfig: packageConfig);
-
-  return Future.forEach(tests.keys, (String testName) {
-    Uri testUri = Uri.parse('memory:$testName');
-    return compiler.compile(testUri).then((bool success) {
-      Expect.equals(testResults[testName], success,
-          'Compilation unexpectedly ${success ? "succeed" : "failed"}.');
-    });
-  });
-}
-
-void handler(Uri uri, int begin, int end, String message, Diagnostic kind) {
-  if (kind != Diagnostic.VERBOSE_INFO) {
-    print('$uri:$begin:$end:$message:$kind');
-  }
-}
diff --git a/tests/compiler/dart2js/inference/inference_test_helper.dart b/tests/compiler/dart2js/inference/inference_test_helper.dart
index 4a916af..43fb2cc 100644
--- a/tests/compiler/dart2js/inference/inference_test_helper.dart
+++ b/tests/compiler/dart2js/inference/inference_test_helper.dart
@@ -15,7 +15,7 @@
 import 'enumerator.dart';
 
 checkCode(String annotatedCode) async {
-  AnnotatedCode code = new AnnotatedCode(annotatedCode);
+  AnnotatedCode code = new AnnotatedCode.fromText(annotatedCode);
   Map<Id, String> expectedMap = computeExpectedMap(code);
   Compiler compiler =
       compilerFor(memorySourceFiles: {'main.dart': code.sourceCode});
diff --git a/tests/compiler/dart2js/js_constant_test.dart b/tests/compiler/dart2js/js_constant_test.dart
index 14ab28a..3ebf646 100644
--- a/tests/compiler/dart2js/js_constant_test.dart
+++ b/tests/compiler/dart2js/js_constant_test.dart
@@ -17,11 +17,6 @@
 """;
 
 main() {
-  RegExp directivePattern = new RegExp(
-      //      \1                    \2        \3
-      r'''// *(present|absent): (?:"([^"]*)"|'([^'']*)')''',
-      multiLine: true);
-
   Future check(String test) {
     Uri uri = new Uri(scheme: 'dart', path: 'test');
     var compiler = compilerFor(test, uri, expectedErrors: 0);
@@ -29,19 +24,7 @@
       var element = findElement(compiler, 'main');
       var backend = compiler.backend;
       String generated = backend.getGeneratedCode(element);
-
-      for (Match match in directivePattern.allMatches(test)) {
-        String directive = match.group(1);
-        String pattern = match.groups([2, 3]).where((s) => s != null).single;
-        if (directive == 'present') {
-          Expect.isTrue(generated.contains(pattern),
-              "Cannot find '$pattern' in:\n$generated");
-        } else {
-          assert(directive == 'absent');
-          Expect.isFalse(generated.contains(pattern),
-              "Must not find '$pattern' in:\n$generated");
-        }
-      }
+      checkerForAbsentPresent(test)(generated);
     });
   }
 
diff --git a/tests/compiler/dart2js/js_spec_optimization_test.dart b/tests/compiler/dart2js/js_spec_optimization_test.dart
index 4b5df36..d81a06f 100644
--- a/tests/compiler/dart2js/js_spec_optimization_test.dart
+++ b/tests/compiler/dart2js/js_spec_optimization_test.dart
@@ -85,31 +85,15 @@
 """;
 
 main() {
-  RegExp directivePattern = new RegExp(
-      //      \1                    \2        \3
-      r'''// *(present|absent): (?:"([^"]*)"|'([^'']*)')''',
-      multiLine: true);
-
   Future check(String test) {
+    var checker = checkerForAbsentPresent(test);
     Uri uri = new Uri(scheme: 'dart', path: 'test');
     var compiler = compilerFor(test, uri, expectedErrors: 0);
     return compiler.run(uri).then((_) {
       var element = findElement(compiler, 'main');
       var backend = compiler.backend;
       String generated = backend.getGeneratedCode(element);
-
-      for (Match match in directivePattern.allMatches(test)) {
-        String directive = match.group(1);
-        String pattern = match.groups([2, 3]).where((s) => s != null).single;
-        if (directive == 'present') {
-          Expect.isTrue(generated.contains(pattern),
-              "Cannot find '$pattern' in:\n$generated");
-        } else {
-          assert(directive == 'absent');
-          Expect.isFalse(generated.contains(pattern),
-              "Must not find '$pattern' in:\n$generated");
-        }
-      }
+      checker(generated);
     });
   }
 
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index 491356c3..4f301af 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -57,7 +57,7 @@
         setThrows: (b) => actualThrows = b,
         setIsAllocation: (b) => actualNew = b,
         setUseGvn: (b) => actualGvn = b,
-        lookupType: (t) => t,
+        lookupType: (t, {required}) => t,
         typesReturned: actualReturns,
         typesInstantiated: actualCreates,
         objectType: OBJECT,
diff --git a/tests/compiler/dart2js/kernel/closed_world_test.dart b/tests/compiler/dart2js/kernel/closed_world_test.dart
index 6a3f583..fd62785 100644
--- a/tests/compiler/dart2js/kernel/closed_world_test.dart
+++ b/tests/compiler/dart2js/kernel/closed_world_test.dart
@@ -92,7 +92,6 @@
         const TreeShakingEnqueuerStrategy(),
         compiler.globalDependencies,
         backend,
-        compiler.cacheStrategy,
         'enqueuer from kernel');
     // TODO(johnniwinther): Store backend info separately. This replacement is
     // made to reset a field in [TypeVariableHandler] that prevents it from
diff --git a/tests/compiler/dart2js/kernel/getters_setters_test.dart b/tests/compiler/dart2js/kernel/getters_setters_test.dart
index e6e6083..31a3809 100644
--- a/tests/compiler/dart2js/kernel/getters_setters_test.dart
+++ b/tests/compiler/dart2js/kernel/getters_setters_test.dart
@@ -25,6 +25,38 @@
 ''';
       return check(code);
     });
+
+    test('super get', () {
+      String code = '''
+class A {
+  int get foo => 1;
+}
+
+class B extends A {
+
+  int get rotations => super.foo * 3;
+}
+
+main() => new B().foo;
+''';
+      return check(code);
+    });
+
+    test('super get no such method', () {
+      String code = '''
+class A {
+  static int get foo => 1;
+}
+
+class B extends A {
+
+  int get rotations => super.nothing * 3;
+}
+
+main() => new B().foo;
+''';
+      return check(code);
+    });
   });
 
   group('compile setters with kernel', () {
@@ -53,4 +85,39 @@
       return check(code);
     });
   });
+
+  test('super set', () {
+    String code = '''
+class A {
+  set ferocious(int newFerocious) {}
+}
+
+class B extends A {
+  bar() {
+    super.ferocious = 87;
+  }
+}
+main() {
+  new B().bar();
+}''';
+    return check(code);
+  });
+
+  test('super set no such method', () {
+    String code = '''
+class A {
+  final ferocious = 0;
+  noSuchMethod(_) => 42;
+}
+
+class B extends A {
+  bar() {
+    super.ferocious = 87;
+  }
+}
+main() {
+  new B().bar();
+}''';
+    return check(code);
+  });
 }
diff --git a/tests/compiler/dart2js/kernel/impact_test.dart b/tests/compiler/dart2js/kernel/impact_test.dart
index e011e2d..b380732 100644
--- a/tests/compiler/dart2js/kernel/impact_test.dart
+++ b/tests/compiler/dart2js/kernel/impact_test.dart
@@ -11,8 +11,11 @@
 import 'package:compiler/src/common/resolution.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/constants/expressions.dart';
-import 'package:compiler/src/elements/resolution_types.dart';
 import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/elements/resolution_types.dart';
+import 'package:compiler/src/js_backend/backend.dart';
+import 'package:compiler/src/kernel/element_adapter.dart';
+import 'package:compiler/src/kernel/world_builder.dart';
 import 'package:compiler/src/resolution/registry.dart';
 import 'package:compiler/src/resolution/tree_elements.dart';
 import 'package:compiler/src/ssa/kernel_impact.dart';
@@ -21,13 +24,24 @@
 import 'package:compiler/src/universe/feature.dart';
 import 'package:compiler/src/universe/use.dart';
 import 'package:expect/expect.dart';
+import 'package:kernel/ast.dart' as ir;
 import '../memory_compiler.dart';
 import '../serialization/test_helper.dart';
 
 const Map<String, String> SOURCE = const <String, String>{
-  'main.dart': r'''
-import 'helper.dart';
+  // Pretend this is a dart2js_native test to allow use of 'native' keyword.
+  'sdk/tests/compiler/dart2js_native/main.dart': r'''
+import 'dart:_foreign_helper';
+import 'dart:_js_helper';
+import 'dart:_interceptors';
+import 'dart:_native_typed_data';
+import 'dart:indexed_db';
 import 'dart:html';
+import 'dart:html_common';
+import 'dart:math';
+import 'dart:typed_data';
+import 'dart:web_sql';
+import 'helper.dart';
 
 main() {
   testEmpty();
@@ -170,6 +184,16 @@
   testEnum();
   testStaticGenericMethod();
   testInstanceGenericMethod();
+  testDynamicPrivateMethodInvoke();
+  testJSCall();
+  testNativeMethod();
+  testNativeMethodCreates();
+  testNativeMethodReturns();
+  testNativeField(null);
+  testMixinInstantiation();
+  testNamedMixinInstantiation();
+  testGenericMixinInstantiation();
+  testGenericNamedMixinInstantiation();
 }
 
 testEmpty() {}
@@ -594,8 +618,33 @@
 testInstanceGenericMethod() {
   new GenericClass<int, String>.generative().genericMethod<bool>(false);
 }
+
+testDynamicPrivateMethodInvoke([o]) => o._privateMethod();
+testJSCall() => JS('int|bool|NativeUint8List|Rectangle|IdbFactory|'
+    'SqlDatabase|TypedData|ContextAttributes', '#', null);
+@JSName('foo')
+@SupportedBrowser(SupportedBrowser.CHROME)
+testNativeMethod() native;
+@Creates('int|Null|JSArray')
+testNativeMethodCreates() native;
+@Returns('String|Null|JSArray')
+testNativeMethodReturns() native;
+
+@Native("NativeClass")
+class NativeClass {
+  @annotation_Creates_SerializedScriptValue
+  final Object field;
+
+  factory NativeClass._() { throw new UnsupportedError("Not supported"); }
+}
+testNativeField(NativeClass c) => c.field;
+testMixinInstantiation() => new Sub();
+testNamedMixinInstantiation() => new NamedMixin();
+testGenericMixinInstantiation() => new GenericSub<int, String>();
+testGenericNamedMixinInstantiation() => new GenericNamedMixin<int, String>();
 ''',
-  'helper.dart': '''
+  'sdk/tests/compiler/dart2js_native/helper.dart': '''
+import 'dart:_js_helper';
 class Class {
   const Class.generative();
   factory Class.fact() => null;
@@ -610,6 +659,20 @@
 }
 typedef Typedef();
 typedef X GenericTypedef<X, Y>(Y y);
+
+class Super {}
+class Mixin1 {}
+class Mixin2 {}
+class Sub extends Super with Mixin1, Mixin2 {}
+class NamedMixin = Super with Mixin1, Mixin2;
+
+class GenericSuper<X1, Y1> {}
+class GenericMixin1<X2, Y2> {}
+class GenericMixin2<X3, Y3> {}
+class GenericSub<X4, Y4> extends GenericSuper<X4, Y4>
+    with GenericMixin1<X4, Y4>, GenericMixin2<X4, Y4> {}
+class GenericNamedMixin<X5, Y5> = GenericSuper<X5, Y5>
+    with GenericMixin1<X5, Y5>, GenericMixin2<X5, Y5>;
 ''',
 };
 
@@ -617,7 +680,8 @@
   bool fullTest = args.contains('--full');
   asyncTest(() async {
     enableDebugMode();
-    Uri entryPoint = Uri.parse('memory:main.dart');
+    Uri entryPoint =
+        Uri.parse('memory:sdk/tests/compiler/dart2js_native/main.dart');
     Compiler compiler = compilerFor(
         entryPoint: entryPoint,
         memorySourceFiles: SOURCE,
@@ -627,63 +691,43 @@
           Flags.enableAssertMessage
         ]);
     compiler.resolution.retainCachesForTesting = true;
-    await compiler.run(entryPoint);
-    checkLibrary(compiler, compiler.mainApp, fullTest: fullTest);
-    if (fullTest) {
-      // TODO(johnniwinther): Handle all libraries for `!fullTest`.
-      compiler.libraryLoader.libraries.forEach((LibraryElement library) {
-        if (library == compiler.mainApp) return;
-        checkLibrary(compiler, library, fullTest: fullTest);
-      });
-    }
+    Expect.isTrue(await compiler.run(entryPoint));
+    JavaScriptBackend backend = compiler.backend;
+    KernelElementAdapter kernelElementAdapter =
+        new KernelWorldBuilder(compiler.reporter, backend.kernelTask.program);
+
+    checkLibrary(compiler, kernelElementAdapter, compiler.mainApp,
+        fullTest: fullTest);
+    compiler.libraryLoader.libraries.forEach((LibraryElement library) {
+      if (library == compiler.mainApp) return;
+      checkLibrary(compiler, kernelElementAdapter, library, fullTest: fullTest);
+    });
   });
 }
 
-void checkLibrary(Compiler compiler, LibraryElement library,
+void checkLibrary(Compiler compiler, KernelElementAdapter kernelElementAdapter,
+    LibraryElement library,
     {bool fullTest: false}) {
   library.forEachLocalMember((AstElement element) {
     if (element.isClass) {
       ClassElement cls = element;
       cls.forEachLocalMember((AstElement member) {
-        checkElement(compiler, member, fullTest: fullTest);
+        checkElement(compiler, kernelElementAdapter, member,
+            fullTest: fullTest);
       });
     } else if (element.isTypedef) {
       // Skip typedefs.
     } else {
-      checkElement(compiler, element, fullTest: fullTest);
+      checkElement(compiler, kernelElementAdapter, element, fullTest: fullTest);
     }
   });
 }
 
-void checkElement(Compiler compiler, AstElement element,
+void checkElement(Compiler compiler, KernelElementAdapter kernelElementAdapter,
+    AstElement element,
     {bool fullTest: false}) {
-  if (!fullTest) {
-    if (element.library.isPlatformLibrary) {
-      // TODO(johnniwinther): Enqueue these elements for `!fullTest`.
-      // Test only selected elements in web-related platform libraries since
-      // this unittest otherwise takes too long to run.
-      switch (element.library.canonicalUri.path) {
-        case 'html':
-          if ('$element' ==
-              'function(_ValidatingTreeSanitizer#_sanitizeUntrustedElement)') {
-            break;
-          }
-          return;
-        case 'web_gl':
-          if ('$element' ==
-              'function(RenderingContext#getFramebufferAttachmentParameter)') {
-            break;
-          }
-          return;
-        case 'indexed_db':
-          if ('$element' == 'field(ObjectStore#keyPath)') {
-            break;
-          }
-          return;
-        case 'web_audio':
-          return;
-      }
-    }
+  if (!fullTest && element.library.isPlatformLibrary) {
+    return;
   }
   if (element.isConstructor) {
     ConstructorElement constructor = element;
@@ -695,12 +739,24 @@
   if (!fullTest && !compiler.resolution.hasResolutionImpact(element)) {
     return;
   }
-  ResolutionImpact astImpact = compiler.resolution.getResolutionImpact(element);
-  astImpact = laxImpact(compiler, element, astImpact);
-  ResolutionImpact kernelImpact = build(compiler, element.resolvedAst);
-  Expect.isNotNull(kernelImpact, 'No impact computed for $element');
-  testResolutionImpactEquivalence(
-      astImpact, kernelImpact, const CheckStrategy());
+  compiler.reporter.withCurrentElement(element.implementation, () {
+    ResolutionImpact astImpact =
+        compiler.resolution.getResolutionImpact(element);
+    astImpact = laxImpact(compiler, element, astImpact);
+    ResolutionImpact kernelImpact1 = build(compiler, element.resolvedAst);
+    ir.Member member = getIrMember(compiler, element.resolvedAst);
+    Expect.isNotNull(kernelImpact1, 'No impact computed for $element');
+    ResolutionImpact kernelImpact2 =
+        buildKernelImpact(member, kernelElementAdapter);
+    Expect.isNotNull(kernelImpact2, 'No impact computed for $member');
+    testResolutionImpactEquivalence(astImpact, kernelImpact1,
+        strategy: const CheckStrategy());
+    KernelEquivalence equivalence = new KernelEquivalence(kernelElementAdapter);
+    testResolutionImpactEquivalence(astImpact, kernelImpact2,
+        strategy: new CheckStrategy(
+            elementEquivalence: equivalence.entityEquivalence,
+            typeEquivalence: equivalence.typeEquivalence));
+  });
 }
 
 /// Lax the precision of [impact] to meet expectancy of the corresponding impact
diff --git a/tests/compiler/dart2js/kernel/loops_test.dart b/tests/compiler/dart2js/kernel/loops_test.dart
index b257e4b..13a75e7 100644
--- a/tests/compiler/dart2js/kernel/loops_test.dart
+++ b/tests/compiler/dart2js/kernel/loops_test.dart
@@ -52,10 +52,8 @@
   }
   return sum;
 }''';
-    // TODO(het): Check that the code is alpha-equivalent. That is,
-    // the same except for variable names.
     return check(code);
-  }, skip: "The output is the same, with one variable renamed");
+  });
 
   test('for-in loop optimized', () {
     String code = '''
diff --git a/tests/compiler/dart2js/link_helper.dart b/tests/compiler/dart2js/link_helper.dart
index dc0fe6f..00e82ae 100644
--- a/tests/compiler/dart2js/link_helper.dart
+++ b/tests/compiler/dart2js/link_helper.dart
@@ -4,8 +4,8 @@
 
 library link_helper;
 
-import 'package:compiler/src/util/util.dart';
-import 'package:compiler/src/util/util_implementation.dart';
+import 'package:front_end/src/fasta/util/link.dart';
+import 'package:front_end/src/fasta/util/link_implementation.dart';
 
 Link LinkFromList(List list) {
   switch (list.length) {
diff --git a/tests/compiler/dart2js/map_tracer_test.dart b/tests/compiler/dart2js/map_tracer_test.dart
index bab5e22..ed48c4a 100644
--- a/tests/compiler/dart2js/map_tracer_test.dart
+++ b/tests/compiler/dart2js/map_tracer_test.dart
@@ -211,8 +211,8 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(generateTest(allocation), uri,
       expectedErrors: 0, expectedWarnings: 1);
-  compiler.closeResolution();
   asyncTest(() => compiler.run(uri).then((_) {
+        compiler.closeResolution();
         var keyType, valueType;
         var typesInferrer = compiler.globalInference.typesInferrerInternal;
         var closedWorld = typesInferrer.closedWorld;
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index 03252d1..8e348ac8 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -22,7 +22,6 @@
 /// However, consider that a single concise diagnostic is easier to understand,
 /// so try to change error reporting logic before adding an exception.
 final Set<MessageKind> kindsWithExtraMessages = new Set<MessageKind>.from([
-  // If you add something here, please file a *new* bug report.
   // See http://dartbug.com/18361:
   MessageKind.CANNOT_EXTEND_MALFORMED,
   MessageKind.CANNOT_IMPLEMENT_MALFORMED,
@@ -42,6 +41,7 @@
   MessageKind.UNIMPLEMENTED_METHOD,
   MessageKind.UNIMPLEMENTED_METHOD_ONE,
   MessageKind.VAR_FUNCTION_TYPE_PARAMETER,
+  MessageKind.UNMATCHED_TOKEN,
 ]);
 
 /// Most messages can be tested without causing a fatal error. Add an exception
diff --git a/tests/compiler/dart2js/missing_file_test.dart b/tests/compiler/dart2js/missing_file_test.dart
index 96ccf03..a2b98b2 100644
--- a/tests/compiler/dart2js/missing_file_test.dart
+++ b/tests/compiler/dart2js/missing_file_test.dart
@@ -61,15 +61,23 @@
 
     await runTest(Uri.parse('dart:foo'), error: MessageKind.LIBRARY_NOT_FOUND);
 
-    await runTest(Uri.parse('dart:io'),
-        error: MessageKind.LIBRARY_NOT_SUPPORTED,
+    await runTest(Uri.parse('dart:_mirror_helper'),
+        error: MessageKind.INTERNAL_LIBRARY,
         info: MessageKind.DISALLOWED_LIBRARY_IMPORT);
 
     await runTest(Uri.parse('memory:bar.dart'),
         error: MessageKind.LIBRARY_NOT_FOUND);
 
-    await runTest(Uri.parse('memory:baz.dart'),
-        error: MessageKind.LIBRARY_NOT_SUPPORTED,
-        info: MessageKind.DISALLOWED_LIBRARY_IMPORT);
+    // Importing dart:io is temporarily allowed as a stopgap measure for the
+    // lack of config specific imports. Once that is added, this will be
+    // disallowed again.
+
+    //await runTest(Uri.parse('dart:io'),
+    //    error: MessageKind.LIBRARY_NOT_SUPPORTED,
+    //    info: MessageKind.DISALLOWED_LIBRARY_IMPORT);
+
+    //await runTest(Uri.parse('memory:baz.dart'),
+    //    error: MessageKind.LIBRARY_NOT_SUPPORTED,
+    //    info: MessageKind.DISALLOWED_LIBRARY_IMPORT);
   });
 }
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index c6506fd..97ad29f 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -98,7 +98,7 @@
   'Resource': 'class Resource {}',
   'StackTrace': 'abstract class StackTrace {}',
   'String': 'class String implements Pattern {}',
-  'Symbol': 'class Symbol { final name; const Symbol(this.name); }',
+  'Symbol': 'class Symbol { final _name; const Symbol(this._name); }',
   'Type': 'class Type {}',
   'Pattern': 'abstract class Pattern {}',
   '_genericNoSuchMethod': '_genericNoSuchMethod(a,b,c,d,e) {}',
diff --git a/tests/compiler/dart2js/modulo_remainder_test.dart b/tests/compiler/dart2js/modulo_remainder_test.dart
index a391a34..eeec8593 100644
--- a/tests/compiler/dart2js/modulo_remainder_test.dart
+++ b/tests/compiler/dart2js/modulo_remainder_test.dart
@@ -67,26 +67,8 @@
 """;
 
 main() {
-  RegExp directivePattern = new RegExp(
-      //      \1                    \2        \3
-      r'''// *(present|absent): (?:"([^"]*)"|'([^'']*)')''',
-      multiLine: true);
-
   Future check(String test) {
-    return compile(test, entry: 'foo', check: (String generated) {
-      for (Match match in directivePattern.allMatches(test)) {
-        String directive = match.group(1);
-        String pattern = match.groups([2, 3]).where((s) => s != null).single;
-        if (directive == 'present') {
-          Expect.isTrue(generated.contains(pattern),
-              "Cannot find '$pattern' in:\n$generated");
-        } else {
-          assert(directive == 'absent');
-          Expect.isFalse(generated.contains(pattern),
-              "Must not find '$pattern' in:\n$generated");
-        }
-      }
-    });
+    return compile(test, entry: 'foo', check: checkerForAbsentPresent(test));
   }
 
   asyncTest(() => Future.wait([
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index 36472bb..2dbeced 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -4,42 +4,38 @@
 
 library parser_helper;
 
-import "package:expect/expect.dart";
+import 'package:expect/expect.dart';
 
-import "package:compiler/src/elements/elements.dart";
+import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/id_generator.dart';
-import "package:compiler/src/tree/tree.dart";
-import "package:compiler/src/parser/element_listener.dart";
-import "package:compiler/src/parser/node_listener.dart";
-import "package:compiler/src/parser/parser.dart";
-import "package:compiler/src/parser/partial_parser.dart";
-import "package:compiler/src/scanner/string_scanner.dart";
-import "package:compiler/src/tokens/token.dart";
-import "package:compiler/src/tokens/token_constants.dart";
-import "package:compiler/src/io/source_file.dart";
-import "package:compiler/src/util/util.dart";
+import 'package:compiler/src/tree/tree.dart';
+import 'package:compiler/src/parser/element_listener.dart';
+import 'package:compiler/src/parser/node_listener.dart';
+import 'package:compiler/src/parser/diet_parser_task.dart';
+import 'package:front_end/src/fasta/parser.dart' hide parse;
+import 'package:front_end/src/fasta/scanner.dart' hide scan;
+import 'package:compiler/src/io/source_file.dart';
+import 'package:compiler/src/util/util.dart';
 
-import "package:compiler/src/elements/modelx.dart"
+import 'package:compiler/src/elements/modelx.dart'
     show CompilationUnitElementX, ElementX, LibraryElementX;
 
-import "package:compiler/src/compiler.dart";
+import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/options.dart';
-import "package:compiler/src/diagnostics/source_span.dart";
-import "package:compiler/src/diagnostics/spannable.dart";
-import "package:compiler/src/diagnostics/diagnostic_listener.dart";
-import "package:compiler/src/diagnostics/messages.dart";
-import "package:compiler/src/script.dart";
+import 'package:compiler/src/diagnostics/source_span.dart';
+import 'package:compiler/src/diagnostics/spannable.dart';
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/script.dart';
 
-import "options_helper.dart";
+import 'options_helper.dart';
 
-export "package:compiler/src/diagnostics/diagnostic_listener.dart";
-export 'package:compiler/src/parser/listener.dart';
+export 'package:front_end/src/fasta/parser.dart' hide parse;
+export 'package:front_end/src/fasta/scanner.dart' hide scan;
+export 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 export 'package:compiler/src/parser/node_listener.dart';
-export 'package:compiler/src/parser/parser.dart';
-export 'package:compiler/src/parser/partial_parser.dart';
-export 'package:compiler/src/parser/partial_elements.dart';
-export "package:compiler/src/tokens/token.dart";
-export "package:compiler/src/tokens/token_constants.dart";
+export 'package:compiler/src/parser/diet_parser_task.dart';
+export 'package:front_end/src/fasta/scanner/token_constants.dart';
 
 class LoggerCanceler extends DiagnosticReporter {
   DiagnosticOptions get options => const MockDiagnosticOptions();
@@ -56,6 +52,8 @@
     throw 'unsupported operation';
   }
 
+  SourceSpan spanFromToken(token) => null;
+
   void reportError(DiagnosticMessage message,
       [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
     log(message);
@@ -92,7 +90,7 @@
   bool get hasReportedError => false;
 }
 
-Token scan(String text) => new StringScanner.fromString(text).tokenize();
+Token scan(String text) => new StringScanner(text).tokenize();
 
 Node parseBodyCode(String text, Function parseMethod,
     {DiagnosticReporter reporter}) {
diff --git a/tests/compiler/dart2js/parser_test.dart b/tests/compiler/dart2js/parser_test.dart
index 0487450..4a1fcc7 100644
--- a/tests/compiler/dart2js/parser_test.dart
+++ b/tests/compiler/dart2js/parser_test.dart
@@ -306,7 +306,12 @@
 
   void reportError(DiagnosticMessage message,
       [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportFatalError(message.spannable);
+    assert(token != -1);
+    throw this;
+  }
+
+  spanFromToken(Token token) {
+    this.token = token.kind;
   }
 
   void log(message) {
diff --git a/tests/compiler/dart2js/platform_consistency_test.dart b/tests/compiler/dart2js/platform_consistency_test.dart
index 5d6e638..59b257c 100644
--- a/tests/compiler/dart2js/platform_consistency_test.dart
+++ b/tests/compiler/dart2js/platform_consistency_test.dart
@@ -7,8 +7,6 @@
 import "package:compiler/compiler_new.dart";
 import "package:expect/expect.dart";
 
-Uri unsupported = Uri.parse("unsupported:");
-
 main() async {
   CompilerInput input = new CompilerSourceFileProvider();
   Map<String, Uri> client =
@@ -22,7 +20,8 @@
 
   for (String libraryName in shared.keys) {
     test(Map<String, Uri> m) {
-      if (m[libraryName] != unsupported && shared[libraryName] != unsupported) {
+      if (m[libraryName].scheme != 'unsupported' &&
+          shared[libraryName].scheme != 'unsupported') {
         Expect.equals(shared[libraryName], m[libraryName]);
       }
     }
diff --git a/tests/compiler/dart2js/scanner_offset_length_test.dart b/tests/compiler/dart2js/scanner_offset_length_test.dart
index 5239f1c..f03e393 100644
--- a/tests/compiler/dart2js/scanner_offset_length_test.dart
+++ b/tests/compiler/dart2js/scanner_offset_length_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'package:compiler/src/scanner/string_scanner.dart';
-import 'package:compiler/src/tokens/token.dart';
-import 'package:compiler/src/tokens/token_constants.dart';
+import 'package:front_end/src/fasta/scanner.dart';
 
 Token scan(String text) =>
-    new StringScanner.fromString(text, includeComments: true).tokenize();
+    new StringScanner(text, includeComments: true).tokenize();
 
 check(String text) {
   Token token = scan(text);
diff --git a/tests/compiler/dart2js/scanner_test.dart b/tests/compiler/dart2js/scanner_test.dart
index ae5dfd3..82f4d5e 100644
--- a/tests/compiler/dart2js/scanner_test.dart
+++ b/tests/compiler/dart2js/scanner_test.dart
@@ -3,17 +3,16 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'package:compiler/src/scanner/utf8_bytes_scanner.dart';
-import 'package:compiler/src/tokens/precedence_constants.dart';
-import 'package:compiler/src/tokens/token.dart';
-import 'package:compiler/src/util/characters.dart';
+import 'package:front_end/src/fasta/scanner.dart';
+import 'package:front_end/src/fasta/scanner/characters.dart';
+import 'package:front_end/src/fasta/scanner/precedence.dart';
 import 'dart:typed_data';
 
 Token scan(List<int> bytes) {
   List<int> zeroTerminated = new Uint8List(bytes.length + 1);
   zeroTerminated.setRange(0, bytes.length, bytes);
   zeroTerminated[bytes.length] = 0;
-  return new Utf8BytesScanner.fromBytes(zeroTerminated).tokenize();
+  return new Utf8BytesScanner(zeroTerminated).tokenize();
 }
 
 Token scanUTF8(List<int> bytes) {
@@ -26,7 +25,7 @@
   for (int i = 0; i < l; i++) {
     stringLiteral[i + 1] = bytes[i];
   }
-  return new Utf8BytesScanner.fromBytes(stringLiteral).tokenize();
+  return new Utf8BytesScanner(stringLiteral).tokenize();
 }
 
 bool isRunningOnJavaScript() => identical(1, 1.0);
diff --git a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
index 47b55ca..c32a8be 100644
--- a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
@@ -1546,15 +1546,12 @@
         ''',
         const Visit(VisitKind.VISIT_DYNAMIC_TYPE_LITERAL_GET,
             constant: 'dynamic')),
-    // TODO(johnniwinther): Update these to expect the constant to be `dynamic`
-    // instead of `Type`. Currently the compile time constant evaluator cannot
-    // detect `dynamic` as a constant subexpression.
     const Test(
         '''
         m() { dynamic(null, 42); }
         ''',
         const Visit(VisitKind.VISIT_DYNAMIC_TYPE_LITERAL_INVOKE,
-            constant: 'Type', arguments: '(null,42)')),
+            constant: 'dynamic', arguments: '(null,42)')),
     const Test(
         '''
         m() => dynamic = 42;
diff --git a/tests/compiler/dart2js/serialization/equivalence_test.dart b/tests/compiler/dart2js/serialization/equivalence_test.dart
index 602daa1..18ef0cf 100644
--- a/tests/compiler/dart2js/serialization/equivalence_test.dart
+++ b/tests/compiler/dart2js/serialization/equivalence_test.dart
@@ -14,6 +14,7 @@
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/diagnostics/invariant.dart';
 import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/elements/resolution_types.dart';
 import 'package:compiler/src/elements/visitor.dart';
 import 'package:compiler/src/filenames.dart';
 import 'package:compiler/src/library_loader.dart';
@@ -205,8 +206,9 @@
   @override
   visitGenerative(GenerativeConstantConstructor constructor1,
       GenerativeConstantConstructor constructor2) {
-    checkTypes(constructor1, constructor2, 'type', constructor1.type,
-        constructor2.type);
+    ResolutionInterfaceType type1 = constructor1.type;
+    ResolutionInterfaceType type2 = constructor2.type;
+    checkTypes(constructor1, constructor2, 'type', type1, type2);
     check(constructor1, constructor2, 'defaultValues.length',
         constructor1.defaultValues.length, constructor2.defaultValues.length);
     constructor1.defaultValues.forEach((k, v) {
diff --git a/tests/compiler/dart2js/serialization/model_test_helper.dart b/tests/compiler/dart2js/serialization/model_test_helper.dart
index 66e73cb..746ca0a 100644
--- a/tests/compiler/dart2js/serialization/model_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/model_test_helper.dart
@@ -16,6 +16,7 @@
 import 'package:compiler/src/elements/resolution_types.dart';
 import 'package:compiler/src/deferred_load.dart';
 import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/enqueue.dart';
 import 'package:compiler/src/filenames.dart';
 import 'package:compiler/src/js_backend/js_backend.dart';
diff --git a/tests/compiler/dart2js/serialization/test_helper.dart b/tests/compiler/dart2js/serialization/test_helper.dart
index a07dfe2..4d7bafb 100644
--- a/tests/compiler/dart2js/serialization/test_helper.dart
+++ b/tests/compiler/dart2js/serialization/test_helper.dart
@@ -8,11 +8,15 @@
 import 'package:compiler/src/common/resolution.dart';
 import 'package:compiler/src/constants/expressions.dart';
 import 'package:compiler/src/constants/values.dart';
-import 'package:compiler/src/elements/resolution_types.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/elements/entities.dart';
+import 'package:compiler/src/elements/resolution_types.dart';
+import 'package:compiler/src/elements/types.dart';
+import 'package:compiler/src/kernel/elements.dart';
+import 'package:compiler/src/kernel/world_builder.dart';
 import 'package:compiler/src/serialization/equivalence.dart';
-import 'package:compiler/src/tree/nodes.dart';
+import 'package:compiler/src/util/util.dart';
 import 'package:expect/expect.dart';
 import 'test_data.dart';
 
@@ -55,8 +59,25 @@
 ///
 /// Use this strategy to fail early with contextual information in the event of
 /// inequivalence.
-class CheckStrategy implements TestStrategy {
-  const CheckStrategy();
+class CheckStrategy extends TestStrategy {
+  const CheckStrategy(
+      {Equivalence<Entity> elementEquivalence: areElementsEquivalent,
+      Equivalence<DartType> typeEquivalence: areTypesEquivalent,
+      Equivalence<ConstantExpression> constantEquivalence:
+          areConstantsEquivalent,
+      Equivalence<ConstantValue> constantValueEquivalence:
+          areConstantValuesEquivalent})
+      : super(
+            elementEquivalence: elementEquivalence,
+            typeEquivalence: typeEquivalence,
+            constantEquivalence: constantEquivalence,
+            constantValueEquivalence: constantValueEquivalence);
+
+  TestStrategy get testOnly => new TestStrategy(
+      elementEquivalence: elementEquivalence,
+      typeEquivalence: typeEquivalence,
+      constantEquivalence: constantEquivalence,
+      constantValueEquivalence: constantValueEquivalence);
 
   @override
   bool test(var object1, var object2, String property, var value1, var value2,
@@ -93,56 +114,6 @@
     return checkMapEquivalence(object1, object2, property, map1, map2,
         keyEquivalence, valueEquivalence);
   }
-
-  @override
-  bool testElements(Object object1, Object object2, String property,
-      Element element1, Element element2) {
-    return checkElementIdentities(
-        object1, object2, property, element1, element2);
-  }
-
-  @override
-  bool testTypes(Object object1, Object object2, String property,
-      ResolutionDartType type1, ResolutionDartType type2) {
-    return checkTypes(object1, object2, property, type1, type2);
-  }
-
-  @override
-  bool testConstants(Object object1, Object object2, String property,
-      ConstantExpression exp1, ConstantExpression exp2) {
-    return checkConstants(object1, object2, property, exp1, exp2);
-  }
-
-  @override
-  bool testConstantValues(Object object1, Object object2, String property,
-      ConstantValue value1, ConstantValue value2) {
-    return areConstantValuesEquivalent(value1, value2);
-  }
-
-  @override
-  bool testTypeLists(Object object1, Object object2, String property,
-      List<ResolutionDartType> list1, List<ResolutionDartType> list2) {
-    return checkTypeLists(object1, object2, property, list1, list2);
-  }
-
-  @override
-  bool testConstantLists(Object object1, Object object2, String property,
-      List<ConstantExpression> list1, List<ConstantExpression> list2) {
-    return checkConstantLists(object1, object2, property, list1, list2);
-  }
-
-  @override
-  bool testConstantValueLists(Object object1, Object object2, String property,
-      List<ConstantValue> list1, List<ConstantValue> list2) {
-    return checkConstantValueLists(object1, object2, property, list1, list2);
-  }
-
-  @override
-  bool testNodes(
-      Object object1, Object object2, String property, Node node1, Node node2) {
-    return new NodeEquivalenceVisitor(this)
-        .testNodes(object1, object2, property, node1, node2);
-  }
 }
 
 /// Check that the values [property] of [object1] and [object2], [value1] and
@@ -465,7 +436,8 @@
     throw 'Missing impact for $member2. $member1 has $impact1';
   }
 
-  testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy());
+  testResolutionImpactEquivalence(impact1, impact2,
+      strategy: const CheckStrategy());
 }
 
 void checkSets(
@@ -661,3 +633,198 @@
     return [segmentNumber(index - 1), segmentNumber(index)];
   }
 }
+
+class KernelEquivalence {
+  final WorldDeconstructionForTesting testing;
+
+  /// Set of mixin applications assumed to be equivalent.
+  ///
+  /// We need co-inductive reasoning because mixin applications are compared
+  /// structurally and therefore, in the case of generic mixin applications,
+  /// meet themselves through the equivalence check of their type variables.
+  Set<Pair<ClassEntity, ClassEntity>> assumedMixinApplications =
+      new Set<Pair<ClassEntity, ClassEntity>>();
+
+  KernelEquivalence(KernelWorldBuilder builder)
+      : testing = new WorldDeconstructionForTesting(builder);
+
+  TestStrategy get defaultStrategy => new TestStrategy(
+      elementEquivalence: entityEquivalence, typeEquivalence: typeEquivalence);
+
+  bool entityEquivalence(Element a, Entity b, {TestStrategy strategy}) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    strategy ??= defaultStrategy;
+    switch (a.kind) {
+      case ElementKind.GENERATIVE_CONSTRUCTOR:
+        if (b is KGenerativeConstructor) {
+          return strategy.test(a, b, 'name', a.name, b.name) &&
+              strategy.testElements(
+                  a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
+        }
+        return false;
+      case ElementKind.FACTORY_CONSTRUCTOR:
+        if (b is KFactoryConstructor) {
+          return strategy.test(a, b, 'name', a.name, b.name) &&
+              strategy.testElements(
+                  a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
+        }
+        return false;
+      case ElementKind.CLASS:
+        if (b is KClass) {
+          List<InterfaceType> aMixinTypes = [];
+          List<InterfaceType> bMixinTypes = [];
+          ClassElement aClass = a;
+          while (aClass.isMixinApplication) {
+            MixinApplicationElement aMixinApplication = aClass;
+            aMixinTypes.add(aMixinApplication.mixinType);
+            aClass = aMixinApplication.superclass;
+          }
+          KClass bClass = b;
+          while (bClass != null) {
+            InterfaceType mixinType = testing.getMixinTypeForClass(bClass);
+            if (mixinType == null) break;
+            bMixinTypes.add(mixinType);
+            bClass = testing.getSuperclassForClass(bClass);
+          }
+          if (aMixinTypes.isNotEmpty || aMixinTypes.isNotEmpty) {
+            if (aClass.isNamedMixinApplication &&
+                !strategy.test(a, b, 'name', a.name, b.name)) {
+              return false;
+            }
+            Pair<ClassEntity, ClassEntity> pair =
+                new Pair<ClassEntity, ClassEntity>(aClass, bClass);
+            if (assumedMixinApplications.contains(pair)) {
+              return true;
+            } else {
+              assumedMixinApplications.add(pair);
+              bool result = strategy.testTypeLists(
+                  a, b, 'mixinTypes', aMixinTypes, bMixinTypes);
+              assumedMixinApplications.remove(pair);
+              return result;
+            }
+          }
+          return strategy.test(a, b, 'name', a.name, b.name) &&
+              strategy.testElements(
+                  a, b, 'library', a.library, testing.getLibraryForClass(b));
+        }
+        return false;
+      case ElementKind.LIBRARY:
+        if (b is KLibrary) {
+          LibraryElement libraryA = a;
+          return libraryA.canonicalUri == testing.getLibraryUri(b);
+        }
+        return false;
+      case ElementKind.FUNCTION:
+        if (b is KMethod) {
+          if (!strategy.test(a, b, 'name', a.name, b.name)) return false;
+          if (b.enclosingClass != null) {
+            return strategy.testElements(
+                a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
+          } else {
+            return strategy.testElements(
+                a, b, 'library', a.library, testing.getLibraryForFunction(b));
+          }
+        } else if (b is KLocalFunction) {
+          LocalFunctionElement aLocalFunction = a;
+          return strategy.test(a, b, 'name', a.name, b.name ?? '') &&
+              strategy.testElements(a, b, 'executableContext',
+                  aLocalFunction.executableContext, b.executableContext) &&
+              strategy.testElements(a, b, 'memberContext',
+                  aLocalFunction.memberContext, b.memberContext);
+        }
+        return false;
+      case ElementKind.GETTER:
+        if (b is KGetter) {
+          if (!strategy.test(a, b, 'name', a.name, b.name)) return false;
+          if (b.enclosingClass != null) {
+            return strategy.testElements(
+                a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
+          } else {
+            return strategy.testElements(
+                a, b, 'library', a.library, testing.getLibraryForFunction(b));
+          }
+        }
+        return false;
+      case ElementKind.SETTER:
+        if (b is KSetter) {
+          if (!strategy.test(a, b, 'name', a.name, b.name)) return false;
+          if (b.enclosingClass != null) {
+            return strategy.testElements(
+                a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
+          } else {
+            return strategy.testElements(
+                a, b, 'library', a.library, testing.getLibraryForFunction(b));
+          }
+        }
+        return false;
+      case ElementKind.FIELD:
+        if (b is KField) {
+          if (!strategy.test(a, b, 'name', a.name, b.name)) return false;
+          if (b.enclosingClass != null) {
+            return strategy.testElements(
+                a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass);
+          } else {
+            return strategy.testElements(
+                a, b, 'library', a.library, testing.getLibraryForField(b));
+          }
+        }
+        return false;
+      case ElementKind.TYPE_VARIABLE:
+        if (b is KTypeVariable) {
+          TypeVariableElement aElement = a;
+          return strategy.test(a, b, 'index', aElement.index, b.index) &&
+              strategy.testElements(a, b, 'typeDeclaration',
+                  aElement.typeDeclaration, b.typeDeclaration);
+        }
+        return false;
+      default:
+        throw new UnsupportedError('Unsupported equivalence: '
+            '$a (${a.runtimeType}) vs $b (${b.runtimeType})');
+    }
+  }
+
+  bool typeEquivalence(ResolutionDartType a, DartType b,
+      {TestStrategy strategy}) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    strategy ??= defaultStrategy;
+    switch (a.kind) {
+      case ResolutionTypeKind.DYNAMIC:
+        return b is DynamicType;
+      case ResolutionTypeKind.VOID:
+        return b is VoidType;
+      case ResolutionTypeKind.INTERFACE:
+        if (b is InterfaceType) {
+          ResolutionInterfaceType aType = a;
+          return strategy.testElements(a, b, 'element', a.element, b.element) &&
+              strategy.testTypeLists(
+                  a, b, 'typeArguments', aType.typeArguments, b.typeArguments);
+        }
+        return false;
+      case ResolutionTypeKind.TYPE_VARIABLE:
+        if (b is TypeVariableType) {
+          return strategy.testElements(a, b, 'element', a.element, b.element);
+        }
+        return false;
+      case ResolutionTypeKind.FUNCTION:
+        if (b is FunctionType) {
+          ResolutionFunctionType aType = a;
+          return strategy.testTypes(
+                  a, b, 'returnType', aType.returnType, b.returnType) &&
+              strategy.testTypeLists(a, b, 'parameterTypes',
+                  aType.parameterTypes, b.parameterTypes) &&
+              strategy.testTypeLists(a, b, 'optionalParameterTypes',
+                  aType.optionalParameterTypes, b.optionalParameterTypes) &&
+              strategy.testLists(a, b, 'namedParameters', aType.namedParameters,
+                  b.namedParameters) &&
+              strategy.testTypeLists(a, b, 'namedParameterTypes',
+                  aType.namedParameterTypes, b.namedParameterTypes);
+        }
+        return false;
+      default:
+        throw new UnsupportedError('Unsupported equivalence: '
+            '$a (${a.runtimeType}) vs $b (${b.runtimeType})');
+    }
+  }
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
index 2a31462..08643af 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
@@ -37,9 +37,9 @@
               typesInferrer.getTypeOfElement(element).containsOnly(type));
         }
 
-        checkFieldTypeInClass('A', 'intField',
-            compiler.backend.backendClasses.uint31Implementation);
-        checkFieldTypeInClass('A', 'stringField',
-            compiler.backend.backendClasses.stringImplementation);
+        checkFieldTypeInClass(
+            'A', 'intField', compiler.backend.backendClasses.uint31Class);
+        checkFieldTypeInClass(
+            'A', 'stringField', compiler.backend.backendClasses.stringClass);
       }));
 }
diff --git a/tests/compiler/dart2js/sourcemaps/diff_view.dart b/tests/compiler/dart2js/sourcemaps/diff_view.dart
index db07f93..e1b0158 100644
--- a/tests/compiler/dart2js/sourcemaps/diff_view.dart
+++ b/tests/compiler/dart2js/sourcemaps/diff_view.dart
@@ -886,7 +886,7 @@
   if (element.isLibrary) {
     LibraryElement library = element;
     kind = CodeKind.LIBRARY;
-    name = library.libraryOrScriptName;
+    name = library.name;
     uri = library.entryCompilationUnit.script.resourceUri;
   } else if (element.isClass) {
     kind = CodeKind.CLASS;
diff --git a/tests/compiler/dart2js/sourcemaps/mapping_test.dart b/tests/compiler/dart2js/sourcemaps/mapping_test.dart
new file mode 100644
index 0000000..ee1901e
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/mapping_test.dart
@@ -0,0 +1,216 @@
+// 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:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/compiler_new.dart';
+import 'package:compiler/src/apiimpl.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/dart2js.dart' as entry;
+import 'package:expect/expect.dart';
+import 'package:source_maps/source_maps.dart';
+import 'package:source_maps/src/utils.dart';
+
+import '../annotated_code_helper.dart';
+import '../memory_compiler.dart';
+import '../source_map_validator_helper.dart';
+
+const List<String> TESTS = const <String>[
+  '''
+@{main}main() {
+@{main}}
+''',
+  '''
+@{main}main() {
+  @{+main}throw '';
+@{main}}
+''',
+  '''
+@{main}main() {
+  @{main}return 0;
+@{main}}
+''',
+  '''
+import 'package:expect/expect.dart';
+@{main}main() {
+  @{main}test();
+@{main}}
+
+@NoInline()
+@{test}test() {
+@{test}}
+''',
+];
+
+class Test {
+  final String annotatedCode;
+  final String code;
+  final List<SourceLocation> expectedLocations;
+
+  Test(this.annotatedCode, this.code, this.expectedLocations);
+}
+
+Test processTestCode(String code, {bool useNewSourceInfo}) {
+  List<SourceLocation> expectedLocations = <SourceLocation>[];
+  AnnotatedCode annotatedCode = new AnnotatedCode.fromText(code);
+  for (Annotation annotation in annotatedCode.annotations) {
+    String methodName;
+    if (annotation.text.startsWith('-')) {
+      // Expect only in old source maps
+      if (useNewSourceInfo) continue;
+      methodName = annotation.text.substring(1);
+    } else if (annotation.text.startsWith('+')) {
+      // Expect only in new source maps
+      if (!useNewSourceInfo) continue;
+      methodName = annotation.text.substring(1);
+    } else {
+      methodName = annotation.text;
+    }
+    expectedLocations.add(
+        new SourceLocation(methodName, annotation.lineNo, annotation.columnNo));
+  }
+  return new Test(code, annotatedCode.sourceCode, expectedLocations);
+}
+
+void main(List<String> arguments) {
+  bool verbose = false;
+  bool printJs = false;
+  bool writeJs = false;
+  List<int> indices;
+  for (String arg in arguments) {
+    if (arg == '-v') {
+      verbose = true;
+    } else if (arg == '--print-js') {
+      printJs = true;
+    } else if (arg == '--write-js') {
+      writeJs = true;
+    } else {
+      int index = int.parse(arg, onError: (_) => null);
+      if (index != null) {
+        indices ??= <int>[];
+        if (index < 0 || index >= TESTS.length * 2) {
+          print('Index $index out of bounds: [0;${TESTS.length - 1}]');
+        } else {
+          indices.add(index);
+        }
+      }
+    }
+  }
+  if (indices == null) {
+    indices = new List<int>.generate(TESTS.length * 2, (i) => i);
+  }
+  asyncTest(() async {
+    for (int index in indices) {
+      bool useNewSourceInfo = index % 2 == 1;
+      await runTest(
+          index,
+          processTestCode(TESTS[index ~/ 2],
+              useNewSourceInfo: useNewSourceInfo),
+          printJs: printJs,
+          writeJs: writeJs,
+          verbose: verbose,
+          useNewSourceInfo: useNewSourceInfo);
+    }
+  });
+}
+
+Future runTest(int index, Test test,
+    {bool printJs: false,
+    bool writeJs,
+    bool verbose: false,
+    bool useNewSourceInfo: false}) async {
+  print("--$index------------------------------------------------------------");
+  print("Compiling dart2js ${useNewSourceInfo ? Flags.useNewSourceInfo : ''}\n"
+      "${test.annotatedCode}");
+  OutputCollector collector = new OutputCollector();
+  List<String> options = <String>['--out=out.js', '--source-map=out.js.map'];
+  if (useNewSourceInfo) {
+    options.add(Flags.useNewSourceInfo);
+  }
+  CompilationResult compilationResult = await runCompiler(
+      entryPoint: Uri.parse('memory:main.dart'),
+      memorySourceFiles: {'main.dart': test.code},
+      outputProvider: collector,
+      options: options);
+  Expect.isTrue(compilationResult.isSuccess,
+      "Unsuccessful compilation of test:\n${test.code}");
+  String sourceMapText = collector.getOutput('', 'js.map');
+  SingleMapping sourceMap = parse(sourceMapText);
+  if (writeJs) {
+    new File('out.js').writeAsStringSync(collector.getOutput('', 'js'));
+    new File('out.js.map').writeAsStringSync(sourceMapText);
+  }
+
+  Set<SourceLocation> expectedLocations = test.expectedLocations.toSet();
+  List<SourceLocation> actualLocations = <SourceLocation>[];
+  List<SourceLocation> extraLocations = <SourceLocation>[];
+  for (TargetLineEntry targetLineEntry in sourceMap.lines) {
+    for (TargetEntry targetEntry in targetLineEntry.entries) {
+      if (targetEntry.sourceUrlId != null &&
+          sourceMap.urls[targetEntry.sourceUrlId] == 'memory:main.dart') {
+        String methodName;
+        if (targetEntry.sourceNameId != null) {
+          methodName = sourceMap.names[targetEntry.sourceNameId];
+        }
+        SourceLocation location = new SourceLocation(methodName,
+            targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1);
+        actualLocations.add(location);
+        if (!expectedLocations.remove(location)) {
+          extraLocations.add(location);
+        }
+      }
+    }
+  }
+
+  if (expectedLocations.isNotEmpty) {
+    print('--Missing source locations:---------------------------------------');
+    AnnotatedCode annotatedCode = new AnnotatedCode(test.code, []);
+    expectedLocations.forEach(
+        (l) => annotatedCode.addAnnotation(l.lineNo, l.columnNo, l.methodName));
+    print(annotatedCode.toText());
+    print('------------------------------------------------------------------');
+    Expect.isTrue(
+        expectedLocations.isEmpty,
+        "Missing source locations:\n${test.code}\n"
+        "Actual:\n${actualLocations.join('\n')}\n"
+        "Missing:\n${expectedLocations.join('\n')}\n");
+  }
+  if (extraLocations.isNotEmpty) {
+    print('--Extra source locations:-----------------------------------------');
+    AnnotatedCode annotatedCode = new AnnotatedCode(test.code, []);
+    extraLocations.forEach(
+        (l) => annotatedCode.addAnnotation(l.lineNo, l.columnNo, l.methodName));
+    print(annotatedCode.toText());
+    print('------------------------------------------------------------------');
+    Expect.isTrue(
+        extraLocations.isEmpty,
+        "Extra source locations:\n${test.code}\n"
+        "Actual:\n${actualLocations.join('\n')}\n"
+        "Extra:\n${extraLocations.join('\n')}\n");
+  }
+}
+
+class SourceLocation {
+  final String methodName;
+  final int lineNo;
+  final int columnNo;
+
+  SourceLocation(this.methodName, this.lineNo, this.columnNo);
+
+  int get hashCode =>
+      methodName.hashCode * 13 + lineNo.hashCode * 17 + columnNo.hashCode * 19;
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! SourceLocation) return false;
+    return methodName == other.methodName &&
+        lineNo == other.lineNo &&
+        columnNo == other.columnNo;
+  }
+
+  String toString() => '$methodName:$lineNo:$columnNo';
+}
diff --git a/tests/compiler/dart2js/sourcemaps/nomapping_test.dart b/tests/compiler/dart2js/sourcemaps/nomapping_test.dart
new file mode 100644
index 0000000..124e0ea
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/nomapping_test.dart
@@ -0,0 +1,129 @@
+// 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:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/compiler_new.dart';
+import 'package:compiler/src/apiimpl.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/dart2js.dart' as entry;
+import 'package:expect/expect.dart';
+import 'package:source_maps/source_maps.dart';
+import 'package:source_maps/src/utils.dart';
+
+import '../annotated_code_helper.dart';
+import '../memory_compiler.dart';
+import '../source_map_validator_helper.dart';
+
+const List<String> TESTS = const <String>[
+  '''
+main() {}
+''',
+];
+
+void main(List<String> arguments) {
+  bool verbose = false;
+  bool writeJs = false;
+  List<int> indices;
+  for (String arg in arguments) {
+    if (arg == '-v') {
+      verbose = true;
+    } else if (arg == '--write-js') {
+      writeJs = true;
+    } else {
+      int index = int.parse(arg, onError: (_) => null);
+      if (index != null) {
+        indices ??= <int>[];
+        if (index < 0 || index >= TESTS.length * 2) {
+          print('Index $index out of bounds: [0;${TESTS.length - 1}]');
+        } else {
+          indices.add(index);
+        }
+      }
+    }
+  }
+  if (indices == null) {
+    indices = new List<int>.generate(TESTS.length * 2, (i) => i);
+  }
+  asyncTest(() async {
+    for (int index in indices) {
+      bool useNewSourceInfo = index % 2 == 1;
+      await runTest(index, TESTS[index ~/ 2],
+          writeJs: writeJs,
+          verbose: verbose,
+          useNewSourceInfo: useNewSourceInfo);
+    }
+  });
+}
+
+Future runTest(int index, String code,
+    {bool writeJs, bool verbose: false, bool useNewSourceInfo: false}) async {
+  print("--$index------------------------------------------------------------");
+  print("Compiling dart2js ${useNewSourceInfo ? Flags.useNewSourceInfo : ''}\n"
+      "${code}");
+  OutputCollector collector = new OutputCollector();
+  List<String> options = <String>['--out=out.js', '--source-map=out.js.map'];
+  if (useNewSourceInfo) {
+    options.add(Flags.useNewSourceInfo);
+  }
+  CompilationResult compilationResult = await runCompiler(
+      entryPoint: Uri.parse('memory:main.dart'),
+      memorySourceFiles: {'main.dart': code},
+      outputProvider: collector,
+      options: options);
+  Expect.isTrue(compilationResult.isSuccess,
+      "Unsuccessful compilation of test:\n${code}");
+  String sourceMapText = collector.getOutput('', 'js.map');
+  SingleMapping sourceMap = parse(sourceMapText);
+  if (writeJs) {
+    new File('out.js').writeAsStringSync(collector.getOutput('', 'js'));
+    new File('out.js.map').writeAsStringSync(sourceMapText);
+  }
+  Expect.isTrue(sourceMap.lines.isNotEmpty);
+  TargetLineEntry firstLineEntry = sourceMap.lines.first;
+  Expect.isTrue(firstLineEntry.entries.isNotEmpty);
+  TargetEntry firstEntry = firstLineEntry.entries.first;
+  Expect.isNull(
+      firstEntry.sourceUrlId,
+      "Unexpected first entry: "
+      "${entryToString(firstLineEntry, firstEntry, sourceMap)}");
+  TargetLineEntry lastLineEntry = sourceMap.lines.last;
+  Expect.isTrue(lastLineEntry.entries.isNotEmpty);
+  TargetEntry lastEntry = firstLineEntry.entries.last;
+  Expect.isNull(
+      lastEntry.sourceUrlId,
+      "Unexpected last entry: "
+      "${entryToString(lastLineEntry, lastEntry, sourceMap)}");
+}
+
+String entryToString(
+    TargetLineEntry lineEntry, TargetEntry entry, SingleMapping mapping) {
+  StringBuffer sb = new StringBuffer();
+  sb.write('[line=');
+  sb.write(lineEntry.line);
+  sb.write(',column=');
+  sb.write(entry.column);
+  sb.write(',');
+  if (entry.sourceUrlId != null) {
+    sb.write('sourceUrl=');
+    sb.write(mapping.urls[entry.sourceUrlId]);
+    sb.write(',');
+  }
+  if (entry.sourceNameId != null) {
+    sb.write('sourceName=');
+    sb.write(mapping.names[entry.sourceNameId]);
+    sb.write(',');
+  }
+  if (entry.sourceLine != null) {
+    sb.write('sourceLine=');
+    sb.write(entry.sourceLine);
+    sb.write(',sourceColumn=');
+    sb.write(entry.sourceColumn);
+  }
+  sb.write(']');
+  return sb.toString();
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
index fa8ea09..3c5ab62 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -138,8 +138,7 @@
 
 /// A wrapper of [SourceInformationProcessor] that records source locations and
 /// code positions.
-class RecordingSourceInformationProcessor
-    implements SourceInformationProcessor {
+class RecordingSourceInformationProcessor extends SourceInformationProcessor {
   final RecordingSourceInformationStrategy wrapper;
   final SourceInformationProcessor processor;
   final CodePositionRecorder codePositions;
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
index 185b8a5..6bd7621 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
@@ -69,8 +69,8 @@
 }
 class Class {
   @NoInline()
-  Class() {
-    @{2:Class}throw '$EXCEPTION_MARKER';
+  @{2:Class}Class() {
+    @{3:Class}throw '$EXCEPTION_MARKER';
   }
 }
 ''',
@@ -129,6 +129,22 @@
 ''',
   '''
 import 'package:expect/expect.dart';
+class MyType {
+  get length => 3; // ensures we build an interceptor for `.length`
+}
+
+main() {
+  confuse('').trim(); // includes some code above the interceptors
+  confuse([]).length;
+  confuse(new MyType()).length;
+  // TODO(johnniwinther): Intercepted access should point to 'length':
+  @{1:main}confuse(null).length; // called through the interceptor
+}
+
+@NoInline()
+confuse(x) => x;''',
+  '''
+import 'package:expect/expect.dart';
 main() {
   // This call is no longer on the stack when the error is thrown.
   @{:main}test();
@@ -178,8 +194,8 @@
 }
 class Class {
   @NoInline()
-  Class() {
-    @{2:Class}throw '$EXCEPTION_MARKER';
+  @{2:Class}Class() {
+    @{3:Class}throw '$EXCEPTION_MARKER';
   }
 }
 ''',
@@ -193,14 +209,10 @@
   Test(this.code, this.expectedLines, this.unexpectedLines);
 }
 
-const int _LF = 0x0A;
-const int _CR = 0x0D;
-const int _LBRACE = 0x7B;
-
 Test processTestCode(String code) {
   Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
   List<StackTraceLine> unexpectedLines = <StackTraceLine>[];
-  AnnotatedCode annotatedCode = new AnnotatedCode(code);
+  AnnotatedCode annotatedCode = new AnnotatedCode.fromText(code);
   for (Annotation annotation in annotatedCode.annotations) {
     int colonIndex = annotation.text.indexOf(':');
     String indexText = annotation.text.substring(0, colonIndex);
@@ -225,12 +237,15 @@
 void main(List<String> arguments) {
   bool verbose = false;
   bool printJs = false;
+  bool writeJs = false;
   List<int> indices;
   for (String arg in arguments) {
     if (arg == '-v') {
       verbose = true;
     } else if (arg == '--print-js') {
       printJs = true;
+    } else if (arg == '--write-js') {
+      writeJs = true;
     } else {
       int index = int.parse(arg, onError: (_) => null);
       if (index != null) {
@@ -249,13 +264,13 @@
   asyncTest(() async {
     for (int index in indices) {
       await runTest(index, processTestCode(TESTS[index]),
-          printJs: printJs, verbose: verbose);
+          printJs: printJs, writeJs: writeJs, verbose: verbose);
     }
   });
 }
 
 Future runTest(int index, Test test,
-    {bool printJs: false, bool verbose: false}) async {
+    {bool printJs: false, bool writeJs, bool verbose: false}) async {
   Directory tmpDir = await createTempDir();
   String input = '${tmpDir.path}/$INPUT_FILE_NAME';
   new File(input).writeAsStringSync(test.code);
@@ -272,14 +287,17 @@
   CompilationResult compilationResult = await entry.internalMain(arguments);
   Expect.isTrue(compilationResult.isSuccess,
       "Unsuccessful compilation of test:\n${test.code}");
-  CompilerImpl compiler = compilationResult.compiler;
-  SingleMapping sourceMap = new SingleMapping.fromJson(
-      JSON.decode(new File('$output.map').readAsStringSync()));
+  String sourceMapText = new File('$output.map').readAsStringSync();
+  SingleMapping sourceMap = parse(sourceMapText);
 
   if (printJs) {
     print('JavaScript output:');
     print(new File(output).readAsStringSync());
   }
+  if (writeJs) {
+    new File('out.js').writeAsStringSync(new File(output).readAsStringSync());
+    new File('out.js.map').writeAsStringSync(sourceMapText);
+  }
   print("Running d8 $output");
   ProcessResult runResult = Process.runSync(d8executable,
       ['sdk/lib/_internal/js_runtime/lib/preambles/d8.js', output]);
@@ -312,18 +330,23 @@
         fileName = sourceMap.urls[targetEntry.sourceUrlId];
       }
       dartStackTrace.add(new StackTraceLine(methodName, fileName,
-          targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1));
+          targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1,
+          isMapped: true));
     }
   }
 
   int expectedIndex = 0;
   List<StackTraceLine> unexpectedLines = <StackTraceLine>[];
+  List<StackTraceLine> unexpectedBeforeLines = <StackTraceLine>[];
+  List<StackTraceLine> unexpectedAfterLines = <StackTraceLine>[];
   for (StackTraceLine line in dartStackTrace) {
+    bool found = false;
     if (expectedIndex < test.expectedLines.length) {
       StackTraceLine expectedLine = test.expectedLines[expectedIndex];
       if (line.methodName == expectedLine.methodName &&
           line.lineNo == expectedLine.lineNo &&
           line.columnNo == expectedLine.columnNo) {
+        found = true;
         expectedIndex++;
       }
     }
@@ -334,6 +357,23 @@
         unexpectedLines.add(line);
       }
     }
+    if (line.isMapped && !found) {
+      List<LineException> exceptions =
+          expectedIndex == 0 ? beforeExceptions : afterExceptions;
+      for (LineException exception in exceptions) {
+        if (line.methodName == exception.methodName &&
+            line.fileName.endsWith(exception.fileName)) {
+          found = true;
+        }
+      }
+      if (!found) {
+        if (expectedIndex == 0) {
+          unexpectedBeforeLines.add(line);
+        } else {
+          unexpectedAfterLines.add(line);
+        }
+      }
+    }
   }
   if (verbose) {
     print('JavaScript stacktrace:');
@@ -352,6 +392,12 @@
       "Unexpected stack trace lines for test:\n${test.code}\n"
       "Actual:\n${dartStackTrace.join('\n')}\n"
       "Unexpected:\n${test.unexpectedLines.join('\n')}\n");
+  Expect.isTrue(
+      unexpectedBeforeLines.isEmpty && unexpectedAfterLines.isEmpty,
+      "Unexpected stack trace lines:\n${test.code}\n"
+      "Actual:\n${dartStackTrace.join('\n')}\n"
+      "Unexpected before:\n${unexpectedBeforeLines.join('\n')}\n"
+      "Unexpected after:\n${unexpectedAfterLines.join('\n')}\n");
 
   print("Deleting '${tmpDir.path}'.");
   tmpDir.deleteSync(recursive: true);
@@ -362,8 +408,10 @@
   String fileName;
   int lineNo;
   int columnNo;
+  bool isMapped;
 
-  StackTraceLine(this.methodName, this.fileName, this.lineNo, this.columnNo);
+  StackTraceLine(this.methodName, this.fileName, this.lineNo, this.columnNo,
+      {this.isMapped: false});
 
   /// Creates a [StackTraceLine] by parsing a d8 stack trace line [text]. The
   /// expected formats are
@@ -478,3 +526,34 @@
   }
   throw new UnsupportedError('Unsupported platform.');
 }
+
+/// A line allowed in the mapped stack trace.
+class LineException {
+  final String methodName;
+  final String fileName;
+
+  const LineException(this.methodName, this.fileName);
+}
+
+/// Lines allowed before the intended stack trace. Typically from helper
+/// methods.
+const List<LineException> beforeExceptions = const [
+  const LineException('wrapException', 'js_helper.dart'),
+];
+
+/// Lines allowed after the intended stack trace. Typically from the event
+/// queue.
+const List<LineException> afterExceptions = const [
+  const LineException('_wrapJsFunctionForAsync', 'async_patch.dart'),
+  const LineException(
+      '_wrapJsFunctionForAsync.<anonymous function>', 'async_patch.dart'),
+  const LineException(
+      '_awaitOnObject.<anonymous function>', 'async_patch.dart'),
+  const LineException('_RootZone.runUnary', 'zone.dart'),
+  const LineException('_FutureListener.handleValue', 'future_impl.dart'),
+  const LineException(
+      '_Future._propagateToListeners.handleValueCallback', 'future_impl.dart'),
+  const LineException('_Future._propagateToListeners', 'future_impl.dart'),
+  const LineException(
+      '_Future._addListener.<anonymous function>', 'future_impl.dart'),
+];
diff --git a/tests/compiler/dart2js/tdiv_test.dart b/tests/compiler/dart2js/tdiv_test.dart
index f6407d4..99d0693 100644
--- a/tests/compiler/dart2js/tdiv_test.dart
+++ b/tests/compiler/dart2js/tdiv_test.dart
@@ -62,26 +62,8 @@
 """;
 
 main() {
-  RegExp directivePattern = new RegExp(
-      //      \1                    \2        \3
-      r'''// *(present|absent): (?:"([^"]*)"|'([^'']*)')''',
-      multiLine: true);
-
   Future check(String test) {
-    return compile(test, entry: 'foo', check: (String generated) {
-      for (Match match in directivePattern.allMatches(test)) {
-        String directive = match.group(1);
-        String pattern = match.groups([2, 3]).where((s) => s != null).single;
-        if (directive == 'present') {
-          Expect.isTrue(generated.contains(pattern),
-              "Cannot find '$pattern' in:\n$generated");
-        } else {
-          assert(directive == 'absent');
-          Expect.isFalse(generated.contains(pattern),
-              "Must not find '$pattern' in:\n$generated");
-        }
-      }
-    });
+    return compile(test, entry: 'foo', check: checkerForAbsentPresent(test));
   }
 
   asyncTest(() => Future.wait([
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart
index f54364e..a29d790 100644
--- a/tests/compiler/dart2js/type_combination_test.dart
+++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -745,7 +745,8 @@
     JavaScriptBackend backend = compiler.backend;
     BackendHelpers helpers = backend.helpers;
     WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
-    helpers.interceptorsLibrary.forEachLocalMember((element) {
+    LibraryElement interceptorsLibrary = helpers.interceptorsLibrary;
+    interceptorsLibrary.forEachLocalMember((element) {
       if (element.isClass) {
         element.ensureResolved(compiler.resolution);
         impactBuilder
diff --git a/tests/compiler/dart2js/type_mask2_test.dart b/tests/compiler/dart2js/type_mask2_test.dart
index 609cac7..a33f50f 100644
--- a/tests/compiler/dart2js/type_mask2_test.dart
+++ b/tests/compiler/dart2js/type_mask2_test.dart
@@ -217,7 +217,7 @@
 
   ClassElement Object_ = env.getElement("Object");
   ClassElement String_ = env.getElement("String");
-  ClassElement JSString = closedWorld.backendClasses.stringImplementation;
+  ClassElement JSString = closedWorld.backendClasses.stringClass;
 
   List<ClassElement> allClasses = <ClassElement>[Object_, String_];
 
diff --git a/tests/compiler/dart2js/type_mask_test.dart b/tests/compiler/dart2js/type_mask_test.dart
index e3fd1cb..2a55aa0 100644
--- a/tests/compiler/dart2js/type_mask_test.dart
+++ b/tests/compiler/dart2js/type_mask_test.dart
@@ -21,10 +21,9 @@
 main() {
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(CODE, uri);
-  compiler.closeResolution();
-  var closedWorld = compiler.resolutionWorldBuilder.closedWorldForTesting;
-
   asyncTest(() => compiler.run(uri).then((_) {
+        compiler.closeResolution();
+        var closedWorld = compiler.resolutionWorldBuilder.closedWorldForTesting;
         var classA = findElement(compiler, 'A');
         var classB = findElement(compiler, 'B');
         var classC = findElement(compiler, 'C');
diff --git a/tests/compiler/dart2js/unparser2_test.dart b/tests/compiler/dart2js/unparser2_test.dart
index 820fab7..d3ede31 100644
--- a/tests/compiler/dart2js/unparser2_test.dart
+++ b/tests/compiler/dart2js/unparser2_test.dart
@@ -5,9 +5,8 @@
 import "package:expect/expect.dart";
 import "package:compiler/src/parser/element_listener.dart";
 import "package:compiler/src/parser/node_listener.dart";
-import "package:compiler/src/parser/parser.dart";
-import "package:compiler/src/scanner/string_scanner.dart";
-import "package:compiler/src/tokens/token.dart";
+import "package:front_end/src/fasta/parser.dart";
+import "package:front_end/src/fasta/scanner.dart";
 import "package:compiler/src/tree/tree.dart";
 
 import "package:compiler/src/diagnostics/diagnostic_listener.dart";
@@ -17,8 +16,6 @@
     show CompilationUnitElementX, LibraryElementX;
 import "package:compiler/src/script.dart";
 
-import "options_helper.dart";
-
 main() {
   testClassDef();
   testClass1Field();
@@ -89,7 +86,7 @@
   Script script = new Script(null, null, null);
   LibraryElement lib = new LibraryElementX(script);
   CompilationUnitElement element = new CompilationUnitElementX(script, lib);
-  StringScanner scanner = new StringScanner.fromString(source);
+  StringScanner scanner = new StringScanner(source);
   Token beginToken = scanner.tokenize();
   NodeListener listener =
       new NodeListener(const ScannerOptions(), diagnosticListener, element);
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 596f35a..5be8d14 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -98,6 +98,7 @@
 [ $compiler == none && $runtime == vm ]
 invalid_annotation_test/01: MissingCompileTimeError, OK # vm is lazy
 lookup_map/dead_entry_through_mirrors_test: SkipByDesign # Test for tree-shaking, vm never tree-shakes
+unconditional_dartio_import_test: SkipByDesign # dart2js only test
 
 [ $compiler == dart2js && $cps_ir == false ]
 big_allocation_expression_test: Crash # Issue 24635
diff --git a/tests/compiler/dart2js_extra/unconditional_dartio_import_test.dart b/tests/compiler/dart2js_extra/unconditional_dartio_import_test.dart
new file mode 100644
index 0000000..5facb9a
--- /dev/null
+++ b/tests/compiler/dart2js_extra/unconditional_dartio_import_test.dart
@@ -0,0 +1,20 @@
+// 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.
+
+
+/// Tests that dart2js allows to import dart:io for web clients, but it
+/// continues to indicate that it is not supported (so config-specific imports
+/// continue to have the same semantics as before).
+library unconditional_dartio_import_test;
+
+import 'dart:io' as io; // import is allowed!
+import 'package:expect/expect.dart';
+
+main() {
+  // their APIs throw:
+  Expect.throws(() => new io.File('name').existsSync());
+
+  // ... but environment variable will indicate it is not supported.
+  Expect.isFalse(const bool.fromEnvironment('dart.library.io'));
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index f64a564..7c16962 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -57,6 +57,7 @@
 integer_to_radix_string_test: RuntimeError # issue 22045
 int_modulo_arith_test/bignum: RuntimeError # No bigints.
 int_modulo_arith_test/modPow: RuntimeError # No bigints.
+list_unmodifiable_test: Pass, RuntimeError # Issue 28712
 
 [ $compiler == dart2js && $fast_startup ]
 apply3_test: Fail # mirrors not supported
@@ -151,6 +152,9 @@
 string_test: StaticWarning, OK # Test generates error on purpose.
 duration2_test: StaticWarning, OK # Test generates error on purpose.
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $system == windows && $arch == x64 ]
 stopwatch_test: Skip  # Flaky test due to expected performance behaviour.
 
@@ -192,10 +196,6 @@
 apply3_test: SkipByDesign # Imports dart:mirrors
 
 [ $compiler == precompiler ]
-# Stacktraces in precompilation omit inlined frames.
-stacktrace_current_test: Pass, RuntimeError
-error_stack_trace1_test: Pass, RuntimeError
-
 regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
 big_integer_huge_mul_vm_test: Pass, Timeout # --no_intrinsify
 big_integer_parsed_mul_div_vm_test: Pass, Timeout # --no_intrinsify
diff --git a/tests/corelib/uri_example_test.dart b/tests/corelib/uri_example_test.dart
new file mode 100644
index 0000000..8868a9a
--- /dev/null
+++ b/tests/corelib/uri_example_test.dart
@@ -0,0 +1,96 @@
+// 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 uri.examples;
+
+// Examples from the Uri class documentation.
+// Get an error if the documentation starts to be wrong.
+// REMEMBER TO UPDATE BOTH.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+main() {
+  // Uri.http
+  test("http://example.org/path?q=dart",
+      new Uri.http("example.org", "/path", { "q" : "dart" }));
+  test("http://user:pass@localhost:8080",
+      new Uri.http("user:pass@localhost:8080", ""));
+  test("http://example.org/a%20b", new Uri.http("example.org", "a b"));
+  test("http://example.org/a%252F", new Uri.http("example.org", "/a%2F"));
+
+  // Uri.file
+  test("xxx/yyy", new Uri.file("xxx/yyy", windows: false));
+  test("xxx/yyy/", new Uri.file("xxx/yyy/", windows: false));
+  test("file:///xxx/yyy", new Uri.file("/xxx/yyy", windows: false));
+  test("file:///xxx/yyy/", new Uri.file("/xxx/yyy/", windows: false));
+  test("C%3A", new Uri.file("C:", windows: false));
+  test("xxx/yyy", new Uri.file(r"xxx\yyy", windows: true));
+  test("xxx/yyy/", new Uri.file(r"xxx\yyy\", windows: true));
+  test("file:///xxx/yyy", new Uri.file(r"\xxx\yyy", windows: true));
+  test("file:///xxx/yyy/", new Uri.file(r"\xxx\yyy/", windows: true));
+  test("file:///C:/xxx/yyy", new Uri.file(r"C:\xxx\yyy", windows: true));
+  test("file://server/share/file",
+      new Uri.file(r"\\server\share\file", windows: true));
+  Expect.throws(() => new Uri.file(r"C:", windows: true));
+  Expect.throws(() => new Uri.file(r"C:xxx\yyy", windows: true));
+
+  // isScheme.
+  var uri = Uri.parse("http://example.com/");
+  Expect.isTrue(uri.isScheme("HTTP"));
+
+  // toFilePath.
+  Expect.equals(r"xxx/yyy", Uri.parse("xxx/yyy").toFilePath(windows: false));
+  Expect.equals(r"xxx/yyy/", Uri.parse("xxx/yyy/").toFilePath(windows: false));
+  Expect.equals(r"/xxx/yyy",
+      Uri.parse("file:///xxx/yyy").toFilePath(windows: false));
+  Expect.equals(r"/xxx/yyy/",
+      Uri.parse("file:///xxx/yyy/").toFilePath(windows: false));
+  Expect.equals(r"/C:", Uri.parse("file:///C:").toFilePath(windows: false));
+  Expect.equals(r"/C:a", Uri.parse("file:///C:a").toFilePath(windows: false));
+
+  Expect.equals(r"xxx\yyy", Uri.parse("xxx/yyy").toFilePath(windows: true));
+  Expect.equals(r"xxx\yyy\", Uri.parse("xxx/yyy/").toFilePath(windows: true));
+  Expect.equals(r"\xxx\yyy",
+      Uri.parse("file:///xxx/yyy").toFilePath(windows: true));
+  Expect.equals(r"\xxx\yyy\",
+      Uri.parse("file:///xxx/yyy/").toFilePath(windows: true));
+  Expect.equals(r"C:\xxx\yyy",
+      Uri.parse("file:///C:/xxx/yyy").toFilePath(windows: true));
+  Expect.throws(() => Uri.parse("file:C:xxx/yyy").toFilePath(windows: true));
+  Expect.equals(r"\\server\share\file",
+      Uri.parse("file://server/share/file").toFilePath(windows: true));  //
+
+  // replace.
+  Uri uri1 = Uri.parse("a://b@c:4/d/e?f#g");
+  Uri uri2 = uri1.replace(scheme: "A", path: "D/E/E", fragment: "G");
+  Expect.equals("a://b@c:4/D/E/E?f#G", "$uri2");
+  Uri uri3 = new Uri(
+      scheme: "A",
+      userInfo: uri1.userInfo,
+      host: uri1.host,
+      port: uri1.port,
+      path: "D/E/E",
+      query: uri1.query,
+      fragment: "G");
+  Expect.equals("a://b@c:4/D/E/E?f#G", "$uri3");
+  Expect.equals(uri2, uri3);
+
+  // UriData.mimeType
+  var data = UriData.parse("data:text/plain;charset=utf-8,Hello%20World!");
+  Expect.equals("text/plain", data.mimeType);
+  Expect.equals("utf-8", data.charset);
+
+  // Uri.parseIPv6Address - shouldn't throw.
+  Uri.parseIPv6Address("::1");
+  Uri.parseIPv6Address("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210");
+  Uri.parseIPv6Address("3ffe:2a00:100:7031::1");
+  Uri.parseIPv6Address("::FFFF:129.144.52.38");
+  Uri.parseIPv6Address("2010:836B:4179::836B:4179");
+}
+
+test(String result, Uri value) {
+  Expect.equals(Uri.parse(result), value);
+  Expect.equals(result, value.toString());
+}
diff --git a/tests/corelib/uri_file_test.dart b/tests/corelib/uri_file_test.dart
index 79da833..ab7c6ab 100644
--- a/tests/corelib/uri_file_test.dart
+++ b/tests/corelib/uri_file_test.dart
@@ -88,6 +88,8 @@
     ["file:///C:/", "C:/", "C:\\"],
     ["file:///C:/a/b", "C:/a/b", "C:\\a\\b"],
     ["file:///C:/a/b/", "C:/a/b/", "C:\\a\\b\\"],
+
+    ["file:///C:/xxx/yyy", "C:\\xxx\\yyy", "C:\\xxx\\yyy"],
   ];
 
   for (var test in tests) {
diff --git a/tests/corelib/uri_test.dart b/tests/corelib/uri_test.dart
index bcd0976..76c59cf 100644
--- a/tests/corelib/uri_test.dart
+++ b/tests/corelib/uri_test.dart
@@ -33,10 +33,21 @@
                   Uri.parse(uriText + "#fragment").removeFragment());
   }
 
-  // Test uri.replace on uri with fragment
-  uri = Uri.parse('http://hello.com/fake#fragment');
-  uri = uri.replace(path: "D/E/E");
-  Expect.stringEquals('http://hello.com/D/E/E#fragment', uri.toString());
+  Expect.isTrue(uri.isScheme(uri.scheme));
+  Expect.isTrue(uri.isScheme(uri.scheme.toLowerCase()));
+  Expect.isTrue(uri.isScheme(uri.scheme.toUpperCase()));
+  if (uri.hasScheme) {
+    // Capitalize
+    Expect.isTrue(uri.isScheme(
+        uri.scheme[0].toUpperCase()+uri.scheme.substring(1)));
+    Expect.isFalse(uri.isScheme(
+        uri.scheme.substring(0, uri.scheme.length - 1)));
+    Expect.isFalse(uri.isScheme(uri.scheme + ":"));
+    Expect.isFalse(uri.isScheme(uri.scheme + "\x00"));
+  } else {
+    Expect.isTrue(uri.isScheme(null));
+    Expect.isFalse(uri.isScheme(":"));
+  }
 }
 
 testEncodeDecode(String orig, String encoded) {
@@ -753,6 +764,11 @@
   Expect.equals("s://a:1/b/c?#e", uri.replace(query: "").toString());
   Expect.equals("s://a:1?d#e", uri.replace(path: "").toString());
   Expect.equals("s://:1/b/c?d#e", uri.replace(host: "").toString());
+
+  // Test uri.replace on uri with fragment
+  uri = Uri.parse('http://hello.com/fake#fragment');
+  uri = uri.replace(path: "D/E/E");
+  Expect.stringEquals('http://hello.com/D/E/E#fragment', uri.toString());
 }
 
 void testRegression28359() {
diff --git a/tests/corelib_strong/apply3_test.dart b/tests/corelib_strong/apply3_test.dart
index ed0e6de..4f7051e 100644
--- a/tests/corelib_strong/apply3_test.dart
+++ b/tests/corelib_strong/apply3_test.dart
@@ -29,7 +29,7 @@
 
   var symbol = const Symbol('a');
   var requiredParameters = [1];
-  var optionalParameters = new Map()..[symbol] = 42;
+  var optionalParameters = new Map<Symbol, int>()..[symbol] = 42;
   Invocation i = Function.apply(
       new G(), requiredParameters, optionalParameters);
 
diff --git a/tests/corelib_strong/const_list_remove_range_test.dart b/tests/corelib_strong/const_list_remove_range_test.dart
index cff8a47..b7b15f7 100644
--- a/tests/corelib_strong/const_list_remove_range_test.dart
+++ b/tests/corelib_strong/const_list_remove_range_test.dart
@@ -10,7 +10,7 @@
   testImmutable(const [1, 2]);
 }
 
-void expectUOE(Function f) {
+void expectUOE(f()) {
   Expect.throws(f, (e) => e is UnsupportedError);
 }
 
diff --git a/tests/corelib_strong/const_list_set_range_test.dart b/tests/corelib_strong/const_list_set_range_test.dart
index 5523844..5a7a755 100644
--- a/tests/corelib_strong/const_list_set_range_test.dart
+++ b/tests/corelib_strong/const_list_set_range_test.dart
@@ -10,7 +10,7 @@
   testImmutable(const [1, 2]);
 }
 
-void expectUOE(Function f) {
+void expectUOE(f()) {
   Expect.throws(f, (e) => e is UnsupportedError);
 }
 
diff --git a/tests/corelib_strong/iterable_skip_test.dart b/tests/corelib_strong/iterable_skip_test.dart
index 59d604d..b9d97aa 100644
--- a/tests/corelib_strong/iterable_skip_test.dart
+++ b/tests/corelib_strong/iterable_skip_test.dart
@@ -215,17 +215,17 @@
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
-  skip0 = set2.skip(0);
-  it = skip0.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicSkip0 = set2.skip(0);
+  var dynamicIt = dynamicSkip0.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 
-  skip1 = set2.skip(1);
-  it = skip1.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicSkip1 = set2.skip(1);
+  dynamicIt = dynamicSkip1.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 
   testSkipTake(Iterable input, int skip, int take) {
     List expected = [];
diff --git a/tests/corelib_strong/iterable_skip_while_test.dart b/tests/corelib_strong/iterable_skip_while_test.dart
index d812300..1dcd869 100644
--- a/tests/corelib_strong/iterable_skip_while_test.dart
+++ b/tests/corelib_strong/iterable_skip_while_test.dart
@@ -134,15 +134,15 @@
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
-  skipWhileTrue = set2.skipWhile((x) => true);
-  it = skipWhileTrue.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicSkipWhileTrue = set2.skipWhile((x) => true);
+  var dynamicIt = dynamicSkipWhileTrue.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 
-  skipWhileFalse = set2.skipWhile((x) => false);
-  it = skipWhileFalse.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicSkipWhileFalse = set2.skipWhile((x) => false);
+  dynamicIt = dynamicSkipWhileFalse.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 }
diff --git a/tests/corelib_strong/iterable_take_test.dart b/tests/corelib_strong/iterable_take_test.dart
index fdedb93..926ab91 100644
--- a/tests/corelib_strong/iterable_take_test.dart
+++ b/tests/corelib_strong/iterable_take_test.dart
@@ -204,17 +204,17 @@
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
-  take0 = set2.take(0);
-  it = take0.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicTake0 = set2.take(0);
+  var dynamicIt = dynamicTake0.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 
-  take1 = set2.take(1);
-  it = take1.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicTake1 = set2.take(1);
+  dynamicIt = dynamicTake1.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 
   Expect.throws(() => list1.skip(-1), (e) => e is RangeError);
   Expect.throws(() => list2.skip(-1), (e) => e is RangeError);
diff --git a/tests/corelib_strong/iterable_take_while_test.dart b/tests/corelib_strong/iterable_take_while_test.dart
index 3fb615e..1407b57 100644
--- a/tests/corelib_strong/iterable_take_while_test.dart
+++ b/tests/corelib_strong/iterable_take_while_test.dart
@@ -118,15 +118,15 @@
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
-  takeWhileFalse = set2.takeWhile((x) => false);
-  it = takeWhileFalse.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicTakeWhileFalse = set2.takeWhile((x) => false);
+  var dynamicIt = dynamicTakeWhileFalse.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 
-  takeEverything = set2.takeWhile((x) => true);
-  it = takeEverything.iterator;
-  Expect.isNull(it.current);
-  Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
+  var dynamicTakeEverything = set2.takeWhile((x) => true);
+  dynamicIt = dynamicTakeEverything.iterator;
+  Expect.isNull(dynamicIt.current);
+  Expect.isFalse(dynamicIt.moveNext());
+  Expect.isNull(dynamicIt.current);
 }
diff --git a/tests/corelib_strong/list_fill_range_test.dart b/tests/corelib_strong/list_fill_range_test.dart
index 4553e43..5051d9c 100644
--- a/tests/corelib_strong/list_fill_range_test.dart
+++ b/tests/corelib_strong/list_fill_range_test.dart
@@ -65,10 +65,10 @@
   expectUE(() => test(const [1, 2, 3], 1, 4));
 }
 
-void expectRE(Function f) {
+void expectRE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
 
-void expectUE(Function f) {
+void expectUE(void f()) {
   Expect.throws(f, (e) => e is UnsupportedError);
 }
diff --git a/tests/corelib_strong/list_get_range_test.dart b/tests/corelib_strong/list_get_range_test.dart
index 221931c..faecef0 100644
--- a/tests/corelib_strong/list_get_range_test.dart
+++ b/tests/corelib_strong/list_get_range_test.dart
@@ -67,6 +67,6 @@
   Expect.equals(2, iterable.length);
 }
 
-void expectRE(Function f) {
+void expectRE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
diff --git a/tests/corelib_strong/list_insert_all_test.dart b/tests/corelib_strong/list_insert_all_test.dart
index a1d025a..08b08f4 100644
--- a/tests/corelib_strong/list_insert_all_test.dart
+++ b/tests/corelib_strong/list_insert_all_test.dart
@@ -75,10 +75,10 @@
   expectUE(() => test([1, 2, 3].toList(growable: false), 0, [4, 5]));
 }
 
-void expectRE(Function f) {
+void expectRE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
 
-void expectUE(Function f) {
+void expectUE(void f()) {
   Expect.throws(f, (e) => e is UnsupportedError);
 }
diff --git a/tests/corelib_strong/list_map_test.dart b/tests/corelib_strong/list_map_test.dart
index a5f48a8..4addcc7 100644
--- a/tests/corelib_strong/list_map_test.dart
+++ b/tests/corelib_strong/list_map_test.dart
@@ -56,7 +56,7 @@
     for (int i = 0; i < list.length; i++) {
       mappedList[i] = rev(list[i]);
     }
-    Iterable reversed = list.map(rev);
+    Iterable<int> reversed = list.map(rev);
 
     void testEquals(v1, v2, path) {
       if (v1 is Iterable) {
diff --git a/tests/corelib_strong/list_remove_range_test.dart b/tests/corelib_strong/list_remove_range_test.dart
index 94032a1..a36896f 100644
--- a/tests/corelib_strong/list_remove_range_test.dart
+++ b/tests/corelib_strong/list_remove_range_test.dart
@@ -41,7 +41,7 @@
   testNegativeIndices();
 }
 
-void expectIOORE(Function f) {
+void expectIOORE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
 
diff --git a/tests/corelib_strong/list_replace_range_test.dart b/tests/corelib_strong/list_replace_range_test.dart
index 26f016a..45b1a84 100644
--- a/tests/corelib_strong/list_replace_range_test.dart
+++ b/tests/corelib_strong/list_replace_range_test.dart
@@ -108,10 +108,10 @@
   expectUE(() => test(const [1, 2, 3], 1, 4, []));
 }
 
-void expectRE(Function f) {
+void expectRE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
 
-void expectUE(Function f) {
+void expectUE(void f()) {
   Expect.throws(f, (e) => e is UnsupportedError);
 }
diff --git a/tests/corelib_strong/list_set_all_test.dart b/tests/corelib_strong/list_set_all_test.dart
index 50be8b3..7214952 100644
--- a/tests/corelib_strong/list_set_all_test.dart
+++ b/tests/corelib_strong/list_set_all_test.dart
@@ -88,10 +88,10 @@
   expectUE(() => test(const [1, 2, 3], 1, [4, 5, 6]));
 }
 
-void expectRE(Function f) {
+void expectRE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
 
-void expectUE(Function f) {
+void expectUE(void f()) {
   Expect.throws(f, (e) => e is UnsupportedError);
 }
diff --git a/tests/corelib_strong/list_set_range_test.dart b/tests/corelib_strong/list_set_range_test.dart
index da80052..53195ab 100644
--- a/tests/corelib_strong/list_set_range_test.dart
+++ b/tests/corelib_strong/list_set_range_test.dart
@@ -58,15 +58,15 @@
   testNonExtendableList();
 }
 
-void expectIOORE(Function f) {
+void expectIOORE(void f()) {
   Expect.throws(f, (e) => e is RangeError);
 }
 
-void expectSE(Function f) {
+void expectSE(void f()) {
   Expect.throws(f, (e) => e is StateError);
 }
 
-void expectAE(Function f) {
+void expectAE(void f()) {
   Expect.throws(f, (e) => e is ArgumentError);
 }
 
diff --git a/tests/corelib_strong/list_sublist_test.dart b/tests/corelib_strong/list_sublist_test.dart
index 0581473..b513b8a 100644
--- a/tests/corelib_strong/list_sublist_test.dart
+++ b/tests/corelib_strong/list_sublist_test.dart
@@ -53,6 +53,6 @@
   expectAE(() => [1].sublist(1, 0));
 }
 
-void expectAE(Function f) {
+void expectAE(void f()) {
   Expect.throws(f, (e) => e is ArgumentError);
 }
diff --git a/tests/corelib_strong/set_test.dart b/tests/corelib_strong/set_test.dart
index 55e7250..e205ce6 100644
--- a/tests/corelib_strong/set_test.dart
+++ b/tests/corelib_strong/set_test.dart
@@ -369,10 +369,11 @@
   String toString() => "CE($id)";
 }
 
+typedef int CECompare(CE e1, CE e2);
 // Equality of Id objects based on id modulo value.
 Function customEq(int mod) => (CE e1, CE e2) => ((e1.id - e2.id) % mod) == 0;
 Function customHash(int mod) => (CE e) => e.id % mod;
-Function customCompare(int mod) => (CE e1, CE e2) =>
+CECompare customCompare(int mod) => (CE e1, CE e2) =>
     (e1.id % mod) - (e2.id % mod);
 bool validKey(Object o) => o is CE;
 final customId = new Map.identity();
diff --git a/tests/corelib_strong/shuffle_test.dart b/tests/corelib_strong/shuffle_test.dart
index c221c83..7f67911 100644
--- a/tests/corelib_strong/shuffle_test.dart
+++ b/tests/corelib_strong/shuffle_test.dart
@@ -95,7 +95,7 @@
 
 // Checks that the "random" argument to shuffle is used.
 testRandom() {
-  List randomNums = [37, 87, 42, 157, 252, 17];
+  List<int> randomNums = [37, 87, 42, 157, 252, 17];
   List numbers = new List.generate(25, (x) => x);
   List l1 = numbers.toList()..shuffle(new MockRandom(randomNums));
   for (int i = 0; i < 50; i++) {
diff --git a/tests/corelib_strong/sort_test.dart b/tests/corelib_strong/sort_test.dart
index 9327363..72e11a4 100644
--- a/tests/corelib_strong/sort_test.dart
+++ b/tests/corelib_strong/sort_test.dart
@@ -15,14 +15,14 @@
   compare = (a, b) => -a.compareTo(b);
   new SortHelper(sort, compare).run();
 
-  compare = (a, b) => a.compareTo(b);
+  var intCompare = (int a, int b) => a.compareTo(b);
 
   // Pivot-canditate indices: 7, 15, 22, 29, 37
   // Test dutch flag partitioning (canditates 2 and 4 are the same).
   var list = [0, 0, 0, 0, 0, 0, 0, 0/**/, 0, 0, 0, 0, 0, 0, 0,
               1/**/, 1, 1, 1, 1, 1, 1, 1/**/, 1, 1, 1, 1, 1, 1, 1/**/,
               2, 2, 2, 2, 2, 2, 2, 2/**/, 2, 2, 2, 2, 2, 2, 2];
-  list.sort(compare);
+  list.sort(intCompare);
   Expect.listEquals(list, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]);
@@ -30,7 +30,7 @@
   list = [0, 0, 0, 0, 0, 0, 0, 1/**/, 0, 0, 0, 0, 0, 0, 0,
           0/**/, 1, 1, 1, 1, 1, 1, 0/**/, 1, 1, 1, 1, 1, 1, 0/**/,
           2/**/, 2, 2, 2, 2, 2, 2, 2/**/, 2, 2, 2, 2, 2, 2, 2];
-  list.sort(compare);
+  list.sort(intCompare);
   Expect.listEquals(list, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                            0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]);
@@ -41,7 +41,7 @@
   list = [0, 9, 0, 9, 3, 9, 0, 1/**/, 1, 0, 1, 9, 8, 2, 1,
           1/**/, 4, 5, 2, 5, 0, 1, 8/**/, 8, 8, 5, 2, 2, 9, 8/**/,
           8, 4, 4, 1, 5, 3, 2, 8/**/, 5, 1, 2, 8, 5, 6, 8];
-  list.sort(compare);
+  list.sort(intCompare);
   Expect.listEquals(list, [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
                            2, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5,
                            6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9]);
diff --git a/tests/corelib_strong/splay_tree_from_iterable_test.dart b/tests/corelib_strong/splay_tree_from_iterable_test.dart
index 6ba1818..35bdf92 100644
--- a/tests/corelib_strong/splay_tree_from_iterable_test.dart
+++ b/tests/corelib_strong/splay_tree_from_iterable_test.dart
@@ -117,6 +117,8 @@
   Expect.isFalse(map is SplayTreeMap<String, dynamic>);
   Expect.isFalse(map is SplayTreeMap<dynamic, int>);
 }
+typedef String intToString(int v);
+typedef bool intToBool(int v);
 
 // Test in checked mode with explicitly given types.
 void typedTest() {
@@ -124,11 +126,11 @@
   assert((isCheckedMode = true));
   if (!isCheckedMode) return;
 
-  // Assign functions to untyped function variables.
-  Function key = (int v) => "$v";
-  Function value = (int v) => v.isOdd;
+  // Assign functions to typed function variables.
+  intToString key = (int v) => "$v";
+  intToBool value = (int v) => v.isOdd;
   Function id = (int i) => i;
-
+  
   Expect.throws(() {
     new SplayTreeMap<String,bool>.fromIterable(<int>[1, 2, 3],
       key: key
@@ -145,7 +147,7 @@
 
   Expect.throws(() {
     new SplayTreeMap<String,bool>.fromIterable(<int>[1, 2, 3],
-      key: id,     // wrong type.
+      key: id as dynamic,     // wrong type.
       value: value
     );
   });
@@ -153,7 +155,7 @@
   Expect.throws(() {
     new SplayTreeMap<String,bool>.fromIterable(<int>[1, 2, 3],
       key: key,
-      value: id    // wrong type.
+      value: id as dynamic   // wrong type.
     );
   });
 
diff --git a/tests/html/html.status b/tests/html/html.status
index 0bf4421..963d72a 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -422,6 +422,9 @@
 window_nosuchmethod_test: StaticWarning
 js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue #25759
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $compiler == dart2js && $fast_startup ]
 custom/constructor_calls_created_synchronously_test: Fail # mirrors not supported
 custom/js_custom_test: Fail # mirrors not supported
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index f9ff809..2af147b 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -2,6 +2,9 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
+[$runtime == vm && $compiler == none && $system == fuchsia]
+*: Skip  # Not yet triaged.
+
 [ $runtime == vm || $runtime == dart_precompiled ]
 browser/*: SkipByDesign  # Browser specific tests
 isolate_stress_test: Skip # Issue 12588: Uses dart:html. This should be able to pass when we have wrapper-less tests.
@@ -166,6 +169,9 @@
 browser/typed_data_message_test: StaticWarning
 mint_maker_test: StaticWarning
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $compiler == none && $runtime == vm ]
 scenarios/short_package/short_package_test: Fail, OK  # We do not plan to support the tested behavior anyway.
 
diff --git a/tests/kernel/kernel.status b/tests/kernel/kernel.status
index ab88299..066d789 100644
--- a/tests/kernel/kernel.status
+++ b/tests/kernel/kernel.status
@@ -12,6 +12,9 @@
 unsorted/invocation_errors_test: StaticWarning
 unsorted/super_mixin_test: CompileTimeError
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $compiler == dart2js ]
 unsorted/invocation_errors_test: Pass
 unsorted/nsm_dispatcher_test: Skip # The test uses Symbol without MirrorsUsed
diff --git a/tests/language/bad_raw_string_negative_test.dart b/tests/language/bad_raw_string_negative_test.dart
deleted file mode 100644
index 89b4659..0000000
--- a/tests/language/bad_raw_string_negative_test.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-main() {
-  // Raw String may not contain newline (may not be multi-line).
-  print(r'
-');
-}
diff --git a/tests/language/bad_raw_string_test.dart b/tests/language/bad_raw_string_test.dart
new file mode 100644
index 0000000..8c3890d
--- /dev/null
+++ b/tests/language/bad_raw_string_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+  // Raw String may not contain newline (may not be multi-line).
+  String x = ''
+    r'  /// 01: compile-time error
+'       /// 01: continued
+    r"  /// 02: compile-time error
+"       /// 02: continued
+    // Test that a raw string containing just one character, a \n char, fails.
+    // Enclose the test string in a bigger multiline string, except in case 03:
+    '''  /// 03: compile-time error
+    """
+    '''  /// 03: continued
+    r'
+'
+    '''  /// 03: continued
+    """
+    '''  /// 03: continued
+  ;
+}
diff --git a/tests/language/deferred_regression_28678_lib.dart b/tests/language/deferred_regression_28678_lib.dart
new file mode 100644
index 0000000..f36c206
--- /dev/null
+++ b/tests/language/deferred_regression_28678_lib.dart
@@ -0,0 +1,7 @@
+// 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.
+
+var v;
+
+class Clazz { }
diff --git a/tests/language/deferred_regression_28678_test.dart b/tests/language/deferred_regression_28678_test.dart
new file mode 100644
index 0000000..5051e72
--- /dev/null
+++ b/tests/language/deferred_regression_28678_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that await after deferred loading works as expected.
+
+import 'dart:async';
+import "package:expect/expect.dart";
+import 'deferred_regression_28678_lib.dart' deferred as lib;
+
+class A {
+  m() => "here";
+}
+
+f(a, b) => new Future.microtask(() {});
+
+class R {
+  Future test_deferred() async {
+    var a = new A();
+    await lib.loadLibrary();
+    await f(lib.Clazz, lib.v);
+    Expect.equals("here", a.m());
+  }
+}
+
+main() async {
+  await new R().test_deferred();
+}
diff --git a/tests/language/full_stacktrace1_test.dart b/tests/language/full_stacktrace1_test.dart
index 945ca70..9206158 100644
--- a/tests/language/full_stacktrace1_test.dart
+++ b/tests/language/full_stacktrace1_test.dart
@@ -15,6 +15,7 @@
     func2();
   } on Object catch(e, s) {
     var fullTrace = s.toString();
+    print(fullTrace);
     Expect.isTrue(fullTrace.contains("func1"));
     Expect.isTrue(fullTrace.contains("func2"));
     Expect.isTrue(fullTrace.contains("func3"));
diff --git a/tests/language/full_stacktrace2_test.dart b/tests/language/full_stacktrace2_test.dart
index 5de34e0..57934f6 100644
--- a/tests/language/full_stacktrace2_test.dart
+++ b/tests/language/full_stacktrace2_test.dart
@@ -15,6 +15,7 @@
     func2();
   } on Object catch(e, s) {
     var fullTrace = s.toString();
+    print(fullTrace);
     Expect.isTrue(fullTrace.contains("func1"));
     Expect.isTrue(fullTrace.contains("func2"));
     Expect.isTrue(fullTrace.contains("func3"));
@@ -36,6 +37,7 @@
     func4();
   } on Object catch(e, s) {
     var fullTrace = s.toString();
+    print(fullTrace);
     Expect.isTrue(fullTrace.contains("func1"));
     Expect.isTrue(fullTrace.contains("func2"));
     Expect.isTrue(fullTrace.contains("func3"));
diff --git a/tests/language/full_stacktrace3_test.dart b/tests/language/full_stacktrace3_test.dart
index 553f86a..2d98a9b 100644
--- a/tests/language/full_stacktrace3_test.dart
+++ b/tests/language/full_stacktrace3_test.dart
@@ -15,6 +15,7 @@
     func2();
   } on Object catch(e, s) {
     var fullTrace = s.toString();
+    print(fullTrace);
     Expect.isTrue(fullTrace.contains("func1"));
     Expect.isTrue(fullTrace.contains("func2"));
     Expect.isTrue(fullTrace.contains("func3"));
@@ -35,6 +36,7 @@
     func4();
   } on Object catch(e, s) {
     var fullTrace = s.toString();
+    print(fullTrace);
     Expect.isFalse(fullTrace.contains("func1"));
     Expect.isFalse(fullTrace.contains("func2"));
     Expect.isTrue(fullTrace.contains("func3"));
diff --git a/tests/language/language.status b/tests/language/language.status
index 717b3d4..83474af 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -44,7 +44,7 @@
 dynamic_prefix_core_test/01: RuntimeError # Issue 12478
 multiline_strings_test: Fail # Issue 23020
 
-deferred_redirecting_factory_test: Fail # Issue 23408
+deferred_redirecting_factory_test: Fail, Crash # Issue 23408
 redirecting_constructor_initializer_test: RuntimeError # Issue 23488
 
 async_star_regression_2238_test: CompileTimeError, RuntimeError # drt only runtime-errs.
@@ -66,6 +66,7 @@
 
 [ ($compiler == none || $compiler == precompiler || $compiler == app_jit) && $checked ]
 type_variable_bounds4_test/01: Fail # Issue 14006
+generalized_function_type_test: SkipSlow # Times out in checked mode. Generated test is too large.
 
 [ ($compiler == none || $compiler == precompiler || $compiler == app_jit) && (($runtime == vm || $runtime == dart_precompiled) || $runtime == drt || $runtime == dartium) ]
 dynamic_prefix_core_test/none: Fail # Issue 12478
@@ -152,18 +153,6 @@
 [ $compiler == precompiler && $runtime == dart_precompiled ]
 vm/regress_27671_test: Skip # Unsupported
 
-[ $runtime == dart_precompiled ]
-# Stacktraces in precompilation omit inlined frames.
-full_stacktrace1_test: Pass, RuntimeError
-full_stacktrace2_test: Pass, RuntimeError
-full_stacktrace3_test: Pass, RuntimeError
-stack_trace_test: Pass, RuntimeError
-stacktrace_rethrow_error_test: Pass, RuntimeError
-stacktrace_rethrow_nonerror_test: Pass, RuntimeError
-stacktrace_test: Pass, RuntimeError
-vm/regress_28325_test: RuntimeError  # Missing source position in AOT.
-
-
 [ $runtime == dart_precompiled || $mode == product ]
 # Imports dart:mirrors
 const_evaluation_test: SkipByDesign
@@ -187,21 +176,26 @@
 super_getter_setter_test: SkipByDesign
 vm/reflect_core_vm_test: SkipByDesign
 regress_28255_test: SkipByDesign
+# Causal async stacks are not supported in product mode
+vm/causal_async_exception_stack_test: SkipByDesign
+vm/causal_async_exception_stack2_test: SkipByDesign
 
 [ $mode == product || $compiler == app_jit || $compiler == precompiler ]
 # Deferred loading happens eagerly. Issue #27587
-regress_23408_test: Fail
-deferred_inheritance_constraints_test/redirecting_constructor: Fail
 deferred_load_constants_test/02: Fail
 deferred_load_constants_test/03: Fail
 deferred_load_constants_test/05: Fail
 deferred_not_loaded_check_test: Fail
 vm/regress_27201_test: Fail
 
+[ $compiler == app_jit ]
+deferred_inheritance_constraints_test/redirecting_constructor: Crash
+
 [ $compiler == precompiler ]
 # Deferred loading happens eagerly. Issue #27587
 deferred_global_test: Fail
 vm/regress_27201_test: Fail
+regress_23408_test: RuntimeError
 
 [ $compiler == precompiler ]
 implicit_closure_test: Skip # Incompatible flag: --use_slow_path
@@ -272,6 +266,7 @@
 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
@@ -311,9 +306,10 @@
 # Use package:unittest
 async_await_test: RuntimeError
 async_star_test: RuntimeError
+vm/causal_async_exception_stack_test: RuntimeError
 # TODO(zra): Investigate
 vm/regress_28325_test: RuntimeError
-closure_cycles_test: Crash
+closure_cycles_test: Pass, Crash
 
 [$compiler == dart2analyzer]
 vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index a0d13a5..f48642d 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -4,6 +4,9 @@
 
 [ $compiler == dart2analyzer ]
 
+generic_methods_generic_function_parameter_test: CompileTimeError # Issue 28515
+generic_local_functions_test: CompileTimeError # Issue 28515
+
 regress_26668_test: Fail # Issue 26678
 regress_27617_test/1: MissingCompileTimeError
 
@@ -496,3 +499,9 @@
 initializing_formal_type_test: StaticWarning # Issue 26658
 
 regress_27572_test: StaticWarning # Warning about undefined method expected.
+
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
+[ $compiler == dart2analyzer && $system != windows ]
+bad_raw_string_test/03: MissingCompileTimeError # Issue 28664
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 49d844c..2e8e2ed 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -15,9 +15,6 @@
 try_catch_on_syntax_test/10: Fail # Issue 19823
 try_catch_on_syntax_test/11: Fail # Issue 19823
 
-deep_nesting1_negative_test: Crash # Issue 25557
-deep_nesting2_negative_test: Crash # Issue 25557
-
 call_function_apply_test: RuntimeError # Issue 23873
 mixin_supertype_subclass_test: CompileTimeError # Issue 23773
 mixin_supertype_subclass2_test: CompileTimeError # Issue 23773
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index c53b287..90433a9 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -11,14 +11,14 @@
 ###############################################################################
 
 [ $compiler == dartk || $compiler == dartkp ]
-conditional_import_string_test: DartkCompileTimeError
-conditional_import_test: DartkCompileTimeError
-conflicting_type_variable_and_setter_test: DartkCompileTimeError
+bad_raw_string_test/03: MissingCompileTimeError
+conditional_import_string_test: CompileTimeError
+conditional_import_test: CompileTimeError
+conflicting_type_variable_and_setter_test: CompileTimeError
 const_for_in_variable_test/01: MissingCompileTimeError
 constructor_duplicate_final_test/03: MissingCompileTimeError
 deep_nesting1_negative_test: DartkCrash
 deep_nesting2_negative_test: DartkCrash
-enum_syntax_test/05: MissingCompileTimeError
 enum_syntax_test/06: MissingCompileTimeError
 external_test/21: MissingCompileTimeError
 external_test/24: MissingCompileTimeError
@@ -27,39 +27,33 @@
 final_syntax_test/02: MissingCompileTimeError
 final_syntax_test/03: MissingCompileTimeError
 final_syntax_test/04: MissingCompileTimeError
-metadata_test: DartkCompileTimeError
-multiline_newline_test/01: DartkCompileTimeError
-multiline_newline_test/02: DartkCompileTimeError
-multiline_newline_test/03: DartkCompileTimeError
+generic_local_functions_test: CompileTimeError # Issue 28515
+generic_methods_generic_function_parameter_test: CompileTimeError # Issue 28515
+main_not_a_function_test/01: Pass # Fails if tree shaking is disabled
+metadata_test: CompileTimeError
+mixin_illegal_syntax_test/00: DartkCrash
+multiline_newline_test/01: CompileTimeError
+multiline_newline_test/02: CompileTimeError
+multiline_newline_test/03: CompileTimeError
 multiline_newline_test/04: MissingCompileTimeError
 multiline_newline_test/05: MissingCompileTimeError
 multiline_newline_test/06: MissingCompileTimeError
-not_enough_positional_arguments_test/01: DartkCompileTimeError
 regress_27617_test/1: MissingCompileTimeError
 type_variable_conflict2_test/02: MissingCompileTimeError
-vm/debug_break_enabled_vm_test/01: DartkCompileTimeError
-vm/debug_break_enabled_vm_test/none: DartkCompileTimeError
-vm/reflect_core_vm_test: DartkCompileTimeError
-vm/regress_27201_test: DartkCompileTimeError
+vm/debug_break_enabled_vm_test/01: CompileTimeError
+vm/debug_break_enabled_vm_test/none: CompileTimeError
+vm/reflect_core_vm_test: CompileTimeError
+vm/regress_27201_test: CompileTimeError
 vm/regress_28325_test: RuntimeError  # Issue 28055.
 
-# dartk: temporary failure
-mixin_illegal_syntax_test/00: DartkCrash
-
-# Passing for the wrong reason
-language/main_not_a_function_test/01: Pass # Fails if tree shaking is disabled
-
 # dartk: JIT failures
 [ $compiler == dartk && $runtime == vm ]
 config_import_corelib_test: RuntimeError
-reify_typevar_static_test/00: MissingCompileTimeError
-type_variable_conflict2_test/06: MissingCompileTimeError
-type_variable_conflict2_test/08: MissingCompileTimeError
-type_variable_conflict2_test/10: MissingCompileTimeError
 
 # dartk: precompilation failures
 [ $compiler == dartkp && $runtime == dart_precompiled ]
 config_import_corelib_test: RuntimeError
+not_enough_positional_arguments_test/01: DartkCompileTimeError # Issue 28590
 
 ###############################################################################
 # VM Entries
@@ -168,27 +162,20 @@
 inferrer_closure_test: RuntimeError
 initializing_formal_final_test: RuntimeError
 is_not_class2_test: RuntimeError
-issue13474_test: RuntimeError
 issue_1751477_test: RuntimeError
 library_env_test/has_html_support: RuntimeError
 library_env_test/has_no_io_support: RuntimeError
 list_literal4_test: RuntimeError
 malformed_test/none: RuntimeError
 map_literal3_test: RuntimeError
-map_literal4_test: RuntimeError  # VM checked mode Issue 28420
 map_literal6_test: RuntimeError
 method_override_test: RuntimeError
 mixin_type_parameters_super_extends_test: RuntimeError
 mixin_type_parameters_super_test: RuntimeError
 multiline_newline_test/none: RuntimeError
-named_parameters_type_test/01: MissingRuntimeError
-named_parameters_type_test/02: MissingRuntimeError
-named_parameters_type_test/03: MissingRuntimeError
 not_enough_positional_arguments_test/02: MissingRuntimeError  # Dartk Issue 28301
 not_enough_positional_arguments_test/05: MissingRuntimeError  # Dartk Issue 28301
 number_identifier_test/05: RuntimeError
-positional_parameters_type_test/01: MissingRuntimeError
-positional_parameters_type_test/02: MissingRuntimeError
 prefix10_negative_test: Fail
 prefix21_test: RuntimeError
 redirecting_constructor_initializer_test: RuntimeError
@@ -202,7 +189,6 @@
 switch7_negative_test: Fail  # Dartk Issue 28416
 try_catch_on_syntax_test/10: MissingRuntimeError  # Dartk Issue 28410
 try_catch_on_syntax_test/11: MissingRuntimeError  # Dartk Issue 28410
-type_checks_in_factory_method_test: RuntimeError
 type_variable_function_type_test: RuntimeError
 vm/type_cast_vm_test: RuntimeError
 vm/type_vm_test: RuntimeError
@@ -212,9 +198,15 @@
 const_locals_test: RuntimeError
 constructor_named_arguments_test/01: Crash  # Dartk Issue 28301
 const_string_test: RuntimeError  # Dartk Issue 28306
+deferred_regression_28678_test: RuntimeError
 library_env_test/has_no_mirror_support: RuntimeError
+main_not_a_function_test/01: Crash
 redirecting_factory_reflection_test: RuntimeError
 
+# Casual async stack traces are not implemented for Kernel.
+vm/causal_async_exception_stack_test: RuntimeError
+vm/causal_async_exception_stack2_test: RuntimeError
+
 # dartk: JIT failures (debug)
 [ $compiler == dartk && $runtime == vm && $mode == debug ]
 not_enough_positional_arguments_test/02: Crash  # Dartk Issue 28301
@@ -222,14 +214,14 @@
 
 # dartk: precompilation failures
 [ $compiler == dartkp && $runtime == dart_precompiled ]
-if_null_assignment_static_test/35: Crash  # Dartk Issue 28302
+deferred_regression_28678_test: RuntimeError # Issue 28335
+enum_syntax_test/05: MissingCompileTimeError
 
 # dartk: precompilation failures (debug)
 [ $compiler == dartkp && $runtime == dart_precompiled && $mode == debug ]
 constructor_named_arguments_test/01: Crash  # Dartk Issue 28301
 not_enough_positional_arguments_test/05: Crash  # Dartk Issue 28301
 
-
 # New failures after respecting VMOptions in test files
 [ $compiler == dartk || $compiler == dartkp ]
 vm/regress_27671_test: RuntimeError
@@ -242,23 +234,14 @@
 [ $compiler == dartk && $runtime == vm ]
 hello_dart_test: CompileTimeError  # VMOptions=--compile-all causes us to hit "native function VMServiceIO_Shutdown cannot be resolved"
 ct_const2_test: Pass, CompileTimeError  # VMOptions=--compile-all causes us to hit "native function VMServiceIO_Shutdown cannot be resolved"
-disassemble_test: Pass, Crash  # Multitest via multiple VMOptions!
 
 # Failures during Gardening shift: To be triaged!
 [ $compiler == dartk || $compiler == dartkp ]
 runtime_type_function_test: RuntimeError
 
-# Failures during Gardening shift: To be triaged!
-[ $compiler == dartkp && $runtime == dart_precompiled ]
-assert_with_type_test_or_cast_test: Pass, Crash  # Multitest via multiple VMOptions.
-named_parameters_type_test/01: Crash
-named_parameters_type_test/02: Crash
-named_parameters_type_test/03: Crash
-positional_parameters_type_test/01: Crash
-positional_parameters_type_test/02: Crash
-type_checks_in_factory_method_test: Crash
-vm/regress_27671_test: Crash
-vm/type_vm_test: Crash
+[ $compiler == dartkp ]
+bad_raw_string_test/none: Skip # Issue 28680
+bad_raw_string_test/03: Skip # Issue 28680
 
 # Triaged checked mode failures
 [ ($compiler == dartk || $compiler == dartkp) && $checked ]
diff --git a/tests/language/regress_28610_test.dart b/tests/language/regress_28610_test.dart
new file mode 100644
index 0000000..adefd32d
--- /dev/null
+++ b/tests/language/regress_28610_test.dart
@@ -0,0 +1,14 @@
+// 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:expect/expect.dart";
+
+class A {
+  final int Function = 0;
+}
+
+main() {
+  final int Function = 0;
+  Expect.equals(Function, new A().Function);
+}
diff --git a/tests/language/stack_trace_test.dart b/tests/language/stack_trace_test.dart
index 5b728a9..b3ebea5 100644
--- a/tests/language/stack_trace_test.dart
+++ b/tests/language/stack_trace_test.dart
@@ -121,6 +121,7 @@
       try {
         d();
       } catch (e, s) {
+        print(s);
         Expect.isTrue(s.toString().contains("issue12940"));
       }
     }
diff --git a/tests/language/vm/async_await_catch_stacktrace_test.dart b/tests/language/vm/async_await_catch_stacktrace_test.dart
index f49ce15..727b242 100644
--- a/tests/language/vm/async_await_catch_stacktrace_test.dart
+++ b/tests/language/vm/async_await_catch_stacktrace_test.dart
@@ -43,7 +43,6 @@
 
       Expect.isFalse(stText.contains("propagateToListeners"));
       Expect.isFalse(stText.contains("_completeError"));
-      Expect.isFalse(stText.contains("main"));
     }
     print("Ending!");
   }
diff --git a/tests/language/vm/causal_async_exception_stack2_test.dart b/tests/language/vm/causal_async_exception_stack2_test.dart
new file mode 100644
index 0000000..18afd98
--- /dev/null
+++ b/tests/language/vm/causal_async_exception_stack2_test.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:unittest/unittest.dart';
+
+foo3() async => throw "foo";
+bar3() async => throw "bar";
+
+foo2() async => foo3();
+bar2() async => bar3();
+
+foo() async => foo2();
+bar() async => bar2();
+
+test1() async {
+  // test1 -> foo -> foo2 -> foo3
+  // test1 -> bar -> bar2 -> bar3
+  // These run interleaved, check their stack traces don't become mixed.
+  var a = foo();
+  var b = bar();
+
+  try {
+    await a;
+  } catch(e, st) {
+    // st has foo,2,3 and not bar,2,3.
+    expect(st.toString(), stringContainsInOrder([
+           'foo3',
+           '<asynchronous suspension>',
+           'foo2',
+           '<asynchronous suspension>',
+           'foo',
+           '<asynchronous suspension>',
+           'test1',
+           ]));
+    expect(st.toString().contains('bar'), isFalse);
+  }
+
+  try {
+    await b;
+  } catch(e, st) {
+    // st has bar,2,3 but not foo,2,3
+    expect(st.toString(), stringContainsInOrder([
+           'bar3',
+           '<asynchronous suspension>',
+           'bar2',
+           '<asynchronous suspension>',
+           'bar',
+           '<asynchronous suspension>',
+           'test1',
+           ]));
+    expect(st.toString().contains('foo'), isFalse);
+  }
+}
+
+test2() async {
+  // test2 -> foo -> foo2 -> foo3
+  // test2 -> bar -> bar2 -> bar3
+  // These run sequentially, check the former stack trace didn't get linked to
+  // from the latter stack trace.
+
+  try {
+    await foo();
+  } catch(e, st) {
+    // st has foo,2,3 but not bar,2,3
+    expect(st.toString(), stringContainsInOrder([
+           'foo3',
+           '<asynchronous suspension>',
+           'foo2',
+           '<asynchronous suspension>',
+           'foo',
+           '<asynchronous suspension>',
+           'test2',
+           ]));
+    expect(st.toString().contains('bar'), isFalse);
+  }
+
+  try {
+    await bar();
+  } catch(e, st) {
+    // st has bar,2,3 but not foo,2,3
+    expect(st.toString(), stringContainsInOrder([
+           'bar3',
+           '<asynchronous suspension>',
+           'bar2',
+           '<asynchronous suspension>',
+           'bar',
+           '<asynchronous suspension>',
+           'test2',
+           ]));
+    expect(st.toString().contains('foo'), isFalse);
+  }
+}
+
+main() async {
+  await test1();
+  await test2();
+}
\ No newline at end of file
diff --git a/tests/language/vm/causal_async_exception_stack_test.dart b/tests/language/vm/causal_async_exception_stack_test.dart
new file mode 100644
index 0000000..ed4147f
--- /dev/null
+++ b/tests/language/vm/causal_async_exception_stack_test.dart
@@ -0,0 +1,75 @@
+// 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:unittest/unittest.dart';
+
+thrower() async {
+  throw 'oops';
+}
+
+number() async {
+  return 4;
+}
+
+generator() async* {
+  yield await number();
+  yield await thrower();
+}
+
+foo() async {
+  await for (var i in generator()) {
+    print(i);
+  }
+}
+
+main() async {
+  // Test async and async*.
+  try {
+    await foo();
+  } catch (e, st) {
+    expect(st.toString(), stringContainsInOrder([
+        'thrower',
+        '<asynchronous suspension>',
+        'generator',
+        '<asynchronous suspension>',
+        'foo',
+        '<asynchronous suspension>',
+        'main',
+        ]));
+  }
+
+  inner() async {
+    deep() async {
+      await thrower();
+    }
+    await deep();
+  }
+
+  // Test inner functions.
+  try {
+    await inner();
+  } catch (e, st) {
+    expect(st.toString(), stringContainsInOrder([
+          'thrower',
+          '<asynchronous suspension>',
+          'main.inner.deep',
+          '<asynchronous suspension>',
+          'main.inner',
+          '<asynchronous suspension>',
+          'main',
+          '<asynchronous suspension>',
+          ]));
+  }
+
+  // Test for correct linkage.
+  try {
+    await thrower();
+  } catch(e, st) {
+    expect(st.toString(), stringContainsInOrder([
+           'thrower',
+           '<asynchronous suspension>',
+           'main',
+           ]));
+  }
+}
\ No newline at end of file
diff --git a/tests/language_strong/async_call_test.dart b/tests/language_strong/async_call_test.dart
new file mode 100644
index 0000000..3bddf87
--- /dev/null
+++ b/tests/language_strong/async_call_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "package:expect/expect.dart";
+
+var result = "";
+
+foo() {
+  result += "foo";
+}
+
+bar() async {
+  result += "bar";
+}
+
+main() async {
+  var f = new Future(foo);
+  var b = bar();
+  Expect.equals("", result);
+  scheduleMicrotask(() => result += "micro");
+  await b;
+  await f;
+
+  // Validates that bar is scheduled as a microtask, before foo.
+  Expect.equals("barmicrofoo", result);
+}
diff --git a/tests/language_strong/field_override_optimization_test.dart b/tests/language_strong/field_override_optimization_test.dart
new file mode 100644
index 0000000..573d154
--- /dev/null
+++ b/tests/language_strong/field_override_optimization_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:meta/meta.dart";
+
+class A {
+  @virtual final bool flag = true;
+  @virtual final int x = 42;
+}
+
+class B extends A {
+  bool flag;
+  int x;
+}
+
+void main() {
+  A a = new B();
+  var exception;
+  try {
+    if (a.flag) {
+      Expect.fail('This should be unreachable');
+    } else {
+      Expect.fail('This should also be unreachable');
+    }
+  } on AssertionError catch(e) {
+    exception = e;
+  }
+  Expect.isTrue(exception is AssertionError);
+  Expect.throws(() => a.x + 8);
+}
+
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 98b521c..97c88b3 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -2,29 +2,37 @@
 # for 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 == dartanalyzer || $compiler == dart2analyzer ]
-lib/html/dart2js/html_dart2js: CompileTimeError # Issue 16522
-lib/html/html_common/html_common_dart2js: CompileTimeError # Issue 16522
+[ $compiler == dart2analyzer && $use_sdk ]
+lib/*: Skip # Issue 28620
+lib/analyzer: Skip # Issue 28620
+lib/analysis_server: Skip # Issue 28620
+lib/dev_compiler: Skip # Issue 28620
+lib/front_end: Skip # Issue 28620
+
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
+[ $compiler == dart2analyzer ]
+lib/_blink/dartium/_blink_dartium: StaticWarning # Undefined Creates and Returns classes
 lib/_chrome/dart2js/chrome_dart2js: CompileTimeError # Issue 16522
+lib/html/dart2js/html_dart2js: CompileTimeError # Issue 16522
+lib/html/dartium/html_dartium: StaticWarning # Issue 21647
+lib/html/html_common/html_common: StaticWarning # Issue 21647
+lib/html/html_common/html_common_dart2js: CompileTimeError # Issue 16522
 lib/html/html_common/html_common_dart2js: CompileTimeError # Issue 16522
 lib/indexed_db/dart2js/indexed_db_dart2js: CompileTimeError # Issue 16522
+lib/indexed_db/dartium/indexed_db_dartium: StaticWarning # Issue 21647
 lib/js/dart2js/js_dart2js: CompileTimeError # Issue 16522
 lib/js_util/dart2js/js_util_dart2js: CompileTimeError # Issue 16522
 lib/svg/dart2js/svg_dart2js: CompileTimeError # Issue 16522
+lib/svg/dartium/svg_dartium: StaticWarning # Issue 21647
 lib/typed_data/dart2js/native_typed_data_dart2js: CompileTimeError # Issue 16522
 lib/typed_data/dart2js/typed_data_dart2js: CompileTimeError # Issue 16522
 lib/web_audio/dart2js/web_audio_dart2js: CompileTimeError # Issue 16522
-lib/web_gl/dart2js/web_gl_dart2js: CompileTimeError # Issue 16522
-lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError # Issue 16522
-
-[ $compiler == dart2analyzer ]
-lib/web_gl/dartium/web_gl_dartium: StaticWarning # Issue 21647
-lib/web_sql/dartium/web_sql_dartium: StaticWarning # Issue 21647
-lib/html/dartium/html_dartium: StaticWarning # Issue 21647
-lib/html/html_common/html_common: StaticWarning # Issue 21647
-lib/indexed_db/dartium/indexed_db_dartium: StaticWarning # Issue 21647
 lib/web_audio/dartium/web_audio_dartium: StaticWarning # Issue 21647
-lib/svg/dartium/svg_dartium: StaticWarning # Issue 21647
-lib/_blink/dartium/_blink_dartium: StaticWarning # Undefined Creates and Returns classes
+lib/web_gl/dart2js/web_gl_dart2js: CompileTimeError # Issue 16522
+lib/web_gl/dartium/web_gl_dartium: StaticWarning # Issue 21647
+lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError # Issue 16522
+lib/web_sql/dartium/web_sql_dartium: StaticWarning # Issue 21647
 lib/js/dartium/js_dartium: StaticWarning # Undefined Creates and Returns classes
 lib/js_util/dartium/js_util_dartium: StaticWarning # Issue 21647
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index c064cd7..493fe57 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -243,6 +243,9 @@
 async/slow_consumer_test: Pass, Timeout # Issue 22696
 async/catch_errors11_test: Pass, Timeout # Issue 22696
 
+[ $runtime == chrome && $system == linux ]
+mirrors/native_class_test: Pass, Slow
+
 [ $runtime == chrome || $runtime == ff ]
 convert/streamed_conversion_utf8_encode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
@@ -281,6 +284,49 @@
 
 async/future_or_strong_test: RuntimeError, OK
 
+[ $runtime == vm && $system == fuchsia ]
+# These use package:unittest
+async/first_regression_test: RuntimeError
+async/future_timeout_test: RuntimeError
+async/multiple_timer_test: RuntimeError
+async/schedule_microtask2_test: RuntimeError
+async/schedule_microtask3_test: RuntimeError
+async/schedule_microtask5_test: RuntimeError
+async/stream_controller_async_test: RuntimeError
+async/stream_first_where_test: RuntimeError
+async/stream_from_iterable_test: RuntimeError
+async/stream_iterator_test: RuntimeError
+async/stream_join_test: RuntimeError
+async/stream_last_where_test: RuntimeError
+async/stream_periodic2_test: RuntimeError
+async/stream_periodic3_test: RuntimeError
+async/stream_periodic4_test: RuntimeError
+async/stream_periodic5_test: RuntimeError
+async/stream_periodic6_test: RuntimeError
+async/stream_periodic_test: RuntimeError
+async/stream_single_test: RuntimeError
+async/stream_single_to_multi_subscriber_test: RuntimeError
+async/stream_state_nonzero_timer_test: RuntimeError
+async/stream_state_test: RuntimeError
+async/stream_subscription_as_future_test: RuntimeError
+async/stream_subscription_cancel_test: RuntimeError
+async/stream_timeout_test: RuntimeError
+async/stream_transform_test: RuntimeError
+async/stream_transformation_broadcast_test: RuntimeError
+async/timer_cancel1_test: RuntimeError
+async/timer_cancel2_test: RuntimeError
+async/timer_cancel_test: RuntimeError
+async/timer_isActive_test: RuntimeError
+async/timer_repeat_test: RuntimeError
+async/timer_test: RuntimeError
+convert/json_lib_test: RuntimeError
+math/point_test: RuntimeError
+math/rectangle_test: RuntimeError
+mirrors/library_uri_io_test: RuntimeError
+mirrors/library_uri_package_test: RuntimeError
+# fstat bug, MG-479.
+mirrors/invocation_fuzz_test: Crash
+
 [ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 async/future_or_bad_type_test/implements: Pass # Issue 28084
 
@@ -340,6 +386,9 @@
 [ ($compiler == dartanalyzer || $compiler == dart2analyzer) && $checked ]
 mirrors/regress_16321_test/01: MissingCompileTimeError # Issue 16391
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $compiler == dart2js && $runtime == d8 && $system == windows ]
 async/*deferred*: Pass,RuntimeError # Issue 17458
 mirrors/*deferred*: Pass,RuntimeError # Issue 17458
@@ -389,7 +438,6 @@
 *: Skip # Issue 25761
 
 [ $compiler == dart2js && $host_checked ]
-mirrors/circular_factory_redirection_test/02: Crash # Assertion failure: Constant constructor already computed for generative_constructor(A#circular2).  Issue 25911
 mirrors/metadata_allowed_values_test/28: Crash # Issue 25911
 mirrors/metadata_allowed_values_test/29: Crash # Issue 25911
 mirrors/metadata_allowed_values_test/30: Crash # Issue 25911
diff --git a/tests/lib/mirrors/circular_factory_redirection_test.dart b/tests/lib/mirrors/circular_factory_redirection_test.dart
index a7b1882..b833854 100644
--- a/tests/lib/mirrors/circular_factory_redirection_test.dart
+++ b/tests/lib/mirrors/circular_factory_redirection_test.dart
@@ -7,31 +7,30 @@
 
 class A {
   A();
-  A.circular() = B.circular;  /// 01: compile-time error
-  const A.circular2() = B.circular2;  /// 02: compile-time error
+  factory A.circular() = B.circular;
+  const factory A.circular2() = B.circular2;
 }
-class B {
+class B implements A {
   B();
-  B.circular() = C.circular;  /// 01: continued
-  const B.circular2() = C.circular2;  /// 02: continued
+  factory B.circular() = C.circular;
+  const factory B.circular2() = C.circular2;
 }
-class C {
-  C();
-  C.circular() = A.circular;  /// 01: continued
-  const C.circular2() = A.circular2;  /// 02: continued
+class C implements B {
+  const C();
+  factory C.circular()
+  /* /// 01: compile-time error
+     = C;
+  */ = A.circular; /// 01: continued
+
+  const factory C.circular2()
+  /* /// 02: compile-time error
+     = C;
+  */ = A.circular2; /// 02: continued
 }
 
 main() {
   ClassMirror cm = reflectClass(A);
 
-  new A.circular();  /// 01: continued
-  new A.circular2();  /// 02: continued
-
-  Expect.throws(() => cm.newInstance(#circular, []),
-                (e) => e is NoSuchMethodError,
-                'Should disallow circular redirection (non-const)');
-
-  Expect.throws(() => cm.newInstance(#circular2, []),
-                (e) => e is NoSuchMethodError,
-                'Should disallow circular redirection (const)');
+  new A.circular();
+  new A.circular2();
 }
diff --git a/tests/lib/mirrors/invocation_fuzz_test.dart b/tests/lib/mirrors/invocation_fuzz_test.dart
index 8add257..1043145 100644
--- a/tests/lib/mirrors/invocation_fuzz_test.dart
+++ b/tests/lib/mirrors/invocation_fuzz_test.dart
@@ -50,6 +50,8 @@
   // Don't call private methods in dart.async as they may circumvent the zoned
   // error handling below.
   new RegExp(r"^dart\.async\._.*$"),
+
+  'dart._internal.fatal',
 ];
 
 bool isBlacklisted(Symbol qualifiedSymbol) {
diff --git a/tests/standalone/dart_developer_disabled_env_test.dart b/tests/standalone/dart_developer_disabled_env_test.dart
new file mode 100644
index 0000000..1d9653b
--- /dev/null
+++ b/tests/standalone/dart_developer_disabled_env_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--no_causal_async_stacks
+
+import "package:expect/expect.dart";
+
+main() {
+  Expect.isFalse(
+      const bool.fromEnvironment('dart.developer.causal_async_stacks'));
+}
diff --git a/tests/standalone/dart_developer_env_test.dart b/tests/standalone/dart_developer_env_test.dart
new file mode 100644
index 0000000..1d0a276
--- /dev/null
+++ b/tests/standalone/dart_developer_env_test.dart
@@ -0,0 +1,10 @@
+// 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:expect/expect.dart";
+
+main() {
+  Expect.isTrue(
+      const bool.fromEnvironment('dart.developer.causal_async_stacks'));
+}
diff --git a/tests/standalone/io/directory_list_pause_test.dart b/tests/standalone/io/directory_list_pause_test.dart
index fac2d67..a38f125 100644
--- a/tests/standalone/io/directory_list_pause_test.dart
+++ b/tests/standalone/io/directory_list_pause_test.dart
@@ -68,7 +68,7 @@
         close();
       }
     }, onDone: () {
-      Expect.fail('the stream was canceled, onDone should not happend');
+      Expect.fail('the stream was canceled, onDone should not happen');
     });
   });
 }
diff --git a/tests/standalone/io/file_stream_test.dart b/tests/standalone/io/file_stream_test.dart
index f7da717..e1a9105 100644
--- a/tests/standalone/io/file_stream_test.dart
+++ b/tests/standalone/io/file_stream_test.dart
@@ -29,7 +29,7 @@
             close();
           }
         }, onDone: () {
-          Expect.fail('the stream was canceled, onDone should not happend');
+          Expect.fail('the stream was canceled, onDone should not happen');
         });
       });
   });
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index 7c3295d..701add3 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -1261,6 +1261,15 @@
     });
   }
 
+  static void testLastAccessed() {
+    asyncTestStarted();
+    new File(Platform.executable).lastAccessed().then((accessed) {
+      Expect.isTrue(accessed is DateTime);
+      Expect.isTrue(accessed.isBefore(new DateTime.now()));
+      asyncTestDone("testLastAccessed");
+    });
+  }
+
   static void testDoubleAsyncOperation() {
     asyncTestStarted();
     var file = new File(Platform.executable).openSync();
@@ -1290,6 +1299,12 @@
     Expect.isTrue(modified.isBefore(new DateTime.now()));
   }
 
+  static void testLastAccessedSync() {
+    var accessed = new File(Platform.executable).lastAccessedSync();
+    Expect.isTrue(accessed is DateTime);
+    Expect.isTrue(accessed.isBefore(new DateTime.now()));
+  }
+
   static void testLastModifiedSyncDirectory() {
     Directory tmp = tempDirectory.createTempSync('file_last_modified_test_');
     String dirPath = '${tmp.path}/dir';
@@ -1307,6 +1322,115 @@
     }
   }
 
+  static void testLastAccessedSyncDirectory() {
+    Directory tmp = tempDirectory.createTempSync('file_last_accessed_test_');
+    String dirPath = '${tmp.path}/dir';
+    new Directory(dirPath).createSync();
+    try {
+      new File(dirPath).lastAccessedSync();
+      Expect.fail('Expected operation to throw');
+    } catch (e) {
+      if (e is! FileSystemException) {
+        print(e);
+      }
+      Expect.isTrue(e is FileSystemException);
+    } finally {
+      tmp.deleteSync(recursive: true);
+    }
+  }
+
+  static void testSetLastModifiedSync() {
+    String newFilePath = '${tempDirectory.path}/set_last_modified_sync_test';
+    File file = new File(newFilePath);
+    file.createSync();
+    DateTime modifiedTime = new DateTime(2016, 1, 1);
+    file.setLastModifiedSync(modifiedTime);
+    FileStat stat = file.statSync();
+    Expect.equals(2016, stat.modified.year);
+    Expect.equals(1, stat.modified.month);
+    Expect.equals(1, stat.modified.day);
+  }
+
+
+  static testSetLastModified() async {
+    asyncTestStarted();
+    String newFilePath = '${tempDirectory.path}/set_last_modified_test';
+    File file = new File(newFilePath);
+    file.createSync();
+    DateTime modifiedTime = new DateTime(2016, 1, 1);
+    await file.setLastModified(modifiedTime);
+    FileStat stat = await file.stat();
+    Expect.equals(2016, stat.modified.year);
+    Expect.equals(1, stat.modified.month);
+    Expect.equals(1, stat.modified.day);
+    asyncTestDone("testSetLastModified");
+  }
+
+
+  static void testSetLastModifiedSyncDirectory() {
+    Directory tmp = tempDirectory.createTempSync('file_last_modified_test_');
+    String dirPath = '${tmp.path}/dir';
+    new Directory(dirPath).createSync();
+    try {
+      DateTime modifiedTime = new DateTime(2016, 1, 1);
+      new File(dirPath).setLastModifiedSync(modifiedTime);
+      Expect.fail('Expected operation to throw');
+    } catch (e) {
+      if (e is! FileSystemException) {
+        print(e);
+      }
+      Expect.isTrue(e is FileSystemException);
+    } finally {
+      tmp.deleteSync(recursive: true);
+    }
+  }
+
+  static void testSetLastAccessedSync() {
+    String newFilePath = '${tempDirectory.path}/set_last_accessed_sync_test';
+    File file = new File(newFilePath);
+    file.createSync();
+    DateTime accessedTime = new DateTime(2016, 1, 1);
+    file.setLastAccessedSync(accessedTime);
+    FileStat stat = file.statSync();
+    Expect.equals(2016, stat.accessed.year);
+    Expect.equals(1, stat.accessed.month);
+    Expect.equals(1, stat.accessed.day);
+  }
+
+
+  static testSetLastAccessed() async {
+    asyncTestStarted();
+    String newFilePath = '${tempDirectory.path}/set_last_accessed_test';
+    File file = new File(newFilePath);
+    file.createSync();
+    DateTime accessedTime = new DateTime(2016, 1, 1);
+    await file.setLastAccessed(accessedTime);
+    FileStat stat = await file.stat();
+    Expect.equals(2016, stat.accessed.year);
+    Expect.equals(1, stat.accessed.month);
+    Expect.equals(1, stat.accessed.day);
+    asyncTestDone("testSetLastAccessed");
+  }
+
+
+  static void testSetLastAccessedSyncDirectory() {
+    Directory tmp = tempDirectory.createTempSync('file_last_accessed_test_');
+    String dirPath = '${tmp.path}/dir';
+    new Directory(dirPath).createSync();
+    try {
+      DateTime accessedTime = new DateTime(2016, 1, 1);
+      new File(dirPath).setLastAccessedSync(accessedTime);
+      Expect.fail('Expected operation to throw');
+    } catch (e) {
+      if (e is! FileSystemException) {
+        print(e);
+      }
+      Expect.isTrue(e is FileSystemException);
+    } finally {
+      tmp.deleteSync(recursive: true);
+    }
+  }
+
   // Test that opens the same file for writing then for appending to test
   // that the file is not truncated when opened for appending.
   static void testAppend() {
@@ -1481,6 +1605,7 @@
     testReadAsTextSyncEmptyFile();
     testReadAsLinesSync();
     testLastModifiedSync();
+    testLastAccessedSync();
 
     createTempDirectory(() {
       testLength();
@@ -1524,7 +1649,15 @@
       testRename(targetExists: true);
       testRenameSync(targetExists: true);
       testLastModified();
+      testLastAccessed();
       testLastModifiedSyncDirectory();
+      testLastAccessedSyncDirectory();
+      testSetLastModified();
+      testSetLastModifiedSync();
+      testSetLastModifiedSyncDirectory();
+      testSetLastAccessed();
+      testSetLastAccessedSync();
+      testSetLastAccessedSyncDirectory();
       testDoubleAsyncOperation();
       asyncEnd();
     });
diff --git a/tests/standalone/io/http_client_request_test.dart b/tests/standalone/io/http_client_request_test.dart
index 9015b9f..cd2a7be 100644
--- a/tests/standalone/io/http_client_request_test.dart
+++ b/tests/standalone/io/http_client_request_test.dart
@@ -108,25 +108,8 @@
 }
 
 
-void testBadHeaders() {
-  asyncStart();
-  testClientRequest((request) {
-    var value = "a";
-    for (int i = 0; i < 8 * 1024; i++) {
-      value += 'a';
-    }
-    request.headers.set('name', value);
-    request.done.catchError((error) {
-      asyncEnd();
-    }, test: (e) => e is HttpException);
-    return request.close();
-  });
-}
-
-
 void main() {
   testResponseDone();
   testBadResponseAdd();
   testBadResponseClose();
-  testBadHeaders();
 }
diff --git a/tests/standalone/io/http_server_response_test.dart b/tests/standalone/io/http_server_response_test.dart
index c3c0afb..a6c06af 100644
--- a/tests/standalone/io/http_server_response_test.dart
+++ b/tests/standalone/io/http_server_response_test.dart
@@ -281,20 +281,6 @@
 }
 
 
-void testBadHeaders() {
-  testServerRequest((server, request) {
-    var value = "a";
-    for (int i = 0; i < 8 * 1024; i++) {
-      value += 'a';
-    }
-    request.response.headers.set('name', value);
-    request.response.close().catchError((error) {
-      server.close();
-    }, test: (e) => e is HttpException);
-  });
-}
-
-
 void testWriteCharCode() {
   testServerRequest((server, request) {
     // Test that default is latin-1 (only 2 bytes).
@@ -315,6 +301,5 @@
   testBadResponseAdd();
   testBadResponseClose();
   testIgnoreRequestData();
-  testBadHeaders();
   testWriteCharCode();
 }
diff --git a/tests/standalone/io/named_pipe_script_test.dart b/tests/standalone/io/named_pipe_script_test.dart
index ed5a659..9a9b562 100644
--- a/tests/standalone/io/named_pipe_script_test.dart
+++ b/tests/standalone/io/named_pipe_script_test.dart
@@ -47,7 +47,8 @@
     process.kill();
   });
   process.stdin.writeln(script);
-  process.stdin.close();
+  await process.stdin.flush();
+  await process.stdin.close();
 
   int status = await process.exitCode;
   if (!stdinWriteFailed) {
diff --git a/tests/standalone/io/process_detached_test.dart b/tests/standalone/io/process_detached_test.dart
index b72f26a..b412252 100644
--- a/tests/standalone/io/process_detached_test.dart
+++ b/tests/standalone/io/process_detached_test.dart
@@ -47,7 +47,7 @@
     Expect.isNull(process.exitCode);
     var message = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
     process.stdin.add(message);
-    process.stdin.close();
+    process.stdin.flush().then((_) => process.stdin.close());
     var f1 = process.stdout.fold([], (p, e) => p..addAll(e));
     var f2 = process.stderr.fold([], (p, e) => p..addAll(e));
     Future.wait([f1, f2])
diff --git a/tests/standalone/io/process_stderr_test.dart b/tests/standalone/io/process_stderr_test.dart
index 6c821d9..981b39a 100644
--- a/tests/standalone/io/process_stderr_test.dart
+++ b/tests/standalone/io/process_stderr_test.dart
@@ -48,7 +48,7 @@
 
     process.stdout.listen((_) {});
     process.stdin.add(data);
-    process.stdin.close();
+    process.stdin.flush().then((_) => process.stdin.close());
     process.stderr.listen(readData);
   });
 }
diff --git a/tests/standalone/io/process_stdin_transform_unsubscribe_test.dart b/tests/standalone/io/process_stdin_transform_unsubscribe_test.dart
index 8b10d73..2730ae0 100644
--- a/tests/standalone/io/process_stdin_transform_unsubscribe_test.dart
+++ b/tests/standalone/io/process_stdin_transform_unsubscribe_test.dart
@@ -25,6 +25,9 @@
     process.stdout.listen((_) {});
     process.stderr.listen((_) {});
     process.stdin.writeln("Line1");
+    process.stdin.flush().then((_) {
+      print("flush completed");
+    });
   });
 }
 
diff --git a/tests/standalone/io/process_stdout_test.dart b/tests/standalone/io/process_stdout_test.dart
index 8b117fe..b3f8820 100644
--- a/tests/standalone/io/process_stdout_test.dart
+++ b/tests/standalone/io/process_stdout_test.dart
@@ -48,7 +48,7 @@
 
     process.stderr.listen((_) {});
     process.stdin.add(data);
-    process.stdin.close();
+    process.stdin.flush().then((_) => process.stdin.close());
     process.stdout.listen(readData);
   });
 }
diff --git a/tests/standalone/io/socket_info_ipv4_test.dart b/tests/standalone/io/socket_info_ipv4_test.dart
index f8d63bd..08baebc 100644
--- a/tests/standalone/io/socket_info_ipv4_test.dart
+++ b/tests/standalone/io/socket_info_ipv4_test.dart
@@ -7,18 +7,18 @@
 
 void testHostAndPort() {
   ServerSocket.bind("127.0.0.1", 0).then((server) {
-
     Socket.connect("127.0.0.1", server.port).then((clientSocket) {
       server.listen((socket) {
         Expect.equals(socket.port, server.port);
         Expect.equals(clientSocket.port, socket.remotePort);
         Expect.equals(clientSocket.remotePort, socket.port);
         Expect.equals(socket.remoteAddress.address, "127.0.0.1");
-        Expect.equals(socket.remoteAddress.type,
-                      InternetAddressType.IP_V4);
+        Expect.equals(socket.remoteAddress.type, InternetAddressType.IP_V4);
+        Expect.listEquals(socket.remoteAddress.rawAddress, [127, 0, 0, 1]);
         Expect.equals(clientSocket.remoteAddress.address, "127.0.0.1");
-        Expect.equals(clientSocket.remoteAddress.type,
-                      InternetAddressType.IP_V4);
+        Expect.equals(
+            clientSocket.remoteAddress.type, InternetAddressType.IP_V4);
+        Expect.listEquals(clientSocket.remoteAddress.rawAddress, [127, 0, 0, 1]);
         socket.destroy();
         clientSocket.destroy();
         server.close();
diff --git a/tests/standalone/io/socket_info_ipv6_test.dart b/tests/standalone/io/socket_info_ipv6_test.dart
index d6969ab..016c582 100644
--- a/tests/standalone/io/socket_info_ipv6_test.dart
+++ b/tests/standalone/io/socket_info_ipv6_test.dart
@@ -7,18 +7,20 @@
 
 void testHostAndPort() {
   ServerSocket.bind("::1", 0).then((server) {
-
     Socket.connect("::1", server.port).then((clientSocket) {
       server.listen((socket) {
         Expect.equals(socket.port, server.port);
         Expect.equals(clientSocket.port, socket.remotePort);
         Expect.equals(clientSocket.remotePort, socket.port);
         Expect.equals(socket.remoteAddress.address, "::1");
-        Expect.equals(socket.remoteAddress.type,
-                      InternetAddressType.IP_V6);
+        Expect.equals(socket.remoteAddress.type, InternetAddressType.IP_V6);
+        Expect.listEquals(socket.remoteAddress.rawAddress,
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
         Expect.equals(clientSocket.remoteAddress.address, "::1");
-        Expect.equals(clientSocket.remoteAddress.type,
-                      InternetAddressType.IP_V6);
+        Expect.equals(
+            clientSocket.remoteAddress.type, InternetAddressType.IP_V6);
+        Expect.listEquals(clientSocket.remoteAddress.rawAddress,
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
         socket.destroy();
         clientSocket.destroy();
         server.close();
diff --git a/tests/standalone/io/socket_source_address_test.dart b/tests/standalone/io/socket_source_address_test.dart
index 8f076ed..9670ac5 100644
--- a/tests/standalone/io/socket_source_address_test.dart
+++ b/tests/standalone/io/socket_source_address_test.dart
@@ -107,9 +107,9 @@
                                    sourceAddress: sourceAddress);
       closeDestroyFunction(s);
     } else {
-      // Cannot use an IPv6 source address to connect to IPv6 if
+      // Cannot use an IPv4 source address to connect to IPv6 if
       // v6Only is specified.
-      await throws(() => connectFunction(InternetAddress.LOOPBACK_IP_V4,
+      await throws(() => connectFunction(InternetAddress.LOOPBACK_IP_V6,
                                          server.port,
                                          sourceAddress: sourceAddress),
                    (e) => e is SocketException);
@@ -125,7 +125,7 @@
       closeDestroyFunction(s);
     } else {
       // Cannot use an IPv6 source address to connect to IPv4.
-      await throws(() => connectFunction(InternetAddress.LOOPBACK_IP_V6,
+      await throws(() => connectFunction(InternetAddress.LOOPBACK_IP_V4,
                                          server.port,
                                          sourceAddress: sourceAddress),
                    (e) => e is SocketException);
diff --git a/tests/standalone/io/stdin_sync_test.dart b/tests/standalone/io/stdin_sync_test.dart
index e9e5610..2710b0a 100644
--- a/tests/standalone/io/stdin_sync_test.dart
+++ b/tests/standalone/io/stdin_sync_test.dart
@@ -17,7 +17,7 @@
                   [script]..addAll(
                       expected.map(JSON.encode))).then((process) {
       process.stdin.write(line);
-      process.stdin.close();
+      process.stdin.flush().then((_) => process.stdin.close());
       process.stderr
           .transform(UTF8.decoder)
           .transform(new LineSplitter())
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 98f7d8f..63bbebb 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -9,7 +9,6 @@
 
 io/raw_socket_test: Pass, RuntimeError # Issue 28288
 io/http_close_test: Pass, RuntimeError # Issue 28380
-
 packages_file_test: Skip # Issue 26715
 packages_file_test/none: Skip   # contains no tests.
 
@@ -22,6 +21,9 @@
 
 issue14236_test: Pass # Do not remove this line. It serves as a marker for Issue 14516 comment #4.
 
+[$runtime == vm && $compiler == none && $system == fuchsia]
+*: Skip  # Not yet triaged.
+
 [ ($runtime != vm && $runtime != dart_precompiled) && ($runtime != drt || $compiler != none) ]
 no_assert_test: Fail, OK # This is testing a vm flag.
 env_test: Skip # This is testing a vm command line parsing scenario.
@@ -84,6 +86,7 @@
 verbose_gc_to_bmu_test: Skip
 regress_26031_test: SkipByDesign # Standalone only test
 env_test: Skip # This is testing a vm command line parsing scenario.
+dart_developer_disabled_env_test: SkipByDesign # Dartium does not respect VMOptions
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 issue14236_test: Skip # Analyzer can't handle Script snapshots.
@@ -94,6 +97,9 @@
 # This is runtime test.
 io/process_exit_negative_test: Skip
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $compiler == dart2js ]
 number_identity_test: Skip # Bigints and int/double diff. not supported.
 typed_data_test: Skip # dart:typed_data support needed.
@@ -122,6 +128,8 @@
 pair_location_remapping_test: Skip
 regress_25335_test: Skip # Int64List not supported.
 deferred_transitive_import_error_test: Skip # Contains intentional errors.
+dart_developer_env_test: SkipByDesign # Unsupported by dart2js
+dart_developer_disabled_env_test: SkipByDesign # Unsupported by dart2js
 
 [ $compiler == dart2js && $cps_ir && $checked ]
 *: Skip # `assert` not implemented
@@ -205,13 +213,26 @@
 package/scenarios/invalid/same_package_twice_test: Crash, OK # Analyzer exits on invalid package config
 
 [ $system == windows ]
-io/skipping_dart2js_compilations_test: Fail # Issue 19551.
 verbose_gc_to_bmu_test: Skip
-io/platform_resolved_executable_test/06: RuntimeError  # Issue 23641
 io/process_sync_test: Pass, Timeout # Issue 24596
 io/sleep_test: Pass, Fail # Issue 25757
-io/socket_info_ipv6_test: RuntimeError # Issue 27876
 io/http_server_early_client_close2_test: Pass, Crash  # Issue 28197
+io/process_stdin_transform_unsubscribe_test: Pass, Timeout # Issue #28558
+
+[ $system == windows && $compiler != dart2analyzer ]
+io/platform_resolved_executable_test/06: RuntimeError  # Issue 23641
+io/skipping_dart2js_compilations_test: Fail # Issue 19551.
+io/socket_info_ipv6_test: RuntimeError # Issue 27876
+
+[ $system == windows && $compiler == dart2analyzer ]
+package/package_isolate_test: Crash # Issue 28645
+package/scenarios/empty_packages_file/empty_packages_file_noimports_test: Crash # Issue 28645
+package/scenarios/empty_packages_file/empty_packages_file_option_test: Crash, Pass # Issue 28645
+package/scenarios/packages_file_strange_formatting/empty_lines_test: Crash # Issue 28645
+package/scenarios/packages_file_strange_formatting/empty_package_dir_test: Crash # Issue 28645
+package/scenarios/packages_file_strange_formatting/mixed_line_ends_test: Crash # Issue 28645
+package/scenarios/packages_option_only/packages_option_only_noimports_test: Crash # Issue 28645
+package/scenarios/packages_option_only/packages_option_only_test: Crash, CompileTimeError # Issue 28645
 
 [ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
 io/file_lock_test: Skip  # Timeout.
@@ -229,8 +250,6 @@
 link_natives_lazily_test: SkipByDesign # Not supported.
 
 [ $compiler == precompiler ]
-# Stacktraces in precompilation omit inlined frames.
-assert_test: Pass, RuntimeError
 map_insert_remove_oom_test: Skip # Heap limit too low. Increasing iteration count to make a higher limit a meaningful test makes it too slow for simarm[64] bots.
 io/web_socket_test: Pass, RuntimeError # Issue 24674
 
@@ -315,6 +334,7 @@
 no_support_service_test: SkipByDesign
 no_support_timeline_test: SkipByDesign
 io/stdio_implicit_close_test: Skip # SkipByDesign
+dart_developer_env_test: SkipByDesign
 
 # Following tests are skipped on dart_app as package mapping is not supported.
 [ $runtime == dart_precompiled || $compiler == app_jit ]
@@ -334,6 +354,8 @@
 # SIMDBC interpreter doesn't support --no_lazy_dispatchers
 no_lazy_dispatchers_test: SkipByDesign
 
+io/secure_unauthorized_test: Pass, RuntimeError # Issue 28719
+
 [ $system == android ]
 # Issue 26376
 io/platform_resolved_executable_test: RuntimeError
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index fde7eba..331242f 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -21,6 +21,9 @@
 dummy_compiler_test: Crash # Issue 24485
 recursive_import_test: Crash # Issue 24485
 
+[ $compiler == dart2analyzer && $builder_tag == strong ]
+*: Skip # Issue 28649
+
 [ $hot_reload || $hot_reload_rollback ]
 recursive_import_test: Skip # Running dart2js under frequent reloads is slow.
 dummy_compiler_test: Skip # Running dart2js under frequent reloads is slow.
diff --git a/tools/VERSION b/tools/VERSION
index 455a4a0..dfbe20c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
 #
 CHANNEL dev
 MAJOR 1
-MINOR 22
+MINOR 23
 PATCH 0
-PRERELEASE 10
-PRERELEASE_PATCH 7
+PRERELEASE 0
+PRERELEASE_PATCH 0
diff --git a/tools/bots/pkg.py b/tools/bots/pkg.py
index 7dad673..2ee2595 100644
--- a/tools/bots/pkg.py
+++ b/tools/bots/pkg.py
@@ -17,13 +17,12 @@
 
 import bot
 
-PKG_BUILDER = r'pkg-(linux|mac|win)(-(russian))?(-(debug))?'
+PKG_BUILDER = r'pkg-(linux|mac|win)(-(russian))?'
 
 def PkgConfig(name, is_buildbot):
   """Returns info for the current buildbot based on the name of the builder.
 
   Currently, this is just:
-  - mode: "debug", "release"
   - system: "linux", "mac", or "win"
   """
   pkg_pattern = re.match(PKG_BUILDER, name)
@@ -32,10 +31,9 @@
 
   system = pkg_pattern.group(1)
   locale = pkg_pattern.group(3)
-  mode = pkg_pattern.group(5) or 'release'
   if system == 'win': system = 'windows'
 
-  return bot.BuildInfo('none', 'vm', mode, system, checked=True,
+  return bot.BuildInfo('none', 'vm', 'release', system, checked=True,
                        builder_tag=locale)
 
 def PkgSteps(build_info):
@@ -44,8 +42,7 @@
     common_args.append('--builder-tag=%s' % build_info.builder_tag)
 
   # There are a number of big/integration tests in pkg, run with bigger timeout
-  timeout = 300 if build_info.mode == 'debug' else 120
-  common_args.append('--timeout=%s' % timeout)
+  common_args.append('--timeout=120')
   # We have some unreproducible vm crashes on these bots
   common_args.append('--copy-coredumps')
 
@@ -58,25 +55,17 @@
               common_args + ['pkg', 'docs'],
               swallow_error=True)
 
-  # Pkg tests currently have a lot of timeouts when run in debug mode.
-  # See issue 18479
-  if build_info.mode != 'release': return
-
   with bot.BuildStep('third_party pkg tests', swallow_error=True):
     pkg_tested = os.path.join('third_party', 'pkg_tested')
     for entry in os.listdir(pkg_tested):
       path = os.path.join(pkg_tested, entry)
-      if os.path.isdir(path): bot.RunTestRunner(build_info, path)
+      if os.path.isdir(path):
+        bot.RunTestRunner(build_info, path)
 
   pkgbuild_build_info = bot.BuildInfo('none', 'vm', build_info.mode,
                                       build_info.system, checked=False)
-  bot.RunTest('pkgbuild_repo_pkgs', pkgbuild_build_info,
-              common_args + ['--append_logs', '--use-repository-packages',
-                             'pkgbuild'],
-              swallow_error=True)
 
-  public_args = (common_args +
-                 ['--append_logs', '--use-public-packages', 'pkgbuild'])
+  public_args = (common_args + ['--append_logs', 'pkgbuild'])
   bot.RunTest('pkgbuild_public_pkgs', pkgbuild_build_info, public_args)
 
 if __name__ == '__main__':
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 91c3241..647d196 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -9,7 +9,7 @@
 
 vars.update({
   "dartium_chromium_commit": "7558afb6379171d7f96b2db68ae9d2b64b2c5544",
-  "dartium_webkit_commit": "8c167a4ffeaa5402dde4d9e113bb272b2e4640d2",
+  "dartium_webkit_commit": "c75f4816a4a066834be431a2dc4b84d788020b64",
   "chromium_base_revision": "338390",
 
   # We use mirrors of all github repos to guarantee reproducibility and
@@ -32,7 +32,7 @@
   "collection_tag": "@1.9.1",
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
-  "dart2js_info_tag" : "@0.5.0",
+  "dart2js_info_tag" : "@0.5.3+1",
   "glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
   "html_tag" : "@0.12.1+1",
   "http_rev" : "@9b93e1542c753090c50b46ef1592d44bc858bfe7",
@@ -69,7 +69,7 @@
   "web_components_rev": "@6349e09f9118dce7ae1b309af5763745e25a9d61",
   "WebCore_rev": "@a86fe28efadcfc781f836037a80f27e22a5dad17",
 
-  "co19_rev": "@cf831f58ac65f68f14824c0b1515f6b7814d94b8",
+  "co19_rev": "@4af9ef149be554216c5bb16cbac8e50d4c28cdf1",
 })
 
 deps.update({
diff --git a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
index 495011e2..1c33e5f 100644
--- a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
@@ -21,6 +21,11 @@
     return style;
   }
 
+  /// Returns the value of the property if the provided *CSS* property
+  /// name is supported on this element and if the value is set. Otherwise
+  /// returns an empty string.
+  ///
+  /// Please note the property name uses camelCase, not-hyphens.
   String getPropertyValue(String propertyName) {
     var propValue = _getPropertyValueHelper(propertyName);
     return propValue != null ? propValue : '';
diff --git a/tools/sdks/linux/dart-sdk.tar.gz.sha1 b/tools/sdks/linux/dart-sdk.tar.gz.sha1
index 22e70b3..beedf8a 100644
--- a/tools/sdks/linux/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/linux/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-cfffe4b391ce4e907b7ed9a2e876ca6e077b7be3
\ No newline at end of file
+55b4aa43d1595e46d60f99f461144821eef3538a
\ No newline at end of file
diff --git a/tools/sdks/mac/dart-sdk.tar.gz.sha1 b/tools/sdks/mac/dart-sdk.tar.gz.sha1
index 98b4d2c..e112aea 100644
--- a/tools/sdks/mac/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/mac/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-ca26cc2413c9ad174794e17fbbb0797815591138
\ No newline at end of file
+07ef41f60d3e64040d69f08dedecae7e07371e78
\ No newline at end of file
diff --git a/tools/sdks/win/dart-sdk.tar.gz.sha1 b/tools/sdks/win/dart-sdk.tar.gz.sha1
index cca45ed..61c24c8 100644
--- a/tools/sdks/win/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/win/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-e6b6200db59ebb84570f0ed995c7c5e3b0b47c7b
\ No newline at end of file
+6800410f4ad065648a1039280b1c492cd49ec76d
\ No newline at end of file
diff --git a/tools/task_kill.py b/tools/task_kill.py
index ed8b555..44c8e2ee 100755
--- a/tools/task_kill.py
+++ b/tools/task_kill.py
@@ -46,6 +46,7 @@
   },
   'macos': {
     'chrome': 'Chrome',
+    'chrome_helper': 'Chrome Helper',
     'content_shell': 'Content Shell',
     'dart': 'dart',
     'firefox': 'firefox',
@@ -210,6 +211,7 @@
   # We don't give error on killing chrome. It happens quite often that the
   # browser controller fails in killing chrome, so we silently do it here.
   Kill('chrome')
+  status += Kill('chrome_helper')
   status += Kill('iexplore')
   status += Kill('safari')
   status += Kill('content_shell')
diff --git a/tools/testing/dart/android.dart b/tools/testing/dart/android.dart
index 615d5b0..985f6bc 100644
--- a/tools/testing/dart/android.dart
+++ b/tools/testing/dart/android.dart
@@ -55,6 +55,7 @@
   return Process.start(executable, args).then((Process process) async {
     if (stdin != null && stdin != '') {
       process.stdin.write(stdin);
+      await process.stdin.flush();
     }
     process.stdin.close();
 
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index aeb7fae..d545b3f 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -68,6 +68,9 @@
     bool hotReloadRollback = configuration['hot_reload_rollback'];
     bool useFastStartup = configuration['fast_startup'];
     bool verifyKernel = configuration['verify-ir'];
+    bool useDFE = configuration['useDFE'];
+    bool useFasta = configuration['useFasta'];
+    bool treeShake = !configuration['no-tree-shake'];
 
     switch (compiler) {
       case 'dart2analyzer':
@@ -99,12 +102,25 @@
             useBlobs: useBlobs,
             isAndroid: configuration['system'] == 'android');
       case 'dartk':
-        return ComposedCompilerConfiguration.createDartKConfiguration(
-            isChecked: isChecked,
-            isHostChecked: isHostChecked,
-            useSdk: useSdk,
-            verify: verifyKernel,
-            strong: isStrong);
+        if (!useDFE) {
+          return ComposedCompilerConfiguration.createDartKConfiguration(
+              isChecked: isChecked,
+              isHostChecked: isHostChecked,
+              useSdk: useSdk,
+              verify: verifyKernel,
+              strong: isStrong,
+              treeShake: treeShake);
+        }
+
+        return new NoneCompilerConfiguration(
+              isDebug: isDebug,
+              isChecked: isChecked,
+              isHostChecked: isHostChecked,
+              useSdk: useSdk,
+              hotReload: hotReload,
+              hotReloadRollback: hotReloadRollback,
+              dfeMode: useFasta ? DFEMode.Fasta : DFEMode.DartK);
+
       case 'dartkp':
         return ComposedCompilerConfiguration.createDartKPConfiguration(
             isChecked: isChecked,
@@ -114,7 +130,8 @@
             isAndroid: configuration['system'] == 'android',
             useSdk: useSdk,
             verify: verifyKernel,
-            strong: isStrong);
+            strong: isStrong,
+            treeShake: treeShake);
       case 'none':
         return new NoneCompilerConfiguration(
             isDebug: isDebug,
@@ -181,22 +198,28 @@
   }
 }
 
+enum DFEMode {
+  None,
+  DartK,
+  Fasta
+}
+
 /// The "none" compiler.
 class NoneCompilerConfiguration extends CompilerConfiguration {
   final bool hotReload;
   final bool hotReloadRollback;
+  final DFEMode dfeMode;
 
   NoneCompilerConfiguration(
       {bool isDebug, bool isChecked, bool isHostChecked, bool useSdk,
-       bool hotReload,
-       bool hotReloadRollback})
+       bool this.hotReload,
+       bool this.hotReloadRollback,
+       DFEMode this.dfeMode: DFEMode.None})
       : super._subclass(
             isDebug: isDebug,
             isChecked: isChecked,
             isHostChecked: isHostChecked,
-            useSdk: useSdk),
-        this.hotReload = hotReload,
-        this.hotReloadRollback = hotReloadRollback;
+            useSdk: useSdk);
 
   bool get hasCompiler => false;
 
@@ -209,6 +232,12 @@
       List<String> originalArguments,
       CommandArtifact artifact) {
     List<String> args = [];
+    if (dfeMode != DFEMode.None) {
+      args.add('--dfe=utils/kernel-service/kernel-service.dart');
+    }
+    if (dfeMode == DFEMode.Fasta) {
+      args.add('-DDFE_USE_FASTA=true');
+    }
     if (isChecked) {
       args.add('--enable_asserts');
       args.add('--enable_type_checks');
@@ -227,10 +256,10 @@
 
 /// The "dartk" compiler.
 class DartKCompilerConfiguration extends CompilerConfiguration {
-  final bool verify, strong;
+  final bool verify, strong, treeShake;
 
   DartKCompilerConfiguration({bool isChecked, bool isHostChecked, bool useSdk,
-        this.verify, this.strong})
+        this.verify, this.strong, this.treeShake})
       : super._subclass(isChecked: isChecked, isHostChecked: isHostChecked,
                         useSdk: useSdk);
 
@@ -250,6 +279,7 @@
       '$buildDir/patched_sdk',
       '--link',
       '--target=vm',
+      treeShake ? '--tree-shake' : null,
       strong ? '--strong' : null,
       verify ? '--verify-ir' : null,
       '--out',
@@ -406,14 +436,14 @@
 
   static ComposedCompilerConfiguration createDartKPConfiguration(
       {bool isChecked, bool isHostChecked, String arch, bool useBlobs,
-       bool isAndroid, bool useSdk, bool verify, bool strong}) {
+       bool isAndroid, bool useSdk, bool verify, bool strong, bool treeShake}) {
     var nested = [];
 
     // Compile with dartk.
     nested.add(new PipelineCommand.runWithGlobalArguments(
         new DartKCompilerConfiguration(isChecked: isChecked,
             isHostChecked: isHostChecked, useSdk: useSdk, verify: verify,
-            strong: strong)));
+            strong: strong, treeShake: treeShake)));
 
     // Run the normal precompiler.
     nested.add(new PipelineCommand.runWithPreviousKernelOutput(
@@ -426,14 +456,14 @@
 
   static ComposedCompilerConfiguration createDartKConfiguration(
       {bool isChecked, bool isHostChecked, bool useSdk, bool verify,
-       bool strong}) {
+       bool strong, bool treeShake}) {
     var nested = [];
 
     // Compile with dartk.
     nested.add(new PipelineCommand.runWithGlobalArguments(
         new DartKCompilerConfiguration(isChecked: isChecked,
             isHostChecked: isHostChecked, useSdk: useSdk,
-            verify: verify, strong: strong)));
+            verify: verify, strong: strong, treeShake: treeShake)));
 
     return new ComposedCompilerConfiguration(nested);
   }
@@ -759,8 +789,8 @@
       : super._subclass(isDebug: isDebug, isChecked: isChecked);
 
   int computeTimeoutMultiplier() {
-    int multiplier = 2;
-    if (isDebug) multiplier *= 4;
+    int multiplier = 1;
+    if (isDebug) multiplier *= 2;
     if (isChecked) multiplier *= 2;
     return multiplier;
   }
diff --git a/tools/testing/dart/package_testing_support.dart b/tools/testing/dart/package_testing_support.dart
new file mode 100644
index 0000000..66ad351
--- /dev/null
+++ b/tools/testing/dart/package_testing_support.dart
@@ -0,0 +1,26 @@
+// 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 package_testing_support;
+
+import 'dart:convert' show
+    JSON;
+
+import 'test_configurations.dart' show
+    testConfigurations;
+
+import 'test_options.dart' show
+    TestOptionsParser;
+
+import 'test_suite.dart' show
+    TestUtils;
+
+main(List<String> arguments) {
+  TestUtils.setDartDirUri(Uri.base);
+  List<Map> configurations = <Map>[];
+  for (String argument in arguments) {
+    configurations.addAll(new TestOptionsParser().parse(argument.split(" ")));
+  }
+  testConfigurations(configurations);
+}
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index c077e7d..e0d306b 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -227,6 +227,8 @@
       CommandArtifact artifact,
       List<String> arguments,
       Map<String, String> environmentOverrides) {
+    final bool needsDFERunner = suite.configuration['compiler'] == 'dartk' &&
+        !suite.configuration['noBatch'];
     String script = artifact.filename;
     String type = artifact.mimeType;
     if (script != null &&
@@ -236,7 +238,7 @@
     }
     String executable = suite.dartVmBinaryFileName;
     return <Command>[
-      commandBuilder.getVmCommand(executable, arguments, environmentOverrides)
+      commandBuilder.getVmCommand(executable, arguments, environmentOverrides, needsDFERunner: needsDFERunner)
     ];
   }
 }
diff --git a/tools/testing/dart/test_configurations.dart b/tools/testing/dart/test_configurations.dart
index ee68349..1592b0c 100644
--- a/tools/testing/dart/test_configurations.dart
+++ b/tools/testing/dart/test_configurations.dart
@@ -5,6 +5,7 @@
 library test_configurations;
 
 import "dart:async";
+import 'dart:convert';
 import 'dart:io';
 import "dart:math" as math;
 
@@ -54,6 +55,9 @@
   new Path('utils/tests/peg'),
 ];
 
+// This file is created by gclient runhooks.
+final VS_TOOLCHAIN_FILE = new Path("build/win_toolchain.json");
+
 Future testConfigurations(List<Map> configurations) async {
   var startTime = new DateTime.now();
   // Extract global options from first configuration.
@@ -208,12 +212,6 @@
         } else if (conf['compiler'] == 'none' &&
             conf['runtime'] == 'vm' &&
             key == 'pkgbuild') {
-          if (!conf['use_repository_packages'] &&
-              !conf['use_public_packages']) {
-            print("You need to use either --use-repository-packages or "
-                "--use-public-packages with the pkgbuild test suite!");
-            exit(1);
-          }
           if (!conf['use_sdk']) {
             print("Running the 'pkgbuild' test suite requires "
                 "passing the '--use-sdk' to test.py");
@@ -272,7 +270,7 @@
     eventListener.add(new TestOutcomeLogWriter());
   }
   if (firstConf['copy_coredumps']) {
-    eventListener.add(new UnexpectedCrashDumpArchiver());
+    eventListener.add(new UnexpectedCrashLogger());
   }
 
   // The only progress indicator when listing tests should be the
@@ -300,6 +298,13 @@
     await Future.wait(serverFutures);
   }
 
+  if (Platform.isWindows) {
+    // When running tests on Windows, use cdb from depot_tools to dump
+    // stack traces of tests timing out.
+    var text = await new File(VS_TOOLCHAIN_FILE.toNativePath()).readAsString();
+    firstConf['win_sdk_path'] = JSON.decode(text)['win_sdk'];
+  }
+
   // [firstConf] is needed here, since the ProcessQueue needs to know the
   // settings of 'noBatch' and 'local_ip'
   new ProcessQueue(
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 194f834..206059a 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -291,6 +291,15 @@
           'verify-ir', 'Verify kernel IR', ['--verify-ir'], [], false,
           type: 'bool'),
       new _TestOptionSpecification(
+          'no-tree-shake', 'Disable kernel IR tree shaking', ['--no-tree-shake'], [], false,
+          type: 'bool'),
+      new _TestOptionSpecification(
+          'useDFE', 'Use Kernel Isolate', ['--use-dfe'], [], true,
+          type: 'bool'),
+      new _TestOptionSpecification(
+          'useFasta', 'Use Fasta in Kernel Isolate', ['--use-fasta'], [], false,
+          type: 'bool'),
+      new _TestOptionSpecification(
           'list', 'List tests only, do not run them', ['--list'], [], false,
           type: 'bool'),
       new _TestOptionSpecification(
@@ -334,23 +343,6 @@
           false,
           type: 'bool'),
       new _TestOptionSpecification(
-          'use_public_packages',
-          'For tests using packages: Use pub.dartlang.org packages '
-          'instead the ones in the repository.',
-          ['--use-public-packages'],
-          [],
-          false,
-          type: 'bool'),
-      new _TestOptionSpecification(
-          'use_repository_packages',
-          'For tests using packages: Use pub.dartlang.org packages '
-          'but use overrides for the packages available in the '
-          'repository.',
-          ['--use-repository-packages'],
-          [],
-          false,
-          type: 'bool'),
-      new _TestOptionSpecification(
           'build_directory',
           'The name of the build directory, where products are placed.',
           ['--build-directory'],
@@ -746,12 +738,6 @@
       print("Error: shard index is ${config['shard']} out of "
           "${config['shards']} shards");
     }
-
-    if (config['use_repository_packages'] && config['use_public_packages']) {
-      isValid = false;
-      print("Cannot have both --use-repository-packages and "
-          "--use-public-packages");
-    }
     if ((config['runtime'] == 'flutter') && (config['flutter'] == '')) {
       isValid = false;
       print("-rflutter requires the flutter engine executable to "
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index 7e57a60..9baa97f 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -262,8 +262,6 @@
     'system',
     'vm_options',
     'use_sdk',
-    'use_repository_packages',
-    'use_public_packages',
     'builder_tag'
   ];
 
@@ -315,52 +313,53 @@
   }
 }
 
-class UnexpectedCrashDumpArchiver extends EventListener {
+class UnexpectedCrashLogger extends EventListener {
   final archivedBinaries = <String, String>{};
 
   void done(TestCase test) {
     if (test.unexpectedOutput &&
         test.result == Expectation.CRASH &&
         test.lastCommandExecuted is ProcessCommand) {
-      final name = "core.${test.lastCommandOutput.pid}";
-      final file = new File(name);
-      final exists = file.existsSync();
-      if (exists) {
-        final lastCommand = test.lastCommandExecuted as ProcessCommand;
-        // We have a coredump for the process. This coredump will be archived by
-        // CoreDumpArchiver (see tools/utils.py). For debugging purposes we
-        // need to archive the crashed binary as well. To simplify the
-        // archiving code we simply copy binaries into current folder next to
-        // core dumps and name them `core.${mode}_${arch}_${binary_name}`.
-        final binName = lastCommand.executable;
-        final binFile = new File(binName);
-        final binBaseName = new Path(binName).filename;
-        if (!archivedBinaries.containsKey(binName) &&
-            binFile.existsSync()) {
-          final mode = test.configuration['mode'];
-          final arch = test.configuration['arch'];
-          final archived = "binary.${mode}_${arch}_${binBaseName}";
-          TestUtils.copyFile(new Path(binName), new Path(archived));
-          archivedBinaries[binName] = archived;
-        }
+      final pid = "${test.lastCommandOutput.pid}";
+      final lastCommand = test.lastCommandExecuted as ProcessCommand;
 
-        if (archivedBinaries.containsKey(binName)) {
-          // We have found and copied the binary.
-          var coredumpsList;
+      // We might have a coredump for the process. This coredump will be
+      // archived by CoreDumpArchiver (see tools/utils.py).
+      //
+      // For debugging purposes we need to archive the crashed binary as well.
+      //
+      // To simplify the archiving code we simply copy binaries into current
+      // folder next to core dumps and name them
+      // `binary.${mode}_${arch}_${binary_name}`.
+      final binName = lastCommand.executable;
+      final binFile = new File(binName);
+      final binBaseName = new Path(binName).filename;
+      if (!archivedBinaries.containsKey(binName) &&
+          binFile.existsSync()) {
+        final mode = test.configuration['mode'];
+        final arch = test.configuration['arch'];
+        final archived = "binary.${mode}_${arch}_${binBaseName}";
+        TestUtils.copyFile(new Path(binName), new Path(archived));
+        archivedBinaries[binName] = archived;
+      }
+
+      if (archivedBinaries.containsKey(binName)) {
+        // We have found and copied the binary.
+        var unexpectedCrashesFile;
+        try {
+          unexpectedCrashesFile =
+              new File('unexpected-crashes').openSync(mode: FileMode.APPEND);
+          unexpectedCrashesFile.writeStringSync(
+              "${test.displayName},${pid},${archivedBinaries[binName]}\n");
+        } catch (e) {
+          print('Failed to add crash to unexpected-crashes list: ${e}');
+        } finally {
           try {
-            coredumpsList =
-                new File('coredumps').openSync(mode: FileMode.APPEND);
-            coredumpsList.writeStringSync(
-                "${test.displayName},${name},${archivedBinaries[binName]}\n");
-          } catch (e) {
-            print('Failed to add crash to coredumps list: ${e}');
-          } finally {
-            try {
-              if (coredumpsList != null)
-                coredumpsList.closeSync();
-            } catch (e) {
-              print('Failed to close coredumps list: ${e}');
+            if (unexpectedCrashesFile != null) {
+              unexpectedCrashesFile.closeSync();
             }
+          } catch (e) {
+            print('Failed to close unexpected-crashes file: ${e}');
           }
         }
       }
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index ac80516..9a5eed8 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -19,8 +19,6 @@
 import "dart:io" as io;
 import "dart:math" as math;
 
-import 'package:yaml/yaml.dart';
-
 import 'android.dart';
 import "browser_controller.dart";
 import 'dependency_graph.dart' as dgraph;
@@ -365,14 +363,25 @@
 }
 
 class VmCommand extends ProcessCommand {
+  final bool needsDFERunner;
   VmCommand._(String executable, List<String> arguments,
-      Map<String, String> environmentOverrides)
+      Map<String, String> environmentOverrides,
+      bool this.needsDFERunner)
       : super._("vm", executable, arguments, environmentOverrides);
+
+  void _buildHashCode(HashCodeBuilder builder) {
+    super._buildHashCode(builder);
+    builder.add(needsDFERunner);
+  }
+
+  bool _equal(VmCommand other) =>
+      super._equal(other) && needsDFERunner == other.needsDFERunner;
 }
 
 class VmBatchCommand extends ProcessCommand implements VmCommand {
   final String dartFile;
   final bool checked;
+  final needsDFERunner = false;
 
   VmBatchCommand._(String executable, String dartFile, List<String> arguments,
       Map<String, String> environmentOverrides, {this.checked: true})
@@ -443,11 +452,11 @@
   final String command;
 
   PubCommand._(String pubCommand, String pubExecutable,
-      String pubspecYamlDirectory, String pubCacheDirectory)
+      String pubspecYamlDirectory, String pubCacheDirectory, List<String> args)
       : super._(
             'pub_$pubCommand',
             new io.File(pubExecutable).absolute.path,
-            [pubCommand],
+            [pubCommand]..addAll(args),
             {'PUB_CACHE': pubCacheDirectory},
             pubspecYamlDirectory),
         command = pubCommand;
@@ -514,98 +523,6 @@
       _destinationDirectory == other._destinationDirectory;
 }
 
-class ModifyPubspecYamlCommand extends ScriptCommand {
-  String _pubspecYamlFile;
-  String _destinationFile;
-  Map<String, Map> _dependencyOverrides;
-
-  ModifyPubspecYamlCommand._(
-      this._pubspecYamlFile, this._destinationFile, this._dependencyOverrides)
-      : super._("modify_pubspec") {
-    assert(_pubspecYamlFile.endsWith("pubspec.yaml"));
-    assert(_destinationFile.endsWith("pubspec.yaml"));
-  }
-
-  static Map<String, Map> _filterOverrides(
-      String pubspec, Map<String, Map> overrides) {
-    if (overrides.isEmpty) return overrides;
-    var yaml = loadYaml(pubspec);
-    var deps = yaml['dependencies'];
-    var filteredOverrides = <String, Map>{};
-    if (deps != null) {
-      for (var d in deps.keys) {
-        if (!overrides.containsKey(d)) {
-          // pub depends on compiler_unsupported instead of compiler
-          // The dependency is so hackish that we currently ignore it here.
-          if (d == 'compiler_unsupported') continue;
-          throw "Repo doesn't have package $d used in $pubspec";
-        }
-        filteredOverrides[d] = overrides[d];
-      }
-    }
-    return filteredOverrides;
-  }
-
-  String get reproductionCommand =>
-      "Adding necessary dependency overrides to '$_pubspecYamlFile' "
-      "(destination = $_destinationFile).";
-
-  Future<ScriptCommandOutputImpl> run() {
-    var watch = new Stopwatch()..start();
-
-    var pubspecLockFile = _destinationFile.substring(
-            0, _destinationFile.length - ".yaml".length) +
-        ".lock";
-
-    var file = new io.File(_pubspecYamlFile);
-    var destinationFile = new io.File(_destinationFile);
-    var lockfile = new io.File(pubspecLockFile);
-    return file.readAsString().then((String yamlString) {
-      var overrides = _filterOverrides(yamlString, _dependencyOverrides);
-      var dependencyOverrideSection = new StringBuffer();
-      if (_dependencyOverrides.isNotEmpty) {
-        dependencyOverrideSection.write("\n"
-            "# This section was autogenerated by test.py!\n"
-            "dependency_overrides:\n");
-        overrides.forEach((String packageName, Map override) {
-          dependencyOverrideSection.write("  $packageName:\n");
-          override.forEach((overrideKey, overrideValue) {
-            dependencyOverrideSection
-                .write("    $overrideKey: $overrideValue\n");
-          });
-        });
-      }
-      var modifiedYamlString = "$yamlString\n$dependencyOverrideSection";
-      return destinationFile.writeAsString(modifiedYamlString).then((_) {
-        lockfile.exists().then((bool lockfileExists) {
-          if (lockfileExists) {
-            return lockfile.delete();
-          }
-        });
-      });
-    }).then((_) {
-      return new ScriptCommandOutputImpl(
-          this, Expectation.PASS, "", watch.elapsed);
-    }).catchError((error) {
-      return new ScriptCommandOutputImpl(
-          this, Expectation.FAIL, "An error occured: $error.", watch.elapsed);
-    });
-  }
-
-  void _buildHashCode(HashCodeBuilder builder) {
-    super._buildHashCode(builder);
-    builder.addJson(_pubspecYamlFile);
-    builder.addJson(_destinationFile);
-    builder.addJson(_dependencyOverrides);
-  }
-
-  bool _equal(ModifyPubspecYamlCommand other) =>
-      super._equal(other) &&
-      _pubspecYamlFile == other._pubspecYamlFile &&
-      _destinationFile == other._destinationFile &&
-      deepJsonCompare(_dependencyOverrides, other._dependencyOverrides);
-}
-
 /*
  * [MakeSymlinkCommand] makes a symbolic link to another directory.
  */
@@ -733,8 +650,8 @@
   }
 
   VmCommand getVmCommand(String executable, List<String> arguments,
-      Map<String, String> environmentOverrides) {
-    var command = new VmCommand._(executable, arguments, environmentOverrides);
+      Map<String, String> environmentOverrides, {bool needsDFERunner: false}) {
+    var command = new VmCommand._(executable, arguments, environmentOverrides, needsDFERunner);
     return _getUniqueCommand(command);
   }
 
@@ -778,9 +695,11 @@
   }
 
   Command getPubCommand(String pubCommand, String pubExecutable,
-      String pubspecYamlDirectory, String pubCacheDirectory) {
+      String pubspecYamlDirectory, String pubCacheDirectory,
+      {List<String> arguments: const <String>[]}) {
     var command = new PubCommand._(
-        pubCommand, pubExecutable, pubspecYamlDirectory, pubCacheDirectory);
+        pubCommand, pubExecutable, pubspecYamlDirectory, pubCacheDirectory,
+        arguments);
     return _getUniqueCommand(command);
   }
 
@@ -788,13 +707,6 @@
     return _getUniqueCommand(new MakeSymlinkCommand._(link, target));
   }
 
-  Command getModifyPubspecCommand(String pubspecYamlFile, Map depsOverrides,
-      {String destinationFile: null}) {
-    if (destinationFile == null) destinationFile = pubspecYamlFile;
-    return _getUniqueCommand(new ModifyPubspecYamlCommand._(
-        pubspecYamlFile, destinationFile, depsOverrides));
-  }
-
   Command _getUniqueCommand(Command command) {
     // All Command classes implement hashCode and operator==.
     // We check if this command has already been built.
@@ -1592,6 +1504,7 @@
 
 class VmCommandOutputImpl extends CommandOutputImpl
     with UnittestSuiteMessagesMixin {
+  static const DART_VM_EXITCODE_DFE_ERROR = 252;
   static const DART_VM_EXITCODE_COMPILE_TIME_ERROR = 254;
   static const DART_VM_EXITCODE_UNCAUGHT_EXCEPTION = 255;
 
@@ -1601,6 +1514,7 @@
 
   Expectation result(TestCase testCase) {
     // Handle crashes and timeouts first
+    if (exitCode == DART_VM_EXITCODE_DFE_ERROR) return Expectation.DARTK_CRASH;
     if (hasCrashed) return Expectation.CRASH;
     if (hasTimedOut) return Expectation.TIMEOUT;
 
@@ -1893,6 +1807,40 @@
   }
 }
 
+// Helper to get a list of all child pids for a parent process.
+// The first element of the list is the parent pid.
+Future<List<int>> _getPidList(pid, diagnostics) async {
+  var pid_list = [pid];
+  var lines;
+  var start_line = 0;
+  if (io.Platform.isLinux || io.Platform.isMacOS) {
+    var result = await io.Process.run("pgrep",
+        ["-P", "${pid_list[0]}"],
+        runInShell: true);
+    lines = result.stdout.split('\n');
+  } else if (io.Platform.isWindows) {
+    var result = await io.Process.run("wmic",
+        ["process", "where" , "(ParentProcessId=${pid_list[0]})",
+         "get", "ProcessId"],
+        runInShell: true);
+    lines = result.stdout.split('\n');
+    // Skip first line containing header "ProcessId".
+    start_line = 1;
+  } else {
+    assert(false);
+  }
+  if (lines.length > start_line) {
+    for (int i = start_line; i < lines.length; ++i) {
+      var pid = int.parse(lines[i], onError: (source) => null);
+      if (pid != null) pid_list.add(pid);
+    }
+  } else {
+    diagnostics.add("Could not find child pids");
+    diagnostics.addAll(lines);
+  }
+  return pid_list;
+}
+
 /**
  * A RunningProcess actually runs a test, getting the command lines from
  * its [TestCase], starting the test process (and first, a compilation
@@ -1915,8 +1863,13 @@
   List<String> diagnostics = <String>[];
   bool compilationSkipped = false;
   Completer<CommandOutput> completer;
+  Map configuration;
+  List<String> preArguments;
 
-  RunningProcess(this.command, this.timeout);
+  RunningProcess(this.command,
+                 this.timeout,
+                 {this.configuration,
+                  this.preArguments});
 
   Future<CommandOutput> run() {
     completer = new Completer<CommandOutput>();
@@ -1932,8 +1885,12 @@
         _commandComplete(0);
       } else {
         var processEnvironment = _createProcessEnvironment();
+        var args = command.arguments;
+        if (preArguments != null) {
+          args = []..addAll(preArguments)..addAll(args);
+        }
         Future processFuture = io.Process.start(
-            command.executable, command.arguments,
+            command.executable, args,
             environment: processEnvironment,
             workingDirectory: command.workingDirectory);
         processFuture.then((io.Process process) {
@@ -1979,26 +1936,52 @@
           timeoutHandler() async {
             timedOut = true;
             if (process != null) {
-              var executable, arguments;
+              var executable;
               if (io.Platform.isLinux) {
                 executable = 'eu-stack';
-                arguments = ['-p ${process.pid}'];
               } else if (io.Platform.isMacOS) {
                 // Try to print stack traces of the timed out process.
                 // `sample` is a sampling profiler but we ask it sample for 1
                 // second with a 4 second delay between samples so that we only
                 // sample the threads once.
                 executable = '/usr/bin/sample';
-                arguments = ['${process.pid}', '1', '4000', '-mayDie'];
+              } else if (io.Platform.isWindows) {
+                bool is_x64 = command.executable.contains("X64") ||
+                              command.executable.contains("SIMARM64");
+                var win_sdk_path = configuration['win_sdk_path'];
+                if (win_sdk_path != null) {
+                  executable = win_sdk_path +
+                      "\\Debuggers\\" + (is_x64 ? "x64" : "x86") + "\\cdb.exe";
+                  diagnostics.add("Using $executable to print stack traces");
+                } else {
+                  diagnostics.add("win_sdk path not found");
+                }
+              } else {
+                diagnostics.add("Capturing stack traces on"
+                                "${io.Platform.operatingSystem} not supported");
               }
-
               if (executable != null) {
-                try {
-                  var result = await io.Process.run(executable, arguments);
-                  diagnostics.addAll(result.stdout.split('\n'));
-                  diagnostics.addAll(result.stderr.split('\n'));
-                } catch (error) {
-                  diagnostics.add("Unable to capture stack traces: $error");
+                var pid_list = await _getPidList(process.pid, diagnostics);
+                diagnostics.add("Process list including children: $pid_list");
+                for (pid in pid_list) {
+                  var arguments;
+                  if (io.Platform.isLinux) {
+                    arguments = ['-p $pid'];
+                  } else if (io.Platform.isMacOS) {
+                    arguments = ['$pid', '1', '4000', '-mayDie'];
+                  } else if (io.Platform.isWindows) {
+                    arguments = ['-p', '$pid', '-c', '!uniqstack;qd'];
+                  } else {
+                    assert(false);
+                  }
+                  diagnostics.add("Trying to capture stack trace for pid $pid");
+                  try {
+                    var result = await io.Process.run(executable, arguments);
+                    diagnostics.addAll(result.stdout.split('\n'));
+                    diagnostics.addAll(result.stderr.split('\n'));
+                  } catch (error) {
+                    diagnostics.add("Unable to capture stack traces: $error");
+                  }
                 }
               }
 
@@ -2087,7 +2070,7 @@
   }
 }
 
-class BatchRunnerProcess {
+class BatchRunnerProcess  {
   Completer<CommandOutput> _completer;
   ProcessCommand _command;
   List<String> _arguments;
@@ -2108,8 +2091,6 @@
   DateTime _startTime;
   Timer _timer;
 
-  BatchRunnerProcess();
-
   Future<CommandOutput> runCommand(String runnerType, ProcessCommand command,
       int timeout, List<String> arguments) {
     assert(_completer == null);
@@ -2306,6 +2287,102 @@
   }
 }
 
+class BatchDFEProcess  {
+  io.Process _process;
+  int _port = -1;
+  Function _processExitHandler;
+
+  Completer terminating = null;
+
+  bool locked = false;
+
+  Future<int> acquire() async {
+    try {
+      assert(!locked);
+      locked = true;
+      if (_process == null) {
+        await _startProcess();
+      }
+      return _port;
+    } catch(e) {
+      locked = false;
+      rethrow;
+    }
+  }
+
+  void release() {
+    locked = false;
+  }
+
+  Future terminate() {
+    locked = true;
+    if (_process == null) {
+      return new Future.value(true);
+    }
+    if (terminating == null) {
+      terminating = new Completer();
+      _process.kill();
+    }
+    return terminating.future;
+  }
+
+  _onExit(exitCode) {
+    if (terminating != null) {
+      terminating.complete();
+      return;
+    }
+
+    _process = null;
+    locked = false;
+    _port = -1;
+  }
+
+  static Future<String> _firstLine(stream) {
+    var completer = new Completer<String>();
+    stream.transform(UTF8.decoder)
+          .transform(new LineSplitter())
+          .listen((line) {
+      if (!completer.isCompleted) {
+        completer.complete(line);
+      }
+      // We need to drain a pipe continuously.
+    }, onDone: () {
+      if (!completer.isCompleted) {
+        completer.completeError(
+            "DFE kernel compiler server did not sucessfully start up");
+      }
+    });
+    return completer.future;
+  }
+
+  Future _startProcess() async {
+    final executable = io.Platform.executable;
+    final arguments = ['utils/kernel-service/kernel-service.dart', '--batch'];
+
+    try {
+      _port = -1;
+      _process = await io.Process.start(executable, arguments);
+      _process.exitCode.then(_onExit);
+      _process.stderr.transform(UTF8.decoder).listen(DebugLogger.error);
+
+      final readyMsg = await _firstLine(_process.stdout);
+      final data = readyMsg.split(' ');
+      assert(data[0] == 'READY');
+
+      _port = int.parse(data[1]);
+    } catch (e) {
+      print("Process error:");
+      print("  Command: $executable ${arguments.join(' ')}");
+      print("  Error: $e");
+      // If there is an error starting a batch process, chances are that
+      // it will always fail. So rather than re-trying a 1000+ times, we
+      // exit.
+      io.exit(1);
+      return true;
+    }
+  }
+}
+
 /**
  * [TestCaseEnqueuer] takes a list of TestSuites, generates TestCases and
  * builds a dependency graph of all commands in every TestSuite.
@@ -2614,6 +2691,8 @@
   // We keep a BrowserTestRunner for every configuration.
   final _browserTestRunners = new Map<Map, BrowserTestRunner>();
 
+  List<BatchDFEProcess> _dfeProcesses = null;
+
   bool _finishing = false;
 
   CommandExecutorImpl(
@@ -2638,7 +2717,14 @@
       return Future.wait(futures);
     }
 
-    return Future.wait([_terminateBatchRunners(), _terminateBrowserRunners()]);
+    Future _terminateDFEWorkers() =>
+      Future.wait((_dfeProcesses ?? <BatchDFEProcess>[]).map((p) => p.terminate()));
+
+    return Future.wait([
+      _terminateBatchRunners(),
+      _terminateBrowserRunners(),
+      _terminateDFEWorkers()
+    ]);
   }
 
   Future<CommandOutput> runCommand(node, Command command, int timeout) {
@@ -2686,12 +2772,20 @@
           adbDevicePool.releaseDevice(device);
         });
       });
+    } else if (command is VmCommand && command.needsDFERunner) {
+      final runner = _getDFEProcess();
+      return runner.acquire().then((port) {
+        return new RunningProcess(command, timeout,
+            configuration: globalConfiguration,
+            preArguments: ['-DDFE_WORKER_PORT=${port}']).run();
+      }).whenComplete(() => runner.release());
     } else if (command is VmBatchCommand) {
       var name = command.displayName;
       return _getBatchRunner(command.displayName + command.dartFile)
           .runCommand(name, command, timeout, command.arguments);
     } else {
-      return new RunningProcess(command, timeout).run();
+      return new RunningProcess(
+          command, timeout, configuration: globalConfiguration).run();
     }
   }
 
@@ -2788,6 +2882,12 @@
     throw new Exception('Unable to find inactive batch runner.');
   }
 
+  BatchDFEProcess _getDFEProcess() {
+    _dfeProcesses ??= new List<BatchDFEProcess>.generate(maxProcesses,
+        (_) => new BatchDFEProcess());
+    return _dfeProcesses.firstWhere((runner) => !runner.locked);
+  }
+
   Future<CommandOutput> _startBrowserControllerTest(
       BrowserTestCommand browserCommand, int timeout) {
     var completer = new Completer<CommandOutput>();
@@ -3162,7 +3262,7 @@
           eventFinishedTestCase(finishedTestCase);
         }
       }, onDone: () {
-        // Wait until the commandQueue/execturo is done (it may need to stop
+        // Wait until the commandQueue/exectutor is done (it may need to stop
         // batch runners, browser controllers, ....)
         commandQueue.done.then((_) {
           cancelDebugTimer();
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index a556912..a16141d 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -386,10 +386,8 @@
     var strong =  configuration['strong'] ? '-strong' : '';
     var minified = configuration['minified'] ? '-minified' : '';
     var sdk = configuration['use_sdk'] ? '-sdk' : '';
-    var packages =
-        configuration['use_public_packages'] ? '-public_packages' : '';
     var dirName = "${configuration['compiler']}-${configuration['runtime']}"
-        "$checked$strong$minified$packages$sdk";
+        "$checked$strong$minified$sdk";
     return createGeneratedTestDirectoryHelper(
         "tests", dirName, testPath, optionsName);
   }
@@ -400,29 +398,21 @@
     var minified = configuration['minified'] ? '-minified' : '';
     var csp = configuration['csp'] ? '-csp' : '';
     var sdk = configuration['use_sdk'] ? '-sdk' : '';
-    var packages =
-        configuration['use_public_packages'] ? '-public_packages' : '';
     var dirName = "${configuration['compiler']}"
-        "$checked$strong$minified$csp$packages$sdk";
+        "$checked$strong$minified$csp$sdk";
     return createGeneratedTestDirectoryHelper(
         "compilations", dirName, testPath, "");
   }
 
   String createPubspecCheckoutDirectory(Path directoryOfPubspecYaml) {
-    var sdk = configuration['use_sdk'] ? '-sdk' : '';
-    var pkg = configuration['use_public_packages']
-        ? 'public_packages'
-        : 'repo_packages';
+    var sdk = configuration['use_sdk'] ? 'sdk' : '';
     return createGeneratedTestDirectoryHelper(
-        "pubspec_checkouts", '$pkg$sdk', directoryOfPubspecYaml, "");
+        "pubspec_checkouts", sdk, directoryOfPubspecYaml, "");
   }
 
   String createPubPackageBuildsDirectory(Path directoryOfPubspecYaml) {
-    var pkg = configuration['use_public_packages']
-        ? 'public_packages'
-        : 'repo_packages';
     return createGeneratedTestDirectoryHelper(
-        "pub_package_builds", pkg, directoryOfPubspecYaml, "");
+        "pub_package_builds", 'public_packages', directoryOfPubspecYaml, "");
   }
 
   /**
@@ -516,17 +506,6 @@
       return packageDirectories;
     });
   }
-
-  /**
-   * Helper function for building dependency_overrides for pubspec.yaml files.
-   */
-  Map buildPubspecDependencyOverrides(Map packageDirectories) {
-    Map overrides = {};
-    packageDirectories.forEach((String packageName, String fullPath) {
-      overrides[packageName] = {'path': fullPath};
-    });
-    return overrides;
-  }
 }
 
 Future<Iterable<String>> ccTestLister(String runnerPath) {
@@ -896,87 +875,14 @@
       enqueueHtmlTest(info, testName, expectations);
       return;
     }
-    var filePath = info.filePath;
     var optionsFromFile = info.optionsFromFile;
 
-    Map buildSpecialPackageRoot(Path pubspecYamlFile) {
-      var commands = <Command>[];
-      var packageDir = pubspecYamlFile.directoryPath;
-      var packageName = packageDir.filename;
-
-      var checkoutDirectory = createPubspecCheckoutDirectory(packageDir);
-      var modifiedYamlFile = new Path(checkoutDirectory).append("pubspec.yaml");
-      var pubCacheDirectory = new Path(checkoutDirectory).append("pub-cache");
-      var newPackageRoot = new Path(checkoutDirectory).append("packages");
-
-      // Remove the old packages directory, so we can do a clean 'pub get'.
-      var newPackagesDirectory = new Directory(newPackageRoot.toNativePath());
-      if (newPackagesDirectory.existsSync()) {
-        newPackagesDirectory.deleteSync(recursive: true);
-      }
-
-      // NOTE: We make a link in the package-root to [packageName], since
-      // 'pub get' doesn't create the link to the package containing
-      // pubspec.yaml if there is no lib directory.
-      var packageLink = newPackageRoot.append(packageName);
-      var packageLinkTarget = packageDir.append('lib');
-
-      // NOTE: We make a link in the package-root to pkg/expect, since
-      // 'package:expect' is not available on pub.dartlang.org!
-      var expectLink = newPackageRoot.append('expect');
-      var expectLinkTarget =
-          TestUtils.dartDir.append('pkg').append('expect').append('lib');
-
-      // Generate dependency overrides if we use repository packages.
-      var packageDirectories = {};
-      if (configuration['use_repository_packages']) {
-        packageDirectories = new Map.from(localPackageDirectories);
-
-        // Don't create a dependency override for pub, since it's an application
-        // package and it has a dependency on compiler_unsupported which isn't
-        // in the repo.
-        packageDirectories.remove('pub');
-
-        // Do not create an dependency override for the package itself.
-        if (packageDirectories.containsKey(packageName)) {
-          packageDirectories.remove(packageName);
-        }
-      }
-      var overrides = buildPubspecDependencyOverrides(packageDirectories);
-
-      commands.add(CommandBuilder.instance.getModifyPubspecCommand(
-          pubspecYamlFile.toNativePath(), overrides,
-          destinationFile: modifiedYamlFile.toNativePath()));
-      commands.add(CommandBuilder.instance.getPubCommand(
-          "get", pubPath, checkoutDirectory, pubCacheDirectory.toNativePath()));
-      if (new Directory(packageLinkTarget.toNativePath()).existsSync()) {
-        commands.add(CommandBuilder.instance.getMakeSymlinkCommand(
-            packageLink.toNativePath(), packageLinkTarget.toNativePath()));
-      }
-      commands.add(CommandBuilder.instance.getMakeSymlinkCommand(
-          expectLink.toNativePath(), expectLinkTarget.toNativePath()));
-
-      return {'commands': commands, 'package-root': newPackageRoot,};
-    }
-
     // If this test is inside a package, we will check if there is a
     // pubspec.yaml file and if so, create a custom package root for it.
     List<Command> baseCommands = <Command>[];
     Path packageRoot;
     Path packages;
-    if (configuration['use_repository_packages'] ||
-        configuration['use_public_packages']) {
-      Path pubspecYamlFile = _findPubspecYamlFile(filePath);
-      if (pubspecYamlFile != null) {
-        var result = buildSpecialPackageRoot(pubspecYamlFile);
-        baseCommands.addAll(result['commands']);
-        packageRoot = result['package-root'];
-        if (optionsFromFile['packageRoot'] == null ||
-            optionsFromFile['packageRoot'] == "") {
-          optionsFromFile['packageRoot'] = packageRoot.toNativePath();
-        }
-      }
-    }
+
     if (optionsFromFile['packageRoot'] == null &&
         optionsFromFile['packages'] == null) {
       if (configuration['package_root'] != null) {
@@ -1962,9 +1868,13 @@
 }
 
 class AnalyzeLibraryTestSuite extends DartcCompilationTestSuite {
+  static String libraryPath(Map configuration) => configuration['use_sdk']
+      ? '${TestUtils.buildDir(configuration)}/dart-sdk'
+      : 'sdk';
+
   AnalyzeLibraryTestSuite(Map configuration)
-      : super(configuration, 'analyze_library', 'sdk', ['lib'],
-            ['tests/lib/analyzer/analyze_library.status']);
+      : super(configuration, 'analyze_library', libraryPath(configuration),
+            ['lib'], ['tests/lib/analyzer/analyze_library.status']);
 
   List<String> additionalOptions(Path filePath, {bool showSdkWarnings}) {
     var options = super.additionalOptions(filePath);
@@ -2013,39 +1923,19 @@
         var directoryPath = absoluteDirectoryPath.relativeTo(TestUtils.dartDir);
         var testName = "$directoryPath";
         var displayName = '$suiteName/$testName';
-        var packageName = directoryPath.filename;
 
-        // Collect necessary paths for pubspec.yaml overrides, pub-cache, ...
         var checkoutDir =
             createPubPackageBuildsDirectory(absoluteDirectoryPath);
         var cacheDir = new Path(checkoutDir).append("pub-cache").toNativePath();
-        var pubspecYamlFile =
-            new Path(checkoutDir).append('pubspec.yaml').toNativePath();
-
-        var packageDirectories = {};
-        if (!configuration['use_public_packages']) {
-          packageDirectories = new Map.from(localPackageDirectories);
-
-          // Don't create a dependency override for pub, since it's an
-          // application package and it has a dependency on compiler_unsupported
-          // which isn't in the repo.
-          packageDirectories.remove('pub');
-
-          if (packageDirectories.containsKey(packageName)) {
-            packageDirectories.remove(packageName);
-          }
-        }
-        var dependencyOverrides =
-            buildPubspecDependencyOverrides(packageDirectories);
 
         // Build all commands
-        var commands = new List<Command>();
-        commands.add(
-            CommandBuilder.instance.getCopyCommand(directory, checkoutDir));
-        commands.add(CommandBuilder.instance
-            .getModifyPubspecCommand(pubspecYamlFile, dependencyOverrides));
-        commands.add(CommandBuilder.instance
-            .getPubCommand("get", pubPath, checkoutDir, cacheDir));
+        // In order to debug timeouts on the buildbots, We run `pub get` with
+        // "--verbose". See https://github.com/dart-lang/sdk/issues/28734.
+        var commands = [
+          CommandBuilder.instance.getCopyCommand(directory, checkoutDir),
+          CommandBuilder.instance.getPubCommand(
+              "get", pubPath, checkoutDir, cacheDir, arguments: ['--verbose'])
+        ];
 
         bool containsWebDirectory = dirExists(directoryPath.append('web'));
         bool containsBuildDartFile =
@@ -2257,10 +2147,8 @@
       var minified = configuration['minified'] ? '-minified' : '';
       var csp = configuration['csp'] ? '-csp' : '';
       var sdk = configuration['use_sdk'] ? '-sdk' : '';
-      var packages =
-          configuration['use_public_packages'] ? '-public_packages' : '';
       var dirName = "${configuration['compiler']}"
-          "$checked$strong$minified$csp$packages$sdk";
+          "$checked$strong$minified$csp$sdk";
       String generatedPath = "${TestUtils.buildDir(configuration)}"
           "/generated_compilations/$dirName";
       TestUtils.deleteDirectory(generatedPath);
diff --git a/tools/utils.py b/tools/utils.py
index 87ee907..da2cd28 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -6,6 +6,7 @@
 # scripts.
 
 import commands
+import contextlib
 import datetime
 import glob
 import imp
@@ -606,7 +607,7 @@
     osname = osdict[system]
   except KeyError:
     print >>sys.stderr, ('WARNING: platform "%s" not supported') % (system)
-    return None;
+    return None
   tools_dir = os.path.dirname(os.path.realpath(__file__))
   return os.path.join(tools_dir,
                       'sdks',
@@ -649,6 +650,23 @@
   return False
 
 
+def CheckLinuxCoreDumpPattern(fatal=False):
+  core_pattern_file = '/proc/sys/kernel/core_pattern'
+  core_pattern = open(core_pattern_file).read()
+
+  expected_core_pattern = 'core.%p'
+  if core_pattern.strip() != expected_core_pattern:
+    if fatal:
+      message = ('Invalid core_pattern configuration. '
+          'The configuration of core dump handling is *not* correct for '
+          'a buildbot. The content of {0} must be "{1}" instead of "{2}".'
+          .format(core_pattern_file, expected_core_pattern, core_pattern))
+      raise Exception(message)
+    else:
+      return False
+  return True
+
+
 class TempDir(object):
   def __init__(self, prefix=''):
     self._temp_dir = None
@@ -674,100 +692,164 @@
     print "Enter directory = ", self._old_cwd
     os.chdir(self._old_cwd)
 
-class CoreDump(object):
-  def __init__(self, test, core, binary):
+
+class UnexpectedCrash(object):
+  def __init__(self, test, pid, binary):
     self.test = test
-    self.core = core
+    self.pid = pid 
     self.binary = binary
 
   def __str__(self):
-    return "%s: %s %s" % (self.test, self.binary, self.core)
+    return "%s: %s %s" % (self.test, self.binary, self.pid)
 
-class CoreDumpArchiver(object):
+
+class PosixCoredumpEnabler(object):
+  def __init__(self):
+    self._old_limits = None
+
+  def __enter__(self):
+    self._old_limits = resource.getrlimit(resource.RLIMIT_CORE)
+
+    # Bump core limits to unlimited if core_pattern is correctly configured.
+    if CheckLinuxCoreDumpPattern(fatal=False):
+      resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
+
+  def __exit__(self, *_):
+    resource.setrlimit(resource.RLIMIT_CORE, self._old_limits)
+    CheckLinuxCoreDumpPattern(fatal=True)
+
+class WindowsCoredumpEnabler(object):
+  """Configure Windows Error Reporting to store crash dumps.
+
+  The documentation can be found here:
+  https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181.aspx
+  """
+
+  WINDOWS_COREDUMP_FOLDER = r'crashes'
+
+  WER_NAME = r'SOFTWARE\Microsoft\Windows\Windows Error Reporting'
+  WER_LOCALDUMPS_NAME = r'%s\LocalDumps' % WER_NAME
+  IMGEXEC_NAME = (r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
+                  r'\Image File Execution Options\WerFault.exe')
+
+  def __init__(self):
+    # Depending on whether we're in cygwin or not we use a different import.
+    try:
+      import winreg
+    except ImportError:
+      import _winreg as winreg
+    self.winreg = winreg
+
+  def __enter__(self):
+    # We want 32 and 64 bit coredumps to land in the same coredump directory.
+    for sam in [self.winreg.KEY_WOW64_64KEY, self.winreg.KEY_WOW64_32KEY]:
+      # In case WerFault.exe was prevented from executing, we fix it here.
+      # TODO(kustermann): Remove this once https://crbug.com/691971 is fixed.
+      self._prune_existing_key(
+          self.winreg.HKEY_LOCAL_MACHINE, self.IMGEXEC_NAME, sam)
+
+      # Create (or open) the WER keys.
+      with self.winreg.CreateKeyEx(
+            self.winreg.HKEY_LOCAL_MACHINE, self.WER_NAME, 0,
+            self.winreg.KEY_ALL_ACCESS | sam) as wer:
+        with self.winreg.CreateKeyEx(
+            self.winreg.HKEY_LOCAL_MACHINE, self.WER_LOCALDUMPS_NAME, 0,
+            self.winreg.KEY_ALL_ACCESS | sam) as wer_localdumps:
+          # Prevent any modal UI dialog & disable normal windows error reporting
+          # TODO(kustermann): Remove this once https://crbug.com/691971 is fixed
+          self.winreg.SetValueEx(wer, "DontShowUI", 0, self.winreg.REG_DWORD, 1)
+          self.winreg.SetValueEx(wer, "Disabled", 0, self.winreg.REG_DWORD, 1)
+
+          coredump_folder = os.path.join(
+              os.getcwd(), WindowsCoredumpEnabler.WINDOWS_COREDUMP_FOLDER)
+
+          # Create the directory which will contain the dumps
+          if not os.path.exists(coredump_folder):
+            os.mkdir(coredump_folder)
+
+          # Do full dumps (not just mini dumps), keep max 100 dumps and specify
+          # folder.
+          self.winreg.SetValueEx(
+              wer_localdumps, "DumpType", 0, self.winreg.REG_DWORD, 2)
+          self.winreg.SetValueEx(
+              wer_localdumps, "DumpCount", 0, self.winreg.REG_DWORD, 200)
+          self.winreg.SetValueEx(
+              wer_localdumps, "DumpFolder", 0, self.winreg.REG_EXPAND_SZ,
+              coredump_folder)
+
+  def __exit__(self, *_):
+    # We remove the local dumps settings after running the tests.
+    for sam in [self.winreg.KEY_WOW64_64KEY, self.winreg.KEY_WOW64_32KEY]:
+      with self.winreg.CreateKeyEx(
+          self.winreg.HKEY_LOCAL_MACHINE, self.WER_LOCALDUMPS_NAME, 0,
+          self.winreg.KEY_ALL_ACCESS | sam) as wer_localdumps:
+        self.winreg.DeleteValue(wer_localdumps, 'DumpType')
+        self.winreg.DeleteValue(wer_localdumps, 'DumpCount')
+        self.winreg.DeleteValue(wer_localdumps, 'DumpFolder')
+
+  def _prune_existing_key(self, key, subkey, wowbit):
+    handle = None
+
+    # If the open fails, the key doesn't exist and it's fine.
+    try:
+      handle = self.winreg.OpenKey(
+          key, subkey, 0, self.winreg.KEY_READ | wowbit)
+    except OSError:
+      pass
+
+    # If the key exists then we delete it. If the deletion does not work, we
+    # let the exception through.
+    if handle:
+      handle.Close()
+      self.winreg.DeleteKeyEx(key, subkey, wowbit, 0)
+
+class BaseCoreDumpArchiver(object):
   """This class reads coredumps file written by UnexpectedCrashDumpArchiver
   into the current working directory and uploads all cores and binaries
   listed in it into Cloud Storage (see tools/testing/dart/test_progress.dart).
   """
 
-  def __init__(self, args):
-    self._enabled = '--copy-coredumps' in args and GuessOS() == 'linux'
-    self._search_dir = os.getcwd()
+  # test.dart will write a line for each unexpected crash into this file.
+  _UNEXPECTED_CRASHES_FILE = "unexpected-crashes"
+
+  def __init__(self):
     self._bucket = 'dart-temp-crash-archive'
-    self._old_limits = None
+    self._binaries_dir = os.getcwd()
 
   def __enter__(self):
-    if not self._enabled:
-      return
-
-    # Cleanup any stale coredumps
+    # Cleanup any stale files
     if self._cleanup():
       print "WARNING: Found and removed stale coredumps"
 
-    self._old_limits = resource.getrlimit(resource.RLIMIT_CORE)
-
-    # Bump core limits to unlimited if core_pattern is correctly configured.
-    if self._check_core_dump_pattern(fatal=False):
-      resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
-
   def __exit__(self, *_):
-    if not self._enabled:
-      return
-
     try:
-      # Restore old core limit.
-      resource.setrlimit(resource.RLIMIT_CORE, self._old_limits)
-
-      # Check that kernel was correctly configured to use core.%p
-      # core_pattern.
-      self._check_core_dump_pattern(fatal=True)
-
-      coredumps = self._find_coredumps()
-      if coredumps:
+      crashes = self._find_unexpected_crashes()
+      if crashes:
         # If we get a ton of crashes, only archive 10 dumps.
-        archive_coredumps = coredumps[:10]
-        print 'Archiving coredumps:'
-        for core in archive_coredumps:
-          print '----> %s' % core
+        archive_crashes = crashes[:10]
+        print 'Archiving coredumps for crash (if possible):'
+        for crash in archive_crashes:
+          print '----> %s' % crash
 
         sys.stdout.flush()
-        self._archive(archive_coredumps)
+        self._archive(archive_crashes)
 
     finally:
       self._cleanup()
 
-  def _cleanup(self):
-    found = False
-    for core in glob.glob(os.path.join(self._search_dir, 'core.*')):
-      found = True
-      os.unlink(core)
-    for binary in glob.glob(os.path.join(self._search_dir, 'binary.*')):
-      found = True
-      os.unlink(binary)
-    try:
-      os.unlink(os.path.join(self._search_dir, 'coredumps'))
-      found = True
-    except:
-      pass
-
-    return found
-
-  def _find_coredumps(self):
-    """Load coredumps file. Each line has the following format:
-
-              test-name,core-file,binary-file
-    """
-    try:
-      with open('coredumps') as f:
-        return [CoreDump(*ln.strip('\n').split(',')) for ln in f.readlines()]
-    except:
-      return []
-
-  def _archive(self, coredumps):
+  def _archive(self, crashes):
     files = set()
-    for core in coredumps:
-      files.add(core.core)
-      files.add(core.binary)
+    missing = []
+    for crash in crashes:
+      files.add(crash.binary)
+      core = self._find_coredump_file(crash)
+      if core:
+        files.add(core)
+      else:
+        missing.append(crash)
     self._upload(files)
+    if missing:
+      raise Exception('Missing crash dumps for: %s' % ', '.join(missing))
 
   def _upload(self, files):
     bot_utils = GetBotUtils()
@@ -805,21 +887,84 @@
       os.unlink(tarname)
     print '--- Done ---\n'
 
-  def _check_core_dump_pattern(self, fatal=False):
-    core_pattern_file = '/proc/sys/kernel/core_pattern'
-    core_pattern = open(core_pattern_file).read()
+  def _find_unexpected_crashes(self):
+    """Load coredumps file. Each line has the following format:
 
-    expected_core_pattern = 'core.%p'
-    if core_pattern.strip() != expected_core_pattern:
-      if fatal:
-        message = ('Invalid core_pattern configuration. '
-            'The configuration of core dump handling is *not* correct for '
-            'a buildbot. The content of {0} must be "{1}" instead of "{2}".'
-            .format(core_pattern_file, expected_core_pattern, core_pattern))
-        raise Exception(message)
-      else:
-        return False
-    return True
+        test-name,pid,binary-file
+    """
+    try:
+      with open(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE) as f:
+        return [UnexpectedCrash(*ln.strip('\n').split(',')) for ln in f.readlines()]
+    except:
+      return []
+
+  def _cleanup(self):
+    found = False
+    if os.path.exists(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE):
+      os.unlink(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE)
+      found = True
+    for binary in glob.glob(os.path.join(self._binaries_dir, 'binary.*')):
+      found = True
+      os.unlink(binary)
+    return found
+
+class LinuxCoreDumpArchiver(BaseCoreDumpArchiver):
+  def __init__(self):
+    super(self.__class__, self).__init__()
+    self._search_dir = os.getcwd()
+
+  def _cleanup(self):
+    found = super(self.__class__, self)._cleanup()
+    for core in glob.glob(os.path.join(self._search_dir, 'core.*')):
+      found = True
+      os.unlink(core)
+    return found
+
+  def _find_coredump_file(self, crash):
+    core_filename = os.path.join(self._search_dir, 'core.%s' % crash.pid)
+    if os.path.exists(core_filename):
+      return core_filename
+
+class WindowsCoreDumpArchiver(BaseCoreDumpArchiver):
+  def __init__(self):
+    super(self.__class__, self).__init__()
+    self._search_dir = os.path.join(
+        os.getcwd(), WindowsCoredumpEnabler.WINDOWS_COREDUMP_FOLDER)
+
+  def _cleanup(self):
+    found = super(self.__class__, self)._cleanup()
+    for core in glob.glob(os.path.join(self._search_dir, '*')):
+      found = True
+      os.unlink(core)
+    return found
+
+  def _find_coredump_file(self, crash):
+    pattern = os.path.join(self._search_dir, '*.%s.*' % crash.pid)
+    for core_filename in glob.glob(pattern):
+      return core_filename
+
+@contextlib.contextmanager
+def NooptCoreDumpArchiver():
+  yield
+
+
+def CoreDumpArchiver(args):
+  enabled = '--copy-coredumps' in args
+
+  if not enabled:
+    return NooptCoreDumpArchiver()
+
+  osname = GuessOS()
+  if osname == 'linux':
+    return contextlib.nested(PosixCoredumpEnabler(),
+                             LinuxCoreDumpArchiver())
+  elif osname == 'win32':
+    return contextlib.nested(WindowsCoredumpEnabler(),
+                             WindowsCoreDumpArchiver())
+  else:
+    # We don't have support for MacOS yet.
+    assert osname == 'macos'
+    return NooptCoreDumpArchiver()
 
 if __name__ == "__main__":
   import sys
diff --git a/utils/kernel-service/BUILD.gn b/utils/kernel-service/BUILD.gn
new file mode 100644
index 0000000..f62e064
--- /dev/null
+++ b/utils/kernel-service/BUILD.gn
@@ -0,0 +1,17 @@
+# 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("../application_snapshot.gni")
+
+application_snapshot("kernel-service") {
+  dfe_script = "kernel-service.dart"
+  deps = [
+    "../../runtime/vm:patched_sdk($host_toolchain)",
+  ]
+  main_dart = dfe_script
+  training_args = [
+    "--train",
+    "file://" + rebase_path("../../pkg/compiler/lib/src/dart2js.dart"),
+  ]
+}
diff --git a/utils/kernel-service/kernel-service.dart b/utils/kernel-service/kernel-service.dart
new file mode 100644
index 0000000..d162465
--- /dev/null
+++ b/utils/kernel-service/kernel-service.dart
@@ -0,0 +1,407 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This is an interface to the Dart Kernel parser and Kernel binary generator.
+///
+/// It is used by the kernel-isolate to load Dart source code and generate
+/// Kernel binary format.
+///
+/// This is either invoked as the root script of the Kernel isolate when used
+/// as a part of
+///
+///           dart --dfe=utils/kernel-service/kernel-service.dart ...
+///
+/// invocation or it is invoked as a standalone script to perform batch mode
+/// compilation requested via an HTTP interface
+///
+///           dart utils/kernel-service/kernel-service.dart --batch
+///
+/// The port for the batch mode worker is controlled by DFE_WORKER_PORT
+/// environment declarations (set by -DDFE_WORKER_PORT=... command line flag).
+/// When not set (or set to 0) an ephemeral port returned by the OS is used
+/// instead.
+///
+/// When this script is used as a Kernel isolate root script and DFE_WORKER_PORT
+/// is set to non-zero value then Kernel isolate will forward all compilation
+/// requests it receives to the batch worker on the given port.
+///
+/// Set DFE_USE_FASTA environment declaration to true to use fasta front-end
+/// instead of dartk. Note: we expect patched_sdk folder to contain
+/// platform.dill file that contains patched SDK in the Kernel binary form.
+/// This file can be created using the following command line:
+///
+///   export DART_AOT_SDK=<path-to-patched_sdk>
+///   dart pkg/front_end/lib/src/fasta/bin/compile_platform.dart \
+///        ${DART_AOT_SDK}/platform.dill
+///
+library runtime.tools.kernel_service;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:typed_data';
+
+import 'package:kernel/analyzer/loader.dart';
+import 'package:kernel/binary/ast_to_binary.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/target/targets.dart';
+
+import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
+import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
+import 'package:front_end/src/fasta/ticker.dart' show Ticker;
+import 'package:front_end/src/fasta/kernel/kernel_target.dart'
+    show KernelTarget;
+import 'package:front_end/src/fasta/ast_kind.dart' show AstKind;
+import 'package:front_end/src/fasta/errors.dart' show InputError;
+
+const bool verbose = const bool.fromEnvironment('DFE_VERBOSE');
+const int workerPort = const int.fromEnvironment('DFE_WORKER_PORT') ?? 0;
+const bool useFasta = const bool.fromEnvironment('DFE_USE_FASTA');
+
+class DataSink implements Sink<List<int>> {
+  final BytesBuilder builder = new BytesBuilder();
+
+  void add(List<int> data) {
+    builder.add(data);
+  }
+
+  void close() {
+    // Nothing to do.
+  }
+}
+
+// Note: these values must match Dart_KernelCompilationStatus in dart_api.h.
+const int STATUS_OK = 0; // Compilation was successful.
+const int STATUS_ERROR = 1; // Compilation failed with a compile time error.
+const int STATUS_CRASH = 2; // Compiler crashed.
+
+abstract class CompilationResult {
+  List toResponse();
+}
+
+class CompilationOk extends CompilationResult {
+  final Uint8List binary;
+
+  CompilationOk(this.binary);
+
+  List toResponse() => [STATUS_OK, binary];
+
+  String toString() => "CompilationOk(${binary.length} bytes)";
+}
+
+abstract class CompilationFail extends CompilationResult {
+  String get errorString;
+
+  Map<String, dynamic> toJson();
+
+  static CompilationFail fromJson(Map m) {
+    switch (m['status']) {
+      case STATUS_ERROR:
+        return new CompilationError(m['errors']);
+      case STATUS_CRASH:
+        return new CompilationCrash(m['exception'], m['stack']);
+      default:
+        throw "Can't deserialize CompilationFail from ${m}.";
+    }
+  }
+}
+
+class CompilationError extends CompilationFail {
+  final List<String> errors;
+
+  CompilationError(this.errors);
+
+  List toResponse() => [STATUS_ERROR, errorString];
+
+  Map<String, dynamic> toJson() => {
+        "status": STATUS_ERROR,
+        "errors": errors,
+      };
+
+  String get errorString => errors.take(10).join('\n');
+
+  String toString() => "CompilationError(${errorString})";
+}
+
+class CompilationCrash extends CompilationFail {
+  final String exception;
+  final String stack;
+
+  CompilationCrash(this.exception, this.stack);
+
+  List toResponse() => [STATUS_CRASH, errorString];
+
+  Map<String, dynamic> toJson() => {
+        "status": STATUS_CRASH,
+        "exception": exception,
+        "stack": stack,
+      };
+
+  String get errorString => "${exception}\n${stack}";
+
+  String toString() => "CompilationCrash(${errorString})";
+}
+
+Future<CompilationResult> parseScriptImpl(DartLoaderBatch batch_loader,
+    Uri fileName, String packageConfig, String sdkPath) async {
+  if (!FileSystemEntity.isFileSync(fileName.path)) {
+    throw "Input file '${fileName.path}' does not exist.";
+  }
+
+  if (!FileSystemEntity.isDirectorySync(sdkPath)) {
+    throw "Patched sdk directory not found at $sdkPath";
+  }
+
+  Target target = getTarget("vm", new TargetFlags(strongMode: false));
+
+  Program program;
+  if (useFasta) {
+    final uriTranslator = await TranslateUri.parse(new Uri.file(packageConfig));
+    final Ticker ticker = new Ticker(isVerbose: verbose);
+    final DillTarget dillTarget = new DillTarget(ticker, uriTranslator);
+    dillTarget.read(new Uri.directory(sdkPath).resolve('platform.dill'));
+    final KernelTarget kernelTarget =
+        new KernelTarget(dillTarget, uriTranslator);
+    try {
+      kernelTarget.read(fileName);
+      await dillTarget.writeOutline(null);
+      program = await kernelTarget.writeOutline(null);
+      program = await kernelTarget.writeProgram(null, AstKind.Kernel);
+      if (kernelTarget.errors.isNotEmpty) {
+        return new CompilationError(kernelTarget.errors
+            .map((err) => err.toString())
+            .toList(growable: false));
+      }
+    } on InputError catch (e) {
+      return new CompilationError(<String>[e.error]);
+    }
+  } else {
+    DartOptions dartOptions = new DartOptions(
+        strongMode: false,
+        strongModeSdk: false,
+        sdk: sdkPath,
+        packagePath: packageConfig,
+        customUriMappings: const {},
+        declaredVariables: const {});
+    DartLoader loader =
+        await batch_loader.getLoader(new Repository(), dartOptions);
+    program = loader.loadProgram(fileName, target: target);
+
+    if (loader.errors.isNotEmpty) {
+      return new CompilationError(loader.errors.toList(growable: false));
+    }
+  }
+
+  // Perform target-specific transformations.
+  target.performModularTransformations(program);
+  target.performGlobalTransformations(program);
+
+  // Write the program to a list of bytes and return it.
+  var sink = new DataSink();
+  new BinaryPrinter(sink).writeProgramFile(program);
+  return new CompilationOk(sink.builder.takeBytes());
+}
+
+Future<CompilationResult> parseScript(DartLoaderBatch loader, Uri fileName,
+    String packageConfig, String sdkPath) async {
+  try {
+    return await parseScriptImpl(loader, fileName, packageConfig, sdkPath);
+  } catch (err, stack) {
+    return new CompilationCrash(err.toString(), stack.toString());
+  }
+}
+
+Future _processLoadRequestImpl(String inputFileUrl) async {
+  Uri scriptUri = Uri.parse(inputFileUrl);
+
+  // Because we serve both Loader and bootstrapping requests we need to
+  // duplicate the logic from _resolveScriptUri(...) here and attempt to
+  // resolve schemaless uris using current working directory.
+  if (scriptUri.scheme == '') {
+    // Script does not have a scheme, assume that it is a path,
+    // resolve it against the working directory.
+    scriptUri = Directory.current.uri.resolveUri(scriptUri);
+  }
+
+  if (scriptUri.scheme != 'file') {
+    // TODO: reuse loader code to support other schemes.
+    throw "Expected 'file' scheme for a script uri: got ${scriptUri.scheme}";
+  }
+
+  final Uri packagesUri = (Platform.packageConfig != null)
+      ? Uri.parse(Platform.packageConfig)
+      : await _findPackagesFile(scriptUri);
+  if (packagesUri == null) {
+    throw "Could not find .packages";
+  }
+
+  final Uri patchedSdk =
+      Uri.parse(Platform.resolvedExecutable).resolve("patched_sdk");
+
+  if (verbose) {
+    print("""DFE: Requesting compilation {
+  scriptUri: ${scriptUri}
+  packagesUri: ${packagesUri}
+  patchedSdk: ${patchedSdk}
+}""");
+  }
+
+  if (workerPort != 0) {
+    return await requestParse(scriptUri, packagesUri, patchedSdk);
+  } else {
+    return await parseScript(
+        new DartLoaderBatch(), scriptUri, packagesUri.path, patchedSdk.path);
+  }
+}
+
+// Process a request from the runtime. See KernelIsolate::CompileToKernel in
+// kernel_isolate.cc and Loader::SendKernelRequest in loader.cc.
+Future _processLoadRequest(request) async {
+  if (verbose) {
+    print("DFE: request: $request");
+    print("DFE: Platform.packageConfig: ${Platform.packageConfig}");
+    print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}");
+  }
+
+  final int tag = request[0];
+  final SendPort port = request[1];
+  final String inputFileUrl = request[2];
+
+  var result;
+  try {
+    result = await _processLoadRequestImpl(inputFileUrl);
+  } catch (error, stack) {
+    result = new CompilationCrash(error.toString(), stack.toString());
+  }
+
+  if (verbose) {
+    print("DFE:> ${result}");
+  }
+
+  // Check whether this is a Loader request or a bootstrapping request from
+  // KernelIsolate::CompileToKernel.
+  final isBootstrapRequest = tag == null;
+  if (isBootstrapRequest) {
+    port.send(result.toResponse());
+  } else {
+    // See loader.cc for the code that handles these replies.
+    if (result is CompilationOk) {
+      port.send([tag, inputFileUrl, inputFileUrl, null, result]);
+    } else {
+      port.send([-tag, inputFileUrl, inputFileUrl, null, result.errorString]);
+    }
+  }
+}
+
+Future<CompilationResult> requestParse(
+    Uri scriptUri, Uri packagesUri, Uri patchedSdk) async {
+  if (verbose) {
+    print(
+        "DFE: forwarding request to worker at http://localhost:${workerPort}/");
+  }
+
+  HttpClient client = new HttpClient();
+  final rq = await client
+      .postUrl(new Uri(host: 'localhost', port: workerPort, scheme: 'http'));
+  rq.headers.contentType = ContentType.JSON;
+  rq.write(JSON.encode({
+    "inputFileUrl": scriptUri.toString(),
+    "packagesUri": packagesUri.toString(),
+    "patchedSdk": patchedSdk.toString(),
+  }));
+  final rs = await rq.close();
+  try {
+    if (rs.statusCode == HttpStatus.OK) {
+      final BytesBuilder bb = new BytesBuilder();
+      await rs.forEach(bb.add);
+      return new CompilationOk(bb.takeBytes());
+    } else {
+      return CompilationFail.fromJson(JSON.decode(await UTF8.decodeStream(rs)));
+    }
+  } finally {
+    await client.close();
+  }
+}
+
+void startBatchServer() {
+  final loader = new DartLoaderBatch();
+  HttpServer.bind('localhost', workerPort).then((server) {
+    print('READY ${server.port}');
+    server.listen((HttpRequest request) async {
+      final rq = JSON.decode(await UTF8.decodeStream(request));
+
+      final Uri scriptUri = Uri.parse(rq['inputFileUrl']);
+      final Uri packagesUri = Uri.parse(rq['packagesUri']);
+      final Uri patchedSdk = Uri.parse(rq['patchedSdk']);
+
+      final CompilationResult result = await parseScript(
+          loader, scriptUri, packagesUri.path, patchedSdk.path);
+
+      if (result is CompilationOk) {
+        request.response.statusCode = HttpStatus.OK;
+        request.response.headers.contentType = ContentType.BINARY;
+        request.response.add(result.binary);
+        request.response.close();
+      } else {
+        request.response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
+        request.response.headers.contentType = ContentType.TEXT;
+        request.response.write(JSON.encode(result));
+        request.response.close();
+      }
+    });
+    ProcessSignal.SIGTERM.watch().first.then((_) => server.close());
+  });
+}
+
+train(String scriptUri) {
+  // TODO(28532): Enable on Windows.
+  if (Platform.isWindows) return;
+
+  var tag = 1;
+  var responsePort = new RawReceivePort();
+  responsePort.handler = (response) {
+    if (response[0] == tag) {
+      // Success.
+      responsePort.close();
+    } else if (response[0] == -tag) {
+      // Compilation error.
+      throw response[4];
+    } else {
+      throw "Unexpected response: $response";
+    }
+  };
+  var request = [tag, responsePort.sendPort, scriptUri];
+  _processLoadRequest(request);
+}
+
+main([args]) {
+  if (args?.length == 1 && args[0] == '--batch') {
+    startBatchServer();
+  } else if (args?.length == 2 && args[0] == '--train') {
+    // This entry point is used when creating an app snapshot. The argument
+    // provides a script to compile to warm-up generated code.
+    train(args[1]);
+  } else {
+    // Entry point for the Kernel isolate.
+    return new RawReceivePort()..handler = _processLoadRequest;
+  }
+}
+
+// This duplicates functionality from the Loader which we can't easily
+// access from here.
+Future<Uri> _findPackagesFile(Uri base) async {
+  var dir = new File.fromUri(base).parent;
+  while (true) {
+    final packagesFile = dir.uri.resolve(".packages");
+    if (await new File.fromUri(packagesFile).exists()) {
+      return packagesFile;
+    }
+    if (dir.parent.path == dir.path) {
+      break;
+    }
+    dir = dir.parent;
+  }
+  return null;
+}