Version 2.1.1-dev.2.0

Merge commit 'd9944433af2fa90899a1787d48f7e64eb2f129e8' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 165e23f..910c41c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,60 @@
+## 2.1.1-dev.2.0
+
+### Core library changes
+
+#### `dart:core`
+
+*   Made `DateTime.parse()` also recognize `,` as a valid decimal separator
+    when parsing from a string. (Issue [35576][])
+
+[35576]: https://github.com/dart-lang/sdk/issues/35576
+
+### Tool Changes
+
+#### Analyzer
+
+*   New hints added:
+
+    *   `NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR` and
+        `NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW` when a `@literal`
+        const constructor is called in a non-const context (or with `new`).
+
+#### dart2js
+
+* `--fast-startup` is forced on.  The flag is silently ignored and will be
+  deprecated and then removed at a later date.
+
+  The alternative 'full emitter' is no longer available. The generated code for
+  `--fast-startup` is optimized to load faster, even though it can be slightly
+  larger.
+
 ## 2.1.1-dev.1.0
 
+### Dart VM
+
+In previous releases it was possible to violate static types using dart:mirrors but this bug is fixed now. Meaning that the code below would run without any TypeErrors and print "impossible" output.
+
+```dart
+import 'dart:mirrors';
+
+class A {
+  void method(int v) {
+    if (v != null && v is! int) {
+      print("This should be impossible: expected null or int got ${v}");
+    }
+  }
+}
+
+void main() {
+  final obj = A();
+  reflect(obj).invoke(#method, ['not-an-number']);
+}
+```
+
+Only code that already violates static typing will break.
+
+See Issue [#35611](https://github.com/dart-lang/sdk/issues/35611) for more details.
+
 ### Tool Changes
 
 #### Analyzer
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 88ffd12..80cdf8e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -11,7 +11,7 @@
       click that icon to report a bug on the page.
     * To report an API doc bug,
       [create an SDK issue](https://github.com/dart-lang/sdk/issues/new?title=API%20doc%20issue:).
-  * Contribute to the Dart developer websites such as [www.dartlang.org](https://www.dartlang.org) (repo: [dart-lang/site-www](https://github.com/dart-lang/site-www)) and [webdev.dartlang.org](https://webdev.dartlang.org) (repo: [dart-lang/site-webdev](https://github.com/dart-lang/site-webdev)). For more information, see [Writing for *.dartlang.org](https://github.com/dart-lang/site-www/wiki/Writing-for-dartlang.org).
+  * Contribute to the Dart developer websites such as [www.dartlang.org](https://www.dartlang.org) (repo: [dart-lang/site-www](https://github.com/dart-lang/site-www)) and [webdev.dartlang.org](https://webdev.dartlang.org) (repo: [dart-lang/site-webdev](https://github.com/dart-lang/site-webdev)). For more information, see [Writing for Dart and Flutter websites](https://github.com/dart-lang/site-shared/wiki/Writing-for-Dart-and-Flutter-websites).
   * Improve the API reference docs at [api.dartlang.org](https://api.dartlang.org) by editing doc comments in the [Dart SDK repo](https://github.com/dart-lang/sdk/tree/master/sdk/lib). For more information on how to write API docs, see [Effective Dart: Documentation](https://www.dartlang.org/guides/language/effective-dart/documentation).
 
 ## Before you contribute
diff --git a/DEPS b/DEPS
index 2798d2c..f44b9ec 100644
--- a/DEPS
+++ b/DEPS
@@ -161,7 +161,7 @@
       "packages": [
           {
               "package": "dart/dart-sdk/${{platform}}",
-              "version": "version:2.1.1-dev.0.1",
+              "version": "version:2.1.1-dev.1.0",
           },
       ],
       "dep_type": "cipd",
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 57b7bfa..f7291e8 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -168,15 +168,40 @@
         'DEPS file must have only dependencies from allowed hosts.',
         long_text=error.output)]
 
+def _CheckLayering(input_api, output_api):
+  """Run VM layering check.
+
+  This check validates that sources from one layer do not reference sources
+  from another layer accidentally.
+  """
+  # Run only if .cc or .h file was modified.
+  def is_cpp_file(path):
+    return path.endswith('.cc') or path.endswith('.h')
+  if all(not is_cpp_file(f.LocalPath()) for f in input_api.AffectedFiles()):
+    return []
+
+  local_root = input_api.change.RepositoryRoot()
+  layering_check = imp.load_source('layering_check',
+      os.path.join(local_root, 'runtime', 'tools', 'layering_check.py'))
+  errors = layering_check.DoCheck(local_root)
+  if errors:
+    return [output_api.PresubmitError(
+        'Layering check violation for C++ sources.',
+        long_text='\n'.join(errors))]
+  else:
+    return []
+
 
 def CheckChangeOnCommit(input_api, output_api):
   return (_CheckValidHostsInDEPS(input_api, output_api) +
           _CheckBuildStatus(input_api, output_api) +
           _CheckDartFormat(input_api, output_api) +
-          _CheckStatusFiles(input_api, output_api))
+          _CheckStatusFiles(input_api, output_api) +
+          _CheckLayering(input_api, output_api))
 
 
 def CheckChangeOnUpload(input_api, output_api):
   return (_CheckValidHostsInDEPS(input_api, output_api) +
           _CheckDartFormat(input_api, output_api) +
-          _CheckStatusFiles(input_api, output_api))
+          _CheckStatusFiles(input_api, output_api) +
+          _CheckLayering(input_api, output_api))
diff --git a/docs/language/Makefile b/docs/language/Makefile
index aecfd61..1bdd95a 100644
--- a/docs/language/Makefile
+++ b/docs/language/Makefile
@@ -39,7 +39,7 @@
 	@echo "  clean: remove all generated files"
 
 cleanish:
-	rm -f *.aux *.log *.toc *.out *.idx *.ilg
+	rm -f *.aux *.log *.toc *.out
 
 clean: cleanish
-	rm -f *.dvi *.pdf *.ind $(HASH) $(LIST)
+	rm -f *.dvi *.pdf $(HASH) $(LIST)
diff --git a/docs/language/dart.sty b/docs/language/dart.sty
index 27433a7..0776ec0 100644
--- a/docs/language/dart.sty
+++ b/docs/language/dart.sty
@@ -184,7 +184,7 @@
   {#1}_1\FunctionTypeExtends{#2}_1,\,\ldots,\ %
   {#1}_{#3}\FunctionTypeExtends{#2}_{#3}}}
 
-% Used to specify function types: Same syntax as in source.
+% Used to specify non-generic function types: Same syntax as in source.
 % Arguments: Return type, formal parameter declarations.
 \newcommand{\FunctionTypeSimple}[2]{\code{\ensuremath{#1}\ \FUNCTION({#2})}}
 
@@ -199,33 +199,51 @@
 \newcommand{\RawFunctionType}[5]{\code{%
   \ensuremath{#1}\ \FUNCTION<\FTTypeParameters{#2}{#3}{#4}>({#5})}}
 
+% Used to specify function type parameter lists with positional optionals.
+% Arguments: Parameter type, number of required parameters,
+% number of optional parameters.
+\newcommand{\FunctionTypePositionalArguments}[3]{%
+  \List{#1}{1}{#2},\ [\List{#1}{{#2}+1}{{#2}+{#3}}]}
+
+\newcommand{\FunctionTypePositionalArgumentsStd}{%
+  \FunctionTypePositionalArguments{T}{n}{k}}
+
 % Used to specify function types with positional optionals:
 % Arguments: Return type, spacer, type parameter name, bound name,
 %   number of type parameters, parameter type, number of required parameters,
 %   number of optional parameters.
 \newcommand{\FunctionTypePositional}[8]{%
-  \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7},\ %
-    [\List{#6}{{#7}+1}{{#7}+{#8}}]}}
+  \FunctionType{#1}{#2}{#3}{#4}{#5}{%
+    \FunctionTypePositionalArguments{#6}{#7}{#8}}}
 
 % Same as \FunctionTypePositional except suitable for inline usage,
 % hence omitting the spacer argument.
 \newcommand{\RawFunctionTypePositional}[7]{%
-  \RawFunctionType{#1}{#2}{#3}{#4}{\List{#5}{1}{#6},\ %
-    [\List{#5}{{#6}+1}{{#6}+{#7}}]}}
+  \RawFunctionType{#1}{#2}{#3}{#4}{%
+    \FunctionTypePositionalArguments{#5}{#6}{#7}}}
+
+% Used to specify function type parameter lists with named optionals.
+% Arguments: Parameter type, number of required parameters,
+% name of optional parameters, number of optional parameters.
+\newcommand{\FunctionTypeNamedArguments}[4]{%
+  \List{#1}{1}{#2},\ \{\PairList{#1}{#3}{{#2}+1}{{#2}+{#4}}\}}
+  
+\newcommand{\FunctionTypeNamedArgumentsStd}{%
+  \FunctionTypeNamedArguments{T}{n}{x}{k}}
 
 % Used to specify function types with named parameters:
 % Arguments: Return type, spacer, type parameter name, bound name,
 %   number of type parameters, parameter type, number of required parameters,
 %   name of optional parameters, number of optional parameters.
 \newcommand{\FunctionTypeNamed}[9]{%
-  \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7},\ %
-    \{\PairList{#6}{#8}{{#7}+1}{{#7}+{#9}}\}}}
+  \FunctionType{#1}{#2}{#3}{#4}{#5}{%
+    \FunctionTypePositionalArguments{#6}{#7}{#8}{#9}}}
 
 % Same as \FunctionType except suitable for inline usage, hence omitting
 % the spacer argument.
 \newcommand{\RawFunctionTypeNamed}[8]{%
-  \RawFunctionType{#1}{#2}{#3}{#4}{\List{#5}{1}{#6},\ %
-    \{\PairList{#5}{#7}{{#6}+1}{{#6}+{#8}}\}}}
+  \RawFunctionType{#1}{#2}{#3}{#4}{%
+    \FunctionTypePositionalArguments{#5}{#6}{#7}{#8}}}
 
 % Used to specify function types with no optional parameters:
 % Arguments: Return type, spacer, type parameter name, bound name,
@@ -237,9 +255,15 @@
 \newcommand{\FunctionTypePositionalStd}[1]{%
   \FunctionTypePositional{#1}{ }{X}{B}{s}{T}{n}{k}}
 
+\newcommand{\RawFunctionTypePositionalStd}[1]{%
+  \RawFunctionTypePositional{#1}{X}{B}{s}{T}{n}{k}}
+
 \newcommand{\FunctionTypeNamedStd}[1]{%
   \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}}
 
+\newcommand{\RawFunctionTypeNamedStd}[1]{%
+  \RawFunctionTypeNamed{#1}{X}{B}{s}{T}{n}{x}{k}}
+
 \newcommand{\FunctionTypeAllRequiredStd}[1]{%
   \FunctionTypeAllRequired{#1}{ }{X}{B}{s}{T}{n}}
 
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index a781f90..2202ec5 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -32,6 +32,10 @@
 % - Specify that a getter/setter and a method with the same basename is
 %   an error, also in the case where a class obtains both from its
 %   superinterfaces.
+% - Specify the Dart 2.0 rule that you cannot implement, extend or mix-in
+%   Function.
+% - Generalize specification of type aliases such that they can denote any
+%   type, not just function types.
 %
 % 2.1
 % - Remove 64-bit constraint on integer literals compiled to JavaScript numbers.
@@ -3440,12 +3444,20 @@
 
 \LMHash{}%
 It is a compile-time error if the type in the \EXTENDS{} clause of a class $C$ is
-a type variable (\ref{generics}), a type alias (\ref{typedef}),
+a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}),
 an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
 a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
 or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
 
-\commentary{
+\commentary{%
+Note that \VOID{} is a reserved word,
+which implies that the same restrictions apply for the type \VOID,
+and similar restrictions are specified for other types like
+\code{Null} (\ref{null}) and
+\code{String} (\ref{strings}).%
+}
+
+\commentary{%
 The type parameters of a generic class are available in the lexical scope of the superclass clause, potentially shadowing classes in the surrounding scope.
 The following code is therefore illegal and should cause a compile-time error:
 }
@@ -3622,7 +3634,7 @@
 
 \LMHash{}%
 It is a compile-time error if an element in the type list of the \IMPLEMENTS{} clause of a class $C$ is
-a type variable (\ref{generics}), a type alias (\ref{typedef}),
+a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}),
 an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
 a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
 or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
@@ -4194,7 +4206,7 @@
   $p'$ is the parameter of $m'$ corresponding to $p$,
   $p$ has default value $d$ and $p'$ has default value $d'$,
   then $d$ and $d'$ must be identical,
-  or a compile-time warning occurs.
+  or a static warning occurs.
 \item
   If $m$ and $m'$ are both getters:
   The return type of $m$ must be a subtype of the return type of $m'$.
@@ -4229,7 +4241,7 @@
 The mixin application may be used to extend a class per section \ref{classes};
 alternatively, a class may be defined as a mixin application as described in this section.
 It is a compile-time error if an element in the type list of the \WITH{} clause of a mixin application is
-a type variable (\ref{generics}), a type alias (\ref{typedef}),
+a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}),
 an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
 a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
 or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
@@ -4319,6 +4331,14 @@
 It is a compile-time error if $M$ (respectively, any of $M_1, \ldots, M_k$) is an enumerated type (\ref{enums}) or a malformed type.
 It is a compile-time error if a well formed mixin cannot be derived from $M$ (respectively, from each of $M_1, \ldots, M_k$).
 
+\commentary{%
+Note that \VOID{} is a reserved word,
+which implies that the same restrictions apply for the type \VOID,
+and similar restrictions are specified for other types like
+\code{Null} (\ref{null}) and
+\code{String} (\ref{strings}).%
+}
+
 \LMHash{}%
 Let $K$ be a class declaration with the same constructors, superclass and interfaces as $C$, and the instance members declared by $M$ (respectively $M_1, \ldots, M_k$).
 It is a compile-time error if the declaration of $K$ would cause a compile-time error.
@@ -4457,9 +4477,9 @@
 introduces a generic class into the enclosing library scope.
 A \IndexCustom{generic class}{class!generic}
 is a mapping that accepts a list of actual type arguments and maps them to a class.
-Consider a generic class declaration $G$ named \code{C} with formal type parameter declarations
+Consider a generic class declaration $G$ named $C$ with formal type parameter declarations
 $X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$,
-and a parameterized type $T$ of the form \code{C<$T_1, \ldots,\ T_l$>}.
+and a parameterized type $T$ of the form \code{$C$<$T_1, \ldots,\ T_l$>}.
 
 \LMHash{}%
 It is a compile-time error if $m \not= l$.
@@ -4467,8 +4487,8 @@
 (\ref{superBoundedTypes}).
 
 \LMHash{}%
-Otherwise, said parameterized type \code{C<$T_1, \ldots,\ T_m$>} denotes an application of the generic class declared by $G$ to the type arguments $T_1, \ldots, T_m$.
-This yields a class $C'$ whose members are equivalent to those of a class declaration which is obtained from the declaration of $G$ by replacing each occurrence of $X_j$ by $T_j$.
+Otherwise, said parameterized type \code{$C$<$T_1, \ldots,\ T_m$>} denotes an application of the generic class declared by $G$ to the type arguments $T_1, \ldots, T_m$.
+This yields a class $C'$ whose members are equivalent to those of a class declaration which is obtained from the declaration $G$ by replacing each occurrence of $X_j$ by $T_j$.
 \commentary{
 
 % TODO(eernst): make sure this list of properties is complete.
@@ -4478,47 +4498,76 @@
 
 \LMHash{}%
 A \IndexCustom{generic type alias}{type alias!generic}
-introduces a mapping from actual type argument lists to types.
-Consider a generic type alias declaration $G$ named \code{F}
-with formal type parameter declarations
-$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$,
-%% TODO(eernst): 'right hand side' works only for a type alias using `=`.
-%% Explain what "the right hand side" means for an old-style declaration.
-and right hand side $T$.
+is a declaration $D$ of one of the following forms:
+
+\begin{itemize}
+\item \code{$m$ \TYPEDEF{} \id<\TypeParametersStd> = $T$;}
+\item \code{$m$ \TYPEDEF{} $S$?\ \id<\TypeParametersStd>(\\
+  \mbox\quad\PairList{T}{p}{1}{n},\ [\PairList{T}{p}{n+1}{n+k}]);}
+\item \code{$m$ \TYPEDEF{} $S$?\ \id<\TypeParametersStd>(\\
+  \mbox\quad\PairList{T}{p}{1}{n},\ \{\PairList{T}{p}{n+1}{n+k}\});}
+\end{itemize}
+
+\noindent
+where $m$ is derived from \synt{metadata},
+$T$ is a type,
+and \code{$S$?} is a type or the empty string.
+Let $S'$ be \code{$S$?} if it is a type, otherwise let $S'$ be \DYNAMIC.
+The associated function type of $D$, call it $F$, is, respectively:
+
+\begin{itemize}
+\item $T$
+\item \FunctionTypeSimple{S'}{\FunctionTypePositionalArgumentsStd}
+\item \FunctionTypeSimple{S'}{\FunctionTypeNamedArgumentsStd}
+\end{itemize}
 
 \LMHash{}%
-Under the assumption that $X_1,\ \ldots,\ X_m$ are types such that
-$X_j <: B_j$, for all $j \in 1 .. m$,
-it is a compile-time error if any type in $T$ is not regular-bounded.
+$D$ introduces a mapping from actual type argument lists to types.
+Under the assumption that \List{X}{1}{s} are types such that
+$X_j <: B_j$, for all $j \in 1 .. s$,
+it is a compile-time error if $T$ is not regular-bounded,
+and it is a compile-time error if any type occurring in $T$ is not well-bounded.
 
 \commentary{
 This means that the bounds declared for
 the formal type parameters of a generic type alias
 must be such that when they are satisfied,
-the bounds that pertain to any type in the body must also be satisfied.
+the bounds that pertain to the body are also satisfied,
+and a type occurring as a subterm of the body can violate its bounds,
+but only if it is a correct super-bounded type.
 }
 
 \LMHash{}%
-Let $G$, \code{F}, and $X_1,\ \ldots,\ X_m$ be as defined above,
-let $T_1,\ \ldots,\ T_l$ be types,
-and let $S$ be the parameterized type \code{F<$T_1, \ldots,\ T_l$>}.
-It is a compile-time error if $m \not= l$.
-It is a compile-time error if $S$ is not well-bounded
+Moreover,
+let $T_1,\ \ldots,\ T_l$ be types
+and let $U$ be the parameterized type \code{\id<$T_1, \ldots,\ T_l$>}
+in a location where \id{} denotes $D$.
+It is a compile-time error if $l \not= s$.
+It is a compile-time error if $U$ is not well-bounded
 (\ref{superBoundedTypes}).
 
 \LMHash{}%
-Otherwise, said parameterized type
-\code{F<$T_1, \ldots,\ T_m$>}
-denotes an application of the mapping denoted by $G$ to the type arguments
-$T_1, \ldots, T_m$.
-This yields the type
-$[T_1/X_1, \ldots, T_m/X_m]T$.
+Otherwise,
+$U$ denotes an application of the mapping denoted by $D$ to the type arguments
+$T_1, \ldots, T_s$,
+yielding the type
+$[T_1/X_1, \ldots, T_s/X_s]F$.
+
+\commentary{%
+Note that the type alias syntax without \syntax{`='}
+can only express function types,
+and it cannot express the type of a generic function.
+When such a type alias is generic,
+it always expresses a family of non-generic function types.
+These restrictions exist because that syntax was defined
+before generic functions were added to Dart.%
+}
 
 \rationale{
 The requirement that satisfaction of the bounds on
-the formal type parameters of a generic type alias $G$
+the formal type parameters of a generic type alias $D$
 must imply satisfaction of all bounds pertaining to
-every type that occurs in the body of $G$
+every type that occurs in the body of $D$
 limits the expressive power of generic type aliases.
 However, it would require the constraints on formal type parameters
 to be expressed in a much more powerful language
@@ -7170,7 +7219,8 @@
 a class or a parameterized type accessible in the current scope,
 or if $T$ is a parameterized type which is not a class.
 \commentary{
-For instance, \code{\NEW{} F<int>()} is an error if \code{F} is a type alias.
+For instance, \code{\NEW{} F<int>()} is an error if \code{F} is a type alias
+that does not denote a class.
 }
 
 \LMHash{}%
@@ -8799,7 +8849,7 @@
 Let $T$ be the static type of $e$.
 It is a compile-time error if $T$ does not have a method or getter named \id{}
 unless $T$ is \DYNAMIC{},
-or $T$ is \FUNCTION{} and \id{} is \code{call}.
+or $T$ is \FUNCTION{} and \id{} is \CALL{}.
 The static type of $i$ is:
 
 \begin{itemize}
@@ -11427,7 +11477,7 @@
 \end{itemize}
 
 \commentary{
-In other words, a warning will be emitted if a switch statement over an enum is not exhaustive.
+In other words, a static warning will be emitted if a switch statement over an enum is not exhaustive.
 }
 
 
@@ -12773,29 +12823,94 @@
 \LMLabel{staticTypes}
 
 \LMHash{}%
-Type annotations are used in variable declarations (\ref{variables}) (including formal parameters (\ref{formalParameters})), in the return types of functions (\ref{functions}) and in the bounds of type variables.
+Type annotations can occur in variable declarations (\ref{variables}),
+including formal parameters (\ref{formalParameters}),
+in the return types of functions (\ref{functions}),
+and in the bounds of type variables (\ref{generics}).
 Type annotations are used during static checking and when running programs.
+Types are specified using the following grammar rules.
+
+%% TODO(eernst): The following non-terminal is currently undefined (it will
+%% be defined when more rules are transferred from Dart.g): <typeIdentifier>.
+%% The precise rules are slightly different than the following sentence, but
+%% we should be able to make do with that for now.
+\LMHash{}%
+In the grammar rules below, \synt{typeIdentifier} denotes an identifier which can be
+the name of a type, that is, it denotes an \synt{IDENTIFIER} which is not a
+\synt{BUILT\_IN\_IDENTIFIER}.
+
+%% TODO(eernst): The following non-terminals are currently unused (they will
+%% be used when we transfer more grammar rules from Dart.g): <typeNotVoid>
+%% and <typeNotVoidNotFunctionList>. They are used in the syntax for
+%% \EXTENDS{}, \WITH{}, \IMPLEMENTS{} syntax and for mixin applications
+%% in Dart.g, and it seems likely that we will use them here as well.
+
+\commentary{
+Non-terminals with names of the form \synt{\ldots{}NotFunction}
+derive terms which are types that are not function types.
+Note that it \emph{does} derive the type \FUNCTION{},
+which is not itself a function type,
+but it is the least upper bound of all function types.
+}
 
 \begin{grammar}
-<type> ::= <typeNotVoid> | \VOID{}
+<type> ::= <functionTypeTails>
+  \alt <typeNotFunction> <functionTypeTails>
+  \alt <typeNotFunction>
 
-<typeNotVoid> ::= <typeName> <typeArguments>?
+<typeNotFunction> ::= <typeNotVoidNotFunction>
+  \alt \VOID{}
 
-<typeName> ::= <qualified>
+<typeNotVoidNotFunction> ::= <typeName> <typeArguments>?
+  \alt \FUNCTION{}
+
+<typeName> ::= <typeIdentifier> (`.' <typeIdentifier>)?
 
 <typeArguments> ::= `<' <typeList> `>'
 
 <typeList> ::= <type> (`,' <type>)*
+
+<typeNotVoidNotFunctionList> ::=
+  <typeNotVoidNotFunction> (`,' <typeNotVoidNotFunction>)*
+
+<typeNotVoid> ::= <functionType>
+  \alt <typeNotVoidNotFunction>
+
+<functionType> ::= <functionTypeTails>
+  \alt <typeNotFunction> <functionTypeTails>
+
+<functionTypeTails> ::= <functionTypeTail> <functionTypeTails>
+  \alt <functionTypeTail>
+
+<functionTypeTail> ::= \FUNCTION{} <typeParameters>? <parameterTypeList>
+
+<parameterTypeList> ::= `(' `)'
+  \alt `(' <normalParameterTypes> `,' <optionalParameterTypes> `)'
+  \alt `(' <normalParameterTypes> `,'? `)'
+  \alt `(' <optionalParameterTypes> `)'
+
+<normalParameterTypes> ::= <normalParameterType> (`,' <normalParameterType>)*
+
+<normalParameterType> ::= <typedIdentifier>
+  \alt <type>
+
+<optionalParameterTypes> ::= <optionalPositionalParameterTypes>
+  \alt <namedParameterTypes>
+
+<optionalPositionalParameterTypes> ::= `[' <normalParameterTypes> `,'? `]'
+
+<namedParameterTypes> ::=
+  `\{' <typedIdentifier> (`,' <typedIdentifier>)* `,'? `\}'
+
+<typedIdentifier> ::= <type> <identifier>
 \end{grammar}
 
 \LMHash{}%
-A Dart implementation must provide a static checker that detects and reports exactly those situations this specification identifies as compile-time errors,
+A Dart implementation must provide a static checker that detects and reports
+exactly those situations this specification identifies as compile-time errors,
 and only those situations.
-However:
-\begin{itemize}
-\item Running the static checker on a program $P$ is not required for compiling and running $P$.
-\item Running the static checker on a program $P$ must not prevent successful compilation of $P$ nor may it prevent the execution of $P$, regardless of whether any compile-time errors occur.
-\end{itemize}
+Similarly, the static checker must emit static warnings
+for at least the situations specified as such in this specification.
 
 \commentary{
 Nothing precludes additional tools that implement alternative static analyses (e.g., interpreting the existing type annotations in a sound manner such as either non-variant generics, or inferring declaration based variance from the actual declarations).
@@ -12956,7 +13071,7 @@
 \}
 \end{dartCode}
 
-\LMHash{}
+\LMHash{}%
 \commentary{
 Instances of \code{Type} can be obtained in various ways,
 for example by using reflection,
@@ -12964,7 +13079,7 @@
 or by evaluating a \emph{type literal} expression.
 }
 
-\LMHash{}
+\LMHash{}%
 An expression is a \emph{type literal} if it is an identifier,
 or a qualified identifier,
 which denotes a class, mixin or type alias declaration, or it is
@@ -12975,53 +13090,126 @@
 A constant type literal is a constant expression (\ref{constants}).
 }
 
-\subsection{Type Declarations}
-\LMLabel{typeDeclarations}
-
-
-\subsubsection{Typedef}
+\subsection{Type Aliases}
 \LMLabel{typedef}
 
 \LMHash{}%
 A \Index{type alias} declares a name for a type expression.
 
+\commentary{
+It is common to use the phrase ``a typedef'' for such a declaration,
+because of the prominent occurrence of the token \TYPEDEF.
+}
+
+% TODO(eernst): We include <metadata> in <typeAlias> even though it is not
+% there in Dart.g, because <libraryDefinition> in Dart.g allows metadata
+% before every <topLevelDefinition>, but that's not yet been transferred to
+% this document. So we'll need to remove the <metadata> below _when_ it is
+% made redundant by changing <libraryDefinition> to be like in Dart.g.
+
 \begin{grammar}
-<typeAlias> ::= <metadata> \TYPEDEF{} <typeAliasBody>
+<typeAlias> ::=
+  <metadata> \TYPEDEF{} <typeIdentifier> <typeParameters>? `=' <type> `;'
+  \alt <metadata> \TYPEDEF{} <functionTypeAlias>
 
-<typeAliasBody> ::= <functionTypeAlias>
-
-<functionTypeAlias> ::= \gnewline{}
-  <functionPrefix> <typeParameters>? <formalParameterList> `;'
+<functionTypeAlias> ::= <functionPrefix> <formalParameterPart> `;'
 
 <functionPrefix> ::= <type>? <identifier>
 \end{grammar}
 
-% TODO(eernst): Introduce new type aliases and new function type syntax, then
-% include support for generic functions here.
+\LMHash{}%
+The effect of a type alias of the form
+\code{\TYPEDEF{} \id{} = $T$;}
+declared in a library $L$ is to introduce the name \id{} into the scope of $L$,
+bound to the type $T$.
 
 \LMHash{}%
 The effect of a type alias of the form
 
-\code{\TYPEDEF{} $T$ \id($T_1\ p_1, \ldots,\ T_n\ p_n,\ [T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}]$)}
+\noindent
+\code{\TYPEDEF{} $T$ \id($T_1\ p_1, \ldots,\ T_n\ p_n,\ [T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}]$);}
 
 \noindent
 declared in a library $L$ is to introduce the name \id{} into the scope of $L$, bound to the function type
-$(T_1, \ldots,\ T_n, [T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k} p_{n+k}]) \rightarrow T$.
+\FunctionTypeSimple{T}{\List{T}{1}{n},\ [\List{T}{n+1}{n+k}]}.
+
+\LMHash{}%
 The effect of a type alias of the form
 
-\code{\TYPEDEF{} $T$ \id($T_1\ p_1, \ldots,\ T_n\ p_n,\ \{T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}\}$)}
+\noindent
+\code{\TYPEDEF{} $T$ \id($T_1\ p_1, \ldots,\ T_n\ p_n,\ \{T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}\}$);}
 
 \noindent
 declared in a library $L$ is to introduce the name \id{} into the scope of $L$, bound to the function type
-$(T_1, \ldots,\ T_n, \{T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}\}) \rightarrow T$.
+\FunctionTypeSimple{T}{\List{T}{1}{n},\ \{\PairList{T}{p}{n+1}{n+k}\}}.
+
+\LMHash{}%
 In either case, if{}f no return type is specified, it is taken to be \DYNAMIC{}.
 Likewise, if a type annotation is omitted on a formal parameter, it is taken to be \DYNAMIC{}.
 
 \LMHash{}%
-It is a compile-time error if any default values are specified in the signature of a function type alias.
+It is a compile-time error if any default values are specified
+in the signature of a function type in a type alias.
 %A typedef may only refer to itself via the bounds of its generic parameters.
-Any self reference in a typedef, either directly, or recursively via another typedef, is a compile-time error.
-%via a chain of references that does not include a class declaration.
+Any self reference in a type alias,
+either directly or recursively via another type declaration,
+is a compile-time error.
+
+\commentary{
+This kind of error may also arise when type arguments have been
+omitted in the program, but are added during static analysis
+via instantiation to bound
+(\ref{instantiationToBound})
+or via type inference
+(\commentary{which will be specified later (\ref{overview})}).
+}
+
+\commentary{%
+A type alias can be used as a type annotation,
+as a return type or parameter type in a function declaration,
+in a function type,
+as a type argument,
+in a type test,
+in a type cast,
+and in an \ON{} clause of a \TRY{} statement.
+
+Consider the case where the body of a given type alias $F$
+is a \synt{typeName} that denotes a non-generic class,
+or it is a parameterized type that starts with
+a \synt{typeName} that denotes a generic class,
+or one of these cases occur indirectly via another type alias.
+In this case $F$ or a parameterized type that starts with $F$,
+whichever is not an error,
+can also be used to name a constructor in an instance creation expression
+(\ref{instanceCreation}),
+and it can be used as a superclass, mixin, or superinterface
+(\ref{superclasses}, \ref{superinterfaces}, \ref{mixinApplication}).
+Moreover, $F$ or a parameterized type that starts with $F$,
+whichever is not an error,
+can be used to invoke static methods of the denoted class.
+}
+
+\rationale{%
+This indirectly allows an invocation of a static method to pass
+a list of actual type arguments to the class.
+This is currently an error when it occurs directly
+(e.g., \code{List<int>.castFrom(xs)}).
+But it may be part of a future language extension to allow
+static methods to use the type parameters declared by the enclosing class,
+in which case both the direct and indirect approach will be allowed.
+At that time,
+existing invocations where type arguments are passed indirectly will not break,
+because it is currently an error for a static method to depend on the value
+of a formal type parameter of the enclosing class.
+}
+
+%% TODO(eernst): Move specification of generic type aliases to this
+%% section, change the non-generic case to a special case.
+\commentary{
+The generic variants of type alias declarations are specified
+in the section about generics
+(\ref{generics}).
+}
 
 
 \subsection{Subtypes}
@@ -13680,33 +13868,26 @@
 \subsection{Function Types}
 \LMLabel{functionTypes}
 
-%% TODO(eernst): This section is heavily updated in CL 81263 as well as
-%% in this CL 84027. Double-check the merge when 81263 has been landed.
-%% In particular, we do _not_ change the notation in this CL to use the
-%% function types that we use in section 'Subtypes', that's done in 81263.
-
 \LMHash{}%
 Function types come in two variants:
 \begin{enumerate}
 \item
-The types of functions that only have positional parameters.
-These have the general form
-
-\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
-
-\code{($T_1, \ldots,\ T_n,\ $[$T_{n+1}, \ldots,\ T_{n+k}$]) $ \rightarrow T$}.
+  The types of functions that only have positional parameters.
+  These have the general form
+  \FunctionTypePositionalStd{T}.
 \item
-The types of functions with named parameters.
-These have the general form
-
-\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
-
-\code{($T_1, \ldots,\ T_n,\ $\{$T_{x_1}\ x_1, \ldots,\ T_{x_k}\ x_k$\}) $ \rightarrow T$}.
+  The types of functions with named parameters.
+  These have the general form
+  \FunctionTypeNamedStd{T}.
 \end{enumerate}
 
 \commentary{
-Note that the non-generic case is covered by using $s = 0$,
-in which case the type parameter declarations are omitted (\ref{generics}).
+Note that the non-generic case is covered by having $s = 0$,
+in which case the type parameter declarations are omitted
+(\ref{generics}).
+The case with no optional parameters is covered by having $k = 0$;
+note that all rules involving function types of the two kinds
+coincide in this case.
 }
 
 \LMHash{}%
@@ -13722,13 +13903,49 @@
 }
 
 \LMHash{}%
-A function object is always an instance of some class that implements the class \FUNCTION{}.
+A function object is always an instance of some class that implements the class \FUNCTION{} (\ref{functionType}).
 \commentary{%
 Consequently, all function types are subtypes of \FUNCTION{}
 (\ref{subtypes}).
 }
 
 
+\subsection{Type \FUNCTION{}}
+\LMLabel{functionType}
+
+\LMHash{}%
+The built-in class \FUNCTION{} is a supertype of all function types
+(\ref{functionTypes}).
+It is impossible to extend, implement, or mix in the class \FUNCTION{}.
+
+\LMHash{}%
+If a class declaration or mixin application has \FUNCTION{} as superclass,
+it instead uses \code{Object} as superclass.
+
+\LMHash{}%
+If a class or mixin declaration implements \FUNCTION{}, it has no effect.
+It is as if the \FUNCTION was removed from the \code{implements} clause
+(and if it's the only implemented interface, the entire clause is removed).
+The resulting class or mixin interface
+does not have \FUNCTION{} as a superinterface.
+
+\LMHash{}%
+If a mixin application mixes \FUNCTION{} onto a superclass, it follows the
+normal rules for mixin-application, but since the result of that mixin
+application is equivalent to a class with \code{implements Function}, and
+that clause has no effect, the resulting class also does not
+implement \FUNCTION{}. \commentary{The \FUNCTION{} class declares no
+concrete instance members, so the mixin application creates a sub-class
+of the superclass with no new members and no new interfaces.}
+
+\rationale{Since using \FUNCTION{} in these ways has no effect, it would be
+reasonable to disallow it completely, like we do extending, implementing or
+mixing in types like \code{int} or \code{String}.
+For backwards compatibility with Dart 1 programs,
+the syntax is allowed to remain, even if it has no effect.
+Tools may choose to warn users that their code has no effect.}
+
+
 \subsection{Type \DYNAMIC{}}
 \LMLabel{typeDynamic}
 
@@ -13826,7 +14043,7 @@
   function expression invocation where an entity of static type \code{Type} is
   invoked. Note that it could actually succeed: An overriding implementation
   of \code{runtimeType} could return an instance whose dynamic type is a subtype
-  of \code{Type} that has a \code{call} method.
+  of \code{Type} that has a \CALL{} method.
   We decided to make it an error because it is likely to be a mistake,
   especially in cases like \code{$d$.hashCode()}
   where a developer might have forgotten that \code{hashCode} is a getter.
@@ -14442,6 +14659,9 @@
 
 % Function types
 
+%% TODO(eernst): This section should use the new syntax for function types
+%% (\FunctionTypePositionalStd{} etc.); these updates are made by CL 84908.
+
 \LMHash{}%
 The least upper bound of a function type and an interface type $T$ is the least upper bound of \FUNCTION{} and $T$.
 Let $F$ and $G$ be function types.
diff --git a/docs/language/informal/generic-function-type-alias.md b/docs/language/informal/generic-function-type-alias.md
index f03c5cc..2318146 100644
--- a/docs/language/informal/generic-function-type-alias.md
+++ b/docs/language/informal/generic-function-type-alias.md
@@ -1,6 +1,6 @@
 # Feature: Generic Function Type Alias
 
-**Status**: Implemented.
+**Status**: Background material. Normative text is now in dartLangSpec.tex.
 
 **This document** is an informal specification of a feature supporting the
 definition of function type aliases using a more expressive syntax than the
diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart
index 713177c..1448599 100644
--- a/pkg/analysis_server/benchmark/benchmarks.dart
+++ b/pkg/analysis_server/benchmark/benchmarks.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index da92839..f3b7032 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index fdf4066..c28b9f9 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
index 0058fdf..85f6a7f 100644
--- a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/local_runner.dart b/pkg/analysis_server/benchmark/integration/local_runner.dart
index 28ef5bb..8986e1f 100644
--- a/pkg/analysis_server/benchmark/integration/local_runner.dart
+++ b/pkg/analysis_server/benchmark/integration/local_runner.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
index 2ef5e6a..cb4bd81 100644
--- a/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/main.dart b/pkg/analysis_server/benchmark/integration/main.dart
index 2182796..a1be95e 100644
--- a/pkg/analysis_server/benchmark/integration/main.dart
+++ b/pkg/analysis_server/benchmark/integration/main.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/integration/operation.dart b/pkg/analysis_server/benchmark/integration/operation.dart
index 75cf2a7..470756b 100644
--- a/pkg/analysis_server/benchmark/integration/operation.dart
+++ b/pkg/analysis_server/benchmark/integration/operation.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart b/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart
index 0c460c2..56aca72 100644
--- a/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart
+++ b/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart b/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart
index 3d0957e..0634a11 100644
--- a/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart
+++ b/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/bin/server.dart b/pkg/analysis_server/bin/server.dart
index 8c669ff..9dedc84 100644
--- a/pkg/analysis_server/bin/server.dart
+++ b/pkg/analysis_server/bin/server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 713507e..bf31832 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  1.21.1
+  1.22.1
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -2918,6 +2918,12 @@
           is only defined if the displayed text should be different than the
           completion.  Otherwise it is omitted.
         </p>
+      </dd><dt class="field"><b>elementUri: String<span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          The URI of the element corresponding to this suggestion. It will be
+          set whenever analysis server is able to compute it.
+        </p>
       </dd><dt class="field"><b>selectionOffset: int</b></dt><dd>
         
         <p>
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
index 55623c1..8e0f2a2 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
@@ -474,6 +474,9 @@
 class CodeActionOptions implements ToJsonable {
   CodeActionOptions(this.codeActionKinds);
   static CodeActionOptions fromJson(Map<String, dynamic> json) {
+    if (CodeActionRegistrationOptions.canParse(json)) {
+      return CodeActionRegistrationOptions.fromJson(json);
+    }
     final codeActionKinds = json['codeActionKinds']
         ?.map((item) => item != null ? CodeActionKind.fromJson(item) : null)
         ?.cast<CodeActionKind>()
@@ -2548,11 +2551,7 @@
 }
 
 class DidChangeConfigurationParams implements ToJsonable {
-  DidChangeConfigurationParams(this.settings) {
-    if (settings == null) {
-      throw 'settings is required but was not provided';
-    }
-  }
+  DidChangeConfigurationParams(this.settings);
   static DidChangeConfigurationParams fromJson(Map<String, dynamic> json) {
     final settings = json['settings'];
     return new DidChangeConfigurationParams(settings);
@@ -2563,8 +2562,7 @@
 
   Map<String, dynamic> toJson() {
     Map<String, dynamic> __result = {};
-    __result['settings'] =
-        settings ?? (throw 'settings is required but was not set');
+    __result['settings'] = settings;
     return __result;
   }
 
@@ -3932,6 +3930,7 @@
 
   /// Defined by the protocol.
   static const RequestCancelled = const ErrorCodes(-32800);
+  static const ContentModified = const ErrorCodes(-32801);
 
   Object toJson() => _value;
 
@@ -4682,12 +4681,7 @@
   /// The capabilities provided by the client (editor or tool)
   final ClientCapabilities capabilities;
 
-  /// Client provided initialization options. Usually these are options that
-  /// could equally be command line options passed when starting the server.
-  /// This property shouldn't be used to pass any user configuration to the
-  /// server. If a user configuration is needed the server should use
-  /// `workspace/configuration` requests together with dynamic registration to
-  /// obtain them.
+  /// User provided initialization options.
   final dynamic initializationOptions;
 
   /// The process Id of the parent process that started the server. Is null if
@@ -4961,6 +4955,9 @@
     if (targetRange == null) {
       throw 'targetRange is required but was not provided';
     }
+    if (targetSelectionRange == null) {
+      throw 'targetSelectionRange is required but was not provided';
+    }
   }
   static LocationLink fromJson(Map<String, dynamic> json) {
     final originSelectionRange = json['originSelectionRange'] != null
@@ -5108,7 +5105,7 @@
 /// https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
 ///
 /// Here is an example how such a string can be constructed using JavaScript /
-/// TypeScript: ```ts let markdown: MarkdownContent = {
+/// TypeScript: ```typescript let markdown: MarkdownContent = {
 ///
 /// kind: MarkupKind.Markdown,
 /// 	value: [
@@ -5222,6 +5219,15 @@
     }
   }
   static Message fromJson(Map<String, dynamic> json) {
+    if (RequestMessage.canParse(json)) {
+      return RequestMessage.fromJson(json);
+    }
+    if (ResponseMessage.canParse(json)) {
+      return ResponseMessage.fromJson(json);
+    }
+    if (NotificationMessage.canParse(json)) {
+      return NotificationMessage.fromJson(json);
+    }
     final jsonrpc = json['jsonrpc'];
     return new Message(jsonrpc);
   }
@@ -5685,9 +5691,13 @@
   /// The label of this parameter information.
   ///
   /// Either a string or an inclusive start and exclusive end offsets within its
-  /// containing signature label. (see SignatureInformation.label). *Note*: A
-  /// label of type string must be a substring of its containing signature
-  /// label.
+  /// containing signature label. (see SignatureInformation.label). The offsets
+  /// are based on a UTF-16 string representation as `Position` and `Range`
+  /// does.
+  ///
+  /// *Note*: a label of type string should be a substring of its containing
+  /// signature label. Its intended use case is to highlight the parameter label
+  /// part in the `SignatureInformation.label`.
   final String label;
 
   Map<String, dynamic> toJson() {
@@ -5910,6 +5920,60 @@
   String toString() => jsonEncoder.convert(toJson());
 }
 
+class RangeAndPlaceholder implements ToJsonable {
+  RangeAndPlaceholder(this.range, this.placeholder) {
+    if (range == null) {
+      throw 'range is required but was not provided';
+    }
+    if (placeholder == null) {
+      throw 'placeholder is required but was not provided';
+    }
+  }
+  static RangeAndPlaceholder fromJson(Map<String, dynamic> json) {
+    final range = json['range'] != null ? Range.fromJson(json['range']) : null;
+    final placeholder = json['placeholder'];
+    return new RangeAndPlaceholder(range, placeholder);
+  }
+
+  final String placeholder;
+  final Range range;
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> __result = {};
+    __result['range'] = range ?? (throw 'range is required but was not set');
+    __result['placeholder'] =
+        placeholder ?? (throw 'placeholder is required but was not set');
+    return __result;
+  }
+
+  static bool canParse(Object obj) {
+    return obj is Map<String, dynamic> &&
+        obj.containsKey('range') &&
+        Range.canParse(obj['range']) &&
+        obj.containsKey('placeholder') &&
+        obj['placeholder'] is String;
+  }
+
+  @override
+  bool operator ==(other) {
+    if (other is RangeAndPlaceholder) {
+      return range == other.range && placeholder == other.placeholder && true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, range.hashCode);
+    hash = JenkinsSmiHash.combine(hash, placeholder.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+
+  @override
+  String toString() => jsonEncoder.convert(toJson());
+}
+
 class ReferenceContext implements ToJsonable {
   ReferenceContext(this.includeDeclaration) {
     if (includeDeclaration == null) {
@@ -6689,14 +6753,15 @@
   Map<String, dynamic> toJson() {
     Map<String, dynamic> __result = {};
     __result['id'] = id;
-    if (result != null) {
-      __result['result'] = result;
-    }
-    if (error != null) {
-      __result['error'] = error;
-    }
     __result['jsonrpc'] =
         jsonrpc ?? (throw 'jsonrpc is required but was not set');
+    if (error != null && result != null) {
+      throw 'result and error cannot both be set';
+    } else if (error != null) {
+      __result['error'] = error;
+    } else {
+      __result['result'] = result;
+    }
     return __result;
   }
 
@@ -7202,13 +7267,7 @@
   static ServerCapabilitiesWorkspaceFolders fromJson(
       Map<String, dynamic> json) {
     final supported = json['supported'];
-    final changeNotifications = json['changeNotifications'] is String
-        ? new Either2<String, bool>.t1(json['changeNotifications'])
-        : (json['changeNotifications'] is bool
-            ? new Either2<String, bool>.t2(json['changeNotifications'])
-            : (json['changeNotifications'] == null
-                ? null
-                : (throw '''${json['changeNotifications']} was not one of (String, bool)''')));
+    final changeNotifications = json['changeNotifications'];
     return new ServerCapabilitiesWorkspaceFolders(
         supported, changeNotifications);
   }
@@ -7219,7 +7278,7 @@
   /// notification is registered on the client side. The ID can be used to
   /// unregister for these events using the `client/unregisterCapability`
   /// request.
-  final Either2<String, bool> changeNotifications;
+  final bool changeNotifications;
 
   /// The server has support for workspace folders
   final bool supported;
@@ -8106,7 +8165,9 @@
   /// Capabilities specific to the `textDocument/declaration`
   final TextDocumentClientCapabilitiesDeclaration declaration;
 
-  /// Capabilities specific to the `textDocument/definition`
+  /// Capabilities specific to the `textDocument/definition`.
+  ///
+  /// Since 3.14.0
   final TextDocumentClientCapabilitiesDefinition definition;
 
   /// Capabilities specific to the `textDocument/documentHighlight`
@@ -8793,6 +8854,8 @@
   final bool dynamicRegistration;
 
   /// The client supports additional metadata in the form of declaration links.
+  ///
+  /// Since 3.14.0
   final bool linkSupport;
 
   Map<String, dynamic> toJson() {
@@ -9230,6 +9293,8 @@
   final bool dynamicRegistration;
 
   /// The client supports additional metadata in the form of definition links.
+  ///
+  /// Since 3.14.0
   final bool linkSupport;
 
   Map<String, dynamic> toJson() {
@@ -9323,6 +9388,8 @@
 
   /// The client supports processing label offsets instead of a simple label
   /// string.
+  ///
+  /// Since 3.14.0
   final bool labelOffsetSupport;
 
   Map<String, dynamic> toJson() {
@@ -9803,6 +9870,8 @@
   final bool dynamicRegistration;
 
   /// The client supports additional metadata in the form of definition links.
+  ///
+  /// Since 3.14.0
   final bool linkSupport;
 
   Map<String, dynamic> toJson() {
@@ -9981,6 +10050,9 @@
     }
   }
   static TextDocumentIdentifier fromJson(Map<String, dynamic> json) {
+    if (VersionedTextDocumentIdentifier.canParse(json)) {
+      return VersionedTextDocumentIdentifier.fromJson(json);
+    }
     final uri = json['uri'];
     return new TextDocumentIdentifier(uri);
   }
@@ -10114,6 +10186,12 @@
     }
   }
   static TextDocumentPositionParams fromJson(Map<String, dynamic> json) {
+    if (CompletionParams.canParse(json)) {
+      return CompletionParams.fromJson(json);
+    }
+    if (ReferenceParams.canParse(json)) {
+      return ReferenceParams.fromJson(json);
+    }
     final textDocument = json['textDocument'] != null
         ? TextDocumentIdentifier.fromJson(json['textDocument'])
         : null;
@@ -10170,6 +10248,33 @@
 class TextDocumentRegistrationOptions implements ToJsonable {
   TextDocumentRegistrationOptions(this.documentSelector);
   static TextDocumentRegistrationOptions fromJson(Map<String, dynamic> json) {
+    if (TextDocumentChangeRegistrationOptions.canParse(json)) {
+      return TextDocumentChangeRegistrationOptions.fromJson(json);
+    }
+    if (TextDocumentSaveRegistrationOptions.canParse(json)) {
+      return TextDocumentSaveRegistrationOptions.fromJson(json);
+    }
+    if (CompletionRegistrationOptions.canParse(json)) {
+      return CompletionRegistrationOptions.fromJson(json);
+    }
+    if (SignatureHelpRegistrationOptions.canParse(json)) {
+      return SignatureHelpRegistrationOptions.fromJson(json);
+    }
+    if (CodeActionRegistrationOptions.canParse(json)) {
+      return CodeActionRegistrationOptions.fromJson(json);
+    }
+    if (CodeLensRegistrationOptions.canParse(json)) {
+      return CodeLensRegistrationOptions.fromJson(json);
+    }
+    if (DocumentLinkRegistrationOptions.canParse(json)) {
+      return DocumentLinkRegistrationOptions.fromJson(json);
+    }
+    if (DocumentOnTypeFormattingRegistrationOptions.canParse(json)) {
+      return DocumentOnTypeFormattingRegistrationOptions.fromJson(json);
+    }
+    if (RenameRegistrationOptions.canParse(json)) {
+      return RenameRegistrationOptions.fromJson(json);
+    }
     final documentSelector = json['documentSelector']
         ?.map((item) => item != null ? DocumentFilter.fromJson(item) : null)
         ?.cast<DocumentFilter>()
@@ -10961,6 +11066,8 @@
   }
 
   /// Did change watched files notification supports dynamic registration.
+  /// Please note that the current protocol doesn't support static configuration
+  /// for file changes from the server side.
   final bool dynamicRegistration;
 
   Map<String, dynamic> toJson() {
diff --git a/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart b/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart
index 22a85fd..9267bc4 100644
--- a/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart
+++ b/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
index 06bbf6b..adc7fd9 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
index 08fe4f3..fe2c234 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
index ccc79a9..32834a2 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 1d115fa..fb3c5ec 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
index cab3a80..aaecbef 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/protocol/protocol.dart b/pkg/analysis_server/lib/protocol/protocol.dart
index f3253cf..b769bd4 100644
--- a/pkg/analysis_server/lib/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/protocol/protocol.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 15c626a..fd21adb 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.21.1';
+const String PROTOCOL_VERSION = '1.22.1';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server/lib/src/analysis_logger.dart b/pkg/analysis_server/lib/src/analysis_logger.dart
index 3391196..768ab01 100644
--- a/pkg/analysis_server/lib/src/analysis_logger.dart
+++ b/pkg/analysis_server/lib/src/analysis_logger.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 03fd356..a917fb1 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -16,7 +16,6 @@
 import 'package:analysis_server/src/analysis_logger.dart';
 import 'package:analysis_server/src/analysis_server_abstract.dart';
 import 'package:analysis_server/src/channel/channel.dart';
-import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/computer/computer_highlights.dart';
 import 'package:analysis_server/src/computer/computer_highlights2.dart';
 import 'package:analysis_server/src/computer/computer_outline.dart';
@@ -50,6 +49,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/overlay_file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/context/builder.dart';
@@ -76,9 +76,6 @@
 /// Instances of the class [AnalysisServer] implement a server that listens on a
 /// [CommunicationChannel] for analysis requests and process them.
 class AnalysisServer extends AbstractAnalysisServer {
-  /// The options of this server instance.
-  AnalysisServerOptions options;
-
   /// The channel from which requests are received and to which responses should
   /// be sent.
   final ServerCommunicationChannel channel;
@@ -124,22 +121,6 @@
   /// notifications should be sent.
   Map<FlutterService, Set<String>> flutterServices = {};
 
-  /// Performance information before initial analysis is complete.
-  final ServerPerformance performanceDuringStartup = new ServerPerformance();
-
-  /// Performance information after initial analysis is complete
-  /// or `null` if the initial analysis is not yet complete
-  ServerPerformance performanceAfterStartup;
-
-  /// A [RecentBuffer] of the most recent exceptions encountered by the analysis
-  /// server.
-  final RecentBuffer<ServerException> exceptions = new RecentBuffer(10);
-
-  /// The class into which performance information is currently being recorded.
-  /// During startup, this will be the same as [performanceDuringStartup]
-  /// and after startup is complete, this switches to [performanceAfterStartup].
-  ServerPerformance _performance;
-
   /// The [Completer] that completes when analysis is complete.
   Completer _onAnalysisCompleteCompleter;
 
@@ -191,18 +172,16 @@
   AnalysisServer(
     this.channel,
     ResourceProvider baseResourceProvider,
-    this.options,
+    AnalysisServerOptions options,
     this.sdkManager,
     this.instrumentationService, {
     this.diagnosticServer,
     ResolverProvider fileResolverProvider: null,
     ResolverProvider packageResolverProvider: null,
     this.detachableFileSystemManager: null,
-  }) : super(baseResourceProvider) {
+  }) : super(options, baseResourceProvider) {
     notificationManager = new NotificationManager(channel, resourceProvider);
 
-    _performance = performanceDuringStartup;
-
     pluginManager = new PluginManager(
         resourceProvider,
         _getByteStorePath(),
@@ -252,7 +231,7 @@
     onAnalysisStarted.first.then((_) {
       onAnalysisComplete.then((_) {
         performanceAfterStartup = new ServerPerformance();
-        _performance = performanceAfterStartup;
+        performance = performanceAfterStartup;
       });
     });
     searchEngine = new SearchEngineImpl(driverMap.values);
@@ -302,13 +281,6 @@
     return _onAnalysisStartedController.stream;
   }
 
-  /// Return the total time the server's been alive.
-  Duration get uptime {
-    DateTime start = new DateTime.fromMillisecondsSinceEpoch(
-        performanceDuringStartup.startTime);
-    return new DateTime.now().difference(start);
-  }
-
   /// The socket from which requests are being read has been closed.
   void done() {}
 
@@ -340,7 +312,7 @@
 
   /// Handle a [request] that was read from the communication channel.
   void handleRequest(Request request) {
-    _performance.logRequest(request);
+    performance.logRequestTiming(request.clientRequestTime);
     runZoned(() {
       ServerPerformanceStatistics.serverRequests.makeCurrentWhile(() {
         int count = handlers.length;
@@ -686,9 +658,12 @@
   /// Return the path to the location of the byte store on disk, or `null` if
   /// there is no on-disk byte store.
   String _getByteStorePath() {
-    if (resourceProvider is PhysicalResourceProvider) {
-      Folder stateLocation =
-          resourceProvider.getStateLocation('.analysis-driver');
+    ResourceProvider provider = resourceProvider;
+    if (provider is OverlayResourceProvider) {
+      provider = (provider as OverlayResourceProvider).baseProvider;
+    }
+    if (provider is PhysicalResourceProvider) {
+      Folder stateLocation = provider.getStateLocation('.analysis-driver');
       if (stateLocation != null) {
         return stateLocation.path;
       }
@@ -1071,6 +1046,9 @@
   /// The number of requests.
   int requestCount = 0;
 
+  /// The number of requests that recorded latency information.
+  int latencyCount = 0;
+
   /// The total latency (milliseconds) for all recorded requests.
   int requestLatency = 0;
 
@@ -1080,12 +1058,13 @@
   /// The number of requests with latency > 150 milliseconds.
   int slowRequestCount = 0;
 
-  /// Log performance information about the given request.
-  void logRequest(Request request) {
+  /// Log timing information for a request.
+  void logRequestTiming(int clientRequestTime) {
     ++requestCount;
-    if (request.clientRequestTime != null) {
+    if (clientRequestTime != null) {
       int latency =
-          new DateTime.now().millisecondsSinceEpoch - request.clientRequestTime;
+          new DateTime.now().millisecondsSinceEpoch - clientRequestTime;
+      ++latencyCount;
       requestLatency += latency;
       maxLatency = max(maxLatency, latency);
       if (latency > 150) {
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index bdc364e..f784b71 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -1,10 +1,12 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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:async';
 import 'dart:core';
 
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/search/element_visitors.dart';
@@ -29,10 +31,29 @@
 /// Implementations of [AbstractAnalysisServer] implement a server that listens
 /// on a [CommunicationChannel] for analysis messages and process them.
 abstract class AbstractAnalysisServer {
+  /// The options of this server instance.
+  AnalysisServerOptions options;
+
   /// The [ContextManager] that handles the mapping from analysis roots to
   /// context directories.
   ContextManager contextManager;
 
+  /// A [RecentBuffer] of the most recent exceptions encountered by the analysis
+  /// server.
+  final RecentBuffer<ServerException> exceptions = new RecentBuffer(10);
+
+  /// Performance information after initial analysis is complete
+  /// or `null` if the initial analysis is not yet complete
+  ServerPerformance performanceAfterStartup;
+
+  /// The class into which performance information is currently being recorded.
+  /// During startup, this will be the same as [performanceDuringStartup]
+  /// and after startup is complete, this switches to [performanceAfterStartup].
+  ServerPerformance performance;
+
+  /// Performance information before initial analysis is complete.
+  final ServerPerformance performanceDuringStartup = new ServerPerformance();
+
   /// The set of the files that are currently priority.
   final Set<String> priorityFiles = new Set<String>();
 
@@ -52,8 +73,10 @@
   /// list is lazily created and should be accessed using [analyzedFilesGlobs].
   List<Glob> _analyzedFilesGlobs = null;
 
-  AbstractAnalysisServer(ResourceProvider baseResourceProvider)
-      : resourceProvider = OverlayResourceProvider(baseResourceProvider);
+  AbstractAnalysisServer(this.options, ResourceProvider baseResourceProvider)
+      : resourceProvider = OverlayResourceProvider(baseResourceProvider) {
+    performance = performanceDuringStartup;
+  }
 
   /// Return a list of the globs used to determine which files should be
   /// analyzed.
@@ -82,6 +105,13 @@
   /// A table mapping [Folder]s to the [AnalysisDriver]s associated with them.
   Map<Folder, nd.AnalysisDriver> get driverMap => contextManager.driverMap;
 
+  /// Return the total time the server's been alive.
+  Duration get uptime {
+    DateTime start = new DateTime.fromMillisecondsSinceEpoch(
+        performanceDuringStartup.startTime);
+    return new DateTime.now().difference(start);
+  }
+
   /// If the state location can be accessed, return the file byte store,
   /// otherwise return the memory byte store.
   ByteStore createByteStore(ResourceProvider resourceProvider) {
diff --git a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
index 8bdb5d5..7fa2439 100644
--- a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/channel/channel.dart b/pkg/analysis_server/lib/src/channel/channel.dart
index 0f580f1..152c820 100644
--- a/pkg/analysis_server/lib/src/channel/channel.dart
+++ b/pkg/analysis_server/lib/src/channel/channel.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/collections.dart b/pkg/analysis_server/lib/src/collections.dart
index afde613..a20dd6b 100644
--- a/pkg/analysis_server/lib/src/collections.dart
+++ b/pkg/analysis_server/lib/src/collections.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 0905fe7..eb20b24 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
index 24af9ba..c11bac0 100644
--- a/pkg/analysis_server/lib/src/computer/computer_outline.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index 92be0a4..cd1ff67 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_signature.dart b/pkg/analysis_server/lib/src/computer/computer_signature.dart
index b213ef1..518a488 100644
--- a/pkg/analysis_server/lib/src/computer/computer_signature.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_signature.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
index 7973eed..00f2cfc 100644
--- a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
+++ b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/computer/new_notifications.dart b/pkg/analysis_server/lib/src/computer/new_notifications.dart
index 06aabc7..a7c00bf 100644
--- a/pkg/analysis_server/lib/src/computer/new_notifications.dart
+++ b/pkg/analysis_server/lib/src/computer/new_notifications.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 7808ce0..b7312d6 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_abstract.dart b/pkg/analysis_server/lib/src/domain_abstract.dart
index 3c01cbf..6a50a2d 100644
--- a/pkg/analysis_server/lib/src/domain_abstract.dart
+++ b/pkg/analysis_server/lib/src/domain_abstract.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index fd6e154..9d2cbe9 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_analytics.dart b/pkg/analysis_server/lib/src/domain_analytics.dart
index 220fe27..e006ab8 100644
--- a/pkg/analysis_server/lib/src/domain_analytics.dart
+++ b/pkg/analysis_server/lib/src/domain_analytics.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index ce73d98..2b61900 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index 6c03067..dcd24ed 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index 52bf9d6..8930def 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_kythe.dart b/pkg/analysis_server/lib/src/domain_kythe.dart
index 2bfc8c0..ecfcc43 100644
--- a/pkg/analysis_server/lib/src/domain_kythe.dart
+++ b/pkg/analysis_server/lib/src/domain_kythe.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index 728a4dd..c7d5f28 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index cff08c1..2885948 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index 74bbf87..d8fbb56 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
index eedb605..2c44ad4 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
index 6b9cde3..ee06820 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/domains/execution/completion.dart b/pkg/analysis_server/lib/src/domains/execution/completion.dart
index a8a55f1..dbba4ea 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
index 073e434..c9b2ff1 100644
--- a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
@@ -6,6 +6,7 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/edit/fix/non_nullable_fix.dart';
 import 'package:analysis_server/src/edit/fix/prefer_int_literals_fix.dart';
 import 'package:analysis_server/src/edit/fix/prefer_mixin_fix.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
@@ -43,7 +44,8 @@
 
   EditDartFix(this.server, this.request);
 
-  void addFix(String description, Location location, SourceChange change) {
+  void addSourceChange(
+      String description, Location location, SourceChange change) {
     suggestions.add(new DartFixSuggestion(description, location: location));
     for (SourceFileEdit fileEdit in change.edits) {
       for (SourceEdit sourceEdit in fileEdit.edits) {
@@ -52,6 +54,14 @@
     }
   }
 
+  void addSourceFileEdit(
+      String description, Location location, SourceFileEdit fileEdit) {
+    suggestions.add(new DartFixSuggestion(description, location: location));
+    for (SourceEdit sourceEdit in fileEdit.edits) {
+      sourceChange.addEdit(fileEdit.file, fileEdit.fileStamp, sourceEdit);
+    }
+  }
+
   void addRecommendation(String description, [Location location]) {
     otherSuggestions
         .add(new DartFixSuggestion(description, location: location));
@@ -89,6 +99,7 @@
 
     final preferIntLiterals = lintRules['prefer_int_literals'];
     final preferIntLiteralsFix = new PreferIntLiteralsFix(this);
+    final nonNullableFix = new NonNullableFix(this);
     preferIntLiterals?.reporter = preferIntLiteralsFix;
 
     // Setup
@@ -163,6 +174,9 @@
             for (LinterFix fix in fixes) {
               await fix.applyLocalFixes(result);
             }
+            if (isIncluded(source.fullName)) {
+              nonNullableFix.applyLocalFixes(result);
+            }
           }
           break;
         } on InconsistentAnalysisException catch (_) {
@@ -219,7 +233,7 @@
     Fix fix = await processor.computeFix();
     final location = locationFor(result, error.offset, error.length);
     if (fix != null) {
-      addFix(fix.change.message, location, fix.change);
+      addSourceChange(fix.change.message, location, fix.change);
     } else {
       // TODO(danrubel): Determine why the fix could not be applied
       // and report that in the description.
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index f2a9cda..2e1f6e2 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -938,38 +938,14 @@
         var node = new NodeLocator(offset).searchWithin(resolvedUnit.unit);
         var element = server.getElementOfNode(node);
         if (node != null && element != null) {
-          int feedbackOffset = node.offset;
-          int feedbackLength = node.length;
-
-          if (element is FieldFormalParameterElement) {
-            element = (element as FieldFormalParameterElement).field;
-          }
-
-          // Use the prefix offset/length when renaming an import directive.
-          if (node is ImportDirective && element is ImportElement) {
-            if (node.prefix != null) {
-              feedbackOffset = node.prefix.offset;
-              feedbackLength = node.prefix.length;
-            } else {
-              feedbackOffset = -1;
-              feedbackLength = 0;
-            }
-          }
-
-          // Rename the class when on `new` in an instance creation.
-          if (node is InstanceCreationExpression) {
-            InstanceCreationExpression creation = node;
-            var typeIdentifier = creation.constructorName.type.name;
-            element = typeIdentifier.staticElement;
-            feedbackOffset = typeIdentifier.offset;
-            feedbackLength = typeIdentifier.length;
-          }
+          final renameElement =
+              RenameRefactoring.getElementToRename(node, element);
 
           // do create the refactoring
-          refactoring = new RenameRefactoring(
-              refactoringWorkspace, resolvedUnit.session, element);
+          refactoring = new RenameRefactoring(refactoringWorkspace,
+              resolvedUnit.session, renameElement.element);
           feedback = new RenameFeedback(
-              feedbackOffset, feedbackLength, 'kind', 'oldName');
+              renameElement.offset, renameElement.length, 'kind', 'oldName');
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
new file mode 100644
index 0000000..14bad20
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
@@ -0,0 +1,82 @@
+import 'package:analysis_server/src/edit/edit_dartfix.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+
+class NonNullableFix {
+  final EditDartFix dartFix;
+
+  /// The current source being "fixed"
+  Source source;
+
+  /// The source file change or `null` if none
+  SourceFileEdit fileEdit;
+
+  int firstOffset;
+  int firstLength;
+
+  NonNullableFix(this.dartFix);
+
+  void addEdit(int offset, int length, String replacementText) {
+    fileEdit ??= new SourceFileEdit(source.fullName, 0);
+    fileEdit.edits.add(new SourceEdit(offset, length, replacementText));
+  }
+
+  /// Update the source to be non-nullable by
+  /// 1) adding trailing '?' to type references of nullable variables, and
+  /// 2) removing trailing '?' from type references of non-nullable variables.
+  void applyLocalFixes(ResolvedUnitResult result) {
+    final context = result.session.analysisContext;
+    AnalysisOptionsImpl options = context.analysisOptions;
+    if (!options.experimentStatus.non_nullable) {
+      return;
+    }
+
+    final unit = result.unit;
+    source = unit.declaredElement.source;
+
+    // find and fix types
+    unit.accept(new _NonNullableTypeVisitor(this));
+
+    // add source changes to the collection of fixes
+    source = null;
+    if (fileEdit != null) {
+      dartFix.addSourceFileEdit('Update non-nullable type references',
+          dartFix.locationFor(result, firstOffset, firstLength), fileEdit);
+    }
+  }
+}
+
+class _NonNullableTypeVisitor extends RecursiveAstVisitor<void> {
+  final NonNullableFix fix;
+
+  _NonNullableTypeVisitor(this.fix);
+
+  @override
+  void visitConstructorName(ConstructorName node) {
+    // skip the type name associated with the constructor
+    node.type?.typeArguments?.accept(this);
+  }
+
+  @override
+  void visitTypeName(TypeName node) {
+    // TODO(danrubel): Replace this braindead implementation
+    // with something that determines whether or not the type should be nullable
+    // and adds or removes the trailing `?` to match.
+    if (node.question == null) {
+      final identifier = node.name;
+      if (identifier is SimpleIdentifier) {
+        if (identifier.name == 'void') {
+          return;
+        }
+      }
+      fix.addEdit(node.end, 0, '?');
+      fix.firstOffset ??= node.offset;
+      fix.firstLength ??= node.length;
+    }
+    super.visitTypeName(node);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart
index 619cad3..871eb2b 100644
--- a/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart
@@ -34,8 +34,10 @@
           dartFix.locationFor(result, literal.offset, literal.length);
       if (assists.isNotEmpty) {
         for (Assist assist in assists) {
-          dartFix.addFix('Replace a double literal with an int literal',
-              location, assist.change);
+          dartFix.addSourceChange(
+              'Replace a double literal with an int literal',
+              location,
+              assist.change);
         }
       } else {
         // TODO(danrubel): If assists is empty, then determine why
diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
index 7f66a47..2972f49 100644
--- a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
@@ -50,8 +50,8 @@
             dartFix.locationFor(result, elem.nameOffset, elem.nameLength);
         if (assists.isNotEmpty) {
           for (Assist assist in assists) {
-            dartFix.addFix('Convert ${elem.displayName} to a mixin', location,
-                assist.change);
+            dartFix.addSourceChange('Convert ${elem.displayName} to a mixin',
+                location, assist.change);
           }
         } else {
           // TODO(danrubel): If assists is empty, then determine why
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_correction.dart b/pkg/analysis_server/lib/src/flutter/flutter_correction.dart
index 34e2864..3f92193 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_correction.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_correction.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
index 7bc3713..27d5268 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart b/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart
index b387156..054a199 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart b/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
index 5d503b4..d6fae03 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 74a7949..464ab95 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -23,6 +23,7 @@
     // We have to explicitly list this for the client to enable built-in command.
     CodeActionKind.SourceOrganizeImports,
     SortMembers,
+    CodeActionKind.QuickFix,
   ];
   static const SortMembers = const CodeActionKind('source.sortMembers');
 }
@@ -39,6 +40,7 @@
   static const FileNotAnalyzed = const ErrorCodes(-32007);
   static const FileHasErrors = const ErrorCodes(-32008);
   static const ClientFailedToApplyEdit = const ErrorCodes(-32009);
+  static const RenameNotValid = const ErrorCodes(-32010);
 
   /// An error raised when the server detects that the server and client are out
   /// of sync and cannot recover. For example if a textDocument/didChange notification
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
new file mode 100644
index 0000000..6823eb8
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+
+class WorkspaceFoldersHandler
+    extends MessageHandler<DidChangeWorkspaceFoldersParams, void> {
+  WorkspaceFoldersHandler(LspAnalysisServer server) : super(server);
+  Method get handlesMessage => Method.workspace_didChangeWorkspaceFolders;
+
+  @override
+  DidChangeWorkspaceFoldersParams convertParams(Map<String, dynamic> json) =>
+      DidChangeWorkspaceFoldersParams.fromJson(json);
+
+  ErrorOr<void> handle(DidChangeWorkspaceFoldersParams params) {
+    final added = params?.event?.added
+        ?.map((wf) => Uri.parse(wf.uri).toFilePath())
+        ?.toList();
+
+    final removed = params?.event?.removed
+        ?.map((wf) => Uri.parse(wf.uri).toFilePath())
+        ?.toList();
+
+    server.updateAnalysisRoots(added, removed);
+
+    return success();
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index dc83f4f..41d3014 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -13,8 +13,6 @@
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
-import 'package:analysis_server/src/lsp/source_edits.dart';
-import 'package:analysis_server/src/protocol_server.dart' show SourceChange;
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
@@ -90,7 +88,7 @@
       assist.change.message,
       CodeActionKind.Refactor,
       const [],
-      _createWorkspaceEdit(assist.change),
+      createWorkspaceEdit(server, assist.change),
       null,
     ));
   }
@@ -105,25 +103,11 @@
       fix.change.message,
       CodeActionKind.QuickFix,
       [diagnostic],
-      _createWorkspaceEdit(fix.change),
+      createWorkspaceEdit(server, fix.change),
       null,
     ));
   }
 
-  /// Note: This code will fetch the version of each document being modified so
-  /// it's important to call this immediately after computing edits to ensure
-  /// the document is not modified before the version number is read.
-  WorkspaceEdit _createWorkspaceEdit(SourceChange change) {
-    return toWorkspaceEdit(
-        server.clientCapabilities?.workspace,
-        change.edits
-            .map((e) => new FileEditInformation(
-                server.getVersionedDocumentIdentifier(e.file),
-                server.getLineInfo(e.file),
-                e.edits))
-            .toList());
-  }
-
   Future<List<Either2<Command, CodeAction>>> _getAssistActions(
     HashSet<CodeActionKind> clientSupportedCodeActionKinds,
     bool clientSupportsLiteralCodeActions,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 6bf8c1c..bc81078 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -77,12 +77,22 @@
     int offset,
   ) async {
     final performance = new CompletionPerformance();
+    performance.path = unit.path;
+    performance.setContentsAndOffset(unit.content, offset);
+    server.performanceStats.completion.add(performance);
+
     final completionRequest =
         new CompletionRequestImpl(unit, offset, performance);
 
     try {
       CompletionContributor contributor = new DartCompletionManager();
       final items = await contributor.computeSuggestions(completionRequest);
+
+      performance.notificationCount = 1;
+      performance.suggestionCountFirst = items.length;
+      performance.suggestionCountLast = items.length;
+      performance.complete();
+
       return success(items
           .map((item) => toCompletionItem(
                 completionCapabilities,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
new file mode 100644
index 0000000..9f6822e
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/domains/analysis/occurrences.dart';
+import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+
+class DocumentHighlightsHandler extends MessageHandler<
+    TextDocumentPositionParams, List<DocumentHighlight>> {
+  DocumentHighlightsHandler(LspAnalysisServer server) : super(server);
+  Method get handlesMessage => Method.textDocument_documentHighlight;
+
+  @override
+  TextDocumentPositionParams convertParams(Map<String, dynamic> json) =>
+      TextDocumentPositionParams.fromJson(json);
+
+  Future<ErrorOr<List<DocumentHighlight>>> handle(
+      TextDocumentPositionParams params) async {
+    final pos = params.position;
+    final path = pathOfDoc(params.textDocument);
+    final unit = await path.mapResult(requireUnit);
+    final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
+
+    return offset.mapResult((requestedOffset) {
+      final collector = new OccurrencesCollectorImpl();
+      addDartOccurrences(collector, unit.result.unit);
+
+      // Find an occurrence that has an instance that spans the position.
+      for (final occurrence in collector.allOccurrences) {
+        bool spansRequestedPosition(int offset) {
+          return offset <= requestedOffset &&
+              offset + occurrence.length >= requestedOffset;
+        }
+
+        if (occurrence.offsets.any(spansRequestedPosition)) {
+          return success(toHighlights(unit.result.lineInfo, occurrence));
+        }
+      }
+
+      // No matches.
+      return success(null);
+    });
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
index 7783434..e1a72f6 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
@@ -31,14 +31,23 @@
       openWorkspacePaths.add(Uri.parse(params.rootUri).toFilePath());
       // ignore: deprecated_member_use
     } else if (params.rootPath != null) {
-      openWorkspacePaths.add(params.rootUri);
+      // This is deprecated according to LSP spec, but we still want to support
+      // it in case older clients send us it.
+      // ignore: deprecated_member_use
+      openWorkspacePaths.add(params.rootPath);
     }
 
-    server.setClientCapabilities(params.capabilities);
+    server.handleClientConnection(params.capabilities);
     server.messageHandler =
         new InitializingStateMessageHandler(server, openWorkspacePaths);
 
-    return success(new InitializeResult(new ServerCapabilities(
+    final codeActionLiteralSupport =
+        params.capabilities.textDocument?.codeAction?.codeActionLiteralSupport;
+
+    final renameOptionsSupport =
+        params.capabilities.textDocument?.rename?.prepareSupport ?? false;
+
+    server.capabilities = new ServerCapabilities(
         Either2<TextDocumentSyncOptions, num>.t1(new TextDocumentSyncOptions(
           true,
           TextDocumentSyncKind.Incremental,
@@ -66,21 +75,31 @@
         null,
         null,
         true, // referencesProvider
-        null,
+        true, // documentHighlightProvider
         true, // documentSymbolProvider
         null,
-        Either2<bool, CodeActionOptions>.t2(
-            new CodeActionOptions(DartCodeActionKind.serverSupportedKinds)),
+        // "The `CodeActionOptions` return type is only valid if the client
+        // signals code action literal support via the property
+        // `textDocument.codeAction.codeActionLiteralSupport`."
+        codeActionLiteralSupport != null
+            ? Either2<bool, CodeActionOptions>.t2(
+                new CodeActionOptions(DartCodeActionKind.serverSupportedKinds))
+            : Either2<bool, CodeActionOptions>.t1(true),
         null,
         true, // documentFormattingProvider
         false, // documentRangeFormattingProvider
         new DocumentOnTypeFormattingOptions('}', [';']),
-        null,
+        renameOptionsSupport
+            ? Either2<bool, RenameOptions>.t2(new RenameOptions(true))
+            : Either2<bool, RenameOptions>.t1(true),
         null,
         null,
         null,
         new ExecuteCommandOptions(Commands.serverSupportedCommands),
-        null,
-        null)));
+        new ServerCapabilitiesWorkspace(
+            new ServerCapabilitiesWorkspaceFolders(true, true)),
+        null);
+
+    return success(new InitializeResult(server.capabilities));
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
index 8201ae8..3462d78 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
@@ -21,7 +21,7 @@
   ErrorOr<void> handle(InitializedParams params) {
     server.messageHandler = new InitializedStateMessageHandler(server);
 
-    server.setAnalysisRoots(openWorkspacePaths, [], {});
+    server.setAnalysisRoots(openWorkspacePaths);
 
     return success();
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
new file mode 100644
index 0000000..3a9075e
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+
+class PrepareRenameHandler
+    extends MessageHandler<TextDocumentPositionParams, RangeAndPlaceholder> {
+  PrepareRenameHandler(LspAnalysisServer server) : super(server);
+  Method get handlesMessage => Method.textDocument_prepareRename;
+
+  @override
+  TextDocumentPositionParams convertParams(Map<String, dynamic> json) =>
+      TextDocumentPositionParams.fromJson(json);
+
+  @override
+  Future<ErrorOr<RangeAndPlaceholder>> handle(
+      TextDocumentPositionParams params) async {
+    final pos = params.position;
+    final path = pathOfDoc(params.textDocument);
+    final unit = await path.mapResult(requireUnit);
+    final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
+
+    return offset.mapResult((offset) async {
+      final node = await server.getNodeAtOffset(path.result, offset);
+      final element = server.getElementOfNode(node);
+      if (node == null || element == null) {
+        return success(null);
+      }
+
+      final refactorDetails =
+          RenameRefactoring.getElementToRename(node, element);
+      final refactoring = new RenameRefactoring(server.refactoringWorkspace,
+          unit.result.session, refactorDetails.element);
+
+      // Check the rename is valid here.
+      final initStatus = await refactoring.checkInitialConditions();
+      if (initStatus.hasFatalError) {
+        return error(
+            ServerErrorCodes.RenameNotValid, initStatus.problem.message, null);
+      }
+
+      return success(new RangeAndPlaceholder(
+        toRange(
+          unit.result.lineInfo,
+          // If the offset is set to -1 it means there is no location for the
+          // old name. However since we must provide a range for LSP, we'll use
+          // a 0-character span at the originally requested location to ensure
+          // it's valid.
+          refactorDetails.offset == -1 ? offset : refactorDetails.offset,
+          refactorDetails.length,
+        ),
+        refactoring.oldName,
+      ));
+    });
+  }
+}
+
+class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
+  RenameHandler(LspAnalysisServer server) : super(server);
+
+  Method get handlesMessage => Method.textDocument_rename;
+
+  @override
+  RenameParams convertParams(Map<String, dynamic> json) =>
+      RenameParams.fromJson(json);
+
+  @override
+  Future<ErrorOr<WorkspaceEdit>> handle(RenameParams params) async {
+    final pos = params.position;
+    final path = pathOfDoc(params.textDocument);
+    // If the client provided us a version doc identifier, we'll use it to ensure
+    // we're not computing a rename for an old document. If not, we'll just assume
+    // the version the server had at the time of recieving the request is valid
+    // and then use it to verify the document hadn't changed again before we
+    // send the edits.
+    final docIdentifier = await path.mapResult((path) => success(
+        params.textDocument is VersionedTextDocumentIdentifier
+            ? params.textDocument
+            : server.getVersionedDocumentIdentifier(path)));
+    final unit = await path.mapResult(requireUnit);
+    final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
+
+    return offset.mapResult((offset) async {
+      final node = await server.getNodeAtOffset(path.result, offset);
+      final element = server.getElementOfNode(node);
+      if (node == null || element == null) {
+        return success(null);
+      }
+
+      final refactorDetails =
+          RenameRefactoring.getElementToRename(node, element);
+      final refactoring = new RenameRefactoring(server.refactoringWorkspace,
+          unit.result.session, refactorDetails.element);
+
+      // TODO(dantup): Consider using window/showMessageRequest to prompt
+      // the user to see if they'd like to proceed with a rename if there
+      // are non-fatal errors or warnings. For now we will reject all errors
+      // (fatal and not) as this seems like the most logical behaviour when
+      // without a prompt.
+
+      // Check the rename is valid here.
+      final initStatus = await refactoring.checkInitialConditions();
+      if (initStatus.hasError) {
+        return error(
+            ServerErrorCodes.RenameNotValid, initStatus.problem.message, null);
+      }
+
+      // Check the name is valid.
+      refactoring.newName = params.newName;
+      final optionsStatus = refactoring.checkNewName();
+      if (optionsStatus.hasError) {
+        return error(ServerErrorCodes.RenameNotValid,
+            optionsStatus.problem.message, null);
+      }
+
+      // Final validation.
+      final finalStatus = await refactoring.checkFinalConditions();
+      if (finalStatus.hasError) {
+        return error(
+            ServerErrorCodes.RenameNotValid, finalStatus.problem.message, null);
+      }
+
+      // Compute the actual change.
+      final change = await refactoring.createChange();
+
+      // Before we send anything back, ensure the original file didn't change
+      // while we were computing changes.
+      if (server.getVersionedDocumentIdentifier(path.result) !=
+          docIdentifier.result) {
+        return error(ErrorCodes.ContentModified,
+            'Document was modified while rename was being computed', null);
+      }
+
+      final workspaceEdit = createWorkspaceEdit(server, change);
+      return success(workspaceEdit);
+    });
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
index b1e6c2b..9375b8b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/lsp/handlers/handler_code_actions.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_completion.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_definition.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_document_highlights.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_document_symbols.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_execute_command.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_format_on_type.dart';
@@ -18,8 +19,10 @@
 import 'package:analysis_server/src/lsp/handlers/handler_initialize.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_initialized.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_references.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_rename.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_signature_help.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_text_document_changes.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_change_workspace_folders.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 
@@ -54,9 +57,13 @@
     registerHandler(new ReferencesHandler(server));
     registerHandler(new FormattingHandler(server));
     registerHandler(new FormatOnTypeHandler(server));
+    registerHandler(new DocumentHighlightsHandler(server));
     registerHandler(new DocumentSymbolHandler(server));
     registerHandler(new CodeActionHandler(server));
     registerHandler(new ExecuteCommandHandler(server));
+    registerHandler(new WorkspaceFoldersHandler(server));
+    registerHandler(new PrepareRenameHandler(server));
+    registerHandler(new RenameHandler(server));
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 245c116a..925e5a7 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:collection';
 import 'dart:io' as io;
 
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -10,7 +11,10 @@
 import 'package:analysis_server/protocol/protocol_generated.dart' as protocol;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/analysis_server_abstract.dart';
+import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/context_manager.dart';
+import 'package:analysis_server/src/domain_completion.dart'
+    show CompletionDomainHandler;
 import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_states.dart';
@@ -18,9 +22,13 @@
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/plugin/notification_manager.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/services/completion/completion_performance.dart'
+    show CompletionPerformance;
+import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analysis_server/src/utilities/null_string_sink.dart';
+import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/source/line_info.dart';
@@ -45,11 +53,6 @@
   ClientCapabilities _clientCapabilities;
 
   /**
-   * The options of this server instance.
-   */
-  AnalysisServerOptions options;
-
-  /**
    * The channel from which messages are received and to which responses should
    * be sent.
    */
@@ -77,6 +80,15 @@
   final AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl();
 
   /**
+   * The workspace for rename refactorings. Should be accessed through the
+   * refactoringWorkspace getter to be automatically created (lazily).
+   */
+  RefactoringWorkspace _refactoringWorkspace;
+
+  RefactoringWorkspace get refactoringWorkspace => _refactoringWorkspace ??=
+      new RefactoringWorkspace(driverMap.values, searchEngine);
+
+  /**
    * The versions of each document known to the server (keyed by path), used to
    * send back to the client for server-initiated edits so that the client can
    * ensure they have a matching version of the document before applying them.
@@ -112,17 +124,25 @@
   final Map<int, Completer<ResponseMessage>> completers = {};
 
   /**
+   * Capabilities of the server. Will be null prior to initialization as
+   * the server capabilities depend on the client capabilities.
+   */
+  ServerCapabilities capabilities;
+
+  LspPerformance performanceStats = new LspPerformance();
+
+  /**
    * Initialize a newly created server to send and receive messages to the given
    * [channel].
    */
   LspAnalysisServer(
     this.channel,
     ResourceProvider baseResourceProvider,
-    this.options,
+    AnalysisServerOptions options,
     this.sdkManager,
     this.instrumentationService, {
     ResolverProvider packageResolverProvider: null,
-  }) : super(baseResourceProvider) {
+  }) : super(options, baseResourceProvider) {
     messageHandler = new UninitializedStateMessageHandler(this);
     defaultContextOptions.generateImplicitErrors = false;
     defaultContextOptions.useFastaParser = options.useFastaParser;
@@ -206,6 +226,13 @@
             null, new Uri.file(path).toString());
   }
 
+  void handleClientConnection(ClientCapabilities capabilities) {
+    _clientCapabilities = capabilities;
+
+    performanceAfterStartup = new ServerPerformance();
+    performance = performanceAfterStartup;
+  }
+
   /// Handles a response from the client by invoking the completer that the
   /// outbound request created.
   void handleClientResponse(ResponseMessage message) {
@@ -235,8 +262,7 @@
    * Handle a [message] that was read from the communication channel.
    */
   void handleMessage(Message message) {
-    // TODO(dantup): Put in all the things this server is missing, like:
-    //     _performance.logRequest(message);
+    performance.logRequestTiming(null);
     runZoned(() {
       ServerPerformanceStatistics.serverRequests.makeCurrentWhile(() async {
         try {
@@ -290,6 +316,17 @@
     ));
   }
 
+  void publishDiagnostics(String path, List<Diagnostic> errors) {
+    final params =
+        new PublishDiagnosticsParams(Uri.file(path).toString(), errors);
+    final message = new NotificationMessage(
+      Method.textDocument_publishDiagnostics,
+      params,
+      jsonRpcVersion,
+    );
+    sendNotification(message);
+  }
+
   removePriorityFile(String path) {
     final didRemove = priorityFiles.remove(path);
     assert(didRemove);
@@ -375,15 +412,22 @@
     // Log the full message since showMessage above may be truncated or formatted
     // badly (eg. VS Code takes the newlines out).
     logError(fullError.toString());
+
+    // remember the last few exceptions
+    if (exception is CaughtException) {
+      stackTrace ??= exception.stackTrace;
+    }
+    exceptions.add(new ServerException(
+      message,
+      exception,
+      stackTrace is StackTrace ? stackTrace : null,
+      false,
+    ));
   }
 
-  void setAnalysisRoots(List<String> includedPaths, List<String> excludedPaths,
-      Map<String, String> packageRoots) {
-    contextManager.setRoots(includedPaths, excludedPaths, packageRoots);
-  }
-
-  void setClientCapabilities(ClientCapabilities capabilities) {
-    _clientCapabilities = capabilities;
+  void setAnalysisRoots(List<String> includedPaths) {
+    final uniquePaths = HashSet<String>.of(includedPaths ?? const []);
+    contextManager.setRoots(uniquePaths.toList(), [], {});
   }
 
   /**
@@ -412,6 +456,16 @@
     return new Future.value();
   }
 
+  void updateAnalysisRoots(List<String> addedPaths, List<String> removedPaths) {
+    // TODO(dantup): This is currently case-sensitive!
+    final newPaths =
+        HashSet<String>.of(contextManager.includedPaths ?? const [])
+          ..addAll(addedPaths ?? const [])
+          ..removeAll(removedPaths ?? const []);
+
+    contextManager.setRoots(newPaths.toList(), [], {});
+  }
+
   void updateOverlay(String path, String contents) {
     if (contents != null) {
       resourceProvider.setOverlay(path,
@@ -429,6 +483,14 @@
   }
 }
 
+class LspPerformance {
+  /// A list of code completion performance measurements for the latest
+  /// completion operation up to [performanceListMaxLength] measurements.
+  final RecentBuffer<CompletionPerformance> completion =
+      new RecentBuffer<CompletionPerformance>(
+          CompletionDomainHandler.performanceListMaxLength);
+}
+
 class LspServerContextManagerCallbacks extends ContextManagerCallbacks {
   // TODO(dantup): Lots of copy/paste from the Analysis Server one here.
 
@@ -459,14 +521,7 @@
             result.errors,
             toDiagnostic);
 
-        final params = new PublishDiagnosticsParams(
-            Uri.file(result.path).toString(), serverErrors);
-        final message = new NotificationMessage(
-          Method.textDocument_publishDiagnostics,
-          params,
-          jsonRpcVersion,
-        );
-        analysisServer.sendNotification(message);
+        analysisServer.publishDiagnostics(result.path, serverErrors);
       }
     });
     analysisDriver.exceptions.listen((nd.ExceptionResult result) {
@@ -504,7 +559,7 @@
   @override
   void applyFileRemoved(nd.AnalysisDriver driver, String file) {
     driver.removeFile(file);
-    // sendAnalysisNotificationFlushResults(analysisServer, [file]);
+    analysisServer.publishDiagnostics(file, []);
   }
 
   @override
@@ -547,8 +602,10 @@
 
   @override
   void removeContext(Folder folder, List<String> flushedFiles) {
-    // sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
     nd.AnalysisDriver driver = analysisServer.driverMap.remove(folder);
+    // Flush any errors for these files that the client may be displaying.
+    flushedFiles
+        ?.forEach((path) => analysisServer.publishDiagnostics(path, const []));
     driver.dispose();
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
index 47261dc..25a15e1 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
@@ -19,7 +19,7 @@
  * the SocketServer is to manage the lifetime of the AnalysisServer and to
  * encode and decode the JSON messages exchanged with the client.
  */
-class LspSocketServer {
+class LspSocketServer implements AbstractSocketServer {
   final AnalysisServerOptions analysisServerOptions;
   /**
    * The analysis server that was created when a client established a
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index e97f557..d69d15d 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -1,9 +1,11 @@
 import 'dart:collection';
 
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart' as lsp;
-import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart'
+    show ResponseError;
 import 'package:analysis_server/lsp_protocol/protocol_special.dart' as lsp;
-import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart'
+    show ErrorOr, Either2, Either4;
 import 'package:analysis_server/src/lsp/constants.dart' as lsp;
 import 'package:analysis_server/src/lsp/dartdoc.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart' as lsp;
@@ -30,6 +32,21 @@
           _asMarkup(preferredFormats, content));
 }
 
+/// Note: This code will fetch the version of each document being modified so
+/// it's important to call this immediately after computing edits to ensure
+/// the document is not modified before the version number is read.
+lsp.WorkspaceEdit createWorkspaceEdit(
+    lsp.LspAnalysisServer server, server.SourceChange change) {
+  return toWorkspaceEdit(
+      server.clientCapabilities?.workspace,
+      change.edits
+          .map((e) => new FileEditInformation(
+              server.getVersionedDocumentIdentifier(e.file),
+              server.getLineInfo(e.file),
+              e.edits))
+          .toList());
+}
+
 lsp.CompletionItemKind elementKindToCompletionItemKind(
   HashSet<lsp.CompletionItemKind> clientSupportedCompletionKinds,
   server.ElementKind kind,
@@ -212,7 +229,7 @@
     return null;
   }
 
-  return new Location(
+  return new lsp.Location(
     Uri.file(targetFilePath).toString(),
     toRange(lineInfo, target.offset, target.length),
   );
@@ -261,7 +278,7 @@
     return null;
   }
 
-  return new Location(
+  return new lsp.Location(
     Uri.file(result.location.file).toString(),
     toRange(lineInfo, location.offset, location.length),
   );
@@ -400,6 +417,14 @@
   }
 }
 
+List<lsp.DocumentHighlight> toHighlights(
+    server.LineInfo lineInfo, server.Occurrences occurrences) {
+  return occurrences.offsets
+      .map((offset) => new lsp.DocumentHighlight(
+          toRange(lineInfo, offset, occurrences.length), null))
+      .toList();
+}
+
 ErrorOr<int> toOffset(
   server.LineInfo lineInfo,
   lsp.Position pos, {
@@ -505,41 +530,41 @@
 }
 
 lsp.TextDocumentEdit toTextDocumentEdit(FileEditInformation edit) {
-  return new TextDocumentEdit(
+  return new lsp.TextDocumentEdit(
     edit.doc,
     edit.edits.map((e) => toTextEdit(edit.lineInfo, e)).toList(),
   );
 }
 
 lsp.TextEdit toTextEdit(server.LineInfo lineInfo, server.SourceEdit edit) {
-  return new TextEdit(
+  return new lsp.TextEdit(
     toRange(lineInfo, edit.offset, edit.length),
     edit.replacement,
   );
 }
 
 lsp.WorkspaceEdit toWorkspaceEdit(
-  WorkspaceClientCapabilities capabilities,
+  lsp.WorkspaceClientCapabilities capabilities,
   List<FileEditInformation> edits,
 ) {
   final clientSupportsTextDocumentEdits =
       capabilities?.workspaceEdit?.documentChanges == true;
   if (clientSupportsTextDocumentEdits) {
-    return new WorkspaceEdit(
+    return new lsp.WorkspaceEdit(
         null,
         Either2<
-            List<TextDocumentEdit>,
+            List<lsp.TextDocumentEdit>,
             List<
-                Either4<TextDocumentEdit, CreateFile, RenameFile,
-                    DeleteFile>>>.t1(
+                Either4<lsp.TextDocumentEdit, lsp.CreateFile, lsp.RenameFile,
+                    lsp.DeleteFile>>>.t1(
           edits.map(toTextDocumentEdit).toList(),
         ));
   } else {
-    return new WorkspaceEdit(toWorkspaceEditChanges(edits), null);
+    return new lsp.WorkspaceEdit(toWorkspaceEditChanges(edits), null);
   }
 }
 
-Map<String, List<TextEdit>> toWorkspaceEditChanges(
+Map<String, List<lsp.TextEdit>> toWorkspaceEditChanges(
     List<FileEditInformation> edits) {
   createEdit(FileEditInformation file) {
     final edits =
@@ -547,7 +572,7 @@
     return new MapEntry(file.doc.uri, edits);
   }
 
-  return Map<String, List<TextEdit>>.fromEntries(edits.map(createEdit));
+  return Map<String, List<lsp.TextEdit>>.fromEntries(edits.map(createEdit));
 }
 
 lsp.MarkupContent _asMarkup(
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 9943cbd..87aa99d 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/notification_manager.dart b/pkg/analysis_server/lib/src/plugin/notification_manager.dart
index 344697c..120afe9 100644
--- a/pkg/analysis_server/lib/src/plugin/notification_manager.dart
+++ b/pkg/analysis_server/lib/src/plugin/notification_manager.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_locator.dart b/pkg/analysis_server/lib/src/plugin/plugin_locator.dart
index ba53ab3..14c7069 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_locator.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_locator.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
index 63be71f..de2cccf 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart b/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart
index e937e26..ecfe285 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/request_converter.dart b/pkg/analysis_server/lib/src/plugin/request_converter.dart
index 5caa071..9f0a071 100644
--- a/pkg/analysis_server/lib/src/plugin/request_converter.dart
+++ b/pkg/analysis_server/lib/src/plugin/request_converter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/result_collector.dart b/pkg/analysis_server/lib/src/plugin/result_collector.dart
index 04c3f09..dbee3d3 100644
--- a/pkg/analysis_server/lib/src/plugin/result_collector.dart
+++ b/pkg/analysis_server/lib/src/plugin/result_collector.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/result_converter.dart b/pkg/analysis_server/lib/src/plugin/result_converter.dart
index 40a5d2b..b73a280 100644
--- a/pkg/analysis_server/lib/src/plugin/result_converter.dart
+++ b/pkg/analysis_server/lib/src/plugin/result_converter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/plugin/result_merger.dart b/pkg/analysis_server/lib/src/plugin/result_merger.dart
index 43d0a56..1db0891 100644
--- a/pkg/analysis_server/lib/src/plugin/result_merger.dart
+++ b/pkg/analysis_server/lib/src/plugin/result_merger.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/protocol/protocol_internal.dart b/pkg/analysis_server/lib/src/protocol/protocol_internal.dart
index a36fc49..1d6ed2d 100644
--- a/pkg/analysis_server/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analysis_server/lib/src/protocol/protocol_internal.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index 2d6adce..a73691d 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
index f96c93e..c5ee92f 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index 79f3714f..37a6872 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 65be43a..ae98245 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 65eee55..e4bcfe5 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart b/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart
index dc2cead..1f45e5d 100644
--- a/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart
+++ b/pkg/analysis_server/lib/src/server/detachable_filesystem_manager.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/server/dev_server.dart b/pkg/analysis_server/lib/src/server/dev_server.dart
index 44bb21c..c8f52ea 100644
--- a/pkg/analysis_server/lib/src/server/dev_server.dart
+++ b/pkg/analysis_server/lib/src/server/dev_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/server/diagnostic_server.dart b/pkg/analysis_server/lib/src/server/diagnostic_server.dart
index b147a43..011c926 100644
--- a/pkg/analysis_server/lib/src/server/diagnostic_server.dart
+++ b/pkg/analysis_server/lib/src/server/diagnostic_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 21d5cc8..29d59bb 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -407,37 +407,10 @@
         defaultSdk.sdkVersion);
     AnalysisEngine.instance.instrumentationService = instrumentationService;
 
-    if (analysisServerOptions.useLanguageServerProtocol) {
-      startLspServer(results, analysisServerOptions, dartSdkManager,
-          instrumentationService);
-    } else {
-      startAnalysisServer(results, analysisServerOptions, parser,
-          dartSdkManager, instrumentationService, analytics);
-    }
-  }
-
-  void startAnalysisServer(
-      ArgResults results,
-      AnalysisServerOptions analysisServerOptions,
-      CommandLineParser parser,
-      DartSdkManager dartSdkManager,
-      InstrumentationService instrumentationService,
-      telemetry.Analytics analytics) {
-    String trainDirectory = results[TRAIN_USING];
-    if (trainDirectory != null) {
-      if (!FileSystemEntity.isDirectorySync(trainDirectory)) {
-        print("Training directory '$trainDirectory' not found.\n");
-        exitCode = 1;
-        return null;
-      }
-    }
-
-    int port;
-    bool serve_http = false;
+    int diagnosticServerPort;
     if (results[PORT_OPTION] != null) {
       try {
-        port = int.parse(results[PORT_OPTION]);
-        serve_http = true;
+        diagnosticServerPort = int.parse(results[PORT_OPTION]);
       } on FormatException {
         print('Invalid port number: ${results[PORT_OPTION]}');
         print('');
@@ -447,6 +420,40 @@
       }
     }
 
+    if (analysisServerOptions.useLanguageServerProtocol) {
+      startLspServer(results, analysisServerOptions, dartSdkManager,
+          instrumentationService, diagnosticServerPort);
+    } else {
+      startAnalysisServer(
+          results,
+          analysisServerOptions,
+          parser,
+          dartSdkManager,
+          instrumentationService,
+          analytics,
+          diagnosticServerPort);
+    }
+  }
+
+  void startAnalysisServer(
+    ArgResults results,
+    AnalysisServerOptions analysisServerOptions,
+    CommandLineParser parser,
+    DartSdkManager dartSdkManager,
+    InstrumentationService instrumentationService,
+    telemetry.Analytics analytics,
+    int diagnosticServerPort,
+  ) {
+    String trainDirectory = results[TRAIN_USING];
+    if (trainDirectory != null) {
+      if (!FileSystemEntity.isDirectorySync(trainDirectory)) {
+        print("Training directory '$trainDirectory' not found.\n");
+        exitCode = 1;
+        return null;
+      }
+    }
+    final serve_http = diagnosticServerPort != null;
+
     //
     // Process all of the plugins so that extensions are registered.
     //
@@ -474,7 +481,7 @@
 
     diagnosticServer.httpServer = httpServer;
     if (serve_http) {
-      diagnosticServer.startOnPort(port);
+      diagnosticServer.startOnPort(diagnosticServerPort);
     }
 
     if (trainDirectory != null) {
@@ -539,13 +546,25 @@
     AnalysisServerOptions analysisServerOptions,
     DartSdkManager dartSdkManager,
     InstrumentationService instrumentationService,
+    int diagnosticServerPort,
   ) {
+    final serve_http = diagnosticServerPort != null;
+
+    _DiagnosticServerImpl diagnosticServer = new _DiagnosticServerImpl();
+
     final socketServer = new LspSocketServer(
       analysisServerOptions,
       dartSdkManager,
       instrumentationService,
     );
 
+    httpServer = new HttpAnalysisServer(socketServer);
+
+    diagnosticServer.httpServer = httpServer;
+    if (serve_http) {
+      diagnosticServer.startOnPort(diagnosticServerPort);
+    }
+
     _captureLspExceptions(socketServer, instrumentationService, () {
       LspStdioAnalysisServer stdioServer =
           new LspStdioAnalysisServer(socketServer);
diff --git a/pkg/analysis_server/lib/src/server/http_server.dart b/pkg/analysis_server/lib/src/server/http_server.dart
index 5b51304..95e4d34 100644
--- a/pkg/analysis_server/lib/src/server/http_server.dart
+++ b/pkg/analysis_server/lib/src/server/http_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -35,7 +35,7 @@
    * An object that can handle either a WebSocket connection or a connection
    * to the client over stdio.
    */
-  SocketServer socketServer;
+  AbstractSocketServer socketServer;
 
   /**
    * An object that can handle GET requests.
diff --git a/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart b/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart
index 016bd11..1b5cde5 100644
--- a/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart
+++ b/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/server/stdio_server.dart b/pkg/analysis_server/lib/src/server/stdio_server.dart
index 1895444..f7e9305 100644
--- a/pkg/analysis_server/lib/src/server/stdio_server.dart
+++ b/pkg/analysis_server/lib/src/server/stdio_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_core.dart b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
index 02e617b..8b5b0a2 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_performance.dart b/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
index 37ee54e..61df502 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 a2857e1..f7ddb32 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
index 6b74935..7da0e3e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
index f065701..91975c7 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart b/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
index 6dfbf6f..eedd4d9 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
index 6f9d9b3..0f4025b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
index 0f6f992..ef19706 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
index d580fcd..77b4ebf 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
index 7a21679..35826f0 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
index 6b46436..e9d2506 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
index 4d8b351..3318bb5 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
index 007465e..f881357 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index 66a5fc6..a883a59 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
index 57a2f27..cc21160 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
index 405b772..aa25fba 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
index 087b39e..3f98f7e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index e1ba6f9..7c65f43 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index a4e03b3..f3974ce 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
index 6226346..46910af 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index 0f2b10b..409b979 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
index af2d9e3..82555b4 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart b/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
index 1c15d65..86231ae 100644
--- a/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 08a56a1..8601163 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/change_workspace.dart b/pkg/analysis_server/lib/src/services/correction/change_workspace.dart
index b7a2a23..c206924 100644
--- a/pkg/analysis_server/lib/src/services/correction/change_workspace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/change_workspace.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 29c0b2f..e9bf18d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 ebbf645..0db0fb2 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1334,14 +1334,19 @@
     if (constructorElement.enclosingElement is! ClassElement) {
       return;
     }
-    ClassElement targetElement = constructorElement.enclosingElement;
-    // prepare location for a new constructor
-    var targetNode = await _getClassDeclaration(targetElement);
-    if (targetNode == null) {
+
+    // prepare target ClassDeclaration
+    var targetElement = constructorElement.enclosingElement;
+    var targetResult = await sessionHelper.getElementDeclaration(targetElement);
+    if (targetResult.node is! ClassOrMixinDeclaration) {
       return;
     }
-    ClassMemberLocation targetLocation =
-        utils.prepareNewConstructorLocation(targetNode);
+    ClassOrMixinDeclaration targetNode = targetResult.node;
+
+    // prepare location
+    var targetLocation = CorrectionUtils(targetResult.resolvedUnit)
+        .prepareNewConstructorLocation(targetNode);
+
     Source targetSource = targetElement.source;
     String targetFile = targetSource.fullName;
     var changeBuilder = _newDartChangeBuilder();
@@ -1390,17 +1395,22 @@
     if (targetType is! InterfaceType) {
       return;
     }
-    // prepare location for a new constructor
-    ClassElement targetElement = targetType.element as ClassElement;
-    var targetNode = await _getClassDeclaration(targetElement);
-    if (targetNode == null) {
+
+    // prepare target ClassDeclaration
+    ClassElement targetElement = targetType.element;
+    var targetResult = await sessionHelper.getElementDeclaration(targetElement);
+    if (targetResult.node is! ClassOrMixinDeclaration) {
       return;
     }
-    ClassMemberLocation targetLocation =
-        utils.prepareNewConstructorLocation(targetNode);
+    ClassOrMixinDeclaration targetNode = targetResult.node;
+
+    // prepare location
+    var targetLocation = CorrectionUtils(targetResult.resolvedUnit)
+        .prepareNewConstructorLocation(targetNode);
+
     String targetFile = targetElement.source.fullName;
     var changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+    await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
       builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
         builder.write(targetLocation.prefix);
         builder.writeConstructorDeclaration(targetElement.name,
@@ -2147,8 +2157,10 @@
     _addFixFromBuilder(changeBuilder, kind, args: [uriText]);
   }
 
-  Future<void> _addFix_importLibrary_withElement(String name,
-      List<ElementKind> elementKinds, TopLevelDeclarationKind kind2) async {
+  Future<void> _addFix_importLibrary_withElement(
+      String name,
+      List<ElementKind> elementKinds,
+      List<TopLevelDeclarationKind> kinds2) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
     // ignore if private
@@ -2221,7 +2233,7 @@
       var declarations = await session.getTopLevelDeclarations(name);
       for (TopLevelDeclarationInSource declaration in declarations) {
         // Check the kind.
-        if (declaration.declaration.kind != kind2) {
+        if (!kinds2.contains(declaration.declaration.kind)) {
           continue;
         }
         // Check the source.
@@ -2259,8 +2271,13 @@
       MethodInvocation invocation = node.parent as MethodInvocation;
       if (invocation.realTarget == null && invocation.methodName == node) {
         String name = (node as SimpleIdentifier).name;
-        await _addFix_importLibrary_withElement(name,
-            const [ElementKind.FUNCTION], TopLevelDeclarationKind.function);
+        await _addFix_importLibrary_withElement(name, const [
+          ElementKind.FUNCTION,
+          ElementKind.TOP_LEVEL_VARIABLE
+        ], const [
+          TopLevelDeclarationKind.function,
+          TopLevelDeclarationKind.variable
+        ]);
       }
     }
   }
@@ -2273,7 +2290,7 @@
       await _addFix_importLibrary_withElement(
           name,
           const [ElementKind.TOP_LEVEL_VARIABLE],
-          TopLevelDeclarationKind.variable);
+          const [TopLevelDeclarationKind.variable]);
     }
   }
 
@@ -2285,11 +2302,11 @@
       await _addFix_importLibrary_withElement(
           typeName,
           const [ElementKind.CLASS, ElementKind.FUNCTION_TYPE_ALIAS],
-          TopLevelDeclarationKind.type);
+          const [TopLevelDeclarationKind.type]);
     } else if (_mayBeImplicitConstructor(node)) {
       String typeName = (node as SimpleIdentifier).name;
-      await _addFix_importLibrary_withElement(
-          typeName, const [ElementKind.CLASS], TopLevelDeclarationKind.type);
+      await _addFix_importLibrary_withElement(typeName,
+          const [ElementKind.CLASS], const [TopLevelDeclarationKind.type]);
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/levenshtein.dart b/pkg/analysis_server/lib/src/services/correction/levenshtein.dart
index 61cb493..13e16c2 100644
--- a/pkg/analysis_server/lib/src/services/correction/levenshtein.dart
+++ b/pkg/analysis_server/lib/src/services/correction/levenshtein.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
index 79e14d0..14e218e 100644
--- a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
+++ b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/sort_members.dart b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
index 04baf5f..a4bc4a8 100644
--- a/pkg/analysis_server/lib/src/services/correction/sort_members.dart
+++ b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/source_buffer.dart b/pkg/analysis_server/lib/src/services/correction/source_buffer.dart
index a414cd5..382bd1a 100644
--- a/pkg/analysis_server/lib/src/services/correction/source_buffer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/source_buffer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
index db39ca8..184c81b 100644
--- a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/status.dart b/pkg/analysis_server/lib/src/services/correction/status.dart
index 5cc4cc3..67ec9f8 100644
--- a/pkg/analysis_server/lib/src/services/correction/status.dart
+++ b/pkg/analysis_server/lib/src/services/correction/status.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/correction/strings.dart b/pkg/analysis_server/lib/src/services/correction/strings.dart
index 125fc14..87b6fe3 100644
--- a/pkg/analysis_server/lib/src/services/correction/strings.dart
+++ b/pkg/analysis_server/lib/src/services/correction/strings.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/kythe/schema.dart b/pkg/analysis_server/lib/src/services/kythe/schema.dart
index c354abb..339564a 100644
--- a/pkg/analysis_server/lib/src/services/kythe/schema.dart
+++ b/pkg/analysis_server/lib/src/services/kythe/schema.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 94010f7..34908db 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
index a068451..0963233 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart b/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
index 94bfd73..e830d48 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 223d699..7bcbb7b 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -434,6 +434,14 @@
   }
 }
 
+class RenameRefactoringElement {
+  final Element element;
+  final int offset;
+  final int length;
+
+  RenameRefactoringElement(this.element, this.offset, this.length);
+}
+
 /**
  * Abstract [Refactoring] for renaming some [Element].
  */
@@ -475,6 +483,41 @@
     return null;
   }
 
+  /// Given a node/element, finds the best element to rename (for example
+  /// the class when on the `new` keyword).
+  static RenameRefactoringElement getElementToRename(
+      AstNode node, Element element) {
+    int offset = node.offset;
+    int length = node.length;
+
+    if (element is FieldFormalParameterElement) {
+      element = (element as FieldFormalParameterElement).field;
+    }
+
+    // Use the prefix offset/length when renaming an import directive.
+    if (node is ImportDirective && element is ImportElement) {
+      if (node.prefix != null) {
+        offset = node.prefix.offset;
+        length = node.prefix.length;
+      } else {
+        // -1 means the name does not exist yet.
+        offset = -1;
+        length = 0;
+      }
+    }
+
+    // Rename the class when on `new` in an instance creation.
+    if (node is InstanceCreationExpression) {
+      InstanceCreationExpression creation = node;
+      var typeIdentifier = creation.constructorName.type.name;
+      element = typeIdentifier.staticElement;
+      offset = typeIdentifier.offset;
+      length = typeIdentifier.length;
+    }
+
+    return new RenameRefactoringElement(element, offset, length);
+  }
+
   /**
    * Returns the human-readable description of the kind of element being renamed
    * (such as “class” or “function type alias”).
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
index 2a81869..9fc3d94 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index b7663c0..e33f397 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index df98b9e..4f8afd4 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 6baadf4..e8d7555 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 2bc3c99..aebeba1 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
index 012f500..7dbe5bb 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
index 8ad6912..cb88700 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
index 5d20312..cb8683f 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/search/element_visitors.dart b/pkg/analysis_server/lib/src/services/search/element_visitors.dart
index 560edbb7..8dc34d9 100644
--- a/pkg/analysis_server/lib/src/services/search/element_visitors.dart
+++ b/pkg/analysis_server/lib/src/services/search/element_visitors.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index 8862eda..5689c32 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine.dart b/pkg/analysis_server/lib/src/services/search/search_engine.dart
index 74445c4..aa5aec9 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 f16268b..2868b74 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index 9e22d01..b9cdaf0 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -1,10 +1,11 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/analysis_server_abstract.dart';
 import 'package:analysis_server/src/channel/channel.dart';
 import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
 import 'package:analysis_server/src/server/diagnostic_server.dart';
@@ -13,13 +14,18 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/plugin/resolver_provider.dart';
 
+abstract class AbstractSocketServer {
+  AnalysisServerOptions get analysisServerOptions;
+  AbstractAnalysisServer get analysisServer;
+}
+
 /**
  * Instances of the class [SocketServer] implement the common parts of
  * http-based and stdio-based analysis servers.  The primary responsibility of
  * the SocketServer is to manage the lifetime of the AnalysisServer and to
  * encode and decode the JSON messages exchanged with the client.
  */
-class SocketServer {
+class SocketServer implements AbstractSocketServer {
   final AnalysisServerOptions analysisServerOptions;
 
   /**
diff --git a/pkg/analysis_server/lib/src/status/ast_writer.dart b/pkg/analysis_server/lib/src/status/ast_writer.dart
index 5458b27..060cf6f 100644
--- a/pkg/analysis_server/lib/src/status/ast_writer.dart
+++ b/pkg/analysis_server/lib/src/status/ast_writer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index 44fff0a..793b9c3 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -11,7 +11,10 @@
     show PROTOCOL_VERSION;
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/analysis_server_abstract.dart';
 import 'package:analysis_server/src/domain_completion.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart'
+    show LspAnalysisServer;
 import 'package:analysis_server/src/plugin/plugin_manager.dart';
 import 'package:analysis_server/src/server/http_server.dart';
 import 'package:analysis_server/src/services/completion/completion_performance.dart';
@@ -145,6 +148,8 @@
 }
 ''';
 
+/// TODO(devoncarew): We're not currently tracking the time spent in specific
+/// lints by default (analysisOptions / driverOptions enableTiming)
 final bool _showLints = false;
 
 String get _sdkVersion {
@@ -159,6 +164,74 @@
   return '$name: <code>$value</code><br> ';
 }
 
+abstract class AbstractCompletionPage extends DiagnosticPageWithNav {
+  AbstractCompletionPage(DiagnosticsSite site)
+      : super(site, 'completion', 'Code Completion',
+            description: 'Latency statistics for code completion.');
+
+  pathPackage.Context get pathContext;
+  List<CompletionPerformance> get performanceItems;
+
+  @override
+  Future generateContent(Map<String, String> params) async {
+    // TODO(brianwilkerson) Determine whether this await is necessary.
+    await null;
+
+    List<CompletionPerformance> completions = performanceItems;
+
+    if (completions.isEmpty) {
+      blankslate('No completions recorded.');
+      return;
+    }
+
+    int fastCount =
+        completions.where((c) => c.elapsedInMilliseconds <= 100).length;
+    p('${completions.length} results; ${printPercentage(fastCount / completions.length)} within 100ms.');
+
+    // draw a chart
+    buf.writeln(
+        '<div id="chart-div" style="width: 700px; height: 300px;"></div>');
+    StringBuffer rowData = new StringBuffer();
+    for (int i = completions.length - 1; i >= 0; i--) {
+      // [' ', 101.5]
+      if (rowData.isNotEmpty) {
+        rowData.write(',');
+      }
+      rowData.write("[' ', ${completions[i].elapsedInMilliseconds}]");
+    }
+    buf.writeln('''
+      <script type="text/javascript">
+      google.charts.load('current', {'packages':['bar']});
+      google.charts.setOnLoadCallback(drawChart);
+      function drawChart() {
+        var data = google.visualization.arrayToDataTable([
+          ['Completions', 'Time'],
+          $rowData
+        ]);
+        var options = { bars: 'vertical', vAxis: {format: 'decimal'}, height: 300 };
+        var chart = new google.charts.Bar(document.getElementById('chart-div'));
+        chart.draw(data, google.charts.Bar.convertOptions(options));
+      }
+      </script>
+''');
+
+    // emit the data as a table
+    buf.writeln('<table>');
+    buf.writeln(
+        '<tr><th>Time</th><th>Results</th><th>Source</th><th>Snippet</th></tr>');
+    for (CompletionPerformance completion in completions) {
+      String shortName = pathContext.basename(completion.path);
+      buf.writeln('<tr>'
+          '<td class="pre right">${printMilliseconds(completion.elapsedInMilliseconds)}</td>'
+          '<td class="right">${completion.suggestionCount}</td>'
+          '<td>${escape(shortName)}</td>'
+          '<td><code>${escape(completion.snippet)}</code></td>'
+          '</tr>');
+    }
+    buf.writeln('</table>');
+  }
+}
+
 class AstPage extends DiagnosticPageWithNav {
   String _description;
 
@@ -222,6 +295,7 @@
   Future generateContent(Map<String, String> params) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
+
     void writeRow(List<String> data, {List<String> classes}) {
       buf.write("<tr>");
       for (int i = 0; i < data.length; i++) {
@@ -237,28 +311,11 @@
 
     buf.writeln('<div class="columns">');
 
-    ServerPerformance perf = server.performanceAfterStartup;
-    if (perf != null) {
+    if (server.performanceAfterStartup != null) {
       buf.writeln('<div class="column one-half">');
+
       h3('Current');
-
-      int requestCount = perf.requestCount;
-      int averageLatency =
-          requestCount > 0 ? (perf.requestLatency ~/ requestCount) : 0;
-      int maximumLatency = perf.maxLatency;
-      double slowRequestPercent =
-          requestCount > 0 ? (perf.slowRequestCount / requestCount) : 0.0;
-
-      buf.write('<table>');
-      writeRow([printInteger(requestCount), 'requests'],
-          classes: ["right", null]);
-      writeRow([printMilliseconds(averageLatency), 'average latency'],
-          classes: ["right", null]);
-      writeRow([printMilliseconds(maximumLatency), 'maximum latency'],
-          classes: ["right", null]);
-      writeRow([printPercentage(slowRequestPercent), '> 150 ms latency'],
-          classes: ["right", null]);
-      buf.write('</table>');
+      _writePerformanceTable(server.performanceAfterStartup, writeRow);
 
       String time = server.uptime.toString();
       if (time.contains('.')) {
@@ -270,106 +327,64 @@
     }
 
     buf.writeln('<div class="column one-half">');
-    h3('Startup');
-    perf = server.performanceDuringStartup;
 
+    h3('Startup');
+    _writePerformanceTable(server.performanceDuringStartup, writeRow);
+
+    if (server.performanceAfterStartup != null) {
+      int startupTime = server.performanceAfterStartup.startTime -
+          server.performanceDuringStartup.startTime;
+      buf.writeln(
+          writeOption('Initial analysis time', printMilliseconds(startupTime)));
+    }
+
+    buf.write('</div>');
+
+    buf.write('</div>');
+  }
+
+  void _writePerformanceTable(ServerPerformance perf,
+      void writeRow(List<String> data, {List<String> classes})) {
     int requestCount = perf.requestCount;
+    int latencyCount = perf.latencyCount;
     int averageLatency =
-        requestCount > 0 ? (perf.requestLatency ~/ requestCount) : 0;
+        latencyCount > 0 ? (perf.requestLatency ~/ latencyCount) : 0;
     int maximumLatency = perf.maxLatency;
     double slowRequestPercent =
-        requestCount > 0 ? (perf.slowRequestCount / requestCount) : 0.0;
+        latencyCount > 0 ? (perf.slowRequestCount / latencyCount) : 0.0;
 
     buf.write('<table>');
     writeRow([printInteger(requestCount), 'requests'],
         classes: ["right", null]);
-    writeRow([printMilliseconds(averageLatency), 'average latency'],
+    writeRow([printInteger(latencyCount), 'requests with latency information'],
         classes: ["right", null]);
-    writeRow([printMilliseconds(maximumLatency), 'maximum latency'],
-        classes: ["right", null]);
-    writeRow([printPercentage(slowRequestPercent), '> 150 ms latency'],
-        classes: ["right", null]);
-    buf.write('</table>');
-
-    if (server.performanceAfterStartup != null) {
-      int startupTime =
-          server.performanceAfterStartup.startTime - perf.startTime;
-      buf.writeln(
-          writeOption('Initial analysis time', printMilliseconds(startupTime)));
+    if (latencyCount > 0) {
+      writeRow([printMilliseconds(averageLatency), 'average latency'],
+          classes: ["right", null]);
+      writeRow([printMilliseconds(maximumLatency), 'maximum latency'],
+          classes: ["right", null]);
+      writeRow([printPercentage(slowRequestPercent), '> 150 ms latency'],
+          classes: ["right", null]);
     }
-    buf.write('</div>');
-
-    buf.write('</div>');
+    buf.write('</table>');
   }
 }
 
-class CompletionPage extends DiagnosticPageWithNav {
-  CompletionPage(DiagnosticsSite site)
-      : super(site, 'completion', 'Code Completion',
-            description: 'Latency statistics for code completion.');
+class CompletionPage extends AbstractCompletionPage {
+  @override
+  AnalysisServer server;
+  CompletionPage(DiagnosticsSite site, this.server) : super(site);
+
+  CompletionDomainHandler get completionDomain => server.handlers
+      .firstWhere((handler) => handler is CompletionDomainHandler);
 
   @override
-  Future generateContent(Map<String, String> params) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    CompletionDomainHandler completionDomain = server.handlers
-        .firstWhere((handler) => handler is CompletionDomainHandler);
+  pathPackage.Context get pathContext =>
+      completionDomain.server.resourceProvider.pathContext;
 
-    List<CompletionPerformance> completions =
-        completionDomain.performanceList.items.toList();
-
-    if (completions.isEmpty) {
-      blankslate('No completions recorded.');
-      return;
-    }
-
-    int fastCount =
-        completions.where((c) => c.elapsedInMilliseconds <= 100).length;
-    p('${completions.length} results; ${printPercentage(fastCount / completions.length)} within 100ms.');
-
-    // draw a chart
-    buf.writeln(
-        '<div id="chart-div" style="width: 700px; height: 300px;"></div>');
-    StringBuffer rowData = new StringBuffer();
-    for (int i = completions.length - 1; i >= 0; i--) {
-      // [' ', 101.5]
-      if (rowData.isNotEmpty) {
-        rowData.write(',');
-      }
-      rowData.write("[' ', ${completions[i].elapsedInMilliseconds}]");
-    }
-    buf.writeln('''
-      <script type="text/javascript">
-      google.charts.load('current', {'packages':['bar']});
-      google.charts.setOnLoadCallback(drawChart);
-      function drawChart() {
-        var data = google.visualization.arrayToDataTable([
-          ['Completions', 'Time'],
-          $rowData
-        ]);
-        var options = { bars: 'vertical', vAxis: {format: 'decimal'}, height: 300 };
-        var chart = new google.charts.Bar(document.getElementById('chart-div'));
-        chart.draw(data, google.charts.Bar.convertOptions(options));
-      }
-      </script>
-''');
-
-    // emit the data as a table
-    buf.writeln('<table>');
-    buf.writeln(
-        '<tr><th>Time</th><th>Results</th><th>Source</th><th>Snippet</th></tr>');
-    var pathContext = completionDomain.server.resourceProvider.pathContext;
-    for (CompletionPerformance completion in completions) {
-      String shortName = pathContext.basename(completion.path);
-      buf.writeln('<tr>'
-          '<td class="pre right">${printMilliseconds(completion.elapsedInMilliseconds)}</td>'
-          '<td class="right">${completion.suggestionCount}</td>'
-          '<td>${escape(shortName)}</td>'
-          '<td><code>${escape(completion.snippet)}</code></td>'
-          '</tr>');
-    }
-    buf.writeln('</table>');
-  }
+  @override
+  List<CompletionPerformance> get performanceItems =>
+      completionDomain.performanceList.items.toList();
 }
 
 class ContextsPage extends DiagnosticPageWithNav {
@@ -575,15 +590,14 @@
 
 /// A page with a proscriptive notion of layout.
 abstract class DiagnosticPage extends Page {
-  final Site site;
+  final DiagnosticsSite site;
 
   DiagnosticPage(this.site, String id, String title, {String description})
       : super(id, title, description: description);
 
   bool get isNavPage => false;
 
-  AnalysisServer get server =>
-      (site as DiagnosticsSite).socketServer.analysisServer;
+  AbstractAnalysisServer get server => site.socketServer.analysisServer;
 
   Future<void> generateContainer(Map<String, String> params) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
@@ -661,7 +675,7 @@
 }
 
 abstract class DiagnosticPageWithNav extends DiagnosticPage {
-  DiagnosticPageWithNav(Site site, String id, String title,
+  DiagnosticPageWithNav(DiagnosticsSite site, String id, String title,
       {String description})
       : super(site, id, title, description: description);
 
@@ -711,22 +725,31 @@
 class DiagnosticsSite extends Site implements AbstractGetHandler {
   /// An object that can handle either a WebSocket connection or a connection
   /// to the client over stdio.
-  SocketServer socketServer;
+  AbstractSocketServer socketServer;
 
   /// The last few lines printed.
   final List<String> lastPrintedLines;
 
   DiagnosticsSite(this.socketServer, this.lastPrintedLines)
       : super('Analysis Server') {
-    pages.add(new CompletionPage(this));
     pages.add(new CommunicationsPage(this));
     pages.add(new ContextsPage(this));
     pages.add(new EnvironmentVariablesPage(this));
     pages.add(new ExceptionsPage(this));
     pages.add(new InstrumentationPage(this));
-    pages.add(new PluginsPage(this));
     pages.add(new ProfilePage(this));
-    pages.add(new SubscriptionsPage(this));
+
+    // Add server-specific pages. Ordering doesn't matter as the items are
+    // sorted later.
+    final server = this.socketServer.analysisServer;
+    if (server is AnalysisServer) {
+      pages.add(new CompletionPage(this, server));
+      pages.add(new PluginsPage(this, server));
+      pages.add(new SubscriptionsPage(this, server));
+    } else if (server is LspAnalysisServer) {
+      pages.add(new LspCompletionPage(this, server));
+      pages.add(new LspCapabilitiesPage(this, server));
+    }
 
     ProcessProfiler profiler = ProcessProfiler.getProfilerForPlatform();
     if (profiler != null) {
@@ -831,7 +854,7 @@
 class ExceptionPage extends DiagnosticPage {
   final StackTrace trace;
 
-  ExceptionPage(Site site, String message, this.trace)
+  ExceptionPage(DiagnosticsSite site, String message, this.trace)
       : super(site, '', '500 Oops', description: message);
 
   Future generateContent(Map<String, String> params) async {
@@ -948,6 +971,51 @@
   }
 }
 
+class LspCapabilitiesPage extends DiagnosticPageWithNav {
+  @override
+  LspAnalysisServer server;
+
+  LspCapabilitiesPage(DiagnosticsSite site, this.server)
+      : super(site, 'lsp_capabilities', 'LSP Capabilities',
+            description: 'Client and Server LSP Capabilities.');
+
+  @override
+  Future generateContent(Map<String, String> params) async {
+    buf.writeln('<div class="columns">');
+
+    buf.writeln('<div class="column one-half">');
+    h3('Client Capabilities');
+    if (server.clientCapabilities == null) {
+      p('Client capabilities have not yet been received.');
+    } else {
+      prettyJson(server.clientCapabilities.toJson());
+    }
+    buf.writeln('</div>');
+
+    buf.writeln('<div class="column one-half">');
+    h3('Server Capabilities');
+    if (server.capabilities == null) {
+      p('Server capabilities have not yet been computed.');
+    } else {
+      prettyJson(server.capabilities.toJson());
+    }
+    buf.writeln('</div>');
+  }
+}
+
+class LspCompletionPage extends AbstractCompletionPage {
+  @override
+  LspAnalysisServer server;
+  LspCompletionPage(DiagnosticsSite site, this.server) : super(site);
+
+  @override
+  pathPackage.Context get pathContext => server.resourceProvider.pathContext;
+
+  @override
+  List<CompletionPerformance> get performanceItems =>
+      server.performanceStats.completion.items.toList();
+}
+
 class MemoryAndCpuPage extends DiagnosticPageWithNav {
   final ProcessProfiler profiler;
 
@@ -1018,7 +1086,7 @@
 class NotFoundPage extends DiagnosticPage {
   final String path;
 
-  NotFoundPage(Site site, this.path)
+  NotFoundPage(DiagnosticsSite site, this.path)
       : super(site, '', '404 Not found', description: "'$path' not found.");
 
   Future generateContent(Map<String, String> params) async {
@@ -1027,16 +1095,18 @@
   }
 }
 
-// TODO(devoncarew): We're not currently tracking the time spent in specific
-// lints by default (analysisOptions / driverOptions enableTiming)
 class PluginsPage extends DiagnosticPageWithNav {
-  PluginsPage(DiagnosticsSite site)
+  @override
+  AnalysisServer server;
+
+  PluginsPage(DiagnosticsSite site, this.server)
       : super(site, 'plugins', 'Plugins', description: 'Plugins in use.');
 
   @override
   Future generateContent(Map<String, String> params) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
+
     h3('Analysis plugins');
     List<PluginInfo> analysisPlugins = server.pluginManager.plugins;
 
@@ -1255,6 +1325,7 @@
 
     buf.writeln('<div class="column one-half">');
     h3('Status');
+    buf.writeln(writeOption('Server type', server.runtimeType));
     buf.writeln(writeOption('Instrumentation enabled',
         AnalysisEngine.instance.instrumentationService.isActive));
     bool uxExp1 =
@@ -1276,7 +1347,7 @@
 
     buf.writeln('</div>');
 
-    List<String> lines = (site as DiagnosticsSite).lastPrintedLines;
+    List<String> lines = site.lastPrintedLines;
     if (lines.isNotEmpty) {
       h3('Debug output');
       p(lines.join('\n'), style: 'white-space: pre');
@@ -1285,7 +1356,10 @@
 }
 
 class SubscriptionsPage extends DiagnosticPageWithNav {
-  SubscriptionsPage(DiagnosticsSite site)
+  @override
+  AnalysisServer server;
+
+  SubscriptionsPage(DiagnosticsSite site, this.server)
       : super(site, 'subscriptions', 'Subscriptions',
             description: 'Registered subscriptions to analysis server events.');
 
@@ -1293,6 +1367,7 @@
   Future generateContent(Map<String, String> params) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
+
     // server domain
     h3('Server domain subscriptions');
     ul(ServerService.VALUES, (item) {
diff --git a/pkg/analysis_server/lib/src/status/element_writer.dart b/pkg/analysis_server/lib/src/status/element_writer.dart
index 3b6ac79..4e8d3ec 100644
--- a/pkg/analysis_server/lib/src/status/element_writer.dart
+++ b/pkg/analysis_server/lib/src/status/element_writer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/status/pages.dart b/pkg/analysis_server/lib/src/status/pages.dart
index 41b9b80..ff199b9 100644
--- a/pkg/analysis_server/lib/src/status/pages.dart
+++ b/pkg/analysis_server/lib/src/status/pages.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -122,6 +122,13 @@
     buf.writeln('</pre>');
   }
 
+  void prettyJson(Map<String, dynamic> data) {
+    const jsonEncoder = const JsonEncoder.withIndent('  ');
+    pre(() {
+      buf.write(jsonEncoder.convert(data));
+    });
+  }
+
   void ul<T>(Iterable<T> items, void gen(T item), {String classes}) {
     buf.writeln('<ul${classes == null ? '' : ' class=$classes'}>');
     for (T item in items) {
diff --git a/pkg/analysis_server/lib/src/status/tree_writer.dart b/pkg/analysis_server/lib/src/status/tree_writer.dart
index 62b07f1..130c4ad 100644
--- a/pkg/analysis_server/lib/src/status/tree_writer.dart
+++ b/pkg/analysis_server/lib/src/status/tree_writer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/utilities/documentation.dart b/pkg/analysis_server/lib/src/utilities/documentation.dart
index 2cc837e..b47bb2f 100644
--- a/pkg/analysis_server/lib/src/utilities/documentation.dart
+++ b/pkg/analysis_server/lib/src/utilities/documentation.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/utilities/flutter.dart b/pkg/analysis_server/lib/src/utilities/flutter.dart
index 6e754c3..3c63b01 100644
--- a/pkg/analysis_server/lib/src/utilities/flutter.dart
+++ b/pkg/analysis_server/lib/src/utilities/flutter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/utilities/null_string_sink.dart b/pkg/analysis_server/lib/src/utilities/null_string_sink.dart
index 27fef3a..d43c821 100644
--- a/pkg/analysis_server/lib/src/utilities/null_string_sink.dart
+++ b/pkg/analysis_server/lib/src/utilities/null_string_sink.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/lib/src/utilities/profiling.dart b/pkg/analysis_server/lib/src/utilities/profiling.dart
index 9dbd260..d283e10 100644
--- a/pkg/analysis_server/lib/src/utilities/profiling.dart
+++ b/pkg/analysis_server/lib/src/utilities/profiling.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/src/watch_manager.dart b/pkg/analysis_server/lib/src/watch_manager.dart
index 8a3fc97..f7bd8c9 100644
--- a/pkg/analysis_server/lib/src/watch_manager.dart
+++ b/pkg/analysis_server/lib/src/watch_manager.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/lib/starter.dart b/pkg/analysis_server/lib/starter.dart
index 949e761..170c4b8 100644
--- a/pkg/analysis_server/lib/starter.dart
+++ b/pkg/analysis_server/lib/starter.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index cb0baa7..db150ad 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index ac43af1..faadc26 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index d620a0d..cc31c34 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/get_signature_test.dart b/pkg/analysis_server/test/analysis/get_signature_test.dart
index 10567ce..e91c889 100644
--- a/pkg/analysis_server/test/analysis/get_signature_test.dart
+++ b/pkg/analysis_server/test/analysis/get_signature_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
index 90b04f2..4f5ed10 100644
--- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart b/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
index 305acd3..bd83a7d 100644
--- a/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_closingLabels_test.dart b/pkg/analysis_server/test/analysis/notification_closingLabels_test.dart
index d09ef04..a8a2d10 100644
--- a/pkg/analysis_server/test/analysis/notification_closingLabels_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_closingLabels_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index 773fd9f..a270f6c 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_folding_test.dart b/pkg/analysis_server/test/analysis/notification_folding_test.dart
index 3adbf5b..492718f 100644
--- a/pkg/analysis_server/test/analysis/notification_folding_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_folding_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index 54793b6..1046cbe 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test.dart b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
index f36e5d8..030addf 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index ebcd3a7..4401087 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 8035395..7a7aa0f 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
index df66d76..be5f9ff 100644
--- a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index a358bba..c9b26aa 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index aa9a69d..dfaec37 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 1606a84..3d745d7 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index 993fb07..bb6530d 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
index 9628319..5b8b7e9 100644
--- a/pkg/analysis_server/test/analysis/test_all.dart
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 079ec1c..5ab9a4e 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/benchmarks_test.dart b/pkg/analysis_server/test/benchmarks_test.dart
index 96c4c0f..21e70e5 100644
--- a/pkg/analysis_server/test/benchmarks_test.dart
+++ b/pkg/analysis_server/test/benchmarks_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.=> defineTests();
 
diff --git a/pkg/analysis_server/test/channel/byte_stream_channel_test.dart b/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
index f6a0692..a11b461 100644
--- a/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
+++ b/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/channel/test_all.dart b/pkg/analysis_server/test/channel/test_all.dart
index ce5e85a..3edd228 100644
--- a/pkg/analysis_server/test/channel/test_all.dart
+++ b/pkg/analysis_server/test/channel/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index 50b8449..d0cd508 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
index 06829ed..0af04a9 100644
--- a/pkg/analysis_server/test/completion_test_support.dart
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 3c5a3e7..4a7e95d 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -1681,7 +1681,7 @@
   ]);
 
   AnalysisError invalid_assignment_error =
-      new AnalysisError(null, 0, 1, HintCode.INVALID_ASSIGNMENT, [
+      new AnalysisError(null, 0, 1, StaticTypeWarningCode.INVALID_ASSIGNMENT, [
     ['x'],
     ['y']
   ]);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 5c57465..f22f2f2 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/domain_completion_util.dart b/pkg/analysis_server/test/domain_completion_util.dart
index 7d0721b..190c397 100644
--- a/pkg/analysis_server/test/domain_completion_util.dart
+++ b/pkg/analysis_server/test/domain_completion_util.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index 7a84c54..987506c 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/domain_edit_dartfix_test.dart b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
index 16bcdd2..edd543c 100644
--- a/pkg/analysis_server/test/domain_edit_dartfix_test.dart
+++ b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
@@ -111,6 +111,55 @@
     ''');
   }
 
+  test_dartfix_non_nullable() async {
+    // Add analysis options to enable non-nullable analysis
+    newFile('/project/analysis_options.yaml', content: '''
+analyzer:
+  enable-experiment:
+    - non-nullable
+''');
+
+    createProject();
+    addTestFile('''
+main() {
+  functionWithNullableParam(new List<Object>(1));
+  functionWithNullableParam(null);
+}
+
+void functionWithNullableParam(Object object) {
+  if (object == null) {
+    print('object is null');
+  } else {
+    print('object is not-null');
+  }
+  List<Object> list = null;
+  list = <Object>[];
+  list.add(object);
+}
+''');
+    EditDartfixResult result = await performFix();
+    expect(result.suggestions, hasLength(1));
+    expect(result.hasErrors, isFalse);
+    expectSuggestion(result.suggestions[0], 'non-nullable', 46, 6);
+    expectEdits(result.edits, '''
+main() {
+  functionWithNullableParam(new List<Object?>(1));
+  functionWithNullableParam(null);
+}
+
+void functionWithNullableParam(Object? object) {
+  if (object == null) {
+    print('object is null');
+  } else {
+    print('object is not-null');
+  }
+  List<Object?>? list = null;
+  list = <Object?>[];
+  list.add(object);
+}
+''');
+  }
+
   test_dartfix_excludedSource() async {
     // Add analysis options to exclude the lib directory then reanalyze
     newFile('/project/analysis_options.yaml', content: '''
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 1d8389f..120b2de 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/assists_test.dart b/pkg/analysis_server/test/edit/assists_test.dart
index 399706d..d8a77f0 100644
--- a/pkg/analysis_server/test/edit/assists_test.dart
+++ b/pkg/analysis_server/test/edit/assists_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/format_test.dart b/pkg/analysis_server/test/edit/format_test.dart
index ced5eab..1c18cbf 100644
--- a/pkg/analysis_server/test/edit/format_test.dart
+++ b/pkg/analysis_server/test/edit/format_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
index 9ca4c06..e8424aa 100644
--- a/pkg/analysis_server/test/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/postfix_completion_test.dart b/pkg/analysis_server/test/edit/postfix_completion_test.dart
index 7a64a92..00139e5 100644
--- a/pkg/analysis_server/test/edit/postfix_completion_test.dart
+++ b/pkg/analysis_server/test/edit/postfix_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index b696ea8..da70280 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/sort_members_test.dart b/pkg/analysis_server/test/edit/sort_members_test.dart
index 2da9a0a..04828b6 100644
--- a/pkg/analysis_server/test/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/edit/sort_members_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/statement_completion_test.dart b/pkg/analysis_server/test/edit/statement_completion_test.dart
index 7df82ba..50f834b 100644
--- a/pkg/analysis_server/test/edit/statement_completion_test.dart
+++ b/pkg/analysis_server/test/edit/statement_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/edit/test_all.dart b/pkg/analysis_server/test/edit/test_all.dart
index 1376ea6..79cc139 100644
--- a/pkg/analysis_server/test/edit/test_all.dart
+++ b/pkg/analysis_server/test/edit/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart b/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
index e27f275..6088003 100644
--- a/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/error_test.dart b/pkg/analysis_server/test/integration/analysis/error_test.dart
index 1c32caa..4da91dc 100644
--- a/pkg/analysis_server/test/integration/analysis/error_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/error_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk_test.dart b/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk_test.dart
index 4b102a6..c9be4cd 100644
--- a/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_test.dart b/pkg/analysis_server/test/integration/analysis/get_errors_test.dart
index d549e9e..f9e0c95 100644
--- a/pkg/analysis_server/test/integration/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_errors_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
index 8c179cc..e2f25af 100644
--- a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_imported_elements_test.dart b/pkg/analysis_server/test/integration/analysis/get_imported_elements_test.dart
index 65deb3b..29e8ec6 100644
--- a/pkg/analysis_server/test/integration/analysis/get_imported_elements_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_imported_elements_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_library_dependencies_test.dart b/pkg/analysis_server/test/integration/analysis/get_library_dependencies_test.dart
index 51a7659..7f30150 100644
--- a/pkg/analysis_server/test/integration/analysis/get_library_dependencies_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_library_dependencies_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart b/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart
index 9725e58..b3943bc 100644
--- a/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_navigation_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/get_reachable_sources_test.dart b/pkg/analysis_server/test/integration/analysis/get_reachable_sources_test.dart
index eb2ea8b..286a24e 100644
--- a/pkg/analysis_server/test/integration/analysis/get_reachable_sources_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_reachable_sources_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/highlights2_test.dart b/pkg/analysis_server/test/integration/analysis/highlights2_test.dart
index d9f1ebc..d837ff2 100644
--- a/pkg/analysis_server/test/integration/analysis/highlights2_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/highlights2_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/highlights_test.dart b/pkg/analysis_server/test/integration/analysis/highlights_test.dart
index 613a45d..95dfea5 100644
--- a/pkg/analysis_server/test/integration/analysis/highlights_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/highlights_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/hint_sdk_version_async_exported_from_core_test.dart b/pkg/analysis_server/test/integration/analysis/hint_sdk_version_async_exported_from_core_test.dart
index 6703374..585120f 100644
--- a/pkg/analysis_server/test/integration/analysis/hint_sdk_version_async_exported_from_core_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/hint_sdk_version_async_exported_from_core_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/integration/analysis/lint_test.dart b/pkg/analysis_server/test/integration/analysis/lint_test.dart
index 699b43b..ebe8986 100644
--- a/pkg/analysis_server/test/integration/analysis/lint_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/lint_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/navigation_test.dart b/pkg/analysis_server/test/integration/analysis/navigation_test.dart
index 1302b67..61c3f86 100644
--- a/pkg/analysis_server/test/integration/analysis/navigation_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/navigation_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/occurrences_test.dart b/pkg/analysis_server/test/integration/analysis/occurrences_test.dart
index 35a9416..787aa63 100644
--- a/pkg/analysis_server/test/integration/analysis/occurrences_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/occurrences_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/outline_test.dart b/pkg/analysis_server/test/integration/analysis/outline_test.dart
index eafefe8..41ec2b9 100644
--- a/pkg/analysis_server/test/integration/analysis/outline_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/outline_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/overrides_test.dart b/pkg/analysis_server/test/integration/analysis/overrides_test.dart
index 32c238c..a045fb6 100644
--- a/pkg/analysis_server/test/integration/analysis/overrides_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/overrides_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/package_root_test.dart b/pkg/analysis_server/test/integration/analysis/package_root_test.dart
index 0491f9b..09c94a4 100644
--- a/pkg/analysis_server/test/integration/analysis/package_root_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/package_root_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/reanalyze_concurrent_test.dart b/pkg/analysis_server/test/integration/analysis/reanalyze_concurrent_test.dart
index cb707e2..e79a1e1 100644
--- a/pkg/analysis_server/test/integration/analysis/reanalyze_concurrent_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/reanalyze_concurrent_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/reanalyze_test.dart b/pkg/analysis_server/test/integration/analysis/reanalyze_test.dart
index 8740ef0..60fe554 100644
--- a/pkg/analysis_server/test/integration/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/reanalyze_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/set_analysis_roots_test.dart b/pkg/analysis_server/test/integration/analysis/set_analysis_roots_test.dart
index f6c1d61..c0aa33e 100644
--- a/pkg/analysis_server/test/integration/analysis/set_analysis_roots_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/set_analysis_roots_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/set_general_subscriptions_test.dart b/pkg/analysis_server/test/integration/analysis/set_general_subscriptions_test.dart
index ce90165..eeef19e 100644
--- a/pkg/analysis_server/test/integration/analysis/set_general_subscriptions_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/set_general_subscriptions_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/integration/analysis/set_priority_files_test.dart
index 10cb1a0..e1ef4cf 100644
--- a/pkg/analysis_server/test/integration/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/set_priority_files_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/set_subscriptions_test.dart b/pkg/analysis_server/test/integration/analysis/set_subscriptions_test.dart
index 9524b4d..b5d60d4 100644
--- a/pkg/analysis_server/test/integration/analysis/set_subscriptions_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/set_subscriptions_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/test_all.dart b/pkg/analysis_server/test/integration/analysis/test_all.dart
index d85814a..a0cdc52 100644
--- a/pkg/analysis_server/test/integration/analysis/test_all.dart
+++ b/pkg/analysis_server/test/integration/analysis/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/update_content_list_test.dart b/pkg/analysis_server/test/integration/analysis/update_content_list_test.dart
index d44cce7..6c28e46 100644
--- a/pkg/analysis_server/test/integration/analysis/update_content_list_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/update_content_list_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/update_content_test.dart b/pkg/analysis_server/test/integration/analysis/update_content_test.dart
index cc4ceae..c25b133 100644
--- a/pkg/analysis_server/test/integration/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/update_content_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analysis/update_options_test.dart b/pkg/analysis_server/test/integration/analysis/update_options_test.dart
index 1172d78..b61db22 100644
--- a/pkg/analysis_server/test/integration/analysis/update_options_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/update_options_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analytics/enable_test.dart b/pkg/analysis_server/test/integration/analytics/enable_test.dart
index 72e261d..19296ee 100644
--- a/pkg/analysis_server/test/integration/analytics/enable_test.dart
+++ b/pkg/analysis_server/test/integration/analytics/enable_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analytics/is_enabled_test.dart b/pkg/analysis_server/test/integration/analytics/is_enabled_test.dart
index 8e2ffd5..15b5cf8 100644
--- a/pkg/analysis_server/test/integration/analytics/is_enabled_test.dart
+++ b/pkg/analysis_server/test/integration/analytics/is_enabled_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analytics/send_event_test.dart b/pkg/analysis_server/test/integration/analytics/send_event_test.dart
index fbeb48a..5a0b09e 100644
--- a/pkg/analysis_server/test/integration/analytics/send_event_test.dart
+++ b/pkg/analysis_server/test/integration/analytics/send_event_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analytics/send_timing_test.dart b/pkg/analysis_server/test/integration/analytics/send_timing_test.dart
index fb65d8a..141e3b7 100644
--- a/pkg/analysis_server/test/integration/analytics/send_timing_test.dart
+++ b/pkg/analysis_server/test/integration/analytics/send_timing_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/analytics/test_all.dart b/pkg/analysis_server/test/integration/analytics/test_all.dart
index d4352b7..f9e7963 100644
--- a/pkg/analysis_server/test/integration/analytics/test_all.dart
+++ b/pkg/analysis_server/test/integration/analytics/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart b/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
index cf031cf..888a1d2 100644
--- a/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
+++ b/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/completion/test_all.dart b/pkg/analysis_server/test/integration/completion/test_all.dart
index f07053b..1b5962b 100644
--- a/pkg/analysis_server/test/integration/completion/test_all.dart
+++ b/pkg/analysis_server/test/integration/completion/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/coverage_test.dart b/pkg/analysis_server/test/integration/coverage_test.dart
index b8b3c14..a1e5284 100644
--- a/pkg/analysis_server/test/integration/coverage_test.dart
+++ b/pkg/analysis_server/test/integration/coverage_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart b/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart
index e8bf76e..1eb2a17 100644
--- a/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart
+++ b/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart b/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart
index 37efe2c..6005964 100644
--- a/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart
+++ b/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/diagnostic/test_all.dart b/pkg/analysis_server/test/integration/diagnostic/test_all.dart
index 4e45dea..5265193 100644
--- a/pkg/analysis_server/test/integration/diagnostic/test_all.dart
+++ b/pkg/analysis_server/test/integration/diagnostic/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/format_test.dart b/pkg/analysis_server/test/integration/edit/format_test.dart
index 8906109..8380c5b 100644
--- a/pkg/analysis_server/test/integration/edit/format_test.dart
+++ b/pkg/analysis_server/test/integration/edit/format_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/get_assists_test.dart b/pkg/analysis_server/test/integration/edit/get_assists_test.dart
index 69e10f0..f2b57dc 100644
--- a/pkg/analysis_server/test/integration/edit/get_assists_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_assists_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/get_available_refactorings_test.dart b/pkg/analysis_server/test/integration/edit/get_available_refactorings_test.dart
index 820b586..ddbcfe6 100644
--- a/pkg/analysis_server/test/integration/edit/get_available_refactorings_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_available_refactorings_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/get_fixes_test.dart b/pkg/analysis_server/test/integration/edit/get_fixes_test.dart
index cfe923e..81af6dea 100644
--- a/pkg/analysis_server/test/integration/edit/get_fixes_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_fixes_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/get_postfix_completion_test.dart b/pkg/analysis_server/test/integration/edit/get_postfix_completion_test.dart
index 598b4c0..4e0257e 100644
--- a/pkg/analysis_server/test/integration/edit/get_postfix_completion_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_postfix_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/get_refactoring_test.dart b/pkg/analysis_server/test/integration/edit/get_refactoring_test.dart
index c3e5553..93c34fe 100644
--- a/pkg/analysis_server/test/integration/edit/get_refactoring_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_refactoring_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/get_statement_completion_test.dart b/pkg/analysis_server/test/integration/edit/get_statement_completion_test.dart
index 610ece0..b3caa20 100644
--- a/pkg/analysis_server/test/integration/edit/get_statement_completion_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_statement_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/import_elements_test.dart b/pkg/analysis_server/test/integration/edit/import_elements_test.dart
index 9beed5a..842f470 100644
--- a/pkg/analysis_server/test/integration/edit/import_elements_test.dart
+++ b/pkg/analysis_server/test/integration/edit/import_elements_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/is_postfix_completion_applicable_test.dart b/pkg/analysis_server/test/integration/edit/is_postfix_completion_applicable_test.dart
index be1ff11..7c65699 100644
--- a/pkg/analysis_server/test/integration/edit/is_postfix_completion_applicable_test.dart
+++ b/pkg/analysis_server/test/integration/edit/is_postfix_completion_applicable_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/list_postfix_completion_templates_test.dart b/pkg/analysis_server/test/integration/edit/list_postfix_completion_templates_test.dart
index f248e06..63f13e4 100644
--- a/pkg/analysis_server/test/integration/edit/list_postfix_completion_templates_test.dart
+++ b/pkg/analysis_server/test/integration/edit/list_postfix_completion_templates_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/organize_directives_test.dart b/pkg/analysis_server/test/integration/edit/organize_directives_test.dart
index 0e372f4..e5b0a46 100644
--- a/pkg/analysis_server/test/integration/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/integration/edit/organize_directives_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/sort_members_test.dart b/pkg/analysis_server/test/integration/edit/sort_members_test.dart
index 3ff78a7..1896537 100644
--- a/pkg/analysis_server/test/integration/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/integration/edit/sort_members_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/edit/test_all.dart b/pkg/analysis_server/test/integration/edit/test_all.dart
index 81aa121..6706806 100644
--- a/pkg/analysis_server/test/integration/edit/test_all.dart
+++ b/pkg/analysis_server/test/integration/edit/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/execution/create_context_test.dart b/pkg/analysis_server/test/integration/execution/create_context_test.dart
index 6564810..f73fe9a 100644
--- a/pkg/analysis_server/test/integration/execution/create_context_test.dart
+++ b/pkg/analysis_server/test/integration/execution/create_context_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/execution/delete_context_test.dart b/pkg/analysis_server/test/integration/execution/delete_context_test.dart
index c807fa5..a22a9e8 100644
--- a/pkg/analysis_server/test/integration/execution/delete_context_test.dart
+++ b/pkg/analysis_server/test/integration/execution/delete_context_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/execution/map_uri_test.dart b/pkg/analysis_server/test/integration/execution/map_uri_test.dart
index f5abbc0..8038545 100644
--- a/pkg/analysis_server/test/integration/execution/map_uri_test.dart
+++ b/pkg/analysis_server/test/integration/execution/map_uri_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/execution/set_subscriptions_test.dart b/pkg/analysis_server/test/integration/execution/set_subscriptions_test.dart
index 441093b..a95fc27 100644
--- a/pkg/analysis_server/test/integration/execution/set_subscriptions_test.dart
+++ b/pkg/analysis_server/test/integration/execution/set_subscriptions_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/execution/test_all.dart b/pkg/analysis_server/test/integration/execution/test_all.dart
index 6da630d..4f6af5d 100644
--- a/pkg/analysis_server/test/integration/execution/test_all.dart
+++ b/pkg/analysis_server/test/integration/execution/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/kythe/get_kythe_entries_test.dart b/pkg/analysis_server/test/integration/kythe/get_kythe_entries_test.dart
index ccd3c49..0d823a9 100644
--- a/pkg/analysis_server/test/integration/kythe/get_kythe_entries_test.dart
+++ b/pkg/analysis_server/test/integration/kythe/get_kythe_entries_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/kythe/test_all.dart b/pkg/analysis_server/test/integration/kythe/test_all.dart
index d65cff4..0573a6c 100644
--- a/pkg/analysis_server/test/integration/kythe/test_all.dart
+++ b/pkg/analysis_server/test/integration/kythe/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/search/find_element_references_test.dart b/pkg/analysis_server/test/integration/search/find_element_references_test.dart
index 6ea7f6e..eac13f5 100644
--- a/pkg/analysis_server/test/integration/search/find_element_references_test.dart
+++ b/pkg/analysis_server/test/integration/search/find_element_references_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/search/find_member_declarations_test.dart b/pkg/analysis_server/test/integration/search/find_member_declarations_test.dart
index 81148c0..f91ba02 100644
--- a/pkg/analysis_server/test/integration/search/find_member_declarations_test.dart
+++ b/pkg/analysis_server/test/integration/search/find_member_declarations_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/search/find_member_references_test.dart b/pkg/analysis_server/test/integration/search/find_member_references_test.dart
index 36fccbc..9ffc95f 100644
--- a/pkg/analysis_server/test/integration/search/find_member_references_test.dart
+++ b/pkg/analysis_server/test/integration/search/find_member_references_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/search/find_top_level_declarations_test.dart b/pkg/analysis_server/test/integration/search/find_top_level_declarations_test.dart
index 66352f8..4d37e1e 100644
--- a/pkg/analysis_server/test/integration/search/find_top_level_declarations_test.dart
+++ b/pkg/analysis_server/test/integration/search/find_top_level_declarations_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart b/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart
index da44055..2758ed1 100644
--- a/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/integration/search/get_type_hierarchy_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/search/test_all.dart b/pkg/analysis_server/test/integration/search/test_all.dart
index bf7e7a4..c7cc8b8 100644
--- a/pkg/analysis_server/test/integration/search/test_all.dart
+++ b/pkg/analysis_server/test/integration/search/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/server/get_version_test.dart b/pkg/analysis_server/test/integration/server/get_version_test.dart
index c3dc407..7fca35a 100644
--- a/pkg/analysis_server/test/integration/server/get_version_test.dart
+++ b/pkg/analysis_server/test/integration/server/get_version_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/server/set_subscriptions_invalid_service_test.dart b/pkg/analysis_server/test/integration/server/set_subscriptions_invalid_service_test.dart
index c95e046..6bfde08 100644
--- a/pkg/analysis_server/test/integration/server/set_subscriptions_invalid_service_test.dart
+++ b/pkg/analysis_server/test/integration/server/set_subscriptions_invalid_service_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/server/set_subscriptions_test.dart b/pkg/analysis_server/test/integration/server/set_subscriptions_test.dart
index d6de65b..6e9e672 100644
--- a/pkg/analysis_server/test/integration/server/set_subscriptions_test.dart
+++ b/pkg/analysis_server/test/integration/server/set_subscriptions_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/server/shutdown_test.dart b/pkg/analysis_server/test/integration/server/shutdown_test.dart
index 8478d48..ce7e5d4 100644
--- a/pkg/analysis_server/test/integration/server/shutdown_test.dart
+++ b/pkg/analysis_server/test/integration/server/shutdown_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/server/status_test.dart b/pkg/analysis_server/test/integration/server/status_test.dart
index 72163c3..411d1bc 100644
--- a/pkg/analysis_server/test/integration/server/status_test.dart
+++ b/pkg/analysis_server/test/integration/server/status_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/server/test_all.dart b/pkg/analysis_server/test/integration/server/test_all.dart
index 6ab8ac9..2ef3625 100644
--- a/pkg/analysis_server/test/integration/server/test_all.dart
+++ b/pkg/analysis_server/test/integration/server/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 3e82faf..6630dbe 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -202,6 +202,7 @@
  *   "relevance": int
  *   "completion": String
  *   "displayText": optional String
+ *   "elementUri": optional String
  *   "selectionOffset": int
  *   "selectionLength": int
  *   "isDeprecated": bool
@@ -233,6 +234,7 @@
           "isPotential": isBool
         }, optionalFields: {
           "displayText": isString,
+          "elementUri": isString,
           "docSummary": isString,
           "docComplete": isString,
           "declaringType": isString,
diff --git a/pkg/analysis_server/test/integration/test_all.dart b/pkg/analysis_server/test/integration/test_all.dart
index c69d15b..ce11216 100644
--- a/pkg/analysis_server/test/integration/test_all.dart
+++ b/pkg/analysis_server/test/integration/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
new file mode 100644
index 0000000..fd0e3c0
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for 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 'server_abstract.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ChangeWorkspaceFoldersTest);
+  });
+}
+
+@reflectiveTest
+class ChangeWorkspaceFoldersTest extends AbstractLspAnalysisServerTest {
+  String workspaceFolder1Path, workspaceFolder2Path, workspaceFolder3Path;
+  Uri workspaceFolder1Uri, workspaceFolder2Uri, workspaceFolder3Uri;
+
+  @override
+  void setUp() {
+    super.setUp();
+    workspaceFolder1Path = convertPath('/workspace1');
+    workspaceFolder2Path = convertPath('/workspace2');
+    workspaceFolder3Path = convertPath('/workspace3');
+    workspaceFolder1Uri = Uri.file(workspaceFolder1Path);
+    workspaceFolder2Uri = Uri.file(workspaceFolder2Path);
+    workspaceFolder3Uri = Uri.file(workspaceFolder3Path);
+  }
+
+  test_changeWorkspaceFolders_add() async {
+    await initialize(rootUri: workspaceFolder1Uri);
+    await changeWorkspaceFolders(
+        add: [workspaceFolder2Uri, workspaceFolder3Uri]);
+
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([
+        workspaceFolder1Path,
+        workspaceFolder2Path,
+        workspaceFolder3Path,
+      ]),
+    );
+  }
+
+  test_changeWorkspaceFolders_addAndRemove() async {
+    await initialize(
+      workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
+    );
+
+    await changeWorkspaceFolders(
+      add: [workspaceFolder3Uri],
+      remove: [workspaceFolder2Uri],
+    );
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([workspaceFolder1Path, workspaceFolder3Path]),
+    );
+  }
+
+  test_changeWorkspaceFolders_remove() async {
+    await initialize(
+      workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
+    );
+
+    await changeWorkspaceFolders(
+      remove: [workspaceFolder2Uri],
+    );
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([workspaceFolder1Path]),
+    );
+  }
+
+  test_changeWorkspaceFolders_removeFlushesDiagnostics() async {
+    // Add our standard test project as well as a dummy project.
+    await initialize(workspaceFolders: [projectFolderUri, workspaceFolder1Uri]);
+
+    // Generate an error in the test project.
+    final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await openFile(mainFileUri, 'String a = 1;');
+    final initialDiagnostics = await firstDiagnosticsUpdate;
+    expect(initialDiagnostics, hasLength(1));
+
+    // Ensure the error is removed if we removed the workspace folder.
+    final secondDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await changeWorkspaceFolders(remove: [projectFolderUri]);
+    final updatedDiagnostics = await secondDiagnosticsUpdate;
+    expect(updatedDiagnostics, hasLength(0));
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index 2f824c3..4d692a1 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -50,7 +50,7 @@
 
     // Ensure applying the changes will give us the expected content.
     final contents = {
-      mainFilePath: content,
+      mainFilePath: withoutMarkers(content),
     };
     applyDocumentChanges(contents, fixAction.edit.documentChanges);
     expect(contents[mainFilePath], equals(expectedContent));
@@ -88,7 +88,7 @@
 
     // Ensure applying the changes will give us the expected content.
     final contents = {
-      mainFilePath: content,
+      mainFilePath: withoutMarkers(content),
     };
     applyChanges(contents, fixAction.edit.changes);
     expect(contents[mainFilePath], equals(expectedContent));
diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
index e064771..3ea0d20 100644
--- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
@@ -72,7 +72,7 @@
 
     // Ensure applying the changes will give us the expected content.
     final contents = {
-      mainFilePath: content,
+      mainFilePath: withoutMarkers(content),
     };
     applyDocumentChanges(contents, editParams.edit.documentChanges);
     expect(contents[mainFilePath], equals(expectedContent));
@@ -129,7 +129,7 @@
 
     // Ensure applying the changes will give us the expected content.
     final contents = {
-      mainFilePath: content,
+      mainFilePath: withoutMarkers(content),
     };
     applyChanges(contents, editParams.edit.changes);
     expect(contents[mainFilePath], equals(expectedContent));
@@ -270,7 +270,7 @@
 
     // Ensure applying the changes will give us the expected content.
     final contents = {
-      mainFilePath: content,
+      mainFilePath: withoutMarkers(content),
     };
     applyDocumentChanges(contents, editParams.edit.documentChanges);
     expect(contents[mainFilePath], equals(expectedContent));
@@ -320,7 +320,7 @@
 
     // Ensure applying the changes will give us the expected content.
     final contents = {
-      mainFilePath: content,
+      mainFilePath: withoutMarkers(content),
     };
     applyChanges(contents, editParams.edit.changes);
     expect(contents[mainFilePath], equals(expectedContent));
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index 189b82b..802d3be 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -19,21 +19,40 @@
     const initialContents = 'int a = 1;';
     newFile(mainFilePath, content: initialContents);
 
+    final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
     await initialize();
-    final initialDiagnostics = await waitForDiagnostics(mainFileUri);
+    final initialDiagnostics = await firstDiagnosticsUpdate;
     expect(initialDiagnostics, hasLength(0));
 
     await openFile(mainFileUri, initialContents);
+
+    final secondDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
     await replaceFile(222, mainFileUri, 'String a = 1;');
-    final updatedDiagnostics = await waitForDiagnostics(mainFileUri);
+    final updatedDiagnostics = await secondDiagnosticsUpdate;
     expect(updatedDiagnostics, hasLength(1));
   }
 
+  test_deletedFile() async {
+    newFile(mainFilePath, content: 'String a = 1;');
+
+    final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await initialize();
+    final originalDiagnostics = await firstDiagnosticsUpdate;
+    expect(originalDiagnostics, hasLength(1));
+
+    // Deleting the file should result in an update to remove the diagnostics.
+    final secondDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await deleteFile(mainFilePath);
+    final updatedDiagnostics = await secondDiagnosticsUpdate;
+    expect(updatedDiagnostics, hasLength(0));
+  }
+
   test_initialAnalysis() async {
     newFile(mainFilePath, content: 'String a = 1;');
 
+    final diagnosticsUpdate = waitForDiagnostics(mainFileUri);
     await initialize();
-    final diagnostics = await waitForDiagnostics(mainFileUri);
+    final diagnostics = await diagnosticsUpdate;
     expect(diagnostics, hasLength(1));
     final diagnostic = diagnostics.first;
     expect(diagnostic.code, equals('invalid_assignment'));
diff --git a/pkg/analysis_server/test/lsp/document_highlights_test.dart b/pkg/analysis_server/test/lsp/document_highlights_test.dart
new file mode 100644
index 0000000..7f002b4
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/document_highlights_test.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for 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 'server_abstract.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(DocumentHighlightsTest);
+  });
+}
+
+@reflectiveTest
+class DocumentHighlightsTest extends AbstractLspAnalysisServerTest {
+  test_functions() => _testMarkedContent('''
+    [[main]]() {
+      [[mai^n]]();
+    }
+    ''');
+
+  test_localVariable() => _testMarkedContent('''
+    main() {
+      var [[f^oo]] = 1;
+      print([[foo]]);
+      [[foo]] = 2;
+    }
+    ''');
+
+  test_noResult() => _testMarkedContent('''
+    main() {
+      // This one is in a ^ comment!
+    }
+    ''');
+
+  test_onlySelf() => _testMarkedContent('''
+    main() {
+      [[prin^t]]();
+    }
+    ''');
+
+  test_shadow_inner() => _testMarkedContent('''
+    main() {
+      var foo = 1;
+      func() {
+        var [[fo^o]] = 2;
+        print([[foo]]);
+      }
+    }
+    ''');
+
+  test_shadow_outer() => _testMarkedContent('''
+    main() {
+      var [[foo]] = 1;
+      func() {
+        var foo = 2;
+        print(foo);
+      }
+      print([[fo^o]]);
+    }
+    ''');
+
+  test_topLevelVariable() => _testMarkedContent('''
+    String [[foo]] = 'bar';
+    main() {
+      print([[foo]]);
+      [[fo^o]] = 2;
+    }
+    ''');
+
+  /// Tests highlights in a Dart file using the provided content.
+  /// The content should be marked with a ^ where the highlights request should
+  /// be invoked and with `[[double brackets]]` around each range expected to
+  /// be highlighted (eg. all references to the symbol under ^).
+  /// If the content does not include any `[[double brackets]]` then the response
+  /// is expected to be `null`.
+  _testMarkedContent(String content) async {
+    final expectedRanges = rangesFromMarkers(content);
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final pos = positionFromMarker(content);
+    final highlights = await getDocumentHighlights(mainFileUri, pos);
+
+    if (expectedRanges.isEmpty) {
+      expect(highlights, isNull);
+    } else {
+      final highlightRanges = highlights.map((h) => h.range).toList();
+      expect(highlightRanges, equals(expectedRanges));
+    }
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index 86699ed..7afb2a5 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -48,6 +48,21 @@
         response.error.code, equals(ServerErrorCodes.ServerAlreadyInitialized));
   }
 
+  test_initialize_rootPath() async {
+    await initialize(rootPath: projectFolderPath);
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+  }
+
+  test_initialize_rootUri() async {
+    await initialize(rootUri: projectFolderUri);
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+  }
+
+  test_initialize_workspaceFolders() async {
+    await initialize(workspaceFolders: [projectFolderUri]);
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+  }
+
   test_uninitialized_dropsNotifications() async {
     final notification =
         makeNotification(new Method.fromJson('randomNotification'), null);
diff --git a/pkg/analysis_server/test/lsp/rename_test.dart b/pkg/analysis_server/test/lsp/rename_test.dart
new file mode 100644
index 0000000..6226b60
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/rename_test.dart
@@ -0,0 +1,348 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for 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/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'server_abstract.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RenameTest);
+  });
+}
+
+@reflectiveTest
+class RenameTest extends AbstractLspAnalysisServerTest {
+  // TODO(dantup): send a rename without a version
+  // TODO(dantup): send an old version of the doc?
+  // TODO(dantup): check the version returned matches?
+  // TODO(dantup): renames across multiple files
+
+  test_prepare_class() {
+    const content = '''
+    class MyClass {}
+    final a = new [[My^Class]]();
+    ''';
+
+    return _test_prepare(content, 'MyClass');
+  }
+
+  test_prepare_classNewKeyword() async {
+    const content = '''
+    class MyClass {}
+    final a = n^ew [[MyClass]]();
+    ''';
+
+    return _test_prepare(content, 'MyClass');
+  }
+
+  test_prepare_importPrefix() async {
+    const content = '''
+    import 'dart:async' as [[myPr^efix]];
+    ''';
+
+    return _test_prepare(content, 'myPrefix');
+  }
+
+  test_prepare_importWithoutPrefix() async {
+    const content = '''
+    imp[[^]]ort 'dart:async';
+    ''';
+
+    return _test_prepare(content, '');
+  }
+
+  test_prepare_importWithPrefix() async {
+    const content = '''
+    imp^ort 'dart:async' as [[myPrefix]];
+    ''';
+
+    return _test_prepare(content, 'myPrefix');
+  }
+
+  test_prepare_invalidRenameLocation() async {
+    const content = '''
+    main() {
+      // comm^ent
+    }
+    ''';
+
+    return _test_prepare(content, null);
+  }
+
+  test_prepare_sdkClass() async {
+    const content = '''
+    final a = new [[Ob^ject]]();
+    ''';
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final request = makeRequest(
+      Method.textDocument_prepareRename,
+      new TextDocumentPositionParams(
+        new TextDocumentIdentifier(mainFileUri.toString()),
+        positionFromMarker(content),
+      ),
+    );
+    final response = await channel.sendRequestToServer(request);
+
+    expect(response.id, equals(request.id));
+    expect(response.result, isNull);
+    expect(response.error, isNotNull);
+    expect(response.error.code, ServerErrorCodes.RenameNotValid);
+    expect(response.error.message, contains('is defined in the SDK'));
+  }
+
+  test_prepare_variable() async {
+    const content = '''
+    main() {
+      var variable = 0;
+      print([[vari^able]]);
+    }
+    ''';
+
+    return _test_prepare(content, 'variable');
+  }
+
+  test_rename_class() {
+    const content = '''
+    class MyClass {}
+    final a = new [[My^Class]]();
+    ''';
+    const expectedContent = '''
+    class MyNewClass {}
+    final a = new MyNewClass();
+    ''';
+    return _test_rename_withDocumentChanges(
+        content, 'MyNewClass', expectedContent);
+  }
+
+  test_rename_classNewKeyword() async {
+    const content = '''
+    class MyClass {}
+    final a = n^ew MyClass();
+    ''';
+    const expectedContent = '''
+    class MyNewClass {}
+    final a = new MyNewClass();
+    ''';
+    return _test_rename_withDocumentChanges(
+        content, 'MyNewClass', expectedContent);
+  }
+
+  test_rename_importPrefix() {
+    const content = '''
+    import 'dart:async' as myPr^efix;
+    ''';
+    const expectedContent = '''
+    import 'dart:async' as myNewPrefix;
+    ''';
+    return _test_rename_withDocumentChanges(
+        content, 'myNewPrefix', expectedContent);
+  }
+
+  test_rename_importWithoutPrefix() {
+    const content = '''
+    imp^ort 'dart:async';
+    ''';
+    const expectedContent = '''
+    import 'dart:async' as myAddedPrefix;
+    ''';
+    return _test_rename_withDocumentChanges(
+        content, 'myAddedPrefix', expectedContent);
+  }
+
+  test_rename_importWithPrefix() {
+    const content = '''
+    imp^ort 'dart:async' as myPrefix;
+    ''';
+    const expectedContent = '''
+    import 'dart:async' as myNewPrefix;
+    ''';
+    return _test_rename_withDocumentChanges(
+        content, 'myNewPrefix', expectedContent);
+  }
+
+  test_rename_invalidRenameLocation() {
+    const content = '''
+    main() {
+      // comm^ent
+    }
+    ''';
+    return _test_rename_withDocumentChanges(content, 'MyNewClass', null);
+  }
+
+  test_rename_rejectedForBadName() async {
+    const content = '''
+    class MyClass {}
+    final a = n^ew MyClass();
+    ''';
+    final error = await _test_rename_failure(content, 'not a valid class name');
+    expect(error.code, equals(ServerErrorCodes.RenameNotValid));
+    expect(error.message, contains('name must not contain'));
+  }
+
+  test_rename_rejectedForDuplicateName() async {
+    const content = '''
+    class MyOtherClass {}
+    class MyClass {}
+    final a = n^ew MyClass();
+    ''';
+    final error = await _test_rename_failure(content, 'MyOtherClass');
+    expect(error.code, equals(ServerErrorCodes.RenameNotValid));
+    expect(error.message, contains('already declares class with name'));
+  }
+
+  test_rename_rejectedForStaleDocument() async {
+    const content = '''
+    class MyClass {}
+    final a = n^ew MyClass();
+    ''';
+    final error =
+        await _test_rename_failure(content, 'MyNewClass', openFileVersion: 111);
+    expect(error.code, equals(ErrorCodes.ContentModified));
+    expect(error.message, contains('Document was modified'));
+  }
+
+  test_rename_sdkClass() async {
+    const content = '''
+    final a = new [[Ob^ject]]();
+    ''';
+
+    await newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final request = makeRequest(
+      Method.textDocument_rename,
+      new RenameParams(
+        new TextDocumentIdentifier(mainFileUri.toString()),
+        positionFromMarker(content),
+        'Object2',
+      ),
+    );
+    final response = await channel.sendRequestToServer(request);
+
+    expect(response.id, equals(request.id));
+    expect(response.result, isNull);
+    expect(response.error, isNotNull);
+    expect(response.error.code, ServerErrorCodes.RenameNotValid);
+    expect(response.error.message, contains('is defined in the SDK'));
+  }
+
+  test_rename_usingLegacyChangeInterface() async {
+    // This test initializes without support for DocumentChanges (versioning)
+    // whereas the other tests all use DocumentChanges support (preferred).
+    const content = '''
+    class MyClass {}
+    final a = new My^Class();
+    ''';
+    const expectedContent = '''
+    class MyNewClass {}
+    final a = new MyNewClass();
+    ''';
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content), version: 222);
+
+    final result = await rename(
+      mainFileUri,
+      222,
+      positionFromMarker(content),
+      'MyNewClass',
+    );
+
+    // Ensure applying the changes will give us the expected content.
+    final contents = {
+      mainFilePath: withoutMarkers(content),
+    };
+    applyChanges(contents, result.changes);
+    expect(contents[mainFilePath], equals(expectedContent));
+  }
+
+  test_rename_variable() {
+    const content = '''
+    main() {
+      var variable = 0;
+      print([[vari^able]]);
+    }
+    ''';
+    const expectedContent = '''
+    main() {
+      var foo = 0;
+      print(foo);
+    }
+    ''';
+    return _test_rename_withDocumentChanges(content, 'foo', expectedContent);
+  }
+
+  _test_prepare(String content, String expectedPlaceholder) async {
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final result =
+        await prepareRename(mainFileUri, positionFromMarker(content));
+
+    if (expectedPlaceholder == null) {
+      expect(result, isNull);
+    } else {
+      expect(result.range, equals(rangeFromMarkers(content)));
+      expect(result.placeholder, equals(expectedPlaceholder));
+    }
+  }
+
+  Future<ResponseError> _test_rename_failure(
+    String content,
+    String newName, {
+    int openFileVersion = 222,
+    int renameRequestFileVersion = 222,
+  }) async {
+    await initialize(
+      workspaceCapabilities:
+          withDocumentChangesSupport(emptyWorkspaceClientCapabilities),
+    );
+    await openFile(mainFileUri, withoutMarkers(content),
+        version: openFileVersion);
+
+    final result = await renameRaw(
+      mainFileUri,
+      renameRequestFileVersion,
+      positionFromMarker(content),
+      newName,
+    );
+
+    expect(result.result, isNull);
+    expect(result.error, isNotNull);
+    return result.error;
+  }
+
+  _test_rename_withDocumentChanges(
+      String content, String newName, String expectedContent) async {
+    await initialize(
+      workspaceCapabilities:
+          withDocumentChangesSupport(emptyWorkspaceClientCapabilities),
+    );
+    await openFile(mainFileUri, withoutMarkers(content), version: 222);
+
+    final result = await rename(
+      mainFileUri,
+      222,
+      positionFromMarker(content),
+      newName,
+    );
+    if (expectedContent == null) {
+      expect(result, isNull);
+    } else {
+      // Ensure applying the changes will give us the expected content.
+      final contents = {
+        mainFilePath: withoutMarkers(content),
+      };
+      applyDocumentChanges(contents, result.documentChanges);
+      expect(contents[mainFilePath], equals(expectedContent));
+    }
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 45e2ad9..fad7baf 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:meta/meta.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
 import '../mocks.dart';
@@ -41,7 +42,7 @@
 
   int _id = 0;
   String projectFolderPath, mainFilePath;
-  Uri mainFileUri;
+  Uri projectFolderUri, mainFileUri;
 
   void applyChanges(
     Map<String, String> fileContents,
@@ -111,11 +112,29 @@
     // number of inserts followed by a single remove or replace edit. If multiple
     // inserts have the same position, the order in the array defines the order in
     // which the inserted strings appear in the resulting text.
-    if (changes.length > 1) {
-      // TODO(dantup): Implement multi-edit edits.
-      throw 'Test helper applyTextEdits does not support applying multiple edits';
-    } else if (changes.length == 1) {
-      newContent = applyTextEdit(newContent, changes.single);
+
+    /// Ensures changes are simple enough to apply easily without any complicated
+    /// logic.
+    void validateChangesCanBeApplied() {
+      bool intersectsWithOrComesAfter(Position pos, Position other) =>
+          pos.line > other.line ||
+          (pos.line == other.line || pos.character >= other.character);
+
+      Position earliestPositionChanged;
+      for (final change in changes) {
+        if (earliestPositionChanged != null &&
+            intersectsWithOrComesAfter(
+                change.range.end, earliestPositionChanged)) {
+          throw 'Test helper applyTextEdits does not support applying multiple edits '
+              'where the edits are not in reverse order.';
+        }
+        earliestPositionChanged = change.range.start;
+      }
+    }
+
+    validateChangesCanBeApplied();
+    for (final change in changes) {
+      newContent = applyTextEdit(newContent, change);
     }
 
     return newContent;
@@ -137,6 +156,20 @@
     await pumpEventQueue();
   }
 
+  Future changeWorkspaceFolders({List<Uri> add, List<Uri> remove}) async {
+    var notification = makeNotification(
+      Method.workspace_didChangeWorkspaceFolders,
+      new DidChangeWorkspaceFoldersParams(
+        new WorkspaceFoldersChangeEvent(
+          add?.map(toWorkspaceFolder)?.toList() ?? const [],
+          remove?.map(toWorkspaceFolder)?.toList() ?? const [],
+        ),
+      ),
+    );
+    channel.sendNotificationToServer(notification);
+    await pumpEventQueue();
+  }
+
   Future closeFile(Uri uri) async {
     var notification = makeNotification(
       Method.textDocument_didClose,
@@ -198,7 +231,7 @@
     }
   }
 
-  Future<List<TextEdit>> formatDocument(String fileUri) async {
+  Future<List<TextEdit>> formatDocument(String fileUri) {
     final request = makeRequest(
       Method.textDocument_formatting,
       new DocumentFormattingParams(
@@ -210,7 +243,7 @@
   }
 
   Future<List<TextEdit>> formatOnType(
-      String fileUri, Position pos, String character) async {
+      String fileUri, Position pos, String character) {
     final request = makeRequest(
       Method.textDocument_onTypeFormatting,
       new DocumentOnTypeFormattingParams(
@@ -227,7 +260,7 @@
     String fileUri, {
     Range range,
     List<CodeActionKind> kinds,
-  }) async {
+  }) {
     final request = makeRequest(
       Method.textDocument_codeAction,
       new CodeActionParams(
@@ -242,7 +275,7 @@
   }
 
   Future<List<CompletionItem>> getCompletion(Uri uri, Position pos,
-      {CompletionContext context}) async {
+      {CompletionContext context}) {
     final request = makeRequest(
       Method.textDocument_completion,
       new CompletionParams(
@@ -254,7 +287,7 @@
     return expectSuccessfulResponseTo<List<CompletionItem>>(request);
   }
 
-  Future<List<Location>> getDefinition(Uri uri, Position pos) async {
+  Future<List<Location>> getDefinition(Uri uri, Position pos) {
     final request = makeRequest(
       Method.textDocument_definition,
       new TextDocumentPositionParams(
@@ -265,8 +298,19 @@
     return expectSuccessfulResponseTo<List<Location>>(request);
   }
 
+  Future<List<DocumentHighlight>> getDocumentHighlights(Uri uri, Position pos) {
+    final request = makeRequest(
+      Method.textDocument_documentHighlight,
+      new TextDocumentPositionParams(
+        new TextDocumentIdentifier(uri.toString()),
+        pos,
+      ),
+    );
+    return expectSuccessfulResponseTo<List<DocumentHighlight>>(request);
+  }
+
   Future<Either2<List<DocumentSymbol>, List<SymbolInformation>>>
-      getDocumentSymbols(String fileUri) async {
+      getDocumentSymbols(String fileUri) {
     final request = makeRequest(
       Method.textDocument_documentSymbol,
       new DocumentSymbolParams(
@@ -276,7 +320,7 @@
     return expectSuccessfulResponseTo(request);
   }
 
-  Future<Hover> getHover(Uri uri, Position pos) async {
+  Future<Hover> getHover(Uri uri, Position pos) {
     final request = makeRequest(
       Method.textDocument_hover,
       new TextDocumentPositionParams(
@@ -289,7 +333,7 @@
     Uri uri,
     Position pos, {
     includeDeclarations = false,
-  }) async {
+  }) {
     final request = makeRequest(
       Method.textDocument_references,
       new ReferenceParams(
@@ -301,7 +345,7 @@
     return expectSuccessfulResponseTo<List<Location>>(request);
   }
 
-  Future<SignatureHelp> getSignatureHelp(Uri uri, Position pos) async {
+  Future<SignatureHelp> getSignatureHelp(Uri uri, Position pos) {
     final request = makeRequest(
       Method.textDocument_signatureHelp,
       new TextDocumentPositionParams(
@@ -362,16 +406,22 @@
   /// match the spec exactly and are not verified.
   Future<ResponseMessage> initialize({
     String rootPath,
+    Uri rootUri,
+    List<Uri> workspaceFolders,
     TextDocumentClientCapabilities textDocumentCapabilities,
     WorkspaceClientCapabilities workspaceCapabilities,
   }) async {
-    final rootUri = Uri.file(rootPath ?? projectFolderPath).toString();
+    // Assume if none of the project options were set, that we want to default to
+    // opening the test project folder.
+    if (rootPath == null && rootUri == null && workspaceFolders == null) {
+      rootUri = Uri.file(projectFolderPath);
+    }
     final request = makeRequest(
         Method.initialize,
         new InitializeParams(
             null,
-            null,
-            rootUri,
+            rootPath,
+            rootUri?.toString(),
             null,
             new ClientCapabilities(
               workspaceCapabilities,
@@ -379,13 +429,14 @@
               null,
             ),
             null,
-            null));
+            workspaceFolders?.map(toWorkspaceFolder)?.toList()));
     final response = await channel.sendRequestToServer(request);
     expect(response.id, equals(request.id));
 
     if (response.error == null) {
       final notification = makeNotification(Method.initialized, null);
       channel.sendNotificationToServer(notification);
+      await pumpEventQueue();
     }
 
     return response;
@@ -395,6 +446,18 @@
     return new NotificationMessage(method, params, jsonRpcVersion);
   }
 
+  RequestMessage makeRenameRequest(
+      int version, Uri uri, Position pos, String newName) {
+    final docIdentifier = version != null
+        ? new VersionedTextDocumentIdentifier(version, uri.toString())
+        : new TextDocumentIdentifier(uri.toString());
+    final request = makeRequest(
+      Method.textDocument_rename,
+      new RenameParams(docIdentifier, pos, newName),
+    );
+    return request;
+  }
+
   RequestMessage makeRequest(Method method, ToJsonable params) {
     final id = Either2<num, String>.t1(_id++);
     return new RequestMessage(id, method, params, jsonRpcVersion);
@@ -411,34 +474,97 @@
   }
 
   Position positionFromMarker(String contents) =>
-      positionFromOffset(contents.indexOf('^'), contents);
+      positionFromOffset(withoutRangeMarkers(contents).indexOf('^'), contents);
 
   Position positionFromOffset(int offset, String contents) {
-    final lineInfo = LineInfo.fromContent(contents);
+    final lineInfo = LineInfo.fromContent(withoutMarkers(contents));
     return toPosition(lineInfo.getLocation(offset));
   }
 
+  Future<RangeAndPlaceholder> prepareRename(Uri uri, Position pos) {
+    final request = makeRequest(
+      Method.textDocument_prepareRename,
+      new TextDocumentPositionParams(
+        new TextDocumentIdentifier(uri.toString()),
+        pos,
+      ),
+    );
+    return expectSuccessfulResponseTo<RangeAndPlaceholder>(request);
+  }
+
   /// Returns the range surrounded by `[[markers]]` in the provided string,
   /// excluding the markers themselves (as well as position markers `^` from
   /// the offsets).
   Range rangeFromMarkers(String contents) {
-    contents = contents.replaceAll(positionMarker, '');
-    final start = contents.indexOf(rangeMarkerStart);
-    if (start == -1) {
-      throw 'Contents did not contain $rangeMarkerStart';
+    final ranges = rangesFromMarkers(contents);
+    if (ranges.length == 1) {
+      return ranges.first;
+    } else if (ranges.isEmpty) {
+      throw 'Contents did not include a marked range';
+    } else {
+      throw 'Contents contained multiple ranges but only one was expected';
     }
-    final end = contents.indexOf(rangeMarkerEnd);
-    if (end == -1) {
-      throw 'Contents did not contain $rangeMarkerEnd';
-    }
-    return new Range(
-      positionFromOffset(start, contents),
-      positionFromOffset(end - rangeMarkerStart.length, contents),
-    );
   }
 
-  Future replaceFile(int newVersion, Uri uri, String content) async {
-    await changeFile(
+  /// Returns all ranges surrounded by `[[markers]]` in the provided string,
+  /// excluding the markers themselves (as well as position markers `^` from
+  /// the offsets).
+  List<Range> rangesFromMarkers(String content) {
+    Iterable<Range> rangesFromMarkersImpl(String content) sync* {
+      content = content.replaceAll(positionMarker, '');
+      final contentsWithoutMarkers = withoutMarkers(content);
+      var searchStartIndex = 0;
+      var offsetForEarlierMarkers = 0;
+      while (true) {
+        final startMarker = content.indexOf(rangeMarkerStart, searchStartIndex);
+        if (startMarker == -1) {
+          return; // Exit if we didn't find any more.
+        }
+        final endMarker = content.indexOf(rangeMarkerEnd, startMarker);
+        if (endMarker == -1) {
+          throw 'Found unclosed range starting at offset $startMarker';
+        }
+        yield new Range(
+          positionFromOffset(
+              startMarker + offsetForEarlierMarkers, contentsWithoutMarkers),
+          positionFromOffset(
+              endMarker + offsetForEarlierMarkers - rangeMarkerStart.length,
+              contentsWithoutMarkers),
+        );
+        // Start the next search after this one, but remember to offset the future
+        // results by the lengths of these markers since they shouldn't affect the
+        // offsets.
+        searchStartIndex = endMarker;
+        offsetForEarlierMarkers -=
+            rangeMarkerStart.length + rangeMarkerEnd.length;
+      }
+    }
+
+    return rangesFromMarkersImpl(content).toList();
+  }
+
+  Future<WorkspaceEdit> rename(
+    Uri uri,
+    int version,
+    Position pos,
+    String newName,
+  ) {
+    final request = makeRenameRequest(version, uri, pos, newName);
+    return expectSuccessfulResponseTo<WorkspaceEdit>(request);
+  }
+
+  Future<ResponseMessage> renameRaw(
+    Uri uri,
+    int version,
+    Position pos,
+    String newName,
+  ) {
+    final request = makeRenameRequest(version, uri, pos, newName);
+    return channel.sendRequestToServer(request);
+  }
+
+  Future replaceFile(int newVersion, Uri uri, String content) {
+    return changeFile(
       newVersion,
       uri,
       [new TextDocumentContentChangeEvent(null, null, content)],
@@ -447,7 +573,7 @@
 
   /// Sends [responseParams] to the server as a successful response to
   /// a server-initiated [request].
-  void respondTo<T>(RequestMessage request, T responseParams) async {
+  void respondTo<T>(RequestMessage request, T responseParams) {
     channel.sendResponseToServer(
         new ResponseMessage(request.id, responseParams, null, jsonRpcVersion));
   }
@@ -464,6 +590,7 @@
         InstrumentationService.NULL_SERVICE);
 
     projectFolderPath = convertPath('/project');
+    projectFolderUri = Uri.file(projectFolderPath);
     newFolder(projectFolderPath);
     newFolder(join(projectFolderPath, 'lib'));
     // Create a folder and file to aid testing that includes imports/completion.
@@ -478,6 +605,10 @@
     await server.shutdown();
   }
 
+  WorkspaceFolder toWorkspaceFolder(Uri uri) {
+    return WorkspaceFolder(uri.toString(), path.basename(uri.toFilePath()));
+  }
+
   Future<List<Diagnostic>> waitForDiagnostics(Uri uri) async {
     PublishDiagnosticsParams diagnosticParams;
     await channel.serverToClient.firstWhere((message) {
@@ -496,6 +627,10 @@
   /// positions/ranges in strings to avoid hard-coding positions in tests.
   String withoutMarkers(String contents) =>
       contents.replaceAll(allMarkersPattern, '');
+
+  /// Removes range markers from strings to give accurate position offsets.
+  String withoutRangeMarkers(String contents) =>
+      contents.replaceAll(rangeMarkerStart, '').replaceAll(rangeMarkerEnd, '');
 }
 
 mixin ClientCapabilitiesHelperMixin {
diff --git a/pkg/analysis_server/test/lsp/test_all.dart b/pkg/analysis_server/test/lsp/test_all.dart
index c9942f1..d1e29ad 100644
--- a/pkg/analysis_server/test/lsp/test_all.dart
+++ b/pkg/analysis_server/test/lsp/test_all.dart
@@ -12,6 +12,7 @@
 import 'completion_test.dart' as completion_test;
 import 'definition_test.dart' as definition_test;
 import 'diagnostic_test.dart' as diagnostic_test;
+import 'document_highlights_test.dart' as document_highlights_test;
 import 'document_symbols_test.dart' as document_symbols_test;
 import 'file_modification_test.dart' as file_modification_test;
 import 'format_test.dart' as format_test;
@@ -19,6 +20,7 @@
 import 'initialization_test.dart' as initialization_test;
 import 'priority_files_test.dart' as priority_files_test;
 import 'references_test.dart' as references_test;
+import 'rename_test.dart' as rename_test;
 import 'server_test.dart' as server_test;
 import 'signature_help_test.dart' as signature_help_test;
 
@@ -28,6 +30,7 @@
     definition_test.main();
     diagnostic_test.main();
     document_symbols_test.main();
+    document_highlights_test.main();
     file_modification_test.main();
     priority_files_test.main();
     format_test.main();
@@ -40,5 +43,6 @@
     fixes_code_action_tests.main();
     assists_code_action_tests.main();
     packet_transformer_tests.main();
+    rename_test.main();
   }, name: 'lsp');
 }
diff --git a/pkg/analysis_server/test/plugin/protocol_dart_test.dart b/pkg/analysis_server/test/plugin/protocol_dart_test.dart
index ed8e850..1568d90 100644
--- a/pkg/analysis_server/test/plugin/protocol_dart_test.dart
+++ b/pkg/analysis_server/test/plugin/protocol_dart_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/plugin/test_all.dart b/pkg/analysis_server/test/plugin/test_all.dart
index 8390a16..284a4a3 100644
--- a/pkg/analysis_server/test/plugin/test_all.dart
+++ b/pkg/analysis_server/test/plugin/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 9d2e9ca..553f0a8 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/abstract_search_domain.dart b/pkg/analysis_server/test/search/abstract_search_domain.dart
index d4d1465..e16bc24 100644
--- a/pkg/analysis_server/test/search/abstract_search_domain.dart
+++ b/pkg/analysis_server/test/search/abstract_search_domain.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/declarations_test.dart b/pkg/analysis_server/test/search/declarations_test.dart
index 8af7bf4..000ba70 100644
--- a/pkg/analysis_server/test/search/declarations_test.dart
+++ b/pkg/analysis_server/test/search/declarations_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index 6473f65..ff75b70 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/member_declarations_test.dart b/pkg/analysis_server/test/search/member_declarations_test.dart
index 644912e..71509db 100644
--- a/pkg/analysis_server/test/search/member_declarations_test.dart
+++ b/pkg/analysis_server/test/search/member_declarations_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/member_references_test.dart b/pkg/analysis_server/test/search/member_references_test.dart
index 3f29142..56bebb9 100644
--- a/pkg/analysis_server/test/search/member_references_test.dart
+++ b/pkg/analysis_server/test/search/member_references_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/search_result_test.dart b/pkg/analysis_server/test/search/search_result_test.dart
index 47a8560..2f2ff83 100644
--- a/pkg/analysis_server/test/search/search_result_test.dart
+++ b/pkg/analysis_server/test/search/search_result_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/test_all.dart b/pkg/analysis_server/test/search/test_all.dart
index 56465f1..2e85dae 100644
--- a/pkg/analysis_server/test/search/test_all.dart
+++ b/pkg/analysis_server/test/search/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/top_level_declarations_test.dart b/pkg/analysis_server/test/search/top_level_declarations_test.dart
index 7e1fd99..913f821 100644
--- a/pkg/analysis_server/test/search/top_level_declarations_test.dart
+++ b/pkg/analysis_server/test/search/top_level_declarations_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index dfeea6a..3461a4f 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 a14a0a9..cedde60 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
index 44aae62..8afed8b 100644
--- a/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart b/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
index c6f9a95..a1ba82c 100644
--- a/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 7cf8eb5..9bb1010 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
index 5f6e857..6e09724 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
index 28fcdbe..2bdff61 100644
--- a/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 f2e2ba2..73f5b37 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/label_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/label_contributor_test.dart
index 0cd2068..01dd324 100644
--- a/pkg/analysis_server/test/services/completion/dart/label_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/label_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
index 09f41e9..e13ad70 100644
--- a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart
index d4fb175..7309c20 100644
--- a/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
index d58e6fe..36a37e9 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
index 3191090..8e5f942 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart
index f4722d5..579a063 100644
--- a/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
index 52caf6e..49a5e34 100644
--- a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
index 256e647..1d3e804 100644
--- a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
index 72c87931..1298dca 100644
--- a/pkg/analysis_server/test/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
index c9da1a4..5fd129a 100644
--- a/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
index c283cde..49f69ca 100644
--- a/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart
index 36c4d2d..2d776e06 100644
--- a/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart b/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart
index 1fa242e..bf67079 100644
--- a/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart
+++ b/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/postfix/test_all.dart b/pkg/analysis_server/test/services/completion/postfix/test_all.dart
index a2a43c5..4f4c9cb 100644
--- a/pkg/analysis_server/test/services/completion/postfix/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/postfix/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
index 3fb9792..6d789ad 100644
--- a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
+++ b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/statement/test_all.dart b/pkg/analysis_server/test/services/completion/statement/test_all.dart
index f88ea5a..fb89619 100644
--- a/pkg/analysis_server/test/services/completion/statement/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/statement/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/completion/test_all.dart b/pkg/analysis_server/test/services/completion/test_all.dart
index e89a4e8..11542d1 100644
--- a/pkg/analysis_server/test/services/completion/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/change_test.dart b/pkg/analysis_server/test/services/correction/change_test.dart
index d11aabd..1a74aa1 100644
--- a/pkg/analysis_server/test/services/correction/change_test.dart
+++ b/pkg/analysis_server/test/services/correction/change_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/levenshtein_test.dart b/pkg/analysis_server/test/services/correction/levenshtein_test.dart
index c344a4c..d8a77e6 100644
--- a/pkg/analysis_server/test/services/correction/levenshtein_test.dart
+++ b/pkg/analysis_server/test/services/correction/levenshtein_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/name_suggestion_test.dart b/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
index d0ac381..f0703ad 100644
--- a/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
+++ b/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
index ff56f55..8c53f7a 100644
--- a/pkg/analysis_server/test/services/correction/organize_directives_test.dart
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/sort_members_test.dart b/pkg/analysis_server/test/services/correction/sort_members_test.dart
index 81001fa..faaac42 100644
--- a/pkg/analysis_server/test/services/correction/sort_members_test.dart
+++ b/pkg/analysis_server/test/services/correction/sort_members_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/status_test.dart b/pkg/analysis_server/test/services/correction/status_test.dart
index eb27ec2..74b85d5 100644
--- a/pkg/analysis_server/test/services/correction/status_test.dart
+++ b/pkg/analysis_server/test/services/correction/status_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/strings_test.dart b/pkg/analysis_server/test/services/correction/strings_test.dart
index a7a68e7..c55cb7b 100644
--- a/pkg/analysis_server/test/services/correction/strings_test.dart
+++ b/pkg/analysis_server/test/services/correction/strings_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/correction/util_test.dart b/pkg/analysis_server/test/services/correction/util_test.dart
index 53eaa7c..b21db87 100644
--- a/pkg/analysis_server/test/services/correction/util_test.dart
+++ b/pkg/analysis_server/test/services/correction/util_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 import 'dart:async';
diff --git a/pkg/analysis_server/test/services/linter/test_all.dart b/pkg/analysis_server/test/services/linter/test_all.dart
index 270b1a4..feb89d6 100644
--- a/pkg/analysis_server/test/services/linter/test_all.dart
+++ b/pkg/analysis_server/test/services/linter/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index 213972f..bf429de 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
index fec6d34..80308ef 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 abac0c8..b06f849 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 129cf15..d8fe817 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
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index fd048d2..157d574 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
index c4d46de..580a076 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
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 41e32b8..0ca2a60 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 077035c..061ba99 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/move_file_test.dart b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
index dd52924..fa60f61 100644
--- a/pkg/analysis_server/test/services/refactoring/move_file_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart b/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart
index 6973932..d714f0d 100644
--- a/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 90957df..bd297d4 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
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 2f0f4a3..884c04a 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_import_test.dart b/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
index ed29086..ef76288 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_label_test.dart b/pkg/analysis_server/test/services/refactoring/rename_label_test.dart
index 076ec77..b8d8564 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_label_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_label_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_library_test.dart b/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
index dc1df38..b8f8ac2 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_local_test.dart b/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
index 25359cd..042fdcc 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 1f23392..baa28a5 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/refactoring/test_all.dart b/pkg/analysis_server/test/services/refactoring/test_all.dart
index 5dc96b6..a63865d 100644
--- a/pkg/analysis_server/test/services/refactoring/test_all.dart
+++ b/pkg/analysis_server/test/services/refactoring/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/search/element_visitors_test.dart b/pkg/analysis_server/test/services/search/element_visitors_test.dart
index ef2c208..5739ea8 100644
--- a/pkg/analysis_server/test/services/search/element_visitors_test.dart
+++ b/pkg/analysis_server/test/services/search/element_visitors_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/services/search/hierarchy_test.dart b/pkg/analysis_server/test/services/search/hierarchy_test.dart
index cec129e4..785345a 100644
--- a/pkg/analysis_server/test/services/search/hierarchy_test.dart
+++ b/pkg/analysis_server/test/services/search/hierarchy_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/search/test_all.dart b/pkg/analysis_server/test/services/search/test_all.dart
index eed01b8..63d9465 100644
--- a/pkg/analysis_server/test/services/search/test_all.dart
+++ b/pkg/analysis_server/test/services/search/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/services/test_all.dart b/pkg/analysis_server/test/services/test_all.dart
index 2d77c25..76edf82 100644
--- a/pkg/analysis_server/test/services/test_all.dart
+++ b/pkg/analysis_server/test/services/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 5a8dfcb..7242529 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/computer/closingLabels_computer_test.dart b/pkg/analysis_server/test/src/computer/closingLabels_computer_test.dart
index f748909..9e6b5d2 100644
--- a/pkg/analysis_server/test/src/computer/closingLabels_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/closingLabels_computer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/computer/folding_computer_test.dart b/pkg/analysis_server/test/src/computer/folding_computer_test.dart
index 8fcde2d..3f2d2ae 100644
--- a/pkg/analysis_server/test/src/computer/folding_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/folding_computer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart b/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart
index 731ca5f..fde32c7 100644
--- a/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart b/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart
index 8a5dad4..8e123ae 100644
--- a/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/computer/outline_computer_test.dart b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
index eb45aad..643d144c 100644
--- a/pkg/analysis_server/test/src/computer/outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/computer/test_all.dart b/pkg/analysis_server/test/src/computer/test_all.dart
index 8159db8..c99b3c5 100644
--- a/pkg/analysis_server/test/src/computer/test_all.dart
+++ b/pkg/analysis_server/test/src/computer/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/domain_abstract_test.dart b/pkg/analysis_server/test/src/domain_abstract_test.dart
index dde70ce..41ba49d 100644
--- a/pkg/analysis_server/test/src/domain_abstract_test.dart
+++ b/pkg/analysis_server/test/src/domain_abstract_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/domains/execution/completion_test.dart b/pkg/analysis_server/test/src/domains/execution/completion_test.dart
index 41529c6..37ff7fa 100644
--- a/pkg/analysis_server/test/src/domains/execution/completion_test.dart
+++ b/pkg/analysis_server/test/src/domains/execution/completion_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/domains/execution/test_all.dart b/pkg/analysis_server/test/src/domains/execution/test_all.dart
index 20e6141..cde2384 100644
--- a/pkg/analysis_server/test/src/domains/execution/test_all.dart
+++ b/pkg/analysis_server/test/src/domains/execution/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/domains/test_all.dart b/pkg/analysis_server/test/src/domains/test_all.dart
index 81a4c82..ea67387 100644
--- a/pkg/analysis_server/test/src/domains/test_all.dart
+++ b/pkg/analysis_server/test/src/domains/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/flutter/flutter_correction_test.dart b/pkg/analysis_server/test/src/flutter/flutter_correction_test.dart
index 1d7ba263..1039fe9 100644
--- a/pkg/analysis_server/test/src/flutter/flutter_correction_test.dart
+++ b/pkg/analysis_server/test/src/flutter/flutter_correction_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart b/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
index 947fb79..18df136 100644
--- a/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart b/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart
index 84f8f04..0636227 100644
--- a/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart
+++ b/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/flutter/test_all.dart b/pkg/analysis_server/test/src/flutter/test_all.dart
index d209fd5..09ef471 100644
--- a/pkg/analysis_server/test/src/flutter/test_all.dart
+++ b/pkg/analysis_server/test/src/flutter/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart b/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart
index caba741..3a557bb 100644
--- a/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart
+++ b/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/src/plugin/notification_manager_test.dart b/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
index ae42433..124dfd5 100644
--- a/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
+++ b/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart b/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart
index 6bfaf1d..c21b06d 100644
--- a/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart
+++ b/pkg/analysis_server/test/src/plugin/protocol_test_utilities.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/plugin/request_converter_test.dart b/pkg/analysis_server/test/src/plugin/request_converter_test.dart
index 527623b..c0a3d1c 100644
--- a/pkg/analysis_server/test/src/plugin/request_converter_test.dart
+++ b/pkg/analysis_server/test/src/plugin/request_converter_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/plugin/result_collector_test.dart b/pkg/analysis_server/test/src/plugin/result_collector_test.dart
index e6372c6..d628c63 100644
--- a/pkg/analysis_server/test/src/plugin/result_collector_test.dart
+++ b/pkg/analysis_server/test/src/plugin/result_collector_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/plugin/result_converter_test.dart b/pkg/analysis_server/test/src/plugin/result_converter_test.dart
index ffe30cd..5c947aa 100644
--- a/pkg/analysis_server/test/src/plugin/result_converter_test.dart
+++ b/pkg/analysis_server/test/src/plugin/result_converter_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/plugin/result_merger_test.dart b/pkg/analysis_server/test/src/plugin/result_merger_test.dart
index 75f11fa..0b051e6 100644
--- a/pkg/analysis_server/test/src/plugin/result_merger_test.dart
+++ b/pkg/analysis_server/test/src/plugin/result_merger_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/plugin/test_all.dart b/pkg/analysis_server/test/src/plugin/test_all.dart
index a1f7564..48883d7 100644
--- a/pkg/analysis_server/test/src/plugin/test_all.dart
+++ b/pkg/analysis_server/test/src/plugin/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_constructor_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_constructor_test.dart
index d5e8dd5..c847a3d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_constructor_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_constructor_test.dart
@@ -34,9 +34,51 @@
 
 @reflectiveTest
 class CreateConstructorTest extends FixProcessorTest {
+  static final _text200 = 'x' * 200;
+
   @override
   FixKind get kind => DartFixKind.CREATE_CONSTRUCTOR;
 
+  test_inLibrary_insteadOfSyntheticDefault() async {
+    var a = newFile('/home/test/lib/a.dart', content: '''
+/// $_text200
+class A {}
+''').path;
+    await resolveTestUnit('''
+import 'a.dart';
+
+main() {
+  new A.named(1, 2.0);
+}
+''');
+    await assertHasFix('''
+/// $_text200
+class A {
+  A.named(int i, double d);
+}
+''', target: a);
+  }
+
+  test_inLibrary_named() async {
+    var a = newFile('/home/test/lib/a.dart', content: '''
+/// $_text200
+class A {}
+''').path;
+    await resolveTestUnit('''
+import 'a.dart';
+
+main() {
+  new A(1, 2.0);
+}
+''');
+    await assertHasFix('''
+/// $_text200
+class A {
+  A(int i, double d);
+}
+''', target: a);
+  }
+
   test_insteadOfSyntheticDefault() async {
     await resolveTestUnit('''
 class A {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
index 68d5820..78de092 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
@@ -362,6 +362,53 @@
 ''');
   }
 
+  test_withFunction_functionTopLevelVariable() async {
+    addSource('/home/test/lib/lib.dart', 'var myFunction = () {};');
+    await resolveTestUnit('''
+main() {
+  myFunction();
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart';
+
+main() {
+  myFunction();
+}
+''');
+  }
+
+  test_withFunction_preferFunctionOverTopLevelVariable() async {
+    _configureMyPkg({
+      'b.dart': 'var myFunction = () {};',
+      'a.dart': 'myFunction() {}',
+    });
+    await resolveTestUnit('''
+main() {
+  myFunction();
+}
+''');
+    await assertHasFix('''
+import 'package:my_pkg/a.dart';
+
+main() {
+  myFunction();
+}
+''');
+  }
+
+  @failingTest
+  test_withFunction_nonFunctionType() async {
+    // TODO Remove preferFunctionOverTopLevelVariable test once this is passing
+    addSource('/home/test/lib/lib.dart', 'int zero = 0;');
+    await resolveTestUnit('''
+main() {
+  zero();
+}
+''');
+    await assertNoFix();
+  }
+
   test_withTopLevelVariable() async {
     addSource('/home/test/lib/lib.dart', '''
 library lib;
diff --git a/pkg/analysis_server/test/src/utilities/flutter_test.dart b/pkg/analysis_server/test/src/utilities/flutter_test.dart
index c148ef0..20193cb 100644
--- a/pkg/analysis_server/test/src/utilities/flutter_test.dart
+++ b/pkg/analysis_server/test/src/utilities/flutter_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/utilities/profiling_test.dart b/pkg/analysis_server/test/src/utilities/profiling_test.dart
index 4906c4b..ccc4c22 100644
--- a/pkg/analysis_server/test/src/utilities/profiling_test.dart
+++ b/pkg/analysis_server/test/src/utilities/profiling_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/src/utilities/test_all.dart b/pkg/analysis_server/test/src/utilities/test_all.dart
index cf5d6fc..580e29b 100644
--- a/pkg/analysis_server/test/src/utilities/test_all.dart
+++ b/pkg/analysis_server/test/src/utilities/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/stress/replay/operation.dart b/pkg/analysis_server/test/stress/replay/operation.dart
index dbacce9..fc6334e 100644
--- a/pkg/analysis_server/test/stress/replay/operation.dart
+++ b/pkg/analysis_server/test/stress/replay/operation.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
index d713f0a..60397de 100644
--- a/pkg/analysis_server/test/stress/replay/replay.dart
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/stress/utilities/git.dart b/pkg/analysis_server/test/stress/utilities/git.dart
index 1be2307..0b16361 100644
--- a/pkg/analysis_server/test/stress/utilities/git.dart
+++ b/pkg/analysis_server/test/stress/utilities/git.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/stress/utilities/logger.dart b/pkg/analysis_server/test/stress/utilities/logger.dart
index acf7a74..bbdd406 100644
--- a/pkg/analysis_server/test/stress/utilities/logger.dart
+++ b/pkg/analysis_server/test/stress/utilities/logger.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index 5afc1e7..e26c43d 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/timing/completion/completion_simple.dart b/pkg/analysis_server/test/timing/completion/completion_simple.dart
index 50cbaa2..2e8164a 100644
--- a/pkg/analysis_server/test/timing/completion/completion_simple.dart
+++ b/pkg/analysis_server/test/timing/completion/completion_simple.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/timing/timing_framework.dart b/pkg/analysis_server/test/timing/timing_framework.dart
index 9c4be1f..d02e6f0 100644
--- a/pkg/analysis_server/test/timing/timing_framework.dart
+++ b/pkg/analysis_server/test/timing/timing_framework.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart b/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
index bcffd7a..fbf2615 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/test/tool/lsp_spec/json_test.dart b/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
index b352d18..df7a3c8 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
@@ -89,6 +89,42 @@
           .replaceAll(new RegExp('[ \n]'), '');
       expect(output, equals(expected));
     });
+
+    test('ResponseMessage does not include an error with a result', () {
+      final id = new Either2<num, String>.t1(1);
+      final result = 'my result';
+      final resp = new ResponseMessage(id, result, null, jsonRpcVersion);
+      final jsonMap = resp.toJson();
+      expect(jsonMap, contains('result'));
+      expect(jsonMap, isNot(contains('error')));
+    });
+
+    test('ResponseMessage can include a null result', () {
+      final id = new Either2<num, String>.t1(1);
+      final resp = new ResponseMessage(id, null, null, jsonRpcVersion);
+      final jsonMap = resp.toJson();
+      expect(jsonMap, contains('result'));
+      expect(jsonMap, isNot(contains('error')));
+    });
+
+    test('ResponseMessage does not include a result for an error', () {
+      final id = new Either2<num, String>.t1(1);
+      final error =
+          new ResponseError<String>(ErrorCodes.ParseError, 'Error', null);
+      final resp = new ResponseMessage(id, null, error, jsonRpcVersion);
+      final jsonMap = resp.toJson();
+      expect(jsonMap, contains('error'));
+      expect(jsonMap, isNot(contains('result')));
+    });
+
+    test('ResponseMessage throws if both result and error are non-null', () {
+      final id = new Either2<num, String>.t1(1);
+      final result = 'my result';
+      final error =
+          new ResponseError<String>(ErrorCodes.ParseError, 'Error', null);
+      final resp = new ResponseMessage(id, result, error, jsonRpcVersion);
+      expect(resp.toJson, throwsA(new TypeMatcher<String>()));
+    });
   });
 
   group('fromJson', () {
@@ -121,6 +157,18 @@
       final message = NotificationMessage.fromJson(jsonDecode(input));
       expect(message.params, isNull);
     });
+
+    test('deserialises subtypes into the correct class', () {
+      // Create some JSON that includes a VersionedTextDocumentIdenfitier but
+      // where the class definition only references a TextDocumentIdemntifier.
+      final input = jsonEncode(new TextDocumentPositionParams(
+        new VersionedTextDocumentIdentifier(111, 'file:///foo/bar.dart'),
+        new Position(1, 1),
+      ).toJson());
+      final params = TextDocumentPositionParams.fromJson(jsonDecode(input));
+      expect(params.textDocument,
+          const TypeMatcher<VersionedTextDocumentIdentifier>());
+    });
   });
 
   test('objects with lists can round-trip through to json and back', () {
diff --git a/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart b/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
index 103392d..abf1791 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
@@ -21,7 +21,7 @@
 	options?: OptionKind[];
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Interface>());
       final Interface interface = output[0];
@@ -46,7 +46,7 @@
   };
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       // Length is two because we'll fabricate the type of textDoc.
       expect(output, hasLength(2));
 
@@ -87,7 +87,7 @@
 	options1: any;
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Interface>());
       final Interface interface = output[0];
@@ -106,7 +106,7 @@
 	data?: D;
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Interface>());
       final Interface interface = output[0];
@@ -128,7 +128,7 @@
 	params?: Array<any> | object;
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Interface>());
       final Interface interface = output[0];
@@ -152,7 +152,7 @@
 	changes: { [uri: string]: TextEdit[]; };
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Interface>());
       final Interface interface = output[0];
@@ -173,7 +173,7 @@
   canBeUndefined?: string;
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       final Interface interface = output[0];
       expect(interface.members, hasLength(4));
       interface.members.forEach((m) => expect(m, const TypeMatcher<Field>()));
@@ -213,7 +213,7 @@
   a: a;
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       final Interface interface = output[0];
       expect(interface.commentText, equals('''
 Describes the what this class in lots of words that wrap onto multiple lines that will need re-wrapping to format nicely when converted into Dart.
@@ -234,7 +234,7 @@
       final String input = '''
 export type DocumentSelector = DocumentFilter[];
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<TypeAlias>());
       final TypeAlias typeAlias = output[0];
@@ -261,7 +261,7 @@
 	export const Rename: ResourceOperationKind = 'rename';
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Namespace>());
       final Namespace namespace = output[0];
@@ -290,7 +290,7 @@
 	label: string | [number, number];
 }
     ''';
-      final List<AstNode> output = parseFile(input);
+      final List<AstNode> output = parseString(input);
       expect(output, hasLength(1));
       expect(output[0], const TypeMatcher<Interface>());
       final Interface interface = output[0];
diff --git a/pkg/analysis_server/tool/instrumentation/log/log.dart b/pkg/analysis_server/tool/instrumentation/log/log.dart
index 10dfd90..f575765 100644
--- a/pkg/analysis_server/tool/instrumentation/log/log.dart
+++ b/pkg/analysis_server/tool/instrumentation/log/log.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/instrumentation/log_viewer.dart b/pkg/analysis_server/tool/instrumentation/log_viewer.dart
index 62d5722..6edb34b 100644
--- a/pkg/analysis_server/tool/instrumentation/log_viewer.dart
+++ b/pkg/analysis_server/tool/instrumentation/log_viewer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/instrumentation/page/log_page.dart b/pkg/analysis_server/tool/instrumentation/page/log_page.dart
index b537580..bb9b9c9 100644
--- a/pkg/analysis_server/tool/instrumentation/page/log_page.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/log_page.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/instrumentation/page/page_writer.dart b/pkg/analysis_server/tool/instrumentation/page/page_writer.dart
index dca5673..3d1d68a 100644
--- a/pkg/analysis_server/tool/instrumentation/page/page_writer.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/page_writer.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/instrumentation/page/stats_page.dart b/pkg/analysis_server/tool/instrumentation/page/stats_page.dart
index a8932a1..907f16c 100644
--- a/pkg/analysis_server/tool/instrumentation/page/stats_page.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/stats_page.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/instrumentation/page/task_page.dart b/pkg/analysis_server/tool/instrumentation/page/task_page.dart
index f5cd312..e553eab 100644
--- a/pkg/analysis_server/tool/instrumentation/page/task_page.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/task_page.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/instrumentation/server.dart b/pkg/analysis_server/tool/instrumentation/server.dart
index bfeb7cc..4fd50e1 100644
--- a/pkg/analysis_server/tool/instrumentation/server.dart
+++ b/pkg/analysis_server/tool/instrumentation/server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index a8ad68e..fe5bf80 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -38,6 +38,7 @@
 | client/registerCapability | | | | | unused, but should be used for DocumentSelector at least
 | client/unregisterCapability | | | | |
 | workspace/didChangeWatchedFiles | | | | | unused, server does own watching |
+| workspace/didChangeWorkspaceFolders | ✅ | ✅ | ✅ | ✅ |
 | workspace/symbol | | | | |
 | workspace/executeCommand | ✅ | ✅ | ✅ | ✅ |
 | workspace/applyEdit | ✅ | ✅ | ✅ | ✅ |
@@ -55,13 +56,13 @@
 | textDocument/typeDefinition | | | | |
 | textDocument/implementation | | | | |
 | textDocument/references | ✅ | ✅ | ✅ | ✅ |
-| textDocument/documentHighlight | | | | |
+| textDocument/documentHighlight | ✅ | ✅ | ✅ | ✅ |
 | textDocument/documentSymbol | ✅ | ✅ | ✅ | ✅ |
 | textDocument/codeAction (sortMembers) | ✅ | ✅ | ✅ | ✅ |
 | textDocument/codeAction (organiseImports) | ✅ | ✅ | ✅ | ✅ |
 | textDocument/codeAction (refactors) | | | | |
-| textDocument/codeAction (assists) | ✅ | ✅ | ✅ | |
-| textDocument/codeAction (fixes) | ✅ | ✅ | ✅ | |
+| textDocument/codeAction (assists) | ✅ | ✅ | ✅ | ✅ |
+| textDocument/codeAction (fixes) | ✅ | ✅ | ✅ | ✅ |
 | textDocument/codeLens | | | | |
 | codeLens/resolve | | | | |
 | textDocument/documentLink | | | | |
@@ -69,7 +70,7 @@
 | textDocument/formatting | ✅ | ✅ | ✅ | ✅ |
 | textDocument/rangeFormatting | | | | | requires support from dart_style?
 | textDocument/onTypeFormatting | ✅ | ✅ | ✅ | ✅ |
-| textDocument/rename | | | | |
+| textDocument/rename | ✅ | ✅ | Incomplete! | |
 | textDocument/prepareRename | | | | |
 | textDocument/foldingRange | | | | |
 
diff --git a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
index 6b90396..6c87b90 100644
--- a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
+++ b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
@@ -9,6 +9,7 @@
 
 final formatter = new DartFormatter();
 Map<String, Interface> _interfaces = {};
+Map<String, List<String>> _subtypes = {};
 // TODO(dantup): Rename namespaces -> enums since they're always that now.
 Map<String, Namespace> _namespaces = {};
 Map<String, TypeAlias> _typeAliases = {};
@@ -31,9 +32,15 @@
   types
       .whereType<TypeAlias>()
       .forEach((alias) => _typeAliases[alias.name] = alias);
-  types
-      .whereType<Interface>()
-      .forEach((interface) => _interfaces[interface.name] = interface);
+  types.whereType<Interface>().forEach((interface) {
+    _interfaces[interface.name] = interface;
+    // Keep track of our base classes so they can look up their super classes
+    // later in their fromJson() to deserialise into the most specific type.
+    interface.baseTypes.forEach((base) {
+      final subTypes = _subtypes[base.dartType] ??= new List<String>();
+      subTypes.add(interface.name);
+    });
+  });
   types
       .whereType<Namespace>()
       .forEach((namespace) => _namespaces[namespace.name] = namespace);
@@ -403,6 +410,16 @@
     ..writeIndentedln('static ${interface.nameWithTypeArgs} '
         'fromJson${interface.typeArgsString}(Map<String, dynamic> json) {')
     ..indent();
+  // First check whether any of our subclasses can deserialise this.
+  for (final subclassName in _subtypes[interface.name] ?? const <String>[]) {
+    final subclass = _interfaces[subclassName];
+    buffer
+      ..writeIndentedln('if (${subclass.nameWithTypeArgs}.canParse(json)) {')
+      ..indent()
+      ..writeln('return ${subclass.nameWithTypeArgs}.fromJson(json);')
+      ..outdent()
+      ..writeIndentedln('}');
+  }
   for (final field in allFields) {
     buffer.writeIndented('final ${field.name} = ');
     _writeFromJsonCode(buffer, field.type, "json['${field.name}']",
@@ -471,9 +488,9 @@
 
 void _writeJsonMapAssignment(
     IndentableStringBuffer buffer, Field field, String mapName) {
-  // If we are allowed to be undefined (which essentially means required to be
-  // undefined and never explicitly null), we'll only add the value if set.
-  if (field.allowsUndefined) {
+  // If we are allowed to be undefined, we'll only add the value if set.
+  final shouldBeOmittedIfNoValue = field.allowsUndefined;
+  if (shouldBeOmittedIfNoValue) {
     buffer
       ..writeIndentedln('if (${field.name} != null) {')
       ..indent();
@@ -483,7 +500,7 @@
     buffer.write(''' ?? (throw '${field.name} is required but was not set')''');
   }
   buffer.writeln(';');
-  if (field.allowsUndefined) {
+  if (shouldBeOmittedIfNoValue) {
     buffer
       ..outdent()
       ..writeIndentedln('}');
@@ -511,8 +528,15 @@
     ..writeIndentedln('Map<String, dynamic> toJson() {')
     ..indent()
     ..writeIndentedln('Map<String, dynamic> __result = {};');
-  for (var field in _getAllFields(interface)) {
-    _writeJsonMapAssignment(buffer, field, '__result');
+  // ResponseMessage must confirm to JSON-RPC which says only one of
+  // result/error can be included. Since this isn't encoded in the types we
+  // need to special-case it's toJson generation.
+  if (interface.name == "ResponseMessage") {
+    _writeToJsonFieldsForResponseMessage(buffer, interface);
+  } else {
+    for (var field in _getAllFields(interface)) {
+      _writeJsonMapAssignment(buffer, field, '__result');
+    }
   }
   buffer
     ..writeIndentedln('return __result;')
@@ -520,6 +544,35 @@
     ..writeIndentedln('}');
 }
 
+void _writeToJsonFieldsForResponseMessage(
+    IndentableStringBuffer buffer, Interface interface) {
+  const mapName = '__result';
+
+  final allFields = _getAllFields(interface);
+  final standardFields =
+      allFields.where((f) => f.name != 'error' && f.name != 'result');
+
+  for (var field in standardFields) {
+    _writeJsonMapAssignment(buffer, field, mapName);
+  }
+
+  // Write special code for result/error so that only one is populated.
+  buffer
+    ..writeIndentedln('if (error != null && result != null) {')
+    ..indent()
+    ..writeIndentedln('''throw 'result and error cannot both be set';''')
+    ..outdent()
+    ..writeIndentedln('} else if (error != null) {')
+    ..indent()
+    ..writeIndentedln('''$mapName['error'] = error;''')
+    ..outdent()
+    ..writeIndentedln('} else {')
+    ..indent()
+    ..writeIndentedln('''$mapName['result'] = result;''')
+    ..outdent()
+    ..writeIndentedln('}');
+}
+
 void _writeToString(IndentableStringBuffer buffer, Interface interface) {
   buffer
     ..writeIndentedln('@override')
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index 8e93a31..909a06b 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:analysis_server/src/services/correction/strings.dart';
 import 'package:http/http.dart' as http;
 import 'package:path/path.dart' as path;
 
@@ -23,7 +24,7 @@
   final String spec = await fetchSpec();
   final List<AstNode> types = extractTypeScriptBlocks(spec)
       .where(shouldIncludeScriptBlock)
-      .map(parseFile)
+      .map(parseString)
       .expand((f) => f)
       .where(includeTypeDefinitionInOutput)
       .toList();
@@ -31,6 +32,10 @@
   // Generate an enum for all of the request methods to avoid strings.
   types.add(extractMethodsEnum(spec));
 
+  // Extract additional inline types that are specificed online in the `results`
+  // section of the doc.
+  types.addAll(extractResultsInlineTypes(spec));
+
   final String output = generateDartForTypes(types);
 
   new File(path.join(outFolder, 'protocol_generated.dart'))
@@ -89,6 +94,42 @@
 final Uri specUri = Uri.parse(
     'https://raw.githubusercontent.com/Microsoft/language-server-protocol/gh-pages/specification.md');
 
+/// Pattern to extract inline types from the `result: {xx, yy }` notes in the spec.
+/// Doesn't parse past full stops as some of these have english sentences tagged on
+/// the end that we don't want to parse.
+final _resultsInlineTypesPattern = new RegExp(r'''\* result:[^\.]*({.*})''');
+
+/// Extract inline types found directly in the `results:` sections of the spec
+/// that are not declared with their own names elsewhere.
+List<AstNode> extractResultsInlineTypes(String spec) {
+  InlineInterface toInterface(String typeDef) {
+    // The definition passed here will be a bare inline type, such as:
+    //
+    //     { range: Range, placeholder: string }
+    //
+    // In order to parse this, we'll just format it as a type alias and then
+    // run it through the standard parsing code.
+    final typeAlias = 'type temp = ${typeDef.replaceAll(',', ';')};';
+
+    final parsed = parseString(typeAlias);
+
+    // Extract the InlineInterface that was created.
+    InlineInterface interface = parsed.firstWhere((t) => t is InlineInterface);
+
+    // Create a new name based on the fields.
+    var newName = interface.members.map((m) => capitalize(m.name)).join('And');
+
+    return new InlineInterface(newName, interface.members);
+  }
+
+  return _resultsInlineTypesPattern
+      .allMatches(spec)
+      .map((m) => m.group(1).trim())
+      .toList()
+      .map(toInterface)
+      .toList();
+}
+
 Future<String> fetchSpec() async {
   final resp = await http.get(specUri);
   return resp.body;
diff --git a/pkg/analysis_server/tool/lsp_spec/typescript.dart b/pkg/analysis_server/tool/lsp_spec/typescript.dart
index 6f70d2b..6ff12a9 100644
--- a/pkg/analysis_server/tool/lsp_spec/typescript.dart
+++ b/pkg/analysis_server/tool/lsp_spec/typescript.dart
@@ -32,9 +32,15 @@
   return comment.trim();
 }
 
-/// Fixes up some enum types that are not as specific as they could be in the
-/// spec. For example, Diagnostic.severity is typed "number" but can be mapped
-/// to the DiagnosticSeverity enum class.
+/// Improves types in generated code, including:
+///
+/// - Fixes up some enum types that are not as specific as they could be in the
+///   spec. For example, Diagnostic.severity is typed "number" but can be mapped
+///   to the DiagnosticSeverity enum class.
+///
+/// - Narrows unions to single types where they're only generated on the server
+///   and we know we always use a specific type. This avoids wrapping a lot
+///   of code in `EitherX<Y,Z>.tX()` and simplifies the testing of them.
 String getImprovedType(String interfaceName, String fieldName) {
   const Map<String, Map<String, String>> _improvedTypeMappings = {
     "Diagnostic": {
@@ -72,6 +78,9 @@
     },
     "ParameterInformation": {
       "label": "String",
+    },
+    "ServerCapabilities": {
+      "changeNotifications": "bool",
     }
   };
 
diff --git a/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart b/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
index a7c8e4d..bd303e1 100644
--- a/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
+++ b/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
@@ -12,6 +12,8 @@
 
 final _validIdentifierCharacters = RegExp('[a-zA-Z0-9_]');
 
+bool isAnyType(TypeBase t) => t is Type && t.name == 'any';
+
 bool isNullType(TypeBase t) => t is Type && t.name == 'null';
 
 bool isUndefinedType(TypeBase t) => t is Type && t.name == 'undefined';
@@ -20,7 +22,7 @@
 /// of type names for inline types.
 const fieldNameForIndexer = 'indexer';
 
-List<AstNode> parseFile(String input) {
+List<AstNode> parseString(String input) {
   final scanner = new Scanner(input);
   final tokens = scanner.scan();
   final parser = new Parser(tokens);
@@ -298,7 +300,6 @@
     _eatUnwantedKeywords();
     final name = _consume(TokenType.IDENTIFIER, 'Expected identifier');
     var canBeUndefined = _match([TokenType.QUESTION]);
-    var canBeNull = false;
     _consume(TokenType.COLON, 'Expected :');
     TypeBase type;
     Token value;
@@ -327,16 +328,17 @@
     // Special handling for fields that have fixed values.
     if (value != null) {
       return new FixedValueField(
-          leadingComment, name, value, type, canBeNull, canBeUndefined);
+          leadingComment, name, value, type, false, canBeUndefined);
     }
 
+    var canBeNull = false;
     if (type is UnionType) {
       UnionType union = type;
       // Since undefined and null can appear in the union type list but we want to
       // handle it specially in the code generation, we promote them to fields on
       // the Field.
       canBeUndefined |= union.types.any(isUndefinedType);
-      canBeNull = union.types.any(isNullType);
+      canBeNull = union.types.any((t) => isNullType(t) || isAnyType(t));
       // Finally, we need to remove them from the union.
       final remainingTypes = union.types
           .where((t) => !isNullType(t) && !isUndefinedType(t))
@@ -349,6 +351,11 @@
       type = remainingTypes.length > 1
           ? new UnionType(remainingTypes)
           : remainingTypes.single;
+    } else if (isAnyType(type)) {
+      // There are values in the spec marked as `any` that allow nulls (for
+      // example, the result field on ResponseMessage can be null for a
+      // successful response that has no return value, eg. shutdown).
+      canBeNull = true;
     }
     return Field(leadingComment, name, type, canBeNull, canBeUndefined);
   }
diff --git a/pkg/analysis_server/tool/spec/api.dart b/pkg/analysis_server/tool/spec/api.dart
index 1fd0c67..6e98267 100644
--- a/pkg/analysis_server/tool/spec/api.dart
+++ b/pkg/analysis_server/tool/spec/api.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/check_all_test.dart b/pkg/analysis_server/tool/spec/check_all_test.dart
index cd313ee..3aefa25 100644
--- a/pkg/analysis_server/tool/spec/check_all_test.dart
+++ b/pkg/analysis_server/tool/spec/check_all_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_analysis_server.dart b/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
index b713e60..75fc69c 100644
--- a/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
+++ b/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_dart.dart b/pkg/analysis_server/tool/spec/codegen_dart.dart
index 8b736bb..f6d1533 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index f34ea9c..adb57f7 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
index 88870a7a..8fec4fa 100644
--- a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
+++ b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_java.dart b/pkg/analysis_server/tool/spec/codegen_java.dart
index d1e02b4..9956fe1 100644
--- a/pkg/analysis_server/tool/spec/codegen_java.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_java_types.dart b/pkg/analysis_server/tool/spec/codegen_java_types.dart
index dd963d0..2006405 100644
--- a/pkg/analysis_server/tool/spec/codegen_java_types.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java_types.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_matchers.dart b/pkg/analysis_server/tool/spec/codegen_matchers.dart
index 480e46f..226c707 100644
--- a/pkg/analysis_server/tool/spec/codegen_matchers.dart
+++ b/pkg/analysis_server/tool/spec/codegen_matchers.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart b/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart
index 658f2c7..7530d39 100644
--- a/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart
+++ b/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/from_html.dart b/pkg/analysis_server/tool/spec/from_html.dart
index 79f5882..be77a02 100644
--- a/pkg/analysis_server/tool/spec/from_html.dart
+++ b/pkg/analysis_server/tool/spec/from_html.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/generate_all.dart b/pkg/analysis_server/tool/spec/generate_all.dart
index a29593d..c5afd22 100644
--- a/pkg/analysis_server/tool/spec/generate_all.dart
+++ b/pkg/analysis_server/tool/spec/generate_all.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/CompletionSuggestion.java b/pkg/analysis_server/tool/spec/generated/java/types/CompletionSuggestion.java
index 073d802..83f2643 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/CompletionSuggestion.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/CompletionSuggestion.java
@@ -60,6 +60,12 @@
   private final String displayText;
 
   /**
+   * The URI of the element corresponding to this suggestion. It will be set whenever analysis server
+   * is able to compute it.
+   */
+  private final String elementUri;
+
+  /**
    * The offset, relative to the beginning of the completion, of where the selection should be placed
    * after insertion.
    */
@@ -169,11 +175,12 @@
   /**
    * Constructor for {@link CompletionSuggestion}.
    */
-  public CompletionSuggestion(String kind, int relevance, String completion, String displayText, int selectionOffset, int selectionLength, boolean isDeprecated, boolean isPotential, String docSummary, String docComplete, String declaringType, String defaultArgumentListString, int[] defaultArgumentListTextRanges, Element element, String returnType, List<String> parameterNames, List<String> parameterTypes, Integer requiredParameterCount, Boolean hasNamedParameters, String parameterName, String parameterType, String importUri) {
+  public CompletionSuggestion(String kind, int relevance, String completion, String displayText, String elementUri, int selectionOffset, int selectionLength, boolean isDeprecated, boolean isPotential, String docSummary, String docComplete, String declaringType, String defaultArgumentListString, int[] defaultArgumentListTextRanges, Element element, String returnType, List<String> parameterNames, List<String> parameterTypes, Integer requiredParameterCount, Boolean hasNamedParameters, String parameterName, String parameterType, String importUri) {
     this.kind = kind;
     this.relevance = relevance;
     this.completion = completion;
     this.displayText = displayText;
+    this.elementUri = elementUri;
     this.selectionOffset = selectionOffset;
     this.selectionLength = selectionLength;
     this.isDeprecated = isDeprecated;
@@ -203,6 +210,7 @@
         other.relevance == relevance &&
         ObjectUtilities.equals(other.completion, completion) &&
         ObjectUtilities.equals(other.displayText, displayText) &&
+        ObjectUtilities.equals(other.elementUri, elementUri) &&
         other.selectionOffset == selectionOffset &&
         other.selectionLength == selectionLength &&
         other.isDeprecated == isDeprecated &&
@@ -230,6 +238,7 @@
     int relevance = jsonObject.get("relevance").getAsInt();
     String completion = jsonObject.get("completion").getAsString();
     String displayText = jsonObject.get("displayText") == null ? null : jsonObject.get("displayText").getAsString();
+    String elementUri = jsonObject.get("elementUri") == null ? null : jsonObject.get("elementUri").getAsString();
     int selectionOffset = jsonObject.get("selectionOffset").getAsInt();
     int selectionLength = jsonObject.get("selectionLength").getAsInt();
     boolean isDeprecated = jsonObject.get("isDeprecated").getAsBoolean();
@@ -248,7 +257,7 @@
     String parameterName = jsonObject.get("parameterName") == null ? null : jsonObject.get("parameterName").getAsString();
     String parameterType = jsonObject.get("parameterType") == null ? null : jsonObject.get("parameterType").getAsString();
     String importUri = jsonObject.get("importUri") == null ? null : jsonObject.get("importUri").getAsString();
-    return new CompletionSuggestion(kind, relevance, completion, displayText, selectionOffset, selectionLength, isDeprecated, isPotential, docSummary, docComplete, declaringType, defaultArgumentListString, defaultArgumentListTextRanges, element, returnType, parameterNames, parameterTypes, requiredParameterCount, hasNamedParameters, parameterName, parameterType, importUri);
+    return new CompletionSuggestion(kind, relevance, completion, displayText, elementUri, selectionOffset, selectionLength, isDeprecated, isPotential, docSummary, docComplete, declaringType, defaultArgumentListString, defaultArgumentListTextRanges, element, returnType, parameterNames, parameterTypes, requiredParameterCount, hasNamedParameters, parameterName, parameterType, importUri);
   }
 
   public static List<CompletionSuggestion> fromJsonArray(JsonArray jsonArray) {
@@ -330,6 +339,14 @@
   }
 
   /**
+   * The URI of the element corresponding to this suggestion. It will be set whenever analysis server
+   * is able to compute it.
+   */
+  public String getElementUri() {
+    return elementUri;
+  }
+
+  /**
    * True if the function or method being suggested has at least one named parameter. This field is
    * omitted if the parameterNames field is omitted.
    */
@@ -444,6 +461,7 @@
     builder.append(relevance);
     builder.append(completion);
     builder.append(displayText);
+    builder.append(elementUri);
     builder.append(selectionOffset);
     builder.append(selectionLength);
     builder.append(isDeprecated);
@@ -473,6 +491,9 @@
     if (displayText != null) {
       jsonObject.addProperty("displayText", displayText);
     }
+    if (elementUri != null) {
+      jsonObject.addProperty("elementUri", elementUri);
+    }
     jsonObject.addProperty("selectionOffset", selectionOffset);
     jsonObject.addProperty("selectionLength", selectionLength);
     jsonObject.addProperty("isDeprecated", isDeprecated);
@@ -546,6 +567,8 @@
     builder.append(completion + ", ");
     builder.append("displayText=");
     builder.append(displayText + ", ");
+    builder.append("elementUri=");
+    builder.append(elementUri + ", ");
     builder.append("selectionOffset=");
     builder.append(selectionOffset + ", ");
     builder.append("selectionLength=");
diff --git a/pkg/analysis_server/tool/spec/implied_types.dart b/pkg/analysis_server/tool/spec/implied_types.dart
index 49531b7..856b2a4 100644
--- a/pkg/analysis_server/tool/spec/implied_types.dart
+++ b/pkg/analysis_server/tool/spec/implied_types.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 0266e7c..2418991 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  <version>1.21.1</version>
+  <version>1.22.1</version>
 </h1>
 <p>
   This document contains a specification of the API provided by the
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart
index a2c1b37..1683331 100644
--- a/pkg/analysis_server/tool/spec/to_html.dart
+++ b/pkg/analysis_server/tool/spec/to_html.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 15c626a..fd21adb 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.21.1';
+const String PROTOCOL_VERSION = '1.22.1';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 547cb82..0260c07 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -534,6 +534,9 @@
   /// Return `true` if this element has an annotation of the form `@JS(..)`.
   bool get hasJS;
 
+  /// Return `true` if this element has an annotation of the form '@literal'.
+  bool get hasLiteral;
+
   /// Return `true` if this element has an annotation of the form `@override`.
   bool get hasOverride;
 
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index dc89edf..f2ddef8 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -75,6 +75,12 @@
   bool get isDartCoreFunction;
 
   /**
+   * Return `true` if this type represents the type 'int' defined in the
+   * dart:core library.
+   */
+  bool get isDartCoreInt;
+
+  /**
    * Return `true` if this type represents the type 'Null' defined in the
    * dart:core library.
    */
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 7ffa3f6..fdaed1b 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -277,9 +277,10 @@
   HintCode.DEAD_CODE,
   HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
   HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
-  HintCode.DEPRECATED_MEMBER_USE,
-  HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION,
   HintCode.DEPRECATED_EXTENDS_FUNCTION,
+  HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION,
+  HintCode.DEPRECATED_MEMBER_USE,
+  HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE,
   HintCode.DEPRECATED_MIXIN_FUNCTION,
   HintCode.DIVISION_OPTIMIZATION,
   HintCode.DUPLICATE_IMPORT,
@@ -288,7 +289,6 @@
   HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE,
   HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE,
   HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION,
-  HintCode.INVALID_ASSIGNMENT,
   HintCode.INVALID_FACTORY_ANNOTATION,
   HintCode.INVALID_FACTORY_METHOD_DECL,
   HintCode.INVALID_FACTORY_METHOD_IMPL,
@@ -310,6 +310,8 @@
   HintCode.MIXIN_ON_SEALED_CLASS,
   HintCode.MUST_BE_IMMUTABLE,
   HintCode.MUST_CALL_SUPER,
+  HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR,
+  HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW,
   HintCode.NULL_AWARE_BEFORE_OPERATOR,
   HintCode.NULL_AWARE_IN_CONDITION,
   HintCode.NULL_AWARE_IN_LOGICAL_OPERATOR,
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 5e2a359..960c862 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -40,6 +40,7 @@
 import 'package:analyzer/src/workspace/bazel.dart';
 import 'package:analyzer/src/workspace/gn.dart';
 import 'package:analyzer/src/workspace/package_build.dart';
+import 'package:analyzer/src/workspace/pub.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:args/args.dart';
 import 'package:package_config/packages.dart';
@@ -672,16 +673,19 @@
   static Workspace createWorkspace(ResourceProvider resourceProvider,
       String rootPath, ContextBuilder contextBuilder) {
     if (_hasPackageFileInPath(resourceProvider, rootPath)) {
-      // Bazel workspaces that include package files are treated like normal
-      // (non-Bazel) directories. But may still use package:build.
+      // A Bazel or Gn workspace that includes a '.packages' file is treated
+      // like a normal (non-Bazel/Gn) directory. But may still use
+      // package:build or Pub.
       return PackageBuildWorkspace.find(
               resourceProvider, rootPath, contextBuilder) ??
+          PubWorkspace.find(resourceProvider, rootPath, contextBuilder) ??
           BasicWorkspace.find(resourceProvider, rootPath, contextBuilder);
     }
     Workspace workspace = BazelWorkspace.find(resourceProvider, rootPath);
     workspace ??= GnWorkspace.find(resourceProvider, rootPath);
     workspace ??=
         PackageBuildWorkspace.find(resourceProvider, rootPath, contextBuilder);
+    workspace ??= PubWorkspace.find(resourceProvider, rootPath, contextBuilder);
     return workspace ??
         BasicWorkspace.find(resourceProvider, rootPath, contextBuilder);
   }
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index f26ad7d..eebc966 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -262,61 +262,9 @@
 
   @override
   void set analysisOptions(AnalysisOptions options) {
-    bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
-            options.analyzeFunctionBodiesPredicate ||
-        this._options.generateImplicitErrors !=
-            options.generateImplicitErrors ||
-        this._options.generateSdkErrors != options.generateSdkErrors ||
-        this._options.dart2jsHint != options.dart2jsHint ||
-        _notEqual(
-            this._options.enabledPluginNames, options.enabledPluginNames) ||
-        _notEqual(this._options.errorProcessors, options.errorProcessors) ||
-        _notEqual(this._options.excludePatterns, options.excludePatterns) ||
-        (this._options.hint && !options.hint) ||
-        (this._options.lint && !options.lint) ||
-        _notEqual(this._options.lintRules, options.lintRules) ||
-        this._options.preserveComments != options.preserveComments ||
-        this._options.useFastaParser != options.useFastaParser ||
-        this._options.enableLazyAssignmentOperators !=
-            options.enableLazyAssignmentOperators ||
-        ((options is AnalysisOptionsImpl)
-            ? this._options.strongModeHints != options.strongModeHints
-            : false) ||
-        ((options is AnalysisOptionsImpl)
-            ? this._options.implicitCasts != options.implicitCasts
-            : false) ||
-        ((options is AnalysisOptionsImpl)
-            ? this._options.implicitDynamic != options.implicitDynamic
-            : false) ||
-        !_samePatchPaths(this._options.patchPaths, options.patchPaths);
-    this._options.analyzeFunctionBodiesPredicate =
-        options.analyzeFunctionBodiesPredicate;
-    this._options.generateImplicitErrors = options.generateImplicitErrors;
-    this._options.generateSdkErrors = options.generateSdkErrors;
-    this._options.dart2jsHint = options.dart2jsHint;
-    this._options.enableLazyAssignmentOperators =
-        options.enableLazyAssignmentOperators;
-    this._options.enableTiming = options.enableTiming;
-    this._options.enabledPluginNames = options.enabledPluginNames;
-    this._options.errorProcessors = options.errorProcessors;
-    this._options.excludePatterns = options.excludePatterns;
-    this._options.hint = options.hint;
-    this._options.lint = options.lint;
-    this._options.lintRules = options.lintRules;
-    this._options.preserveComments = options.preserveComments;
-    this._options.useFastaParser = options.useFastaParser;
-    this._options.trackCacheDependencies = options.trackCacheDependencies;
-    this._options.disableCacheFlushing = options.disableCacheFlushing;
-    this._options.patchPaths = options.patchPaths;
-    if (options is AnalysisOptionsImpl) {
-      this._options.strongModeHints = options.strongModeHints;
-      this._options.implicitCasts = options.implicitCasts;
-      this._options.implicitDynamic = options.implicitDynamic;
-    }
-    if (needsRecompute) {
-      for (WorkManager workManager in workManagers) {
-        workManager.onAnalysisOptionsChanged();
-      }
+    this._options = options;
+    for (WorkManager workManager in workManagers) {
+      workManager.onAnalysisOptionsChanged();
     }
   }
 
@@ -1650,19 +1598,6 @@
     AnalysisEngine.instance.logger.logInformation(message);
   }
 
-  bool _notEqual<T>(List<T> first, List<T> second) {
-    int length = first.length;
-    if (length != second.length) {
-      return true;
-    }
-    for (int i = 0; i < length; i++) {
-      if (first[i] != second[i]) {
-        return true;
-      }
-    }
-    return false;
-  }
-
   /**
    * Notify all of the analysis listeners that the errors associated with the
    * given [source] has been updated to the given [errors].
@@ -1803,21 +1738,6 @@
     _removeFromCache(source);
     _removeFromPriorityOrder(source);
   }
-
-  static bool _samePatchPaths(
-      Map<String, List<String>> a, Map<String, List<String>> b) {
-    if (a.length != b.length) return false;
-    for (var key in a.keys) {
-      if (!b.containsKey(key)) return false;
-      var aValue = a[key];
-      var bValue = b[key];
-      if (aValue.length != bValue.length) return false;
-      for (var i = 0; i < aValue.length; i++) {
-        if (aValue[i] != bValue[i]) return false;
-      }
-    }
-    return true;
-  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 9369ec0..e8c9902 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -550,7 +550,13 @@
     }
     if (AnalysisEngine.isDartFileName(path)) {
       _fileTracker.addFile(path);
-      _changeFile(path);
+      // If the file is known, it has already been read, even if it did not
+      // exist. Now we are notified that the file exists, so we need to
+      // re-read it and make sure that we invalidate signature of the files
+      // that reference it.
+      if (_fsState.knownFilePaths.contains(path)) {
+        _changeFile(path);
+      }
     }
   }
 
@@ -1330,15 +1336,9 @@
    * Implementation for [changeFile].
    */
   void _changeFile(String path) {
-    // If the file is known, it has already been read, even if it din't exist.
-    // Now we are notified that the file changed (just changed or added), so we
-    // need to re-read it and make sure that we invalidate signature of the
-    // files that reference it.
-    if (_fsState.knownFilePaths.contains(path)) {
-      _fileTracker.changeFile(path);
-      _libraryContext = null;
-      _priorityResults.clear();
-    }
+    _fileTracker.changeFile(path);
+    _libraryContext = null;
+    _priorityResults.clear();
   }
 
   /**
@@ -1807,7 +1807,7 @@
     }
     try {
       List<AnalysisDriverExceptionFileBuilder> contextFiles = libraryFile
-          .libraryFiles
+          .transitiveFiles
           .map((file) => new AnalysisDriverExceptionFileBuilder(
               path: file.path, content: file.content))
           .toList();
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.dart
index 8dad745..4a016fa 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.dart
@@ -40,12 +40,18 @@
   /// String to enable the experiment "constant-update"
   static const String constant_update_2018 = 'constant-update-2018';
 
+  /// String to enable the experiment "control-flow-collections"
+  static const String control_flow_collections = 'control-flow-collections';
+
   /// String to enable the experiment "non-nullable"
   static const String non_nullable = 'non-nullable';
 
   /// String to enable the experiment "set-literals"
   static const String set_literals = 'set-literals';
 
+  /// String to enable the experiment "spread-collections"
+  static const String spread_collections = 'spread-collections';
+
   /// String to enable the experiment "bogus-disabled"
   static const String bogus_disabled = 'bogus-disabled';
 
@@ -76,6 +82,18 @@
         IsEnabledByDefault.non_nullable,
         IsExpired.non_nullable,
         'Non Nullable'),
+    EnableString.control_flow_collections: const ExperimentalFeature(
+        3,
+        EnableString.control_flow_collections,
+        IsEnabledByDefault.control_flow_collections,
+        IsExpired.control_flow_collections,
+        'Control Flow Collections'),
+    EnableString.spread_collections: const ExperimentalFeature(
+        4,
+        EnableString.spread_collections,
+        IsEnabledByDefault.spread_collections,
+        IsExpired.spread_collections,
+        'Spread Collections'),
     EnableString.bogus_disabled: const ExperimentalFeature(
         null,
         EnableString.bogus_disabled,
@@ -143,12 +161,18 @@
   /// Default state of the experiment "constant-update"
   static const bool constant_update_2018 = false;
 
+  /// Default state of the experiment "control-flow-collections"
+  static const bool control_flow_collections = false;
+
   /// Default state of the experiment "non-nullable"
   static const bool non_nullable = false;
 
   /// Default state of the experiment "set-literals"
   static const bool set_literals = false;
 
+  /// Default state of the experiment "spread-collections"
+  static const bool spread_collections = false;
+
   /// Default state of the experiment "bogus-disabled"
   static const bool bogus_disabled = false;
 
@@ -163,12 +187,18 @@
   /// Expiration status of the experiment "constant-update"
   static const bool constant_update_2018 = false;
 
+  /// Expiration status of the experiment "control-flow-collections"
+  static const bool control_flow_collections = false;
+
   /// Expiration status of the experiment "non-nullable"
   static const bool non_nullable = false;
 
   /// Expiration status of the experiment "set-literals"
   static const bool set_literals = false;
 
+  /// Expiration status of the experiment "spread-collections"
+  static const bool spread_collections = false;
+
   /// Expiration status of the experiment "bogus-disabled"
   static const bool bogus_disabled = true;
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 35f1df0..eb87535 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -361,6 +361,23 @@
   }
 
   /**
+   * Return the set of transitive files - the file itself and all of the
+   * directly or indirectly referenced files.
+   */
+  Set<FileState> get transitiveFiles {
+    var transitiveFiles = new Set<FileState>();
+
+    void appendReferenced(FileState file) {
+      if (transitiveFiles.add(file)) {
+        file._directReferencedFiles?.forEach(appendReferenced);
+      }
+    }
+
+    appendReferenced(this);
+    return transitiveFiles;
+  }
+
+  /**
    * Return the signature of the file, based on API signatures of the
    * transitive closure of imported / exported files.
    */
@@ -670,9 +687,8 @@
       return _createEmptyCompilationUnit();
     }
 
-    AnalysisOptions analysisOptions = _fsState._analysisOptions;
-    ExperimentStatus experimentStatus =
-        new ExperimentStatus.fromStrings(analysisOptions.enabledExperiments);
+    AnalysisOptionsImpl analysisOptions = _fsState._analysisOptions;
+    ExperimentStatus experimentStatus = analysisOptions.experimentStatus;
     CharSequenceReader reader = new CharSequenceReader(content);
     Scanner scanner = new Scanner(source, reader, errorListener);
     scanner.enableGtGtGt = experimentStatus.constant_update_2018;
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index a3813f6..8624f12 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/dart/analysis/experiments.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';
@@ -56,6 +55,7 @@
   final TypeProvider _typeProvider;
 
   final TypeSystem _typeSystem;
+  bool isNonNullableMigrated = false;
   LibraryElement _libraryElement;
 
   LibraryScope _libraryScope;
@@ -102,6 +102,8 @@
     for (FileState file in _library.libraryFiles) {
       units[file] = _parse(file);
     }
+    isNonNullableMigrated = (units.values.first as CompilationUnitImpl)
+        .hasPragmaAnalyzerNonNullable;
 
     // Resolve URIs in directives to corresponding sources.
     units.forEach((file, unit) {
@@ -182,13 +184,8 @@
    * Compute [_constants] in all units.
    */
   void _computeConstants() {
-    computeConstants(
-        _typeProvider,
-        _context.typeSystem,
-        _declaredVariables,
-        _constants.toList(),
-        ExperimentStatus.fromStrings(
-            _context.analysisOptions.enabledExperiments));
+    computeConstants(_typeProvider, _context.typeSystem, _declaredVariables,
+        _constants.toList(), _analysisOptions.experimentStatus);
   }
 
   void _computeHints(FileState file, CompilationUnit unit) {
@@ -603,11 +600,13 @@
     // TODO(scheglov) remove EnumMemberBuilder class
 
     new TypeParameterBoundsResolver(
-            _context.typeSystem, _libraryElement, source, errorListener)
+            _context.typeSystem, _libraryElement, source, errorListener,
+            isNonNullableMigrated: isNonNullableMigrated)
         .resolveTypeBounds(unit);
 
     unit.accept(new TypeResolverVisitor(
-        _libraryElement, source, _typeProvider, errorListener));
+        _libraryElement, source, _typeProvider, errorListener,
+        isNonNullableMigrated: isNonNullableMigrated));
 
     unit.accept(new VariableResolverVisitor(
         _libraryElement, source, _typeProvider, errorListener,
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 30e9486..453c439 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -12,12 +12,12 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
 /// Instances of the class `ConstantVerifier` traverse an AST structure looking
@@ -70,8 +70,9 @@
         _typeProvider, declaredVariables,
         forAnalysisDriver: forAnalysisDriver,
         typeSystem: _typeSystem,
-        experimentStatus: ExperimentStatus.fromStrings(
-            currentLibrary.context.analysisOptions.enabledExperiments));
+        experimentStatus:
+            (currentLibrary.context.analysisOptions as AnalysisOptionsImpl)
+                .experimentStatus);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index f23c65a..f764d36 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -12,7 +12,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/constant/compute.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
@@ -20,7 +19,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
 import 'package:analyzer/src/generated/engine.dart'
-    show AnalysisContext, AnalysisEngine;
+    show AnalysisContext, AnalysisEngine, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
@@ -2336,13 +2335,9 @@
   /// of this variable could not be computed because of errors.
   DartObject computeConstantValue() {
     if (evaluationResult == null) {
-      computeConstants(
-          context.typeProvider,
-          context.typeSystem,
-          context.declaredVariables,
-          [this],
-          ExperimentStatus.fromStrings(
-              context.analysisOptions.enabledExperiments));
+      AnalysisOptionsImpl analysisOptions = context.analysisOptions;
+      computeConstants(context.typeProvider, context.typeSystem,
+          context.declaredVariables, [this], analysisOptions.experimentStatus);
     }
     return evaluationResult?.value;
   }
@@ -2556,12 +2551,6 @@
       element.library?.name == _META_LIB_NAME;
 
   @override
-  bool get isLiteral =>
-      element is PropertyAccessorElement &&
-      element.name == _LITERAL_VARIABLE_NAME &&
-      element.library?.name == _META_LIB_NAME;
-
-  @override
   bool get isIsTest =>
       element is PropertyAccessorElement &&
       element.name == _IS_TEST_VARIABLE_NAME &&
@@ -2580,6 +2569,12 @@
       element.library?.name == _JS_LIB_NAME;
 
   @override
+  bool get isLiteral =>
+      element is PropertyAccessorElement &&
+      element.name == _LITERAL_VARIABLE_NAME &&
+      element.library?.name == _META_LIB_NAME;
+
+  @override
   bool get isMustCallSuper =>
       element is PropertyAccessorElement &&
       element.name == _MUST_CALL_SUPER_VARIABLE_NAME &&
@@ -2639,13 +2634,9 @@
   @override
   DartObject computeConstantValue() {
     if (evaluationResult == null) {
-      computeConstants(
-          context.typeProvider,
-          context.typeSystem,
-          context.declaredVariables,
-          [this],
-          ExperimentStatus.fromStrings(
-              context.analysisOptions.enabledExperiments));
+      AnalysisOptionsImpl analysisOptions = context.analysisOptions;
+      computeConstants(context.typeProvider, context.typeSystem,
+          context.declaredVariables, [this], analysisOptions.experimentStatus);
     }
     return constantValue;
   }
@@ -2836,6 +2827,18 @@
   }
 
   @override
+  bool get hasLiteral {
+    var metadata = this.metadata;
+    for (var i = 0; i < metadata.length; i++) {
+      var annotation = metadata[i];
+      if (annotation.isLiteral) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @override
   bool get hasOverride {
     var metadata = this.metadata;
     for (var i = 0; i < metadata.length; i++) {
@@ -4203,7 +4206,10 @@
 
   @override
   DartType get type {
-    if (unlinkedParam != null && unlinkedParam.type == null && field != null) {
+    if (unlinkedParam != null &&
+        unlinkedParam.type == null &&
+        !unlinkedParam.isFunctionTyped &&
+        field != null) {
       _type ??= field?.type ?? DynamicTypeImpl.instance;
     }
     return super.type;
@@ -6400,6 +6406,9 @@
   bool get hasJS => false;
 
   @override
+  bool get hasLiteral => false;
+
+  @override
   bool get hasOverride => false;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index 97f978f..67f47f7 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -46,6 +46,9 @@
   bool get hasJS => actualElement.hasJS;
 
   @override
+  bool get hasLiteral => actualElement.hasLiteral;
+
+  @override
   bool get hasNonFinalField => actualElement.hasNonFinalField;
 
   @override
@@ -389,6 +392,9 @@
   bool get hasJS => actualElement.hasJS;
 
   @override
+  bool get hasLiteral => actualElement.hasLiteral;
+
+  @override
   bool get hasOverride => actualElement.hasOverride;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index bc18d7b7..484458a 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -422,6 +422,9 @@
   bool get hasJS => _baseElement.hasJS;
 
   @override
+  bool get hasLiteral => _baseElement.hasLiteral;
+
+  @override
   bool get hasOverride => _baseElement.hasOverride;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 40d664e..6b7d311 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -56,14 +56,35 @@
  */
 class BottomTypeImpl extends TypeImpl {
   /**
-   * The unique instance of this class.
+   * The unique instance of this class, with indeterminate nullability.
    */
-  static final BottomTypeImpl instance = new BottomTypeImpl._();
+  static final BottomTypeImpl instance = instanceIndeterminate;
+
+  /**
+   * The unique instance of this class, nullable.
+   */
+  static final BottomTypeImpl instanceNullable =
+      new BottomTypeImpl._(Nullability.nullable);
+
+  /**
+   * The unique instance of this class, with indeterminate nullability.
+   */
+  static final BottomTypeImpl instanceIndeterminate =
+      new BottomTypeImpl._(Nullability.indeterminate);
+
+  /**
+   * The unique instance of this class, non-nullable.
+   */
+  static final BottomTypeImpl instanceNonNullable =
+      new BottomTypeImpl._(Nullability.nonNullable);
+
+  @override
+  final Nullability nullability;
 
   /**
    * Prevent the creation of instances of this class.
    */
-  BottomTypeImpl._() : super(null, "<bottom>");
+  BottomTypeImpl._(this.nullability) : super(null, "<bottom>");
 
   @override
   int get hashCode => 0;
@@ -111,6 +132,19 @@
           List<DartType> argumentTypes, List<DartType> parameterTypes,
           [List<FunctionTypeAliasElement> prune]) =>
       this;
+
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    switch (nullability) {
+      case Nullability.nullable:
+        return instanceNullable;
+      case Nullability.indeterminate:
+        return instanceIndeterminate;
+      case Nullability.nonNullable:
+        return instanceNonNullable;
+    }
+    throw StateError('Unexpected nullability: $nullability');
+  }
 }
 
 /**
@@ -119,7 +153,7 @@
  */
 class CircularFunctionTypeImpl extends DynamicTypeImpl
     implements _FunctionTypeImplLazy {
-  CircularFunctionTypeImpl() : super._circular();
+  CircularFunctionTypeImpl() : super._circular(Nullability.indeterminate);
 
   @override
   List<ParameterElement> get baseParameters => const <ParameterElement>[];
@@ -206,7 +240,8 @@
   bool operator ==(Object object) => object is CircularFunctionTypeImpl;
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes) {
+  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
+      {bool withNullability = false}) {
     buffer.write('...');
   }
 
@@ -227,6 +262,9 @@
   FunctionTypeImpl substitute3(List<DartType> argumentTypes) => this;
 
   @override
+  TypeImpl withNullability(Nullability nullability) => this;
+
+  @override
   void _forEachParameterType(
       ParameterKind kind, callback(String name, DartType type)) {
     // There are no parameters.
@@ -256,13 +294,14 @@
  * `...`.
  */
 class CircularTypeImpl extends DynamicTypeImpl {
-  CircularTypeImpl() : super._circular();
+  CircularTypeImpl() : super._circular(Nullability.indeterminate);
 
   @override
   bool operator ==(Object object) => object is CircularTypeImpl;
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes) {
+  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
+      {bool withNullability = false}) {
     buffer.write('...');
   }
 
@@ -292,8 +331,10 @@
   FunctionTypedElement _computedElement;
 
   DeferredFunctionTypeImpl(this._computeElement, String name,
-      List<DartType> typeArguments, bool isInstantiated)
-      : super._(null, name, null, typeArguments, null, null, isInstantiated);
+      List<DartType> typeArguments, bool isInstantiated,
+      {Nullability nullability = Nullability.indeterminate})
+      : super._(null, name, null, typeArguments, null, null, isInstantiated,
+            nullability: nullability);
 
   @override
   FunctionTypedElement get element {
@@ -303,6 +344,14 @@
     }
     return _computedElement;
   }
+
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    if (this.nullability == nullability) return this;
+    return DeferredFunctionTypeImpl(
+        _computeElement, name, typeArguments, isInstantiated,
+        nullability: nullability);
+  }
 }
 
 /**
@@ -310,14 +359,35 @@
  */
 class DynamicTypeImpl extends TypeImpl {
   /**
-   * The unique instance of this class.
+   * The unique instance of this class, with indeterminate nullability.
    */
-  static final DynamicTypeImpl instance = new DynamicTypeImpl._();
+  static final DynamicTypeImpl instance = instanceIndeterminate;
+
+  /**
+   * The unique instance of this class, nullable.
+   */
+  static final DynamicTypeImpl instanceNullable =
+      new DynamicTypeImpl._(Nullability.nullable);
+
+  /**
+   * The unique instance of this class, with indeterminate nullability.
+   */
+  static final DynamicTypeImpl instanceIndeterminate =
+      new DynamicTypeImpl._(Nullability.indeterminate);
+
+  /**
+   * The unique instance of this class, non-nullable.
+   */
+  static final DynamicTypeImpl instanceNonNullable =
+      new DynamicTypeImpl._(Nullability.nonNullable);
+
+  @override
+  final Nullability nullability;
 
   /**
    * Prevent the creation of instances of this class.
    */
-  DynamicTypeImpl._()
+  DynamicTypeImpl._(this.nullability)
       : super(new DynamicElementImpl(), Keyword.DYNAMIC.lexeme) {
     (element as DynamicElementImpl).type = this;
   }
@@ -325,7 +395,8 @@
   /**
    * Constructor used by [CircularTypeImpl].
    */
-  DynamicTypeImpl._circular() : super(instance.element, Keyword.DYNAMIC.lexeme);
+  DynamicTypeImpl._circular(this.nullability)
+      : super(instance.element, Keyword.DYNAMIC.lexeme);
 
   @override
   int get hashCode => 1;
@@ -378,23 +449,41 @@
     }
     return this;
   }
+
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    switch (nullability) {
+      case Nullability.nullable:
+        return instanceNullable;
+      case Nullability.indeterminate:
+        return instanceIndeterminate;
+      case Nullability.nonNullable:
+        return instanceNonNullable;
+    }
+    throw StateError('Unexpected nullability: $nullability');
+  }
 }
 
 /**
  * The type of a function, method, constructor, getter, or setter.
  */
 abstract class FunctionTypeImpl extends TypeImpl implements FunctionType {
+  @override
+  final Nullability nullability;
+
   /**
    * Initialize a newly created function type to be declared by the given
    * [element], and also initialize [typeArguments] to match the
    * [typeParameters], which permits later substitution.
    */
-  factory FunctionTypeImpl(FunctionTypedElement element) {
+  factory FunctionTypeImpl(FunctionTypedElement element,
+      {Nullability nullability = Nullability.indeterminate}) {
     if (element is FunctionTypeAliasElement) {
       throw new StateError('Use FunctionTypeImpl.forTypedef for typedefs');
     }
     return new _FunctionTypeImplLazy._(
-        element, null, null, null, null, null, false);
+        element, null, null, null, null, null, false,
+        nullability: nullability);
   }
 
   /**
@@ -404,9 +493,11 @@
    * Note: this constructor mishandles generics.
    * See https://github.com/dart-lang/sdk/issues/34657.
    */
-  factory FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element) {
+  factory FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element,
+      {Nullability nullability = Nullability.indeterminate}) {
     return new _FunctionTypeImplLazy._(
-        element, element?.name, null, null, null, null, false);
+        element, element?.name, null, null, null, null, false,
+        nullability: nullability);
   }
 
   /**
@@ -417,7 +508,9 @@
    * If type formals is empty, this returns the original unless [force] is set
    * to [true].
    */
-  factory FunctionTypeImpl.fresh(FunctionType original, {bool force = false}) {
+  factory FunctionTypeImpl.fresh(FunctionType original,
+      {bool force = false,
+      Nullability nullability = Nullability.indeterminate}) {
     // We build up a substitution for the type parameters,
     // {variablesFresh/variables} then apply it.
 
@@ -465,19 +558,21 @@
     function.returnType = newType.returnType;
     function.typeParameters = freshVarElements;
     function.shareParameters(newType.parameters);
-    return function.type = new FunctionTypeImpl(function);
+    return function.type =
+        new FunctionTypeImpl(function, nullability: nullability);
   }
 
   /// Creates a function type that's not associated with any element in the
   /// element tree.
-  factory FunctionTypeImpl.synthetic(
-      DartType returnType,
-      List<TypeParameterElement> typeFormals,
-      List<ParameterElement> parameters) {
-    return new _FunctionTypeImplStrict._(returnType, typeFormals, parameters);
+  factory FunctionTypeImpl.synthetic(DartType returnType,
+      List<TypeParameterElement> typeFormals, List<ParameterElement> parameters,
+      {Nullability nullability = Nullability.indeterminate}) {
+    return new _FunctionTypeImplStrict._(returnType, typeFormals, parameters,
+        nullability: nullability);
   }
 
-  FunctionTypeImpl._(Element element, String name) : super(element, name);
+  FunctionTypeImpl._(Element element, String name, this.nullability)
+      : super(element, name);
 
   @deprecated
   @override
@@ -626,7 +721,8 @@
   }
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes) {
+  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
+      {bool withNullability = false}) {
     if (visitedTypes.add(this)) {
       if (typeFormals.isNotEmpty) {
         // To print a type with type variables, first make sure we have unique
@@ -661,7 +757,7 @@
           }
           TypeParameterTypeImpl t =
               new TypeParameterTypeImpl(new TypeParameterElementImpl(name, -1));
-          t.appendTo(buffer, visitedTypes);
+          t.appendTo(buffer, visitedTypes, withNullability: withNullability);
           instantiateTypeArgs.add(t);
           variables.add(e.type);
           if (e.bound != null) {
@@ -675,7 +771,9 @@
 
         // Instantiate it and print the resulting type. After instantiation, it
         // will no longer have typeFormals, so we will continue below.
-        this.instantiate(instantiateTypeArgs).appendTo(buffer, visitedTypes);
+        this
+            .instantiate(instantiateTypeArgs)
+            .appendTo(buffer, visitedTypes, withNullability: withNullability);
         return;
       }
 
@@ -704,7 +802,8 @@
       if (normalParameterTypes.isNotEmpty) {
         for (DartType type in normalParameterTypes) {
           writeSeparator();
-          (type as TypeImpl).appendTo(buffer, visitedTypes);
+          (type as TypeImpl)
+              .appendTo(buffer, visitedTypes, withNullability: withNullability);
         }
       }
       if (optionalParameterTypes.isNotEmpty) {
@@ -712,7 +811,8 @@
         buffer.write("[");
         for (DartType type in optionalParameterTypes) {
           writeSeparator();
-          (type as TypeImpl).appendTo(buffer, visitedTypes);
+          (type as TypeImpl)
+              .appendTo(buffer, visitedTypes, withNullability: withNullability);
         }
         buffer.write("]");
         needsComma = true;
@@ -724,7 +824,8 @@
           writeSeparator();
           buffer.write(name);
           buffer.write(": ");
-          (type as TypeImpl).appendTo(buffer, visitedTypes);
+          (type as TypeImpl)
+              .appendTo(buffer, visitedTypes, withNullability: withNullability);
         });
         buffer.write("}");
         needsComma = true;
@@ -734,7 +835,11 @@
       if (returnType == null) {
         buffer.write("null");
       } else {
-        (returnType as TypeImpl).appendTo(buffer, visitedTypes);
+        (returnType as TypeImpl)
+            .appendTo(buffer, visitedTypes, withNullability: withNullability);
+      }
+      if (withNullability) {
+        _appendNullability(buffer);
       }
       visitedTypes.remove(this);
     } else {
@@ -823,9 +928,9 @@
     if (identical(returnType, this.returnType) &&
         identical(parameters, this.parameters)) {
       return this;
-    } else {
-      return new _FunctionTypeImplStrict._(returnType, typeFormals, parameters);
     }
+    return new _FunctionTypeImplStrict._(returnType, typeFormals, parameters,
+        nullability: nullability);
   }
 
   @override
@@ -1191,6 +1296,9 @@
  * A concrete implementation of an [InterfaceType].
  */
 class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
+  @override
+  final Nullability nullability;
+
   /**
    * A list containing the actual types of the type arguments.
    */
@@ -1231,7 +1339,8 @@
   /**
    * Initialize a newly created type to be declared by the given [element].
    */
-  InterfaceTypeImpl(ClassElement element, [this.prunedTypedefs])
+  InterfaceTypeImpl(ClassElement element,
+      [this.prunedTypedefs, this.nullability = Nullability.indeterminate])
       : super(element, element.displayName);
 
   /**
@@ -1239,26 +1348,42 @@
    * with the given [name] and [typeArguments].
    */
   InterfaceTypeImpl.elementWithNameAndArgs(
-      ClassElement element, String name, this._typeArgumentsComputer)
+      ClassElement element, String name, this._typeArgumentsComputer,
+      {this.nullability = Nullability.indeterminate})
       : prunedTypedefs = null,
         super(element, name) {
     _typeArguments = null;
   }
 
+  InterfaceTypeImpl.explicit(ClassElement element, List<DartType> typeArguments,
+      {this.nullability = Nullability.indeterminate})
+      : prunedTypedefs = null,
+        _typeArguments = typeArguments,
+        super(element, element.displayName);
+
   /**
    * Initialize a newly created type to have the given [name]. This constructor
    * should only be used in cases where there is no declaration of the type.
    */
-  InterfaceTypeImpl.named(String name)
+  InterfaceTypeImpl.named(String name,
+      {this.nullability = Nullability.indeterminate})
       : prunedTypedefs = null,
         super(null, name);
 
   /**
    * Private constructor.
    */
-  InterfaceTypeImpl._(Element element, String name, this.prunedTypedefs)
+  InterfaceTypeImpl._(Element element, String name, this.prunedTypedefs,
+      {this.nullability = Nullability.indeterminate})
       : super(element, name);
 
+  InterfaceTypeImpl._withNullability(InterfaceTypeImpl original,
+      {this.nullability = Nullability.indeterminate})
+      : _typeArguments = original._typeArguments,
+        _typeArgumentsComputer = original._typeArgumentsComputer,
+        prunedTypedefs = original.prunedTypedefs,
+        super(original.element, original.name);
+
   @override
   List<PropertyAccessorElement> get accessors {
     _flushCachedMembersIfStale();
@@ -1380,6 +1505,15 @@
   }
 
   @override
+  bool get isDartCoreInt {
+    ClassElement element = this.element;
+    if (element == null) {
+      return false;
+    }
+    return element.name == "int" && element.library.isDartCore;
+  }
+
+  @override
   bool get isDartCoreNull {
     ClassElement element = this.element;
     if (element == null) {
@@ -1471,7 +1605,8 @@
   }
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes) {
+  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
+      {bool withNullability = false}) {
     if (visitedTypes.add(this)) {
       buffer.write(name);
       int argumentCount = typeArguments.length;
@@ -1481,10 +1616,14 @@
           if (i > 0) {
             buffer.write(", ");
           }
-          (typeArguments[i] as TypeImpl).appendTo(buffer, visitedTypes);
+          (typeArguments[i] as TypeImpl)
+              .appendTo(buffer, visitedTypes, withNullability: withNullability);
         }
         buffer.write(">");
       }
+      if (withNullability) {
+        _appendNullability(buffer);
+      }
       visitedTypes.remove(this);
     } else {
       buffer.write('<recursive>');
@@ -2042,7 +2181,8 @@
       // alias, and function type aliases are always expanded by starting with
       // base types.
       assert(this.prunedTypedefs == null);
-      InterfaceTypeImpl result = new InterfaceTypeImpl._(element, name, prune);
+      InterfaceTypeImpl result = new InterfaceTypeImpl._(element, name, prune,
+          nullability: nullability);
       result.typeArguments = typeArguments
           .map((DartType t) => (t as TypeImpl).pruned(prune))
           .toList();
@@ -2070,7 +2210,8 @@
     if (identical(typeArguments, this.typeArguments)) {
       return this;
     } else {
-      return new InterfaceTypeImpl._(element, name, prunedTypedefs)
+      return new InterfaceTypeImpl._(element, name, prunedTypedefs,
+          nullability: nullability)
         ..typeArguments = typeArguments;
     }
   }
@@ -2093,7 +2234,8 @@
       return this;
     }
 
-    InterfaceTypeImpl newType = new InterfaceTypeImpl(element, prune);
+    InterfaceTypeImpl newType =
+        new InterfaceTypeImpl(element, prune, nullability);
     newType.typeArguments = newTypeArguments;
     return newType;
   }
@@ -2103,6 +2245,12 @@
   InterfaceTypeImpl substitute4(List<DartType> argumentTypes) =>
       instantiate(argumentTypes);
 
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    if (this.nullability == nullability) return this;
+    return InterfaceTypeImpl._withNullability(this, nullability: nullability);
+  }
+
   /**
    * Flush cache members if the version of [element] for which members are
    * cached and the current version of the [element].
@@ -2449,7 +2597,21 @@
         lubArguments[i] = DynamicTypeImpl.instance;
       }
     }
-    InterfaceTypeImpl lub = new InterfaceTypeImpl(firstElement);
+
+    Nullability computeNullability() {
+      Nullability first = (firstType as InterfaceTypeImpl).nullability;
+      Nullability second = (secondType as InterfaceTypeImpl).nullability;
+      if (first == Nullability.nullable || second == Nullability.nullable) {
+        return Nullability.nullable;
+      } else if (first == Nullability.indeterminate ||
+          second == Nullability.indeterminate) {
+        return Nullability.indeterminate;
+      }
+      return Nullability.nonNullable;
+    }
+
+    InterfaceTypeImpl lub =
+        new InterfaceTypeImpl(firstElement, null, computeNullability());
     lub.typeArguments = lubArguments;
     return lub;
   }
@@ -2515,6 +2677,27 @@
 }
 
 /**
+ * The nullability of a type.
+ */
+enum Nullability {
+  /**
+   * An indication that the type includes the value `null`.
+   */
+  nullable,
+
+  /**
+   * An indication that the type is a legacy type which may be interpreted as
+   * either nullable or non-nullable as appropriate.
+   */
+  indeterminate,
+
+  /**
+   * An indication that the type does not include the value `null`.
+   */
+  nonNullable
+}
+
+/**
  * The abstract class `TypeImpl` implements the behavior common to objects
  * representing the declared type of elements in the element model.
  */
@@ -2555,6 +2738,9 @@
   bool get isDartCoreFunction => false;
 
   @override
+  bool get isDartCoreInt => false;
+
+  @override
   bool get isDartCoreNull => false;
 
   @override
@@ -2570,10 +2756,16 @@
   bool get isVoid => false;
 
   /**
+   * Return the nullability of this type.
+   */
+  Nullability get nullability;
+
+  /**
    * Append a textual representation of this type to the given [buffer]. The set
    * of [visitedTypes] is used to prevent infinite recursion.
    */
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes) {
+  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
+      {bool withNullability = false}) {
     if (visitedTypes.add(this)) {
       if (name == null) {
         buffer.write("<unnamed type>");
@@ -2584,6 +2776,9 @@
     } else {
       buffer.write('<recursive>');
     }
+    if (withNullability) {
+      _appendNullability(buffer);
+    }
   }
 
   @override
@@ -2687,13 +2882,32 @@
       [List<FunctionTypeAliasElement> prune]);
 
   @override
-  String toString() {
+  String toString({bool withNullability = false}) {
     StringBuffer buffer = new StringBuffer();
-    appendTo(buffer, new Set.identity());
+    appendTo(buffer, new Set.identity(), withNullability: withNullability);
     return buffer.toString();
   }
 
   /**
+   * Return the same type, but with the given [nullability].
+   */
+  TypeImpl withNullability(Nullability nullability);
+
+  void _appendNullability(StringBuffer buffer) {
+    switch (nullability) {
+      case Nullability.nullable:
+        buffer.write('?');
+        break;
+      case Nullability.indeterminate:
+        buffer.write('*');
+        break;
+      case Nullability.nonNullable:
+        buffer.write('!');
+        break;
+    }
+  }
+
+  /**
    * Return `true` if corresponding elements of the [first] and [second] lists
    * of type arguments are all equal.
    */
@@ -2775,11 +2989,15 @@
 
   static bool _appendingBounds = false;
 
+  @override
+  final Nullability nullability;
+
   /**
    * Initialize a newly created type parameter type to be declared by the given
    * [element] and to have the given name.
    */
-  TypeParameterTypeImpl(TypeParameterElement element)
+  TypeParameterTypeImpl(TypeParameterElement element,
+      {this.nullability = Nullability.indeterminate})
       : super(element, element.name);
 
   @override
@@ -2816,8 +3034,9 @@
    * Append a textual representation of this type to the given [buffer]. The set
    * of [visitedTypes] is used to prevent infinite recursion.
    */
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes) {
-    super.appendTo(buffer, visitedTypes);
+  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
+      {bool withNullability = false}) {
+    super.appendTo(buffer, visitedTypes, withNullability: withNullability);
     TypeParameterElement e = element;
     if (e is TypeParameterMember &&
         e.bound != e.baseElement.bound &&
@@ -2826,7 +3045,8 @@
       // If we're appending bounds already, we don't want to do it recursively.
       _appendingBounds = true;
       try {
-        (e.bound as TypeImpl).appendTo(buffer, visitedTypes);
+        (e.bound as TypeImpl)
+            .appendTo(buffer, visitedTypes, withNullability: withNullability);
       } finally {
         _appendingBounds = false;
       }
@@ -2933,12 +3153,38 @@
     int length = parameterTypes.length;
     for (int i = 0; i < length; i++) {
       if (parameterTypes[i] == this) {
-        return argumentTypes[i];
+        TypeImpl argumentType = argumentTypes[i];
+
+        // TODO(scheglov) It should not happen, but sometimes arguments are null.
+        if (argumentType == null) {
+          return argumentType;
+        }
+
+        // TODO(scheglov) Proposed substitution rules for nullability.
+        Nullability resultNullability;
+        Nullability argumentNullability = argumentType.nullability;
+        if (argumentNullability == Nullability.nullable ||
+            nullability == Nullability.nullable) {
+          resultNullability = Nullability.nullable;
+        } else if (argumentNullability == Nullability.indeterminate ||
+            nullability == Nullability.indeterminate) {
+          resultNullability = Nullability.indeterminate;
+        } else {
+          resultNullability = Nullability.nonNullable;
+        }
+
+        return argumentType.withNullability(resultNullability);
       }
     }
     return this;
   }
 
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    if (this.nullability == nullability) return this;
+    return TypeParameterTypeImpl(element, nullability: nullability);
+  }
+
   /**
    * Return a list containing the type parameter types defined by the given
    * array of type parameter elements ([typeParameters]).
@@ -2986,6 +3232,9 @@
   bool get isUndefined => true;
 
   @override
+  Nullability get nullability => Nullability.indeterminate;
+
+  @override
   bool operator ==(Object object) => identical(object, this);
 
   @override
@@ -3030,6 +3279,9 @@
     }
     return this;
   }
+
+  @override
+  TypeImpl withNullability(Nullability nullability) => this;
 }
 
 /**
@@ -3046,14 +3298,35 @@
  */
 class VoidTypeImpl extends TypeImpl implements VoidType {
   /**
-   * The unique instance of this class.
+   * The unique instance of this class, with indeterminate nullability.
    */
-  static final VoidTypeImpl instance = new VoidTypeImpl._();
+  static final VoidTypeImpl instance = instanceIndeterminate;
+
+  /**
+   * The unique instance of this class, nullable.
+   */
+  static final VoidTypeImpl instanceNullable =
+      new VoidTypeImpl._(Nullability.nullable);
+
+  /**
+   * The unique instance of this class, with indeterminate nullability.
+   */
+  static final VoidTypeImpl instanceIndeterminate =
+      new VoidTypeImpl._(Nullability.indeterminate);
+
+  /**
+   * The unique instance of this class, non-nullable.
+   */
+  static final VoidTypeImpl instanceNonNullable =
+      new VoidTypeImpl._(Nullability.nonNullable);
+
+  @override
+  final Nullability nullability;
 
   /**
    * Prevent the creation of instances of this class.
    */
-  VoidTypeImpl._() : super(null, Keyword.VOID.lexeme);
+  VoidTypeImpl._(this.nullability) : super(null, Keyword.VOID.lexeme);
 
   @override
   int get hashCode => 2;
@@ -3096,6 +3369,19 @@
           List<DartType> argumentTypes, List<DartType> parameterTypes,
           [List<FunctionTypeAliasElement> prune]) =>
       this;
+
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    switch (nullability) {
+      case Nullability.nullable:
+        return instanceNullable;
+      case Nullability.indeterminate:
+        return instanceIndeterminate;
+      case Nullability.nonNullable:
+        return instanceNonNullable;
+    }
+    throw StateError('Unexpected nullability: $nullability');
+  }
 }
 
 /**
@@ -3146,9 +3432,10 @@
       this._typeArguments,
       this._returnType,
       this._parameters,
-      this._isInstantiated)
+      this._isInstantiated,
+      {Nullability nullability = Nullability.indeterminate})
       : _typeParameters = null,
-        super._(element, name);
+        super._(element, name, nullability);
 
   /**
    * Return the base parameter elements of this function element.
@@ -3354,7 +3641,8 @@
     newTypeArgs.addAll(argumentTypes);
 
     return new _FunctionTypeImplLazy._(element, name, prunedTypedefs,
-        newTypeArgs, _returnType, _parameters, true);
+        newTypeArgs, _returnType, _parameters, true,
+        nullability: nullability);
   }
 
   @override
@@ -3375,7 +3663,8 @@
           .map((DartType t) => (t as TypeImpl).pruned(prune))
           .toList(growable: false);
       return new _FunctionTypeImplLazy._(element, name, prune, typeArgs,
-          _returnType, _parameters, _isInstantiated);
+          _returnType, _parameters, _isInstantiated,
+          nullability: nullability);
     }
   }
 
@@ -3403,7 +3692,16 @@
     List<DartType> typeArgs =
         TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes);
     return new _FunctionTypeImplLazy._(element, name, prune, typeArgs,
-        _returnType, _parameters, _isInstantiated);
+        _returnType, _parameters, _isInstantiated,
+        nullability: nullability);
+  }
+
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    if (this.nullability == nullability) return this;
+    return _FunctionTypeImplLazy._(element, name, prunedTypedefs,
+        _typeArguments, _returnType, _parameters, _isInstantiated,
+        nullability: nullability);
   }
 
   @override
@@ -3450,8 +3748,9 @@
   @override
   final List<ParameterElement> parameters;
 
-  _FunctionTypeImplStrict._(this.returnType, this.typeFormals, this.parameters)
-      : super._(null, null);
+  _FunctionTypeImplStrict._(this.returnType, this.typeFormals, this.parameters,
+      {Nullability nullability = Nullability.indeterminate})
+      : super._(null, null, nullability);
 
   @override
   List<TypeParameterElement> get boundTypeParameters => typeFormals;
@@ -3506,7 +3805,8 @@
     return new _FunctionTypeImplStrict._(
         returnType.substitute2(argumentTypes, parameterTypes),
         const [],
-        _transformOrShare(parameters, transformParameter));
+        _transformOrShare(parameters, transformParameter),
+        nullability: nullability);
   }
 
   @override
@@ -3565,7 +3865,15 @@
       return this;
     }
     return new _FunctionTypeImplStrict._(
-        newReturnType, newTypeFormals, newParameters);
+        newReturnType, newTypeFormals, newParameters,
+        nullability: nullability);
+  }
+
+  @override
+  TypeImpl withNullability(Nullability nullability) {
+    if (this.nullability == nullability) return this;
+    return _FunctionTypeImplStrict._(returnType, typeFormals, parameters,
+        nullability: nullability);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/wrapped.dart b/pkg/analyzer/lib/src/dart/element/wrapped.dart
index 3dfc8d6..3c6f7f1 100644
--- a/pkg/analyzer/lib/src/dart/element/wrapped.dart
+++ b/pkg/analyzer/lib/src/dart/element/wrapped.dart
@@ -65,6 +65,9 @@
   bool get hasJS => wrappedUnit.hasJS;
 
   @override
+  bool get hasLiteral => wrappedUnit.hasLiteral;
+
+  @override
   bool get hasLoadLibraryFunction => wrappedUnit.hasLoadLibraryFunction;
 
   @override
@@ -255,6 +258,9 @@
   bool get hasJS => wrappedImport.hasJS;
 
   @override
+  bool get hasLiteral => wrappedImport.hasLiteral;
+
+  @override
   bool get hasOverride => wrappedImport.hasOverride;
 
   @override
@@ -454,6 +460,9 @@
   bool get hasJS => wrappedLib.hasJS;
 
   @override
+  bool get hasLiteral => wrappedLib.hasLiteral;
+
+  @override
   bool get hasLoadLibraryFunction => wrappedLib.hasLoadLibraryFunction;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 07700ec..62c6a8a 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -68,6 +68,23 @@
           "Try replacing the use of the deprecated member with the replacement.");
 
   /**
+   * Deprecated members should not be invoked or used from within the package
+   * where they are declared.
+   *
+   * Intentionally separate from DEPRECATED_MEMBER_USE, so that package owners
+   * can ignore same-package deprecate member use Hints if they like, and
+   * continue to see cross-package deprecated member use Hints.
+   *
+   * Parameters:
+   * 0: the name of the member
+   */
+  static const HintCode DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE = const HintCode(
+      'DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE',
+      "'{0}' is deprecated and shouldn't be used.",
+      correction:
+          "Try replacing the use of the deprecated member with the replacement.");
+
+  /**
    * Users should not create a class named `Function` anymore.
    */
   static const HintCode DEPRECATED_FUNCTION_CLASS_DECLARATION = const HintCode(
@@ -161,23 +178,6 @@
               "rename the function in the imported library.");
 
   /**
-   * This hint is generated anywhere where the
-   * [StaticTypeWarningCode.INVALID_ASSIGNMENT] would have been generated, if we
-   * used propagated information for the warnings.
-   *
-   * Parameters:
-   * 0: the name of the right hand side type
-   * 1: the name of the left hand side type
-   */
-  // TODO(brianwilkerson) This hint code should be removed, as should the code
-  //  that appears to generate it.
-  static const HintCode INVALID_ASSIGNMENT = const HintCode(
-      'INVALID_ASSIGNMENT',
-      "A value of type '{0}' can't be assigned to a variable of type '{1}'.",
-      correction: "Try changing the type of the variable, or "
-          "casting the right-hand type to '{1}'.");
-
-  /**
    * This hint is generated anywhere a @factory annotation is associated with
    * anything other than a method.
    */
@@ -399,6 +399,27 @@
       "but does not invoke the overridden method.");
 
   /**
+   * Generate a hint for non-const instance creation using a constructor
+   * annotated with `@literal`.
+   */
+  static const HintCode NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR = const HintCode(
+      'NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR',
+      "This instance creation must be 'const', because the {0} constructor is "
+      "marked as '@literal'.",
+      correction: "Try adding a 'const' keyword.");
+
+  /**
+   * Generate a hint for non-const instance creation (with the `new` keyword)
+   * using a constructor annotated with `@literal`.
+   */
+  static const HintCode NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW =
+      const HintCode(
+          'NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW',
+          "This instance creation must be 'const', because the {0} constructor is "
+          "marked as '@literal'.",
+          correction: "Try replacing the 'new' keyword with 'const'.");
+
+  /**
    * When the left operand of a binary expression uses '?.' operator, it can be
    * `null`.
    */
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 10894cd..527f2ed 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/context/builder.dart' show EmbedderYamlLocator;
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
@@ -1422,8 +1423,12 @@
   @override
   bool dart2jsHint = false;
 
-  @override
-  List<String> enabledExperiments = const <String>[];
+  List<String> _enabledExperiments = const <String>[];
+
+  /**
+   * Parsed [enabledExperiments].
+   */
+  ExperimentStatus _experimentStatus = ExperimentStatus();
 
   @override
   List<String> enabledPluginNames = const <String>[];
@@ -1602,6 +1607,14 @@
   void set enableConditionalDirectives(_) {}
 
   @override
+  List<String> get enabledExperiments => _enabledExperiments;
+
+  set enabledExperiments(List<String> enabledExperiments) {
+    _enabledExperiments = enabledExperiments;
+    _experimentStatus = ExperimentStatus.fromStrings(enabledExperiments);
+  }
+
+  @override
   @deprecated
   bool get enableGenericMethods => true;
 
@@ -1655,6 +1668,11 @@
   }
 
   /**
+   * The set of enabled experiments.
+   */
+  ExperimentStatus get experimentStatus => _experimentStatus;
+
+  /**
    * Return `true` to enable mixin declarations.
    * https://github.com/dart-lang/language/issues/12
    */
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 7992ecf..5283d92 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2220,7 +2220,7 @@
     if (expressionType == null) {
       return;
     }
-    if (_expressionIsAssignableAtType(expression, expressionType, type)) {
+    if (_typeSystem.isAssignableTo(expressionType, type)) {
       return;
     }
     _errorReporter.reportErrorForNode(errorCode, expression, arguments);
@@ -2239,8 +2239,7 @@
       DartType actualStaticType,
       DartType expectedStaticType,
       ErrorCode errorCode) {
-    if (!_expressionIsAssignableAtType(
-        expression, actualStaticType, expectedStaticType)) {
+    if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) {
       _errorReporter.reportTypeErrorForNode(
           errorCode, expression, [actualStaticType, expectedStaticType]);
       return false;
@@ -3093,7 +3092,7 @@
     if (staticType == null) {
       return;
     }
-    if (_expressionIsAssignableAtType(expression, staticType, fieldType)) {
+    if (_typeSystem.isAssignableTo(staticType, fieldType)) {
       return;
     }
     // report problem
@@ -4972,8 +4971,7 @@
       var checkWithType = (!_inAsync)
           ? fromType
           : _typeProvider.futureType.instantiate(<DartType>[fromType]);
-      if (_expressionIsAssignableAtType(
-          returnExpression, checkWithType, expectedType)) {
+      if (_typeSystem.isAssignableTo(checkWithType, expectedType)) {
         return;
       }
     }
@@ -5075,7 +5073,7 @@
     DartType caseType = getStaticType(caseExpression);
 
     // check types
-    if (!_expressionIsAssignableAtType(expression, expressionType, caseType)) {
+    if (!_typeSystem.isAssignableTo(expressionType, caseType)) {
       _errorReporter.reportErrorForNode(
           StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
           expression,
@@ -5719,11 +5717,6 @@
     }
   }
 
-  bool _expressionIsAssignableAtType(Expression expression,
-      DartType actualStaticType, DartType expectedStaticType) {
-    return _typeSystem.isAssignableTo(actualStaticType, expectedStaticType);
-  }
-
   InterfaceType _findInterfaceTypeForMixin(TypeName mixin,
       InterfaceType supertypeConstraint, List<InterfaceType> interfaceTypes) {
     var element = supertypeConstraint.element;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 3696609..9dc3ff1 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -29,11 +29,11 @@
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
-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/lint/linter.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:path/path.dart' as path;
 
@@ -286,6 +286,9 @@
   /// The [WorkspacePackage] in which [_currentLibrary] is declared.
   WorkspacePackage _workspacePackage;
 
+  /// The [LinterContext] used for possible const calculations.
+  LinterContext _linterContext;
+
   /// Create a new instance of the [BestPracticesVerifier].
   ///
   /// @param errorReporter the error reporter
@@ -295,6 +298,7 @@
     this._currentLibrary, {
     TypeSystem typeSystem,
     ResourceProvider resourceProvider,
+    DeclaredVariables declaredVariables,
   })  : _nullType = typeProvider.nullType,
         _futureNullType = typeProvider.futureNullType,
         _typeSystem = typeSystem ?? new Dart2TypeSystem(typeProvider),
@@ -305,6 +309,8 @@
     Workspace workspace = ContextBuilder.createWorkspace(
         resourceProvider, libraryPath, null /* ContextBuilder */);
     _workspacePackage = workspace.findPackageFor(libraryPath);
+    _linterContext = LinterContextImpl(null /* allUnits */,
+        null /* currentUnit */, declaredVariables, typeProvider, _typeSystem);
   }
 
   @override
@@ -359,9 +365,7 @@
   @override
   void visitAssignmentExpression(AssignmentExpression node) {
     TokenType operatorType = node.operator.type;
-    if (operatorType == TokenType.EQ) {
-      _checkForInvalidAssignment(node.leftHandSide, node.rightHandSide);
-    } else {
+    if (operatorType != TokenType.EQ) {
       _checkForDeprecatedMemberUse(node.staticElement, node);
     }
     super.visitAssignmentExpression(node);
@@ -480,6 +484,7 @@
   @override
   void visitInstanceCreationExpression(InstanceCreationExpression node) {
     _checkForDeprecatedMemberUse(node.staticElement, node);
+    _checkForLiteralConstructorUse(node);
     super.visitInstanceCreationExpression(node);
   }
 
@@ -592,12 +597,6 @@
     }
   }
 
-  @override
-  void visitVariableDeclaration(VariableDeclaration node) {
-    _checkForInvalidAssignment(node.name, node.initializer);
-    super.visitVariableDeclaration(node);
-  }
-
   /// Check for the passed is expression for the unnecessary type check hint
   /// codes as well as null checks expressed using an is expression.
   ///
@@ -717,11 +716,16 @@
       } else if (displayName == FunctionElement.CALL_METHOD_NAME &&
           node is MethodInvocation &&
           node.staticInvokeType is InterfaceType) {
-        displayName =
-            "${resolutionMap.staticInvokeTypeForInvocationExpression(node).displayName}.${element.displayName}";
+        DartType staticInvokeType =
+            resolutionMap.staticInvokeTypeForInvocationExpression(node);
+        displayName = "${staticInvokeType.displayName}.${element.displayName}";
       }
-      _errorReporter.reportErrorForNode(
-          HintCode.DEPRECATED_MEMBER_USE, node, [displayName]);
+      LibraryElement library =
+          element is LibraryElement ? element : element.library;
+      HintCode hintCode = _workspacePackage.contains(library.source.fullName)
+          ? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE
+          : HintCode.DEPRECATED_MEMBER_USE;
+      _errorReporter.reportErrorForNode(hintCode, node, [displayName]);
     }
   }
 
@@ -874,41 +878,6 @@
     }
   }
 
-  /// This verifies that the passed left hand side and right hand side represent
-  /// a valid assignment.
-  ///
-  /// This method corresponds to ErrorVerifier.checkForInvalidAssignment.
-  ///
-  /// @param lhs the left hand side expression
-  /// @param rhs the right hand side expression
-  /// @return `true` if and only if an error code is generated on the passed
-  ///         node
-  /// See [HintCode.INVALID_ASSIGNMENT].
-  bool _checkForInvalidAssignment(Expression lhs, Expression rhs) {
-    if (lhs == null || rhs == null) {
-      return false;
-    }
-    VariableElement leftVariableElement = ErrorVerifier.getVariableElement(lhs);
-    DartType leftType = (leftVariableElement == null)
-        ? ErrorVerifier.getStaticType(lhs)
-        : leftVariableElement.type;
-    DartType staticRightType = ErrorVerifier.getStaticType(rhs);
-    if (!_typeSystem.isAssignableTo(staticRightType, leftType)) {
-      // The warning was generated on this rhs
-      return false;
-    }
-    // Test for, and then generate the hint
-    DartType bestRightType = rhs.staticType;
-    if (leftType != null && bestRightType != null) {
-      if (!_typeSystem.isAssignableTo(bestRightType, leftType)) {
-        _errorReporter.reportTypeErrorForNode(
-            HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]);
-        return true;
-      }
-    }
-    return false;
-  }
-
   void _checkForInvalidFactory(MethodDeclaration decl) {
     // Check declaration.
     // Note that null return types are expected to be flagged by other analyses.
@@ -979,6 +948,32 @@
     }
   }
 
+  /// Check that the instance creation node is const if the constructor is
+  /// marked with [literal].
+  _checkForLiteralConstructorUse(InstanceCreationExpression node) {
+    ConstructorName constructorName = node.constructorName;
+    ConstructorElement constructor = constructorName.staticElement;
+    if (constructor == null) {
+      return;
+    }
+    if (!node.isConst &&
+        constructor.hasLiteral &&
+        _linterContext.canBeConst(node)) {
+      // Echoing jwren's TODO from _checkForDeprecatedMemberUse:
+      // TODO(jwren) We should modify ConstructorElement.getDisplayName(), or
+      // have the logic centralized elsewhere, instead of doing this logic
+      // here.
+      String fullConstructorName = constructorName.type.name.name;
+      if (constructorName.name != null) {
+        fullConstructorName = '$fullConstructorName.${constructorName.name}';
+      }
+      HintCode hint = node.keyword?.keyword == Keyword.NEW
+          ? HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW
+          : HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR;
+      _errorReporter.reportErrorForNode(hint, node, [fullConstructorName]);
+    }
+  }
+
   /// Check that the imported library does not define a loadLibrary function.
   /// The import has already been determined to be deferred when this is called.
   ///
@@ -1254,17 +1249,17 @@
 //    }
 //    return false;
 //  }
-
-  /// Return `true` if the given [type] represents `Future<void>`.
-  bool _isFutureVoid(DartType type) {
-    if (type.isDartAsyncFuture) {
-      List<DartType> typeArgs = (type as InterfaceType).typeArguments;
-      if (typeArgs.length == 1 && typeArgs[0].isVoid) {
-        return true;
-      }
-    }
-    return false;
-  }
+//
+//  /// Return `true` if the given [type] represents `Future<void>`.
+//  bool _isFutureVoid(DartType type) {
+//    if (type.isDartAsyncFuture) {
+//      List<DartType> typeArgs = (type as InterfaceType).typeArguments;
+//      if (typeArgs.length == 1 && typeArgs[0].isVoid) {
+//        return true;
+//      }
+//    }
+//    return false;
+//  }
 
   static bool _hasDeprecatedAnnotation(List<Annotation> annotations) {
     for (var i = 0; i < annotations.length; i++) {
@@ -5220,8 +5215,8 @@
       if (mapT != null &&
           node.typeArguments == null &&
           node.entries.isEmpty &&
-          typeSystem.isAssignableTo(typeProvider.setNullType, mapT) &&
-          !typeSystem.isAssignableTo(typeProvider.mapNullNullType, mapT)) {
+          typeSystem.isAssignableTo(typeProvider.iterableObjectType, mapT) &&
+          !typeSystem.isAssignableTo(typeProvider.mapObjectObjectType, mapT)) {
         // The node is really an empty set literal with no type arguments, so
         // don't try to visit the replaced map literal.
         return;
@@ -6872,6 +6867,8 @@
   final TypeSystem typeSystem;
   final DartType dynamicType;
   final DartType undefinedType;
+  final bool isNonNullableMigrated;
+  final AnalysisOptionsImpl analysisOptions;
   final LibraryElement definingLibrary;
   final Source source;
   final AnalysisErrorListener errorListener;
@@ -6885,11 +6882,17 @@
 
   Scope nameScope;
 
-  TypeNameResolver(this.typeSystem, TypeProvider typeProvider,
-      this.definingLibrary, this.source, this.errorListener,
+  TypeNameResolver(
+      this.typeSystem,
+      TypeProvider typeProvider,
+      this.isNonNullableMigrated,
+      this.definingLibrary,
+      this.source,
+      this.errorListener,
       {this.shouldUseWithClauseInferredTypes: true})
       : dynamicType = typeProvider.dynamicType,
-        undefinedType = typeProvider.undefinedType;
+        undefinedType = typeProvider.undefinedType,
+        analysisOptions = definingLibrary.context.analysisOptions;
 
   /// Report an error with the given error code and arguments.
   ///
@@ -7112,22 +7115,25 @@
       node.type = undefinedType;
       return;
     }
-    DartType type = null;
+
     if (element is ClassElement) {
-      _setElement(typeName, element);
-      type = element.type;
-    } else if (element == DynamicElementImpl.instance) {
+      _resolveClassElement(node, typeName, argumentList, element);
+      return;
+    }
+
+    TypeImpl type = null;
+    if (element == DynamicElementImpl.instance) {
       _setElement(typeName, element);
       type = DynamicTypeImpl.instance;
     } else if (element is FunctionTypeAliasElement) {
       _setElement(typeName, element);
-      type = element.type;
+      type = element.type as TypeImpl;
     } else if (element is TypeParameterElement) {
       _setElement(typeName, element);
-      type = element.type;
+      type = element.type as TypeImpl;
     } else if (element is MultiplyDefinedElement) {
       List<Element> elements = element.conflictingElements;
-      type = _getTypeWhenMultiplyDefined(elements);
+      type = _getTypeWhenMultiplyDefined(elements) as TypeImpl;
     } else {
       // The name does not represent a type.
       RedirectingConstructorKind redirectingConstructorKind;
@@ -7207,37 +7213,15 @@
                 element, typeArguments) ??
             dynamicType;
       } else {
-        DartType redirectedType =
-            _inferTypeArgumentsForRedirectedConstructor(node, type);
-        if (redirectedType != null) {
-          type = redirectedType;
-        } else {
-          type = typeSystem.instantiateToBounds(type);
-        }
+        type = typeSystem.instantiateToBounds(type);
       }
     }
-    DartType refinedType;
-    if (shouldUseWithClauseInferredTypes) {
-      var parent = node.parent;
-      if (parent is WithClause &&
-          type is InterfaceType &&
-          type.element.typeParameters.isNotEmpty) {
-        // Get the (possibly inferred) mixin type from the element model.
-        var grandParent = parent.parent;
-        if (grandParent is ClassDeclaration) {
-          refinedType =
-              _getInferredMixinType(grandParent.declaredElement, type.element);
-        } else if (grandParent is ClassTypeAlias) {
-          refinedType =
-              _getInferredMixinType(grandParent.declaredElement, type.element);
-        } else {
-          assert(false, 'Unexpected context for "with" clause');
-        }
-      }
-    }
-    refinedType ??= type;
-    typeName.staticType = refinedType;
-    node.type = refinedType;
+
+    var nullability = _getNullability(node.question != null);
+    type = type.withNullability(nullability);
+
+    typeName.staticType = type;
+    node.type = type;
   }
 
   DartType _getInferredMixinType(
@@ -7266,6 +7250,22 @@
     return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
   }
 
+  Nullability _getNullability(bool hasQuestion) {
+    Nullability nullability;
+    if (analysisOptions.experimentStatus.non_nullable) {
+      if (hasQuestion) {
+        nullability = Nullability.nullable;
+      } else if (isNonNullableMigrated) {
+        nullability = Nullability.nonNullable;
+      } else {
+        nullability = Nullability.indeterminate;
+      }
+    } else {
+      nullability = Nullability.indeterminate;
+    }
+    return nullability;
+  }
+
   /// Checks if the given [typeName] is the target in a redirected constructor.
   RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
     AstNode parent = typeName.parent;
@@ -7339,7 +7339,7 @@
   /// If the [node] is the type name in a redirected factory constructor,
   /// infer type arguments using the enclosing class declaration. Return `null`
   /// otherwise.
-  DartType _inferTypeArgumentsForRedirectedConstructor(
+  InterfaceTypeImpl _inferTypeArgumentsForRedirectedConstructor(
       TypeName node, DartType type) {
     AstNode constructorName = node.parent;
     AstNode enclosingConstructor = constructorName?.parent;
@@ -7405,6 +7405,77 @@
   bool _isTypeNameInTypeArgumentList(TypeName typeName) =>
       typeName.parent is TypeArgumentList;
 
+  void _resolveClassElement(TypeName node, Identifier typeName,
+      TypeArgumentList argumentList, ClassElement element) {
+    _setElement(typeName, element);
+
+    var typeParameters = element.typeParameters;
+    var parameterCount = typeParameters.length;
+
+    List<DartType> typeArguments;
+    if (argumentList != null) {
+      var argumentNodes = argumentList.arguments;
+      var argumentCount = argumentNodes.length;
+
+      typeArguments = new List<DartType>(parameterCount);
+      if (argumentCount == parameterCount) {
+        for (int i = 0; i < parameterCount; i++) {
+          typeArguments[i] = _getType(argumentNodes[i]);
+        }
+      } else {
+        reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node,
+            [typeName.name, parameterCount, argumentCount]);
+        for (int i = 0; i < parameterCount; i++) {
+          typeArguments[i] = dynamicType;
+        }
+      }
+    } else if (parameterCount == 0) {
+      typeArguments = const <DartType>[];
+    } else {
+      var redirectedType =
+          _inferTypeArgumentsForRedirectedConstructor(node, element.type);
+      if (redirectedType != null) {
+        typeArguments = redirectedType.typeArguments;
+      } else {
+        var typeFormals = typeParameters;
+        typeArguments = typeSystem.instantiateTypeFormalsToBounds(typeFormals);
+      }
+    }
+
+    var parent = node.parent;
+
+    Nullability nullability;
+    if (parent is ClassTypeAlias ||
+        parent is ExtendsClause ||
+        parent is ImplementsClause ||
+        parent is OnClause ||
+        parent is WithClause) {
+      nullability = Nullability.nonNullable;
+    } else {
+      nullability = _getNullability(node.question != null);
+    }
+
+    var type = InterfaceTypeImpl.explicit(element, typeArguments,
+        nullability: nullability);
+
+    if (shouldUseWithClauseInferredTypes) {
+      if (parent is WithClause && parameterCount != 0) {
+        // Get the (possibly inferred) mixin type from the element model.
+        var grandParent = parent.parent;
+        if (grandParent is ClassDeclaration) {
+          type = _getInferredMixinType(grandParent.declaredElement, element);
+        } else if (grandParent is ClassTypeAlias) {
+          type = _getInferredMixinType(grandParent.declaredElement, element);
+        } else {
+          assert(false, 'Unexpected context for "with" clause');
+        }
+      }
+    }
+
+    typeName.staticType = type;
+    node.type = type;
+  }
+
   /// Records the new Element for a TypeName's Identifier.
   ///
   /// A null may be passed in to indicate that the element can't be resolved.
@@ -7638,10 +7709,16 @@
   TypeNameResolver typeNameResolver = null;
 
   TypeParameterBoundsResolver(
-      this.typeSystem, this.library, this.source, this.errorListener)
+      this.typeSystem, this.library, this.source, this.errorListener,
+      {bool isNonNullableMigrated = false})
       : libraryScope = new LibraryScope(library),
-        typeNameResolver = new TypeNameResolver(typeSystem,
-            typeSystem.typeProvider, library, source, errorListener);
+        typeNameResolver = new TypeNameResolver(
+            typeSystem,
+            typeSystem.typeProvider,
+            isNonNullableMigrated,
+            library,
+            source,
+            errorListener);
 
   /// Resolve bounds of type parameters of classes, class and function type
   /// aliases.
@@ -7875,14 +7952,17 @@
   /// Return the type representing the type 'Iterable<dynamic>'.
   InterfaceType get iterableDynamicType;
 
+  /// Return the type representing the type 'Iterable<Object>'.
+  InterfaceType get iterableObjectType;
+
   /// Return the type representing the built-in type 'Iterable'.
   InterfaceType get iterableType;
 
   /// Return the type representing the built-in type 'List'.
   InterfaceType get listType;
 
-  /// Return the type representing 'Map<Null, Null>'.
-  InterfaceType get mapNullNullType;
+  /// Return the type representing 'Map<Object, Object>'.
+  InterfaceType get mapObjectObjectType;
 
   /// Return the type representing the built-in type 'Map'.
   InterfaceType get mapType;
@@ -7903,9 +7983,6 @@
   /// Return the type representing the built-in type 'Object'.
   InterfaceType get objectType;
 
-  /// Return the type representing 'Set<Null>'.
-  InterfaceType get setNullType;
-
   /// Return the type representing the built-in type 'Set'.
   InterfaceType get setType;
 
@@ -8017,6 +8094,9 @@
   /// The type representing 'Iterable<dynamic>'.
   InterfaceType _iterableDynamicType;
 
+  /// The type representing 'Iterable<Object>'.
+  InterfaceType _iterableObjectType;
+
   /// The type representing the built-in type 'Iterable'.
   InterfaceType _iterableType;
 
@@ -8026,8 +8106,8 @@
   /// The type representing the built-in type 'Map'.
   InterfaceType _mapType;
 
-  /// The type representing the built-in type 'Map<Null, Null>'.
-  InterfaceType _mapNullNullType;
+  /// The type representing the built-in type 'Map<Object, Object>'.
+  InterfaceType _mapObjectObjectType;
 
   /// An shared object representing the value 'null'.
   DartObjectImpl _nullObject;
@@ -8035,9 +8115,6 @@
   /// The type representing the type 'Set'.
   InterfaceType _setType;
 
-  /// The type representing the type 'Set<Null>'.
-  InterfaceType _setNullType;
-
   /// The type representing the type 'Null'.
   InterfaceType _nullType;
 
@@ -8125,13 +8202,16 @@
   InterfaceType get iterableDynamicType => _iterableDynamicType;
 
   @override
+  InterfaceType get iterableObjectType => _iterableObjectType;
+
+  @override
   InterfaceType get iterableType => _iterableType;
 
   @override
   InterfaceType get listType => _listType;
 
   @override
-  InterfaceType get mapNullNullType => _mapNullNullType;
+  InterfaceType get mapObjectObjectType => _mapObjectObjectType;
 
   @override
   InterfaceType get mapType => _mapType;
@@ -8154,9 +8234,6 @@
   InterfaceType get objectType => _objectType;
 
   @override
-  InterfaceType get setNullType => _setNullType;
-
-  @override
   InterfaceType get setType => _setType;
 
   @override
@@ -8224,8 +8301,9 @@
     _futureDynamicType = _futureType.instantiate(<DartType>[_dynamicType]);
     _futureNullType = _futureType.instantiate(<DartType>[_nullType]);
     _iterableDynamicType = _iterableType.instantiate(<DartType>[_dynamicType]);
-    _mapNullNullType = _mapType.instantiate(<DartType>[_nullType, _nullType]);
-    _setNullType = _setType.instantiate(<DartType>[_nullType]);
+    _iterableObjectType = _iterableType.instantiate(<DartType>[_objectType]);
+    _mapObjectObjectType =
+        _mapType.instantiate(<DartType>[_objectType, _objectType]);
     _streamDynamicType = _streamType.instantiate(<DartType>[_dynamicType]);
     // FutureOr<T> is still fairly new, so if we're analyzing an SDK that
     // doesn't have it yet, create an element for it.
@@ -8284,6 +8362,9 @@
   /// Type type system in use for this resolver pass.
   TypeSystem _typeSystem;
 
+  /// Whether the library migrated to non-nullable.
+  final bool isNonNullableMigrated;
+
   /// The helper to resolve types.
   TypeNameResolver _typeNameResolver;
 
@@ -8319,6 +8400,7 @@
   TypeResolverVisitor(LibraryElement definingLibrary, Source source,
       TypeProvider typeProvider, AnalysisErrorListener errorListener,
       {Scope nameScope,
+      this.isNonNullableMigrated: false,
       this.mode: TypeResolverMode.everything,
       bool shouldUseWithClauseInferredTypes: true,
       this.shouldSetElementSupertypes: false})
@@ -8327,8 +8409,8 @@
     _dynamicType = typeProvider.dynamicType;
     _undefinedType = typeProvider.undefinedType;
     _typeSystem = TypeSystem.create(definingLibrary.context);
-    _typeNameResolver = new TypeNameResolver(
-        _typeSystem, typeProvider, definingLibrary, source, errorListener,
+    _typeNameResolver = new TypeNameResolver(_typeSystem, typeProvider,
+        isNonNullableMigrated, definingLibrary, source, errorListener,
         shouldUseWithClauseInferredTypes: shouldUseWithClauseInferredTypes);
   }
 
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 89dbcb5..88f8f3b 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -10,12 +10,15 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/task/strong/checker.dart'
@@ -52,6 +55,11 @@
   DartType _dynamicType;
 
   /**
+   * The status of the active experiments of the current context.
+   */
+  ExperimentStatus _experimentStatus;
+
+  /**
    * The type representing the class containing the nodes being analyzed,
    * or `null` if the nodes are not within a class.
    */
@@ -72,6 +80,9 @@
     _typeSystem = _resolver.typeSystem;
     _dynamicType = _typeProvider.dynamicType;
     _promoteManager = _resolver.promoteManager;
+    _experimentStatus = (_resolver.definingLibrary.context.analysisOptions
+            as AnalysisOptionsImpl)
+        .experimentStatus;
   }
 
   /**
@@ -173,21 +184,33 @@
 
   ParameterizedType inferMapType(MapLiteral node, {bool downwards: false}) {
     DartType contextType = InferenceContext.getContext(node);
-    if (contextType != null &&
-        node.typeArguments == null &&
-        node.entries.isEmpty &&
-        _typeSystem.isAssignableTo(_typeProvider.setNullType, contextType) &&
-        !_typeSystem.isAssignableTo(
-            _typeProvider.mapNullNullType, contextType)) {
-      // The node is really an empty set literal with no type arguments. Rewrite
-      // the AST and infer the type of the set as appropriate.
-      SetLiteral setLiteral = new AstFactoryImpl().setLiteral(
-          node.constKeyword, null, node.leftBracket, null, node.rightBracket);
-      InferenceContext.setType(setLiteral, contextType);
-      NodeReplacer.replace(node, setLiteral);
-      DartType type = inferSetType(setLiteral, downwards: downwards);
-      setLiteral.staticType = type;
-      return type;
+    if (contextType != null && _experimentStatus.set_literals) {
+      DartType unwrap(DartType type) {
+        if (type is InterfaceType &&
+            type.isDartAsyncFutureOr &&
+            type.typeArguments.length == 1) {
+          return unwrap(type.typeArguments[0]);
+        }
+        return type;
+      }
+
+      DartType unwrappedContextType = unwrap(contextType);
+      if (node.typeArguments == null &&
+          node.entries.isEmpty &&
+          _typeSystem.isAssignableTo(
+              _typeProvider.iterableObjectType, unwrappedContextType) &&
+          !_typeSystem.isAssignableTo(
+              _typeProvider.mapObjectObjectType, unwrappedContextType)) {
+        // The node is really an empty set literal with no type arguments.
+        // Rewrite the AST and infer the type of the set as appropriate.
+        SetLiteral setLiteral = new AstFactoryImpl().setLiteral(
+            node.constKeyword, null, node.leftBracket, null, node.rightBracket);
+        InferenceContext.setType(setLiteral, contextType);
+        NodeReplacer.replace(node, setLiteral);
+        DartType type = inferSetType(setLiteral, downwards: downwards);
+        setLiteral.staticType = type;
+        return type;
+      }
     }
     List<DartType> elementTypes;
     List<ParameterElement> parameters;
@@ -830,13 +853,14 @@
   void visitPostfixExpression(PostfixExpression node) {
     Expression operand = node.operand;
     DartType staticType = _getStaticType(operand, read: true);
-    TokenType operator = node.operator.type;
-    if (operator == TokenType.MINUS_MINUS || operator == TokenType.PLUS_PLUS) {
-      DartType intType = _typeProvider.intType;
-      if (identical(staticType, intType)) {
-        staticType = intType;
-      }
+
+    // No need to check for `intVar++`, the result is `int`.
+    if (!staticType.isDartCoreInt) {
+      var operatorElement = node.staticElement;
+      var operatorReturnType = _computeStaticReturnType(operatorElement);
+      _checkForInvalidAssignmentIncDec(node, operand, operatorReturnType);
     }
+
     _recordStaticType(node, staticType);
   }
 
@@ -894,9 +918,12 @@
       DartType staticType = _computeStaticReturnType(staticMethodElement);
       if (operator == TokenType.MINUS_MINUS ||
           operator == TokenType.PLUS_PLUS) {
-        DartType intType = _typeProvider.intType;
-        if (identical(_getStaticType(node.operand, read: true), intType)) {
-          staticType = intType;
+        Expression operand = node.operand;
+        var operandReadType = _getStaticType(operand, read: true);
+        if (operandReadType.isDartCoreInt) {
+          staticType = _typeProvider.intType;
+        } else {
+          _checkForInvalidAssignmentIncDec(node, operand, staticType);
         }
       }
       _recordStaticType(node, staticType);
@@ -1189,6 +1216,20 @@
     _recordStaticType(node, staticType);
   }
 
+  /// Check that the result [type] of a prefix or postfix `++` or `--`
+  /// expression is assignable to the write type of the [operand].
+  void _checkForInvalidAssignmentIncDec(
+      AstNode node, Expression operand, DartType type) {
+    var operandWriteType = _getStaticType(operand);
+    if (!_typeSystem.isAssignableTo(type, operandWriteType)) {
+      _resolver.errorReporter.reportTypeErrorForNode(
+        StaticTypeWarningCode.INVALID_ASSIGNMENT,
+        node,
+        [type, operandWriteType],
+      );
+    }
+  }
+
   /**
    * Record that the static type of the given node is the type of the second argument to the method
    * represented by the given element.
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 1f4cc10..30b176b 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -89,6 +89,11 @@
   InterfaceType _iterableDynamicType;
 
   /**
+   * The type representing 'Iterable<Object>'
+   */
+  InterfaceType _iterableObjectType;
+
+  /**
    * The type representing the built-in type 'Iterable'.
    */
   InterfaceType _iterableType;
@@ -109,9 +114,9 @@
   InterfaceType _mapType;
 
   /**
-   * The type representing the built-in type 'Map'.
+   * The type representing the built-in type 'Map<Object, Object>'.
    */
-  InterfaceType _mapNullNullType;
+  InterfaceType _mapObjectObjectType;
 
   /**
    * An shared object representing the value 'null'.
@@ -139,11 +144,6 @@
   InterfaceType _setType;
 
   /**
-   * The type representing the built-in type 'Set'.
-   */
-  InterfaceType _setNullType;
-
-  /**
    * The type representing the built-in type 'StackTrace'.
    */
   InterfaceType _stackTraceType;
@@ -334,6 +334,14 @@
   }
 
   @override
+  InterfaceType get iterableObjectType {
+    if (_iterableObjectType == null) {
+      _iterableObjectType = iterableType.instantiate(<DartType>[objectType]);
+    }
+    return _iterableObjectType;
+  }
+
+  @override
   InterfaceType get iterableType {
     if (_iterableType == null) {
       ClassElementImpl iterableElement =
@@ -399,11 +407,12 @@
   }
 
   @override
-  InterfaceType get mapNullNullType {
-    if (_mapNullNullType == null) {
-      _mapNullNullType = mapType.instantiate(<DartType>[nullType, nullType]);
+  InterfaceType get mapObjectObjectType {
+    if (_mapObjectObjectType == null) {
+      _mapObjectObjectType =
+          mapType.instantiate(<DartType>[objectType, objectType]);
     }
-    return _mapNullNullType;
+    return _mapObjectObjectType;
   }
 
   @override
@@ -494,14 +503,6 @@
   }
 
   @override
-  InterfaceType get setNullType {
-    if (_setNullType == null) {
-      _setNullType = setType.instantiate(<DartType>[nullType]);
-    }
-    return _setNullType;
-  }
-
-  @override
   InterfaceType get setType {
     if (_setType == null) {
       ClassElementImpl setElement = ElementFactory.classElement2("Set", ["E"]);
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 2a2bebe..6a4ffba 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -885,7 +885,7 @@
   DartType _substituteForUnknownType(DartType type, {bool lowerBound: false}) {
     if (identical(type, UnknownInferredType.instance)) {
       if (lowerBound) {
-        // TODO(jmesserly): this should be the bottom type, once i can be
+        // TODO(jmesserly): this should be the bottom type, once it can be
         // reified.
         return typeProvider.nullType;
       }
@@ -896,7 +896,8 @@
       var newTypeArgs = _transformList(type.typeArguments,
           (t) => _substituteForUnknownType(t, lowerBound: lowerBound));
       if (identical(type.typeArguments, newTypeArgs)) return type;
-      return new InterfaceTypeImpl(type.element, type.prunedTypedefs)
+      return new InterfaceTypeImpl(
+          type.element, type.prunedTypedefs, type.nullability)
         ..typeArguments = newTypeArgs;
     }
     if (type is FunctionType) {
@@ -922,7 +923,8 @@
       }
 
       return new FunctionTypeImpl.synthetic(
-          newReturnType, type.typeFormals, newParameters);
+          newReturnType, type.typeFormals, newParameters,
+          nullability: (type as TypeImpl).nullability);
     }
     return type;
   }
@@ -2171,10 +2173,14 @@
   bool get isDynamic => true;
 
   @override
+  Nullability get nullability => Nullability.indeterminate;
+
+  @override
   bool operator ==(Object object) => identical(object, this);
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> types) {
+  void appendTo(StringBuffer buffer, Set<TypeImpl> types,
+      {bool withNullability = false}) {
     buffer.write('?');
   }
 
@@ -2228,6 +2234,9 @@
     return this;
   }
 
+  @override
+  TypeImpl withNullability(Nullability nullability) => this;
+
   /// Given a [type] T, return true if it does not have an unknown type `?`.
   static bool isKnown(DartType type) => !isUnknown(type);
 
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index b9b065e..f0a1a4a 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -62,6 +62,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/builder.dart';
@@ -434,6 +435,9 @@
   bool get strongModeHints => false;
 
   @override
+  ExperimentStatus get experimentStatus => new ExperimentStatus();
+
+  @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
@@ -1008,15 +1012,15 @@
   List<InterfaceType> get interfaces => const [];
 
   @override
+  bool get isAbstract => false;
+
+  @override
   bool get isEnum => true;
 
   @override
   bool get isMixin => false;
 
   @override
-  bool get isAbstract => false;
-
-  @override
   bool get isObject => false;
 
   @override
@@ -5318,15 +5322,15 @@
   InterfaceType _futureType;
   InterfaceType _intType;
   InterfaceType _iterableDynamicType;
+  InterfaceType _iterableObjectType;
   InterfaceType _iterableType;
   InterfaceType _listType;
   InterfaceType _mapType;
-  InterfaceType _mapNullNullType;
+  InterfaceType _mapObjectObjectType;
   InterfaceType _nullType;
   InterfaceType _numType;
   InterfaceType _objectType;
   InterfaceType _setType;
-  InterfaceType _setNullType;
   InterfaceType _stackTraceType;
   InterfaceType _streamDynamicType;
   InterfaceType _streamType;
@@ -5387,6 +5391,10 @@
       iterableType.instantiate(<DartType>[dynamicType]);
 
   @override
+  InterfaceType get iterableObjectType =>
+      _iterableObjectType ??= iterableType.instantiate(<DartType>[objectType]);
+
+  @override
   InterfaceType get iterableType =>
       _iterableType ??= _buildInterfaceType(_linker.coreLibrary, 'Iterable');
 
@@ -5395,8 +5403,8 @@
       _listType ??= _buildInterfaceType(_linker.coreLibrary, 'List');
 
   @override
-  InterfaceType get mapNullNullType =>
-      _mapNullNullType ??= mapType.instantiate(<DartType>[nullType, nullType]);
+  InterfaceType get mapObjectObjectType => _mapObjectObjectType ??=
+      mapType.instantiate(<DartType>[objectType, objectType]);
 
   @override
   InterfaceType get mapType =>
@@ -5421,10 +5429,6 @@
       _objectType ??= _buildInterfaceType(_linker.coreLibrary, 'Object');
 
   @override
-  InterfaceType get setNullType =>
-      _setNullType ??= setType.instantiate(<DartType>[nullType]);
-
-  @override
   InterfaceType get setType =>
       _setType ??= _buildInterfaceType(_linker.coreLibrary, 'Set');
 
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index ae35bf7..3c6b194 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -1458,6 +1458,19 @@
 
   @override
   _ReferenceInfo getReferenceInfo(int index) {
+    // We don't know how to reproduce this.
+    // https://github.com/dart-lang/sdk/issues/35551
+    // https://github.com/dart-lang/sdk/issues/34534
+    // So, adding logging to gather more information.
+    if (index >= referenceInfos.length) {
+      var buffer = StringBuffer();
+      buffer.writeln('librarySource: ${unit.librarySource}');
+      buffer.writeln('unitSource: ${unit.source}');
+      buffer.writeln('unlinkedUnit: ${unlinkedUnit.toJson()}');
+      buffer.writeln('linkedUnit: ${linkedUnit.toJson()}');
+      throw StateError(buffer.toString());
+    }
+
     _ReferenceInfo result = referenceInfos[index];
     if (result == null) {
       LinkedReference linkedReference = linkedUnit.references[index];
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index b60e627..b3389a0 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -128,16 +128,16 @@
   InterfaceType _futureType;
   InterfaceType _intType;
   InterfaceType _iterableDynamicType;
+  InterfaceType _iterableObjectType;
   InterfaceType _iterableType;
   InterfaceType _listType;
   InterfaceType _mapType;
-  InterfaceType _mapNullNullType;
+  InterfaceType _mapObjectObjectType;
   DartObjectImpl _nullObject;
   InterfaceType _nullType;
   InterfaceType _numType;
   InterfaceType _objectType;
   InterfaceType _setType;
-  InterfaceType _setNullType;
   InterfaceType _stackTraceType;
   InterfaceType _streamDynamicType;
   InterfaceType _streamType;
@@ -236,6 +236,13 @@
   }
 
   @override
+  InterfaceType get iterableObjectType {
+    assert(_coreLibrary != null);
+    _iterableObjectType ??= iterableType.instantiate(<DartType>[objectType]);
+    return _iterableObjectType;
+  }
+
+  @override
   InterfaceType get iterableType {
     assert(_coreLibrary != null);
     _iterableType ??= _getType(_coreLibrary, "Iterable");
@@ -250,10 +257,10 @@
   }
 
   @override
-  InterfaceType get mapNullNullType {
+  InterfaceType get mapObjectObjectType {
     assert(_coreLibrary != null);
-    return _mapNullNullType ??=
-        mapType.instantiate(<DartType>[nullType, nullType]);
+    return _mapObjectObjectType ??=
+        mapType.instantiate(<DartType>[objectType, objectType]);
   }
 
   @override
@@ -293,12 +300,6 @@
   }
 
   @override
-  InterfaceType get setNullType {
-    assert(_coreLibrary != null);
-    return _setNullType ??= setType.instantiate(<DartType>[nullType]);
-  }
-
-  @override
   InterfaceType get setType {
     assert(_coreLibrary != null);
     return _setType ??= _getType(_coreLibrary, "Set");
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index b48d3c49..b68d13e 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -106,6 +106,8 @@
 
 abstract class HashMap<K, V> implements Map<K, V> {}
 abstract class LinkedHashMap<K, V> implements Map<K, V> {}
+abstract class HashSet<E> implements Set<E> {}
+abstract class LinkedHashSet<E> implements Set<E> {}
 ''');
 
 const _MockSdkLibrary _LIB_CONVERT = const _MockSdkLibrary(
@@ -152,6 +154,12 @@
   const Deprecated(this.expires);
 }
 
+class pragma {
+  final String name;
+  final Object options;
+  const pragma(this.name, [this.options]);
+}
+
 abstract class double extends num {
   static const double NAN = 0.0 / 0.0;
   static const double INFINITY = 1.0 / 0.0;
diff --git a/pkg/analyzer/lib/src/workspace/basic.dart b/pkg/analyzer/lib/src/workspace/basic.dart
index bfeb81b9..89b270f 100644
--- a/pkg/analyzer/lib/src/workspace/basic.dart
+++ b/pkg/analyzer/lib/src/workspace/basic.dart
@@ -8,29 +8,16 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/source/package_map_resolver.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/workspace/simple.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:package_config/packages.dart';
 
 /**
  * Information about a default Dart workspace.
+ *
+ * A BasicWorkspace should only be used when no other workspace type is valid.
  */
-class BasicWorkspace extends Workspace {
-  /**
-   * The [ResourceProvider] by which paths are converted into [Resource]s.
-   */
-  final ResourceProvider provider;
-
-  /**
-   * The absolute workspace root path.
-   */
-  final String root;
-
-  final ContextBuilder _builder;
-
-  Map<String, List<Folder>> _packageMap;
-
-  Packages _packages;
-
+class BasicWorkspace extends SimpleWorkspace {
   /**
    * The singular package in this workspace.
    *
@@ -38,37 +25,9 @@
    */
   BasicWorkspacePackage _theOnlyPackage;
 
-  BasicWorkspace._(this.provider, this.root, this._builder);
-
-  @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, SummaryDataStore summaryData) {
-    if (summaryData != null) {
-      throw new UnsupportedError(
-          'Summary files are not supported in a basic workspace.');
-    }
-    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);
-  }
+  BasicWorkspace._(
+      ResourceProvider provider, String root, ContextBuilder builder)
+      : super(provider, root, builder);
 
   @override
   WorkspacePackage findPackageFor(String filePath) {
@@ -83,6 +42,10 @@
 
   /**
    * Find the basic workspace that contains the given [path].
+   *
+   * As a [BasicWorkspace] is not defined by any marker files or build
+   * artifacts, this simply creates a BasicWorkspace with [path] as the [root]
+   * (or [path]'s parent if [path] points to a file).
    */
   static BasicWorkspace find(
       ResourceProvider provider, String path, ContextBuilder builder) {
@@ -95,11 +58,11 @@
 }
 
 /**
- * Information about a package defined in a _BasicWorkspace.
+ * Information about a package defined in a [BasicWorkspace].
  *
  * Separate from [Packages] or package maps, this class is designed to simply
  * understand whether arbitrary file paths represent libraries declared within
- * a given package in a _BasicWorkspace.
+ * a given package in a [BasicWorkspace].
  */
 class BasicWorkspacePackage extends WorkspacePackage {
   final String root;
@@ -110,9 +73,9 @@
 
   @override
   bool contains(String path) {
-    // There is a 1-1 relationship between _BasicWorkspaces and
-    // _BasicWorkspacePackages. If a file is in a package's workspace,
-    // then it is in the package as well.
+    // There is a 1-1 relationship between [BasicWorkspace]s and
+    // [BasicWorkspacePackage]s. If a file is in a package's workspace, then it
+    // is in the package as well.
     return workspace.provider.pathContext.isWithin(root, path);
   }
 }
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index d4a83b9c..5e90c71 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -287,11 +287,12 @@
   /**
    * Find the Bazel workspace that contains the given [filePath].
    *
-   * Return `null` if a workspace markers, such as the `WORKSPACE` file, or
+   * Return `null` if a workspace marker, such as the `WORKSPACE` file, or
    * the sibling `READONLY` folder cannot be found.
    *
    * Return `null` if the workspace does not have `bazel-genfiles` or
-   * `blaze-genfiles` folders, so we don't know where to search generated files.
+   * `blaze-genfiles` folders, since we don't know where to search generated
+   * files.
    *
    * Return `null` if there is a folder 'foo' with the sibling `READONLY`
    * folder, but there is corresponding folder 'foo' in `READONLY`, i.e. the
diff --git a/pkg/analyzer/lib/src/workspace/gn.dart b/pkg/analyzer/lib/src/workspace/gn.dart
index 77ef5e8..191c421 100644
--- a/pkg/analyzer/lib/src/workspace/gn.dart
+++ b/pkg/analyzer/lib/src/workspace/gn.dart
@@ -198,6 +198,10 @@
    * file must be found in [filePath]'s output directory.
    */
   static GnWorkspace find(ResourceProvider provider, String filePath) {
+    Resource resource = provider.getResource(filePath);
+    if (resource is File) {
+      filePath = resource.parent.path;
+    }
     Folder folder = provider.getFolder(filePath);
     while (true) {
       Folder parent = folder.parent;
diff --git a/pkg/analyzer/lib/src/workspace/pub.dart b/pkg/analyzer/lib/src/workspace/pub.dart
new file mode 100644
index 0000000..f89937c
--- /dev/null
+++ b/pkg/analyzer/lib/src/workspace/pub.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/workspace/simple.dart';
+import 'package:analyzer/src/workspace/workspace.dart';
+import 'package:package_config/packages.dart';
+
+/// Information about a Pub workspace.
+class PubWorkspace extends SimpleWorkspace {
+  /// The name of the file that identifies the root of the workspace.
+  static const String _pubspecName = 'pubspec.yaml';
+
+  /// The singular package in this workspace.
+  ///
+  /// Each Pub workspace is itself one package.
+  PubWorkspacePackage _theOnlyPackage;
+
+  PubWorkspace._(ResourceProvider provider, String root, ContextBuilder builder)
+      : super(provider, root, builder);
+
+  @override
+  WorkspacePackage findPackageFor(String filePath) {
+    final Folder folder = provider.getFolder(filePath);
+    if (provider.pathContext.isWithin(root, folder.path)) {
+      _theOnlyPackage ??= new PubWorkspacePackage(root, this);
+      return _theOnlyPackage;
+    } else {
+      return null;
+    }
+  }
+
+  /// Find the pub workspace that contains the given [path].
+  static PubWorkspace find(
+      ResourceProvider provider, String filePath, ContextBuilder builder) {
+    Resource resource = provider.getResource(filePath);
+    if (resource is File) {
+      filePath = resource.parent.path;
+    }
+    Folder folder = provider.getFolder(filePath);
+    while (true) {
+      Folder parent = folder.parent;
+      if (parent == null) {
+        return null;
+      }
+
+      if (folder.getChildAssumingFile(_pubspecName).exists) {
+        // Found the pubspec.yaml file; this is our root.
+        String root = folder.path;
+        return new PubWorkspace._(provider, root, builder);
+      }
+
+      // Go up a folder.
+      folder = parent;
+    }
+  }
+}
+
+/// Information about a package defined in a [PubWorkspace].
+///
+/// Separate from [Packages] or package maps, this class is designed to simply
+/// understand whether arbitrary file paths represent libraries declared within
+/// a given package in a [PubWorkspace].
+class PubWorkspacePackage extends WorkspacePackage {
+  final String root;
+
+  final PubWorkspace workspace;
+
+  PubWorkspacePackage(this.root, this.workspace);
+
+  @override
+  bool contains(String path) {
+    // There is a 1-1 relationship between [PubWorkspace]s and
+    // [PubWorkspacePackage]s. If a file is in a package's workspace, then it
+    // is in the package as well.
+    return workspace.provider.pathContext.isWithin(root, path);
+  }
+}
diff --git a/pkg/analyzer/lib/src/workspace/simple.dart b/pkg/analyzer/lib/src/workspace/simple.dart
new file mode 100644
index 0000000..c2d0d8e
--- /dev/null
+++ b/pkg/analyzer/lib/src/workspace/simple.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/workspace/workspace.dart';
+import 'package:package_config/packages.dart';
+
+/// An abstract class for simple workspaces which do not feature any build
+/// artifacts or generated files.
+///
+/// The [packageMap] and [packageUrlResolver] are simple derivations from the
+/// [ContextBuilder] and [ResourceProvider] required for the class.
+abstract class SimpleWorkspace extends Workspace {
+  /// The [ResourceProvider] by which paths are converted into [Resource]s.
+  final ResourceProvider provider;
+
+  /// The absolute workspace root path.
+  final String root;
+
+  final ContextBuilder _builder;
+
+  Map<String, List<Folder>> _packageMap;
+
+  Packages _packages;
+
+  SimpleWorkspace(this.provider, this.root, this._builder);
+
+  @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, SummaryDataStore summaryData) {
+    if (summaryData != null) {
+      throw new UnsupportedError(
+          'Summary files are not supported in a Pub workspace.');
+    }
+    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);
+  }
+}
diff --git a/pkg/analyzer/test/dart/ast/visitor_test.dart b/pkg/analyzer/test/dart/ast/visitor_test.dart
index 0a8e8dd..31b3c35a 100644
--- a/pkg/analyzer/test/dart/ast/visitor_test.dart
+++ b/pkg/analyzer/test/dart/ast/visitor_test.dart
@@ -4,11 +4,11 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:analyzer/src/test_utilities/ast_type_matchers.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../../generated/parser_test.dart' show ParserTestCase;
+import '../../util/ast_type_matchers.dart';
 
 main() {
   defineReflectiveSuite(() {
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 1b05603..0c87fa9 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -31,13 +31,13 @@
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/test_utilities/element_type_matchers.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:path/path.dart' as path;
 import 'package:source_span/source_span.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../util/element_type_matchers.dart';
 import 'parser_test.dart';
 import 'resolver_test_case.dart';
 import 'test_support.dart';
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 0a7da26..e33ea7d 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -15,6 +15,13 @@
 import '../src/util/yaml_test.dart';
 import 'resolver_test_case.dart';
 
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CrossPackageHintCodeTest);
+    defineReflectiveTests(HintCodeTest);
+  });
+}
+
 final metaLibraryStub = r'''
 library meta;
 
@@ -59,20 +66,10 @@
 }
 ''';
 
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(CrossPackageHintCodeTest);
-    defineReflectiveTests(HintCodeTest);
-  });
-}
-
 @reflectiveTest
 class CrossPackageHintCodeTest extends ResolverTestCase {
-  /// Write a pubspec file at [root], so that BestPracticesVerifier can see that
-  /// [root] is the root of a BasicWorkspace, and a BasicWorkspacePackage.
-  void newBasicPackage(String root) {
-    newFile('$root/pubspec.yaml');
-  }
+  @override
+  bool get enableNewAnalysisDriver => true;
 
   test_subtypeOfSealedClass_extending() async {
     super.resetWith(packages: [
@@ -86,7 +83,7 @@
       ]
     ]);
 
-    newBasicPackage('/pkg1');
+    _newPubPackageRoot('/pkg1');
     Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
                     import 'package:foo/foo.dart';
                     class Bar extends Foo {}
@@ -108,7 +105,7 @@
       ]
     ]);
 
-    newBasicPackage('/pkg1');
+    _newPubPackageRoot('/pkg1');
     Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
                     import 'package:foo/foo.dart';
                     class Bar implements Foo {}
@@ -118,94 +115,6 @@
     verify([source]);
   }
 
-  test_subtypeOfSealedClass_with() async {
-    super.resetWith(packages: [
-      ['meta', metaLibraryStub],
-      [
-        'foo',
-        r'''
-import 'package:meta/meta.dart';
-@sealed class Foo {}
-'''
-      ]
-    ]);
-
-    newBasicPackage('/pkg1');
-    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
-                    import 'package:foo/foo.dart';
-                    class Bar extends Object with Foo {}
-                    ''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
-    verify([source]);
-  }
-
-  test_subtypeOfSealedMixin_with() async {
-    super.resetWith(packages: [
-      ['meta', metaLibraryStub],
-      [
-        'foo',
-        r'''
-import 'package:meta/meta.dart';
-@sealed mixin Foo {}
-'''
-      ]
-    ]);
-
-    newBasicPackage('/pkg1');
-    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
-                    import 'package:foo/foo.dart';
-                    class Bar extends Object with Foo {}
-                    ''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
-    verify([source]);
-  }
-
-  test_subtypeOfSealedClass_mixinOn() async {
-    super.resetWith(packages: [
-      ['meta', metaLibraryStub],
-      [
-        'foo',
-        r'''
-import 'package:meta/meta.dart';
-@sealed class Foo {}
-'''
-      ]
-    ]);
-
-    newBasicPackage('/pkg1');
-    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
-                    import 'package:foo/foo.dart';
-                    mixin Bar on Foo {}
-                    ''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.MIXIN_ON_SEALED_CLASS]);
-    verify([source]);
-  }
-
-  test_subtypeOfSealedClass_mixinImplements() async {
-    super.resetWith(packages: [
-      ['meta', metaLibraryStub],
-      [
-        'foo',
-        r'''
-import 'package:meta/meta.dart';
-@sealed class Foo {}
-'''
-      ]
-    ]);
-
-    newBasicPackage('/pkg1');
-    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
-                    import 'package:foo/foo.dart';
-                    mixin Bar implements Foo {}
-                    ''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
-    verify([source]);
-  }
-
   test_subtypeOfSealedClass_mixinApplication() async {
     super.resetWith(packages: [
       ['meta', metaLibraryStub],
@@ -218,7 +127,7 @@
       ]
     ]);
 
-    newBasicPackage('/pkg1');
+    _newPubPackageRoot('/pkg1');
     Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
                     import 'package:foo/foo.dart';
                     class Bar1 {}
@@ -229,23 +138,66 @@
     verify([source]);
   }
 
-  test_subtypeOfSealedMixin_mixinApplication() async {
+  test_subtypeOfSealedClass_mixinImplements() async {
     super.resetWith(packages: [
       ['meta', metaLibraryStub],
       [
         'foo',
         r'''
 import 'package:meta/meta.dart';
-@sealed mixin Foo {}
+@sealed class Foo {}
 '''
       ]
     ]);
 
-    newBasicPackage('/pkg1');
+    _newPubPackageRoot('/pkg1');
     Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
                     import 'package:foo/foo.dart';
-                    class Bar1 {}
-                    class Bar2 = Bar1 with Foo;
+                    mixin Bar implements Foo {}
+                    ''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
+    verify([source]);
+  }
+
+  test_subtypeOfSealedClass_mixinOn() async {
+    super.resetWith(packages: [
+      ['meta', metaLibraryStub],
+      [
+        'foo',
+        r'''
+import 'package:meta/meta.dart';
+@sealed class Foo {}
+'''
+      ]
+    ]);
+
+    _newPubPackageRoot('/pkg1');
+    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
+                    import 'package:foo/foo.dart';
+                    mixin Bar on Foo {}
+                    ''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.MIXIN_ON_SEALED_CLASS]);
+    verify([source]);
+  }
+
+  test_subtypeOfSealedClass_with() async {
+    super.resetWith(packages: [
+      ['meta', metaLibraryStub],
+      [
+        'foo',
+        r'''
+import 'package:meta/meta.dart';
+@sealed class Foo {}
+'''
+      ]
+    ]);
+
+    _newPubPackageRoot('/pkg1');
+    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
+                    import 'package:foo/foo.dart';
+                    class Bar extends Object with Foo {}
                     ''');
     await computeAnalysisResult(source);
     assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
@@ -257,7 +209,7 @@
       ['meta', metaLibraryStub],
     ]);
 
-    newBasicPackage('/pkg1');
+    _newPubPackageRoot('/pkg1');
     Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
                     import 'package:meta/meta.dart';
                     @sealed class Foo {}
@@ -273,12 +225,64 @@
     verify([source]);
   }
 
+  test_subtypeOfSealedClass_withinPackageLibDirectory_OK() async {
+    super.resetWith(packages: [
+      ['meta', metaLibraryStub],
+    ]);
+
+    _newPubPackageRoot('/pkg1');
+    Source source1 = addNamedSource('/pkg1/lib/lib1.dart', r'''
+                     import 'package:meta/meta.dart';
+                     @sealed class Foo {}
+                     ''');
+    Source source2 = addNamedSource('/pkg1/lib/src/lib2.dart', r'''
+                     import '../lib1.dart';
+                     class Bar1 extends Foo {}
+                     class Bar2 implements Foo {}
+                     class Bar4 = Bar1 with Foo;
+                     mixin Bar5 on Foo {}
+                     mixin Bar6 implements Foo {}
+                     ''');
+    await computeAnalysisResult(source1);
+    await computeAnalysisResult(source2);
+    assertNoErrors(source1);
+    assertNoErrors(source2);
+    verify([source1, source2]);
+  }
+
+  test_subtypeOfSealedClass_withinPackageTestDirectory_OK() async {
+    super.resetWith(packages: [
+      ['meta', metaLibraryStub],
+    ]);
+
+    newFolder('/pkg1');
+    _newPubPackageRoot('/pkg1');
+
+    Source source1 = addNamedSource('/pkg1/lib/lib1.dart', r'''
+                     import 'package:meta/meta.dart';
+                     @sealed class Foo {}
+                     ''');
+    Source source2 = addNamedSource('/pkg1/test/test.dart', r'''
+                     import '../lib/lib1.dart';
+                     class Bar1 extends Foo {}
+                     class Bar2 implements Foo {}
+                     class Bar4 = Bar1 with Foo;
+                     mixin Bar5 on Foo {}
+                     mixin Bar6 implements Foo {}
+                     ''');
+    await computeAnalysisResult(source1);
+    await computeAnalysisResult(source2);
+    assertNoErrors(source1);
+    assertNoErrors(source2);
+    verify([source1, source2]);
+  }
+
   test_subtypeOfSealedClass_withinPart_OK() async {
     super.resetWith(packages: [
       ['meta', metaLibraryStub],
     ]);
 
-    newBasicPackage('/pkg1');
+    _newPubPackageRoot('/pkg1');
     Source source1 = addNamedSource('/pkg1/lib/lib1.dart', r'''
                      import 'package:meta/meta.dart';
                      part 'part1.dart';
@@ -297,48 +301,55 @@
     verify([source1]);
   }
 
-  test_subtypeOfSealedClass_withinPackageLibDirectory_OK() async {
+  test_subtypeOfSealedMixin_mixinApplication() async {
     super.resetWith(packages: [
       ['meta', metaLibraryStub],
+      [
+        'foo',
+        r'''
+import 'package:meta/meta.dart';
+@sealed mixin Foo {}
+'''
+      ]
     ]);
 
-    newBasicPackage('/pkg1');
-    Source source1 = addNamedSource('/pkg1/lib/lib1.dart', r'''
-                     import 'package:meta/meta.dart';
-                     @sealed class Foo {}
-                     ''');
-    addNamedSource('/pkg1/lib/src/lib2.dart', r'''
-                     class Bar1 extends Foo {}
-                     class Bar2 implements Foo {}
-                     class Bar4 = Bar1 with Foo;
-                     mixin Bar5 on Foo {}
-                     mixin Bar6 implements Foo {}
-                     ''');
-    await computeAnalysisResult(source1);
-    assertNoErrors(source1);
-    verify([source1]);
+    _newPubPackageRoot('/pkg1');
+    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
+                    import 'package:foo/foo.dart';
+                    class Bar1 {}
+                    class Bar2 = Bar1 with Foo;
+                    ''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
+    verify([source]);
   }
 
-  test_subtypeOfSealedClass_withinPackageTestDirectory_OK() async {
+  test_subtypeOfSealedMixin_with() async {
     super.resetWith(packages: [
       ['meta', metaLibraryStub],
+      [
+        'foo',
+        r'''
+import 'package:meta/meta.dart';
+@sealed mixin Foo {}
+'''
+      ]
     ]);
 
-    newBasicPackage('/pkg1');
-    Source source1 = addNamedSource('/pkg1/lib/lib1.dart', r'''
-                     import 'package:meta/meta.dart';
-                     @sealed class Foo {}
-                     ''');
-    addNamedSource('/pkg1/test/test.dart', r'''
-                     class Bar1 extends Foo {}
-                     class Bar2 implements Foo {}
-                     class Bar4 = Bar1 with Foo;
-                     mixin Bar5 on Foo {}
-                     mixin Bar6 implements Foo {}
-                     ''');
-    await computeAnalysisResult(source1);
-    assertNoErrors(source1);
-    verify([source1]);
+    _newPubPackageRoot('/pkg1');
+    Source source = addNamedSource('/pkg1/lib/lib1.dart', r'''
+                    import 'package:foo/foo.dart';
+                    class Bar extends Object with Foo {}
+                    ''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.SUBTYPE_OF_SEALED_CLASS]);
+    verify([source]);
+  }
+
+  /// Write a pubspec file at [root], so that BestPracticesVerifier can see
+  /// that [root] is the root of a PubWorkspace, and a PubWorkspacePackage.
+  void _newPubPackageRoot(String root) {
+    newFile('$root/pubspec.yaml');
   }
 }
 
@@ -1227,76 +1238,6 @@
     ]);
   }
 
-  test_invalidAssignment_instanceVariable() async {
-    Source source = addSource(r'''
-class A {
-  int x;
-}
-f(var y) {
-  A a;
-  if(y is String) {
-    a.x = y;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
-    verify([source]);
-  }
-
-  test_invalidAssignment_localVariable() async {
-    Source source = addSource(r'''
-f(var y) {
-  if(y is String) {
-    int x = y;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
-    verify([source]);
-  }
-
-  test_invalidAssignment_message() async {
-    // The implementation of HintCode.INVALID_ASSIGNMENT assumes that
-    // StaticTypeWarningCode.INVALID_ASSIGNMENT has the same message.
-    expect(StaticTypeWarningCode.INVALID_ASSIGNMENT.message,
-        HintCode.INVALID_ASSIGNMENT.message);
-  }
-
-  test_invalidAssignment_staticVariable() async {
-    Source source = addSource(r'''
-class A {
-  static int x;
-}
-f(var y) {
-  if(y is String) {
-    A.x = y;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
-    verify([source]);
-  }
-
-  test_invalidAssignment_variableDeclaration() async {
-    // 17971
-    Source source = addSource(r'''
-class Point {
-  final num x, y;
-  Point(this.x, this.y);
-  Point operator +(Point other) {
-    return new Point(x+other.x, y+other.y);
-  }
-}
-main() {
-  var p1 = new Point(0, 0);
-  var p2 = new Point(10, 10);
-  int n = p1 + p2;
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
-    verify([source]);
-  }
-
   test_invalidImmutableAnnotation_method() async {
     Source source = addSource(r'''
 import 'package:meta/meta.dart';
@@ -1323,6 +1264,55 @@
     verify([source]);
   }
 
+  test_nonConstCallToLiteralConstructor_nonConstContext() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @literal
+  const A();
+}
+void main() {
+  var a = A();
+}
+''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR]);
+    verify([source]);
+  }
+
+  test_nonConstCallToLiteralConstructor_usingNew() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @literal
+  const A();
+}
+void main() {
+  var a = new A();
+}
+''');
+    await computeAnalysisResult(source);
+    assertErrors(
+        source, [HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW]);
+    verify([source]);
+  }
+
+  test_nonConstCallToLiteralConstructor_namedConstructor() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @literal
+  const A.named();
+}
+void main() {
+  var a = A.named();
+}
+''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR]);
+    verify([source]);
+  }
+
   test_invalidLiteralAnnotation_nonConstructor() async {
     Source source = addSource(r'''
 import 'package:meta/meta.dart';
@@ -1347,6 +1337,17 @@
     verify([source]);
   }
 
+  test_invalidSealedAnnotation_onMixin() async {
+    Source source = addNamedSource('/lib1.dart', r'''
+import 'package:meta/meta.dart';
+
+@sealed mixin M {}
+''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.INVALID_SEALED_ANNOTATION]);
+    verify([source]);
+  }
+
   test_invalidSealedAnnotation_onMixinApplication() async {
     Source source = addNamedSource('/lib1.dart', r'''
 import 'package:meta/meta.dart';
@@ -1362,17 +1363,6 @@
     verify([source]);
   }
 
-  test_invalidSealedAnnotation_onMixin() async {
-    Source source = addNamedSource('/lib1.dart', r'''
-import 'package:meta/meta.dart';
-
-@sealed mixin M {}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.INVALID_SEALED_ANNOTATION]);
-    verify([source]);
-  }
-
   test_invalidSealedAnnotation_onNonClass() async {
     Source source = addNamedSource('/lib1.dart', r'''
 import 'package:meta/meta.dart';
@@ -2415,21 +2405,6 @@
     verify([source]);
   }
 
-  test_mustBeImmutable_mixinApplicationBase() async {
-    Source source = addSource(r'''
-import 'package:meta/meta.dart';
-class A {
-  int x;
-}
-class B {}
-@immutable
-class C = A with B;
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.MUST_BE_IMMUTABLE]);
-    verify([source]);
-  }
-
   test_mustBeImmutable_fromMixin() async {
     Source source = addSource(r'''
 import 'package:meta/meta.dart';
@@ -2473,6 +2448,21 @@
     verify([source]);
   }
 
+  test_mustBeImmutable_mixinApplicationBase() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  int x;
+}
+class B {}
+@immutable
+class C = A with B;
+''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [HintCode.MUST_BE_IMMUTABLE]);
+    verify([source]);
+  }
+
   test_mustCallSuper() async {
     Source source = addSource(r'''
 import 'package:meta/meta.dart';
@@ -3900,26 +3890,6 @@
     assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
   }
 
-  test_unnecessaryCast_type_supertype() async {
-    Source source = addSource(r'''
-m(int i) {
-  var b = i as Object;
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNNECESSARY_CAST]);
-    verify([source]);
-  }
-
-  test_unnecessaryCast_type_type() async {
-    Source source = addSource(r'''
-m(num i) {
-  var b = i as num;
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNNECESSARY_CAST]);
-    verify([source]);
-  }
-
   test_unnecessaryNoSuchMethod_blockBody() async {
     Source source = addSource(r'''
 class A {
@@ -4746,346 +4716,6 @@
     verify([source]);
   }
 
-  test_unusedField_isUsed_argument() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f = 0;
-  main() {
-    print(++_f);
-  }
-}
-print(x) {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_isUsed_reference_implicitThis() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  main() {
-    print(_f);
-  }
-}
-print(x) {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_isUsed_reference_implicitThis_expressionFunctionBody() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  m() => _f;
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_isUsed_reference_implicitThis_subclass() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  main() {
-    print(_f);
-  }
-}
-class B extends A {
-  int _f;
-}
-print(x) {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_isUsed_reference_qualified_propagatedElement() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-}
-main() {
-  var a = new A();
-  print(a._f);
-}
-print(x) {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_isUsed_reference_qualified_staticElement() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-}
-main() {
-  A a = new A();
-  print(a._f);
-}
-print(x) {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_isUsed_reference_qualified_unresolved() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-}
-main(a) {
-  print(a._f);
-}
-print(x) {}''');
-    await computeAnalysisResult(source);
-    assertErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_compoundAssign() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  main() {
-    _f += 2;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_constructorFieldInitializers() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  A() : _f = 0;
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_fieldFormalParameter() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  A(this._f);
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_noReference() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_nullAssign() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  var _f;
-  m() {
-    _f ??= doSomething();
-  }
-}
-doSomething() => 0;
-''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_postfixExpr() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f = 0;
-  main() {
-    _f++;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_prefixExpr() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f = 0;
-  main() {
-    ++_f;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedField_notUsed_simpleAssignment() async {
-    enableUnusedElement = true;
-    Source source = addSource(r'''
-class A {
-  int _f;
-  m() {
-    _f = 1;
-  }
-}
-main(A a) {
-  a._f = 2;
-}
-''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_FIELD]);
-    verify([source]);
-  }
-
-  test_unusedImport() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart';''');
-    Source source2 = addNamedSource("/lib1.dart", "library lib1;");
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_IMPORT]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  test_unusedImport_as() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart';
-import 'lib1.dart' as one;
-one.A a;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_IMPORT]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  @failingTest
-  test_unusedImport_as_equalPrefixes() async {
-    // See todo at ImportsVerifier.prefixElementMap.
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' as one;
-import 'lib2.dart' as one;
-one.A a;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}''');
-    Source source3 = addNamedSource("/lib2.dart", r'''
-library lib2;
-class B {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    await computeAnalysisResult(source3);
-    assertErrors(source, [HintCode.UNUSED_IMPORT]);
-    assertNoErrors(source2);
-    assertNoErrors(source3);
-    verify([source, source2, source3]);
-  }
-
-  test_unusedImport_hide() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart';
-import 'lib1.dart' hide A;
-A a;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_IMPORT]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  test_unusedImport_inComment_libraryDirective() async {
-    Source source = addSource(r'''
-/// Use [Future] class.
-library L;
-import 'dart:async';
-''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-  }
-
-  test_unusedImport_show() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' show A;
-import 'lib1.dart' show B;
-A a;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}
-class B {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_IMPORT]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  test_unusedLabel_inSwitch() async {
-    Source source = addSource(r'''
-f(x) {
-  switch (x) {
-    label: case 0:
-      break;
-    default:
-      break;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_LABEL]);
-    verify([source]);
-  }
-
-  test_unusedLabel_onWhile() async {
-    Source source = addSource(r'''
-f(condition()) {
-  label: while (condition()) {
-    break;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertErrors(source, [HintCode.UNUSED_LABEL]);
-    verify([source]);
-  }
-
   test_unusedLocalVariable_inCatch_exception() async {
     enableUnusedLocalVariable = true;
     Source source = addSource(r'''
@@ -5287,78 +4917,4 @@
     assertErrors(source);
     verify([source]);
   }
-
-  test_unusedShownName() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' show A, B;
-A a;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}
-class B {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_SHOWN_NAME]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  test_unusedShownName_as() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' as p show A, B;
-p.A a;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}
-class B {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_SHOWN_NAME]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  test_unusedShownName_duplicates() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' show A, B;
-import 'lib1.dart' show C, D;
-A a;
-C c;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}
-class B {}
-class C {}
-class D {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(
-        source, [HintCode.UNUSED_SHOWN_NAME, HintCode.UNUSED_SHOWN_NAME]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
-
-  test_unusedShownName_topLevelVariable() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' show var1, var2;
-import 'lib1.dart' show var3, var4;
-int a = var1;
-int b = var2;
-int c = var3;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-const int var1 = 1;
-const int var2 = 2;
-const int var3 = 3;
-const int var4 = 4;''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source, [HintCode.UNUSED_SHOWN_NAME]);
-    assertNoErrors(source2);
-    verify([source, source2]);
-  }
 }
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 7eb938a..12a26e8 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -2846,6 +2846,74 @@
     verify([source]);
   }
 
+  test_invalidAssignment_postfixExpression_localVariable() async {
+    Source source = addSource(r'''
+class A {
+  A operator+(_) => this;
+}
+
+f(A a) {
+  a++;
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_invalidAssignment_postfixExpression_property() async {
+    Source source = addSource(r'''
+class A {
+  A operator+(_) => this;
+}
+
+class C {
+  A a;
+}
+
+f(C c) {
+  c.a++;
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_invalidAssignment_prefixExpression_localVariable() async {
+    Source source = addSource(r'''
+class A {
+  A operator+(_) => this;
+}
+
+f(A a) {
+  ++a;
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_invalidAssignment_prefixExpression_property() async {
+    Source source = addSource(r'''
+class A {
+  A operator+(_) => this;
+}
+
+class C {
+  A a;
+}
+
+f(C c) {
+  ++c.a;
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   test_invalidAssignment_toDynamic() async {
     Source source = addSource(r'''
 f() {
diff --git a/pkg/analyzer/test/generated/non_hint_code_test.dart b/pkg/analyzer/test/generated/non_hint_code_test.dart
index f1af9c5..bf270f1 100644
--- a/pkg/analyzer/test/generated/non_hint_code_test.dart
+++ b/pkg/analyzer/test/generated/non_hint_code_test.dart
@@ -483,6 +483,57 @@
     verify([source]);
   }
 
+  test_nonConstCallToLiteralConstructor_constCreation() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @literal
+  const A();
+}
+
+void main() {
+  const a = const A();
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_nonConstCallToLiteralConstructor_constContextCreation() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @literal
+  const A();
+}
+
+void main() {
+  const a = A();
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_nonConstCallToLiteralConstructor_unconstableCreation() async {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @literal
+  const A(List list);
+}
+
+void main() {
+  var a = A(new List());
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   test_overrideOnNonOverridingField_inInterface() async {
     Source source = addSource(r'''
 class A {
@@ -910,102 +961,6 @@
     assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
   }
 
-  test_unnecessaryCast_13855_parameter_A() async {
-    // dartbug.com/13855, dartbug.com/13732
-    Source source = addSource(r'''
-class A{
-  a() {}
-}
-class B<E> {
-  E e;
-  m() {
-    (e as A).a();
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unnecessaryCast_conditionalExpression() async {
-    Source source = addSource(r'''
-abstract class I {}
-class A implements I {}
-class B implements I {}
-I m(A a, B b) {
-  return a == null ? b as I : a as I;
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unnecessaryCast_dynamic_type() async {
-    Source source = addSource(r'''
-m(v) {
-  var b = v as Object;
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unnecessaryCast_function() async {
-    Source source = addSource(r'''
-void main() {
-  Function(Null) f = (String x) => x;
-  (f as Function(int))(3); 
-}
-''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unnecessaryCast_function2() async {
-    Source source = addSource(r'''
-class A {}
-
-class B<T extends A> {
-  void foo() {
-    T Function(T) f;
-    A Function(A) g;
-    g = f as A Function(A);
-  }
-}
-''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unnecessaryCast_generics() async {
-    // dartbug.com/18953
-    Source source = addSource(r'''
-import 'dart:async';
-Future<int> f() => new Future.value(0);
-void g(bool c) {
-  (c ? f(): new Future.value(0) as Future<int>).then((int value) {});
-}''');
-    await computeAnalysisResult(source);
-    if (enableNewAnalysisDriver) {
-      assertErrors(source, [HintCode.UNNECESSARY_CAST]);
-    } else {
-      assertNoErrors(source);
-    }
-    verify([source]);
-  }
-
-  test_unnecessaryCast_type_dynamic() async {
-    Source source = addSource(r'''
-m(v) {
-  var b = Object as dynamic;
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
   test_unnecessaryNoSuchMethod_blockBody_notReturnStatement() async {
     Source source = addSource(r'''
 class A {
@@ -1066,224 +1021,6 @@
     assertNoErrors(source);
     verify([source]);
   }
-
-  test_unusedImport_annotationOnDirective() async {
-    Source source = addSource(r'''
-library L;
-@A()
-import 'lib1.dart';''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {
-  const A() {}
-}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    assertErrors(source);
-    verify([source, source2]);
-  }
-
-  test_unusedImport_as_equalPrefixes() async {
-    // 18818
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' as one;
-import 'lib2.dart' as one;
-one.A a;
-one.B b;''');
-    Source source2 = addNamedSource("/lib1.dart", r'''
-library lib1;
-class A {}''');
-    Source source3 = addNamedSource("/lib2.dart", r'''
-library lib2;
-class B {}''');
-    await computeAnalysisResult(source);
-    await computeAnalysisResult(source2);
-    await computeAnalysisResult(source3);
-    assertErrors(source);
-    assertNoErrors(source2);
-    assertNoErrors(source3);
-    verify([source, source2, source3]);
-  }
-
-  test_unusedImport_core_library() async {
-    Source source = addSource(r'''
-library L;
-import 'dart:core';''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedImport_export() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart';
-Two two;''');
-    addNamedSource("/lib1.dart", r'''
-library lib1;
-export 'lib2.dart';
-class One {}''');
-    addNamedSource("/lib2.dart", r'''
-library lib2;
-class Two {}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedImport_export2() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart';
-Three three;''');
-    addNamedSource("/lib1.dart", r'''
-library lib1;
-export 'lib2.dart';
-class One {}''');
-    addNamedSource("/lib2.dart", r'''
-library lib2;
-export 'lib3.dart';
-class Two {}''');
-    addNamedSource("/lib3.dart", r'''
-library lib3;
-class Three {}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedImport_export_infiniteLoop() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart';
-Two two;''');
-    addNamedSource("/lib1.dart", r'''
-library lib1;
-export 'lib2.dart';
-class One {}''');
-    addNamedSource("/lib2.dart", r'''
-library lib2;
-export 'lib3.dart';
-class Two {}''');
-    addNamedSource("/lib3.dart", r'''
-library lib3;
-export 'lib2.dart';
-class Three {}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedImport_metadata() async {
-    Source source = addSource(r'''
-library L;
-@A(x)
-import 'lib1.dart';
-class A {
-  final int value;
-  const A(this.value);
-}''');
-    addNamedSource("/lib1.dart", r'''
-library lib1;
-const x = 0;''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedImport_prefix_topLevelFunction() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' hide topLevelFunction;
-import 'lib1.dart' as one show topLevelFunction;
-class A {
-  static void x() {
-    One o;
-    one.topLevelFunction();
-  }
-}''');
-    addNamedSource("/lib1.dart", r'''
-library lib1;
-class One {}
-topLevelFunction() {}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedImport_prefix_topLevelFunction2() async {
-    Source source = addSource(r'''
-library L;
-import 'lib1.dart' hide topLevelFunction;
-import 'lib1.dart' as one show topLevelFunction;
-import 'lib1.dart' as two show topLevelFunction;
-class A {
-  static void x() {
-    One o;
-    one.topLevelFunction();
-    two.topLevelFunction();
-  }
-}''');
-    addNamedSource("/lib1.dart", r'''
-library lib1;
-class One {}
-topLevelFunction() {}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedLabel_inSwitch() async {
-    Source source = addSource(r'''
-f(x) {
-  switch (x) {
-    label: case 0:
-      break;
-    default:
-      continue label;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_unusedLabel_onWhile() async {
-    Source source = addSource(r'''
-f(condition()) {
-  label: while (condition()) {
-    break label;
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_useOfVoidResult_implicitReturnValue() async {
-    Source source = addSource(r'''
-f() {}
-class A {
-  n() {
-    var a = f();
-  }
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
-
-  test_useOfVoidResult_nonVoidReturnValue() async {
-    Source source = addSource(r'''
-int f() => 1;
-g() {
-  var a = f();
-}''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
 }
 
 class PubSuggestionCodeTest extends ResolverTestCase {
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 1f618d1..b022212 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/generated/parser.dart' as analyzer;
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/string_source.dart';
-import 'package:analyzer/src/test_utilities/ast_type_matchers.dart';
 import 'package:front_end/src/fasta/parser/forwarding_listener.dart' as fasta;
 import 'package:front_end/src/fasta/parser/parser.dart' as fasta;
 import 'package:front_end/src/fasta/scanner.dart'
@@ -26,6 +25,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../util/ast_type_matchers.dart';
 import 'parser_fasta_listener.dart';
 import 'parser_test.dart';
 import 'test_support.dart';
@@ -113,8 +113,9 @@
   void test_conditionalExpression_precedence_nullableType_as2() {
     ExpressionStatement statement = parseStatement('x as bool? ? (x + y) : z;');
     ConditionalExpression expression = statement.expression;
-    Expression condition = expression.condition;
-    expect(condition, isAsExpression);
+    AsExpression asExpression = expression.condition;
+    TypeName type = asExpression.type;
+    expect(type.question.lexeme, '?');
     Expression thenExpression = expression.thenExpression;
     expect(thenExpression, isParenthesizedExpression);
     Expression elseExpression = expression.elseExpression;
@@ -127,9 +128,10 @@
     ExpressionStatement statement =
         parseStatement('(x as bool?) ? (x + y) : z;');
     ConditionalExpression expression = statement.expression;
-    Expression condition = expression.condition;
-    expect(condition, isParenthesizedExpression);
-    expect((condition as ParenthesizedExpression).expression, isAsExpression);
+    ParenthesizedExpression condition = expression.condition;
+    AsExpression asExpression = condition.expression;
+    TypeName type = asExpression.type;
+    expect(type.question.lexeme, '?');
     Expression thenExpression = expression.thenExpression;
     expect(thenExpression, isParenthesizedExpression);
     Expression elseExpression = expression.elseExpression;
@@ -142,8 +144,9 @@
     ExpressionStatement statement =
         parseStatement('x is String? ? (x + y) : z;');
     ConditionalExpression expression = statement.expression;
-    Expression condition = expression.condition;
-    expect(condition, isIsExpression);
+    IsExpression isExpression = expression.condition;
+    TypeName type = isExpression.type;
+    expect(type.question.lexeme, '?');
     Expression thenExpression = expression.thenExpression;
     expect(thenExpression, isParenthesizedExpression);
     Expression elseExpression = expression.elseExpression;
@@ -156,9 +159,10 @@
     ExpressionStatement statement =
         parseStatement('(x is String?) ? (x + y) : z;');
     ConditionalExpression expression = statement.expression;
-    Expression condition = expression.condition;
-    expect(condition, isParenthesizedExpression);
-    expect((condition as ParenthesizedExpression).expression, isIsExpression);
+    ParenthesizedExpression condition = expression.condition;
+    IsExpression isExpression = condition.expression;
+    TypeName type = isExpression.type;
+    expect(type.question.lexeme, '?');
     Expression thenExpression = expression.thenExpression;
     expect(thenExpression, isParenthesizedExpression);
     Expression elseExpression = expression.elseExpression;
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index bab974d..e6fbf65 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -24,7 +24,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'package:analyzer/src/test_utilities/ast_type_matchers.dart';
+import '../util/ast_type_matchers.dart';
 import 'test_support.dart';
 
 main() {
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 0558400..69dc68b 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -1732,13 +1732,13 @@
         null, "A", null, extendsClause, withClause, implementsClause);
     declaration.name.staticElement = elementA;
     _resolveNode(declaration, [elementA, elementB, elementC, elementD]);
-    expect(elementA.supertype, same(elementB.type));
+    expect(elementA.supertype, elementB.type);
     List<InterfaceType> mixins = elementA.mixins;
     expect(mixins, hasLength(1));
-    expect(mixins[0], same(elementC.type));
+    expect(mixins[0], elementC.type);
     List<InterfaceType> interfaces = elementA.interfaces;
     expect(interfaces, hasLength(1));
-    expect(interfaces[0], same(elementD.type));
+    expect(interfaces[0], elementD.type);
     _listener.assertNoErrors();
   }
 
@@ -1759,7 +1759,7 @@
         null, "B", null, extendsClause, null, null);
     declaration.name.staticElement = elementB;
     _resolveNode(declaration, [elementA, elementB]);
-    expect(elementB.supertype, same(elementA.type));
+    expect(elementB.supertype, elementA.type);
     _listener.assertNoErrors();
   }
 
@@ -1785,7 +1785,7 @@
     pElement.type = pType;
 
     _resolveFormalParameter(pNode, [intType.element]);
-    expect(pType.returnType, same(intType));
+    expect(pType.returnType, intType);
     expect(pType.parameters, hasLength(1));
     _listener.assertNoErrors();
   }
@@ -1808,7 +1808,7 @@
         AstTestFactory.fieldFormalParameter(null, intTypeName, parameterName);
     node.identifier.staticElement =
         ElementFactory.requiredParameter(parameterName);
-    expect(_resolveFormalParameter(node, [intType.element]), same(intType));
+    expect(_resolveFormalParameter(node, [intType.element]), intType);
     _listener.assertNoErrors();
   }
 
@@ -2017,7 +2017,7 @@
     SimpleIdentifier identifier = node.identifier;
     ParameterElementImpl element = new ParameterElementImpl.forNode(identifier);
     node.declaredElement = identifier.staticElement = element;
-    expect(_resolveFormalParameter(node, [intElement]), same(intType));
+    expect(_resolveFormalParameter(node, [intElement]), intType);
     _listener.assertNoErrors();
   }
 
@@ -2026,7 +2026,7 @@
     TypeName typeName = AstTestFactory.typeName(classA);
     typeName.type = null;
     _resolveNode(typeName, [classA]);
-    expect(typeName.type, same(classA.type));
+    expect(typeName.type, classA.type);
     _listener.assertNoErrors();
   }
 
@@ -2051,7 +2051,7 @@
     expect(resultType.element, same(classA));
     List<DartType> resultArguments = resultType.typeArguments;
     expect(resultArguments, hasLength(1));
-    expect(resultArguments[0], same(classB.type));
+    expect(resultArguments[0], classB.type);
     _listener.assertNoErrors();
   }
 
@@ -2107,11 +2107,11 @@
     _resolveNode(node, definedElements);
     SimpleIdentifier exceptionParameter = node.exceptionParameter;
     if (exceptionParameter != null) {
-      expect(exceptionParameter.staticType, same(exceptionType));
+      expect(exceptionParameter.staticType, exceptionType);
     }
     SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
     if (stackTraceParameter != null) {
-      expect(stackTraceParameter.staticType, same(stackTraceType));
+      expect(stackTraceParameter.staticType, stackTraceType);
     }
   }
 
diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
index 485d871..a682c9d 100644
--- a/pkg/analyzer/test/generated/resolver_test_case.dart
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -35,6 +35,8 @@
 import 'analysis_context_factory.dart';
 import 'test_support.dart';
 
+const String _defaultSourceName = "/test.dart";
+
 /**
  * An AST visitor used to verify that all of the nodes in an AST structure that
  * should have been resolved were resolved.
@@ -407,7 +409,8 @@
    * file will have the given [contents] set in the content provider. Return the
    * source representing the added file.
    */
-  Source addSource(String contents) => addNamedSource("/test.dart", contents);
+  Source addSource(String contents) =>
+      addNamedSource(_defaultSourceName, contents);
 
   /**
    * The [code] that assigns the value to the variable "v", no matter how. We
@@ -457,8 +460,8 @@
    */
   // TODO(rnystrom): Use this in more tests that have the same structure.
   Future<void> assertErrorsInCode(String code, List<ErrorCode> errors,
-      {bool verify: true}) async {
-    Source source = addSource(code);
+      {bool verify: true, String sourceName: _defaultSourceName}) async {
+    Source source = addNamedSource(sourceName, code);
     await computeAnalysisResult(source);
     assertErrors(source, errors);
     if (verify) {
diff --git a/pkg/analyzer/test/generated/simple_resolver_test.dart b/pkg/analyzer/test/generated/simple_resolver_test.dart
index 634605f..91bb80a 100644
--- a/pkg/analyzer/test/generated/simple_resolver_test.dart
+++ b/pkg/analyzer/test/generated/simple_resolver_test.dart
@@ -1698,9 +1698,8 @@
         DartType staticType = node.staticType;
         expect(staticType is FunctionType, isTrue);
         FunctionType functionType = staticType;
-        expect(
-            functionType.parameters[0].type, same(test.typeProvider.intType));
-        expect(functionType.returnType, same(test.typeProvider.stringType));
+        expect(functionType.parameters[0].type, test.typeProvider.intType);
+        expect(functionType.returnType, test.typeProvider.stringType);
       } on AnalysisException catch (e, stackTrace) {
         thrownException[0] = new CaughtException(e, stackTrace);
       }
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index eae9fe1..fe9cb89 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -32,6 +33,7 @@
 
 main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(SetLiteralsTest);
     defineReflectiveTests(StaticTypeAnalyzerTest);
     defineReflectiveTests(StaticTypeAnalyzer2Test);
     defineReflectiveTests(StaticTypeAnalyzer3Test);
@@ -48,6 +50,27 @@
   fail(message);
 }
 
+@reflectiveTest
+class SetLiteralsTest extends StaticTypeAnalyzer2TestShared {
+  @override
+  List<String> get enabledExperiments => [EnableString.set_literals];
+
+  @override
+  bool get enableNewAnalysisDriver => true;
+
+  test_emptySetLiteral_parameter_typed() async {
+    String code = r'''
+main() {
+  useSet({});
+}
+void useSet(Set<int> s) {
+}
+''';
+    await resolveTestUnit(code);
+    expectExpressionType('{}', 'Set<int>');
+  }
+}
+
 /**
  * Like [StaticTypeAnalyzerTest], but as end-to-end tests.
  */
@@ -210,18 +233,6 @@
     await resolveTestUnit(code);
     expectExpressionType('{}', 'Map<int, int>');
   }
-
-  test_emptySetLiteral_parameter_typed() async {
-    String code = r'''
-main() {
-  useSet({});
-}
-void useSet(Set<int> s) {
-}
-''';
-    await resolveTestUnit(code);
-    expectExpressionType('{}', 'Set<int>');
-  }
 }
 
 @reflectiveTest
@@ -1660,6 +1671,16 @@
 
   bool get enableNewAnalysisDriver => true;
 
+  test_emptySetLiteral_inferredFromLinkedHashSet() async {
+    String code = r'''
+import 'dart:collection';
+LinkedHashSet<int> test4() => {};
+''';
+    await resolveTestUnit(code, noErrors: false);
+    expectExpressionType('{}', 'Set<?>');
+    await assertErrorsInCode(code, [StrongModeCode.INVALID_CAST_LITERAL_SET]);
+  }
+
   test_emptySetLiteral_initializer_typed_nested() async {
     String code = r'''
 Set<Set<int>> ints = {{}};
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 283d077..5c1f94b 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -193,6 +193,13 @@
     ]);
   }
 
+  test_defaultSetLiteralNotEnabled() async {
+    await assertErrorsInCode(r'''
+void main() {
+  Set _ = {};
+}''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
   test_expectedOneListTypeArgument() async {
     await assertErrorsInCode(r'''
 main() {
@@ -549,6 +556,70 @@
 }''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
   }
 
+  test_invalidAssignment_postfixExpression_localVariable() async {
+    await assertErrorsInCode(r'''
+class A {
+  B operator+(_) => new B();
+}
+
+class B {}
+
+f(A a) {
+  a++;
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  test_invalidAssignment_postfixExpression_property() async {
+    await assertErrorsInCode(r'''
+class A {
+  B operator+(_) => new B();
+}
+
+class B {}
+
+class C {
+  A a;
+}
+
+f(C c) {
+  c.a++;
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  test_invalidAssignment_prefixExpression_localVariable() async {
+    await assertErrorsInCode(r'''
+class A {
+  B operator+(_) => new B();
+}
+
+class B {}
+
+f(A a) {
+  ++a;
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  test_invalidAssignment_prefixExpression_property() async {
+    await assertErrorsInCode(r'''
+class A {
+  B operator+(_) => new B();
+}
+
+class B {}
+
+class C {
+  A a;
+}
+
+f(C c) {
+  ++c.a;
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
   test_invalidAssignment_regressionInIssue18468Fix() async {
     // https://code.google.com/p/dart/issues/detail?id=18628
     await assertErrorsInCode(r'''
diff --git a/pkg/analyzer/test/source/error_processor_test.dart b/pkg/analyzer/test/source/error_processor_test.dart
index 5ceb965..247d10f 100644
--- a/pkg/analyzer/test/source/error_processor_test.dart
+++ b/pkg/analyzer/test/source/error_processor_test.dart
@@ -18,8 +18,8 @@
 import '../src/util/yaml_test.dart';
 
 main() {
-  AnalysisError invalid_assignment =
-      new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
+  AnalysisError invalid_assignment = new AnalysisError(
+      new TestSource(), 0, 1, StaticTypeWarningCode.INVALID_ASSIGNMENT, [
     ['x'],
     ['y']
   ]);
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 3594512..23e564e 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -17,7 +17,12 @@
 import 'package:analyzer/src/source/package_map_resolver.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer/src/workspace/basic.dart';
 import 'package:analyzer/src/workspace/bazel.dart';
+import 'package:analyzer/src/workspace/gn.dart';
+import 'package:analyzer/src/workspace/package_build.dart';
+import 'package:analyzer/src/workspace/pub.dart';
+import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:args/args.dart';
 import 'package:package_config/packages.dart';
 import 'package:package_config/src/packages_impl.dart';
@@ -872,6 +877,68 @@
     expect(result.path, filePath);
   }
 
+  void test_createWorkspace_hasPackagesFile_hasDartToolAndPubspec() {
+    newFile('/workspace/.packages');
+    newFolder('/workspace/.dart_tool/build/generated/project/lib');
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<PackageBuildWorkspace>());
+  }
+
+  void test_createWorkspace_hasPackagesFile_hasPubspec() {
+    newFile('/workspace/.packages');
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<PubWorkspace>());
+  }
+
+  void test_createWorkspace_hasPackagesFile_noMarkerFiles() {
+    newFile('/workspace/.packages');
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<BasicWorkspace>());
+  }
+
+  void test_createWorkspace_noPackagesFile_hasDartToolAndPubspec() {
+    newFolder('/workspace/.dart_tool/build/generated/project/lib');
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<PackageBuildWorkspace>());
+  }
+
+  void test_createWorkspace_noPackagesFile_hasPubspec() {
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<PubWorkspace>());
+  }
+
+  void test_createWorkspace_noPackagesFile_noMarkerFiles() {
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<BasicWorkspace>());
+  }
+
+  void test_createWorkspace_noPackagesFile_hasGnMarkerFiles() {
+    newFolder('/workspace/.jiri_root');
+    newFile(
+        '/workspace/out/debug-x87_128/dartlang/gen/project/lib/lib.packages');
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<GnWorkspace>());
+  }
+
+  void test_createWorkspace_noPackagesFile_hasBazelMarkerFiles() {
+    newFile('/workspace/WORKSPACE');
+    newFolder('/workspace/bazel-genfiles');
+    Workspace workspace = ContextBuilder.createWorkspace(
+        resourceProvider, '/workspace/project/lib/lib.dart', builder);
+    expect(workspace, TypeMatcher<BazelWorkspace>());
+  }
+
   _defineMockLintRules() {
     _mockLintRule = new _MockLintRule('mock_lint_rule');
     Registry.ruleRegistry.registerDefault(_mockLintRule);
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index df8a221..5822d82 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -26,7 +26,6 @@
 import 'package:analyzer/src/task/api/model.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/html.dart';
-import 'package:analyzer/src/test_utilities/element_type_matchers.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:html/dom.dart' show Document;
 import 'package:test/test.dart';
@@ -34,6 +33,7 @@
 
 import '../../generated/engine_test.dart';
 import '../../generated/test_support.dart';
+import '../../util/element_type_matchers.dart';
 import 'abstract_context.dart';
 
 main() {
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index b5c6ad8..e52ece7 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -4081,12 +4081,12 @@
 
     VariableDeclarationStatement vStatement = mainStatements[1];
     VariableDeclaration vDeclaration = vStatement.variables.variables[0];
-    expect(vDeclaration.declaredElement.type, same(doubleType));
+    expect(vDeclaration.declaredElement.type, doubleType);
 
     MethodInvocation fInvocation = vDeclaration.initializer;
     expect(fInvocation.methodName.staticElement, same(fElement));
     expect(fInvocation.methodName.staticType.toString(), fTypeString);
-    expect(fInvocation.staticType, same(doubleType));
+    expect(fInvocation.staticType, doubleType);
     expect(fInvocation.staticInvokeType.toString(), fTypeString);
   }
 
@@ -4407,12 +4407,12 @@
     {
       VariableDeclarationStatement statement = mainStatements[1];
       VariableDeclaration declaration = statement.variables.variables[0];
-      expect(declaration.declaredElement.type, same(doubleType));
+      expect(declaration.declaredElement.type, doubleType);
 
       MethodInvocation invocation = declaration.initializer;
       expect(invocation.methodName.staticElement, same(fElement));
       expect(invocation.methodName.staticType.toString(), fTypeString);
-      expect(invocation.staticType, same(doubleType));
+      expect(invocation.staticType, doubleType);
       expect(invocation.staticInvokeType.toString(), fTypeString);
 
       List<Expression> arguments = invocation.argumentList.arguments;
@@ -5773,7 +5773,7 @@
 
     expect(invocation.methodName.staticElement, same(fElement));
     expect(invocation.methodName.staticType.toString(), fTypeString);
-    expect(invocation.staticType, same(doubleType));
+    expect(invocation.staticType, doubleType);
     expect(invocation.staticInvokeType.toString(), fTypeString);
 
     _assertArgumentToParameter(arguments[0], fElement.parameters[0]);
@@ -6868,21 +6868,20 @@
       SimpleIdentifier identifier = statement.expression;
 
       expect(identifier.staticElement, same(getterElement));
-      expect(identifier.staticType, same(typeProvider.intType));
+      expect(identifier.staticType, typeProvider.intType);
     }
 
     // super.getter;
     {
       ExpressionStatement statement = testStatements[3];
       PropertyAccess propertyAccess = statement.expression;
-      expect(propertyAccess.staticType, same(typeProvider.intType));
+      expect(propertyAccess.staticType, typeProvider.intType);
 
       SuperExpression target = propertyAccess.target;
       expect(target.staticType, bNode.declaredElement.type); // raw
 
       expect(propertyAccess.propertyName.staticElement, same(getterElement));
-      expect(
-          propertyAccess.propertyName.staticType, same(typeProvider.intType));
+      expect(propertyAccess.propertyName.staticType, typeProvider.intType);
     }
 
     // setter = 3;
@@ -6892,7 +6891,7 @@
 
       SimpleIdentifier identifier = assignment.leftHandSide;
       expect(identifier.staticElement, same(setterElement));
-      expect(identifier.staticType, same(typeProvider.intType));
+      expect(identifier.staticType, typeProvider.intType);
     }
 
     // this.setter = 4;
@@ -6906,8 +6905,7 @@
       expect(target.staticType, bNode.declaredElement.type); // raw
 
       expect(propertyAccess.propertyName.staticElement, same(setterElement));
-      expect(
-          propertyAccess.propertyName.staticType, same(typeProvider.intType));
+      expect(propertyAccess.propertyName.staticType, typeProvider.intType);
     }
 
     // super + 5;
@@ -7511,7 +7509,7 @@
       TypeName typeName = bDeclaration.fields.type;
       SimpleIdentifier typeIdentifier = typeName.name;
       expect(typeIdentifier.staticElement, same(tElement));
-      expect(typeIdentifier.staticType, same(tElement.type));
+      expect(typeIdentifier.staticType, tElement.type);
 
       VariableDeclaration bNode = bDeclaration.fields.variables[0];
       expect(bNode.declaredElement, same(bElement));
@@ -8816,7 +8814,7 @@
 
     TypeName typeName = node.type;
     if (typeName != null) {
-      expect(typeName.type, same(type));
+      expect(typeName.type, type);
       expect(typeName.name.staticElement, same(type.element));
     }
   }
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 12505a4..aef3c08 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -2337,19 +2337,11 @@
   }
 
   test_hasFilesToAnalyze() async {
-    var a = convertPath('/test/lib/a.dart');
-    var b = convertPath('/test/lib/b.dart');
-    var c = convertPath('/test/lib/c.dart');
-
     // No files yet, nothing to analyze.
     expect(driver.hasFilesToAnalyze, isFalse);
 
     // Add a new file, it should be analyzed.
-    newFile(a, content: r'''
-import 'b.dart';
-main() {}
-''');
-    driver.addFile(a);
+    addTestFile('main() {}', priority: false);
     expect(driver.hasFilesToAnalyze, isTrue);
 
     // Wait for idle, nothing to do.
@@ -2357,25 +2349,19 @@
     expect(driver.hasFilesToAnalyze, isFalse);
 
     // Ask to analyze the file, so there is a file to analyze.
-    Future<ResolvedUnitResult> future = driver.getResult(a);
+    Future<ResolvedUnitResult> future = driver.getResult(testFile);
     expect(driver.hasFilesToAnalyze, isTrue);
 
     // Once analysis is done, there is nothing to analyze.
     await future;
     expect(driver.hasFilesToAnalyze, isFalse);
 
-    // Change a file that is not added, but referenced, so known.
-    driver.changeFile(b);
+    // Change a file, even if not added, it still might affect analysis.
+    driver.changeFile(convertPath('/not/added.dart'));
     expect(driver.hasFilesToAnalyze, isTrue);
     await waitForIdleWithoutExceptions();
     expect(driver.hasFilesToAnalyze, isFalse);
 
-    // Change a file that is not known - neither added, nor referenced.
-    driver.changeFile(c);
-    expect(driver.hasFilesToAnalyze, isFalse);
-    await waitForIdleWithoutExceptions();
-    expect(driver.hasFilesToAnalyze, isFalse);
-
     // Request of referenced names is not analysis of a file.
     driver.getFilesReferencingName('X');
     expect(driver.hasFilesToAnalyze, isFalse);
@@ -3376,6 +3362,28 @@
     expect(result.errors, hasLength(0));
   }
 
+  test_results_removeFile_changeFile() async {
+    var a = convertPath('/test/lib/a.dart');
+    var b = convertPath('/test/lib/b.dart');
+
+    newFile(a, content: r'''
+var v = 0;
+''');
+    driver.addFile(a);
+
+    await waitForIdleWithoutExceptions();
+    expect(allResults.singleWhere((r) => r.path == a).errors, hasLength(0));
+    allResults.clear();
+
+    newFile(a, content: r'''
+var v = 0
+''');
+    driver.removeFile(b);
+    driver.changeFile(a);
+    await waitForIdleWithoutExceptions();
+    expect(allResults.singleWhere((r) => r.path == a).errors, hasLength(1));
+  }
+
   test_results_skipNotAffected() async {
     var a = convertPath('/test/lib/a.dart');
     var b = convertPath('/test/lib/b.dart');
diff --git a/pkg/analyzer/test/src/dart/ast/utilities_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
index f19f1bd..c6d4eab 100644
--- a/pkg/analyzer/test/src/dart/ast/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -14,12 +14,12 @@
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
-import 'package:analyzer/src/test_utilities/ast_type_matchers.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../../../generated/parser_test.dart' show ParserTestCase;
 import '../../../generated/test_support.dart';
+import '../../../util/ast_type_matchers.dart';
 
 main() {
   defineReflectiveSuite(() {
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index b144d20..94176f6 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -817,9 +817,7 @@
 
     DartObjectImpl result = expression.accept(new ConstantVisitor(
         new ConstantEvaluationEngine(typeProvider, new DeclaredVariables(),
-            experimentStatus:
-                ExperimentStatus.fromStrings(options.enabledExperiments),
-            typeSystem: typeSystem),
+            experimentStatus: options.experimentStatus, typeSystem: typeSystem),
         errorReporter,
         lexicalEnvironment: lexicalEnvironment));
     if (errorCodes == null) {
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
index 1d4d442..0616164 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'driver_resolution.dart';
@@ -17,31 +16,205 @@
 
 @reflectiveTest
 class NonNullableTest extends DriverResolutionTest {
+  static const _migrated = "@pragma('analyzer:non-nullable') library test;";
+
   @override
   AnalysisOptionsImpl get analysisOptions =>
       AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
 
-  test_interfaceType() async {
-    addTestFile(r'''
-int v = 0;
+  @override
+  bool get typeToStringWithNullability => true;
+
+  test_class_hierarchy() async {
+    addTestFile('''
+class A {}
+
+class X1 extends A {} // 1
+class X2 implements A {} // 2
+class X3 with A {} // 3
 ''');
     await resolveTestFile();
     assertNoTestErrors();
 
-    var typeName = findNode.typeName('int v');
-    expect(typeName.name.name, 'int');
-    expect(typeName.question, isNull);
+    assertType(findNode.typeName('A {} // 1'), 'A!');
+    assertType(findNode.typeName('A {} // 2'), 'A!');
+    assertType(findNode.typeName('A {} // 3'), 'A!');
   }
 
-  test_interfaceType_nullable() async {
-    addTestFile(r'''
-int? v = 0;
+  test_classTypeAlias_hierarchy() async {
+    addTestFile('''
+class A {}
+class B {}
+class C {}
+
+class X = A with B implements C;
 ''');
     await resolveTestFile();
     assertNoTestErrors();
 
-    var typeName = findNode.typeName('int? v');
-    expect(typeName.name.name, 'int');
-    expect(typeName.question, isNotNull);
+    assertType(findNode.typeName('A with'), 'A!');
+    assertType(findNode.typeName('B implements'), 'B!');
+    assertType(findNode.typeName('C;'), 'C!');
+  }
+
+  test_local_parameter_interfaceType() async {
+    addTestFile('''
+$_migrated
+main() {
+  f(int? a, int b) {}
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('int? a'), 'int?');
+    assertType(findNode.typeName('int b'), 'int!');
+  }
+
+  test_local_returnType_interfaceType() async {
+    addTestFile('''
+$_migrated
+main() {
+  int? f() => 0;
+  int g() => 0;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('int? f'), 'int?');
+    assertType(findNode.typeName('int g'), 'int!');
+  }
+
+  @failingTest
+  test_local_variable_genericFunctionType() async {
+    addTestFile('''
+$_migrated
+main() {
+  int? Function(bool, String?)? a;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(
+      findNode.genericFunctionType('Function('),
+      '(bool!, String?) → int??',
+    );
+  }
+
+  test_local_variable_interfaceType() async {
+    addTestFile('''
+$_migrated
+main() {
+  int? a = 0;
+  int b = 0;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('int? a'), 'int?');
+    assertType(findNode.typeName('int b'), 'int!');
+  }
+
+  test_local_variable_interfaceType_generic() async {
+    addTestFile('''
+$_migrated
+main() {
+  List<int?>? a = [];
+  List<int>? b = [];
+  List<int?> c = [];
+  List<int> d = [];
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('List<int?>? a'), 'List<int?>?');
+    assertType(findNode.typeName('List<int>? b'), 'List<int!>?');
+    assertType(findNode.typeName('List<int?> c'), 'List<int?>!');
+    assertType(findNode.typeName('List<int> d'), 'List<int!>!');
+  }
+
+  test_local_variable_interfaceType_notMigrated() async {
+    addTestFile('''
+main() {
+  int? a = 0;
+  int b = 0;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('int? a'), 'int?');
+    assertType(findNode.typeName('int b'), 'int*');
+  }
+
+  test_local_variable_typeParameter() async {
+    addTestFile('''
+$_migrated
+
+class A<T> {
+  main(T a) {
+    T? b;
+  }
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('T a'), 'T!');
+    assertType(findNode.typeName('T? b'), 'T?');
+  }
+
+  test_mixin_hierarchy() async {
+    addTestFile('''
+class A {}
+
+mixin X1 on A {} // 1
+mixin X2 implements A {} // 2
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('A {} // 1'), 'A!');
+    assertType(findNode.typeName('A {} // 2'), 'A!');
+  }
+
+  test_typedef_classic() async {
+    addTestFile('''
+$_migrated
+
+typedef int? F(bool a, String? b);
+
+main() {
+  F? a;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('F? a'), '(bool!, String?) → int??');
+  }
+
+  @failingTest
+  test_typedef_function() async {
+    addTestFile('''
+$_migrated
+
+typedef F<T> = int? Function(bool, T, T?);
+
+main() {
+  F<String>? a;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(
+      findNode.typeName('F<String>'),
+      '(bool!, String!, String?) → int??',
+    );
   }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 7e7c6b3..efd7d8e 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -58,6 +58,9 @@
   TypeProvider get typeProvider =>
       result.unit.declaredElement.context.typeProvider;
 
+  /// Whether `DartType.toString()` with nullability should be asked.
+  bool get typeToStringWithNullability => false;
+
   void addTestFile(String content) {
     newFile('/test/lib/test.dart', content: content);
   }
@@ -127,7 +130,9 @@
   }
 
   void assertElementTypeString(DartType type, String expected) {
-    expect(type.toString(), expected);
+    TypeImpl typeImpl = type;
+    expect(typeImpl.toString(withNullability: typeToStringWithNullability),
+        expected);
   }
 
   void assertElementTypeStrings(List<DartType> types, List<String> expected) {
@@ -320,7 +325,7 @@
   }
 
   void assertType(AstNode node, String expected) {
-    DartType actual;
+    TypeImpl actual;
     if (node is Expression) {
       actual = node.staticType;
     } else if (node is GenericFunctionType) {
@@ -330,7 +335,8 @@
     } else {
       fail('Unsupported node: (${node.runtimeType}) $node');
     }
-    expect(actual?.toString(), expected);
+    expect(actual?.toString(withNullability: typeToStringWithNullability),
+        expected);
   }
 
   void assertTypeDynamic(Expression expression) {
diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
index bd6d96e..73966e0 100644
--- a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
@@ -17,7 +17,7 @@
 @reflectiveTest
 class ArgumentTypeNotAssignableTest extends ResolverTestCase {
   test_functionType() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m() {
   var a = new A();
   a.n(() => 0);
@@ -29,7 +29,7 @@
   }
 
   test_interfaceType() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m() {
   var i = '';
   n(i);
diff --git a/pkg/analyzer/test/src/diagnostics/can_be_null_after_null_aware_test.dart b/pkg/analyzer/test/src/diagnostics/can_be_null_after_null_aware_test.dart
index 61f3441..94f9c00 100644
--- a/pkg/analyzer/test/src/diagnostics/can_be_null_after_null_aware_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/can_be_null_after_null_aware_test.dart
@@ -17,7 +17,7 @@
 @reflectiveTest
 class CanBeNullAfterNullAwareTest extends ResolverTestCase {
   test_afterCascade() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   x..a?.b.c;
 }
@@ -25,7 +25,7 @@
   }
 
   test_beforeCascade() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   x?.a..m();
 }
@@ -33,7 +33,7 @@
   }
 
   test_cascadeWithParenthesis() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   (x?.a)..m();
 }
@@ -41,7 +41,7 @@
   }
 
   test_definedForNull() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 m(x) {
   x?.a.hashCode;
   x?.a.runtimeType;
@@ -54,7 +54,7 @@
   }
 
   test_guarded_methodInvocation() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 m(x) {
   x?.a()?.b();
 }
@@ -62,7 +62,7 @@
   }
 
   test_guarded_propertyAccess() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 m(x) {
   x?.a?.b;
 }
@@ -70,7 +70,7 @@
   }
 
   test_methodInvocation() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   x?.a.b();
 }
@@ -78,7 +78,7 @@
   }
 
   test_multipleInvocations() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   x?.a
     ..m()
@@ -88,7 +88,7 @@
   }
 
   test_parenthesized() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   (x?.a).b;
 }
@@ -96,7 +96,7 @@
   }
 
   test_propertyAccess() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m(x) {
   x?.a.b;
 }
diff --git a/pkg/analyzer/test/src/diagnostics/const_constructor_with_mixin_with_field_test.dart b/pkg/analyzer/test/src/diagnostics/const_constructor_with_mixin_with_field_test.dart
index 2102064..c864b70 100644
--- a/pkg/analyzer/test/src/diagnostics/const_constructor_with_mixin_with_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_constructor_with_mixin_with_field_test.dart
@@ -16,7 +16,6 @@
   });
 }
 
-@reflectiveTest
 mixin ConstConstructorWithMixinWithFieldMixin implements ResolutionTest {
   test_class_instance() async {
     addTestFile(r'''
diff --git a/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart b/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
index 7519905..1dcc23e 100644
--- a/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
@@ -3,12 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../../generated/resolver_test_case.dart';
 
 main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(DeprecatedMemberUseFromSamePackageTest);
+    defineReflectiveTests(DeprecatedMemberUseFromSamePackageTest_Driver);
     defineReflectiveTests(DeprecatedMemberUseTest);
     defineReflectiveTests(DeprecatedMemberUseTest_Driver);
   });
@@ -16,18 +19,96 @@
 
 @reflectiveTest
 class DeprecatedMemberUseTest extends ResolverTestCase {
-  test__methodInvocation_contructor() async {
+  /// Write a pubspec file at [root], so that BestPracticesVerifier can see that
+  /// [root] is the root of a BasicWorkspace, and a BasicWorkspacePackage.
+  void newBasicPackage(String root) {
+    newFile('$root/pubspec.yaml');
+  }
+
+  test_methodInvocation_contructor() async {
+    resetWithFooLibrary(r'''
+class A {
+  @Deprecated('0.9')
+  m() {}
+}
+''');
+
+    newBasicPackage('/pkg1');
+    assertErrorsInCode(r'''
+import 'package:foo/foo.dart';
+void main() => A().m();
+''', [HintCode.DEPRECATED_MEMBER_USE], sourceName: '/pkg1/lib/lib1.dart');
+  }
+
+  test_methodInvocation_constant() async {
+    resetWithFooLibrary(r'''
+class A {
+  @deprecated
+  m() {}
+}
+''');
+
+    newBasicPackage('/pkg1');
+    assertErrorsInCode(r'''
+import 'package:foo/foo.dart';
+void main() => A().m();
+''', [HintCode.DEPRECATED_MEMBER_USE], sourceName: '/pkg1/lib/lib1.dart');
+  }
+
+  void resetWithFooLibrary(String source) {
+    super.resetWith(packages: [
+      ['foo', source]
+    ]);
+  }
+
+  test_export() async {
+    resetWithFooLibrary(r'''
+@deprecated
+library deprecated_library;
+class A {}
+''');
+
+    newBasicPackage('/pkg1');
+    assertErrorsInCode('''
+export 'package:foo/foo.dart';
+''', [HintCode.DEPRECATED_MEMBER_USE], sourceName: '/pkg1/lib/lib1.dart');
+  }
+
+  test_import() async {
+    resetWithFooLibrary(r'''
+@deprecated
+library deprecated_library;
+class A {}
+''');
+
+    newBasicPackage('/pkg1');
+    assertErrorsInCode(r'''
+import 'package:foo/foo.dart';
+f(A a) {}
+''', [HintCode.DEPRECATED_MEMBER_USE], sourceName: '/pkg1/lib/lib1.dart');
+  }
+}
+
+@reflectiveTest
+class DeprecatedMemberUseTest_Driver extends DeprecatedMemberUseTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
+
+@reflectiveTest
+class DeprecatedMemberUseFromSamePackageTest extends ResolverTestCase {
+  test_methodInvocation_contructor() async {
     assertErrorsInCode(r'''
 class A {
   @Deprecated('0.9')
   m() {}
   n() {m();}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_call() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   call() {}
@@ -36,11 +117,11 @@
     a();
   }
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_compoundAssignment() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   A operator+(A a) { return a; }
@@ -49,7 +130,7 @@
   A b;
   a += b;
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_export() async {
@@ -58,13 +139,13 @@
 library deprecated_library;
 class A {}
 ''');
-    assertErrorsInCode('''
+    await assertErrorsInCode('''
 export 'deprecated_library.dart';
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_field() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   int x = 1;
@@ -72,11 +153,11 @@
 f(A a) {
   return a.x;
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_getter() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   get m => 1;
@@ -84,7 +165,7 @@
 f(A a) {
   return a.m;
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_import() async {
@@ -93,14 +174,14 @@
 library deprecated_library;
 class A {}
 ''');
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 import 'deprecated_library.dart';
 f(A a) {}
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_inDeprecatedClass() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 f() {}
 
@@ -114,7 +195,7 @@
   }
 
   test_inDeprecatedField() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 class C {}
 
@@ -126,7 +207,7 @@
   }
 
   test_inDeprecatedFunction() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 f() {}
 
@@ -138,7 +219,7 @@
   }
 
   test_inDeprecatedLibrary() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 library lib;
 
@@ -154,7 +235,7 @@
   }
 
   test_inDeprecatedMethod() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 f() {}
 
@@ -168,7 +249,7 @@
   }
 
   test_inDeprecatedMethod_inDeprecatedClass() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 f() {}
 
@@ -183,7 +264,7 @@
   }
 
   test_inDeprecatedMixin() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 f() {}
 
@@ -197,7 +278,7 @@
   }
 
   test_inDeprecatedTopLevelVariable() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 @deprecated
 class C {}
 
@@ -207,7 +288,7 @@
   }
 
   test_indexExpression() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   operator[](int i) {}
@@ -215,11 +296,11 @@
 f(A a) {
   return a[1];
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_instanceCreation_defaultConstructor() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   A(int i) {}
@@ -227,11 +308,11 @@
 f() {
   A a = new A(1);
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_instanceCreation_namedConstructor() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   A.named(int i) {}
@@ -239,21 +320,21 @@
 f() {
   A a = new A.named(1);
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_methodInvocation_constant() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   m() {}
   n() {m();}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_operator() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   operator+(A a) {}
@@ -262,26 +343,26 @@
   A b;
   return a + b;
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_parameter_named() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   m({@deprecated int x}) {}
   n() {m(x: 1);}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_parameter_named_inDefiningFunction() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f({@deprecated int x}) => x;
 ''');
   }
 
   test_parameter_named_inDefiningLocalFunction() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C {
   m() {
     f({@deprecated int x}) {
@@ -294,7 +375,7 @@
   }
 
   test_parameter_named_inDefiningMethod() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C {
   m({@deprecated int x}) {
     return x;
@@ -304,7 +385,7 @@
   }
 
   test_parameter_named_inNestedLocalFunction() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C {
   m({@deprecated int x}) {
     f() {
@@ -317,16 +398,16 @@
   }
 
   test_parameter_positional() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   m([@deprecated int x]) {}
   n() {m(1);}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_setter() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   set s(v) {}
@@ -334,11 +415,11 @@
 f(A a) {
   return a.s = 1;
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_superConstructor_defaultConstructor() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   A() {}
@@ -346,11 +427,11 @@
 class B extends A {
   B() : super() {}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 
   test_superConstructor_namedConstructor() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A {
   @deprecated
   A.named() {}
@@ -358,12 +439,13 @@
 class B extends A {
   B() : super.named() {}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
   }
 }
 
 @reflectiveTest
-class DeprecatedMemberUseTest_Driver extends DeprecatedMemberUseTest {
+class DeprecatedMemberUseFromSamePackageTest_Driver
+    extends DeprecatedMemberUseFromSamePackageTest {
   @override
   bool get enableNewAnalysisDriver => true;
 }
diff --git a/pkg/analyzer/test/src/diagnostics/division_optimization_test.dart b/pkg/analyzer/test/src/diagnostics/division_optimization_test.dart
index 539cdf1..6adfcf2 100644
--- a/pkg/analyzer/test/src/diagnostics/division_optimization_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/division_optimization_test.dart
@@ -17,7 +17,7 @@
 @reflectiveTest
 class DivisionOptimizationTest extends ResolverTestCase {
   test_divisionOptimization() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(int x, int y) {
   var v = x / y.toInt();
 }
@@ -25,7 +25,7 @@
   }
 
   test_double() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 f(double x, double y) {
   var v = (x / y).toInt();
 }
@@ -33,7 +33,7 @@
   }
 
   test_dynamic() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(x, y) {
   var v = (x / y).toInt();
 }
@@ -41,7 +41,7 @@
   }
 
   test_int() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 f(int x, int y) {
   var v = (x / y).toInt();
 }
@@ -49,7 +49,7 @@
   }
 
   test_nonNumeric() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class A {
   num operator /(x) { return x; }
 }
@@ -60,7 +60,7 @@
   }
 
   test_wrappedInParentheses() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 f(int x, int y) {
   var v = (((x / y))).toInt();
 }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart
new file mode 100644
index 0000000..0630617
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidAssignmentTest);
+    defineReflectiveTests(InvalidAssignmentTest_Driver);
+  });
+}
+
+@reflectiveTest
+class InvalidAssignmentTest extends ResolverTestCase {
+  test_instanceVariable() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+}
+f(var y) {
+  A a;
+  if (y is String) {
+    a.x = y;
+  }
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  test_localVariable() async {
+    await assertErrorsInCode(r'''
+f(var y) {
+  if (y is String) {
+    int x = y;
+  }
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  test_staticVariable() async {
+    await assertErrorsInCode(r'''
+class A {
+  static int x;
+}
+f(var y) {
+  if (y is String) {
+    A.x = y;
+  }
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  test_variableDeclaration() async {
+    // 17971
+    await assertErrorsInCode(r'''
+class Point {
+  final num x, y;
+  Point(this.x, this.y);
+  Point operator +(Point other) {
+    return new Point(x+other.x, y+other.y);
+  }
+}
+main() {
+  var p1 = new Point(0, 0);
+  var p2 = new Point(10, 10);
+  int n = p1 + p2;
+}
+''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+}
+
+@reflectiveTest
+class InvalidAssignmentTest_Driver extends InvalidAssignmentTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
index 70c22e5..e10b266 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
@@ -25,7 +25,7 @@
   }
 
   test_namedParameter_withDefault() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
 m({@required a = 1}) => null;
@@ -33,7 +33,7 @@
   }
 
   test_positionalParameter_withDefault() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
 m([@required a = 1]) => null;
@@ -41,7 +41,7 @@
   }
 
   test_ppositionalParameter_noDefault() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
 m([@required a]) => null;
@@ -49,7 +49,7 @@
   }
 
   test_requiredParameter() async {
-    assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
 m(@required a) => null;
@@ -57,7 +57,7 @@
   }
 
   test_valid() async {
-    assertNoErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
 m1() => null;
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index a0b3585..0be860c 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -8,7 +8,14 @@
 import 'can_be_null_after_null_aware_test.dart' as can_be_null_after_null_aware;
 import 'deprecated_member_use_test.dart' as deprecated_member_use;
 import 'division_optimization_test.dart' as division_optimization;
+import 'invalid_assignment_test.dart' as invalid_assignment;
 import 'invalid_required_param_test.dart' as invalid_required_param;
+import 'unnecessary_cast_test.dart' as unnecessary_cast;
+import 'unused_field_test.dart' as unused_field;
+import 'unused_import_test.dart' as unused_import;
+import 'unused_label_test.dart' as unused_label;
+import 'unused_shown_name_test.dart' as unused_shown_name;
+import 'use_of_void_result_test.dart' as use_of_void_result;
 
 main() {
   defineReflectiveSuite(() {
@@ -16,6 +23,13 @@
     can_be_null_after_null_aware.main();
     deprecated_member_use.main();
     division_optimization.main();
+    invalid_assignment.main();
     invalid_required_param.main();
+    unnecessary_cast.main();
+    unused_field.main();
+    unused_import.main();
+    unused_label.main();
+    unused_shown_name.main();
+    use_of_void_result.main();
   }, name: 'diagnostics');
 }
diff --git a/pkg/analyzer/test/src/diagnostics/unnecessary_cast_test.dart b/pkg/analyzer/test/src/diagnostics/unnecessary_cast_test.dart
new file mode 100644
index 0000000..507e656
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unnecessary_cast_test.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnnecessaryCastTest);
+    defineReflectiveTests(UnnecessaryCastTest_Driver);
+  });
+}
+
+@reflectiveTest
+class UnnecessaryCastTest extends ResolverTestCase {
+  test_conditionalExpression() async {
+    await assertNoErrorsInCode(r'''
+abstract class I {}
+class A implements I {}
+class B implements I {}
+I m(A a, B b) {
+  return a == null ? b as I : a as I;
+}
+''');
+  }
+
+  test_dynamic_type() async {
+    await assertNoErrorsInCode(r'''
+m(v) {
+  var b = v as Object;
+}
+''');
+  }
+
+  test_function() async {
+    await assertNoErrorsInCode(r'''
+void main() {
+  Function(Null) f = (String x) => x;
+  (f as Function(int))(3); 
+}
+''');
+  }
+
+  test_function2() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+
+class B<T extends A> {
+  void foo() {
+    T Function(T) f;
+    A Function(A) g;
+    g = f as A Function(A);
+  }
+}
+''');
+  }
+
+  test_generics() async {
+    // dartbug.com/18953
+    await assertNoErrorsInCode(r'''
+import 'dart:async';
+Future<int> f() => new Future.value(0);
+void g(bool c) {
+  (c ? f(): new Future.value(0) as Future<int>).then((int value) {});
+}
+''');
+  }
+
+  test_parameter_A() async {
+    // dartbug.com/13855, dartbug.com/13732
+    await assertNoErrorsInCode(r'''
+class A{
+  a() {}
+}
+class B<E> {
+  E e;
+  m() {
+    (e as A).a();
+  }
+}
+''');
+  }
+
+  test_type_dynamic() async {
+    await assertNoErrorsInCode(r'''
+m(v) {
+  var b = Object as dynamic;
+}
+''');
+  }
+
+  test_type_supertype() async {
+    await assertErrorsInCode(r'''
+m(int i) {
+  var b = i as Object;
+}
+''', [HintCode.UNNECESSARY_CAST]);
+  }
+
+  test_type_type() async {
+    await assertErrorsInCode(r'''
+m(num i) {
+  var b = i as num;
+}
+''', [HintCode.UNNECESSARY_CAST]);
+  }
+}
+
+@reflectiveTest
+class UnnecessaryCastTest_Driver extends UnnecessaryCastTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+
+  @override
+  test_generics() async {
+    // dartbug.com/18953
+    assertErrorsInCode(r'''
+import 'dart:async';
+Future<int> f() => new Future.value(0);
+void g(bool c) {
+  (c ? f(): new Future.value(0) as Future<int>).then((int value) {});
+}
+''', [HintCode.UNNECESSARY_CAST]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_field_test.dart b/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
new file mode 100644
index 0000000..6a60a1b
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
@@ -0,0 +1,198 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnusedFieldTest);
+    defineReflectiveTests(UnusedFieldTest_Driver);
+  });
+}
+
+@reflectiveTest
+class UnusedFieldTest extends ResolverTestCase {
+  @override
+  bool get enableUnusedElement => true;
+
+  test_unusedField_isUsed_argument() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f = 0;
+  main() {
+    print(++_f);
+  }
+}
+print(x) {}
+''');
+  }
+
+  test_unusedField_isUsed_reference_implicitThis() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f;
+  main() {
+    print(_f);
+  }
+}
+print(x) {}
+''');
+  }
+
+  test_unusedField_isUsed_reference_implicitThis_expressionFunctionBody() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f;
+  m() => _f;
+}
+''');
+  }
+
+  test_unusedField_isUsed_reference_implicitThis_subclass() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f;
+  main() {
+    print(_f);
+  }
+}
+class B extends A {
+  int _f;
+}
+print(x) {}
+''');
+  }
+
+  test_unusedField_isUsed_reference_qualified_propagatedElement() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f;
+}
+main() {
+  var a = new A();
+  print(a._f);
+}
+print(x) {}
+''');
+  }
+
+  test_unusedField_isUsed_reference_qualified_staticElement() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f;
+}
+main() {
+  A a = new A();
+  print(a._f);
+}
+print(x) {}
+''');
+  }
+
+  test_unusedField_isUsed_reference_qualified_unresolved() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _f;
+}
+main(a) {
+  print(a._f);
+}
+print(x) {}
+''');
+  }
+
+  test_unusedField_notUsed_compoundAssign() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f;
+  main() {
+    _f += 2;
+  }
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+
+  test_unusedField_notUsed_constructorFieldInitializers() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f;
+  A() : _f = 0;
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+
+  test_unusedField_notUsed_fieldFormalParameter() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f;
+  A(this._f);
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+
+  test_unusedField_notUsed_noReference() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f;
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+
+  test_unusedField_notUsed_nullAssign() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  var _f;
+  m() {
+    _f ??= doSomething();
+  }
+}
+doSomething() => 0;
+''');
+  }
+
+  test_unusedField_notUsed_postfixExpr() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f = 0;
+  main() {
+    _f++;
+  }
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+
+  test_unusedField_notUsed_prefixExpr() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f = 0;
+  main() {
+    ++_f;
+  }
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+
+  test_unusedField_notUsed_simpleAssignment() async {
+    await assertErrorsInCode(r'''
+class A {
+  int _f;
+  m() {
+    _f = 1;
+  }
+}
+main(A a) {
+  a._f = 2;
+}
+''', [HintCode.UNUSED_FIELD]);
+  }
+}
+
+@reflectiveTest
+class UnusedFieldTest_Driver extends UnusedFieldTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_import_test.dart b/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
new file mode 100644
index 0000000..e930e3e
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
@@ -0,0 +1,321 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnusedImportTest);
+    defineReflectiveTests(UnusedImportTest_Driver);
+  });
+}
+
+@reflectiveTest
+class UnusedImportTest extends ResolverTestCase {
+  test_annotationOnDirective() async {
+    Source source = addSource(r'''
+library L;
+@A()
+import 'lib1.dart';
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {
+  const A() {}
+}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source);
+    verify([source, source2]);
+  }
+
+  test_as() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' as one;
+one.A a;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_IMPORT]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+
+  test_as_equalPrefixes_referenced() async {
+    // 18818
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' as one;
+import 'lib2.dart' as one;
+one.A a;
+one.B b;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+''');
+    Source source3 = addNamedSource("/lib2.dart", r'''
+library lib2;
+class B {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    await computeAnalysisResult(source3);
+    assertErrors(source);
+    assertNoErrors(source2);
+    assertNoErrors(source3);
+    verify([source, source2, source3]);
+  }
+
+  @failingTest
+  test_as_equalPrefixes_unreferenced() async {
+    // See todo at ImportsVerifier.prefixElementMap.
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' as one;
+import 'lib2.dart' as one;
+one.A a;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+''');
+    Source source3 = addNamedSource("/lib2.dart", r'''
+library lib2;
+class B {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    await computeAnalysisResult(source3);
+    assertErrors(source, [HintCode.UNUSED_IMPORT]);
+    assertNoErrors(source2);
+    assertNoErrors(source3);
+    verify([source, source2, source3]);
+  }
+
+  test_core_library() async {
+    Source source = addSource(r'''
+library L;
+import 'dart:core';
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_export() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+Two two;
+''');
+    addNamedSource("/lib1.dart", r'''
+library lib1;
+export 'lib2.dart';
+class One {}
+''');
+    addNamedSource("/lib2.dart", r'''
+library lib2;
+class Two {}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_export2() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+Three three;
+''');
+    addNamedSource("/lib1.dart", r'''
+library lib1;
+export 'lib2.dart';
+class One {}
+''');
+    addNamedSource("/lib2.dart", r'''
+library lib2;
+export 'lib3.dart';
+class Two {}
+''');
+    addNamedSource("/lib3.dart", r'''
+library lib3;
+class Three {}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_export_infiniteLoop() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+Two two;
+''');
+    addNamedSource("/lib1.dart", r'''
+library lib1;
+export 'lib2.dart';
+class One {}
+''');
+    addNamedSource("/lib2.dart", r'''
+library lib2;
+export 'lib3.dart';
+class Two {}
+''');
+    addNamedSource("/lib3.dart", r'''
+library lib3;
+export 'lib2.dart';
+class Three {}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_hide() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' hide A;
+A a;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_IMPORT]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+
+  test_inComment_libraryDirective() async {
+    Source source = addSource(r'''
+/// Use [Future] class.
+library L;
+import 'dart:async';
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+  }
+
+  test_metadata() async {
+    Source source = addSource(r'''
+library L;
+@A(x)
+import 'lib1.dart';
+class A {
+  final int value;
+  const A(this.value);
+}
+''');
+    addNamedSource("/lib1.dart", r'''
+library lib1;
+const x = 0;
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_prefix_topLevelFunction() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' hide topLevelFunction;
+import 'lib1.dart' as one show topLevelFunction;
+class A {
+  static void x() {
+    One o;
+    one.topLevelFunction();
+  }
+}
+''');
+    addNamedSource("/lib1.dart", r'''
+library lib1;
+class One {}
+topLevelFunction() {}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_prefix_topLevelFunction2() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' hide topLevelFunction;
+import 'lib1.dart' as one show topLevelFunction;
+import 'lib1.dart' as two show topLevelFunction;
+class A {
+  static void x() {
+    One o;
+    one.topLevelFunction();
+    two.topLevelFunction();
+  }
+}
+''');
+    addNamedSource("/lib1.dart", r'''
+library lib1;
+class One {}
+topLevelFunction() {}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_show() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' show A;
+import 'lib1.dart' show B;
+A a;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+class B {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_IMPORT]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+
+  test_unusedImport() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+''');
+    Source source2 = addNamedSource("/lib1.dart", '''
+library lib1;
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_IMPORT]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+}
+
+@reflectiveTest
+class UnusedImportTest_Driver extends UnusedImportTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_label_test.dart b/pkg/analyzer/test/src/diagnostics/unused_label_test.dart
new file mode 100644
index 0000000..7609554
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unused_label_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnusedLabelTest);
+    defineReflectiveTests(UnusedLabelTest_Driver);
+  });
+}
+
+@reflectiveTest
+class UnusedLabelTest extends ResolverTestCase {
+  test_unused_inSwitch() async {
+    await assertErrorsInCode(r'''
+f(x) {
+  switch (x) {
+    label: case 0:
+      break;
+    default:
+      break;
+  }
+}
+''', [HintCode.UNUSED_LABEL]);
+  }
+
+  test_unused_onWhile() async {
+    await assertErrorsInCode(r'''
+f(condition()) {
+  label: while (condition()) {
+    break;
+  }
+}
+''', [HintCode.UNUSED_LABEL]);
+  }
+
+  test_used_inSwitch() async {
+    await assertNoErrorsInCode(r'''
+f(x) {
+  switch (x) {
+    label: case 0:
+      break;
+    default:
+      continue label;
+  }
+}
+''');
+  }
+
+  test_used_onWhile() async {
+    await assertNoErrorsInCode(r'''
+f(condition()) {
+  label: while (condition()) {
+    break label;
+  }
+}
+''');
+  }
+}
+
+@reflectiveTest
+class UnusedLabelTest_Driver extends UnusedLabelTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_shown_name_test.dart b/pkg/analyzer/test/src/diagnostics/unused_shown_name_test.dart
new file mode 100644
index 0000000..8fba003
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unused_shown_name_test.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnusedShownNameTest);
+    defineReflectiveTests(UnusedShownNameTest_Driver);
+  });
+}
+
+@reflectiveTest
+class UnusedShownNameTest extends ResolverTestCase {
+  test_unreferenced() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' show A, B;
+A a;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+class B {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_SHOWN_NAME]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+
+  test_unusedShownName_as() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' as p show A, B;
+p.A a;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+class B {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_SHOWN_NAME]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+
+  test_unusedShownName_duplicates() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' show A, B;
+import 'lib1.dart' show C, D;
+A a;
+C c;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+class A {}
+class B {}
+class C {}
+class D {}
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(
+        source, [HintCode.UNUSED_SHOWN_NAME, HintCode.UNUSED_SHOWN_NAME]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+
+  test_unusedShownName_topLevelVariable() async {
+    Source source = addSource(r'''
+library L;
+import 'lib1.dart' show var1, var2;
+import 'lib1.dart' show var3, var4;
+int a = var1;
+int b = var2;
+int c = var3;
+''');
+    Source source2 = addNamedSource("/lib1.dart", r'''
+library lib1;
+const int var1 = 1;
+const int var2 = 2;
+const int var3 = 3;
+const int var4 = 4;
+''');
+    await computeAnalysisResult(source);
+    await computeAnalysisResult(source2);
+    assertErrors(source, [HintCode.UNUSED_SHOWN_NAME]);
+    assertNoErrors(source2);
+    verify([source, source2]);
+  }
+}
+
+@reflectiveTest
+class UnusedShownNameTest_Driver extends UnusedShownNameTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
new file mode 100644
index 0000000..f44a502
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/resolver_test_case.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UseOfVoidResultTest);
+    defineReflectiveTests(UseOfVoidResultTest_Driver);
+  });
+}
+
+@reflectiveTest
+class UseOfVoidResultTest extends ResolverTestCase {
+  test_implicitReturnValue() async {
+    await assertNoErrorsInCode(r'''
+f() {}
+class A {
+  n() {
+    var a = f();
+  }
+}
+''');
+  }
+
+  test_nonVoidReturnValue() async {
+    await assertNoErrorsInCode(r'''
+int f() => 1;
+g() {
+  var a = f();
+}
+''');
+  }
+}
+
+@reflectiveTest
+class UseOfVoidResultTest_Driver extends UseOfVoidResultTest {
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 9267132..69d2215 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -451,6 +451,36 @@
 ''');
   }
 
+  test_class_constructor_field_formal_functionTyped_noReturnType() async {
+    var library = await checkLibrary(r'''
+class C {
+  var x;
+  C(this.x(double b));
+}
+''');
+    checkElementText(library, r'''
+class C {
+  dynamic x;
+  C((double) → dynamic this.x);
+}
+''');
+  }
+
+  test_class_constructor_field_formal_functionTyped_withReturnType() async {
+    var library = await checkLibrary(r'''
+class C {
+  var x;
+  C(int this.x(double b));
+}
+''');
+    checkElementText(library, r'''
+class C {
+  dynamic x;
+  C((double) → int this.x);
+}
+''');
+  }
+
   test_class_constructor_field_formal_multiple_matching_fields() async {
     // This is a compile-time error but it should still analyze consistently.
     var library = await checkLibrary('class C { C(this.x); int x; String x; }',
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 5554649..71fd7cd 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -100,15 +100,14 @@
       List<String> strings: const <String>[],
       List<_EntityRefValidator> referenceValidators:
           const <_EntityRefValidator>[],
-      bool forTypeInferenceOnly: false,
-      bool enableSetLiterals: IsEnabledByDefault.set_literals}) {
+      bool forTypeInferenceOnly: false}) {
     if (forTypeInferenceOnly && !containsNonConstExprs) {
       expect(constExpr, isNull);
       return;
     }
     expect(constExpr, isNotNull);
     expect(constExpr.sourceRepresentation,
-        _normalizeTokenString(sourceRepresentation, enableSetLiterals));
+        _normalizeTokenString(sourceRepresentation));
     expect(constExpr.isValidConst, isValidConst);
     expect(constExpr.operations, operators);
     expect(constExpr.ints, ints);
@@ -121,29 +120,6 @@
     }
   }
 
-  String _normalizeTokenString(String tokenString, bool enableSetLiterals) {
-    // Note: to normalize the token string it's not sufficient to tokenize it
-    // and then pass the tokens to `tokensToString`; we also need to parse it
-    // because parsing modifies the token stream (splitting up `[]`, `>>`, and
-    // `>>>` tokens when circumstances warrant).
-    //
-    // We wrap the expression in "f() async => ...;" to ensure that the await
-    // keyword is properly parsed.
-    var sourceText = 'f() async => $tokenString;';
-    var errorListener = AnalysisErrorListener.NULL_LISTENER;
-    var reader = new CharSequenceReader(sourceText);
-    var stringSource = new StringSource(sourceText, null);
-    var scanner = new Scanner(stringSource, reader, errorListener);
-    var startToken = scanner.tokenize();
-    var parser = new Parser(stringSource, errorListener)
-      ..enableSetLiterals = enableSetLiterals;
-    var compilationUnit = parser.parseCompilationUnit(startToken);
-    var f = compilationUnit.declarations[0] as FunctionDeclaration;
-    var body = f.functionExpression.body as ExpressionFunctionBody;
-    var expression = body.expression;
-    return tokensToString(expression.beginToken, expression.endToken);
-  }
-
   /**
    * Check that [annotations] contains a single entry which is a reference to
    * a top level variable called `a` in the current library.
@@ -824,11 +800,8 @@
    * with the given [variableName].
    */
   UnlinkedVariable serializeVariableText(String text,
-      {String variableName: 'v',
-      bool allowErrors: false,
-      bool enableSetLiterals: IsEnabledByDefault.set_literals}) {
-    serializeLibraryText(text,
-        allowErrors: allowErrors, enableSetLiterals: enableSetLiterals);
+      {String variableName: 'v', bool allowErrors: false}) {
+    serializeLibraryText(text, allowErrors: allowErrors);
     return findVariable(variableName, failIfAbsent: true);
   }
 
@@ -2968,46 +2941,48 @@
   }
 
   test_constExpr_makeTypedSet() {
-    UnlinkedVariable variable = serializeVariableText(
-        'const v = const <int>{11, 22, 33};',
-        enableSetLiterals: true);
+    experimentStatus = ExperimentStatus(set_literals: true);
+    UnlinkedVariable variable =
+        serializeVariableText('const v = const <int>{11, 22, 33};');
     assertUnlinkedConst(
-        variable.initializer.bodyExpr, 'const <int>{11, 22, 33}',
-        operators: [
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.makeTypedSet
-        ],
-        ints: [11, 22, 33, 3],
-        referenceValidators: [
-          (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
-              expectedKind: ReferenceKind.classOrEnum)
-        ],
-        enableSetLiterals: true);
+      variable.initializer.bodyExpr,
+      'const <int>{11, 22, 33}',
+      operators: [
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.makeTypedSet
+      ],
+      ints: [11, 22, 33, 3],
+      referenceValidators: [
+        (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+            expectedKind: ReferenceKind.classOrEnum)
+      ],
+    );
   }
 
   test_constExpr_makeTypedSet_dynamic() {
-    UnlinkedVariable variable = serializeVariableText(
-        'const v = const <dynamic>{11, 22, 33};',
-        enableSetLiterals: true);
+    experimentStatus = ExperimentStatus(set_literals: true);
+    UnlinkedVariable variable =
+        serializeVariableText('const v = const <dynamic>{11, 22, 33};');
     assertUnlinkedConst(
-        variable.initializer.bodyExpr, 'const <dynamic>{11, 22, 33}',
-        operators: [
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.makeTypedSet
-        ],
-        ints: [11, 22, 33, 3],
-        referenceValidators: [(EntityRef r) => checkDynamicTypeRef(r)],
-        enableSetLiterals: true);
+      variable.initializer.bodyExpr,
+      'const <dynamic>{11, 22, 33}',
+      operators: [
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.makeTypedSet
+      ],
+      ints: [11, 22, 33, 3],
+      referenceValidators: [(EntityRef r) => checkDynamicTypeRef(r)],
+    );
   }
 
   test_constExpr_makeTypedSet_functionType() {
-    UnlinkedVariable variable = serializeVariableText(
-        'final v = <void Function(int)>{};',
-        enableSetLiterals: true);
+    experimentStatus = ExperimentStatus(set_literals: true);
+    UnlinkedVariable variable =
+        serializeVariableText('final v = <void Function(int)>{};');
     assertUnlinkedConst(variable.initializer.bodyExpr, '<void Function(int)>{}',
         operators: [UnlinkedExprOperation.makeTypedSet],
         ints: [
@@ -3034,9 +3009,9 @@
   }
 
   test_constExpr_makeTypedSet_functionType_withTypeParameters() {
+    experimentStatus = ExperimentStatus(set_literals: true);
     UnlinkedVariable variable = serializeVariableText(
-        'final v = <void Function<T>(Function<Q>(T, Q))>{};',
-        enableSetLiterals: true);
+        'final v = <void Function<T>(Function<Q>(T, Q))>{};');
     assertUnlinkedConst(variable.initializer.bodyExpr,
         '<void Function<T>(Function<Q>(T, Q))>{}',
         operators: [UnlinkedExprOperation.makeTypedSet],
@@ -3123,18 +3098,20 @@
   }
 
   test_constExpr_makeUntypedSet() {
-    UnlinkedVariable variable = serializeVariableText(
-        'const v = const {11, 22, 33};',
-        enableSetLiterals: true);
-    assertUnlinkedConst(variable.initializer.bodyExpr, 'const {11, 22, 33}',
-        operators: [
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.pushInt,
-          UnlinkedExprOperation.makeUntypedSet
-        ],
-        ints: [11, 22, 33, 3],
-        enableSetLiterals: true);
+    experimentStatus = ExperimentStatus(set_literals: true);
+    UnlinkedVariable variable =
+        serializeVariableText('const v = const {11, 22, 33};');
+    assertUnlinkedConst(
+      variable.initializer.bodyExpr,
+      'const {11, 22, 33}',
+      operators: [
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.pushInt,
+        UnlinkedExprOperation.makeUntypedSet
+      ],
+      ints: [11, 22, 33, 3],
+    );
   }
 
   test_constExpr_parenthesized() {
@@ -7418,9 +7395,9 @@
   }
 
   test_expr_makeTypedSet() {
-    UnlinkedVariable variable = serializeVariableText(
-        'var v = <int>{11, 22, 33};',
-        enableSetLiterals: true);
+    experimentStatus = ExperimentStatus(set_literals: true);
+    UnlinkedVariable variable =
+        serializeVariableText('var v = <int>{11, 22, 33};');
     assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{11, 22, 33}',
         operators: [UnlinkedExprOperation.makeTypedSet],
         ints: [0],
@@ -7428,8 +7405,7 @@
           (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
               expectedKind: ReferenceKind.classOrEnum)
         ],
-        forTypeInferenceOnly: true,
-        enableSetLiterals: true);
+        forTypeInferenceOnly: true);
   }
 
   test_expr_makeUntypedList() {
@@ -7465,8 +7441,8 @@
   }
 
   test_expr_makeUntypedSet() {
-    UnlinkedVariable variable =
-        serializeVariableText('var v = {11, 22, 33};', enableSetLiterals: true);
+    experimentStatus = ExperimentStatus(set_literals: true);
+    UnlinkedVariable variable = serializeVariableText('var v = {11, 22, 33};');
     assertUnlinkedConst(variable.initializer.bodyExpr, '{11, 22, 33}',
         operators: [
           UnlinkedExprOperation.pushInt,
@@ -7475,8 +7451,7 @@
           UnlinkedExprOperation.makeUntypedSet
         ],
         ints: [11, 22, 33, 3],
-        forTypeInferenceOnly: true,
-        enableSetLiterals: true);
+        forTypeInferenceOnly: true);
   }
 
   test_expr_super() {
@@ -10784,6 +10759,30 @@
         ],
         forTypeInferenceOnly: true);
   }
+
+  String _normalizeTokenString(String tokenString) {
+    // Note: to normalize the token string it's not sufficient to tokenize it
+    // and then pass the tokens to `tokensToString`; we also need to parse it
+    // because parsing modifies the token stream (splitting up `[]`, `>>`, and
+    // `>>>` tokens when circumstances warrant).
+    //
+    // We wrap the expression in "f() async => ...;" to ensure that the await
+    // keyword is properly parsed.
+    var sourceText = 'f() async => $tokenString;';
+    var errorListener = AnalysisErrorListener.NULL_LISTENER;
+    var reader = new CharSequenceReader(sourceText);
+    var stringSource = new StringSource(sourceText, null);
+    var scanner = new Scanner(stringSource, reader, errorListener);
+    var startToken = scanner.tokenize();
+    var parser = new Parser(stringSource, errorListener)
+      ..enableSetLiterals = experimentStatus.set_literals
+      ..enableNonNullable = experimentStatus.non_nullable;
+    var compilationUnit = parser.parseCompilationUnit(startToken);
+    var f = compilationUnit.declarations[0] as FunctionDeclaration;
+    var body = f.functionExpression.body as ExpressionFunctionBody;
+    var expression = body.expression;
+    return tokensToString(expression.beginToken, expression.endToken);
+  }
 }
 
 /**
diff --git a/pkg/analyzer/test/src/summary/test_strategies.dart b/pkg/analyzer/test/src/summary/test_strategies.dart
index 5cab182..fe525e0 100644
--- a/pkg/analyzer/test/src/summary/test_strategies.dart
+++ b/pkg/analyzer/test/src/summary/test_strategies.dart
@@ -22,7 +22,6 @@
 import 'package:analyzer/src/summary/prelink.dart';
 import 'package:analyzer/src/summary/summarize_ast.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/task/api/dart.dart';
 import 'package:analyzer/src/task/api/general.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:path/path.dart' show posix;
@@ -36,15 +35,19 @@
   return posix.toUri(absolutePath).toString();
 }
 
-CompilationUnit _parseText(String text,
-    {bool enableSetLiterals: IsEnabledByDefault.set_literals}) {
+CompilationUnit _parseText(
+  String text, {
+  ExperimentStatus experimentStatus,
+}) {
+  experimentStatus ??= ExperimentStatus();
   CharSequenceReader reader = new CharSequenceReader(text);
   Scanner scanner =
       new Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER);
   Token token = scanner.tokenize();
   Parser parser =
       new Parser(NonExistingSource.unknown, AnalysisErrorListener.NULL_LISTENER)
-        ..enableSetLiterals = enableSetLiterals;
+        ..enableSetLiterals = experimentStatus.set_literals
+        ..enableNonNullable = experimentStatus.non_nullable;
   CompilationUnit unit = parser.parseCompilationUnit(token);
   unit.lineInfo = new LineInfo(scanner.lineStarts);
   return unit;
@@ -91,8 +94,8 @@
 /// The tests themselves can then be provided via mixin, allowing summaries to
 /// be tested in a variety of ways.
 abstract class ResynthesizeTestStrategy {
-  //Future<LibraryElementImpl> checkLibrary(String text,
-  //    {bool allowErrors: false, bool dumpSummaries: false});
+  /// The set of [ExperimentStatus] enabled in this test.
+  ExperimentStatus experimentStatus;
 
   void set allowMissingFiles(bool value);
 
@@ -124,6 +127,9 @@
 /// generation using the old two-phase API.
 class ResynthesizeTestStrategyTwoPhase extends AbstractResynthesizeTest
     implements ResynthesizeTestStrategy {
+  @override
+  ExperimentStatus experimentStatus = ExperimentStatus();
+
   final Set<Source> serializedSources = new Set<Source>();
 
   final Map<String, UnlinkedUnitBuilder> uriToUnit =
@@ -206,7 +212,10 @@
         }
         return null;
       }
-      CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
+
+      String contents = context.getContents(source).data;
+      CompilationUnit unit = _parseText(contents);
+
       UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
       bundleAssembler.addUnlinkedUnit(source, unlinkedUnit);
       return unlinkedUnit;
@@ -285,6 +294,9 @@
 /// The tests themselves can then be provided via mixin, allowing summaries to
 /// be tested in a variety of ways.
 abstract class SummaryBaseTestStrategy {
+  /// The set of [ExperimentStatus] enabled in this test.
+  ExperimentStatus experimentStatus;
+
   /// Add the given package bundle as a dependency so that it may be referenced
   /// by the files under test.
   void addBundle(String path, PackageBundle bundle);
@@ -332,9 +344,7 @@
 
   /// Serialize the given library [text], then deserialize it and store its
   /// summary in [lib].
-  void serializeLibraryText(String text,
-      {bool allowErrors: false,
-      bool enableSetLiterals: IsEnabledByDefault.set_literals});
+  void serializeLibraryText(String text, {bool allowErrors: false});
 }
 
 /// Implementation of [SummaryBlackBoxTestStrategy] that drives summary
@@ -346,11 +356,8 @@
   bool get skipFullyLinkedData => true;
 
   @override
-  void serializeLibraryText(String text,
-      {bool allowErrors: false,
-      bool enableSetLiterals: IsEnabledByDefault.set_literals}) {
-    super.serializeLibraryText(text,
-        allowErrors: allowErrors, enableSetLiterals: enableSetLiterals);
+  void serializeLibraryText(String text, {bool allowErrors: false}) {
+    super.serializeLibraryText(text, allowErrors: allowErrors);
 
     UnlinkedUnit getPart(String absoluteUri) {
       return _linkerInputs.getUnit(absoluteUri);
@@ -507,6 +514,9 @@
   _FilesToLink<UnlinkedUnitBuilder> _filesToLink =
       new _FilesToLink<UnlinkedUnitBuilder>();
 
+  @override
+  ExperimentStatus experimentStatus = ExperimentStatus();
+
   _LinkerInputs _linkerInputs;
 
   bool get _allowMissingFiles;
@@ -541,20 +551,16 @@
     return assembler.assemble();
   }
 
-  UnlinkedUnitBuilder createUnlinkedSummary(Uri uri, String text,
-          {bool enableSetLiterals: IsEnabledByDefault.set_literals}) =>
+  UnlinkedUnitBuilder createUnlinkedSummary(Uri uri, String text) =>
       serializeAstUnlinked(
-          _parseText(text, enableSetLiterals: enableSetLiterals));
+          _parseText(text, experimentStatus: experimentStatus));
 
   _LinkerInputs _createLinkerInputs(String text,
-      {String path: '/test.dart',
-      String uri,
-      bool enableSetLiterals: IsEnabledByDefault.set_literals}) {
+      {String path: '/test.dart', String uri}) {
     uri ??= absUri(path);
     Uri testDartUri = Uri.parse(uri);
-    UnlinkedUnitBuilder unlinkedDefiningUnit = createUnlinkedSummary(
-        testDartUri, text,
-        enableSetLiterals: enableSetLiterals);
+    UnlinkedUnitBuilder unlinkedDefiningUnit =
+        createUnlinkedSummary(testDartUri, text);
     _filesToLink.uriToUnit[testDartUri.toString()] = unlinkedDefiningUnit;
     _LinkerInputs linkerInputs = new _LinkerInputs(
         _allowMissingFiles,
@@ -573,7 +579,7 @@
 /// generation using the old two-phase API.
 ///
 /// Not intended to be used directly; instead use a derived class that either
-/// exercises the full summary algorithmm or just pre-linking.
+/// exercises the full summary algorithm or just pre-linking.
 abstract class _SummaryBlackBoxTestStrategyTwoPhase
     extends _SummaryBaseTestStrategyTwoPhase
     implements SummaryBlackBoxTestStrategy {
@@ -595,12 +601,9 @@
   bool get containsNonConstExprs => true;
 
   @override
-  void serializeLibraryText(String text,
-      {bool allowErrors: false,
-      bool enableSetLiterals: IsEnabledByDefault.set_literals}) {
+  void serializeLibraryText(String text, {bool allowErrors: false}) {
     Map<String, UnlinkedUnitBuilder> uriToUnit = this._filesToLink.uriToUnit;
-    _linkerInputs =
-        _createLinkerInputs(text, enableSetLiterals: enableSetLiterals);
+    _linkerInputs = _createLinkerInputs(text);
     linked = link(
         _linkerInputs.linkedLibraries,
         _linkerInputs.getDependency,
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 645c950..cd1e370 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -69,8 +69,8 @@
         new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
       ['x']
     ]);
-    var invalid_assignment =
-        new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
+    var invalid_assignment = new AnalysisError(
+        new TestSource(), 0, 1, StaticTypeWarningCode.INVALID_ASSIGNMENT, [
       ['x'],
       ['y']
     ]);
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 2991634..51c6016 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -6,6 +6,7 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -17,9 +18,75 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(InferredTypeTest);
     defineReflectiveTests(InferredTypeTest_Driver);
+    defineReflectiveTests(InferredTypeTest_SetLiterals);
   });
 }
 
+@reflectiveTest
+class InferredTypeTest extends AbstractStrongTest with InferredTypeMixin {
+  @override
+  bool get mayCheckTypesOfLocals => true;
+
+  @override
+  Future<CompilationUnitElement> checkFileElement(String content) async {
+    CompilationUnit unit = await checkFile(content);
+    return unit.declaredElement;
+  }
+
+  @override
+  @failingTest
+  test_circularReference_viaClosures() {
+    return super.test_circularReference_viaClosures();
+  }
+
+  @override
+  @failingTest
+  test_circularReference_viaClosures_initializerTypes() {
+    return super.test_circularReference_viaClosures_initializerTypes();
+  }
+
+  @override
+  @failingTest
+  test_instantiateToBounds_typeName_error1() {
+    // Test doesn't work with the old task model
+    return super.test_instantiateToBounds_typeName_error1();
+  }
+
+  @override
+  @failingTest
+  test_instantiateToBounds_typeName_error2() {
+    // Test doesn't work with the old task model
+    return super.test_instantiateToBounds_typeName_error2();
+  }
+
+  @override
+  @failingTest
+  test_instantiateToBounds_typeName_error3() {
+    // Test doesn't work with the old task model
+    return super.test_instantiateToBounds_typeName_error3();
+  }
+
+  @override
+  @failingTest
+  test_instantiateToBounds_typeName_OK_hasBound_definedAfter() {
+    return super.test_instantiateToBounds_typeName_OK_hasBound_definedAfter();
+  }
+
+  @override
+  @failingTest
+  test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1() {
+    return super
+        .test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1();
+  }
+
+  @failingTest
+  @override
+  test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1() {
+    return super
+        .test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1();
+  }
+}
+
 mixin InferredTypeMixin {
   /// Extra top-level errors if needed due to being analyze multiple times.
   bool get hasExtraTaskModelPass => true;
@@ -1504,7 +1571,7 @@
 Iterable<Map<int, int>> bar() sync* {
   yield /*info:INFERRED_TYPE_LITERAL*/{};
   yield /*error:YIELD_OF_INVALID_TYPE*/new List();
-  yield* {};
+  yield* /*error:YIELD_OF_INVALID_TYPE*/{};
   yield* /*info:INFERRED_TYPE_ALLOCATION*/new List();
 }
 ''');
@@ -2229,8 +2296,8 @@
   test_infer_assignToProperty_custom() async {
     await checkFileElement(r'''
 class A {
-  int operator +(other) => 1;
-  double operator -(other) => 2.0;
+  A operator +(other) => this;
+  A operator -(other) => this;
 }
 class B {
   A a;
@@ -4391,71 +4458,6 @@
 }
 
 @reflectiveTest
-class InferredTypeTest extends AbstractStrongTest with InferredTypeMixin {
-  @override
-  bool get mayCheckTypesOfLocals => true;
-
-  @override
-  Future<CompilationUnitElement> checkFileElement(String content) async {
-    CompilationUnit unit = await checkFile(content);
-    return unit.declaredElement;
-  }
-
-  @override
-  @failingTest
-  test_circularReference_viaClosures() {
-    return super.test_circularReference_viaClosures();
-  }
-
-  @override
-  @failingTest
-  test_circularReference_viaClosures_initializerTypes() {
-    return super.test_circularReference_viaClosures_initializerTypes();
-  }
-
-  @override
-  @failingTest
-  test_instantiateToBounds_typeName_error1() {
-    // Test doesn't work with the old task model
-    return super.test_instantiateToBounds_typeName_error1();
-  }
-
-  @override
-  @failingTest
-  test_instantiateToBounds_typeName_error2() {
-    // Test doesn't work with the old task model
-    return super.test_instantiateToBounds_typeName_error2();
-  }
-
-  @override
-  @failingTest
-  test_instantiateToBounds_typeName_error3() {
-    // Test doesn't work with the old task model
-    return super.test_instantiateToBounds_typeName_error3();
-  }
-
-  @override
-  @failingTest
-  test_instantiateToBounds_typeName_OK_hasBound_definedAfter() {
-    return super.test_instantiateToBounds_typeName_OK_hasBound_definedAfter();
-  }
-
-  @override
-  @failingTest
-  test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1() {
-    return super
-        .test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1();
-  }
-
-  @failingTest
-  @override
-  test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1() {
-    return super
-        .test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1();
-  }
-}
-
-@reflectiveTest
 class InferredTypeTest_Driver extends AbstractStrongTest
     with InferredTypeMixin {
   @override
@@ -4487,3 +4489,66 @@
         .test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1();
   }
 }
+
+@reflectiveTest
+class InferredTypeTest_SetLiterals extends AbstractStrongTest
+    with InferredTypeMixin {
+  @override
+  List<String> get enabledExperiments => [EnableString.set_literals];
+
+  @override
+  bool get enableNewAnalysisDriver => true;
+
+  @override
+  bool get hasExtraTaskModelPass => false;
+
+  @override
+  bool get mayCheckTypesOfLocals => true;
+
+  @override
+  Future<CompilationUnitElement> checkFileElement(String content) async {
+    CompilationUnit unit = await checkFile(content);
+    return unit.declaredElement;
+  }
+
+  @override
+  test_downwardsInferenceYieldYieldStar() async {
+    // The fifth to last case is inferred differently with set_literals enabled,
+    // and no longer an error compared to the base implementation.
+    await checkFileElement('''
+import 'dart:async';
+
+abstract class MyStream<T> extends Stream<T> {
+  factory MyStream() => null;
+}
+
+Stream<List<int>> foo() async* {
+  yield /*info:INFERRED_TYPE_LITERAL*/[];
+  yield /*error:YIELD_OF_INVALID_TYPE*/new MyStream();
+  yield* /*error:YIELD_OF_INVALID_TYPE*/[];
+  yield* /*info:INFERRED_TYPE_ALLOCATION*/new MyStream();
+}
+
+Iterable<Map<int, int>> bar() sync* {
+  yield /*info:INFERRED_TYPE_LITERAL*/{};
+  yield /*error:YIELD_OF_INVALID_TYPE*/new List();
+  yield* {};
+  yield* /*info:INFERRED_TYPE_ALLOCATION*/new List();
+}
+''');
+  }
+
+  @failingTest
+  @override
+  test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1() {
+    return super
+        .test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1();
+  }
+
+  @failingTest
+  @override
+  test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1() {
+    return super
+        .test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1();
+  }
+}
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index c9c3fcf..521f759 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -245,6 +245,8 @@
 
   bool get enableNewAnalysisDriver => false;
 
+  List<String> get enabledExperiments => [];
+
   /// Adds a file to check. The file should contain:
   ///
   ///   * all expected failures are listed in the source code using comments
@@ -286,6 +288,7 @@
     analysisOptions.strongModeHints = true;
     analysisOptions.implicitCasts = implicitCasts;
     analysisOptions.implicitDynamic = implicitDynamic;
+    analysisOptions.enabledExperiments = enabledExperiments;
 
     var mockSdk = new MockSdk(resourceProvider: resourceProvider);
     mockSdk.context.analysisOptions = analysisOptions;
diff --git a/pkg/analyzer/test/src/workspace/basic_test.dart b/pkg/analyzer/test/src/workspace/basic_test.dart
index 1abdbc9..6df62db 100644
--- a/pkg/analyzer/test/src/workspace/basic_test.dart
+++ b/pkg/analyzer/test/src/workspace/basic_test.dart
@@ -30,13 +30,40 @@
 
 main() {
   defineReflectiveSuite(() {
-    // TODO(srawlins): Write a BasicWorkspaceTest akin to
-    // PackageBuildWorkspaceTest.
+    defineReflectiveTests(BasicWorkspaceTest);
     defineReflectiveTests(BasicWorkspacePackageTest);
   });
 }
 
 @reflectiveTest
+class BasicWorkspaceTest with ResourceProviderMixin {
+  setUp() {
+    newFolder('/workspace');
+  }
+
+  void test_find_fail_notAbsolute() {
+    expect(
+        () => BasicWorkspace.find(resourceProvider, convertPath('not_absolute'),
+            new MockContextBuilder()),
+        throwsA(TypeMatcher<ArgumentError>()));
+  }
+
+  void test_find_directory() {
+    BasicWorkspace workspace = BasicWorkspace.find(
+        resourceProvider, convertPath('/workspace'), new MockContextBuilder());
+    expect(workspace.root, convertPath('/workspace'));
+  }
+
+  void test_find_file() {
+    BasicWorkspace workspace = BasicWorkspace.find(
+        resourceProvider,
+        convertPath('/workspace/project/lib/lib1.dart'),
+        new MockContextBuilder());
+    expect(workspace.root, convertPath('/workspace/project/lib'));
+  }
+}
+
+@reflectiveTest
 class BasicWorkspacePackageTest with ResourceProviderMixin {
   BasicWorkspace workspace;
 
@@ -47,7 +74,7 @@
     contextBuilder.packagesMapMap[convertPath('/workspace')] = packages;
     contextBuilder.packagesToMapMap[packages] = packageMap;
 
-    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    newFolder('/workspace');
     workspace = BasicWorkspace.find(
         resourceProvider, convertPath('/workspace'), contextBuilder);
   }
diff --git a/pkg/analyzer/test/src/workspace/gn_test.dart b/pkg/analyzer/test/src/workspace/gn_test.dart
index bc75f28..8cd0a5b 100644
--- a/pkg/analyzer/test/src/workspace/gn_test.dart
+++ b/pkg/analyzer/test/src/workspace/gn_test.dart
@@ -182,6 +182,7 @@
     newFile('/ws/.config',
         content: 'FOO=foo\n' + 'FUCHSIA_BUILD_DIR="$buildDir"\n' + 'BAR=bar\n');
     newFile('/ws/out/debug-x87_128/dartlang/gen/some/code/foo.packages');
+    newFolder('/ws/some/code');
     return GnWorkspace.find(resourceProvider, convertPath('/ws/some/code'));
   }
 
diff --git a/pkg/analyzer/test/src/workspace/pub_test.dart b/pkg/analyzer/test/src/workspace/pub_test.dart
new file mode 100644
index 0000000..48d88d6
--- /dev/null
+++ b/pkg/analyzer/test/src/workspace/pub_test.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer/src/workspace/pub.dart';
+import 'package:package_config/packages.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(PubWorkspacePackageTest);
+    defineReflectiveTests(PubWorkspaceTest);
+  });
+}
+
+class MockContextBuilder implements ContextBuilder {
+  Map<String, Packages> packagesMapMap = <String, Packages>{};
+  Map<Packages, Map<String, List<Folder>>> packagesToMapMap =
+      <Packages, Map<String, List<Folder>>>{};
+
+  Map<String, List<Folder>> convertPackagesToMap(Packages packages) =>
+      packagesToMapMap[packages];
+
+  Packages createPackageMap(String rootDirectoryPath) =>
+      packagesMapMap[rootDirectoryPath];
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockPackages implements Packages {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+@reflectiveTest
+class PubWorkspacePackageTest with ResourceProviderMixin {
+  PubWorkspace workspace;
+
+  setUp() {
+    final contextBuilder = new MockContextBuilder();
+    final packages = new MockPackages();
+    final packageMap = <String, List<Folder>>{'project': []};
+    contextBuilder.packagesMapMap[convertPath('/workspace')] = packages;
+    contextBuilder.packagesToMapMap[packages] = packageMap;
+
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    workspace = PubWorkspace.find(
+        resourceProvider, convertPath('/workspace'), contextBuilder);
+  }
+
+  void test_findPackageFor_unrelatedFile() {
+    newFile('/workspace/project/lib/file.dart');
+
+    var package = workspace
+        .findPackageFor(convertPath('/workspace2/project/lib/file.dart'));
+    expect(package, isNull);
+  }
+
+  void test_findPackageFor_includedFile() {
+    newFile('/workspace/project/lib/file.dart');
+
+    var package = workspace
+        .findPackageFor(convertPath('/workspace/project/lib/file.dart'));
+    expect(package, isNotNull);
+    expect(package.root, convertPath('/workspace'));
+    expect(package.workspace, equals(workspace));
+  }
+
+  void test_contains_differentWorkspace() {
+    newFile('/workspace2/project/lib/file.dart');
+
+    var package = workspace
+        .findPackageFor(convertPath('/workspace/project/lib/code.dart'));
+    expect(package.contains('/workspace2/project/lib/file.dart'), isFalse);
+  }
+
+  void test_contains_sameWorkspace() {
+    newFile('/workspace/project/lib/file2.dart');
+
+    var package = workspace
+        .findPackageFor(convertPath('/workspace/project/lib/code.dart'));
+    expect(package.contains('/workspace/project/lib/file2.dart'), isTrue);
+    expect(package.contains('/workspace/project/bin/bin.dart'), isTrue);
+    expect(package.contains('/workspace/project/test/test.dart'), isTrue);
+  }
+}
+
+@reflectiveTest
+class PubWorkspaceTest with ResourceProviderMixin {
+  void test_find_fail_notAbsolute() {
+    expect(
+        () => PubWorkspace.find(resourceProvider, convertPath('not_absolute'),
+            new MockContextBuilder()),
+        throwsA(TypeMatcher<ArgumentError>()));
+  }
+
+  void test_find_missingPubspec() {
+    PubWorkspace workspace = PubWorkspace.find(resourceProvider,
+        convertPath('/workspace/lib/lib1.dart'), new MockContextBuilder());
+    expect(workspace, isNull);
+  }
+
+  void test_find_directory() {
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    PubWorkspace workspace = PubWorkspace.find(
+        resourceProvider, convertPath('/workspace'), new MockContextBuilder());
+    expect(workspace.root, convertPath('/workspace'));
+  }
+
+  void test_find_file() {
+    newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
+    PubWorkspace workspace = PubWorkspace.find(resourceProvider,
+        convertPath('/workspace/lib/lib1.dart'), new MockContextBuilder());
+    expect(workspace.root, convertPath('/workspace'));
+  }
+}
diff --git a/pkg/analyzer/test/src/workspace/test_all.dart b/pkg/analyzer/test/src/workspace/test_all.dart
index 351175b..c2e0512 100644
--- a/pkg/analyzer/test/src/workspace/test_all.dart
+++ b/pkg/analyzer/test/src/workspace/test_all.dart
@@ -4,12 +4,14 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'basic_test.dart' as basic_test;
 import 'bazel_test.dart' as bazel_test;
 import 'gn_test.dart' as gn_test;
 import 'package_build_test.dart' as package_build_test;
 
 main() {
   defineReflectiveSuite(() {
+    basic_test.main();
     bazel_test.main();
     gn_test.main();
     package_build_test.main();
diff --git a/pkg/analyzer/lib/src/test_utilities/ast_type_matchers.dart b/pkg/analyzer/test/util/ast_type_matchers.dart
similarity index 100%
rename from pkg/analyzer/lib/src/test_utilities/ast_type_matchers.dart
rename to pkg/analyzer/test/util/ast_type_matchers.dart
diff --git a/pkg/analyzer/lib/src/test_utilities/element_type_matchers.dart b/pkg/analyzer/test/util/element_type_matchers.dart
similarity index 100%
rename from pkg/analyzer/lib/src/test_utilities/element_type_matchers.dart
rename to pkg/analyzer/test/util/element_type_matchers.dart
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
index 6ab809c..0d84b98 100644
--- a/pkg/analyzer_plugin/doc/api.html
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -1004,6 +1004,12 @@
           is only defined if the displayed text should be different than the
           completion.  Otherwise it is omitted.
         </p>
+      </dd><dt class="field"><b>elementUri: String<span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          The URI of the element corresponding to this suggestion. It will be
+          set whenever analysis server is able to compute it.
+        </p>
       </dd><dt class="field"><b>selectionOffset: int</b></dt><dd>
         
         <p>
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index 596aa9e..b7718d7 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -598,6 +598,7 @@
  *   "relevance": int
  *   "completion": String
  *   "displayText": optional String
+ *   "elementUri": optional String
  *   "selectionOffset": int
  *   "selectionLength": int
  *   "isDeprecated": bool
@@ -629,6 +630,8 @@
 
   String _displayText;
 
+  String _elementUri;
+
   int _selectionOffset;
 
   int _selectionLength;
@@ -729,6 +732,20 @@
   }
 
   /**
+   * The URI of the element corresponding to this suggestion. It will be set
+   * whenever analysis server is able to compute it.
+   */
+  String get elementUri => _elementUri;
+
+  /**
+   * The URI of the element corresponding to this suggestion. It will be set
+   * whenever analysis server is able to compute it.
+   */
+  void set elementUri(String value) {
+    this._elementUri = value;
+  }
+
+  /**
    * The offset, relative to the beginning of the completion, of where the
    * selection should be placed after insertion.
    */
@@ -1003,6 +1020,7 @@
       bool isDeprecated,
       bool isPotential,
       {String displayText,
+      String elementUri,
       String docSummary,
       String docComplete,
       String declaringType,
@@ -1021,6 +1039,7 @@
     this.relevance = relevance;
     this.completion = completion;
     this.displayText = displayText;
+    this.elementUri = elementUri;
     this.selectionOffset = selectionOffset;
     this.selectionLength = selectionLength;
     this.isDeprecated = isDeprecated;
@@ -1073,6 +1092,11 @@
         displayText = jsonDecoder.decodeString(
             jsonPath + ".displayText", json["displayText"]);
       }
+      String elementUri;
+      if (json.containsKey("elementUri")) {
+        elementUri = jsonDecoder.decodeString(
+            jsonPath + ".elementUri", json["elementUri"]);
+      }
       int selectionOffset;
       if (json.containsKey("selectionOffset")) {
         selectionOffset = jsonDecoder.decodeInt(
@@ -1178,6 +1202,7 @@
       return new CompletionSuggestion(kind, relevance, completion,
           selectionOffset, selectionLength, isDeprecated, isPotential,
           displayText: displayText,
+          elementUri: elementUri,
           docSummary: docSummary,
           docComplete: docComplete,
           declaringType: declaringType,
@@ -1206,6 +1231,9 @@
     if (displayText != null) {
       result["displayText"] = displayText;
     }
+    if (elementUri != null) {
+      result["elementUri"] = elementUri;
+    }
     result["selectionOffset"] = selectionOffset;
     result["selectionLength"] = selectionLength;
     result["isDeprecated"] = isDeprecated;
@@ -1265,6 +1293,7 @@
           relevance == other.relevance &&
           completion == other.completion &&
           displayText == other.displayText &&
+          elementUri == other.elementUri &&
           selectionOffset == other.selectionOffset &&
           selectionLength == other.selectionLength &&
           isDeprecated == other.isDeprecated &&
@@ -1297,6 +1326,7 @@
     hash = JenkinsSmiHash.combine(hash, relevance.hashCode);
     hash = JenkinsSmiHash.combine(hash, completion.hashCode);
     hash = JenkinsSmiHash.combine(hash, displayText.hashCode);
+    hash = JenkinsSmiHash.combine(hash, elementUri.hashCode);
     hash = JenkinsSmiHash.combine(hash, selectionOffset.hashCode);
     hash = JenkinsSmiHash.combine(hash, selectionLength.hashCode);
     hash = JenkinsSmiHash.combine(hash, isDeprecated.hashCode);
diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
index 820f31e..d95c14d 100644
--- a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
+++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
@@ -134,6 +134,7 @@
  *   "relevance": int
  *   "completion": String
  *   "displayText": optional String
+ *   "elementUri": optional String
  *   "selectionOffset": int
  *   "selectionLength": int
  *   "isDeprecated": bool
@@ -165,6 +166,7 @@
           "isPotential": isBool
         }, optionalFields: {
           "displayText": isString,
+          "elementUri": isString,
           "docSummary": isString,
           "docComplete": isString,
           "declaringType": isString,
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index ed8daca..d12b351 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -206,6 +206,13 @@
           completion.  Otherwise it is omitted.
         </p>
       </field>
+      <field name="elementUri" optional="true">
+        <ref>String</ref>
+        <p>
+          The URI of the element corresponding to this suggestion. It will be
+          set whenever analysis server is able to compute it.
+        </p>
+      </field>
       <field name="selectionOffset">
         <ref>int</ref>
         <p>
diff --git a/pkg/compiler/analysis_options.yaml b/pkg/compiler/analysis_options.yaml
index 3400954..af22f6b 100644
--- a/pkg/compiler/analysis_options.yaml
+++ b/pkg/compiler/analysis_options.yaml
@@ -5,4 +5,8 @@
 analyzer:
   errors:
     todo: ignore
+    # Allow cross-package deprecated calls
+    # TODO(srawlins): clean these up and remove this "ignore."
     deprecated_member_use: ignore
+    # Allow deprecated calls from within the same package
+    deprecated_member_use_from_same_package: ignore
diff --git a/pkg/compiler/lib/compiler.dart b/pkg/compiler/lib/compiler.dart
index 0c79da0..11816ed 100644
--- a/pkg/compiler/lib/compiler.dart
+++ b/pkg/compiler/lib/compiler.dart
@@ -13,57 +13,51 @@
 // Unless explicitly allowed, passing [:null:] for any argument to the
 // methods of library will result in an Error being thrown.
 
-/**
- * Returns a future that completes to the source corresponding to [uri].
- * If an exception occurs, the future completes with this exception.
- *
- * The source can be represented either as a [:List<int>:] of UTF-8 bytes or as
- * a [String].
- *
- * The following text is non-normative:
- *
- * It is recommended to return a UTF-8 encoded list of bytes because the scanner
- * is more efficient in this case. In either case, the data structure is
- * expected to hold a zero element at the last position. If this is not the
- * case, the entire data structure is copied before scanning.
- */
+/// Returns a future that completes to the source corresponding to [uri].
+/// If an exception occurs, the future completes with this exception.
+///
+/// The source can be represented either as a [:List<int>:] of UTF-8 bytes or as
+/// a [String].
+///
+/// The following text is non-normative:
+///
+/// It is recommended to return a UTF-8 encoded list of bytes because the
+/// scanner is more efficient in this case. In either case, the data structure
+/// is expected to hold a zero element at the last position. If this is not the
+/// case, the entire data structure is copied before scanning.
 typedef Future /* <String | List<int>> */ CompilerInputProvider(Uri uri);
 
 /// Deprecated, please use [CompilerInputProvider] instead.
 typedef Future<String> ReadStringFromUri(Uri uri);
 
-/**
- * Returns an [EventSink] that will serve as compiler output for the given
- * component.
- *
- * Components are identified by [name] and [extension]. By convention,
- * the empty string [:"":] will represent the main script
- * (corresponding to the script parameter of [compile]) even if the
- * main script is a library. For libraries that are compiled
- * separately, the library name is used.
- *
- * At least the following extensions can be expected:
- *
- * * "js" for JavaScript output.
- * * "js.map" for source maps.
- * * "dart" for Dart output.
- * * "dart.map" for source maps.
- *
- * As more features are added to the compiler, new names and
- * extensions may be introduced.
- */
+/// Returns an [EventSink] that will serve as compiler output for the given
+/// component.
+///
+/// Components are identified by [name] and [extension]. By convention,
+/// the empty string [:"":] will represent the main script
+/// (corresponding to the script parameter of [compile]) even if the
+/// main script is a library. For libraries that are compiled
+/// separately, the library name is used.
+///
+/// At least the following extensions can be expected:
+///
+/// * "js" for JavaScript output.
+/// * "js.map" for source maps.
+/// * "dart" for Dart output.
+/// * "dart.map" for source maps.
+///
+/// As more features are added to the compiler, new names and
+/// extensions may be introduced.
 typedef EventSink<String> CompilerOutputProvider(String name, String extension);
 
-/**
- * Invoked by the compiler to report diagnostics. If [uri] is
- * [:null:], so are [begin] and [end]. No other arguments may be
- * [:null:]. If [uri] is not [:null:], neither are [begin] and
- * [end]. [uri] indicates the compilation unit from where the
- * diagnostic originates. [begin] and [end] are zero-based character
- * offsets from the beginning of the compilation unit. [message] is the
- * diagnostic message, and [kind] indicates indicates what kind of
- * diagnostic it is.
- */
+/// Invoked by the compiler to report diagnostics. If [uri] is
+/// [:null:], so are [begin] and [end]. No other arguments may be
+/// [:null:]. If [uri] is not [:null:], neither are [begin] and
+/// [end]. [uri] indicates the compilation unit from where the
+/// diagnostic originates. [begin] and [end] are zero-based character
+/// offsets from the beginning of the compilation unit. [message] is the
+/// diagnostic message, and [kind] indicates indicates what kind of
+/// diagnostic it is.
 typedef void DiagnosticHandler(
     Uri uri, int begin, int end, String message, Diagnostic kind);
 
@@ -82,21 +76,19 @@
   CompilationResult(this.compiler, {this.isSuccess: true});
 }
 
-/**
- * Returns a future that completes to a non-null String when [script]
- * has been successfully compiled.
- *
- * The compiler output is obtained by providing an [outputProvider].
- *
- * If the compilation fails, the future's value will be [:null:] and
- * [handler] will have been invoked at least once with [:kind ==
- * Diagnostic.ERROR:] or [:kind == Diagnostic.CRASH:].
- *
- * Deprecated: if no [outputProvider] is given, the future completes
- * to the compiled script. This behavior will be removed in the future
- * as the compiler may create multiple files to support lazy loading
- * of libraries.
- */
+/// Returns a future that completes to a non-null String when [script]
+/// has been successfully compiled.
+///
+/// The compiler output is obtained by providing an [outputProvider].
+///
+/// If the compilation fails, the future's value will be [:null:] and
+/// [handler] will have been invoked at least once with [:kind ==
+/// Diagnostic.ERROR:] or [:kind == Diagnostic.CRASH:].
+///
+/// Deprecated: if no [outputProvider] is given, the future completes
+/// to the compiled script. This behavior will be removed in the future
+/// as the compiler may create multiple files to support lazy loading
+/// of libraries.
 Future<CompilationResult> compile(
     Uri script,
     Uri librariesSpecificationUri,
@@ -128,74 +120,54 @@
   });
 }
 
-/**
- * Kind of diagnostics that the compiler can report.
- */
+/// Kind of diagnostics that the compiler can report.
 class Diagnostic {
-  /**
-   * An error as identified by the "Dart Programming Language
-   * Specification" [http://www.dartlang.org/docs/spec/].
-   *
-   * Note: the compiler may still produce an executable result after
-   * reporting a compilation error. The specification says:
-   *
-   * "A compile-time error must be reported by a Dart compiler before
-   * the erroneous code is executed." and "If a compile-time error
-   * occurs within the code of a running isolate A, A is immediately
-   * suspended."
-   *
-   * This means that the compiler can generate code that when executed
-   * terminates execution.
-   */
+  /// An error as identified by the "Dart Programming Language
+  /// Specification" [http://www.dartlang.org/docs/spec/].
+  ///
+  /// Note: the compiler may still produce an executable result after
+  /// reporting a compilation error. The specification says:
+  ///
+  /// "A compile-time error must be reported by a Dart compiler before
+  /// the erroneous code is executed." and "If a compile-time error
+  /// occurs within the code of a running isolate A, A is immediately
+  /// suspended."
+  ///
+  /// This means that the compiler can generate code that when executed
+  /// terminates execution.
   static const Diagnostic ERROR = const Diagnostic(1, 'error');
 
-  /**
-   * A warning as identified by the "Dart Programming Language
-   * Specification" [http://www.dartlang.org/docs/spec/].
-   */
+  /// A warning as identified by the "Dart Programming Language
+  /// Specification" [http://www.dartlang.org/docs/spec/].
   static const Diagnostic WARNING = const Diagnostic(2, 'warning');
 
-  /**
-   * Any other warning that is not covered by [WARNING].
-   */
+  /// Any other warning that is not covered by [WARNING].
   static const Diagnostic HINT = const Diagnostic(4, 'hint');
 
-  /**
-   * Additional information about the preceding non-info diagnostic from the
-   * compiler.
-   *
-   * For example, consider a duplicated definition. The compiler first emits a
-   * message about the duplicated definition, then emits an info message about
-   * the location of the existing definition.
-   */
+  /// Additional information about the preceding non-info diagnostic from the
+  /// compiler.
+  ///
+  /// For example, consider a duplicated definition. The compiler first emits a
+  /// message about the duplicated definition, then emits an info message about
+  /// the location of the existing definition.
   static const Diagnostic INFO = const Diagnostic(8, 'info');
 
-  /**
-   * Informational messages that shouldn't be printed unless
-   * explicitly requested by the user of a compiler.
-   */
+  /// Informational messages that shouldn't be printed unless
+  /// explicitly requested by the user of a compiler.
   static const Diagnostic VERBOSE_INFO = const Diagnostic(16, 'verbose info');
 
-  /**
-   * An internal error in the compiler.
-   */
+  /// An internal error in the compiler.
   static const Diagnostic CRASH = const Diagnostic(32, 'crash');
 
-  /**
-   * An [int] representation of this kind. The ordinals are designed
-   * to be used as bitsets.
-   */
+  /// An [int] representation of this kind. The ordinals are designed
+  /// to be used as bitsets.
   final int ordinal;
 
-  /**
-   * The name of this kind.
-   */
+  /// The name of this kind.
   final String name;
 
-  /**
-   * This constructor is not private to support user-defined
-   * diagnostic kinds.
-   */
+  /// This constructor is not private to support user-defined
+  /// diagnostic kinds.
   const Diagnostic(this.ordinal, this.name);
 
   String toString() => name;
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 1ead006..991fb58 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -43,6 +43,8 @@
   static const String experimentCallInstrumentation =
       '--experiment-call-instrumentation';
 
+  static const String enableLanguageExperiments = '--enable-experiment';
+
   static const String fastStartup = '--fast-startup';
   static const String fatalWarnings = '--fatal-warnings';
   static const String generateCodeWithCompileTimeErrors =
@@ -59,6 +61,8 @@
   static const String minify = '--minify';
   static const String noFrequencyBasedMinification =
       '--no-frequency-based-minification';
+  // Disables minification even if enabled by other options, e.g. '-O2'.
+  static const String noMinify = '--no-minify';
   static const String noSourceMaps = '--no-source-maps';
   static const String preserveUris = '--preserve-uris';
   static const String showPackageWarnings = '--show-package-warnings';
@@ -127,6 +131,10 @@
   static const String showPackageWarnings =
       '${Flags.showPackageWarnings}|${Flags.showPackageWarnings}=.*';
 
+  static const String enableLanguageExperiments =
+      '${Flags.enableLanguageExperiments}|'
+      '${Flags.enableLanguageExperiments}=.*';
+
   // Experimental options.
   static const String resolutionInput = '--resolution-input=.+';
   static const String bazelPaths = '--bazel-paths=.+';
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 188f52e..9913a66 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -1905,16 +1905,6 @@
   /// Returns the function type variables defined on [function].
   List<TypeVariableType> getFunctionTypeVariables(FunctionEntity function);
 
-  /// Returns the 'element' type of a function with an async, async* or sync*
-  /// marker. The return type of the method is inspected to determine the type
-  /// parameter of the Future, Stream or Iterable.
-  DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function);
-
-  /// Returns the 'element' type of a function with the async, async* or sync*
-  /// marker [marker]. [returnType] is the return type marked function.
-  DartType getAsyncOrSyncStarElementType(
-      AsyncMarker marker, DartType returnType);
-
   /// Returns the type of the [local] function.
   FunctionType getLocalFunctionType(Local local);
 
@@ -1996,4 +1986,14 @@
   /// This is the type used as the default type argument when no explicit type
   /// argument is passed.
   DartType getTypeVariableDefaultType(TypeVariableEntity typeVariable);
+
+  /// Returns the 'element' type of a function with the async, async* or sync*
+  /// marker [marker]. [returnType] is the return type marked function.
+  DartType getAsyncOrSyncStarElementType(
+      AsyncMarker marker, DartType returnType);
+
+  /// Returns the 'element' type of a function with an async, async* or sync*
+  /// marker. The return type of the method is inspected to determine the type
+  /// parameter of the Future, Stream or Iterable.
+  DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function);
 }
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 96ac042..b35401a 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -195,7 +195,6 @@
   JavaScriptBackend createBackend() {
     return new JavaScriptBackend(this,
         generateSourceMap: options.generateSourceMap,
-        useStartupEmitter: options.useStartupEmitter,
         useMultiSourceInfo: options.useMultiSourceInfo,
         useNewSourceInfo: options.useNewSourceInfo);
   }
@@ -444,9 +443,7 @@
     return jClosedWorld;
   }
 
-  /**
-   * Empty the [enqueuer] queue.
-   */
+  /// Empty the [enqueuer] queue.
   void emptyQueue(Enqueuer enqueuer, {void onProgress(Enqueuer enqueuer)}) {
     selfTask.measureSubtask("emptyQueue", () {
       enqueuer.forEach((WorkItem work) {
@@ -775,11 +772,9 @@
   @override
   bool get hasReportedError => compiler.compilationFailed;
 
-  /**
-   * Perform an operation, [f], returning the return value from [f].  If an
-   * error occurs then report it as having occurred during compilation of
-   * [element].  Can be nested.
-   */
+  /// Perform an operation, [f], returning the return value from [f].  If an
+  /// error occurs then report it as having occurred during compilation of
+  /// [element].  Can be nested.
   withCurrentElement(Entity element, f()) {
     Entity old = currentElement;
     _currentElement = element;
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
index 8d9fab5..1fc88a5 100644
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ b/pkg/compiler/lib/src/constant_system_dart.dart
@@ -51,9 +51,7 @@
   }
 }
 
-/**
- * Operations that only work if both arguments are integers.
- */
+/// Operations that only work if both arguments are integers.
 abstract class BinaryBitOperation implements BinaryOperation {
   const BinaryBitOperation();
   ConstantValue fold(ConstantValue left, ConstantValue right) {
@@ -412,12 +410,10 @@
   }
 }
 
-/**
- * A constant system implementing the Dart semantics. This system relies on
- * the underlying runtime-system. That is, if dart2js is run in an environment
- * that doesn't correctly implement Dart's semantics this constant system will
- * not return the correct values.
- */
+/// A constant system implementing the Dart semantics. This system relies on
+/// the underlying runtime-system. That is, if dart2js is run in an environment
+/// that doesn't correctly implement Dart's semantics this constant system will
+/// not return the correct values.
 class DartConstantSystem extends ConstantSystem {
   final add = const AddOperation();
   final bitAnd = const BitAndOperation();
diff --git a/pkg/compiler/lib/src/constants/constant_system.dart b/pkg/compiler/lib/src/constants/constant_system.dart
index c543720..91d89f2 100644
--- a/pkg/compiler/lib/src/constants/constant_system.dart
+++ b/pkg/compiler/lib/src/constants/constant_system.dart
@@ -14,19 +14,17 @@
 }
 
 abstract class UnaryOperation extends Operation {
-  /** Returns [:null:] if it was unable to fold the operation. */
+  /// Returns [:null:] if it was unable to fold the operation.
   ConstantValue fold(ConstantValue constant);
 }
 
 abstract class BinaryOperation extends Operation {
-  /** Returns [:null:] if it was unable to fold the operation. */
+  /// Returns [:null:] if it was unable to fold the operation.
   ConstantValue fold(ConstantValue left, ConstantValue right);
   apply(left, right);
 }
 
-/**
- * A [ConstantSystem] is responsible for creating constants and folding them.
- */
+/// A [ConstantSystem] is responsible for creating constants and folding them.
 abstract class ConstantSystem {
   BinaryOperation get add;
   BinaryOperation get bitAnd;
@@ -75,15 +73,19 @@
   // system because an int is a double at runtime.
   bool isSubtype(DartTypes types, DartType s, DartType t);
 
-  /** Returns true if the [constant] is an integer at runtime. */
+  /// Returns true if the [constant] is an integer at runtime.
   bool isInt(ConstantValue constant);
-  /** Returns true if the [constant] is a double at runtime. */
+
+  /// Returns true if the [constant] is a double at runtime.
   bool isDouble(ConstantValue constant);
-  /** Returns true if the [constant] is a string at runtime. */
+
+  /// Returns true if the [constant] is a string at runtime.
   bool isString(ConstantValue constant);
-  /** Returns true if the [constant] is a boolean at runtime. */
+
+  /// Returns true if the [constant] is a boolean at runtime.
   bool isBool(ConstantValue constant);
-  /** Returns true if the [constant] is null at runtime. */
+
+  /// Returns true if the [constant] is null at runtime.
   bool isNull(ConstantValue constant);
 
   UnaryOperation lookupUnary(UnaryOperator operator) {
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index aae0175..3d30d3b 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -71,9 +71,11 @@
   bool get isMap => false;
   bool get isConstructedObject => false;
   bool get isFunction => false;
-  /** Returns true if the constant is null, a bool, a number or a string. */
+
+  /// Returns true if the constant is null, a bool, a number or a string.
   bool get isPrimitive => false;
-  /** Returns true if the constant is a list, a map or a constructed object. */
+
+  /// Returns true if the constant is a list, a map or a constructed object.
   bool get isObject => false;
   bool get isType => false;
   bool get isInterceptor => false;
@@ -170,7 +172,7 @@
 }
 
 class NullConstantValue extends PrimitiveConstantValue {
-  /** The value a Dart null is compiled to in JavaScript. */
+  /// The value a Dart null is compiled to in JavaScript.
   static const String JsNull = "null";
 
   const factory NullConstantValue() = NullConstantValue._internal;
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 74818db..dbfe890 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -23,21 +23,17 @@
 const String _defaultSpecificationUri = '../../../../sdk/lib/libraries.json';
 const String OUTPUT_LANGUAGE_DART = 'Dart';
 
-/**
- * A string to identify the revision or build.
- *
- * This ID is displayed if the compiler crashes and in verbose mode, and is
- * an aid in reproducing bug reports.
- *
- * The actual string is rewritten by a wrapper script when included in the sdk.
- */
+/// A string to identify the revision or build.
+///
+/// This ID is displayed if the compiler crashes and in verbose mode, and is
+/// an aid in reproducing bug reports.
+///
+/// The actual string is rewritten by a wrapper script when included in the sdk.
 String BUILD_ID = null;
 
-/**
- * The data passed to the [HandleOption] callback is either a single
- * string argument, or the arguments iterator for multiple arguments
- * handlers.
- */
+/// The data passed to the [HandleOption] callback is either a single
+/// string argument, or the arguments iterator for multiple arguments
+/// handlers.
 typedef void HandleOption(Null data);
 
 class OptionHandler {
@@ -52,12 +48,10 @@
   OptionHandler(this.pattern, this._handle, {this.multipleArguments: false});
 }
 
-/**
- * Extract the parameter of an option.
- *
- * For example, in ['--out=fisk.js'] and ['-ohest.js'], the parameters
- * are ['fisk.js'] and ['hest.js'], respectively.
- */
+/// Extract the parameter of an option.
+///
+/// For example, in ['--out=fisk.js'] and ['-ohest.js'], the parameters
+/// are ['fisk.js'] and ['hest.js'], respectively.
 String extractParameter(String argument, {bool isOptionalArgument: false}) {
   // m[0] is the entire match (which will be equal to argument). m[1]
   // is something like "-o" or "--out=", and m[2] is the parameter.
@@ -340,10 +334,11 @@
     new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
     new OptionHandler('-O.*', setOptimizationLevel),
     new OptionHandler(Flags.allowMockCompilation, ignoreOption),
-    new OptionHandler(Flags.fastStartup, passThrough),
+    new OptionHandler(Flags.fastStartup, ignoreOption),
     new OptionHandler(Flags.genericMethodSyntax, ignoreOption),
     new OptionHandler(Flags.initializingFormalAccess, ignoreOption),
     new OptionHandler(Flags.minify, passThrough),
+    new OptionHandler(Flags.noMinify, passThrough),
     new OptionHandler(Flags.preserveUris, ignoreOption),
     new OptionHandler('--force-strip=.*', setStrip),
     new OptionHandler(Flags.disableDiagnosticColors, (_) {
@@ -380,6 +375,7 @@
     new OptionHandler(Flags.dumpInfo, passThrough),
     new OptionHandler('--disallow-unsafe-eval', ignoreOption),
     new OptionHandler(Option.showPackageWarnings, passThrough),
+    new OptionHandler(Option.enableLanguageExperiments, passThrough),
     new OptionHandler(Flags.useContentSecurityPolicy, passThrough),
     new OptionHandler(Flags.enableExperimentalMirrors, passThrough),
     new OptionHandler(Flags.enableAssertMessage, passThrough),
@@ -765,10 +761,6 @@
   --no-source-maps
     Do not generate a source map file.
 
-  --fast-startup
-    Produce JavaScript that can be parsed more quickly by VMs. This option
-    usually results in larger JavaScript files with faster startup.
-
   -O<0,1,2,3,4>
     Controls optimizations that can help reduce code-size and improve
     performance of the generated code for deployment.
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 31c1687..ddbd195 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -133,14 +133,12 @@
   /// Should describe how to fix the problem. Elided when using --terse option.
   final String howToFix;
 
-  /**
-   *  Examples will be checked by
-   *  tests/compiler/dart2js/message_kind_test.dart.
-   *
-   *  An example is either a String containing the example source code or a Map
-   *  from filenames to source code. In the latter case, the filename for the
-   *  main library code must be 'main.dart'.
-   */
+  ///  Examples will be checked by
+  ///  tests/compiler/dart2js/message_kind_test.dart.
+  ///
+  ///  An example is either a String containing the example source code or a Map
+  ///  from filenames to source code. In the latter case, the filename for the
+  ///  main library code must be 'main.dart'.
   final List examples;
 
   /// Additional options needed for the examples to work.
diff --git a/pkg/compiler/lib/src/diagnostics/spannable.dart b/pkg/compiler/lib/src/diagnostics/spannable.dart
index 3c8b6d1..cdba684 100644
--- a/pkg/compiler/lib/src/diagnostics/spannable.dart
+++ b/pkg/compiler/lib/src/diagnostics/spannable.dart
@@ -4,9 +4,7 @@
 
 library dart2js.diagnostics.spannable;
 
-/**
- * Tagging interface for classes from which source spans can be generated.
- */
+/// Tagging interface for classes from which source spans can be generated.
 // TODO(johnniwinther): Find a better name.
 // TODO(ahe): How about "Bolt"?
 abstract class Spannable {}
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index e2722a0..d3f9c4d 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -32,6 +32,7 @@
   final Compiler compiler;
   final JClosedWorld closedWorld;
   final GlobalTypeInferenceResults _globalInferenceResults;
+  final DumpInfoTask dumpInfoTask;
 
   JElementEnvironment get environment => closedWorld.elementEnvironment;
   CodegenWorldBuilder get codegenWorldBuilder => compiler.codegenWorldBuilder;
@@ -41,13 +42,13 @@
   final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{};
   final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {};
 
-  ElementInfoCollector(
-      this.compiler, this.closedWorld, this._globalInferenceResults);
+  ElementInfoCollector(this.compiler, this.dumpInfoTask, this.closedWorld,
+      this._globalInferenceResults);
 
   void run() {
-    compiler.dumpInfoTask._constantToNode.forEach((constant, node) {
+    dumpInfoTask._constantToNode.forEach((constant, node) {
       // TODO(sigmund): add dependencies on other constants
-      var size = compiler.dumpInfoTask._nodeToSize[node];
+      var size = dumpInfoTask._nodeData[node].length;
       var code = jsAst.prettyPrint(node,
           enableMinification: compiler.options.enableMinification);
       var info = new ConstantInfo(
@@ -64,8 +65,8 @@
   /// output size. Either because it is a function being emitted or inlined,
   /// or because it is an entity that holds dependencies to other entities.
   bool shouldKeep(Entity entity) {
-    return compiler.dumpInfoTask.impacts.containsKey(entity) ||
-        compiler.dumpInfoTask.inlineCount.containsKey(entity);
+    return dumpInfoTask.impacts.containsKey(entity) ||
+        dumpInfoTask.inlineCount.containsKey(entity);
   }
 
   LibraryInfo visitLibrary(LibraryEntity lib) {
@@ -73,7 +74,7 @@
     if (libname.isEmpty) {
       libname = '<unnamed>';
     }
-    int size = compiler.dumpInfoTask.sizeOf(lib);
+    int size = dumpInfoTask.sizeOf(lib);
     LibraryInfo info = new LibraryInfo(libname, lib.canonicalUri, null, size);
     _entityToInfo[lib] = info;
 
@@ -122,8 +123,8 @@
       return null;
     }
 
-    int size = compiler.dumpInfoTask.sizeOf(field);
-    String code = compiler.dumpInfoTask.codeOf(field);
+    int size = dumpInfoTask.sizeOf(field);
+    String code = dumpInfoTask.codeOf(field);
 
     // TODO(het): Why doesn't `size` account for the code size already?
     if (code != null) size += code.length;
@@ -162,7 +163,7 @@
         outputUnit: _unitInfoForClass(clazz));
     _entityToInfo[clazz] = classInfo;
 
-    int size = compiler.dumpInfoTask.sizeOf(clazz);
+    int size = dumpInfoTask.sizeOf(clazz);
     environment.forEachLocalClassMember(clazz, (member) {
       if (member.isFunction || member.isGetter || member.isSetter) {
         FunctionInfo functionInfo = visitFunction(member);
@@ -213,7 +214,7 @@
     ClosureInfo closureInfo = new ClosureInfo(
         name: element.name,
         outputUnit: _unitInfoForClass(element),
-        size: compiler.dumpInfoTask.sizeOf(element));
+        size: dumpInfoTask.sizeOf(element));
     _entityToInfo[element] = closureInfo;
 
     FunctionEntity callMethod = closedWorld.elementEnvironment
@@ -229,7 +230,7 @@
   }
 
   FunctionInfo visitFunction(FunctionEntity function) {
-    int size = compiler.dumpInfoTask.sizeOf(function);
+    int size = dumpInfoTask.sizeOf(function);
     // TODO(sigmund): consider adding a small info to represent unreachable
     // code here.
     if (size == 0 && !shouldKeep(function)) return null;
@@ -260,7 +261,7 @@
           : false,
       isExternal: function.isExternal,
     );
-    String code = compiler.dumpInfoTask.codeOf(function);
+    String code = dumpInfoTask.codeOf(function);
 
     List<ParameterInfo> parameters = <ParameterInfo>[];
     List<String> inferredParameterTypes = <String>[];
@@ -280,7 +281,7 @@
     String sideEffects =
         '${_globalInferenceResults.inferredData.getSideEffectsOfElement(function)}';
 
-    int inlinedCount = compiler.dumpInfoTask.inlineCount[function];
+    int inlinedCount = dumpInfoTask.inlineCount[function];
     if (inlinedCount == null) inlinedCount = 0;
 
     FunctionInfo info = new FunctionInfo(
@@ -400,10 +401,10 @@
   /// The size of the generated output.
   int _programSize;
 
-  // A set of javascript AST nodes that we care about the size of.
-  // This set is automatically populated when registerEntityAst()
-  // is called.
-  final Set<jsAst.Node> _tracking = new Set<jsAst.Node>();
+  /// Data associated with javascript AST nodes. The map only contains keys for
+  /// nodes that we care about.  Keys are automatically added when
+  /// [registerEntityAst] is called.
+  final Map<jsAst.Node, _CodeData> _nodeData = <jsAst.Node, _CodeData>{};
 
   // A mapping from Dart Entities to Javascript AST Nodes.
   final Map<Entity, List<jsAst.Node>> _entityToNodes =
@@ -411,10 +412,6 @@
   final Map<ConstantValue, jsAst.Node> _constantToNode =
       <ConstantValue, jsAst.Node>{};
 
-  // A mapping from Javascript AST Nodes to the size of their
-  // pretty-printed contents.
-  final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{};
-
   final Map<Entity, int> inlineCount = <Entity, int>{};
 
   // A mapping from an entity to a list of entities that are
@@ -470,24 +467,15 @@
     return selections;
   }
 
-  // Returns true if we care about tracking the size of
-  // this node.
-  bool isTracking(jsAst.Node code) {
-    if (compiler.options.dumpInfo) {
-      return _tracking.contains(code);
-    } else {
-      return false;
-    }
-  }
-
   /// Registers that a javascript AST node [code] was produced by the dart
   /// Entity [entity].
-  void registerEntityAst(Entity entity, jsAst.Node code) {
+  void registerEntityAst(Entity entity, jsAst.Node code,
+      {LibraryEntity library}) {
     if (compiler.options.dumpInfo) {
       _entityToNodes
           .putIfAbsent(entity, () => new List<jsAst.Node>())
           .add(code);
-      _tracking.add(code);
+      _nodeData[code] ??= _CodeData();
     }
   }
 
@@ -496,19 +484,36 @@
       assert(_constantToNode[constant] == null ||
           _constantToNode[constant] == code);
       _constantToNode[constant] = code;
-      _tracking.add(code);
+      _nodeData[code] ??= _CodeData();
     }
   }
 
-  /// Records the size of a dart AST node after it has been pretty-printed into
-  /// the output buffer.
-  void recordAstSize(jsAst.Node node, int size) {
-    if (isTracking(node)) {
-      //TODO: should I be incrementing here instead?
-      _nodeToSize[node] = size;
+  // TODO(sigmund): delete the stack once we stop emitting the source text.
+  List<_CodeData> _stack = [];
+  void enterNode(jsAst.Node node, int start) {
+    var data = _nodeData[node];
+    if (data != null) {
+      _stack.add(data);
+      data.start = start;
     }
   }
 
+  void emit(String string) {
+    // Note: historically we emitted the full body of classes and methods, so
+    // instance methods ended up emitted twice.  Once we use a different
+    // encoding of dump info, we also plan to remove this duplication.
+    _stack.forEach((f) => f.text.write(string));
+  }
+
+  void exitNode(jsAst.Node node, int start, int end, int closing) {
+    var data = _nodeData[node];
+    if (data == null) return;
+    var last = _stack.removeLast();
+    assert(data == last);
+    assert(data.start == start);
+    data.end = end;
+  }
+
   /// Returns the size of the source code that was generated for an entity.
   /// If no source code was produced, return 0.
   int sizeOf(Entity entity) {
@@ -519,7 +524,7 @@
     }
   }
 
-  int sizeOfNode(jsAst.Node node) => _nodeToSize[node] ?? 0;
+  int sizeOfNode(jsAst.Node node) => _nodeData[node].length ?? 0;
 
   String codeOf(Entity entity) {
     List<jsAst.Node> code = _entityToNodes[entity];
@@ -527,8 +532,7 @@
     // Concatenate rendered ASTs.
     StringBuffer sb = new StringBuffer();
     for (jsAst.Node ast in code) {
-      sb.writeln(jsAst.prettyPrint(ast,
-          enableMinification: compiler.options.enableMinification));
+      sb.writeln(_nodeData[ast].text);
     }
     return sb.toString();
   }
@@ -537,7 +541,7 @@
       GlobalTypeInferenceResults globalInferenceResults) {
     measure(() {
       infoCollector = new ElementInfoCollector(
-          compiler, closedWorld, globalInferenceResults)
+          compiler, this, closedWorld, globalInferenceResults)
         ..run();
       StringBuffer jsonBuffer = new StringBuffer();
       dumpInfoJson(jsonBuffer, closedWorld);
@@ -634,3 +638,15 @@
     });
   }
 }
+
+/// Helper class to store what dump-info will show for a piece of code.
+///
+/// Currently we print out the actual text, in the future, we will only emit
+/// start and end offsets.
+class _CodeData {
+  int start;
+  int end;
+  StringBuffer text = new StringBuffer();
+
+  int get length => end - start;
+}
diff --git a/pkg/compiler/lib/src/elements/entity_utils.dart b/pkg/compiler/lib/src/elements/entity_utils.dart
index 6096e4a..0a26700 100644
--- a/pkg/compiler/lib/src/elements/entity_utils.dart
+++ b/pkg/compiler/lib/src/elements/entity_utils.dart
@@ -101,15 +101,13 @@
   }
 }
 
-/**
- * Map an operator-name to a valid JavaScript identifier.
- *
- * For non-operator names, this method just returns its input.
- *
- * The results returned from this method are guaranteed to be valid
- * JavaScript identifiers, except it may include reserved words for
- * non-operator names.
- */
+/// Map an operator-name to a valid JavaScript identifier.
+///
+/// For non-operator names, this method just returns its input.
+///
+/// The results returned from this method are guaranteed to be valid
+/// JavaScript identifiers, except it may include reserved words for
+/// non-operator names.
 String operatorNameToIdentifier(String name) {
   if (name == null) {
     return name;
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index bc4d20e..d42f31a 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -103,7 +103,8 @@
   bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) => false;
 }
 
-/// Pairs of [FunctionTypeVariable]s that are currently assumed to be equivalent.
+/// Pairs of [FunctionTypeVariable]s that are currently assumed to be
+/// equivalent.
 ///
 /// This is used to compute the equivalence relation on types coinductively.
 class _Assumptions {
diff --git a/pkg/compiler/lib/src/helpers/expensive_map.dart b/pkg/compiler/lib/src/helpers/expensive_map.dart
index 5f5cb44..ed95b22 100644
--- a/pkg/compiler/lib/src/helpers/expensive_map.dart
+++ b/pkg/compiler/lib/src/helpers/expensive_map.dart
@@ -4,11 +4,9 @@
 
 import "dart:collection";
 
-/**
- * The expensive map is a data structure useful for tracking down
- * excessive memory usage due to large maps. It acts as an ordinary
- * hash map, but it uses 10 times more memory (by default).
- */
+/// The expensive map is a data structure useful for tracking down
+/// excessive memory usage due to large maps. It acts as an ordinary
+/// hash map, but it uses 10 times more memory (by default).
 class ExpensiveMap<K, V> extends MapBase<K, V> {
   final List _maps;
 
diff --git a/pkg/compiler/lib/src/helpers/expensive_set.dart b/pkg/compiler/lib/src/helpers/expensive_set.dart
index 76f8cd7..f4c2f4f 100644
--- a/pkg/compiler/lib/src/helpers/expensive_set.dart
+++ b/pkg/compiler/lib/src/helpers/expensive_set.dart
@@ -4,11 +4,9 @@
 
 import 'dart:collection';
 
-/**
- * The expensive set is a data structure useful for tracking down
- * excessive memory usage due to large sets. It acts as an ordinary
- * hash set, but it uses 10 times more memory (by default).
- */
+/// The expensive set is a data structure useful for tracking down
+/// excessive memory usage due to large sets. It acts as an ordinary
+/// hash set, but it uses 10 times more memory (by default).
 class ExpensiveSet<E> extends SetBase<E> {
   final List _sets;
 
diff --git a/pkg/compiler/lib/src/helpers/trace.dart b/pkg/compiler/lib/src/helpers/trace.dart
index 2c92824..104c227 100644
--- a/pkg/compiler/lib/src/helpers/trace.dart
+++ b/pkg/compiler/lib/src/helpers/trace.dart
@@ -9,23 +9,21 @@
 typedef void Trace(String message,
     {bool condition(String stackTrace), int limit, bool throwOnPrint});
 
-/**
- * Helper method for printing stack traces for debugging.
- *
- * [message] is printed as the header of the stack trace.
- *
- * If [condition] is provided, the stack trace is only printed if [condition]
- * returns [:true:] on the stack trace text. This can be used to filter the
- * printed stack traces based on their content. For instance only print stack
- * traces that contain specific paths.
- *
- * If [limit] is provided, the stack trace is limited to [limit] entries.
- *
- * If [throwOnPrint] is `true`, [message] will be thrown after the stack trace
- * has been printed. Together with [condition] this can be used to discover
- * unknown call-sites in tests by filtering known call-sites and throwning
- * otherwise.
- */
+/// Helper method for printing stack traces for debugging.
+///
+/// [message] is printed as the header of the stack trace.
+///
+/// If [condition] is provided, the stack trace is only printed if [condition]
+/// returns [:true:] on the stack trace text. This can be used to filter the
+/// printed stack traces based on their content. For instance only print stack
+/// traces that contain specific paths.
+///
+/// If [limit] is provided, the stack trace is limited to [limit] entries.
+///
+/// If [throwOnPrint] is `true`, [message] will be thrown after the stack trace
+/// has been printed. Together with [condition] this can be used to discover
+/// unknown call-sites in tests by filtering known call-sites and throwning
+/// otherwise.
 Trace get trace {
   enableDebugMode();
   return _trace;
@@ -293,22 +291,20 @@
 }
 
 // TODO(johnniwinther): Use this format for --throw-on-error.
-/**
- * Converts the normal VM stack trace into a more compact and readable format.
- *
- * The output format is [: <file> . . . <lineNo>:<columnNo> <method> :] where
- * [: <file> :] is file name, [: <lineNo> :] is the line number,
- * [: <columnNo> :] is the column number, and [: <method> :] is the method name.
- *
- * If [rangeStart] and/or [rangeEnd] are provided, only the lines within the
- * range are included.
- * If [showColumnNo] is [:false:], the [: :<columnNo> :] part is omitted.
- * If [showDots] is [:true:], the space between [: <file> :] and [: <lineNo> :]
- * is padded with dots on every other line.
- * If [filePrefix] is provided, then for  every file name thats starts with
- * [filePrefix] only the remainder is printed.
- * If [lambda] is non-null, anonymous closures are printed as [lambda].
- */
+/// Converts the normal VM stack trace into a more compact and readable format.
+///
+/// The output format is `<file> . . . <lineNo>:<columnNo> <method>` where
+/// `<file>` is file name, `<lineNo>` is the line number, `<columnNo>` is the
+/// column number, and `<method>` is the method name.
+///
+/// If [rangeStart] and/or [rangeEnd] are provided, only the lines within the
+/// range are included.
+/// If [showColumnNo] is `false`, the `:<columnNo>` part is omitted.
+/// If [showDots] is `true`, the space between `<file>` and `<lineNo>` is padded
+/// with dots on every other line.
+/// If [filePrefix] is provided, then for  every file name thats starts with
+/// [filePrefix] only the remainder is printed.
+/// If [lambda] is non-null, anonymous closures are printed as [lambda].
 String prettifyStackTrace(StackTrace stackTrace,
     {int rangeStart,
     int rangeEnd,
@@ -324,12 +320,10 @@
       .prettify(showColumnNo: showColumnNo, showDots: showDots);
 }
 
-/**
- * Pads (or truncates) [text] to the [intendedLength].
- *
- * If [padLeft] is [:true:] the text is padding inserted to the left of [text].
- * A repetition of the [dots] text is used for padding.
- */
+/// Pads (or truncates) [text] to the [intendedLength].
+///
+/// If [padLeft] is [:true:] the text is padding inserted to the left of [text].
+/// A repetition of the [dots] text is used for padding.
 String pad(String text, int intendedLength,
     {bool padLeft: false, String dots: ' '}) {
   if (text.length == intendedLength) return text;
diff --git a/pkg/compiler/lib/src/helpers/track_map.dart b/pkg/compiler/lib/src/helpers/track_map.dart
index 7c2eb86..6cb7121 100644
--- a/pkg/compiler/lib/src/helpers/track_map.dart
+++ b/pkg/compiler/lib/src/helpers/track_map.dart
@@ -2,17 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-/**
- * The track map is a simple wrapper around a map that keeps track
- * of the 'final' size of maps grouped by description. It allows
- * determining the distribution of sizes for a specific allocation
- * site and it can be used like this:
- *
- *    Map<String, int> map = new TrackMap<String, int>("my-map");
- *
- * After finishing the compilaton, the histogram of track map sizes
- * is printed but only when running in verbose mode.
- */
+/// The track map is a simple wrapper around a map that keeps track
+/// of the 'final' size of maps grouped by description. It allows
+/// determining the distribution of sizes for a specific allocation
+/// site and it can be used like this:
+///
+///    Map<String, int> map = new TrackMap<String, int>("my-map");
+///
+/// After finishing the compilaton, the histogram of track map sizes
+/// is printed but only when running in verbose mode.
 class TrackMap<K, V> implements Map<K, V> {
   final Map<K, V> _map;
   final List _counts;
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index e029d4f..60ea7a3 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -310,10 +310,8 @@
   GlobalTypeInferenceElementData dataOfMember(MemberEntity element) =>
       _memberData[element] ??= new KernelGlobalTypeInferenceElementData();
 
-  /**
-   * Update [sideEffects] with the side effects of [callee] being
-   * called with [selector].
-   */
+  /// Update [sideEffects] with the side effects of [callee] being
+  /// called with [selector].
   void updateSideEffects(SideEffectsBuilder sideEffectsBuilder,
       Selector selector, MemberEntity callee) {
     if (callee.isField) {
diff --git a/pkg/compiler/lib/src/inferrer/list_tracer.dart b/pkg/compiler/lib/src/inferrer/list_tracer.dart
index 7043105..dfe10a0 100644
--- a/pkg/compiler/lib/src/inferrer/list_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/list_tracer.dart
@@ -11,11 +11,9 @@
 import 'node_tracer.dart';
 import 'type_graph_nodes.dart';
 
-/**
- * A set of selector names that [List] implements, that we know do not
- * change the element type of the list, or let the list escape to code
- * that might change the element type.
- */
+/// A set of selector names that [List] implements, that we know do not
+/// change the element type of the list, or let the list escape to code
+/// that might change the element type.
 Set<String> okListSelectorsSet = new Set<String>.from(const <String>[
   // From Object.
   '==',
@@ -137,11 +135,9 @@
 
   ListTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
 
-  /**
-   * Returns [true] if the analysis completed successfully, [false] if it
-   * bailed out. In the former case, [assignments] holds a list of
-   * [TypeInformation] nodes that flow into the element type of this list.
-   */
+  /// Returns [true] if the analysis completed successfully, [false] if it
+  /// bailed out. In the former case, [assignments] holds a list of
+  /// [TypeInformation] nodes that flow into the element type of this list.
   bool run() {
     analyze();
     ListTypeInformation list = tracedType;
diff --git a/pkg/compiler/lib/src/inferrer/locals_handler.dart b/pkg/compiler/lib/src/inferrer/locals_handler.dart
index cfe7f1c..aff2896 100644
--- a/pkg/compiler/lib/src/inferrer/locals_handler.dart
+++ b/pkg/compiler/lib/src/inferrer/locals_handler.dart
@@ -13,13 +13,11 @@
 import 'inferrer_engine.dart';
 import 'type_graph_nodes.dart';
 
-/**
- * A variable scope holds types for variables. It has a link to a
- * parent scope, but never changes the types in that parent. Instead,
- * updates to locals of a parent scope are put in the current scope.
- * The inferrer makes sure updates get merged into the parent scope,
- * once the control flow block has been visited.
- */
+/// A variable scope holds types for variables. It has a link to a
+/// parent scope, but never changes the types in that parent. Instead,
+/// updates to locals of a parent scope are put in the current scope.
+/// The inferrer makes sure updates get merged into the parent scope,
+/// once the control flow block has been visited.
 class VariableScope {
   /// The number of parent scopes of this scope.
   ///
@@ -241,9 +239,7 @@
   }
 }
 
-/**
- * Placeholder for inferred arguments types on sends.
- */
+/// Placeholder for inferred arguments types on sends.
 class ArgumentsTypes extends IterableMixin<TypeInformation> {
   final List<TypeInformation> positional;
   final Map<String, TypeInformation> named;
@@ -317,9 +313,7 @@
   }
 }
 
-/**
- * Placeholder for inferred types of local variables.
- */
+/// Placeholder for inferred types of local variables.
 class LocalsHandler {
   final VariableScope _locals;
 
@@ -439,36 +433,34 @@
     return this;
   }
 
-  /**
-   * Merge all [LocalsHandler] in [handlers] into [:this:].
-   *
-   * If [keepOwnLocals] is true, the types of locals in this
-   * [LocalsHandler] are being used in the merge. [keepOwnLocals]
-   * should be true if this [LocalsHandler], the dominator of
-   * all [handlers], also directly flows into the join point,
-   * that is the code after all [handlers]. For example, consider:
-   *
-   * [: switch (...) {
-   *      case 1: ...; break;
-   *    }
-   * :]
-   *
-   * The [LocalsHandler] at entry of the switch also flows into the
-   * exit of the switch, because there is no default case. So the
-   * types of locals at entry of the switch have to take part to the
-   * merge.
-   *
-   * The above situation is also true for labeled statements like
-   *
-   * [: L: {
-   *      if (...) break;
-   *      ...
-   *    }
-   * :]
-   *
-   * where [:this:] is the [LocalsHandler] for the paths through the
-   * labeled statement that do not break out.
-   */
+  /// Merge all [LocalsHandler] in [handlers] into [:this:].
+  ///
+  /// If [keepOwnLocals] is true, the types of locals in this
+  /// [LocalsHandler] are being used in the merge. [keepOwnLocals]
+  /// should be true if this [LocalsHandler], the dominator of
+  /// all [handlers], also directly flows into the join point,
+  /// that is the code after all [handlers]. For example, consider:
+  ///
+  /// [: switch (...) {
+  ///      case 1: ...; break;
+  ///    }
+  /// :]
+  ///
+  /// The [LocalsHandler] at entry of the switch also flows into the
+  /// exit of the switch, because there is no default case. So the
+  /// types of locals at entry of the switch have to take part to the
+  /// merge.
+  ///
+  /// The above situation is also true for labeled statements like
+  ///
+  /// [: L: {
+  ///      if (...) break;
+  ///      ...
+  ///    }
+  /// :]
+  ///
+  /// where [:this:] is the [LocalsHandler] for the paths through the
+  /// labeled statement that do not break out.
   LocalsHandler mergeAfterBreaks(
       InferrerEngine inferrer, Iterable<LocalsHandler> handlers,
       {bool keepOwnLocals: true}) {
diff --git a/pkg/compiler/lib/src/inferrer/map_tracer.dart b/pkg/compiler/lib/src/inferrer/map_tracer.dart
index 83ad71c..e9da06a 100644
--- a/pkg/compiler/lib/src/inferrer/map_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/map_tracer.dart
@@ -43,12 +43,10 @@
 
   MapTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
 
-  /**
-   * Returns [true] if the analysis completed successfully, [false]
-   * if it bailed out. In the former case, [keyAssignments] and
-   * [valueAssignments] hold a list of [TypeInformation] nodes that
-   * flow into the key and value types of this map.
-   */
+  /// Returns [true] if the analysis completed successfully, [false]
+  /// if it bailed out. In the former case, [keyAssignments] and
+  /// [valueAssignments] hold a list of [TypeInformation] nodes that
+  /// flow into the key and value types of this map.
   bool run() {
     analyze();
     MapTypeInformation map = tracedType;
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index e88535a..e0abccf 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -249,11 +249,9 @@
     }
   }
 
-  /**
-   * Checks whether this is a call to a list adding method. The definition of
-   * what list adding means has to stay in sync with
-   * [isParameterOfListAddingMethod].
-   */
+  /// Checks whether this is a call to a list adding method. The definition of
+  /// what list adding means has to stay in sync with
+  /// [isParameterOfListAddingMethod].
   bool mightAddToContainer(DynamicCallSiteTypeInformation info) {
     if (info.arguments == null) return false;
     if (info.arguments.named.isNotEmpty) return false;
@@ -275,20 +273,16 @@
     return currentUser == arguments[index];
   }
 
-  /**
-   * Checks whether the call site flows the currentUser to the key argument of
-   * an indexing setter. This must be kept in sync with
-   * [isParameterOfMapAddingMethod].
-   */
+  /// Checks whether the call site flows the currentUser to the key argument of
+  /// an indexing setter. This must be kept in sync with
+  /// [isParameterOfMapAddingMethod].
   bool isIndexSetKey(DynamicCallSiteTypeInformation info) {
     return isIndexSetArgument(info, 0);
   }
 
-  /**
-   * Checks whether the call site flows the currentUser to the value argument of
-   * an indexing setter. This must be kept in sync with
-   * [isParameterOfListAddingMethod] and [isParameterOfMapAddingMethod].
-   */
+  /// Checks whether the call site flows the currentUser to the value argument
+  /// of an indexing setter. This must be kept in sync with
+  /// [isParameterOfListAddingMethod] and [isParameterOfMapAddingMethod].
   bool isIndexSetValue(DynamicCallSiteTypeInformation info) {
     return isIndexSetArgument(info, 1);
   }
@@ -398,11 +392,9 @@
     }
   }
 
-  /**
-   * Check whether element is the parameter of a list adding method.
-   * The definition of what a list adding method is has to stay in sync with
-   * [mightAddToContainer].
-   */
+  /// Check whether element is the parameter of a list adding method.
+  /// The definition of what a list adding method is has to stay in sync with
+  /// [mightAddToContainer].
   bool isParameterOfListAddingMethod(ParameterTypeInformation parameterInfo) {
     if (!parameterInfo.isRegularParameter) return false;
     if (parameterInfo.method.enclosingClass !=
@@ -413,11 +405,9 @@
     return (name == '[]=') || (name == 'add') || (name == 'insert');
   }
 
-  /**
-   * Check whether element is the parameter of a list adding method.
-   * The definition of what a list adding method is has to stay in sync with
-   * [isIndexSetKey] and [isIndexSetValue].
-   */
+  /// Check whether element is the parameter of a list adding method.
+  /// The definition of what a list adding method is has to stay in sync with
+  /// [isIndexSetKey] and [isIndexSetValue].
   bool isParameterOfMapAddingMethod(ParameterTypeInformation parameterInfo) {
     if (!parameterInfo.isRegularParameter) return false;
     if (parameterInfo.method.enclosingClass !=
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 67f830a..d9f69ca 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -18,12 +18,10 @@
 import 'type_graph_nodes.dart';
 import 'types.dart';
 
-/**
- * A work queue for the inferrer. It filters out nodes that are tagged as
- * [TypeInformation.doNotEnqueue], as well as ensures through
- * [TypeInformation.inQueue] that a node is in the queue only once at
- * a time.
- */
+/// A work queue for the inferrer. It filters out nodes that are tagged as
+/// [TypeInformation.doNotEnqueue], as well as ensures through
+/// [TypeInformation.inQueue] that a node is in the queue only once at
+/// a time.
 class WorkQueue {
   final Queue<TypeInformation> queue = new Queue<TypeInformation>();
 
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index f614109..794e62d 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -21,22 +21,20 @@
 import 'inferrer_engine.dart';
 import 'type_system.dart';
 
-/**
- * Common class for all nodes in the graph. The current nodes are:
- *
- * - Concrete types
- * - Elements
- * - Call sites
- * - Narrowing instructions
- * - Phi instructions
- * - Containers (for lists)
- * - Type of the element in a container
- *
- * A node has a set of assignments and users. Assignments are used to
- * compute the type of the node ([TypeInformation.computeType]). Users are
- * added to the inferrer's work queue when the type of the node
- * changes.
- */
+/// Common class for all nodes in the graph. The current nodes are:
+///
+/// - Concrete types
+/// - Elements
+/// - Call sites
+/// - Narrowing instructions
+/// - Phi instructions
+/// - Containers (for lists)
+/// - Type of the element in a container
+///
+/// A node has a set of assignments and users. Assignments are used to
+/// compute the type of the node ([TypeInformation.computeType]). Users are
+/// added to the inferrer's work queue when the type of the node
+/// changes.
 abstract class TypeInformation {
   Set<TypeInformation> users;
   var /* List|ParameterAssignments */ _assignments;
@@ -149,16 +147,12 @@
     return abandonInferencing ? safeType(inferrer) : computeType(inferrer);
   }
 
-  /**
-   * Computes a new type for this [TypeInformation] node depending on its
-   * potentially updated inputs.
-   */
+  /// Computes a new type for this [TypeInformation] node depending on its
+  /// potentially updated inputs.
   AbstractValue computeType(InferrerEngine inferrer);
 
-  /**
-   * Returns an approximation for this [TypeInformation] node that is always
-   * safe to use. Used when abandoning inference on a node.
-   */
+  /// Returns an approximation for this [TypeInformation] node that is always
+  /// safe to use. Used when abandoning inference on a node.
   AbstractValue safeType(InferrerEngine inferrer) {
     return inferrer.types.dynamicType.type;
   }
@@ -243,14 +237,12 @@
   bool mightBePassedToFunctionApply = false;
 }
 
-/**
- * Marker node used only during tree construction but not during actual type
- * refinement.
- *
- * Currently, this is used to give a type to an optional parameter even before
- * the corresponding default expression has been analyzed. See
- * [getDefaultTypeOfParameter] and [setDefaultTypeOfParameter] for details.
- */
+/// Marker node used only during tree construction but not during actual type
+/// refinement.
+///
+/// Currently, this is used to give a type to an optional parameter even before
+/// the corresponding default expression has been analyzed. See
+/// [getDefaultTypeOfParameter] and [setDefaultTypeOfParameter] for details.
 class PlaceholderTypeInformation extends TypeInformation {
   PlaceholderTypeInformation(
       AbstractValueDomain abstractValueDomain, MemberTypeInformation context)
@@ -267,13 +259,11 @@
   toString() => "Placeholder [$hashCode]";
 }
 
-/**
- * Parameters of instance functions behave differently than other
- * elements because the inferrer may remove assignments. This happens
- * when the receiver of a dynamic call site can be refined
- * to a type where we know more about which instance method is being
- * called.
- */
+/// Parameters of instance functions behave differently than other
+/// elements because the inferrer may remove assignments. This happens
+/// when the receiver of a dynamic call site can be refined
+/// to a type where we know more about which instance method is being
+/// called.
 class ParameterAssignments extends IterableBase<TypeInformation> {
   final Map<TypeInformation, int> assignments = new Map<TypeInformation, int>();
 
@@ -314,33 +304,31 @@
   String toString() => assignments.keys.toList().toString();
 }
 
-/**
- * A node representing a resolved element of the component. The kind of
- * elements that need an [ElementTypeInformation] are:
- *
- * - Functions (including getters and setters)
- * - Constructors (factory or generative)
- * - Fields
- * - Parameters
- * - Local variables mutated in closures
- *
- * The [ElementTypeInformation] of a function and a constructor is its
- * return type.
- *
- * Note that a few elements of these kinds must be treated specially,
- * and they are dealt in [ElementTypeInformation.handleSpecialCases]:
- *
- * - Parameters of closures, `noSuchMethod` and `call` instance
- *   methods: we currently do not infer types for those.
- *
- * - Fields and parameters being assigned by synthesized calls done by
- *   the backend: we do not know what types the backend will use.
- *
- * - Native functions and fields: because native methods contain no Dart
- *   code, and native fields do not have Dart assignments, we just
- *   trust their type annotation.
- *
- */
+/// A node representing a resolved element of the component. The kind of
+/// elements that need an [ElementTypeInformation] are:
+///
+/// - Functions (including getters and setters)
+/// - Constructors (factory or generative)
+/// - Fields
+/// - Parameters
+/// - Local variables mutated in closures
+///
+/// The [ElementTypeInformation] of a function and a constructor is its
+/// return type.
+///
+/// Note that a few elements of these kinds must be treated specially,
+/// and they are dealt in [ElementTypeInformation.handleSpecialCases]:
+///
+/// - Parameters of closures, `noSuchMethod` and `call` instance
+///   methods: we currently do not infer types for those.
+///
+/// - Fields and parameters being assigned by synthesized calls done by
+///   the backend: we do not know what types the backend will use.
+///
+/// - Native functions and fields: because native methods contain no Dart
+///   code, and native fields do not have Dart assignments, we just
+///   trust their type annotation.
+///
 abstract class ElementTypeInformation extends TypeInformation {
   /// Marker to disable inference for closures in [handleSpecialCases].
   bool disableInferenceForClosures = true;
@@ -360,42 +348,36 @@
   String get debugName;
 }
 
-/**
- * A node representing members in the broadest sense:
- *
- * - Functions
- * - Constructors
- * - Fields (also synthetic ones due to closures)
- * - Local functions (closures)
- *
- * These should never be created directly but instead are constructed by
- * the [ElementTypeInformation] factory.
- */
+/// A node representing members in the broadest sense:
+///
+/// - Functions
+/// - Constructors
+/// - Fields (also synthetic ones due to closures)
+/// - Local functions (closures)
+///
+/// These should never be created directly but instead are constructed by
+/// the [ElementTypeInformation] factory.
 abstract class MemberTypeInformation extends ElementTypeInformation
     with ApplyableTypeInformation {
   final MemberEntity _member;
 
-  /**
-   * If [element] is a function, [closurizedCount] is the number of
-   * times it is closurized. The value gets updated while inferring.
-   */
+  /// If [element] is a function, [closurizedCount] is the number of
+  /// times it is closurized. The value gets updated while inferring.
   int closurizedCount = 0;
 
   // Strict `bool` value is computed in cleanup(). Also used as a flag to see if
   // cleanup has been called.
   bool _isCalledOnce = null;
 
-  /**
-   * This map contains the callers of [element]. It stores all unique call sites
-   * to enable counting the global number of call sites of [element].
-   *
-   * A call site is either an AST [ast.Node], an [Element] (see uses of
-   * [synthesizeForwardingCall] in [SimpleTypeInferrerVisitor]) or an IR
-   * [ir.Node].
-   *
-   * The global information is summarized in [cleanup], after which [_callers]
-   * is set to `null`.
-   */
+  /// This map contains the callers of [element]. It stores all unique call
+  /// sites to enable counting the global number of call sites of [element].
+  ///
+  /// A call site is either an AST [ast.Node], an [Element] (see uses of
+  /// [synthesizeForwardingCall] in [SimpleTypeInferrerVisitor]) or an IR
+  /// [ir.Node].
+  ///
+  /// The global information is summarized in [cleanup], after which [_callers]
+  /// is set to `null`.
   Map<MemberEntity, Setlet<Object>> _callers;
 
   MemberTypeInformation._internal(
@@ -673,15 +655,13 @@
   }
 }
 
-/**
- * A node representing parameters:
- *
- * - Parameters
- * - Initializing formals
- *
- * These should never be created directly but instead are constructed by
- * the [ElementTypeInformation] factory.
- */
+/// A node representing parameters:
+///
+/// - Parameters
+/// - Initializing formals
+///
+/// These should never be created directly but instead are constructed by
+/// the [ElementTypeInformation] factory.
 class ParameterTypeInformation extends ElementTypeInformation {
   final Local _parameter;
   final DartType _type;
@@ -872,16 +852,14 @@
   throw new StateError('Unexpected call type $callType.');
 }
 
-/**
- * A [CallSiteTypeInformation] is a call found in the AST, or a
- * synthesized call for implicit calls in Dart (such as forwarding
- * factories). The [_call] field is a [ast.Node] for the former, and an
- * [Element] for the latter.
- *
- * In the inferrer graph, [CallSiteTypeInformation] nodes do not have
- * any assignment. They rely on the [caller] field for static calls,
- * and [selector] and [receiver] fields for dynamic calls.
- */
+/// A [CallSiteTypeInformation] is a call found in the AST, or a
+/// synthesized call for implicit calls in Dart (such as forwarding
+/// factories). The [_call] field is a [ast.Node] for the former, and an
+/// [Element] for the latter.
+///
+/// In the inferrer graph, [CallSiteTypeInformation] nodes do not have
+/// any assignment. They rely on the [caller] field for static calls,
+/// and [selector] and [receiver] fields for dynamic calls.
 abstract class CallSiteTypeInformation extends TypeInformation
     with ApplyableTypeInformation {
   final Object _call;
@@ -1069,15 +1047,13 @@
     });
   }
 
-  /**
-   * We optimize certain operations on the [int] class because we know more
-   * about their return type than the actual Dart code. For example, we know int
-   * + int returns an int. The Dart library code for [int.operator+] only says
-   * it returns a [num].
-   *
-   * Returns the more precise TypeInformation, or `null` to defer to the library
-   * code.
-   */
+  /// We optimize certain operations on the [int] class because we know more
+  /// about their return type than the actual Dart code. For example, we know
+  /// int + int returns an int. The Dart library code for [int.operator+] only
+  /// says it returns a [num].
+  ///
+  /// Returns the more precise TypeInformation, or `null` to defer to the
+  /// library code.
   TypeInformation handleIntrisifiedSelector(
       Selector selector, AbstractValue mask, InferrerEngine inferrer) {
     JClosedWorld closedWorld = inferrer.closedWorld;
@@ -1240,8 +1216,8 @@
                 return abstractValueDomain.getDictionaryValueForKey(
                     typeMask, key);
               } else {
-                // The typeMap is precise, so if we do not find the key, the lookup
-                // will be [null] at runtime.
+                // The typeMap is precise, so if we do not find the key, the
+                // lookup will be [null] at runtime.
                 if (debug.VERBOSE) {
                   print("Dictionary lookup for $key yields [null].");
                 }
@@ -1364,16 +1340,14 @@
   }
 }
 
-/**
- * A [ConcreteTypeInformation] represents a type that needed
- * to be materialized during the creation of the graph. For example,
- * literals, [:this:] or [:super:] need a [ConcreteTypeInformation].
- *
- * [ConcreteTypeInformation] nodes have no assignment. Also, to save
- * on memory, we do not add users to [ConcreteTypeInformation] nodes,
- * because we know such node will never be refined to a different
- * type.
- */
+/// A [ConcreteTypeInformation] represents a type that needed
+/// to be materialized during the creation of the graph. For example,
+/// literals, [:this:] or [:super:] need a [ConcreteTypeInformation].
+///
+/// [ConcreteTypeInformation] nodes have no assignment. Also, to save
+/// on memory, we do not add users to [ConcreteTypeInformation] nodes,
+/// because we know such node will never be refined to a different
+/// type.
 class ConcreteTypeInformation extends TypeInformation {
   ConcreteTypeInformation(AbstractValue type) : super.untracked(type) {
     this.isStable = true;
@@ -1447,25 +1421,23 @@
   }
 }
 
-/**
- * A [NarrowTypeInformation] narrows a [TypeInformation] to a type,
- * represented in [typeAnnotation].
- *
- * A [NarrowTypeInformation] node has only one assignment: the
- * [TypeInformation] it narrows.
- *
- * [NarrowTypeInformation] nodes are created for:
- *
- * - Code after `is` and `as` checks, where we have more information
- *   on the type of the right hand side of the expression.
- *
- * - Code after a dynamic call, where we have more information on the
- *   type of the receiver: it can only be of a class that holds a
- *   potential target of this dynamic call.
- *
- * - In checked mode, after a type annotation, we have more
- *   information on the type of a local.
- */
+/// A [NarrowTypeInformation] narrows a [TypeInformation] to a type,
+/// represented in [typeAnnotation].
+///
+/// A [NarrowTypeInformation] node has only one assignment: the
+/// [TypeInformation] it narrows.
+///
+/// [NarrowTypeInformation] nodes are created for:
+///
+/// - Code after `is` and `as` checks, where we have more information
+///   on the type of the right hand side of the expression.
+///
+/// - Code after a dynamic call, where we have more information on the
+///   type of the receiver: it can only be of a class that holds a
+///   potential target of this dynamic call.
+///
+/// - In checked mode, after a type annotation, we have more
+///   information on the type of a local.
 class NarrowTypeInformation extends TypeInformation {
   final AbstractValue typeAnnotation;
 
@@ -1506,14 +1478,12 @@
   }
 }
 
-/**
- * An [InferredTypeInformation] is a [TypeInformation] that
- * defaults to the dynamic type until it is marked as being
- * inferred, at which point it computes its type based on
- * its assignments.
- */
+/// An [InferredTypeInformation] is a [TypeInformation] that
+/// defaults to the dynamic type until it is marked as being
+/// inferred, at which point it computes its type based on
+/// its assignments.
 abstract class InferredTypeInformation extends TypeInformation {
-  /** Whether the element type in that container has been inferred. */
+  /// Whether the element type in that container has been inferred.
   bool inferred = false;
 
   InferredTypeInformation(AbstractValueDomain abstractValueDomain,
@@ -1532,26 +1502,22 @@
   }
 }
 
-/**
- * A [ListTypeInformation] is a [TypeInformation] created
- * for each `List` instantiations.
- */
+/// A [ListTypeInformation] is a [TypeInformation] created
+/// for each `List` instantiations.
 class ListTypeInformation extends TypeInformation with TracedTypeInformation {
   final ElementInContainerTypeInformation elementType;
 
-  /** The container type before it is inferred. */
+  /// The container type before it is inferred.
   final AbstractValue originalType;
 
-  /** The length at the allocation site. */
+  /// The length at the allocation site.
   final int originalLength;
 
-  /** The length after the container has been traced. */
+  /// The length after the container has been traced.
   int inferredLength;
 
-  /**
-   * Whether this list goes through a growable check.
-   * We conservatively assume it does.
-   */
+  /// Whether this list goes through a growable check.
+  /// We conservatively assume it does.
   bool checksGrowable = true;
 
   ListTypeInformation(
@@ -1600,10 +1566,8 @@
   }
 }
 
-/**
- * An [ElementInContainerTypeInformation] holds the common type of the
- * elements in a [ListTypeInformation].
- */
+/// An [ElementInContainerTypeInformation] holds the common type of the
+/// elements in a [ListTypeInformation].
 class ElementInContainerTypeInformation extends InferredTypeInformation {
   ElementInContainerTypeInformation(AbstractValueDomain abstractValueDomain,
       MemberTypeInformation context, elementType)
@@ -1616,10 +1580,8 @@
   }
 }
 
-/**
- * A [MapTypeInformation] is a [TypeInformation] created
- * for maps.
- */
+/// A [MapTypeInformation] is a [TypeInformation] created
+/// for maps.
 class MapTypeInformation extends TypeInformation with TracedTypeInformation {
   // When in Dictionary mode, this map tracks the type of the values that
   // have been assigned to a specific [String] key.
@@ -1777,10 +1739,8 @@
   }
 }
 
-/**
- * A [KeyInMapTypeInformation] holds the common type
- * for the keys in a [MapTypeInformation]
- */
+/// A [KeyInMapTypeInformation] holds the common type
+/// for the keys in a [MapTypeInformation]
 class KeyInMapTypeInformation extends InferredTypeInformation {
   KeyInMapTypeInformation(AbstractValueDomain abstractValueDomain,
       MemberTypeInformation context, TypeInformation keyType)
@@ -1793,10 +1753,8 @@
   String toString() => 'Key in Map $type';
 }
 
-/**
- * A [ValueInMapTypeInformation] holds the common type
- * for the values in a [MapTypeInformation]
- */
+/// A [ValueInMapTypeInformation] holds the common type
+/// for the values in a [MapTypeInformation]
 class ValueInMapTypeInformation extends InferredTypeInformation {
   // [nonNull] is set to true if this value is known to be part of the map.
   // Note that only values assigned to a specific key value in dictionary
@@ -1821,10 +1779,8 @@
   String toString() => 'Value in Map $type';
 }
 
-/**
- * A [PhiElementTypeInformation] is an union of
- * [ElementTypeInformation], that is local to a method.
- */
+/// A [PhiElementTypeInformation] is an union of
+/// [ElementTypeInformation], that is local to a method.
 class PhiElementTypeInformation extends TypeInformation {
   final ir.Node branchNode;
   final Local variable;
@@ -1893,9 +1849,7 @@
   }
 }
 
-/**
- * Mixin for [TypeInformation] nodes that can bail out during tracing.
- */
+/// Mixin for [TypeInformation] nodes that can bail out during tracing.
 abstract class TracedTypeInformation implements TypeInformation {
   /// Set to false once analysis has succeeded.
   bool bailedOut = true;
@@ -1905,19 +1859,16 @@
 
   Set<TypeInformation> _flowsInto;
 
-  /**
-   * The set of [TypeInformation] nodes where values from the traced node could
-   * flow in.
-   */
+  /// The set of [TypeInformation] nodes where values from the traced node could
+  /// flow in.
   Set<TypeInformation> get flowsInto {
     return (_flowsInto == null)
         ? const ImmutableEmptySet<TypeInformation>()
         : _flowsInto;
   }
 
-  /**
-   * Adds [nodes] to the sets of values this [TracedTypeInformation] flows into.
-   */
+  /// Adds [nodes] to the sets of values this [TracedTypeInformation] flows
+  /// into.
   void addFlowsIntoTargets(Iterable<TypeInformation> nodes) {
     if (_flowsInto == null) {
       _flowsInto = nodes.toSet();
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index cff86a1..21c5316 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -43,9 +43,7 @@
   bool checkClassEntity(ClassEntity cls);
 }
 
-/**
- * The class [SimpleInferrerVisitor] will use when working on types.
- */
+/// The class [SimpleInferrerVisitor] will use when working on types.
 class TypeSystem {
   final JClosedWorld _closedWorld;
   final TypeSystemStrategy strategy;
@@ -274,10 +272,8 @@
         _abstractValueDomain, value, _abstractValueDomain.boolType);
   }
 
-  /**
-   * Returns the least upper bound between [firstType] and
-   * [secondType].
-   */
+  /// Returns the least upper bound between [firstType] and
+  /// [secondType].
   TypeInformation computeLUB(
       TypeInformation firstType, TypeInformation secondType) {
     if (firstType == null) return secondType;
@@ -291,22 +287,18 @@
         _abstractValueDomain.union(firstType.type, secondType.type));
   }
 
-  /**
-   * Returns `true` if `selector` should be updated to reflect the new
-   * `receiverType`.
-   */
+  /// Returns `true` if `selector` should be updated to reflect the new
+  /// `receiverType`.
   bool selectorNeedsUpdate(TypeInformation info, AbstractValue mask) {
     return info.type != mask;
   }
 
-  /**
-   * Returns a new receiver type for this [selector] applied to
-   * [receiverType].
-   *
-   * The option [isConditional] is true when [selector] was seen in a
-   * conditional send (e.g.  `a?.selector`), in which case the returned type may
-   * be null.
-   */
+  /// Returns a new receiver type for this [selector] applied to
+  /// [receiverType].
+  ///
+  /// The option [isConditional] is true when [selector] was seen in a
+  /// conditional send (e.g.  `a?.selector`), in which case the returned type
+  /// may be null.
   TypeInformation refineReceiver(
       Selector selector, AbstractValue mask, TypeInformation receiver,
       {bool isConditional}) {
@@ -333,11 +325,9 @@
     return newType;
   }
 
-  /**
-   * Returns the intersection between [type] and [annotation].
-   * [isNullable] indicates whether the annotation implies a null
-   * type.
-   */
+  /// Returns the intersection between [type] and [annotation].
+  /// [isNullable] indicates whether the annotation implies a null
+  /// type.
   TypeInformation narrowType(TypeInformation type, DartType annotation,
       {bool isNullable: true}) {
     if (annotation.treatAsDynamic) return type;
@@ -377,9 +367,7 @@
     }
   }
 
-  /**
-   * Returns the non-nullable type of [type].
-   */
+  /// Returns the non-nullable type of [type].
   TypeInformation narrowNotNull(TypeInformation type) {
     if (_abstractValueDomain.isExact(type.type).isDefinitelyTrue) {
       return type;
@@ -423,9 +411,7 @@
     return typeInformation;
   }
 
-  /**
-   * Returns the internal inferrer representation for [mask].
-   */
+  /// Returns the internal inferrer representation for [mask].
   ConcreteTypeInformation getConcreteTypeFor(AbstractValue mask) {
     assert(mask != null);
     return concreteTypes.putIfAbsent(mask, () {
@@ -558,9 +544,7 @@
     return info.isConcrete ? info.type : mask;
   }
 
-  /**
-   * Returns a new type that unions [firstInput] and [secondInput].
-   */
+  /// Returns a new type that unions [firstInput] and [secondInput].
   TypeInformation allocateDiamondPhi(
       TypeInformation firstInput, TypeInformation secondInput) {
     PhiElementTypeInformation result = new PhiElementTypeInformation(
@@ -582,10 +566,8 @@
     return result;
   }
 
-  /**
-   * Returns a new type for holding the potential types of [element].
-   * [inputType] is the first incoming type of the phi.
-   */
+  /// Returns a new type for holding the potential types of [element].
+  /// [inputType] is the first incoming type of the phi.
   PhiElementTypeInformation allocatePhi(
       ir.Node node, Local variable, TypeInformation inputType,
       {bool isTry}) {
@@ -601,13 +583,11 @@
     return _addPhi(node, variable, inputType, isTry);
   }
 
-  /**
-   * Returns a new type for holding the potential types of [element].
-   * [inputType] is the first incoming type of the phi. [allocateLoopPhi]
-   * only differs from [allocatePhi] in that it allows the underlying
-   * implementation of [TypeSystem] to differentiate Phi nodes due to loops
-   * from other merging uses.
-   */
+  /// Returns a new type for holding the potential types of [element].
+  /// [inputType] is the first incoming type of the phi. [allocateLoopPhi]
+  /// only differs from [allocatePhi] in that it allows the underlying
+  /// implementation of [TypeSystem] to differentiate Phi nodes due to loops
+  /// from other merging uses.
   PhiElementTypeInformation allocateLoopPhi(
       ir.Node node, Local variable, TypeInformation inputType,
       {bool isTry}) {
@@ -615,12 +595,10 @@
     return _addPhi(node, variable, inputType, isTry);
   }
 
-  /**
-   * Simplies the phi representing [element] and of the type
-   * [phiType]. For example, if this phi has one incoming input, an
-   * implementation of this method could just return that incoming
-   * input type.
-   */
+  /// Simplies the phi representing [element] and of the type
+  /// [phiType]. For example, if this phi has one incoming input, an
+  /// implementation of this method could just return that incoming
+  /// input type.
   TypeInformation simplifyPhi(
       ir.Node node, Local variable, PhiElementTypeInformation phiType) {
     assert(phiType.branchNode == node);
@@ -628,9 +606,7 @@
     return phiType;
   }
 
-  /**
-   * Adds [newType] as an input of [phiType].
-   */
+  /// Adds [newType] as an input of [phiType].
   PhiElementTypeInformation addPhiInput(Local variable,
       PhiElementTypeInformation phiType, TypeInformation newType) {
     phiType.addAssignment(newType);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
index 8b67ca6..8463350 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
@@ -4,14 +4,12 @@
 
 part of masks;
 
-/**
- * A [DictionaryTypeMask] is a [TypeMask] for a specific allocation
- * site of a map (currently only internal Map class) that is used as
- * a dictionary, i.e. a mapping from a set of statically known strings
- * to values. These typemasks only come into existence after the
- * [TypeGraphInferrer] has successfully identified such a usage. Otherwise,
- * the more general [MapTypeMask] is used.
- */
+/// A [DictionaryTypeMask] is a [TypeMask] for a specific allocation
+/// site of a map (currently only internal Map class) that is used as
+/// a dictionary, i.e. a mapping from a set of statically known strings
+/// to values. These typemasks only come into existence after the
+/// [TypeGraphInferrer] has successfully identified such a usage. Otherwise,
+/// the more general [MapTypeMask] is used.
 class DictionaryTypeMask extends MapTypeMask {
   /// Tag used for identifying serialized [DictionaryTypeMask] objects in a
   /// debugging data stream.
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
index 2dfe38a..41db5e8 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
@@ -4,10 +4,8 @@
 
 part of masks;
 
-/**
- * A flat type mask is a type mask that has been flattened to contain a
- * base type.
- */
+/// A flat type mask is a type mask that has been flattened to contain a
+/// base type.
 class FlatTypeMask implements TypeMask {
   /// Tag used for identifying serialized [FlatTypeMask] objects in a
   /// debugging data stream.
@@ -45,10 +43,8 @@
 
   FlatTypeMask.internal(this.base, this.flags);
 
-  /**
-   * Ensures that the generated mask is normalized, i.e., a call to
-   * [TypeMask.assertIsNormalized] with the factory's result returns `true`.
-   */
+  /// Ensures that the generated mask is normalized, i.e., a call to
+  /// [TypeMask.assertIsNormalized] with the factory's result returns `true`.
   factory FlatTypeMask.normalized(
       ClassEntity base, int flags, JClosedWorld world) {
     if ((flags >> 1) == EMPTY || ((flags >> 1) == EXACT)) {
@@ -260,9 +256,7 @@
     }
   }
 
-  /**
-   * Returns whether or not this type mask contains all types.
-   */
+  /// Returns whether or not this type mask contains all types.
   bool containsAll(JClosedWorld closedWorld) {
     if (isEmptyOrNull || isExact) return false;
     return identical(base, closedWorld.commonElements.objectClass);
@@ -519,11 +513,9 @@
         : new TypeMask.nonNullEmpty();
   }
 
-  /**
-   * Returns whether [element] is a potential target when being
-   * invoked on this type mask. [selector] is used to ensure library
-   * privacy is taken into account.
-   */
+  /// Returns whether [element] is a potential target when being
+  /// invoked on this type mask. [selector] is used to ensure library
+  /// privacy is taken into account.
   bool canHit(MemberEntity element, Name name, JClosedWorld closedWorld) {
     CommonElements commonElements = closedWorld.commonElements;
     assert(element.name == name.text);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
index 781a51e..7b8e73a 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
@@ -4,10 +4,8 @@
 
 part of masks;
 
-/**
- * A type mask that wraps an other one, and delegate all its
- * implementation methods to it.
- */
+/// A type mask that wraps an other one, and delegate all its
+/// implementation methods to it.
 abstract class ForwardingTypeMask implements TypeMask {
   TypeMask get forwardTo;
 
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
index 4a59fcd..2486256 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
@@ -4,11 +4,9 @@
 
 part of masks;
 
-/**
- * A [MapTypeMask] is a [TypeMask] for a specific allocation
- * site of a map (currently only internal Map class) that will get specialized
- * once the [TypeGraphInferrer] phase finds a key and/or value type for it.
- */
+/// A [MapTypeMask] is a [TypeMask] for a specific allocation
+/// site of a map (currently only internal Map class) that will get specialized
+/// once the [TypeGraphInferrer] phase finds a key and/or value type for it.
 class MapTypeMask extends AllocationTypeMask {
   /// Tag used for identifying serialized [MapTypeMask] objects in a
   /// debugging data stream.
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
index eb06347..d54859d 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
@@ -103,11 +103,9 @@
   value,
 }
 
-/**
- * A type mask represents a set of contained classes, but the
- * operations on it are not guaranteed to be precise and they may
- * yield conservative answers that contain too many classes.
- */
+/// A type mask represents a set of contained classes, but the
+/// operations on it are not guaranteed to be precise and they may
+/// yield conservative answers that contain too many classes.
 abstract class TypeMask implements AbstractValue {
   factory TypeMask(
       ClassEntity base, int kind, bool isNullable, JClosedWorld closedWorld) {
@@ -245,10 +243,8 @@
   /// Serializes this [TypeMask] to [sink].
   void writeToDataSink(DataSink sink);
 
-  /**
-   * If [mask] is forwarding, returns the first non-forwarding [TypeMask] in
-   * [mask]'s forwarding chain.
-   */
+  /// If [mask] is forwarding, returns the first non-forwarding [TypeMask] in
+  /// [mask]'s forwarding chain.
   static TypeMask nonForwardingMask(mask) {
     while (mask.isForwarding) {
       mask = mask.forwardTo;
@@ -256,13 +252,11 @@
     return mask;
   }
 
-  /**
-   * Asserts that this mask uses the smallest possible representation for
-   * its types. Currently, we normalize subtype and subclass to exact if no
-   * subtypes or subclasses are present and subtype to subclass if only
-   * subclasses exist. We also normalize exact to empty if the corresponding
-   * baseclass was never instantiated.
-   */
+  /// Asserts that this mask uses the smallest possible representation for
+  /// its types. Currently, we normalize subtype and subclass to exact if no
+  /// subtypes or subclasses are present and subtype to subclass if only
+  /// subclasses exist. We also normalize exact to empty if the corresponding
+  /// baseclass was never instantiated.
   static bool assertIsNormalized(TypeMask mask, JClosedWorld closedWorld) {
     String reason = getNotNormalizedReason(mask, closedWorld);
     assert(reason == null,
@@ -307,14 +301,10 @@
     return 'Unknown type mask $mask.';
   }
 
-  /**
-   * Returns a nullable variant of [this] type mask.
-   */
+  /// Returns a nullable variant of [this] type mask.
   TypeMask nullable();
 
-  /**
-   * Returns a non-nullable variant of [this] type mask.
-   */
+  /// Returns a non-nullable variant of [this] type mask.
   TypeMask nonNullable();
 
   /// Whether nothing matches this mask, not even null.
@@ -361,38 +351,28 @@
   bool containsOnlyString(JClosedWorld closedWorld);
   bool containsOnly(ClassEntity cls);
 
-  /**
-   * Compares two [TypeMask] objects for structural equality.
-   *
-   * Note: This may differ from semantic equality in the set containment sense.
-   *   Use [containsMask] and [isInMask] for that, instead.
-   */
+  /// Compares two [TypeMask] objects for structural equality.
+  ///
+  /// Note: This may differ from semantic equality in the set containment sense.
+  ///   Use [containsMask] and [isInMask] for that, instead.
   bool operator ==(other);
 
-  /**
-   * If this returns `true`, [other] is guaranteed to be a supertype of this
-   * mask, i.e., this mask is in [other]. However, the inverse does not hold.
-   * Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of
-   * false negatives.
-   */
+  /// If this returns `true`, [other] is guaranteed to be a supertype of this
+  /// mask, i.e., this mask is in [other]. However, the inverse does not hold.
+  /// Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of
+  /// false negatives.
   bool isInMask(TypeMask other, JClosedWorld closedWorld);
 
-  /**
-   * If this returns `true`, [other] is guaranteed to be a subtype of this mask,
-   * i.e., this mask contains [other]. However, the inverse does not hold.
-   * Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of
-   * false negatives.
-   */
+  /// If this returns `true`, [other] is guaranteed to be a subtype of this
+  /// mask, i.e. this mask contains [other]. However, the inverse does not hold.
+  /// Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of
+  /// false negatives.
   bool containsMask(TypeMask other, JClosedWorld closedWorld);
 
-  /**
-   * Returns whether this type mask is an instance of [cls].
-   */
+  /// Returns whether this type mask is an instance of [cls].
   bool satisfies(ClassEntity cls, JClosedWorld closedWorld);
 
-  /**
-   * Returns whether or not this type mask contains the given class [cls].
-   */
+  /// Returns whether or not this type mask contains the given class [cls].
   bool contains(ClassEntity cls, JClosedWorld closedWorld);
 
   /// Returns whether or not this type mask contains all types.
@@ -402,17 +382,13 @@
   /// otherwise returns `null`.  This method is conservative.
   ClassEntity singleClass(JClosedWorld closedWorld);
 
-  /**
-   * Returns a type mask representing the union of [this] and [other].
-   */
+  /// Returns a type mask representing the union of [this] and [other].
   TypeMask union(TypeMask other, JClosedWorld closedWorld);
 
   /// Returns whether the intersection of this and [other] is empty.
   bool isDisjoint(TypeMask other, JClosedWorld closedWorld);
 
-  /**
-   * Returns a type mask representing the intersection of [this] and [other].
-   */
+  /// Returns a type mask representing the intersection of [this] and [other].
   TypeMask intersection(TypeMask other, JClosedWorld closedWorld);
 
   /// Returns whether [element] is a potential target when being invoked on this
@@ -423,9 +399,7 @@
   /// [noSuchMethod].
   bool needsNoSuchMethodHandling(Selector selector, JClosedWorld world);
 
-  /**
-   * Returns the [element] that is known to always be hit at runtime
-   * on this mask. Returns null if there is none.
-   */
+  /// Returns the [element] that is known to always be hit at runtime
+  /// on this mask. Returns null if there is none.
   MemberEntity locateSingleMember(Selector selector, JClosedWorld closedWorld);
 }
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
index 0d252f0..2f1f9de 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
@@ -232,14 +232,12 @@
   bool get isForwarding => false;
   bool get isValue => false;
 
-  /**
-   * Checks whether [other] is contained in this union.
-   *
-   * Invariants:
-   * - [other] may not be a [UnionTypeMask] itself
-   * - the cheap test matching against individual members of [disjointMasks]
-   *   must have failed.
-   */
+  /// Checks whether [other] is contained in this union.
+  ///
+  /// Invariants:
+  /// - [other] may not be a [UnionTypeMask] itself
+  /// - the cheap test matching against individual members of [disjointMasks]
+  ///   must have failed.
   bool slowContainsCheck(TypeMask other, JClosedWorld closedWorld) {
     // Unions should never make it here.
     assert(!other.isUnion);
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 4fb641a..0d3b387 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -549,6 +549,7 @@
             CallPosition.getSemanticPositionForCall(node);
         registerPosition(callPosition.sourcePositionKind);
         break;
+      case StepKind.ACCESS:
       case StepKind.NEW:
       case StepKind.RETURN:
       case StepKind.BREAK:
@@ -771,6 +772,7 @@
   FUN_EXIT,
   CALL,
   NEW,
+  ACCESS,
   RETURN,
   BREAK,
   CONTINUE,
@@ -1010,6 +1012,18 @@
   @override
   visitAccess(js.PropertyAccess node) {
     visit(node.receiver);
+    notifyStep(
+        node,
+        // Technically we'd like to use the offset of the `.` in the property
+        // access, but the js_ast doesn't expose it. Since this is only used to
+        // search backwards for inlined frames, we use the receiver's END offset
+        // instead as an approximation. Note that the END offset points one
+        // character after the end of the node, so it is likely always the
+        // offset we want.
+        getOffsetForNode(
+            node, getSyntaxOffset(node.receiver, kind: CodePositionKind.END)),
+        StepKind.ACCESS);
+    steps.add(node);
     visit(node.selector);
   }
 
diff --git a/pkg/compiler/lib/src/ir/cached_static_type.dart b/pkg/compiler/lib/src/ir/cached_static_type.dart
index 19ff07f..5daea39 100644
--- a/pkg/compiler/lib/src/ir/cached_static_type.dart
+++ b/pkg/compiler/lib/src/ir/cached_static_type.dart
@@ -14,8 +14,10 @@
 /// and a precomputed cache for complex expression type.
 class CachedStaticType extends StaticTypeBase implements StaticTypeProvider {
   final Map<ir.Expression, ir.DartType> _cache;
+  final ThisInterfaceType thisType;
 
-  CachedStaticType(ir.TypeEnvironment typeEnvironment, this._cache)
+  CachedStaticType(
+      ir.TypeEnvironment typeEnvironment, this._cache, this.thisType)
       : super(typeEnvironment);
 
   @override
diff --git a/pkg/compiler/lib/src/ir/impact.dart b/pkg/compiler/lib/src/ir/impact.dart
new file mode 100644
index 0000000..570fa82
--- /dev/null
+++ b/pkg/compiler/lib/src/ir/impact.dart
@@ -0,0 +1,534 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:front_end/src/api_unstable/dart2js.dart'
+    show operatorFromString;
+
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/class_hierarchy.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
+
+import '../common.dart';
+import 'scope.dart';
+import 'static_type.dart';
+import 'static_type_base.dart';
+import 'util.dart';
+
+abstract class ImpactBuilder extends StaticTypeVisitor {
+  final VariableScopeModel variableScopeModel;
+
+  ImpactBuilder(ir.TypeEnvironment typeEnvironment,
+      ir.ClassHierarchy classHierarchy, this.variableScopeModel)
+      : super(typeEnvironment, classHierarchy);
+
+  ClassRelation _computeClassRelationFromType(ir.DartType type) {
+    if (type is ThisInterfaceType) {
+      return ClassRelation.thisExpression;
+    } else if (type is ExactInterfaceType) {
+      return ClassRelation.exact;
+    } else {
+      return ClassRelation.subtype;
+    }
+  }
+
+  void registerIntLiteral(int value);
+
+  @override
+  void handleIntLiteral(ir.IntLiteral node) {
+    registerIntLiteral(node.value);
+  }
+
+  void registerDoubleLiteral(double value);
+
+  @override
+  void handleDoubleLiteral(ir.DoubleLiteral node) {
+    registerDoubleLiteral(node.value);
+  }
+
+  void registerBoolLiteral(bool value);
+
+  @override
+  void handleBoolLiteral(ir.BoolLiteral node) {
+    registerBoolLiteral(node.value);
+  }
+
+  void registerStringLiteral(String value);
+
+  @override
+  void handleStringLiteral(ir.StringLiteral node) {
+    registerStringLiteral(node.value);
+  }
+
+  void registerSymbolLiteral(String value);
+
+  @override
+  void handleSymbolLiteral(ir.SymbolLiteral node) {
+    registerSymbolLiteral(node.value);
+  }
+
+  void registerNullLiteral();
+
+  @override
+  void handleNullLiteral(ir.NullLiteral node) {
+    registerNullLiteral();
+  }
+
+  void registerListLiteral(ir.DartType elementType,
+      {bool isConstant, bool isEmpty});
+
+  @override
+  void handleListLiteral(ir.ListLiteral node) {
+    registerListLiteral(node.typeArgument,
+        isConstant: node.isConst, isEmpty: node.expressions.isEmpty);
+  }
+
+  void registerMapLiteral(ir.DartType keyType, ir.DartType valueType,
+      {bool isConstant, bool isEmpty});
+
+  @override
+  void handleMapLiteral(ir.MapLiteral node) {
+    registerMapLiteral(node.keyType, node.valueType,
+        isConstant: node.isConst, isEmpty: node.entries.isEmpty);
+  }
+
+  void registerStaticTearOff(
+      ir.Procedure procedure, ir.LibraryDependency import);
+
+  void registerStaticGet(ir.Member member, ir.LibraryDependency import);
+
+  @override
+  void handleStaticGet(ir.StaticGet node, ir.DartType resultType) {
+    ir.Member target = node.target;
+    if (target is ir.Procedure && target.kind == ir.ProcedureKind.Method) {
+      registerStaticTearOff(target, getDeferredImport(node));
+    } else {
+      registerStaticGet(target, getDeferredImport(node));
+    }
+  }
+
+  void registerStaticSet(ir.Member member, ir.LibraryDependency import);
+
+  @override
+  void handleStaticSet(ir.StaticSet node, ir.DartType valueType) {
+    registerStaticSet(node.target, getDeferredImport(node));
+  }
+
+  void registerAssert({bool withMessage});
+
+  @override
+  void handleAssertStatement(ir.AssertStatement node) {
+    registerAssert(withMessage: node.message != null);
+  }
+
+  void registerGenericInstantiation(
+      ir.FunctionType expressionType, List<ir.DartType> typeArguments);
+
+  @override
+  void handleInstantiation(ir.Instantiation node,
+      ir.FunctionType expressionType, ir.DartType resultType) {
+    registerGenericInstantiation(expressionType, node.typeArguments);
+  }
+
+  void registerSyncStar(ir.DartType elementType);
+
+  void registerAsync(ir.DartType elementType);
+
+  void registerAsyncStar(ir.DartType elementType);
+
+  void handleAsyncMarker(ir.FunctionNode function) {
+    ir.AsyncMarker asyncMarker = function.asyncMarker;
+    ir.DartType returnType = function.returnType;
+
+    switch (asyncMarker) {
+      case ir.AsyncMarker.Sync:
+        break;
+      case ir.AsyncMarker.SyncStar:
+        ir.DartType elementType = const ir.DynamicType();
+        if (returnType is ir.InterfaceType) {
+          if (returnType.classNode == typeEnvironment.coreTypes.iterableClass) {
+            elementType = returnType.typeArguments.first;
+          }
+        }
+        registerSyncStar(elementType);
+        break;
+
+      case ir.AsyncMarker.Async:
+        ir.DartType elementType = const ir.DynamicType();
+        if (returnType is ir.InterfaceType) {
+          if (returnType.classNode == typeEnvironment.coreTypes.futureOrClass) {
+            elementType = returnType.typeArguments.first;
+          } else if (returnType.classNode ==
+              typeEnvironment.coreTypes.futureClass) {
+            elementType = returnType.typeArguments.first;
+          }
+        }
+        registerAsync(elementType);
+        break;
+
+      case ir.AsyncMarker.AsyncStar:
+        ir.DartType elementType = const ir.DynamicType();
+        if (returnType is ir.InterfaceType) {
+          if (returnType.classNode == typeEnvironment.coreTypes.streamClass) {
+            elementType = returnType.typeArguments.first;
+          }
+        }
+        registerAsyncStar(elementType);
+        break;
+
+      case ir.AsyncMarker.SyncYielding:
+        failedAt(CURRENT_ELEMENT_SPANNABLE,
+            "Unexpected async marker: ${asyncMarker}");
+    }
+  }
+
+  void registerStringConcatenation();
+
+  @override
+  void handleStringConcatenation(ir.StringConcatenation node) {
+    registerStringConcatenation();
+  }
+
+  void registerLocalFunction(ir.TreeNode node);
+
+  @override
+  Null handleFunctionDeclaration(ir.FunctionDeclaration node) {
+    registerLocalFunction(node);
+    handleAsyncMarker(node.function);
+  }
+
+  @override
+  void handleFunctionExpression(ir.FunctionExpression node) {
+    registerLocalFunction(node);
+    handleAsyncMarker(node.function);
+  }
+
+  void registerLocalWithoutInitializer();
+
+  @override
+  void handleVariableDeclaration(ir.VariableDeclaration node) {
+    if (node.initializer == null) {
+      registerLocalWithoutInitializer();
+    }
+  }
+
+  void registerIsCheck(ir.DartType type);
+
+  @override
+  void handleIsExpression(ir.IsExpression node) {
+    registerIsCheck(node.type);
+  }
+
+  void registerImplicitCast(ir.DartType type);
+
+  void registerAsCast(ir.DartType type);
+
+  @override
+  void handleAsExpression(ir.AsExpression node, ir.DartType operandType) {
+    if (typeEnvironment.isSubtypeOf(operandType, node.type)) {
+      // Skip unneeded casts.
+      return;
+    }
+    if (node.isTypeError) {
+      registerImplicitCast(node.type);
+    } else {
+      registerAsCast(node.type);
+    }
+  }
+
+  void registerThrow();
+
+  @override
+  void handleThrow(ir.Throw node) {
+    registerThrow();
+  }
+
+  void registerSyncForIn(ir.DartType iterableType);
+
+  void registerAsyncForIn(ir.DartType iterableType);
+
+  @override
+  void handleForInStatement(ir.ForInStatement node, ir.DartType iterableType) {
+    if (node.isAsync) {
+      registerAsyncForIn(iterableType);
+    } else {
+      registerSyncForIn(iterableType);
+    }
+  }
+
+  void registerCatch();
+
+  void registerStackTrace();
+
+  void registerCatchType(ir.DartType type);
+
+  @override
+  void handleCatch(ir.Catch node) {
+    registerCatch();
+    if (node.stackTrace != null) {
+      registerStackTrace();
+    }
+    if (node.guard is! ir.DynamicType) {
+      registerCatchType(node.guard);
+    }
+  }
+
+  void registerTypeLiteral(ir.DartType type, ir.LibraryDependency import);
+
+  @override
+  void handleTypeLiteral(ir.TypeLiteral node) {
+    registerTypeLiteral(node.type, getDeferredImport(node));
+  }
+
+  void registerFieldInitializer(ir.Field node);
+
+  @override
+  void handleFieldInitializer(ir.FieldInitializer node) {
+    registerFieldInitializer(node.field);
+  }
+
+  void registerLoadLibrary();
+
+  @override
+  void handleLoadLibrary(ir.LoadLibrary node) {
+    registerLoadLibrary();
+  }
+
+  void registerRedirectingInitializer(
+      ir.Constructor constructor, ir.Arguments arguments);
+
+  void handleRedirectingInitializer(
+      ir.RedirectingInitializer node, ArgumentTypes argumentTypes) {
+    registerRedirectingInitializer(node.target, node.arguments);
+  }
+
+  void registerParameterCheck(ir.DartType type);
+
+  @override
+  void handleParameter(ir.VariableDeclaration parameter) {
+    registerParameterCheck(parameter.type);
+  }
+
+  @override
+  void handleSignature(ir.FunctionNode node) {
+    for (ir.TypeParameter parameter in node.typeParameters) {
+      registerParameterCheck(parameter.bound);
+    }
+  }
+
+  void registerLazyField();
+
+  @override
+  void handleField(ir.Field field) {
+    registerParameterCheck(field.type);
+    if (field.initializer != null) {
+      if (!field.isInstanceMember &&
+          !field.isConst &&
+          field.initializer is! ir.NullLiteral) {
+        registerLazyField();
+      }
+    } else {
+      registerNullLiteral();
+    }
+  }
+
+  @override
+  void handleProcedure(ir.Procedure procedure) {
+    handleAsyncMarker(procedure.function);
+  }
+
+  void registerNew(ir.Member constructor, ir.InterfaceType type,
+      ir.Arguments arguments, ir.LibraryDependency import,
+      {bool isConst});
+
+  @override
+  void handleConstructorInvocation(ir.ConstructorInvocation node,
+      ArgumentTypes argumentTypes, ir.DartType resultType) {
+    registerNew(node.target, node.constructedType, node.arguments,
+        getDeferredImport(node),
+        isConst: node.isConst);
+  }
+
+  void registerStaticInvocation(
+      ir.Procedure target, ir.Arguments arguments, ir.LibraryDependency import);
+
+  @override
+  void handleStaticInvocation(ir.StaticInvocation node,
+      ArgumentTypes argumentTypes, ir.DartType returnType) {
+    if (node.target.kind == ir.ProcedureKind.Factory) {
+      // TODO(johnniwinther): We should not mark the type as instantiated but
+      // rather follow the type arguments directly.
+      //
+      // Consider this:
+      //
+      //    abstract class A<T> {
+      //      factory A.regular() => new B<T>();
+      //      factory A.redirect() = B<T>;
+      //    }
+      //
+      //    class B<T> implements A<T> {}
+      //
+      //    main() {
+      //      print(new A<int>.regular() is B<int>);
+      //      print(new A<String>.redirect() is B<String>);
+      //    }
+      //
+      // To track that B is actually instantiated as B<int> and B<String> we
+      // need to follow the type arguments passed to A.regular and A.redirect
+      // to B. Currently, we only do this soundly if we register A<int> and
+      // A<String> as instantiated. We should instead register that A.T is
+      // instantiated as int and String.
+      registerNew(
+          node.target,
+          new ir.InterfaceType(
+              node.target.enclosingClass, node.arguments.types),
+          node.arguments,
+          getDeferredImport(node),
+          isConst: node.isConst);
+    } else {
+      registerStaticInvocation(
+          node.target, node.arguments, getDeferredImport(node));
+    }
+  }
+
+  void registerLocalFunctionInvocation(
+      ir.FunctionDeclaration localFunction, ir.Arguments arguments);
+
+  void registerDynamicInvocation(ir.DartType receiverType,
+      ClassRelation relation, ir.Name name, ir.Arguments arguments);
+
+  void registerInstanceInvocation(ir.DartType receiverType,
+      ClassRelation relation, ir.Member target, ir.Arguments arguments);
+
+  void registerFunctionInvocation(
+      ir.DartType receiverType, ir.Arguments arguments);
+
+  @override
+  void handleMethodInvocation(
+      ir.MethodInvocation node,
+      ir.DartType receiverType,
+      ArgumentTypes argumentTypes,
+      ir.DartType returnType) {
+    ir.Expression receiver = node.receiver;
+    if (receiver is ir.VariableGet &&
+        receiver.variable.isFinal &&
+        receiver.variable.parent is ir.FunctionDeclaration) {
+      registerLocalFunctionInvocation(receiver.variable.parent, node.arguments);
+    } else {
+      ClassRelation relation = _computeClassRelationFromType(receiverType);
+
+      ir.Member interfaceTarget = node.interfaceTarget;
+      if (interfaceTarget == null) {
+        registerDynamicInvocation(
+            receiverType, relation, node.name, node.arguments);
+        // TODO(johnniwinther): Avoid treating a known function call as a
+        // dynamic call when CFE provides a way to distinguish the two.
+        if (operatorFromString(node.name.name) == null &&
+            receiverType is ir.DynamicType) {
+          // We might implicitly call a getter that returns a function.
+          registerFunctionInvocation(const ir.DynamicType(), node.arguments);
+        }
+      } else {
+        if (interfaceTarget is ir.Field ||
+            interfaceTarget is ir.Procedure &&
+                interfaceTarget.kind == ir.ProcedureKind.Getter) {
+          registerInstanceInvocation(
+              receiverType, relation, interfaceTarget, node.arguments);
+          registerFunctionInvocation(
+              interfaceTarget.getterType, node.arguments);
+        } else {
+          registerInstanceInvocation(
+              receiverType, relation, interfaceTarget, node.arguments);
+        }
+      }
+    }
+  }
+
+  @override
+  void handleDirectMethodInvocation(
+      ir.DirectMethodInvocation node,
+      ir.DartType receiverType,
+      ArgumentTypes argumentTypes,
+      ir.DartType returnType) {
+    registerInstanceInvocation(
+        receiverType, ClassRelation.exact, node.target, node.arguments);
+  }
+
+  void registerDynamicGet(
+      ir.DartType receiverType, ClassRelation relation, ir.Name name);
+
+  void registerInstanceGet(
+      ir.DartType receiverType, ClassRelation relation, ir.Member target);
+
+  @override
+  void handlePropertyGet(
+      ir.PropertyGet node, ir.DartType receiverType, ir.DartType resultType) {
+    ClassRelation relation = _computeClassRelationFromType(receiverType);
+    if (node.interfaceTarget != null) {
+      registerInstanceGet(receiverType, relation, node.interfaceTarget);
+    } else {
+      registerDynamicGet(receiverType, relation, node.name);
+    }
+  }
+
+  @override
+  void handleDirectPropertyGet(ir.DirectPropertyGet node,
+      ir.DartType receiverType, ir.DartType resultType) {
+    registerInstanceGet(receiverType, ClassRelation.exact, node.target);
+  }
+
+  void registerDynamicSet(
+      ir.DartType receiverType, ClassRelation relation, ir.Name name);
+
+  void registerInstanceSet(
+      ir.DartType receiverType, ClassRelation relation, ir.Member target);
+
+  @override
+  void handlePropertySet(
+      ir.PropertySet node, ir.DartType receiverType, ir.DartType valueType) {
+    ClassRelation relation = _computeClassRelationFromType(receiverType);
+    if (node.interfaceTarget != null) {
+      registerInstanceSet(receiverType, relation, node.interfaceTarget);
+    } else {
+      registerDynamicSet(receiverType, relation, node.name);
+    }
+  }
+
+  @override
+  void handleDirectPropertySet(ir.DirectPropertySet node,
+      ir.DartType receiverType, ir.DartType valueType) {
+    registerInstanceSet(receiverType, ClassRelation.exact, node.target);
+  }
+
+  void registerSuperInvocation(ir.Name name, ir.Arguments arguments);
+
+  @override
+  void handleSuperMethodInvocation(ir.SuperMethodInvocation node,
+      ArgumentTypes argumentTypes, ir.DartType returnType) {
+    registerSuperInvocation(node.name, node.arguments);
+  }
+
+  void registerSuperGet(ir.Name name);
+
+  @override
+  void handleSuperPropertyGet(
+      ir.SuperPropertyGet node, ir.DartType resultType) {
+    registerSuperGet(node.name);
+  }
+
+  void registerSuperSet(ir.Name name);
+
+  @override
+  void handleSuperPropertySet(ir.SuperPropertySet node, ir.DartType valueType) {
+    registerSuperSet(node.name);
+  }
+
+  void registerSuperInitializer(
+      ir.Constructor source, ir.Constructor target, ir.Arguments arguments);
+
+  @override
+  void handleSuperInitializer(
+      ir.SuperInitializer node, ArgumentTypes argumentTypes) {
+    registerSuperInitializer(node.parent, node.target, node.arguments);
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/runtime_type_analysis.dart b/pkg/compiler/lib/src/ir/runtime_type_analysis.dart
similarity index 72%
rename from pkg/compiler/lib/src/kernel/runtime_type_analysis.dart
rename to pkg/compiler/lib/src/ir/runtime_type_analysis.dart
index b5da035..cde8217 100644
--- a/pkg/compiler/lib/src/kernel/runtime_type_analysis.dart
+++ b/pkg/compiler/lib/src/ir/runtime_type_analysis.dart
@@ -1,18 +1,86 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart' as ir;
 
 import '../common/names.dart';
-import '../elements/types.dart';
-import '../ir/util.dart';
-import '../universe/feature.dart';
-import 'element_map.dart';
+import 'util.dart';
 
-/// Computes the [RuntimeTypeUse] corresponding to the `e.runtimeType` [node].
-RuntimeTypeUse computeRuntimeTypeUse(
-    KernelToElementMap elementMap, ir.PropertyGet node) {
+/// Enum for recognized use kinds of `Object.runtimeType`.
+enum RuntimeTypeUseKind {
+  /// Unknown use of `Object.runtimeType`. This is the fallback value if the
+  /// usage didn't match any of the recognized patterns.
+  unknown,
+
+  /// `Object.runtimeType` used in a pattern like
+  /// `a.runtimeType == b.runtimeType`.
+  equals,
+
+  /// `Object.runtimeType` used in a pattern like `'${e.runtimeType}'` or
+  /// `e.runtimeType.toString()`.
+  string,
+}
+
+/// Data object use for computing static type information on uses of
+/// `Object.runtimeType`.
+class RuntimeTypeUseData {
+  /// The use kind of `Object.runtimeType`.
+  final RuntimeTypeUseKind kind;
+
+  /// The property get for the left (or single) occurrence of `.runtimeType`.
+  final ir.PropertyGet leftRuntimeTypeExpression;
+
+  /// The receiver expression.
+  final ir.Expression receiver;
+
+  /// The static type of the receiver expression. This is set in the static type
+  /// visitor.
+  ir.DartType receiverType;
+
+  /// The property get for the right occurrence of `.runtimeType` when [kind]
+  /// is `RuntimeTypeUseKind.equals`.
+  final ir.PropertyGet rightRuntimeTypeExpression;
+
+  /// The argument expression if [kind] is `RuntimeTypeUseKind.equals`.
+  final ir.Expression argument;
+
+  /// The static type of the argument expression. This is set in the static type
+  /// visitor.
+  ir.DartType argumentType;
+
+  RuntimeTypeUseData(this.kind, this.leftRuntimeTypeExpression, this.receiver,
+      this.rightRuntimeTypeExpression, this.argument);
+
+  bool get isComplete {
+    switch (kind) {
+      case RuntimeTypeUseKind.unknown:
+      case RuntimeTypeUseKind.string:
+        return receiverType != null;
+      case RuntimeTypeUseKind.equals:
+        return receiverType != null && argumentType != null;
+    }
+    throw new UnsupportedError("Unexpected RuntimeTypeUseKind $kind.");
+  }
+
+  String toString() {
+    return "RuntimeTypeUseData(kind=$kind,"
+        "receiverGet=$leftRuntimeTypeExpression,receiver=$receiver,"
+        "receiverType=$receiverType,argumentGet=$rightRuntimeTypeExpression,"
+        "argument=$argument,argumentType=$argumentType)";
+  }
+}
+
+/// Computes the [RuntimeTypeUseData] corresponding to the `e.runtimeType`
+/// [node].
+///
+/// [cache] is used to ensure that only one [RuntimeTypeUseData] object is
+/// created per case, even for the `==` case.
+RuntimeTypeUseData computeRuntimeTypeUse(
+    Map<ir.PropertyGet, RuntimeTypeUseData> cache, ir.PropertyGet node) {
+  RuntimeTypeUseData receiverData = cache[node];
+  if (receiverData != null) return receiverData;
+
   /// Returns `true` if [node] is of the form `e.runtimeType`.
   bool isGetRuntimeType(ir.TreeNode node) {
     return node is ir.PropertyGet && node.name.name == Identifiers.runtimeType_;
@@ -32,7 +100,9 @@
   assert(isGetRuntimeType(node));
 
   // TODO(johnniwinther): Special-case `this.runtimeType`.
+  ir.PropertyGet receiverGet;
   ir.Expression receiver;
+  ir.PropertyGet argumentGet;
   ir.Expression argument;
   RuntimeTypeUseKind kind;
 
@@ -65,6 +135,7 @@
           //
           kind = RuntimeTypeUseKind.string;
           receiver = nullAware.receiver;
+          receiverGet = node;
         }
       } else if (nullAware.parent is ir.MethodInvocation) {
         ir.MethodInvocation methodInvocation = nullAware.parent;
@@ -87,7 +158,9 @@
             //        .==(e1.runtimeType)
             kind = RuntimeTypeUseKind.equals;
             receiver = nullAware.receiver;
+            receiverGet = node;
             argument = otherGetRuntimeType.receiver;
+            argumentGet = methodInvocation.arguments.positional.first;
           }
 
           NullAwareExpression otherNullAware = getNullAwareExpression(
@@ -106,7 +179,9 @@
             //
             kind = RuntimeTypeUseKind.equals;
             receiver = nullAware.receiver;
+            receiverGet = node;
             argument = otherNullAware.receiver;
+            argumentGet = otherNullAware.expression;
           }
         } else if (isInvokeToString(nullAware.parent)) {
           // Detected
@@ -121,6 +196,7 @@
           //
           kind = RuntimeTypeUseKind.string;
           receiver = nullAware.receiver;
+          receiverGet = node;
         }
       } else if (nullAware.parent is ir.Arguments &&
           nullAware.parent.parent is ir.MethodInvocation) {
@@ -146,7 +222,9 @@
             //                                                  ^
             kind = RuntimeTypeUseKind.equals;
             receiver = otherGetRuntimeType.receiver;
+            receiverGet = otherGetRuntimeType;
             argument = nullAware.receiver;
+            argumentGet = node;
           }
 
           if (otherNullAware != null &&
@@ -162,7 +240,9 @@
             //                                                      ^
             kind = RuntimeTypeUseKind.equals;
             receiver = otherNullAware.receiver;
+            receiverGet = otherNullAware.expression;
             argument = nullAware.receiver;
+            argumentGet = node;
           }
         }
       } else if (nullAware.parent is ir.StringConcatenation) {
@@ -176,6 +256,7 @@
         //                                                ^
         kind = RuntimeTypeUseKind.string;
         receiver = nullAware.receiver;
+        receiverGet = node;
       } else {
         // Default to unknown
         //
@@ -187,6 +268,7 @@
         //                                         ^
         kind = RuntimeTypeUseKind.unknown;
         receiver = nullAware.receiver;
+        receiverGet = node;
       }
     }
   } else if (node.parent is ir.VariableDeclaration &&
@@ -203,6 +285,7 @@
       //                 ^
       kind = RuntimeTypeUseKind.string;
       receiver = node.receiver;
+      receiverGet = node;
     }
   } else if (node.parent is ir.MethodInvocation) {
     ir.MethodInvocation methodInvocation = node.parent;
@@ -225,7 +308,9 @@
         //        ^
         kind = RuntimeTypeUseKind.equals;
         receiver = node.receiver;
+        receiverGet = node;
         argument = otherGetRuntimeType.receiver;
+        argumentGet = otherGetRuntimeType;
       } else if (nullAware != null && isGetRuntimeType(nullAware.expression)) {
         // Detected
         //
@@ -238,7 +323,9 @@
         //         let #t1 = e1 in #t1 == null ? null : #t1.runtimeType)
         kind = RuntimeTypeUseKind.equals;
         receiver = node.receiver;
+        receiverGet = node;
         argument = nullAware.receiver;
+        argumentGet = nullAware.expression;
       }
     } else if (isInvokeToString(node.parent)) {
       // Detected
@@ -247,6 +334,7 @@
       //       ^
       kind = RuntimeTypeUseKind.string;
       receiver = node.receiver;
+      receiverGet = node;
     }
   } else if (node.parent is ir.Arguments &&
       node.parent.parent is ir.MethodInvocation) {
@@ -270,7 +358,9 @@
         //                          ^
         kind = RuntimeTypeUseKind.equals;
         receiver = otherGetRuntimeType.receiver;
+        receiverGet = otherGetRuntimeType;
         argument = node.receiver;
+        argumentGet = node;
       } else if (nullAware != null && isGetRuntimeType(nullAware.expression)) {
         // Detected
         //
@@ -283,7 +373,9 @@
         //                ^
         kind = RuntimeTypeUseKind.equals;
         receiver = nullAware.receiver;
+        receiverGet = nullAware.expression;
         argument = node.receiver;
+        argumentGet = node;
       }
     }
   } else if (node.parent is ir.StringConcatenation) {
@@ -293,6 +385,7 @@
     //          ^
     kind = RuntimeTypeUseKind.string;
     receiver = node.receiver;
+    receiverGet = node;
   }
 
   if (kind == null) {
@@ -302,10 +395,20 @@
     //       ^
     kind = RuntimeTypeUseKind.unknown;
     receiver = node.receiver;
+    receiverGet = node;
   }
 
-  DartType receiverType = elementMap.getStaticType(receiver);
-  DartType argumentType =
-      argument == null ? null : elementMap.getStaticType(argument);
-  return new RuntimeTypeUse(kind, receiverType, argumentType);
+  RuntimeTypeUseData data = new RuntimeTypeUseData(
+      kind, receiverGet, receiver, argumentGet, argument);
+  cache[receiverGet] = data;
+  if (argumentGet != null) {
+    cache[argumentGet] = data;
+  }
+
+  assert(receiverGet != null, "Missing receiverGet in $data for $node.");
+  assert(!(argument != null && argumentGet == null),
+      "Missing argumentGet in $data for $node.");
+  assert(
+      receiverGet != argumentGet, "Duplicate property get in $data for $node.");
+  return data;
 }
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index 47129b6..9ddc390 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -7,9 +7,11 @@
 import 'package:kernel/core_types.dart' as ir;
 import 'package:kernel/type_algebra.dart' as ir;
 import 'package:kernel/type_environment.dart' as ir;
+import '../common/names.dart';
+import '../util/util.dart';
+import 'runtime_type_analysis.dart';
 import 'scope.dart';
 import 'static_type_base.dart';
-import '../util/util.dart';
 
 /// Enum values for how the target of a static type should be interpreted.
 enum ClassRelation {
@@ -35,8 +37,13 @@
 abstract class StaticTypeVisitor extends StaticTypeBase {
   Map<ir.Expression, ir.DartType> _cache = {};
   Map<ir.Expression, TypeMap> typeMapsForTesting;
+  Map<ir.PropertyGet, RuntimeTypeUseData> _pendingRuntimeTypeUseData = {};
 
-  StaticTypeVisitor(ir.TypeEnvironment typeEnvironment)
+  final ir.ClassHierarchy hierarchy;
+
+  ThisInterfaceType _thisType;
+
+  StaticTypeVisitor(ir.TypeEnvironment typeEnvironment, this.hierarchy)
       : super(typeEnvironment);
 
   Map<ir.Expression, ir.DartType> get cachedStaticTypes => _cache;
@@ -51,7 +58,17 @@
 
   VariableScopeModel get variableScopeModel;
 
-  bool completes(ir.DartType type) => type != const ir.BottomType();
+  ThisInterfaceType get thisType {
+    assert(_thisType != null);
+    return _thisType;
+  }
+
+  void set thisType(ThisInterfaceType value) {
+    assert(value == null || _thisType == null);
+    _thisType = value;
+  }
+
+  bool completes(ir.DartType type) => type != const DoesNotCompleteType();
 
   Set<ir.VariableDeclaration> _currentVariables;
   Set<ir.VariableDeclaration> _invalidatedVariables =
@@ -148,7 +165,7 @@
     }
     if (type is ir.InterfaceType) {
       ir.InterfaceType upcastType =
-          typeEnvironment.hierarchy.getTypeAsInstanceOf(type, superclass);
+          typeEnvironment.getTypeAsInstanceOf(type, superclass);
       if (upcastType != null) return upcastType;
     } else if (type is ir.BottomType) {
       return superclass.bottomType;
@@ -165,8 +182,8 @@
       ir.PropertyGet node, ir.DartType receiverType) {
     ir.Member interfaceTarget = node.interfaceTarget;
     if (interfaceTarget == null && receiverType is ir.InterfaceType) {
-      interfaceTarget = node.interfaceTarget = typeEnvironment.hierarchy
-          .getInterfaceMember(receiverType.classNode, node.name);
+      interfaceTarget = node.interfaceTarget =
+          hierarchy.getInterfaceMember(receiverType.classNode, node.name);
     }
     if (interfaceTarget != null) {
       ir.Class superclass = interfaceTarget.enclosingClass;
@@ -187,6 +204,9 @@
   void handlePropertyGet(
       ir.PropertyGet node, ir.DartType receiverType, ir.DartType resultType) {}
 
+  void handleRuntimeTypeUse(ir.PropertyGet node, RuntimeTypeUseKind kind,
+      ir.DartType receiverType, ir.DartType argumentType) {}
+
   @override
   ir.DartType visitPropertyGet(ir.PropertyGet node) {
     ir.DartType receiverType = visitNode(node.receiver);
@@ -194,6 +214,31 @@
         _cache[node] = _computePropertyGetType(node, receiverType);
     receiverType = _narrowInstanceReceiver(node.interfaceTarget, receiverType);
     handlePropertyGet(node, receiverType, resultType);
+    if (node.name.name == Identifiers.runtimeType_) {
+      RuntimeTypeUseData data =
+          computeRuntimeTypeUse(_pendingRuntimeTypeUseData, node);
+      if (data.leftRuntimeTypeExpression == node) {
+        // [node] is the left (or single) occurrence of `.runtimeType` so we
+        // can set the static type of the receiver expression.
+        data.receiverType = receiverType;
+      } else {
+        // [node] is the right occurrence of `.runtimeType` so we
+        // can set the static type of the argument expression.
+        assert(data.rightRuntimeTypeExpression == node,
+            "Unexpected RuntimeTypeUseData for $node: $data");
+        data.argumentType = receiverType;
+      }
+      if (data.isComplete) {
+        /// We now have all need static types so we can remove the data from
+        /// the cache and handle the runtime type use.
+        _pendingRuntimeTypeUseData.remove(data.leftRuntimeTypeExpression);
+        if (data.rightRuntimeTypeExpression != null) {
+          _pendingRuntimeTypeUseData.remove(data.rightRuntimeTypeExpression);
+        }
+        handleRuntimeTypeUse(
+            node, data.kind, data.receiverType, data.argumentType);
+      }
+    }
     return resultType;
   }
 
@@ -205,7 +250,7 @@
     ir.DartType receiverType = visitNode(node.receiver);
     ir.DartType valueType = super.visitPropertySet(node);
     if (node.interfaceTarget == null && receiverType is ir.InterfaceType) {
-      node.interfaceTarget = typeEnvironment.hierarchy
+      node.interfaceTarget = hierarchy
           .getInterfaceMember(receiverType.classNode, node.name, setter: true);
     }
     receiverType = _narrowInstanceReceiver(node.interfaceTarget, receiverType);
@@ -388,8 +433,8 @@
       interfaceTarget = node.interfaceTarget = objectEquals;
     }
     if (interfaceTarget == null && receiverType is ir.InterfaceType) {
-      ir.Member member = typeEnvironment.hierarchy
-          .getInterfaceMember(receiverType.classNode, node.name);
+      ir.Member member =
+          hierarchy.getInterfaceMember(receiverType.classNode, node.name);
       if (_isApplicable(node.arguments, member)) {
         interfaceTarget = node.interfaceTarget = member;
       }
@@ -428,7 +473,7 @@
     if (node.name.name == 'call') {
       if (receiverType is ir.FunctionType) {
         if (receiverType.typeParameters.length != node.arguments.types.length) {
-          return const ir.BottomType();
+          return const DoesNotCompleteType();
         }
         return ir.Substitution.fromPairs(
                 receiverType.typeParameters, node.arguments.types)
@@ -582,8 +627,8 @@
   ir.DartType visitConstructorInvocation(ir.ConstructorInvocation node) {
     ArgumentTypes argumentTypes = _visitArguments(node.arguments);
     ir.DartType resultType = node.arguments.types.isEmpty
-        ? node.target.enclosingClass.rawType
-        : new ir.InterfaceType(
+        ? new ExactInterfaceType.from(node.target.enclosingClass.rawType)
+        : new ExactInterfaceType(
             node.target.enclosingClass, node.arguments.types);
     _cache[node] = resultType;
     handleConstructorInvocation(node, argumentTypes, resultType);
@@ -604,8 +649,8 @@
       if (declaringClass.typeParameters.isEmpty) {
         resultType = node.interfaceTarget.getterType;
       } else {
-        ir.DartType receiver = typeEnvironment.hierarchy
-            .getTypeAsInstanceOf(typeEnvironment.thisType, declaringClass);
+        ir.DartType receiver =
+            typeEnvironment.getTypeAsInstanceOf(thisType, declaringClass);
         resultType = ir.Substitution.fromInterfaceType(receiver)
             .substituteType(node.interfaceTarget.getterType);
       }
@@ -637,8 +682,8 @@
       returnType = const ir.DynamicType();
     } else {
       ir.Class superclass = node.interfaceTarget.enclosingClass;
-      ir.InterfaceType receiverType = typeEnvironment.hierarchy
-          .getTypeAsInstanceOf(typeEnvironment.thisType, superclass);
+      ir.InterfaceType receiverType =
+          typeEnvironment.getTypeAsInstanceOf(thisType, superclass);
       returnType = ir.Substitution.fromInterfaceType(receiverType)
           .substituteType(node.interfaceTarget.function.returnType);
       returnType = ir.Substitution.fromPairs(
@@ -709,14 +754,14 @@
       return null;
     } else {
       typeMap = afterThen.join(afterOtherwise);
-      return const ir.BottomType();
+      return const DoesNotCompleteType();
     }
   }
 
   @override
   ir.DartType visitConditionalExpression(ir.ConditionalExpression node) {
-    // TODO(johnniwinther): Should we return `const ir.BottomType()` if both
-    // branches are failing?
+    // TODO(johnniwinther): Should we return `const DoesNotCompleteType()` if
+    // both branches are failing?
     _handleConditional(node.condition, node.then, node.otherwise);
     return super.visitConditionalExpression(node);
   }
@@ -766,12 +811,15 @@
 
   @override
   ir.DartType visitBlock(ir.Block node) {
+    assert(_pendingRuntimeTypeUseData.isEmpty);
     ir.DartType type;
     for (ir.Statement statement in node.statements) {
       if (!completes(visitNode(statement))) {
-        type = const ir.BottomType();
+        type = const DoesNotCompleteType();
       }
     }
+    assert(_pendingRuntimeTypeUseData.isEmpty,
+        "Incomplete RuntimeTypeUseData: $_pendingRuntimeTypeUseData");
     return type;
   }
 
@@ -902,7 +950,7 @@
 
   @override
   ir.DartType visitContinueSwitchStatement(ir.ContinueSwitchStatement node) {
-    return const ir.BottomType();
+    return const DoesNotCompleteType();
   }
 
   @override
@@ -912,7 +960,7 @@
 
   @override
   ir.DartType visitBreakStatement(ir.BreakStatement node) {
-    return const ir.BottomType();
+    return const DoesNotCompleteType();
   }
 
   @override
@@ -1028,7 +1076,7 @@
   @override
   ir.DartType visitReturnStatement(ir.ReturnStatement node) {
     visitNode(node.expression);
-    return const ir.BottomType();
+    return const DoesNotCompleteType();
   }
 
   @override
@@ -1122,22 +1170,21 @@
 
   @override
   Null visitProcedure(ir.Procedure node) {
-    typeEnvironment.thisType =
-        node.enclosingClass != null ? node.enclosingClass.thisType : null;
+    thisType = new ThisInterfaceType.from(node.enclosingClass?.thisType);
     _currentVariables = new Set<ir.VariableDeclaration>();
     visitSignature(node.function);
     visitNode(node.function.body);
     handleProcedure(node);
     _invalidatedVariables.removeAll(_currentVariables);
     _currentVariables = null;
-    typeEnvironment.thisType = null;
+    thisType = null;
   }
 
   void handleConstructor(ir.Constructor node) {}
 
   @override
   Null visitConstructor(ir.Constructor node) {
-    typeEnvironment.thisType = node.enclosingClass.thisType;
+    thisType = new ThisInterfaceType.from(node.enclosingClass.thisType);
     _currentVariables = new Set<ir.VariableDeclaration>();
     visitSignature(node.function);
     visitNodes(node.initializers);
@@ -1145,18 +1192,17 @@
     handleConstructor(node);
     _invalidatedVariables.removeAll(_currentVariables);
     _currentVariables = null;
-    typeEnvironment.thisType = null;
+    thisType = null;
   }
 
   void handleField(ir.Field node) {}
 
   @override
   Null visitField(ir.Field node) {
-    typeEnvironment.thisType =
-        node.enclosingClass != null ? node.enclosingClass.thisType : null;
+    thisType = new ThisInterfaceType.from(node.enclosingClass?.thisType);
     visitNode(node.initializer);
     handleField(node);
-    typeEnvironment.thisType = null;
+    thisType = null;
   }
 
   void handleVariableDeclaration(ir.VariableDeclaration node) {}
@@ -1227,7 +1273,8 @@
           // We cannot promote. No single type is most specific.
           // TODO(johnniwinther): Compute implied types? For instance when the
           // declared type is `Iterable<String>` and tested type is
-          // `List<dynamic>` we could promote to the implied type `List<String>`.
+          // `List<dynamic>` we could promote to the implied type
+          // `List<String>`.
           return null;
         }
       }
diff --git a/pkg/compiler/lib/src/ir/static_type_base.dart b/pkg/compiler/lib/src/ir/static_type_base.dart
index 508c4d0..20cf00c 100644
--- a/pkg/compiler/lib/src/ir/static_type_base.dart
+++ b/pkg/compiler/lib/src/ir/static_type_base.dart
@@ -8,6 +8,41 @@
 import 'package:kernel/type_algebra.dart' as ir;
 import 'package:kernel/type_environment.dart' as ir;
 
+/// Special bottom type used to signal that an expression or statement does
+/// not complete normally. This is the case for instance of throw expressions
+/// and return statements.
+class DoesNotCompleteType extends ir.BottomType {
+  const DoesNotCompleteType();
+
+  String toString() => 'DoesNotCompleteType()';
+}
+
+/// Special interface type used to signal that the static type of an expression
+/// has precision of a this-expression.
+class ThisInterfaceType extends ir.InterfaceType {
+  ThisInterfaceType(ir.Class classNode, [List<ir.DartType> typeArguments])
+      : super(classNode, typeArguments);
+
+  factory ThisInterfaceType.from(ir.InterfaceType type) => type != null
+      ? new ThisInterfaceType(type.classNode, type.typeArguments)
+      : null;
+
+  String toString() => 'this:${super.toString()}';
+}
+
+/// Special interface type used to signal that the static type of an expression
+/// is exact, i.e. the runtime type is not a subtype or subclass of the type.
+class ExactInterfaceType extends ir.InterfaceType {
+  ExactInterfaceType(ir.Class classNode, [List<ir.DartType> typeArguments])
+      : super(classNode, typeArguments);
+
+  factory ExactInterfaceType.from(ir.InterfaceType type) => type != null
+      ? new ExactInterfaceType(type.classNode, type.typeArguments)
+      : null;
+
+  String toString() => 'exact:${super.toString()}';
+}
+
 /// Base class for computing static types.
 ///
 /// This class uses the visitor pattern to compute the static type that are
@@ -18,7 +53,7 @@
 /// expression kind. For instance method invocations whose static type depend
 /// on the static types of the receiver and type arguments and the signature
 /// of the targeted procedure.
-class StaticTypeBase extends ir.Visitor<ir.DartType> {
+abstract class StaticTypeBase extends ir.Visitor<ir.DartType> {
   final ir.TypeEnvironment _typeEnvironment;
 
   StaticTypeBase(this._typeEnvironment);
@@ -27,6 +62,8 @@
 
   ir.TypeEnvironment get typeEnvironment => _typeEnvironment;
 
+  ThisInterfaceType get thisType;
+
   @override
   ir.DartType defaultNode(ir.Node node) {
     return null;
@@ -73,7 +110,7 @@
   }
 
   @override
-  ir.DartType visitNullLiteral(ir.NullLiteral node) => const ir.BottomType();
+  ir.DartType visitNullLiteral(ir.NullLiteral node) => typeEnvironment.nullType;
 
   @override
   ir.DartType visitIntLiteral(ir.IntLiteral node) => typeEnvironment.intType;
@@ -112,8 +149,7 @@
   }
 
   @override
-  ir.DartType visitThisExpression(ir.ThisExpression node) =>
-      typeEnvironment.thisType;
+  ThisInterfaceType visitThisExpression(ir.ThisExpression node) => thisType;
 
   @override
   ir.DartType visitStaticGet(ir.StaticGet node) => node.target.getterType;
@@ -129,10 +165,10 @@
   }
 
   @override
-  ir.DartType visitThrow(ir.Throw node) => const ir.BottomType();
+  ir.DartType visitThrow(ir.Throw node) => const DoesNotCompleteType();
 
   @override
-  ir.DartType visitRethrow(ir.Rethrow node) => const ir.BottomType();
+  ir.DartType visitRethrow(ir.Rethrow node) => const DoesNotCompleteType();
 
   @override
   ir.DartType visitLogicalExpression(ir.LogicalExpression node) =>
@@ -168,7 +204,7 @@
 
   @override
   ir.DartType visitInvalidExpression(ir.InvalidExpression node) =>
-      const ir.BottomType();
+      const DoesNotCompleteType();
 
   @override
   ir.DartType visitLoadLibrary(ir.LoadLibrary node) {
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 9893f5b..523cd66 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -69,20 +69,20 @@
 
   @override
   void emit(String string) {
+    monitor?.emit(string);
     outBuffer.add(string);
   }
 
   @override
   void enterNode(Node node, int startPosition) {
+    monitor?.enterNode(node, startPosition);
     codePositionListener.onStartPosition(node, startPosition);
   }
 
   @override
   void exitNode(
       Node node, int startPosition, int endPosition, int closingPosition) {
-    if (monitor != null) {
-      monitor.recordAstSize(node, endPosition - startPosition);
-    }
+    monitor?.exitNode(node, startPosition, endPosition, closingPosition);
     codePositionListener.onPositions(
         node, startPosition, endPosition, closingPosition);
   }
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
index f58853e..d191491 100644
--- a/pkg/compiler/lib/src/js/js_debug.dart
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -52,9 +52,7 @@
     openAndCloseNode(node, '${node.runtimeType}', {'value': node.value});
   }
 
-  /**
-   * Pretty-prints given node tree into string.
-   */
+  /// Pretty-prints given node tree into string.
   static String prettyPrint(Node node) {
     var p = new DebugPrinter();
     node.accept(p);
diff --git a/pkg/compiler/lib/src/js_backend/allocator_analysis.dart b/pkg/compiler/lib/src/js_backend/allocator_analysis.dart
index 9312d15..787e64c 100644
--- a/pkg/compiler/lib/src/js_backend/allocator_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/allocator_analysis.dart
@@ -31,12 +31,11 @@
 //     this.x = this.z = null;
 //
 class KAllocatorAnalysis implements AllocatorAnalysis {
-  final CompilerOptions _options;
   final KernelToElementMap _elementMap;
 
   final Map<KField, ConstantValue> _fixedInitializers = {};
 
-  KAllocatorAnalysis(this._options, KernelFrontEndStrategy kernelStrategy)
+  KAllocatorAnalysis(KernelFrontEndStrategy kernelStrategy)
       : _elementMap = kernelStrategy.elementMap;
 
   // Register class during resolution. Use simple syntactic analysis to find
@@ -53,19 +52,13 @@
       if (initializer == null || initializer is ir.NullLiteral) {
         inits[field] = const NullConstantValue();
       } else if (initializer is ir.IntLiteral) {
-        if (_options.useStartupEmitter) {
-          BigInt intValue = BigInt.from(initializer.value).toUnsigned(64);
-          inits[field] = IntConstantValue(intValue);
-        }
+        BigInt intValue = BigInt.from(initializer.value).toUnsigned(64);
+        inits[field] = IntConstantValue(intValue);
       } else if (initializer is ir.BoolLiteral) {
-        if (_options.useStartupEmitter) {
-          inits[field] = BoolConstantValue(initializer.value);
-        }
+        inits[field] = BoolConstantValue(initializer.value);
       } else if (initializer is ir.StringLiteral) {
-        if (_options.useStartupEmitter) {
-          if (initializer.value.length <= 20) {
-            inits[field] = StringConstantValue(initializer.value);
-          }
+        if (initializer.value.length <= 20) {
+          inits[field] = StringConstantValue(initializer.value);
         }
       }
     }
@@ -92,16 +85,15 @@
   static const String tag = 'allocator-analysis';
 
   // --csp and --fast-startup have different constraints to the generated code.
-  final CompilerOptions _options;
   final Map<JField, ConstantValue> _fixedInitializers = {};
 
-  JAllocatorAnalysis._(this._options);
+  JAllocatorAnalysis._();
 
   /// Deserializes a [JAllocatorAnalysis] object from [source].
   factory JAllocatorAnalysis.readFromDataSource(
       DataSource source, CompilerOptions options) {
     source.begin(tag);
-    JAllocatorAnalysis analysis = new JAllocatorAnalysis._(options);
+    JAllocatorAnalysis analysis = new JAllocatorAnalysis._();
     int fieldCount = source.readInt();
     for (int i = 0; i < fieldCount; i++) {
       JField field = source.readMember();
@@ -125,7 +117,7 @@
 
   static JAllocatorAnalysis from(KAllocatorAnalysis kAnalysis,
       JsToFrontendMap map, CompilerOptions options) {
-    var result = new JAllocatorAnalysis._(options);
+    var result = JAllocatorAnalysis._();
 
     kAnalysis._fixedInitializers.forEach((KField kField, ConstantValue value) {
       // TODO(sra): Translate constant, but Null and these primitives do not
@@ -142,11 +134,6 @@
   }
 
   bool get _isEnabled {
-    if (_options.useContentSecurityPolicy && !_options.useStartupEmitter) {
-      // TODO(sra): Refactor csp 'precompiled' constructor generation to allow
-      // in-allocator initialization.
-      return false;
-    }
     return true;
   }
   // TODO(sra): Add way to let injected fields be initialized to a constant in
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 81ea82f..be118eb 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -9,7 +9,8 @@
 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
 import '../common/names.dart' show Uris;
 import '../common/tasks.dart' show CompilerTask;
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
+import '../common_elements.dart'
+    show CommonElements, ElementEnvironment, JElementEnvironment;
 import '../compiler.dart' show Compiler;
 import '../constants/constant_system.dart';
 import '../deferred_load.dart' show DeferredLoadTask;
@@ -312,9 +313,7 @@
 
   CodeEmitterTask emitter;
 
-  /**
-   * The generated code as a js AST for compiled methods.
-   */
+  /// The generated code as a js AST for compiled methods.
   final Map<MemberEntity, jsAst.Expression> generatedCode =
       <MemberEntity, jsAst.Expression>{};
 
@@ -326,9 +325,7 @@
     return _namer;
   }
 
-  /**
-   * Set of classes whose `operator ==` methods handle `null` themselves.
-   */
+  /// Set of classes whose `operator ==` methods handle `null` themselves.
   final Set<ClassEntity> specialOperatorEqClasses = new Set<ClassEntity>();
 
   List<CompilerTask> get tasks {
@@ -387,7 +384,6 @@
 
   JavaScriptBackend(this.compiler,
       {bool generateSourceMap: true,
-      bool useStartupEmitter: false,
       bool useMultiSourceInfo: false,
       bool useNewSourceInfo: false})
       : this.sourceInformationStrategy =
@@ -397,9 +393,7 @@
     _backendUsageBuilder =
         new BackendUsageBuilderImpl(compiler.frontendStrategy);
     _checkedModeHelpers = new CheckedModeHelpers();
-    emitter =
-        new CodeEmitterTask(compiler, generateSourceMap, useStartupEmitter);
-
+    emitter = new CodeEmitterTask(compiler, generateSourceMap);
     noSuchMethodRegistry = new NoSuchMethodRegistryImpl(
         commonElements, compiler.frontendStrategy.createNoSuchMethodResolver());
     functionCompiler = new SsaFunctionCompiler(
@@ -555,7 +549,7 @@
         nativeBasicData,
         _backendUsageBuilder);
     _allocatorResolutionAnalysis =
-        new KAllocatorAnalysis(compiler.options, compiler.frontendStrategy);
+        new KAllocatorAnalysis(compiler.frontendStrategy);
     ClassQueries classQueries = compiler.frontendStrategy.createClassQueries();
     ClassHierarchyBuilder classHierarchyBuilder =
         new ClassHierarchyBuilder(commonElements, classQueries);
@@ -702,11 +696,9 @@
 
   NativeEnqueuer get nativeCodegenEnqueuer => _nativeCodegenEnqueuer;
 
-  /**
-   * Unit test hook that returns code of an element as a String.
-   *
-   * Invariant: [element] must be a declaration element.
-   */
+  /// Unit test hook that returns code of an element as a String.
+  ///
+  /// Invariant: [element] must be a declaration element.
   String getGeneratedCode(MemberEntity element) {
     return jsAst.prettyPrint(generatedCode[element],
         enableMinification: compiler.options.enableMinification);
@@ -719,10 +711,8 @@
     return programSize;
   }
 
-  /**
-   * Returns [:true:] if the checking of [type] is performed directly on the
-   * object and not on an interceptor.
-   */
+  /// Returns [:true:] if the checking of [type] is performed directly on the
+  /// object and not on an interceptor.
   bool hasDirectCheckFor(CommonElements commonElements, DartType type) {
     if (!type.isInterfaceType) return false;
     InterfaceType interfaceType = type;
@@ -810,7 +800,7 @@
 
   jsAst.Expression rewriteAsync(
       CommonElements commonElements,
-      ElementEnvironment elementEnvironment,
+      JElementEnvironment elementEnvironment,
       CodegenRegistry registry,
       FunctionEntity element,
       jsAst.Expression code,
@@ -886,7 +876,7 @@
 
   AsyncRewriter _makeAsyncRewriter(
       CommonElements commonElements,
-      ElementEnvironment elementEnvironment,
+      JElementEnvironment elementEnvironment,
       CodegenRegistry registry,
       FunctionEntity element,
       jsAst.Expression code,
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index efe00d9..39612fd 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -7,6 +7,7 @@
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../frontend_strategy.dart';
+import '../ir/runtime_type_analysis.dart';
 import '../serialization/serialization.dart';
 import '../universe/feature.dart';
 import '../util/util.dart' show Setlet;
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 ed231cc..71bb262 100644
--- a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
@@ -154,12 +154,10 @@
       new Map<String, CheckedModeHelper>.fromIterable(helpers,
           key: (helper) => helper.name);
 
-  /**
-   * Returns the checked mode helper that will be needed to do a type check/type
-   * cast on [type] at runtime. Note that this method is being called both by
-   * the resolver with interface types (int, String, ...), and by the SSA
-   * backend with implementation types (JSInt, JSString, ...).
-   */
+  /// Returns the checked mode helper that will be needed to do a type
+  /// check/type cast on [type] at runtime. Note that this method is being
+  /// called both by the resolver with interface types (int, String, ...), and
+  /// by the SSA backend with implementation types (JSInt, JSString, ...).
   CheckedModeHelper getCheckedModeHelper(
       DartType type, CommonElements commonElements,
       {bool typeCast}) {
@@ -167,11 +165,9 @@
         typeCast: typeCast, nativeCheckOnly: false);
   }
 
-  /**
-   * Returns the native checked mode helper that will be needed to do a type
-   * check/type cast on [type] at runtime. If no native helper exists for
-   * [type], [:null:] is returned.
-   */
+  /// Returns the native checked mode helper that will be needed to do a type
+  /// check/type cast on [type] at runtime. If no native helper exists for
+  /// [type], [:null:] is returned.
   CheckedModeHelper getNativeCheckedModeHelper(
       DartType type, CommonElements commonElements,
       {bool typeCast}) {
@@ -179,10 +175,9 @@
         typeCast: typeCast, nativeCheckOnly: true);
   }
 
-  /**
-   * Returns the checked mode helper for the type check/type cast for [type]. If
-   * [nativeCheckOnly] is [:true:], only names for native helpers are returned.
-   */
+  /// Returns the checked mode helper for the type check/type cast for
+  /// [type]. If [nativeCheckOnly] is [:true:], only names for native helpers
+  /// are returned.
   CheckedModeHelper getCheckedModeHelperInternal(
       DartType type, CommonElements commonElements,
       {bool typeCast, bool nativeCheckOnly}) {
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 7afba73..3fb4475 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -22,13 +22,11 @@
 
 typedef jsAst.Expression _ConstantListGenerator(jsAst.Expression array);
 
-/**
- * Generates the JavaScript expressions for constants.
- *
- * It uses a given [constantReferenceGenerator] to reference nested constants
- * (if there are some). It is hence up to that function to decide which
- * constants should be inlined or not.
- */
+/// Generates the JavaScript expressions for constants.
+///
+/// It uses a given [constantReferenceGenerator] to reference nested constants
+/// (if there are some). It is hence up to that function to decide which
+/// constants should be inlined or not.
 class ConstantEmitter implements ConstantValueVisitor<jsAst.Expression, Null> {
   // Matches blank lines, comment lines and trailing comments that can't be part
   // of a string.
@@ -45,11 +43,9 @@
   final _ConstantReferenceGenerator constantReferenceGenerator;
   final _ConstantListGenerator makeConstantList;
 
-  /**
-   * The given [constantReferenceGenerator] function must, when invoked with a
-   * constant, either return a reference or return its literal expression if it
-   * can be inlined.
-   */
+  /// The given [constantReferenceGenerator] function must, when invoked with a
+  /// constant, either return a reference or return its literal expression if it
+  /// can be inlined.
   ConstantEmitter(
       this._options,
       this._commonElements,
@@ -63,11 +59,9 @@
 
   Emitter get _emitter => _task.emitter;
 
-  /**
-   * Constructs a literal expression that evaluates to the constant. Uses a
-   * canonical name unless the constant can be emitted multiple times (as for
-   * numbers and strings).
-   */
+  /// Constructs a literal expression that evaluates to the constant. Uses a
+  /// canonical name unless the constant can be emitted multiple times (as for
+  /// numbers and strings).
   jsAst.Expression generate(ConstantValue constant) {
     return _visit(constant);
   }
@@ -171,11 +165,9 @@
     }
   }
 
-  /**
-   * Write the contents of the quoted string to a [CodeBuffer] in
-   * a form that is valid as JavaScript string literal content.
-   * The string is assumed quoted by double quote characters.
-   */
+  /// Write the contents of the quoted string to a [CodeBuffer] in
+  /// a form that is valid as JavaScript string literal content.
+  /// The string is assumed quoted by double quote characters.
   @override
   jsAst.Expression visitString(StringConstantValue constant, [_]) {
     return js.escapedString(constant.stringValue, ascii: true);
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 d454cf3..6b9de6a 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -31,14 +31,12 @@
   ConstantSystem get constantSystem => dartConstantSystem;
 }
 
-/**
- * The [JavaScriptConstantCompiler] is used to keep track of compile-time
- * constants, initializations of global and static fields, and default values of
- * optional parameters for the JavaScript interpretation of constants.
- */
+/// The [JavaScriptConstantCompiler] is used to keep track of compile-time
+/// constants, initializations of global and static fields, and default values
+/// of optional parameters for the JavaScript interpretation of constants.
 class JavaScriptConstantCompiler implements BackendConstantEnvironment {
   // TODO(johnniwinther): Move this to the backend constant handler.
-  /** Caches the statics where the initial value cannot be eagerly compiled. */
+  /// Caches the statics where the initial value cannot be eagerly compiled.
   final Set<FieldEntity> lazyStatics = new Set<FieldEntity>();
 
   JavaScriptConstantCompiler();
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 8b0d237..21eabbf 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -28,10 +28,8 @@
   }
 }
 
-/**
- * In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0
- * is treated as if it was the integer 0.
- */
+/// In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0
+/// is treated as if it was the integer 0.
 class JavaScriptBinaryBitOperation implements BinaryOperation {
   final BinaryBitOperation dartBitOperation;
 
@@ -223,10 +221,8 @@
   }
 }
 
-/**
- * Constant system following the semantics for Dart code that has been
- * compiled to JavaScript.
- */
+/// Constant system following the semantics for Dart code that has been
+/// compiled to JavaScript.
 class JavaScriptConstantSystem extends ConstantSystem {
   final BITS32 = new BigInt.from(0xFFFFFFFF);
 
@@ -269,10 +265,8 @@
 
   JavaScriptConstantSystem._internal();
 
-  /**
-   * Returns true if [value] will turn into NaN or infinity
-   * at runtime.
-   */
+  /// Returns true if [value] will turn into NaN or infinity
+  /// at runtime.
   bool integerBecomesNanOrInfinity(BigInt value) {
     double doubleValue = value.toDouble();
     return doubleValue.isNaN || doubleValue.isInfinite;
@@ -411,13 +405,11 @@
 }
 
 class JavaScriptMapConstant extends MapConstantValue {
-  /**
-   * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript
-   * object. It would change the prototype chain.
-   */
+  /// The [PROTO_PROPERTY] must not be used as normal property in any JavaScript
+  /// object. It would change the prototype chain.
   static const String PROTO_PROPERTY = "__proto__";
 
-  /** The dart class implementing constant map literals. */
+  /// The dart class implementing constant map literals.
   static const String DART_CLASS = "ConstantMap";
   static const String DART_STRING_CLASS = "ConstantStringMap";
   static const String DART_PROTO_CLASS = "ConstantProtoMap";
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 4b27e24..79a4453 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -14,43 +14,41 @@
 import 'backend_usage.dart' show BackendUsageBuilder;
 import 'native_data.dart';
 
-/**
- * Support for Custom Elements.
- *
- * The support for custom elements the compiler builds a table that maps the
- * custom element class's [Type] to the interceptor for the class and the
- * constructor(s) for the class.
- *
- * We want the table to contain only the custom element classes used, and we
- * want to avoid resolving and compiling constructors that are not used since
- * that may bring in unused code.  This class controls the resolution and code
- * generation to restrict the impact.
- *
- * The following line of code requires the generation of the generative
- * constructor factory function(s) for FancyButton, and their insertion into the
- * table:
- *
- *     document.register(FancyButton, 'x-fancy-button');
- *
- * We detect this by 'joining' the classes that are referenced as type literals
- * with the classes that are custom elements, enabled by detecting the presence
- * of the table access code used by document.register.
- *
- * We have to be more conservative when the type is unknown, e.g.
- *
- *     document.register(classMirror.reflectedType, tagFromMetadata);
- *
- * and
- *
- *     class Component<T> {
- *       final tag;
- *       Component(this.tag);
- *       void register() => document.register(T, tag);
- *     }
- *     const Component<FancyButton>('x-fancy-button').register();
- *
- * In these cases we conservatively generate all viable entries in the table.
- */
+/// Support for Custom Elements.
+///
+/// The support for custom elements the compiler builds a table that maps the
+/// custom element class's [Type] to the interceptor for the class and the
+/// constructor(s) for the class.
+///
+/// We want the table to contain only the custom element classes used, and we
+/// want to avoid resolving and compiling constructors that are not used since
+/// that may bring in unused code.  This class controls the resolution and code
+/// generation to restrict the impact.
+///
+/// The following line of code requires the generation of the generative
+/// constructor factory function(s) for FancyButton, and their insertion into
+/// the table:
+///
+///     document.register(FancyButton, 'x-fancy-button');
+///
+/// We detect this by 'joining' the classes that are referenced as type literals
+/// with the classes that are custom elements, enabled by detecting the presence
+/// of the table access code used by document.register.
+///
+/// We have to be more conservative when the type is unknown, e.g.
+///
+///     document.register(classMirror.reflectedType, tagFromMetadata);
+///
+/// and
+///
+///     class Component<T> {
+///       final tag;
+///       Component(this.tag);
+///       void register() => document.register(T, tag);
+///     }
+///     const Component<FancyButton>('x-fancy-button').register();
+///
+/// In these cases we conservatively generate all viable entries in the table.
 abstract class CustomElementsAnalysisBase {
   final NativeBasicData _nativeData;
   final ElementEnvironment _elementEnvironment;
diff --git a/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart b/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
index f7e8984..828dd25 100644
--- a/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
+++ b/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
@@ -33,13 +33,11 @@
   }
 }
 
-/**
- * Encapsulates the global state of field naming.
- *
- * The field naming registry allocates names to be used along a path in the
- * inheritance hierarchy of fields, starting with the object class. The actual
- * hierarchy is encoded using instances of [_FieldNamingScope].
- */
+/// Encapsulates the global state of field naming.
+///
+/// The field naming registry allocates names to be used along a path in the
+/// inheritance hierarchy of fields, starting with the object class. The actual
+/// hierarchy is encoded using instances of [_FieldNamingScope].
 class _FieldNamingRegistry {
   final Namer namer;
 
@@ -82,18 +80,16 @@
   }
 }
 
-/**
- * A [_FieldNamingScope] encodes a node in the inheritance tree of the current
- * class hierarchy. The root node typically is the node corresponding to the
- * `Object` class. It is used to assign a unique name to each field of a class.
- * Unique here means unique wrt. all fields along the path back to the root.
- * This is achieved at construction time via the [_fieldNameCounter] field that
- * counts the number of fields on the path to the root node that have been
- * encountered so far.
- *
- * Obviously, this only works if no fields are added to a parent node after its
- * children have added their first field.
- */
+/// A [_FieldNamingScope] encodes a node in the inheritance tree of the current
+/// class hierarchy. The root node typically is the node corresponding to the
+/// `Object` class. It is used to assign a unique name to each field of a class.
+/// Unique here means unique wrt. all fields along the path back to the root.
+/// This is achieved at construction time via the [_fieldNameCounter] field that
+/// counts the number of fields on the path to the root node that have been
+/// encountered so far.
+///
+/// Obviously, this only works if no fields are added to a parent node after its
+/// children have added their first field.
 class _FieldNamingScope {
   final _FieldNamingScope superScope;
   final Entity container;
@@ -160,9 +156,7 @@
     _fieldNameCounter = superScope.inheritanceBasedFieldNameCounter;
   }
 
-  /**
-   * Checks whether [name] is already used in the current scope chain.
-   */
+  /// Checks whether [name] is already used in the current scope chain.
   _isNameUnused(jsAst.Name name) {
     return !names.values.contains(name) &&
         ((superScope == null) || superScope._isNameUnused(name));
@@ -187,15 +181,13 @@
   bool containsField(Entity field) => names.containsKey(field);
 }
 
-/**
- * Field names for mixins have two constraints: They need to be unique in the
- * hierarchy of each application of a mixin and they need to be the same for
- * all applications of a mixin. To achieve this, we use global naming for
- * mixins from the same name pool as fields and add a `$` at the end to ensure
- * they do not collide with normal field names. The `$` sign is typically used
- * as a separator between method names and argument counts and does not appear
- * in generated names themselves.
- */
+/// Field names for mixins have two constraints: They need to be unique in the
+/// hierarchy of each application of a mixin and they need to be the same for
+/// all applications of a mixin. To achieve this, we use global naming for
+/// mixins from the same name pool as fields and add a `$` at the end to ensure
+/// they do not collide with normal field names. The `$` sign is typically used
+/// as a separator between method names and argument counts and does not appear
+/// in generated names themselves.
 class _MixinFieldNamingScope extends _FieldNamingScope {
   int get _localFieldNameCounter => registry.globalCount;
   void set _localFieldNameCounter(int val) {
@@ -218,12 +210,10 @@
   }
 }
 
-/**
- * [BoxFieldElement] fields work differently in that they do not belong to an
- * actual class but an anonymous box associated to a [Local]. As there is no
- * inheritance chain, we do not need to compute fields a priori but can assign
- * names on the fly.
- */
+/// [BoxFieldElement] fields work differently in that they do not belong to an
+/// actual class but an anonymous box associated to a [Local]. As there is no
+/// inheritance chain, we do not need to compute fields a priori but can assign
+/// names on the fly.
 class _BoxFieldNamingScope extends _FieldNamingScope {
   _BoxFieldNamingScope(Local box, _FieldNamingRegistry registry)
       : super.rootScope(box, registry);
diff --git a/pkg/compiler/lib/src/js_backend/minify_namer.dart b/pkg/compiler/lib/src/js_backend/minify_namer.dart
index 3739932..2d772ff 100644
--- a/pkg/compiler/lib/src/js_backend/minify_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/minify_namer.dart
@@ -4,9 +4,7 @@
 
 part of js_backend.namer;
 
-/**
- * Assigns JavaScript identifiers to Dart variables, class-names and members.
- */
+/// Assigns JavaScript identifiers to Dart variables, class-names and members.
 class MinifyNamer extends Namer
     with
         _MinifiedFieldNamer,
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 0fe5bd1..9e7a95b 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -40,103 +40,101 @@
 part 'minify_namer.dart';
 part 'namer_names.dart';
 
-/**
- * Assigns JavaScript identifiers to Dart variables, class-names and members.
- *
- * Names are generated through three stages:
- *
- * 1. Original names and proposed names
- * 2. Disambiguated names (also known as "mangled names")
- * 3. Annotated names
- *
- * Original names are names taken directly from the input.
- *
- * Proposed names are either original names or synthesized names for input
- * elements that do not have original names.
- *
- * Disambiguated names are derived from the above, but are mangled to ensure
- * uniqueness within some namespace (e.g. as fields on the same JS object).
- * In [MinifyNamer], disambiguated names are also minified.
- *
- * Annotated names are names generated from a disambiguated name. Annotated
- * names must be computable at runtime by prefixing/suffixing constant strings
- * onto the disambiguated name.
- *
- * For example, some entity called `x` might be associated with these names:
- *
- *     Original name: `x`
- *
- *     Disambiguated name: `x1` (if something else was called `x`)
- *
- *     Annotated names: `x1`     (field name)
- *                      `get$x1` (getter name)
- *                      `set$x1` (setter name)
- *
- * The [Namer] can choose the disambiguated names, and to some degree the
- * prefix/suffix constants used to construct annotated names. It cannot choose
- * annotated names with total freedom, for example, it cannot choose that the
- * getter for `x1` should be called `getX` -- the annotated names are always
- * built by concatenation.
- *
- * Disambiguated names must be chosen such that none of the annotated names can
- * clash with each other. This may happen even if the disambiguated names are
- * distinct, for example, suppose a field `x` and `get$x` exists in the input:
- *
- *     Original names: `x` and `get$x`
- *
- *     Disambiguated names: `x` and `get$x` (the two names a different)
- *
- *     Annotated names: `x` (field for `x`)
- *                      `get$x` (getter for `x`)
- *                      `get$x` (field for `get$x`)
- *                      `get$get$x` (getter for `get$x`)
- *
- * The getter for `x` clashes with the field name for `get$x`, so the
- * disambiguated names are invalid.
- *
- * Additionally, disambiguated names must be chosen such that all annotated
- * names are valid JavaScript identifiers and do not coincide with a native
- * JavaScript property such as `__proto__`.
- *
- * The following annotated names are generated for instance members, where
- * <NAME> denotes the disambiguated name.
- *
- * 0. The disambiguated name can itself be seen as an annotated name.
- *
- * 1. Multiple annotated names exist for the `call` method, encoding arity and
- *    named parameters with the pattern:
- *
- *       call$<N>$namedParam1...$namedParam<M>
- *
- *    where <N> is the number of parameters (required and optional) and <M> is
- *    the number of named parameters, and namedParam<n> are the names of the
- *    named parameters in alphabetical order.
- *
- *    Note that the same convention is used for the *proposed name* of other
- *    methods. Thus, for ordinary methods, the suffix becomes embedded in the
- *    disambiguated name (and can be minified), whereas for the 'call' method,
- *    the suffix is an annotation that must be computable at runtime
- *    (and thus cannot be minified).
- *
- *    Note that the ordering of named parameters is not encapsulated in the
- *    [Namer], and is hardcoded into other components, such as [Element] and
- *    [Selector].
- *
- * 2. The getter/setter for a field:
- *
- *        get$<NAME>
- *        set$<NAME>
- *
- *    (The [getterPrefix] and [setterPrefix] are different in [MinifyNamer]).
- *
- * 3. The `is` and operator uses the following names:
- *
- *        $is<NAME>
- *        $as<NAME>
- *
- * For local variables, the [Namer] only provides *proposed names*. These names
- * must be disambiguated elsewhere.
- */
+/// Assigns JavaScript identifiers to Dart variables, class-names and members.
+///
+/// Names are generated through three stages:
+///
+/// 1. Original names and proposed names
+/// 2. Disambiguated names (also known as "mangled names")
+/// 3. Annotated names
+///
+/// Original names are names taken directly from the input.
+///
+/// Proposed names are either original names or synthesized names for input
+/// elements that do not have original names.
+///
+/// Disambiguated names are derived from the above, but are mangled to ensure
+/// uniqueness within some namespace (e.g. as fields on the same JS object).
+/// In [MinifyNamer], disambiguated names are also minified.
+///
+/// Annotated names are names generated from a disambiguated name. Annotated
+/// names must be computable at runtime by prefixing/suffixing constant strings
+/// onto the disambiguated name.
+///
+/// For example, some entity called `x` might be associated with these names:
+///
+///     Original name: `x`
+///
+///     Disambiguated name: `x1` (if something else was called `x`)
+///
+///     Annotated names: `x1`     (field name)
+///                      `get$x1` (getter name)
+///                      `set$x1` (setter name)
+///
+/// The [Namer] can choose the disambiguated names, and to some degree the
+/// prefix/suffix constants used to construct annotated names. It cannot choose
+/// annotated names with total freedom, for example, it cannot choose that the
+/// getter for `x1` should be called `getX` -- the annotated names are always
+/// built by concatenation.
+///
+/// Disambiguated names must be chosen such that none of the annotated names can
+/// clash with each other. This may happen even if the disambiguated names are
+/// distinct, for example, suppose a field `x` and `get$x` exists in the input:
+///
+///     Original names: `x` and `get$x`
+///
+///     Disambiguated names: `x` and `get$x` (the two names a different)
+///
+///     Annotated names: `x` (field for `x`)
+///                      `get$x` (getter for `x`)
+///                      `get$x` (field for `get$x`)
+///                      `get$get$x` (getter for `get$x`)
+///
+/// The getter for `x` clashes with the field name for `get$x`, so the
+/// disambiguated names are invalid.
+///
+/// Additionally, disambiguated names must be chosen such that all annotated
+/// names are valid JavaScript identifiers and do not coincide with a native
+/// JavaScript property such as `__proto__`.
+///
+/// The following annotated names are generated for instance members, where
+/// <NAME> denotes the disambiguated name.
+///
+/// 0. The disambiguated name can itself be seen as an annotated name.
+///
+/// 1. Multiple annotated names exist for the `call` method, encoding arity and
+///    named parameters with the pattern:
+///
+///       call$<N>$namedParam1...$namedParam<M>
+///
+///    where <N> is the number of parameters (required and optional) and <M> is
+///    the number of named parameters, and namedParam<n> are the names of the
+///    named parameters in alphabetical order.
+///
+///    Note that the same convention is used for the *proposed name* of other
+///    methods. Thus, for ordinary methods, the suffix becomes embedded in the
+///    disambiguated name (and can be minified), whereas for the 'call' method,
+///    the suffix is an annotation that must be computable at runtime
+///    (and thus cannot be minified).
+///
+///    Note that the ordering of named parameters is not encapsulated in the
+///    [Namer], and is hardcoded into other components, such as [Element] and
+///    [Selector].
+///
+/// 2. The getter/setter for a field:
+///
+///        get$<NAME>
+///        set$<NAME>
+///
+///    (The [getterPrefix] and [setterPrefix] are different in [MinifyNamer]).
+///
+/// 3. The `is` and operator uses the following names:
+///
+///        $is<NAME>
+///        $as<NAME>
+///
+/// For local variables, the [Namer] only provides *proposed names*. These names
+/// must be disambiguated elsewhere.
 class Namer {
   static const List<String> javaScriptKeywords = const <String>[
     // ES5 7.6.1.1 Keywords.
@@ -616,10 +614,8 @@
   String get isolatePropertiesName => r'$isolateProperties';
   jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_);
 
-  /**
-   * Some closures must contain their name. The name is stored in
-   * [STATIC_CLOSURE_NAME_NAME].
-   */
+  /// Some closures must contain their name. The name is stored in
+  /// [STATIC_CLOSURE_NAME_NAME].
   String get STATIC_CLOSURE_NAME_NAME => r'$name';
   String get closureInvocationSelectorName => Identifiers.call;
   bool get shouldMinify => false;
@@ -763,17 +759,15 @@
     return 'c\$${target.nestingLevel}';
   }
 
-  /**
-   * If the [originalName] is not private returns [originalName]. Otherwise
-   * mangles the [originalName] so that each library has its own distinguished
-   * version of the name.
-   *
-   * Although the name is not guaranteed to be unique within any namespace,
-   * clashes are very unlikely in practice. Therefore, it can be used in cases
-   * where uniqueness is nice but not a strict requirement.
-   *
-   * The resulting name is a *proposed name* and is never minified.
-   */
+  /// If the [originalName] is not private returns [originalName]. Otherwise
+  /// mangles the [originalName] so that each library has its own distinguished
+  /// version of the name.
+  ///
+  /// Although the name is not guaranteed to be unique within any namespace,
+  /// clashes are very unlikely in practice. Therefore, it can be used in cases
+  /// where uniqueness is nice but not a strict requirement.
+  ///
+  /// The resulting name is a *proposed name* and is never minified.
   String privateName(Name originalName) {
     String text = originalName.text;
 
@@ -933,26 +927,20 @@
         CURRENT_ELEMENT_SPANNABLE, 'Unexpected special selector: $selector');
   }
 
-  /**
-   * Returns the internal name used for an invocation mirror of this selector.
-   */
+  /// Returns the internal name used for an invocation mirror of this selector.
   jsAst.Name invocationMirrorInternalName(Selector selector) =>
       invocationName(selector);
 
-  /**
-   * Returns the disambiguated name for the given field, used for constructing
-   * the getter and setter names.
-   */
+  /// Returns the disambiguated name for the given field, used for constructing
+  /// the getter and setter names.
   jsAst.Name fieldAccessorName(FieldEntity element) {
     return element.isInstanceMember
         ? _disambiguateMember(element.memberName)
         : _disambiguateGlobalMember(element);
   }
 
-  /**
-   * Returns name of the JavaScript property used to store a static or instance
-   * field.
-   */
+  /// Returns name of the JavaScript property used to store a static or instance
+  /// field.
   jsAst.Name fieldPropertyName(FieldEntity element) {
     return element.isInstanceMember
         ? instanceFieldPropertyName(element)
@@ -983,9 +971,7 @@
   jsAst.Name globalPropertyNameForType(Entity element) =>
       _disambiguateGlobalType(element);
 
-  /**
-   * Returns the JavaScript property name used to store an instance field.
-   */
+  /// Returns the JavaScript property name used to store an instance field.
   jsAst.Name instanceFieldPropertyName(FieldEntity element) {
     ClassEntity enclosingClass = element.enclosingClass;
 
@@ -1410,10 +1396,8 @@
     }
   }
 
-  /**
-   * Returns a proposed name for the given [LibraryElement].
-   * The returned id is guaranteed to be a valid JavaScript identifier.
-   */
+  /// Returns a proposed name for the given [LibraryElement].
+  /// The returned id is guaranteed to be a valid JavaScript identifier.
   // TODO(sra): Pre-process libraries to assign [libraryLongNames] in a way that
   // is independent of the order of calls to namer.
   String _proposeNameForLibrary(LibraryEntity library) {
@@ -1837,21 +1821,19 @@
   }
 }
 
-/**
- * Generator of names for [ConstantValue] values.
- *
- * The names are stable under perturbations of the source.  The name is either a
- * short sequence of words, if this can be found from the constant, or a type
- * followed by a hash tag.
- *
- *     List_imX                // A List, with hash tag.
- *     C_Sentinel              // const Sentinel(),  "C_" added to avoid clash
- *                             //   with class name.
- *     JSInt_methods           // an interceptor.
- *     Duration_16000          // const Duration(milliseconds: 16)
- *     EventKeyProvider_keyup  // const EventKeyProvider('keyup')
- *
- */
+/// Generator of names for [ConstantValue] values.
+///
+/// The names are stable under perturbations of the source.  The name is either
+/// a short sequence of words, if this can be found from the constant, or a type
+/// followed by a hash tag.
+///
+///     List_imX                // A List, with hash tag.
+///     C_Sentinel              // const Sentinel(),  "C_" added to avoid clash
+///                             //   with class name.
+///     JSInt_methods           // an interceptor.
+///     Duration_16000          // const Duration(milliseconds: 16)
+///     EventKeyProvider_keyup  // const EventKeyProvider('keyup')
+///
 class ConstantNamingVisitor implements ConstantValueVisitor {
   static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$');
   static const MAX_FRAGMENTS = 5;
@@ -2083,14 +2065,12 @@
   }
 }
 
-/**
- * Generates canonical hash values for [ConstantValue]s.
- *
- * Unfortunately, [Constant.hashCode] is not stable under minor perturbations,
- * so it can't be used for generating names.  This hasher keeps consistency
- * between runs by basing hash values of the names of elements, rather than
- * their hashCodes.
- */
+/// Generates canonical hash values for [ConstantValue]s.
+///
+/// Unfortunately, [Constant.hashCode] is not stable under minor perturbations,
+/// so it can't be used for generating names.  This hasher keeps consistency
+/// between runs by basing hash values of the names of elements, rather than
+/// their hashCodes.
 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> {
   static const _MASK = 0x1fffffff;
   static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024;
@@ -2260,12 +2240,10 @@
     }
   }
 
-  /**
-   * [_combine] and [_finish] are parts of the [Jenkins hash function][1],
-   * modified by using masking to keep values in SMI range.
-   *
-   * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
-   */
+  /// [_combine] and [_finish] are parts of the [Jenkins hash function][1],
+  /// modified by using masking to keep values in SMI range.
+  ///
+  /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
   static int _combine(int hash, int value) {
     hash = _MASK & (hash + value);
     hash = _MASK & (hash + (((_MASK >> 10) & hash) << 10));
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 937a205..ec375e0 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -15,6 +15,7 @@
 import '../elements/entities.dart';
 import '../elements/names.dart';
 import '../elements/types.dart';
+import '../ir/runtime_type_analysis.dart';
 import '../js/js.dart' as jsAst;
 import '../js/js.dart' show js;
 import '../js_emitter/js_emitter.dart' show Emitter;
@@ -703,15 +704,13 @@
 
   _RuntimeTypesBase(this._types);
 
-  /**
-   * Compute type arguments of classes that use one of their type variables in
-   * is-checks and add the is-checks that they imply.
-   *
-   * This function must be called after all is-checks have been registered.
-   *
-   * TODO(karlklose): move these computations into a function producing an
-   * immutable datastructure.
-   */
+  /// Compute type arguments of classes that use one of their type variables in
+  /// is-checks and add the is-checks that they imply.
+  ///
+  /// This function must be called after all is-checks have been registered.
+  ///
+  /// TODO(karlklose): move these computations into a function producing an
+  /// immutable datastructure.
   void registerImplicitChecks(
       Set<InterfaceType> instantiatedTypes,
       Iterable<ClassEntity> classesUsingChecks,
@@ -2276,20 +2275,18 @@
     }
   }
 
-  /**
-   * Compute a JavaScript expression that describes the necessary substitution
-   * for type arguments in a subtype test.
-   *
-   * The result can be:
-   *  1) `null`, if no substituted check is necessary, because the
-   *     type variables are the same or there are no type variables in the class
-   *     that is checked for.
-   *  2) A list expression describing the type arguments to be used in the
-   *     subtype check, if the type arguments to be used in the check do not
-   *     depend on the type arguments of the object.
-   *  3) A function mapping the type variables of the object to be checked to
-   *     a list expression.
-   */
+  /// Compute a JavaScript expression that describes the necessary substitution
+  /// for type arguments in a subtype test.
+  ///
+  /// The result can be:
+  ///  1) `null`, if no substituted check is necessary, because the type
+  ///     variables are the same or there are no type variables in the class
+  ///     that is checked for.
+  ///  2) A list expression describing the type arguments to be used in the
+  ///     subtype check, if the type arguments to be used in the check do not
+  ///     depend on the type arguments of the object.
+  ///  3) A function mapping the type variables of the object to be checked to
+  ///     a list expression.
   @override
   jsAst.Expression getSubstitutionCode(
       Emitter emitter, Substitution substitution) {
@@ -2381,10 +2378,8 @@
 
   TypeRepresentationGenerator(this.namer, this._nativeData);
 
-  /**
-   * Creates a type representation for [type]. [onVariable] is called to provide
-   * the type representation for type variables.
-   */
+  /// Creates a type representation for [type]. [onVariable] is called to
+  /// provide the type representation for type variables.
   jsAst.Expression getTypeRepresentation(
       Emitter emitter,
       DartType type,
@@ -2787,10 +2782,8 @@
       'parameters=$parameters,length=$length)';
 }
 
-/**
- * A pair of a class that we need a check against and the type argument
- * substitution for this check.
- */
+/// A pair of a class that we need a check against and the type argument
+/// substitution for this check.
 class TypeCheck {
   final ClassEntity cls;
   final bool needsIs;
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 73a5d1c..fb31e92 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -85,11 +85,9 @@
         'function(#, v) { return #.# = v; }', [args, receiver, fieldName]);
   }
 
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: [member] must be a declaration element.
-   */
+  /// Documentation wanted -- johnniwinther
+  ///
+  /// Invariant: [member] must be a declaration element.
   Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter(
       MemberEntity member, Map<Selector, SelectorConstraints> selectors) {
     // If the method is intercepted, the stub gets the
@@ -245,12 +243,13 @@
 ///
 /// `tearOff` takes the following arguments:
 ///   * `funcs`: a list of functions. These are the functions representing the
-///    member that is torn off. There can be more than one, since a member
-///    can have several stubs.
-///    Each function must have the `$callName` property set.
-///   * `applyTrampolineIndex` is the index of the stub to be used for Function.apply
+///     member that is torn off. There can be more than one, since a member
+///     can have several stubs.
+///     Each function must have the `$callName` property set.
+///   * `applyTrampolineIndex` is the index of the stub to be used for
+///     Function.apply
 ///   * `reflectionInfo`: contains reflective information, and the function
-///    type. TODO(floitsch): point to where this is specified.
+///     type. TODO(floitsch): point to where this is specified.
 ///   * `isStatic`.
 ///   * `name`.
 ///   * `isIntercepted.
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 36f8a9f..7fac11d 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -17,7 +17,6 @@
 import '../js_backend/inferred_data.dart';
 import '../universe/codegen_world_builder.dart';
 import '../world.dart' show JClosedWorld;
-import 'full_emitter/emitter.dart' as full_js_emitter;
 import 'program_builder/program_builder.dart';
 import 'startup_emitter/emitter.dart' as startup_js_emitter;
 
@@ -27,12 +26,10 @@
 import 'type_test_registry.dart' show TypeTestRegistry;
 import 'sorter.dart';
 
-/**
- * Generates the code for all used classes in the program. Static fields (even
- * in classes) are ignored, since they can be treated as non-class elements.
- *
- * The code for the containing (used) methods must exist in the `universe`.
- */
+/// Generates the code for all used classes in the program. Static fields (even
+/// in classes) are ignored, since they can be treated as non-class elements.
+///
+/// The code for the containing (used) methods must exist in the `universe`.
 class CodeEmitterTask extends CompilerTask {
   TypeTestRegistry typeTestRegistry;
   NativeEmitter _nativeEmitter;
@@ -50,14 +47,10 @@
   /// Contains a list of all classes that are emitted.
   Set<ClassEntity> neededClasses;
 
-  CodeEmitterTask(
-      Compiler compiler, bool generateSourceMap, bool useStartupEmitter)
+  CodeEmitterTask(Compiler compiler, bool generateSourceMap)
       : compiler = compiler,
-        _emitterFactory = useStartupEmitter
-            ? new startup_js_emitter.EmitterFactory(
-                generateSourceMap: generateSourceMap)
-            : new full_js_emitter.EmitterFactory(
-                generateSourceMap: generateSourceMap),
+        _emitterFactory = startup_js_emitter.EmitterFactory(
+            generateSourceMap: generateSourceMap),
         super(compiler.measurer);
 
   NativeEmitter get nativeEmitter {
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
deleted file mode 100644
index 7f55142..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
+++ /dev/null
@@ -1,97 +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.js_emitter.full_emitter.class_builder;
-
-import '../../elements/entities.dart';
-import '../../js/js.dart' as jsAst;
-import '../../js/js.dart' show js;
-import '../../js_backend/js_backend.dart' show Namer;
-
-/**
- * A data structure for collecting fragments of a class definition.
- */
-class ClassBuilder {
-  final List<jsAst.Property> properties = <jsAst.Property>[];
-  final List<jsAst.Literal> fields = <jsAst.Literal>[];
-
-  jsAst.Name superName;
-  jsAst.Node functionType;
-  List<jsAst.Expression> fieldMetadata;
-
-  final Entity element;
-  final Namer namer;
-  final bool isForActualClass;
-
-  ClassBuilder.forLibrary(LibraryEntity library, this.namer)
-      : isForActualClass = false,
-        element = library;
-
-  ClassBuilder.forClass(ClassEntity cls, this.namer)
-      : isForActualClass = true,
-        element = cls;
-
-  ClassBuilder.forStatics(this.element, this.namer) : isForActualClass = false;
-
-  jsAst.Property addProperty(jsAst.Literal name, jsAst.Expression value) {
-    jsAst.Property property = new jsAst.Property(js.quoteName(name), value);
-    properties.add(property);
-    return property;
-  }
-
-  jsAst.Property addPropertyByName(String name, jsAst.Expression value) {
-    jsAst.Property property = new jsAst.Property(js.string(name), value);
-    properties.add(property);
-    return property;
-  }
-
-  void addField(jsAst.Literal field) {
-    fields.add(field);
-  }
-
-  static String functionTypeEncodingDescription =
-      'For simple function types the function type is stored in the metadata '
-      'and the index is encoded into the superclass field.';
-
-  static String fieldEncodingDescription =
-      'Fields are encoded as a comma separated list. If there is a superclass '
-      '(and possibly a function type encoding) the fields are separated from '
-      'the superclass by a semicolon.';
-
-  jsAst.ObjectInitializer toObjectInitializer(
-      {bool emitClassDescriptor: true}) {
-    List<jsAst.Literal> parts = <jsAst.Literal>[];
-    if (isForActualClass) {
-      if (superName != null) {
-        parts.add(superName);
-        if (functionType != null) {
-          // See [functionTypeEncodingDescription] above.
-          parts.add(js.stringPart(':'));
-          parts.add(functionType);
-        }
-      }
-      parts.add(js.stringPart(';'));
-    }
-    // See [fieldEncodingDescription] above.
-    parts.addAll(js.joinLiterals(fields, js.stringPart(',')));
-    dynamic classData = js.concatenateStrings(parts, addQuotes: true);
-    if (fieldMetadata != null) {
-      // If we need to store fieldMetadata, classData is turned into an array,
-      // and the field metadata is appended. So if classData is just a string,
-      // there is no field metadata.
-      classData =
-          new jsAst.ArrayInitializer([classData]..addAll(fieldMetadata));
-    }
-    List<jsAst.Property> fieldsAndProperties;
-    if (emitClassDescriptor) {
-      fieldsAndProperties = <jsAst.Property>[];
-      fieldsAndProperties.add(new jsAst.Property(
-          js.string(namer.classDescriptorProperty), classData));
-      fieldsAndProperties.addAll(properties);
-    } else {
-      fieldsAndProperties = properties;
-    }
-    return new jsAst.ObjectInitializer(fieldsAndProperties, isOneLiner: false);
-  }
-}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
deleted file mode 100644
index be7634c..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
+++ /dev/null
@@ -1,343 +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.js_emitter.full_emitter.class_emitter;
-
-import '../../common.dart';
-import '../../common/names.dart' show Names;
-import '../../common_elements.dart';
-import '../../deferred_load.dart' show OutputUnit;
-import '../../elements/entities.dart';
-import '../../js/js.dart' as jsAst;
-import '../../js/js.dart' show js;
-import '../../js_backend/js_backend.dart' show CompoundName, Namer;
-import '../../world.dart' show JClosedWorld;
-import '../js_emitter.dart' hide Emitter, EmitterFactory;
-import '../model.dart';
-import 'emitter.dart';
-
-class ClassEmitter extends CodeEmitterHelper {
-  final JClosedWorld closedWorld;
-
-  ClassEmitter(this.closedWorld);
-
-  ClassStubGenerator get _stubGenerator => new ClassStubGenerator(task.emitter,
-      closedWorld.commonElements, namer, codegenWorldBuilder, closedWorld,
-      enableMinification: compiler.options.enableMinification);
-
-  ElementEnvironment get _elementEnvironment => closedWorld.elementEnvironment;
-
-  /**
-   * Documentation wanted -- johnniwinther
-   */
-  void emitClass(Class cls, ClassBuilder enclosingBuilder, Fragment fragment) {
-    ClassEntity classElement = cls.element;
-
-    emitter.needsClassSupport = true;
-
-    ClassEntity superclass = _elementEnvironment.getSuperClass(classElement);
-    jsAst.Name superName;
-    if (superclass != null) {
-      superName = namer.className(superclass);
-    }
-
-    if (cls.mixinClass != null) {
-      jsAst.Name mixinName = cls.mixinClass.name;
-      superName = new CompoundName([superName, Namer.literalPlus, mixinName]);
-      emitter.needsMixinSupport = true;
-    }
-
-    ClassBuilder builder = new ClassBuilder.forClass(classElement, namer);
-    builder.superName = superName;
-    emitConstructorsForCSP(cls);
-    emitFields(cls, builder);
-    if (cls.hasRtiField) {
-      builder.addField(namer.rtiFieldJsName);
-    }
-    emitCheckedClassSetters(cls, builder);
-    emitClassGettersSettersForCSP(cls, builder);
-    emitInstanceMembers(cls, builder);
-    emitStubs(cls.callStubs, builder);
-    emitRuntimeTypeInformation(cls, builder);
-    emitNativeInfo(cls, builder);
-
-    if (classElement == closedWorld.commonElements.closureClass) {
-      // We add a special getter here to allow for tearing off a closure from
-      // itself.
-      jsAst.Fun function = js('function() { return this; }');
-      jsAst.Name name = namer.getterForMember(Names.call);
-      builder.addProperty(name, function);
-    }
-
-    emitClassBuilderWithReflectionData(
-        cls, builder, enclosingBuilder, fragment);
-  }
-
-  /**
-  * Emits the precompiled constructor when in CSP mode.
-  */
-  void emitConstructorsForCSP(Class cls) {
-    if (!compiler.options.useContentSecurityPolicy) return;
-
-    List<jsAst.Name> fieldNames = <jsAst.Name>[];
-    if (!cls.onlyForRti && !cls.isNative) {
-      fieldNames = cls.fields.map((Field field) => field.name).toList();
-    }
-
-    ClassEntity classElement = cls.element;
-
-    jsAst.Expression constructorAst = _stubGenerator.generateClassConstructor(
-        classElement, fieldNames, cls.hasRtiField);
-
-    jsAst.Name constructorName = namer.className(classElement);
-    OutputUnit outputUnit =
-        closedWorld.outputUnitData.outputUnitForClass(classElement);
-    emitter.assemblePrecompiledConstructor(
-        outputUnit, constructorName, constructorAst, fieldNames);
-  }
-
-  /// Returns `true` if fields added.
-  bool emitFields(FieldContainer container, ClassBuilder builder,
-      {bool classIsNative: false, bool emitStatics: false}) {
-    Iterable<Field> fields;
-    if (container is Class) {
-      if (emitStatics) {
-        fields = container.staticFieldsForReflection;
-      } else if (container.onlyForRti) {
-        return false;
-      } else {
-        fields = container.fields;
-      }
-    } else {
-      assert(container is Library);
-      assert(emitStatics);
-      fields = container.staticFieldsForReflection;
-    }
-
-    bool fieldsAdded = false;
-
-    for (Field field in fields) {
-      FieldEntity fieldElement = field.element;
-      jsAst.Name name = field.name;
-      jsAst.Name accessorName = field.accessorName;
-      bool needsGetter = field.needsGetter;
-      bool needsSetter = field.needsUncheckedSetter;
-
-      // Ignore needsCheckedSetter - that is handled below.
-      bool needsAccessor = (needsGetter || needsSetter);
-      // We need to output the fields for non-native classes so we can auto-
-      // generate the constructor.  For native classes there are no
-      // constructors, so we don't need the fields unless we are generating
-      // accessors at runtime.
-      bool needsFieldsForConstructor = !emitStatics && !classIsNative;
-      if (needsFieldsForConstructor || needsAccessor) {
-        List<jsAst.Literal> fieldNameParts = <jsAst.Literal>[];
-        if (field.initializerInAllocator != null) {
-          assert(field.initializerInAllocator.isNull);
-          fieldNameParts.add(js.stringPart('0'));
-        }
-        if (!needsAccessor) {
-          // Emit field for constructor generation.
-          assert(!classIsNative);
-          fieldNameParts.add(name);
-        } else {
-          // Emit (possibly renaming) field name so we can add accessors at
-          // runtime.
-          if (name != accessorName) {
-            fieldNameParts.add(accessorName);
-            fieldNameParts.add(js.stringPart(':'));
-          }
-          fieldNameParts.add(name);
-          if (field.needsInterceptedGetter) {
-            emitter.interceptorEmitter.interceptorInvocationNames
-                .add(namer.getterForElement(fieldElement));
-          }
-          // TODO(16168): The setter creator only looks at the getter-name.
-          // Even though the setter could avoid the interceptor convention we
-          // currently still need to add the additional argument.
-          if (field.needsInterceptedGetter || field.needsInterceptedSetter) {
-            emitter.interceptorEmitter.interceptorInvocationNames
-                .add(namer.setterForMember(fieldElement));
-          }
-
-          int code = field.getterFlags + (field.setterFlags << 2);
-          if (code == 0) {
-            reporter.internalError(
-                fieldElement, 'Field code is 0 ($fieldElement).');
-          }
-          fieldNameParts.add(
-              js.stringPart(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]));
-        }
-        jsAst.Literal fieldNameAst = js.concatenateStrings(fieldNameParts);
-        builder.addField(fieldNameAst);
-        // Add 1 because adding a field to the class also requires a comma
-        compiler.dumpInfoTask.registerEntityAst(fieldElement, fieldNameAst);
-        fieldsAdded = true;
-      }
-    }
-
-    return fieldsAdded;
-  }
-
-  /// Emits checked setters for fields.
-  void emitCheckedClassSetters(Class cls, ClassBuilder builder) {
-    if (cls.onlyForRti) return;
-
-    for (StubMethod method in cls.checkedSetters) {
-      MemberEntity member = method.element;
-      assert(member != null);
-      jsAst.Expression code = method.code;
-      jsAst.Name setterName = method.name;
-      compiler.dumpInfoTask
-          .registerEntityAst(member, builder.addProperty(setterName, code));
-    }
-  }
-
-  /// Emits getters/setters for fields if compiling in CSP mode.
-  void emitClassGettersSettersForCSP(Class cls, ClassBuilder builder) {
-    if (!compiler.options.useContentSecurityPolicy || cls.onlyForRti) return;
-
-    for (Field field in cls.fields) {
-      FieldEntity member = field.element;
-      reporter.withCurrentElement(member, () {
-        if (field.needsGetter) {
-          emitGetterForCSP(member, field.name, field.accessorName, builder);
-        }
-        if (field.needsUncheckedSetter) {
-          emitSetterForCSP(member, field.name, field.accessorName, builder);
-        }
-      });
-    }
-  }
-
-  void emitStubs(Iterable<StubMethod> stubs, ClassBuilder builder) {
-    for (Method method in stubs) {
-      jsAst.Property property = builder.addProperty(method.name, method.code);
-      compiler.dumpInfoTask.registerEntityAst(method.element, property);
-    }
-  }
-
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: [classElement] must be a declaration element.
-   */
-  void emitInstanceMembers(Class cls, ClassBuilder builder) {
-    ClassEntity classElement = cls.element;
-
-    if (cls.onlyForRti || cls.isSimpleMixinApplication) return;
-
-    // TODO(herhut): This is a no-op. Should it be removed?
-    for (Field field in cls.fields) {
-      emitter.containerBuilder.addMemberField(field, builder);
-    }
-
-    for (Method method in cls.methods) {
-      assert(method.element.isInstanceMember, failedAt(classElement));
-      emitter.containerBuilder.addMemberMethod(method, builder);
-    }
-
-    if (classElement == closedWorld.commonElements.objectClass &&
-        closedWorld.backendUsage.isNoSuchMethodUsed) {
-      // Emit the noSuchMethod handlers on the Object prototype now,
-      // so that the code in the dynamicFunction helper can find
-      // them. Note that this helper is invoked before analyzing the
-      // full JS script.
-      emitter.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty);
-    }
-  }
-
-  /// Emits the members from the model.
-  void emitRuntimeTypeInformation(Class cls, ClassBuilder builder) {
-    assert(builder.functionType == null);
-    if (cls.functionTypeIndex != null) {
-      builder.functionType = cls.functionTypeIndex;
-    }
-
-    for (Method method in cls.isChecks) {
-      builder.addProperty(method.name, method.code);
-    }
-  }
-
-  void emitNativeInfo(Class cls, ClassBuilder builder) {
-    jsAst.Expression nativeInfo = NativeGenerator.encodeNativeInfo(cls);
-    if (nativeInfo != null) {
-      builder.addPropertyByName(namer.nativeSpecProperty, nativeInfo);
-    }
-  }
-
-  void emitClassBuilderWithReflectionData(Class cls, ClassBuilder classBuilder,
-      ClassBuilder enclosingBuilder, Fragment fragment) {
-    ClassEntity classEntity = cls.element;
-    jsAst.Name className = cls.name;
-
-    List<jsAst.Property> statics = new List<jsAst.Property>();
-    ClassBuilder staticsBuilder =
-        new ClassBuilder.forStatics(classEntity, namer);
-    if (emitFields(cls, staticsBuilder, emitStatics: true)) {
-      jsAst.ObjectInitializer initializer =
-          staticsBuilder.toObjectInitializer();
-      compiler.dumpInfoTask.registerEntityAst(classEntity, initializer);
-      jsAst.Node property = initializer.properties.single;
-      compiler.dumpInfoTask.registerEntityAst(classEntity, property);
-      statics.add(property);
-    }
-
-    // TODO(herhut): Do not grab statics out of the properties.
-    ClassBuilder classProperties =
-        emitter.classDescriptors[fragment]?.remove(classEntity);
-    if (classProperties != null) {
-      statics.addAll(classProperties.properties);
-    }
-
-    if (!statics.isEmpty) {
-      classBuilder.addProperty(
-          namer.staticsPropertyName, // 'static' or its minified name.
-          new jsAst.ObjectInitializer(statics, isOneLiner: false));
-    }
-
-    // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
-    jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer();
-    compiler.dumpInfoTask
-        .registerEntityAst(classBuilder.element, propertyValue);
-    enclosingBuilder.addProperty(className, propertyValue);
-
-    String reflectionName =
-        emitter.getReflectionClassName(classEntity, className);
-    if (reflectionName != null) {
-      // TODO(herhut): Fix use of reflection name here.
-      enclosingBuilder.addPropertyByName("+$reflectionName", js.number(0));
-    }
-  }
-
-  void emitGetterForCSP(FieldEntity member, jsAst.Name fieldName,
-      jsAst.Name accessorName, ClassBuilder builder) {
-    jsAst.Expression function =
-        _stubGenerator.generateGetter(member, fieldName);
-
-    jsAst.Name getterName = namer.deriveGetterName(accessorName);
-    ClassEntity cls = member.enclosingClass;
-    jsAst.Name className = namer.className(cls);
-    OutputUnit outputUnit =
-        closedWorld.outputUnitData.outputUnitForMember(member);
-    emitter
-        .cspPrecompiledFunctionFor(outputUnit)
-        .add(js('#.prototype.# = #', [className, getterName, function]));
-  }
-
-  void emitSetterForCSP(FieldEntity member, jsAst.Name fieldName,
-      jsAst.Name accessorName, ClassBuilder builder) {
-    jsAst.Expression function =
-        _stubGenerator.generateSetter(member, fieldName);
-
-    jsAst.Name setterName = namer.deriveSetterName(accessorName);
-    ClassEntity cls = member.enclosingClass;
-    jsAst.Name className = namer.className(cls);
-    OutputUnit outputUnit =
-        closedWorld.outputUnitData.outputUnitForMember(member);
-    emitter
-        .cspPrecompiledFunctionFor(outputUnit)
-        .add(js('#.prototype.# = #', [className, setterName, function]));
-  }
-}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
deleted file mode 100644
index 36932fb..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
+++ /dev/null
@@ -1,27 +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.js_emitter.full_emitter;
-
-class CodeEmitterHelper {
-  Emitter emitter;
-
-  Namer get namer => emitter.namer;
-
-  JavaScriptBackend get backend => emitter.backend;
-
-  CodeEmitterTask get task => emitter.task;
-
-  Compiler get compiler => emitter.compiler;
-
-  DiagnosticReporter get reporter => compiler.reporter;
-
-  CodegenWorldBuilder get codegenWorldBuilder => compiler.codegenWorldBuilder;
-
-  String get n => emitter.n;
-
-  String get _ => emitter._;
-
-  String get N => emitter.N;
-}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
deleted file mode 100644
index 0836206..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
+++ /dev/null
@@ -1,184 +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.js_emitter.full_emitter.container_builder;
-
-import '../../deferred_load.dart' show OutputUnit;
-import '../../elements/entities.dart';
-import '../../elements/names.dart';
-import '../../js/js.dart' as jsAst;
-import '../../js/js.dart' show js;
-import '../../world.dart';
-import '../js_emitter.dart' hide Emitter, EmitterFactory;
-import '../model.dart';
-import 'emitter.dart';
-
-/// This class should morph into something that makes it easy to build
-/// JavaScript representations of libraries, class-sides, and instance-sides.
-/// Initially, it is just a placeholder for code that is moved from
-/// [CodeEmitterTask].
-class ContainerBuilder extends CodeEmitterHelper {
-  JClosedWorld _closedWorld;
-
-  ContainerBuilder(this._closedWorld);
-
-  void addMemberMethod(DartMethod method, ClassBuilder builder) {
-    FunctionEntity member = method.element;
-    OutputUnit outputUnit =
-        _closedWorld.outputUnitData.outputUnitForMember(member);
-    jsAst.Name name = method.name;
-    ParameterStructure parameters = member.parameterStructure;
-    jsAst.Expression code = method.code;
-    bool needsStubs = method.parameterStubs.isNotEmpty;
-    bool canBeApplied = method.canBeApplied;
-    bool canTearOff = method.needsTearOff;
-    jsAst.Name tearOffName = method.tearOffName;
-    bool isClosure = method is InstanceMethod && method.isClosureCallMethod;
-    jsAst.Name superAlias = method is InstanceMethod ? method.aliasName : null;
-    bool hasSuperAlias = superAlias != null;
-    jsAst.Expression memberTypeExpression = method.functionType;
-    bool needStructuredInfo = canTearOff || canBeApplied || hasSuperAlias;
-
-    bool isIntercepted = false;
-    if (method is InstanceMethod) {
-      isIntercepted = method.isIntercepted;
-    }
-
-    emitter.interceptorEmitter.recordMangledNameOfMemberMethod(member, name);
-
-    if (!needStructuredInfo) {
-      compiler.dumpInfoTask
-          .registerEntityAst(member, builder.addProperty(name, code));
-
-      for (ParameterStubMethod stub in method.parameterStubs) {
-        assert(stub.callName == null);
-        jsAst.Property property = builder.addProperty(stub.name, stub.code);
-        compiler.dumpInfoTask.registerEntityAst(member, property);
-        emitter.interceptorEmitter
-            .recordMangledNameOfMemberMethod(member, stub.name);
-      }
-      return;
-    }
-    emitter.needsStructuredMemberInfo = true;
-
-    // This element is needed for reflection or needs additional stubs or has a
-    // super alias. So we need to retain additional information.
-
-    // The information is stored in an array with this format:
-    //
-    // 1.   The alias name for this function (optional).
-    // 2.   Index into the functions and stubs of the apply stub (optional).
-    // 3.   The JS function for this member.
-    // 4.   First stub.
-    // 5.   Name of first stub.
-    // ...
-    // M.   Call name of this member.
-    // M+1. Call name of first stub.
-    // ...
-    // N.   Getter name for tearOff.
-    // N+1. (Required parameter count << 2) + (member.isAccessor ? 2 : 0) +
-    //        (isIntercepted ? 1 : 0)
-    // N+2. (Optional parameter count << 1) +
-    //                      (parameters.optionalParametersAreNamed ? 1 : 0).
-    // N+3. Index to function type in constant pool.
-    // N+4. First default argument.
-    // ...
-    // O.   First parameter name (if needed for reflection or Function.apply).
-    // ...
-    // P.   Unmangled name (if reflectable).
-    // P+1. First metadata (if reflectable).
-    // ...
-    // TODO(ahe): Consider one of the parameter counts can be replaced by the
-    // length property of the JavaScript function object.
-
-    List<jsAst.Expression> expressions = <jsAst.Expression>[];
-
-    // Create the optional aliasing entry if this method is called via super.
-    if (hasSuperAlias) {
-      expressions.add(js.quoteName(superAlias));
-    }
-
-    if (canBeApplied && parameters.typeParameters > 0) {
-      // The first stub is the one that has all the value parameters parameters
-      // but no type parameters. This is the entry point for Function.apply.
-      expressions.add(js.number(1));
-    }
-
-    expressions.add(code);
-
-    bool onlyNeedsSuperAlias = !(canTearOff || canBeApplied || needsStubs);
-
-    if (onlyNeedsSuperAlias) {
-      jsAst.ArrayInitializer arrayInit =
-          new jsAst.ArrayInitializer(expressions);
-      compiler.dumpInfoTask
-          .registerEntityAst(member, builder.addProperty(name, arrayInit));
-      return;
-    }
-
-    jsAst.Literal callSelectorString;
-    if (method.callName == null) {
-      callSelectorString = new jsAst.LiteralNull();
-    } else {
-      callSelectorString = js.quoteName(method.callName);
-    }
-
-    // On [requiredParameterCount], the lower bit is set if this method can be
-    // called reflectively.
-    int requiredParameterCount = parameters.requiredParameters << 2;
-    if (member.isGetter || member.isSetter) requiredParameterCount += 2;
-    if (isIntercepted) requiredParameterCount += 1;
-
-    int optionalParameterCount = parameters.optionalParameters << 1;
-    if (parameters.namedParameters.isNotEmpty) optionalParameterCount++;
-
-    var tearOffInfo = <jsAst.Expression>[callSelectorString];
-
-    for (ParameterStubMethod stub in method.parameterStubs) {
-      jsAst.Name invocationName = stub.name;
-      emitter.interceptorEmitter
-          .recordMangledNameOfMemberMethod(member, invocationName);
-
-      expressions.add(stub.code);
-      if (member.isInstanceMember) {
-        expressions.add(js.quoteName(invocationName));
-      }
-      jsAst.Name callName = stub.callName;
-      jsAst.Literal callSelectorString =
-          (callName == null) ? new jsAst.LiteralNull() : js.quoteName(callName);
-      tearOffInfo.add(callSelectorString);
-    }
-
-    expressions
-      ..addAll(tearOffInfo)
-      ..add((tearOffName == null || member.isGetter || member.isSetter)
-          ? js("null")
-          : js.quoteName(tearOffName))
-      ..add(js.number(requiredParameterCount))
-      ..add(js.number(optionalParameterCount))
-      ..add(memberTypeExpression == null ? js("null") : memberTypeExpression);
-
-    if (canBeApplied) {
-      expressions.addAll(
-          task.metadataCollector.reifyDefaultArguments(member, outputUnit));
-
-      codegenWorldBuilder.forEachParameter(member, (_, String name, _2) {
-        expressions.add(task.metadataCollector.reifyName(name, outputUnit));
-      });
-    }
-    Name memberName = member.memberName;
-    if (isClosure && canBeApplied) {
-      expressions.add(js.string(namer.privateName(memberName)));
-    }
-
-    jsAst.ArrayInitializer arrayInit =
-        new jsAst.ArrayInitializer(expressions.toList());
-    compiler.dumpInfoTask
-        .registerEntityAst(member, builder.addProperty(name, arrayInit));
-  }
-
-  void addMemberField(Field field, ClassBuilder builder) {
-    // For now, do nothing.
-  }
-}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart
deleted file mode 100644
index ac14c66..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart
+++ /dev/null
@@ -1,37 +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.js_emitter.full_emitter;
-
-/// Enables debugging of fast/slow objects using V8-specific primitives.
-const DEBUG_FAST_OBJECTS = false;
-
-/**
- * Call-back for adding property with [name] and [value].
- */
-typedef jsAst.Property AddPropertyFunction(
-    jsAst.Name name, jsAst.Expression value);
-
-// Compact field specifications.  The format of the field specification is
-// <accessorName>:<fieldName><suffix> where the suffix and accessor name
-// prefix are optional.  The suffix directs the generation of getter and
-// setter methods.  Each of the getter and setter has two bits to determine
-// the calling convention.  Setter listed below, getter is similar.
-//
-//     00: no setter
-//     01: function(value) { this.field = value; }
-//     10: function(receiver, value) { receiver.field = value; }
-//     11: function(receiver, value) { this.field = value; }
-//
-// The suffix encodes 4 bits using three ASCII ranges of non-identifier
-// characters.
-const FIELD_CODE_CHARACTERS = r"<=>?@{|}~%&'()*";
-const NO_FIELD_CODE = 0;
-const FIRST_FIELD_CODE = 1;
-const RANGE1_FIRST = 0x3c; //  <=>?@    encodes 1..5
-const RANGE1_LAST = 0x40;
-const RANGE2_FIRST = 0x7b; //  {|}~     encodes 6..9
-const RANGE2_LAST = 0x7e;
-const RANGE3_FIRST = 0x25; //  %&'()*+  encodes 10..16
-const RANGE3_LAST = 0x2b;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/deferred_output_unit_hash.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/deferred_output_unit_hash.dart
deleted file mode 100644
index 8c79a8b..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/deferred_output_unit_hash.dart
+++ /dev/null
@@ -1,24 +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.js_emitter.full_emitter;
-
-class _DeferredOutputUnitHash extends jsAst.DeferredString {
-  String _hash;
-  final OutputUnit _outputUnit;
-
-  _DeferredOutputUnitHash(this._outputUnit);
-
-  void setHash(String hash) {
-    assert(_hash == null);
-    _hash = hash;
-  }
-
-  String get value {
-    assert(_hash != null);
-    return '"$_hash"';
-  }
-
-  String toString() => "HashCode for ${_outputUnit} [$_hash]";
-}
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
deleted file mode 100644
index 9da5325..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ /dev/null
@@ -1,1725 +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.js_emitter.full_emitter;
-
-import 'dart:convert';
-
-import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
-import 'package:js_runtime/shared/embedded_names.dart'
-    show JsBuiltin, JsGetName;
-
-import '../../../compiler_new.dart';
-import '../../common.dart';
-import '../../common_elements.dart' show CommonElements, ElementEnvironment;
-import '../../compiler.dart' show Compiler;
-import '../../constants/values.dart';
-import '../../deferred_load.dart'
-    show deferredPartFileName, OutputUnit, OutputUnitData;
-import '../../elements/entities.dart';
-import '../../hash/sha1.dart' show Hasher;
-import '../../io/code_output.dart';
-import '../../io/location_provider.dart' show LocationCollector;
-import '../../io/source_map_builder.dart' show SourceMapBuilder;
-import '../../js/js.dart' as jsAst;
-import '../../js/js.dart' show js;
-import '../../js_backend/js_backend.dart'
-    show ConstantEmitter, JavaScriptBackend, Namer;
-import '../../js_backend/native_data.dart';
-import '../../js_backend/js_interop_analysis.dart' as jsInteropAnalysis;
-import '../../universe/call_structure.dart' show CallStructure;
-import '../../universe/codegen_world_builder.dart';
-import '../../util/uri_extras.dart' show relativize;
-import '../../world.dart' show JClosedWorld;
-import '../constant_ordering.dart' show ConstantOrdering;
-import '../headers.dart';
-import '../js_emitter.dart' hide Emitter, EmitterFactory;
-import '../js_emitter.dart' as js_emitter show EmitterBase, EmitterFactory;
-import '../model.dart';
-import '../program_builder/program_builder.dart';
-import '../sorter.dart';
-
-import 'class_builder.dart';
-import 'class_emitter.dart';
-import 'container_builder.dart';
-import 'interceptor_emitter.dart';
-import 'nsm_emitter.dart';
-
-export 'class_builder.dart';
-export 'class_emitter.dart';
-export 'container_builder.dart';
-export 'interceptor_emitter.dart';
-export 'nsm_emitter.dart';
-
-part 'code_emitter_helper.dart';
-part 'declarations.dart';
-part 'deferred_output_unit_hash.dart';
-part 'setup_program_builder.dart';
-
-class EmitterFactory implements js_emitter.EmitterFactory {
-  final bool generateSourceMap;
-
-  EmitterFactory({this.generateSourceMap});
-
-  @override
-  bool get supportsReflection => true;
-
-  @override
-  Emitter createEmitter(CodeEmitterTask task, Namer namer,
-      JClosedWorld closedWorld, Sorter sorter) {
-    return new Emitter(
-        task.compiler, namer, closedWorld, generateSourceMap, task, sorter);
-  }
-}
-
-class Emitter extends js_emitter.EmitterBase {
-  final Compiler compiler;
-  final CodeEmitterTask task;
-  final JClosedWorld _closedWorld;
-
-  // The following fields will be set to copies of the program-builder's
-  // collector.
-  Map<OutputUnit, List<FieldEntity>> outputStaticNonFinalFieldLists;
-  Map<OutputUnit, Set<LibraryEntity>> outputLibraryLists;
-
-  final ContainerBuilder containerBuilder;
-  final ClassEmitter classEmitter;
-  final NsmEmitter nsmEmitter;
-  final InterceptorEmitter interceptorEmitter;
-  final Sorter _sorter;
-  final ConstantOrdering _constantOrdering;
-
-  // TODO(johnniwinther): Wrap these fields in a caching strategy.
-  final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[];
-
-  bool needsClassSupport = false;
-  bool needsMixinSupport = false;
-  bool needsLazyInitializer = false;
-
-  /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info",
-  /// that is, some function was needed for reflection, had stubs, or had a
-  /// super alias.
-  bool needsStructuredMemberInfo = false;
-
-  final Namer namer;
-  ConstantEmitter constantEmitter;
-  NativeEmitter get nativeEmitter => task.nativeEmitter;
-  TypeTestRegistry get typeTestRegistry => task.typeTestRegistry;
-  CommonElements get commonElements => _closedWorld.commonElements;
-  ElementEnvironment get _elementEnvironment => _closedWorld.elementEnvironment;
-  CodegenWorldBuilder get _worldBuilder => compiler.codegenWorldBuilder;
-  OutputUnitData get _outputUnitData => _closedWorld.outputUnitData;
-
-  // The full code that is written to each hunk part-file.
-  Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>();
-
-  String classesCollector;
-
-  JavaScriptBackend get backend => compiler.backend;
-
-  String get _ => space;
-  String get space => compiler.options.enableMinification ? "" : " ";
-  String get n => compiler.options.enableMinification ? "" : "\n";
-  String get N => compiler.options.enableMinification ? "\n" : ";\n";
-
-  /**
-   * List of expressions and statements that will be included in the
-   * precompiled function.
-   *
-   * To save space, dart2js normally generates constructors and accessors
-   * dynamically. This doesn't work in CSP mode, so dart2js emits them directly
-   * when in CSP mode.
-   */
-  Map<OutputUnit, List<jsAst.Node>> _cspPrecompiledFunctions =
-      new Map<OutputUnit, List<jsAst.Node>>();
-
-  Map<OutputUnit, List<jsAst.Expression>> _cspPrecompiledConstructorNames =
-      new Map<OutputUnit, List<jsAst.Expression>>();
-
-  /**
-   * Accumulate properties for classes and libraries, describing their
-   * static/top-level members.
-   * Later, these members are emitted when the class or library is emitted.
-   *
-   * See [getElementDescriptor].
-   */
-  // TODO(ahe): Generate statics with their class, and store only libraries in
-  // this map.
-  final Map<Fragment, Map<LibraryEntity, ClassBuilder>> libraryDescriptors =
-      new Map<Fragment, Map<LibraryEntity, ClassBuilder>>();
-
-  final Map<Fragment, Map<ClassEntity, ClassBuilder>> classDescriptors =
-      new Map<Fragment, Map<ClassEntity, ClassBuilder>>();
-
-  final bool generateSourceMap;
-
-  Emitter(this.compiler, this.namer, this._closedWorld, this.generateSourceMap,
-      this.task, Sorter sorter)
-      : classEmitter = new ClassEmitter(_closedWorld),
-        interceptorEmitter = new InterceptorEmitter(_closedWorld),
-        nsmEmitter = new NsmEmitter(_closedWorld),
-        _sorter = sorter,
-        containerBuilder = new ContainerBuilder(_closedWorld),
-        _constantOrdering = new ConstantOrdering(sorter) {
-    constantEmitter = new ConstantEmitter(
-        compiler.options,
-        _closedWorld.commonElements,
-        compiler.codegenWorldBuilder,
-        _closedWorld.rtiNeed,
-        compiler.backend.rtiEncoder,
-        _closedWorld.allocatorAnalysis,
-        task,
-        this.constantReference,
-        constantListGenerator);
-    containerBuilder.emitter = this;
-    classEmitter.emitter = this;
-    nsmEmitter.emitter = this;
-    interceptorEmitter.emitter = this;
-  }
-
-  DiagnosticReporter get reporter => compiler.reporter;
-
-  NativeData get _nativeData => _closedWorld.nativeData;
-
-  List<jsAst.Node> cspPrecompiledFunctionFor(OutputUnit outputUnit) {
-    return _cspPrecompiledFunctions.putIfAbsent(
-        outputUnit, () => new List<jsAst.Node>());
-  }
-
-  List<jsAst.Expression> cspPrecompiledConstructorNamesFor(
-      OutputUnit outputUnit) {
-    return _cspPrecompiledConstructorNames.putIfAbsent(
-        outputUnit, () => new List<jsAst.Expression>());
-  }
-
-  @override
-  bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
-    if (constant.isFunction) return true; // Already emitted.
-    if (constant.isPrimitive) return true; // Inlined.
-    if (constant.isDummy) return true; // Inlined.
-    // The name is null when the constant is already a JS constant.
-    // TODO(floitsch): every constant should be registered, so that we can
-    // share the ones that take up too much space (like some strings).
-    if (namer.constantName(constant) == null) return true;
-    return false;
-  }
-
-  @override
-  int compareConstants(ConstantValue a, ConstantValue b) {
-    // Inlined constants don't affect the order and sometimes don't even have
-    // names.
-    int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1;
-    int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1;
-    if (cmp1 + cmp2 < 2) return cmp1 - cmp2;
-
-    // Emit constant interceptors first. Constant interceptors for primitives
-    // might be used by code that builds other constants.  See Issue 18173.
-    if (a.isInterceptor != b.isInterceptor) {
-      return a.isInterceptor ? -1 : 1;
-    }
-
-    // Sorting by the long name clusters constants with the same constructor
-    // which compresses a tiny bit better.
-    int r = namer.constantLongName(a).compareTo(namer.constantLongName(b));
-    if (r != 0) return r;
-
-    // Resolve collisions in the long name by using a structural order.
-    return _constantOrdering.compare(a, b);
-  }
-
-  @override
-  jsAst.Expression constantReference(ConstantValue value) {
-    if (value.isFunction) {
-      FunctionConstantValue functionConstant = value;
-      return isolateStaticClosureAccess(functionConstant.element);
-    }
-
-    // We are only interested in the "isInlined" part, but it does not hurt to
-    // test for the other predicates.
-    if (isConstantInlinedOrAlreadyEmitted(value)) {
-      return constantEmitter.generate(value);
-    }
-    return js('#.#',
-        [namer.globalObjectForConstant(value), namer.constantName(value)]);
-  }
-
-  jsAst.Expression constantInitializerExpression(ConstantValue value) {
-    return constantEmitter.generate(value);
-  }
-
-  String get name => 'CodeEmitter';
-
-  String get finishIsolateConstructorName =>
-      '${namer.isolateName}.\$finishIsolateConstructor';
-  String get isolatePropertiesName =>
-      '${namer.isolateName}.${namer.isolatePropertiesName}';
-  String get lazyInitializerProperty => r'$lazy';
-  String get lazyInitializerName =>
-      '${namer.isolateName}.${lazyInitializerProperty}';
-  String get initName => 'init';
-
-  jsAst.Name get makeConstListProperty =>
-      namer.internalGlobal('makeConstantList');
-
-  /// For deferred loading we communicate the initializers via this global var.
-  final String deferredInitializers = r"$dart_deferred_initializers$";
-
-  /// Contains the global state that is needed to initialize and load a
-  /// deferred library.
-  String get globalsHolder => r"$globals$";
-
-  @override
-  jsAst.Expression generateEmbeddedGlobalAccess(String global) {
-    return js(generateEmbeddedGlobalAccessString(global));
-  }
-
-  String generateEmbeddedGlobalAccessString(String global) {
-    // TODO(floitsch): don't use 'init' as global embedder storage.
-    return '$initName.$global';
-  }
-
-  @override
-  jsAst.Expression isolateLazyInitializerAccess(FieldEntity element) {
-    return jsAst.js('#.#', [
-      namer.globalObjectForMember(element),
-      namer.lazyInitializerName(element)
-    ]);
-  }
-
-  @override
-  jsAst.Expression isolateStaticClosureAccess(FunctionEntity element) {
-    return jsAst.js('#.#()', [
-      namer.globalObjectForMember(element),
-      namer.staticClosureName(element)
-    ]);
-  }
-
-  @override
-  jsAst.PropertyAccess prototypeAccess(
-      ClassEntity element, bool hasBeenInstantiated) {
-    return jsAst.js('#.prototype', constructorAccess(element));
-  }
-
-  @override
-  jsAst.Template templateForBuiltin(JsBuiltin builtin) {
-    switch (builtin) {
-      case JsBuiltin.dartObjectConstructor:
-        return jsAst.js
-            .expressionTemplateYielding(typeAccess(commonElements.objectClass));
-
-      case JsBuiltin.isCheckPropertyToJsConstructorName:
-        int isPrefixLength = namer.operatorIsPrefix.length;
-        return jsAst.js.expressionTemplateFor('#.substring($isPrefixLength)');
-
-      case JsBuiltin.isFunctionType:
-        return backend.rtiEncoder.templateForIsFunctionType;
-
-      case JsBuiltin.isFutureOrType:
-        return backend.rtiEncoder.templateForIsFutureOrType;
-
-      case JsBuiltin.isVoidType:
-        return backend.rtiEncoder.templateForIsVoidType;
-
-      case JsBuiltin.isDynamicType:
-        return backend.rtiEncoder.templateForIsDynamicType;
-
-      case JsBuiltin.isJsInteropTypeArgument:
-        return backend.rtiEncoder.templateForIsJsInteropTypeArgument;
-
-      case JsBuiltin.rawRtiToJsConstructorName:
-        return jsAst.js.expressionTemplateFor("#.$typeNameProperty");
-
-      case JsBuiltin.rawRuntimeType:
-        return jsAst.js.expressionTemplateFor("#.constructor");
-
-      case JsBuiltin.isSubtype:
-        // TODO(floitsch): move this closer to where is-check properties are
-        // built.
-        String isPrefix = namer.operatorIsPrefix;
-        return jsAst.js
-            .expressionTemplateFor("('$isPrefix' + #) in #.prototype");
-
-      case JsBuiltin.isGivenTypeRti:
-        return jsAst.js.expressionTemplateFor('#.$typeNameProperty === #');
-
-      case JsBuiltin.getMetadata:
-        String metadataAccess =
-            generateEmbeddedGlobalAccessString(embeddedNames.METADATA);
-        return jsAst.js.expressionTemplateFor("$metadataAccess[#]");
-
-      case JsBuiltin.getType:
-        String typesAccess =
-            generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
-        return jsAst.js.expressionTemplateFor("$typesAccess[#]");
-
-      default:
-        reporter.internalError(
-            NO_LOCATION_SPANNABLE, "Unhandled Builtin: $builtin");
-        return null;
-    }
-  }
-
-  @override
-  int generatedSize(OutputUnit unit) {
-    return outputBuffers[unit].length;
-  }
-
-  List<jsAst.Statement> buildTrivialNsmHandlers() {
-    return nsmEmitter.buildTrivialNsmHandlers();
-  }
-
-  jsAst.Statement buildNativeInfoHandler(
-      jsAst.Expression infoAccess,
-      jsAst.Expression constructorAccess,
-      jsAst.Expression subclassReadGenerator(jsAst.Expression subclass),
-      jsAst.Expression interceptorsByTagAccess,
-      jsAst.Expression leafTagsAccess) {
-    return NativeGenerator.buildNativeInfoHandler(infoAccess, constructorAccess,
-        subclassReadGenerator, interceptorsByTagAccess, leafTagsAccess);
-  }
-
-  /// In minified mode we want to keep the name for the most common core types.
-  bool _isNativeTypeNeedingReflectionName(ClassEntity element) {
-    return (element == commonElements.intClass ||
-        element == commonElements.doubleClass ||
-        element == commonElements.numClass ||
-        element == commonElements.stringClass ||
-        element == commonElements.boolClass ||
-        element == commonElements.nullClass ||
-        element == commonElements.listClass);
-  }
-
-  /// Returns the "reflection name" of a [ClassEntity], if needed.
-  ///
-  /// The reflection name of class 'C' is 'C'.
-  /// An anonymous mixin application has no reflection name.
-  ///
-  /// This is used by js_mirrors.dart.
-  // TODO(johnniwinther): Do we still need this when js_mirrors is deleted?
-  String getReflectionClassName(ClassEntity cls, jsAst.Name mangledName) {
-    // Make sure to retain names of common native types.
-    if (_isNativeTypeNeedingReflectionName(cls)) {
-      assert(!cls.isClosure);
-      assert(!_elementEnvironment.isUnnamedMixinApplication(cls));
-      return cls.name;
-    }
-    return null;
-  }
-
-  String namedParametersAsReflectionNames(CallStructure structure) {
-    if (structure.isUnnamed) return '';
-    String names = structure.getOrderedNamedArguments().join(':');
-    return ':$names';
-  }
-
-  jsAst.Statement buildCspPrecompiledFunctionFor(OutputUnit outputUnit) {
-    if (compiler.options.useContentSecurityPolicy) {
-      // TODO(ahe): Compute a hash code.
-      // TODO(sigurdm): Avoid this precompiled function. Generated
-      // constructor-functions and getter/setter functions can be stored in the
-      // library-description table. Setting properties on these can be moved to
-      // finishClasses.
-      return js.statement(r"""
-        #precompiled = function ($collectedClasses$) {
-          #norename;
-          var $desc;
-          #functions;
-          return #result;
-        };""", {
-        'norename': new jsAst.Comment("// ::norenaming:: "),
-        'precompiled': generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED),
-        'functions': cspPrecompiledFunctionFor(outputUnit),
-        'result': new jsAst.ArrayInitializer(
-            cspPrecompiledConstructorNamesFor(outputUnit))
-      });
-    } else {
-      return js.comment("Constructors are generated at runtime.");
-    }
-  }
-
-  void assembleClass(
-      Class cls, ClassBuilder enclosingBuilder, Fragment fragment) {
-    ClassEntity classElement = cls.element;
-    reporter.withCurrentElement(classElement, () {
-      classEmitter.emitClass(cls, enclosingBuilder, fragment);
-    });
-  }
-
-  void assembleStaticFunctions(
-      Iterable<Method> staticFunctions, Fragment fragment) {
-    if (staticFunctions == null) return;
-
-    for (Method method in staticFunctions) {
-      FunctionEntity element = method.element;
-      // We need to filter out null-elements for the interceptors.
-      // TODO(floitsch): use the precomputed interceptors here.
-      if (element == null) continue;
-      ClassBuilder builder = new ClassBuilder.forStatics(element, namer);
-      containerBuilder.addMemberMethod(method, builder);
-      getStaticMethodDescriptor(element, fragment)
-          .properties
-          .addAll(builder.properties);
-    }
-  }
-
-  jsAst.Statement buildStaticNonFinalFieldInitializations(
-      OutputUnit outputUnit) {
-    jsAst.Statement buildInitialization(
-        FieldEntity element, jsAst.Expression initialValue) {
-      return js.statement('${namer.staticStateHolder}.# = #',
-          [namer.globalPropertyNameForMember(element), initialValue]);
-    }
-
-    bool inMainUnit = (outputUnit == _outputUnitData.mainOutputUnit);
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    Iterable<FieldEntity> fields = outputStaticNonFinalFieldLists[outputUnit];
-    // If the outputUnit does not contain any static non-final fields, then
-    // [fields] is `null`.
-    if (fields != null) {
-      for (FieldEntity element in fields) {
-        reporter.withCurrentElement(element, () {
-          ConstantValue constant =
-              _worldBuilder.getConstantFieldInitializer(element);
-          parts.add(buildInitialization(element, constantReference(constant)));
-        });
-      }
-    }
-
-    if (inMainUnit && outputStaticNonFinalFieldLists.length > 1) {
-      // In the main output-unit we output a stub initializer for deferred
-      // variables, so that `isolateProperties` stays a fast object.
-      outputStaticNonFinalFieldLists
-          .forEach((OutputUnit fieldsOutputUnit, Iterable<FieldEntity> fields) {
-        if (fieldsOutputUnit == outputUnit) return; // Skip the main unit.
-        for (FieldEntity element in fields) {
-          reporter.withCurrentElement(element, () {
-            parts.add(buildInitialization(element, jsAst.number(0)));
-          });
-        }
-      });
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildLazilyInitializedStaticFields(
-      Iterable<StaticField> lazyFields,
-      {bool isMainFragment: true}) {
-    if (lazyFields.isNotEmpty) {
-      needsLazyInitializer = true;
-      List<jsAst.Expression> laziesInfo =
-          buildLaziesInfo(lazyFields, isMainFragment);
-      return js.statement('''
-      (function(lazies) {
-        for (var i = 0; i < lazies.length; ) {
-          var fieldName = lazies[i++];
-          var getterName = lazies[i++];
-          var lazyValue = lazies[i++];
-          if (#notMinified) {
-            var staticName = lazies[i++];
-          }
-          if (#isDeferredFragment) {
-            var fieldHolder = lazies[i++];
-          }
-          // We build the lazy-check here:
-          //   lazyInitializer(fieldName, getterName, lazyValue, staticName);
-          // 'staticName' is used for error reporting in non-minified mode.
-          // 'lazyValue' must be a closure that constructs the initial value.
-          if (#isMainFragment) {
-            if (#notMinified) {
-              #lazy(fieldName, getterName, lazyValue, staticName);
-            } else {
-              #lazy(fieldName, getterName, lazyValue);
-            }
-          } else {
-            if (#notMinified) {
-              #lazy(fieldName, getterName, lazyValue, staticName, fieldHolder);
-            } else {
-              #lazy(fieldName, getterName, lazyValue, null, fieldHolder);
-            }
-          }
-        }
-      })(#laziesInfo)
-      ''', {
-        'notMinified': !compiler.options.enableMinification,
-        'laziesInfo': new jsAst.ArrayInitializer(laziesInfo),
-        'lazy': js(lazyInitializerName),
-        'isMainFragment': isMainFragment,
-        'isDeferredFragment': !isMainFragment
-      });
-    } else {
-      return js.comment("No lazy statics.");
-    }
-  }
-
-  List<jsAst.Expression> buildLaziesInfo(
-      Iterable<StaticField> lazies, bool isMainFragment) {
-    List<jsAst.Expression> laziesInfo = <jsAst.Expression>[];
-    for (StaticField field in lazies) {
-      laziesInfo.add(js.quoteName(field.name));
-      laziesInfo.add(js.quoteName(field.getterName));
-      laziesInfo.add(field.code);
-      if (!compiler.options.enableMinification) {
-        laziesInfo.add(js.quoteName(field.name));
-      }
-      if (!isMainFragment) {
-        laziesInfo.add(js('#', field.holder.name));
-      }
-    }
-    return laziesInfo;
-  }
-
-  jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    jsAst.Expression metadata = program.metadataForOutputUnit(outputUnit);
-    jsAst.Expression types = program.metadataTypesForOutputUnit(outputUnit);
-
-    if (outputUnit == _outputUnitData.mainOutputUnit) {
-      jsAst.Expression metadataAccess =
-          generateEmbeddedGlobalAccess(embeddedNames.METADATA);
-      jsAst.Expression typesAccess =
-          generateEmbeddedGlobalAccess(embeddedNames.TYPES);
-
-      parts
-        ..add(js.statement('# = #;', [metadataAccess, metadata]))
-        ..add(js.statement('# = #;', [typesAccess, types]));
-    } else if (types != null) {
-      parts.add(
-          js.statement('var ${namer.deferredMetadataName} = #;', metadata));
-      parts.add(js.statement('var ${namer.deferredTypesName} = #;', types));
-    }
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildCompileTimeConstants(List<Constant> constants,
-      {bool isMainFragment}) {
-    assert(isMainFragment != null);
-
-    if (constants.isEmpty) return js.comment("No constants in program.");
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-    for (Constant constant in constants) {
-      ConstantValue constantValue = constant.value;
-      parts.add(buildConstantInitializer(constantValue));
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildConstantInitializer(ConstantValue constant) {
-    jsAst.Name name = namer.constantName(constant);
-    jsAst.Statement initializer = js.statement('#.# = #', [
-      namer.globalObjectForConstant(constant),
-      name,
-      constantInitializerExpression(constant)
-    ]);
-    compiler.dumpInfoTask.registerConstantAst(constant, initializer);
-    return initializer;
-  }
-
-  jsAst.Expression constantListGenerator(jsAst.Expression array) {
-    // TODO(floitsch): there is no harm in caching the template.
-    return js('${namer.isolateName}.#(#)', [makeConstListProperty, array]);
-  }
-
-  jsAst.Statement buildMakeConstantList(bool outputContainsConstantList) {
-    if (outputContainsConstantList) {
-      return js.statement(r'''
-          // Functions are stored in the hidden class and not as properties in
-          // the object. We never actually look at the value, but only want
-          // to know if the property exists.
-          #.# = function (list) {
-            list.immutable$list = Array;
-            list.fixed$length = Array;
-            return list;
-          }''', [namer.isolateName, makeConstListProperty]);
-    } else {
-      return js.comment("Output contains no constant list.");
-    }
-  }
-
-  jsAst.Statement buildFunctionThatReturnsNull() {
-    return js.statement('#.# = function() {}',
-        [namer.isolateName, backend.rtiEncoder.getFunctionThatReturnsNullName]);
-  }
-
-  jsAst.Expression generateFunctionThatReturnsNull() {
-    return js("#.#",
-        [namer.isolateName, backend.rtiEncoder.getFunctionThatReturnsNullName]);
-  }
-
-  buildMain(jsAst.Statement invokeMain) {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    if (NativeGenerator.needsIsolateAffinityTagInitialization(
-        _closedWorld.backendUsage)) {
-      parts.add(NativeGenerator.generateIsolateAffinityTagInitialization(
-          _closedWorld.backendUsage, generateEmbeddedGlobalAccess, js("""
-        // On V8, the 'intern' function converts a string to a symbol, which
-        // makes property access much faster.
-        function (s) {
-          var o = {};
-          o[s] = 1;
-          return Object.keys(convertToFastObject(o))[0];
-        }""", [])));
-    }
-
-    parts
-      ..add(js.comment('BEGIN invoke [main].'))
-      ..add(invokeMain)
-      ..add(js.comment('END invoke [main].'));
-
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildInitFunction(bool outputContainsConstantList) {
-    jsAst.Expression allClassesAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
-    jsAst.Expression getTypeFromNameAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.GET_TYPE_FROM_NAME);
-    jsAst.Expression interceptorsByTagAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
-    jsAst.Expression leafTagsAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
-    jsAst.Expression finishedClassesAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
-    jsAst.Expression cyclicThrow =
-        staticFunctionAccess(commonElements.cyclicThrowHelper);
-    jsAst.Expression laziesAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
-
-    return js.statement("""
-      function init() {
-        $isolatePropertiesName = Object.create(null);
-        #allClasses = map();
-        #getTypeFromName = function(name) {return #allClasses[name];};
-        #interceptorsByTag = map();
-        #leafTags = map();
-        #finishedClasses = map();
-
-        if (#needsLazyInitializer) {
-          // [staticName] is only provided in non-minified mode. If missing, we
-          // fall back to [fieldName]. Likewise, [prototype] is optional and
-          // defaults to the isolateProperties object.
-          $lazyInitializerName = function (fieldName, getterName, lazyValue,
-                                           staticName, prototype) {
-            if (!#lazies) #lazies = Object.create(null);
-            #lazies[fieldName] = getterName;
-
-            // 'prototype' will be undefined except if we are doing an update
-            // during incremental compilation. In this case we put the lazy
-            // field directly on the isolate instead of the isolateProperties.
-            prototype = prototype || $isolatePropertiesName;
-            var sentinelUndefined = {};
-            var sentinelInProgress = {};
-            prototype[fieldName] = sentinelUndefined;
-
-            prototype[getterName] = function () {
-              var result = this[fieldName];
-              if (result == sentinelInProgress) {
-                // In minified mode, static name is not provided, so fall back
-                // to the minified fieldName.
-                #cyclicThrow(staticName || fieldName);
-              }
-              try {
-                if (result === sentinelUndefined) {
-                  this[fieldName] = sentinelInProgress;
-                  try {
-                    result = this[fieldName] = lazyValue();
-                  } finally {
-                    // Use try-finally, not try-catch/throw as it destroys the
-                    // stack trace.
-                    if (result === sentinelUndefined)
-                      this[fieldName] = null;
-                  }
-                }
-                return result;
-              } finally {
-                this[getterName] = function() { return this[fieldName]; };
-              }
-            }
-          }
-        }
-
-        // We replace the old Isolate function with a new one that initializes
-        // all its fields with the initial (and often final) value of all
-        // globals.
-        //
-        // We also copy over old values like the prototype, and the
-        // isolateProperties themselves.
-        $finishIsolateConstructorName = function (oldIsolate) {
-          var isolateProperties = oldIsolate.#isolatePropertiesName;
-          function Isolate() {
-
-            var staticNames = Object.keys(isolateProperties);
-            for (var i = 0; i < staticNames.length; i++) {
-              var staticName = staticNames[i];
-              this[staticName] = isolateProperties[staticName];
-            }
-
-            // Reset lazy initializers to null.
-            // When forcing the object to fast mode (below) v8 will consider
-            // functions as part the object's map. Since we will change them
-            // (after the first call to the getter), we would have a map
-            // transition.
-            var lazies = init.lazies;
-            var lazyInitializers = lazies ? Object.keys(lazies) : [];
-            for (var i = 0; i < lazyInitializers.length; i++) {
-               this[lazies[lazyInitializers[i]]] = null;
-            }
-
-            // Use the newly created object as prototype. In Chrome,
-            // this creates a hidden class for the object and makes
-            // sure it is fast to access.
-            function ForceEfficientMap() {}
-            ForceEfficientMap.prototype = this;
-            new ForceEfficientMap();
-
-            // Now, after being a fast map we can set the lazies again.
-            for (var i = 0; i < lazyInitializers.length; i++) {
-              var lazyInitName = lazies[lazyInitializers[i]];
-              this[lazyInitName] = isolateProperties[lazyInitName];
-            }
-          }
-          Isolate.prototype = oldIsolate.prototype;
-          Isolate.prototype.constructor = Isolate;
-          Isolate.#isolatePropertiesName = isolateProperties;
-          if (#outputContainsConstantList) {
-            Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty;
-          }
-          Isolate.#functionThatReturnsNullProperty =
-              oldIsolate.#functionThatReturnsNullProperty;
-          return Isolate;
-      }
-
-      }""", {
-      'allClasses': allClassesAccess,
-      'getTypeFromName': getTypeFromNameAccess,
-      'interceptorsByTag': interceptorsByTagAccess,
-      'leafTags': leafTagsAccess,
-      'finishedClasses': finishedClassesAccess,
-      'needsLazyInitializer': needsLazyInitializer,
-      'lazies': laziesAccess,
-      'cyclicThrow': cyclicThrow,
-      'isolatePropertiesName': namer.isolatePropertiesName,
-      'outputContainsConstantList': outputContainsConstantList,
-      'makeConstListProperty': makeConstListProperty,
-      'functionThatReturnsNullProperty':
-          backend.rtiEncoder.getFunctionThatReturnsNullName,
-    });
-  }
-
-  jsAst.Statement buildConvertToFastObjectFunction() {
-    List<jsAst.Statement> debugCode = <jsAst.Statement>[];
-    if (DEBUG_FAST_OBJECTS) {
-      debugCode.add(js.statement(r'''
-        // The following only works on V8 when run with option
-        // "--allow-natives-syntax".  We use'new Function' because the
-         // miniparser does not understand V8 native syntax.
-        if (typeof print === "function") {
-          var HasFastProperties =
-            new Function("a", "return %HasFastProperties(a)");
-          print("Size of global object: "
-                   + String(Object.getOwnPropertyNames(properties).length)
-                   + ", fast properties " + HasFastProperties(properties));
-        }'''));
-    }
-
-    return js.statement(r'''
-      function convertToFastObject(properties) {
-        // Create an instance that uses 'properties' as prototype. This should
-        // make 'properties' a fast object.
-        function MyClass() {};
-        MyClass.prototype = properties;
-        new MyClass();
-        #;
-        return properties;
-      }''', [debugCode]);
-  }
-
-  jsAst.Statement buildConvertToSlowObjectFunction() {
-    return js.statement(r'''
-    function convertToSlowObject(properties) {
-      // Add and remove a property to make the object transition into hashmap
-      // mode.
-      properties.__MAGIC_SLOW_PROPERTY = 1;
-      delete properties.__MAGIC_SLOW_PROPERTY;
-      return properties;
-    }''');
-  }
-
-  jsAst.Statement buildSupportsDirectProtoAccess() {
-    jsAst.Statement supportsDirectProtoAccess;
-
-    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;
-  }
-
-  jsAst.Expression generateLibraryDescriptor(
-      LibraryEntity library, Fragment fragment) {
-    dynamic uri = "";
-    if (!compiler.options.enableMinification) {
-      uri = library.canonicalUri;
-      if (uri.scheme == 'file' && compiler.options.outputUri != null) {
-        uri =
-            relativize(compiler.options.outputUri, library.canonicalUri, false);
-      }
-    }
-
-    String libraryName = !compiler.options.enableMinification
-        ? _elementEnvironment.getLibraryName(library)
-        : "";
-
-    jsAst.Fun metadata = null;
-
-    ClassBuilder descriptor = libraryDescriptors[fragment][library];
-
-    jsAst.ObjectInitializer initializer;
-    if (descriptor == null) {
-      // Nothing of the library was emitted.
-      // TODO(floitsch): this should not happen. We currently have an example
-      // with language/prefix6_negative_test.dart where we have an instance
-      // method without its corresponding class.
-      initializer = new jsAst.ObjectInitializer([]);
-    } else {
-      initializer = descriptor.toObjectInitializer();
-    }
-
-    compiler.dumpInfoTask.registerEntityAst(library, metadata);
-    compiler.dumpInfoTask.registerEntityAst(library, initializer);
-
-    List<jsAst.Expression> parts = <jsAst.Expression>[];
-    parts
-      ..add(js.string(libraryName))
-      ..add(js.string(uri.toString()))
-      ..add(metadata == null ? new jsAst.ArrayHole() : metadata)
-      ..add(js('#', namer.globalObjectForLibrary(library)))
-      ..add(initializer);
-    if (library == _closedWorld.elementEnvironment.mainLibrary) {
-      parts.add(js.number(1));
-    }
-
-    return new jsAst.ArrayInitializer(parts);
-  }
-
-  void assemblePrecompiledConstructor(
-      OutputUnit outputUnit,
-      jsAst.Name constructorName,
-      jsAst.Expression constructorAst,
-      List<jsAst.Name> fields) {
-    cspPrecompiledFunctionFor(outputUnit)
-        .add(new jsAst.FunctionDeclaration(constructorName, constructorAst));
-
-    cspPrecompiledFunctionFor(outputUnit).add(js.statement(r'''
-        {
-          #constructorName.#typeNameProperty = #constructorNameString;
-          // IE does not have a name property.
-          if (!("name" in #constructorName))
-              #constructorName.name = #constructorNameString;
-          $desc = $collectedClasses$.#constructorName[1];
-          #constructorName.prototype = $desc;
-        }''', {
-      "constructorName": constructorName,
-      "typeNameProperty": typeNameProperty,
-      "constructorNameString": js.quoteName(constructorName),
-    }));
-
-    cspPrecompiledConstructorNamesFor(outputUnit).add(js('#', constructorName));
-  }
-
-  jsAst.Statement buildGlobalObjectSetup(bool isProgramSplit) {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    parts.add(js.comment("""
-      // The global objects start as so-called "slow objects". For V8, this
-      // means that it won't try to make map transitions as we add properties
-      // to these objects. Later on, we attempt to turn these objects into
-      // fast objects by calling "convertToFastObject" (see
-      // [emitConvertToFastObjectFunction]).
-      """));
-
-    for (String globalObject in Namer.reservedGlobalObjectNames) {
-      if (isProgramSplit) {
-        String template =
-            "var #globalObject = #globalsHolder.#globalObject = map();";
-        parts.add(js.statement(template,
-            {"globalObject": globalObject, "globalsHolder": globalsHolder}));
-      } else {
-        parts.add(js.statement(
-            "var #globalObject = map();", {"globalObject": globalObject}));
-      }
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildConvertGlobalObjectToFastObjects() {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    for (String globalObject in Namer.reservedGlobalObjectNames) {
-      parts.add(js.statement(
-          '#globalObject = convertToFastObject(#globalObject);',
-          {"globalObject": globalObject}));
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildDebugFastObjectCode() {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    if (DEBUG_FAST_OBJECTS) {
-      parts.add(js.statement(r'''
-          // The following only works on V8 when run with option
-          // "--allow-natives-syntax".  We use'new Function' because the
-          // miniparser does not understand V8 native syntax.
-          if (typeof print === "function") {
-            var HasFastProperties =
-              new Function("a", "return %HasFastProperties(a)");
-            print("Size of global helper object: "
-                   + String(Object.getOwnPropertyNames(H).length)
-                   + ", fast properties " + HasFastProperties(H));
-            print("Size of global platform object: "
-                   + String(Object.getOwnPropertyNames(P).length)
-                   + ", fast properties " + HasFastProperties(P));
-            print("Size of global dart:html object: "
-                   + String(Object.getOwnPropertyNames(W).length)
-                   + ", fast properties " + HasFastProperties(W));
-            print("Size of isolate properties object: "
-                   + String(Object.getOwnPropertyNames($).length)
-                   + ", fast properties " + HasFastProperties($));
-            print("Size of constant object: "
-                   + String(Object.getOwnPropertyNames(C).length)
-                   + ", fast properties " + HasFastProperties(C));
-            var names = Object.getOwnPropertyNames($);
-            for (var i = 0; i < names.length; i++) {
-              print("$." + names[i]);
-            }
-          }
-       '''));
-
-      for (String object in Namer.userGlobalObjects) {
-        parts.add(js.statement('''
-          if (typeof print === "function") {
-            print("Size of " + #objectString + ": "
-                  + String(Object.getOwnPropertyNames(#object).length)
-                  + ", fast properties " + HasFastProperties(#object));
-          }
-        ''', {"object": object, "objectString": js.string(object)}));
-      }
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  void checkEverythingEmitted(
-      Map<ClassEntity, ClassBuilder> pendingClassBuilders) {
-    if (pendingClassBuilders == null) return;
-    List<ClassEntity> pendingClasses =
-        _sorter.sortClasses(pendingClassBuilders.keys);
-
-    pendingClasses.forEach((ClassEntity element) => reporter.reportInfo(
-        element, MessageKind.GENERIC, {'text': 'Pending statics.'}));
-
-    if (pendingClasses != null && !pendingClasses.isEmpty) {
-      reporter.internalError(
-          pendingClasses.first, 'Pending statics (see above).');
-    }
-  }
-
-  void assembleLibrary(Library library, Fragment fragment) {
-    LibraryEntity libraryElement = library.element;
-
-    assembleStaticFunctions(library.statics, fragment);
-
-    ClassBuilder libraryBuilder =
-        getLibraryDescriptor(libraryElement, fragment);
-    for (Class cls in library.classes) {
-      assembleClass(cls, libraryBuilder, fragment);
-    }
-
-    classEmitter.emitFields(library, libraryBuilder, emitStatics: true);
-  }
-
-  void assembleProgram(Program program) {
-    for (Fragment fragment in program.fragments) {
-      for (Library library in fragment.libraries) {
-        assembleLibrary(library, fragment);
-      }
-    }
-  }
-
-  jsAst.Statement buildDeferredHeader() {
-    /// For deferred loading we communicate the initializers via this global
-    /// variable. The deferred hunks will add their initialization to this.
-    /// The semicolon is important in minified mode, without it the
-    /// following parenthesis looks like a call to the object literal.
-    return js.statement(
-        'self.#deferredInitializers = '
-        'self.#deferredInitializers || Object.create(null);',
-        {'deferredInitializers': deferredInitializers});
-  }
-
-  jsAst.Program buildOutputAstForMain(Program program,
-      Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes) {
-    MainFragment mainFragment = program.mainFragment;
-    OutputUnit mainOutputUnit = mainFragment.outputUnit;
-    bool isProgramSplit = program.isSplit;
-
-    List<jsAst.Statement> statements = <jsAst.Statement>[];
-
-    statements..add(buildGeneratedBy())..add(js.comment(HOOKS_API_USAGE));
-
-    if (isProgramSplit) {
-      statements.add(buildDeferredHeader());
-    }
-
-    // Collect the AST for the descriptors.
-    Map<LibraryEntity, ClassBuilder> descriptors =
-        libraryDescriptors[mainFragment] ?? const {};
-
-    checkEverythingEmitted(classDescriptors[mainFragment]);
-
-    Iterable<LibraryEntity> libraries = outputLibraryLists[mainOutputUnit];
-    if (libraries == null) libraries = <LibraryEntity>[];
-
-    List<jsAst.Expression> parts = <jsAst.Expression>[];
-    for (LibraryEntity library in _sorter.sortLibraries(libraries)) {
-      parts.add(generateLibraryDescriptor(library, mainFragment));
-      descriptors.remove(library);
-    }
-
-    if (descriptors.isNotEmpty) {
-      List<LibraryEntity> remainingLibraries = descriptors.keys.toList();
-
-      // The remaining descriptors are only accessible through reflection.
-      // The program builder does not collect libraries that only
-      // contain typedefs that are used for reflection.
-      for (LibraryEntity element in remainingLibraries) {
-        parts.add(generateLibraryDescriptor(element, mainFragment));
-        descriptors.remove(element);
-      }
-    }
-    jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts);
-
-    // Using a named function here produces easier to read stack traces in
-    // Chrome/V8.
-    statements.add(js.statement("""
-    (function() {
-       // No renaming in the top-level function to save the locals for the
-       // nested context where they will be used more. We have to put the
-       // comment into a hole as the parser strips out comments right away.
-       #disableVariableRenaming;
-       #supportsDirectProtoAccess;
-
-       if (#isProgramSplit) {
-         /// We collect all the global state, so it can be passed to the
-         /// initializer of deferred files.
-         var #globalsHolder = Object.create(null)
-       }
-
-       // [map] returns an object that V8 shouldn't try to optimize with a
-       // hidden class. This prevents a potential performance problem where V8
-       // tries to build a hidden class for an object used as a hashMap.
-       // It requires fewer characters to declare a variable as a parameter than
-       // with `var`.
-       function map(x) {
-         x = Object.create(null);
-         x.x = 0;
-         delete x.x;
-         return x;
-       }
-
-       #globalObjectSetup;
-
-       function #isolateName() {}
-
-       if (#isProgramSplit) {
-         #globalsHolder.#isolateName = #isolateName;
-         #globalsHolder.#initName = #initName;
-         #globalsHolder.#setupProgramName = #setupProgramName;
-       }
-
-       init();
-
-       #cspPrecompiledFunctions;
-
-       #setupProgram;
-
-       #functionThatReturnsNull;
-
-       // The argument to reflectionDataParser is assigned to a temporary 'dart'
-       // so that 'dart.' will appear as the prefix to dart methods in stack
-       // traces and profile entries.
-       var dart = #descriptors;
-
-       #setupProgramName(dart, 0, 0);
-
-       #getInterceptorMethods;
-       #oneShotInterceptors;
-
-       #makeConstantList;
-
-       // We abuse the short name used for the isolate here to store
-       // the isolate properties. This is safe as long as the real isolate
-       // object does not exist yet.
-       var ${namer.staticStateHolder} = #isolatePropertiesName;
-
-       // Constants in checked mode call into RTI code to set type information
-       // which may need getInterceptor (and one-shot interceptor) methods, so
-       // we have to make sure that [emitGetInterceptorMethods] and
-       // [emitOneShotInterceptors] have been called.
-       #compileTimeConstants;
-
-       // Static field initializations require the classes and compile-time
-       // constants to be set up.
-       #staticNonFinalInitializers;
-
-       ${namer.staticStateHolder} = null;
-
-       #deferredBoilerPlate;
-
-       #typeToInterceptorMap;
-
-       #lazyStaticFields;
-
-       #isolateName = $finishIsolateConstructorName(#isolateName);
-
-       ${namer.staticStateHolder} = new #isolateName();
-
-       #metadata;
-
-       #convertToFastObject;
-       #convertToSlowObject;
-
-       #convertGlobalObjectsToFastObjects;
-       #debugFastObjects;
-
-       #init;
-
-       #main;
-    })();
-    """, {
-      "disableVariableRenaming": js.comment("/* ::norenaming:: */"),
-      "isProgramSplit": isProgramSplit,
-      "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(),
-      "globalsHolder": globalsHolder,
-      "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit),
-      "isolateName": namer.isolateName,
-      "isolatePropertiesName": js(isolatePropertiesName),
-      "initName": initName,
-      "functionThatReturnsNull": buildFunctionThatReturnsNull(),
-      "setupProgram": buildSetupProgram(
-          program, compiler, backend, namer, this, _closedWorld),
-      "setupProgramName": setupProgramName,
-      "descriptors": descriptorsAst,
-      "cspPrecompiledFunctions": buildCspPrecompiledFunctionFor(mainOutputUnit),
-      "getInterceptorMethods": interceptorEmitter.buildGetInterceptorMethods(),
-      "oneShotInterceptors": interceptorEmitter.buildOneShotInterceptors(),
-      "makeConstantList":
-          buildMakeConstantList(program.outputContainsConstantList),
-      "compileTimeConstants": buildCompileTimeConstants(mainFragment.constants,
-          isMainFragment: true),
-      "deferredBoilerPlate": buildDeferredBoilerPlate(deferredLoadHashes),
-      "staticNonFinalInitializers":
-          buildStaticNonFinalFieldInitializations(mainOutputUnit),
-      "typeToInterceptorMap":
-          interceptorEmitter.buildTypeToInterceptorMap(program),
-      "lazyStaticFields": buildLazilyInitializedStaticFields(
-          mainFragment.staticLazilyInitializedFields),
-      "metadata": buildMetadata(program, mainOutputUnit),
-      "convertToFastObject": buildConvertToFastObjectFunction(),
-      "convertToSlowObject": buildConvertToSlowObjectFunction(),
-      "convertGlobalObjectsToFastObjects":
-          buildConvertGlobalObjectToFastObjects(),
-      "debugFastObjects": buildDebugFastObjectCode(),
-      "init": buildInitFunction(program.outputContainsConstantList),
-      "main": buildMain(mainFragment.invokeMain)
-    }));
-
-    return new jsAst.Program(statements);
-  }
-
-  void emitMainOutputUnit(OutputUnit mainOutputUnit, jsAst.Program program) {
-    LocationCollector locationCollector;
-    List<CodeOutputListener> codeOutputListeners;
-    if (generateSourceMap) {
-      locationCollector = new LocationCollector();
-      codeOutputListeners = <CodeOutputListener>[locationCollector];
-    }
-
-    CodeOutput mainOutput = new StreamCodeOutput(
-        compiler.outputProvider.createOutputSink('', 'js', OutputType.js),
-        codeOutputListeners);
-    outputBuffers[mainOutputUnit] = mainOutput;
-
-    mainOutput.addBuffer(jsAst.createCodeBuffer(
-        program, compiler.options, backend.sourceInformationStrategy,
-        monitor: compiler.dumpInfoTask));
-
-    if (compiler.options.deferredMapUri != null) {
-      outputDeferredMap();
-    }
-
-    if (generateSourceMap) {
-      mainOutput.add(SourceMapBuilder.generateSourceMapTag(
-          compiler.options.sourceMapUri, compiler.options.outputUri));
-    }
-
-    mainOutput.close();
-
-    if (generateSourceMap) {
-      SourceMapBuilder.outputSourceMap(
-          mainOutput,
-          locationCollector,
-          namer.createMinifiedGlobalNameMap(),
-          namer.createMinifiedInstanceNameMap(),
-          '',
-          compiler.options.sourceMapUri,
-          compiler.options.outputUri,
-          compiler.outputProvider);
-    }
-  }
-
-  Map<OutputUnit, jsAst.Expression> buildDescriptorsForOutputUnits(
-      Program program) {
-    Map<OutputUnit, jsAst.Expression> outputs =
-        new Map<OutputUnit, jsAst.Expression>();
-
-    for (Fragment fragment in program.deferredFragments) {
-      OutputUnit outputUnit = fragment.outputUnit;
-
-      Map<LibraryEntity, ClassBuilder> descriptors =
-          libraryDescriptors[fragment];
-
-      if (descriptors != null && descriptors.isNotEmpty) {
-        Iterable<LibraryEntity> libraries = outputLibraryLists[outputUnit];
-        if (libraries == null) libraries = <LibraryEntity>[];
-
-        // TODO(johnniwinther): Avoid creating [CodeBuffer]s.
-        List<jsAst.Expression> parts = <jsAst.Expression>[];
-        for (LibraryEntity library in _sorter.sortLibraries(libraries)) {
-          parts.add(generateLibraryDescriptor(library, fragment));
-          descriptors.remove(library);
-        }
-
-        outputs[outputUnit] = new jsAst.ArrayInitializer(parts);
-      }
-    }
-
-    return outputs;
-  }
-
-  void finalizeTokensInAst(
-      jsAst.Program main, Iterable<jsAst.Program> deferredParts) {
-    jsAst.TokenCounter counter = new jsAst.TokenCounter();
-    counter.countTokens(main);
-    deferredParts.forEach(counter.countTokens);
-    task.metadataCollector.finalizeTokens();
-    if (backend.namer is jsAst.TokenFinalizer) {
-      dynamic finalizer = backend.namer;
-      finalizer.finalizeTokens();
-    }
-  }
-
-  int emitProgram(ProgramBuilder programBuilder) {
-    Program program =
-        programBuilder.buildProgram(storeFunctionTypesInMetadata: true);
-    if (retainDataForTesting) {
-      programForTesting = program;
-    }
-
-    outputStaticNonFinalFieldLists =
-        programBuilder.collector.outputStaticNonFinalFieldLists;
-    outputLibraryLists = programBuilder.collector.outputLibraryLists;
-
-    assembleProgram(program);
-
-    // Construct the ASTs for all deferred output units.
-    Map<OutputUnit, jsAst.Program> deferredParts =
-        buildOutputAstForDeferredCode(program);
-
-    Map<OutputUnit, _DeferredOutputUnitHash> deferredHashTokens =
-        new Map<OutputUnit, _DeferredOutputUnitHash>.fromIterables(
-            deferredParts.keys, deferredParts.keys.map((OutputUnit unit) {
-      return new _DeferredOutputUnitHash(unit);
-    }));
-
-    jsAst.Program mainOutput =
-        buildOutputAstForMain(program, deferredHashTokens);
-
-    finalizeTokensInAst(mainOutput, deferredParts.values);
-
-    // Emit deferred units first, so we have their hashes.
-    // Map from OutputUnit to a hash of its content. The hash uniquely
-    // identifies the code of the output-unit. It does not include
-    // boilerplate JS code, like the sourcemap directives or the hash
-    // itself.
-    Map<OutputUnit, String> deferredLoadHashes =
-        emitDeferredOutputUnits(deferredParts);
-
-    deferredHashTokens.forEach((OutputUnit key, _DeferredOutputUnitHash token) {
-      token.setHash(deferredLoadHashes[key]);
-    });
-    emitMainOutputUnit(program.mainFragment.outputUnit, mainOutput);
-
-    if (_closedWorld.backendUsage.requiresPreamble &&
-        !backend.htmlLibraryIsLoaded) {
-      reporter.reportHintMessage(NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
-    }
-    // Return the total program size.
-    return outputBuffers.values.fold(0, (a, b) => a + b.length);
-  }
-
-  ClassBuilder getStaticMethodDescriptor(
-      FunctionEntity element, Fragment fragment) {
-    if (!_nativeData.isNativeMember(element)) {
-      // For static (not top level) elements, record their code in a buffer
-      // specific to the class. For now, not supported for native classes and
-      // native elements.
-      ClassEntity cls = element.enclosingClass;
-      if (compiler.codegenWorldBuilder.directlyInstantiatedClasses
-              .contains(cls) &&
-          !_nativeData.isNativeClass(cls) &&
-          _outputUnitData.outputUnitForMember(element) ==
-              _outputUnitData.outputUnitForClass(cls)) {
-        return classDescriptors
-            .putIfAbsent(fragment, () => new Map<ClassEntity, ClassBuilder>())
-            .putIfAbsent(cls, () {
-          return new ClassBuilder.forClass(cls, namer);
-        });
-      }
-    }
-    return _getLibraryDescriptor(element, element.library, fragment);
-  }
-
-  ClassBuilder getLibraryDescriptor(LibraryEntity element, Fragment fragment) {
-    return _getLibraryDescriptor(element, element, fragment);
-  }
-
-  ClassBuilder _getLibraryDescriptor(
-      Entity element, LibraryEntity owner, Fragment fragment) {
-    if (owner == null) {
-      reporter.internalError(element, 'Owner is null.');
-    }
-    return libraryDescriptors
-        .putIfAbsent(fragment, () => new Map<LibraryEntity, ClassBuilder>())
-        .putIfAbsent(owner, () {
-      return new ClassBuilder.forLibrary(owner, namer);
-    });
-  }
-
-  /// Emits support-code for deferred loading into [output].
-  jsAst.Statement buildDeferredBoilerPlate(
-      Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes) {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    parts.add(js.statement('''
-        {
-          // Function for checking if a hunk is loaded given its hash.
-          #isHunkLoaded = function(hunkHash) {
-            return !!$deferredInitializers[hunkHash];
-          };
-          #deferredInitialized = new Object(null);
-          // Function for checking if a hunk is initialized given its hash.
-          #isHunkInitialized = function(hunkHash) {
-            return #deferredInitialized[hunkHash];
-          };
-          // Function for initializing a loaded hunk, given its hash.
-          #initializeLoadedHunk = function(hunkHash) {
-            var hunk = $deferredInitializers[hunkHash];
-            if (hunk == null) {
-                throw "DeferredLoading state error: code with hash '" +
-                    hunkHash + "' was not loaded";
-            }
-            hunk(#globalsHolder, ${namer.staticStateHolder});
-            #deferredInitialized[hunkHash] = true;
-          };
-        }
-        ''', {
-      "globalsHolder": globalsHolder,
-      "isHunkLoaded":
-          generateEmbeddedGlobalAccess(embeddedNames.IS_HUNK_LOADED),
-      "isHunkInitialized":
-          generateEmbeddedGlobalAccess(embeddedNames.IS_HUNK_INITIALIZED),
-      "initializeLoadedHunk":
-          generateEmbeddedGlobalAccess(embeddedNames.INITIALIZE_LOADED_HUNK),
-      "deferredInitialized":
-          generateEmbeddedGlobalAccess(embeddedNames.DEFERRED_INITIALIZED)
-    }));
-
-    void store(
-        jsAst.Expression map, jsAst.Expression uris, jsAst.Expression hashes) {
-      void assign(String name, jsAst.Expression value) {
-        parts.add(
-            js.statement('# = #', [generateEmbeddedGlobalAccess(name), value]));
-      }
-
-      assign(embeddedNames.DEFERRED_LIBRARY_PARTS, map);
-      assign(embeddedNames.DEFERRED_PART_URIS, uris);
-      assign(embeddedNames.DEFERRED_PART_HASHES, hashes);
-    }
-
-    createDeferredLoadingData(
-        _closedWorld.outputUnitData.hunksToLoad, deferredLoadHashes, store);
-
-    return new jsAst.Block(parts);
-  }
-
-  // Create data used for loading and initializing the hunks for a deferred
-  // import. There are three parts: a map from loadId to list of parts, where
-  // parts are represented as an index; an array of uris indexed by part; and an
-  // array of hashes indexed by part.
-  void createDeferredLoadingData(
-      Map<String, List<OutputUnit>> loadMap,
-      Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes,
-      void finish(jsAst.Expression map, jsAst.Expression uris,
-          jsAst.Expression hashes)) {
-    Map<OutputUnit, int> fragmentIndexes = <OutputUnit, int>{};
-    var uris = <jsAst.Expression>[];
-    var hashes = <jsAst.Expression>[];
-
-    List<jsAst.Property> libraryPartsMapEntries = <jsAst.Property>[];
-
-    loadMap.forEach((String loadId, List<OutputUnit> fragmentList) {
-      List<jsAst.Expression> indexes = <jsAst.Expression>[];
-      for (OutputUnit fragment in fragmentList) {
-        int index = fragmentIndexes[fragment];
-        if (index == null) {
-          index = fragmentIndexes[fragment] = fragmentIndexes.length;
-          uris.add(js.escapedString(
-              deferredPartFileName(compiler.options, fragment.name)));
-          _DeferredOutputUnitHash hash = deferredLoadHashes[fragment];
-          assert(hash != null, "No hash for $fragment in $deferredLoadHashes.");
-          hashes.add(hash);
-        }
-        indexes.add(js.number(index));
-      }
-      libraryPartsMapEntries.add(new jsAst.Property(
-          js.string(loadId), new jsAst.ArrayInitializer(indexes)));
-    });
-
-    finish(new jsAst.ObjectInitializer(libraryPartsMapEntries),
-        new jsAst.ArrayInitializer(uris), new jsAst.ArrayInitializer(hashes));
-  }
-
-  Map<OutputUnit, jsAst.Program> buildOutputAstForDeferredCode(
-      Program program) {
-    if (!program.isSplit) return const <OutputUnit, jsAst.Program>{};
-
-    Map<OutputUnit, jsAst.Program> result =
-        new Map<OutputUnit, jsAst.Program>();
-
-    Map<OutputUnit, jsAst.Expression> deferredAsts =
-        buildDescriptorsForOutputUnits(program);
-
-    for (Fragment fragment in program.deferredFragments) {
-      OutputUnit outputUnit = fragment.outputUnit;
-      jsAst.Expression libraryDescriptor = deferredAsts[outputUnit];
-      List<jsAst.Statement> body = <jsAst.Statement>[];
-
-      // No renaming in the top-level function to save the locals for the
-      // nested context where they will be used more.
-      body.add(js.comment("/* ::norenaming:: "));
-
-      for (String globalObject in Namer.reservedGlobalObjectNames) {
-        body.add(js.statement('var #object = #globalsHolder.#object;',
-            {'globalsHolder': globalsHolder, 'object': globalObject}));
-      }
-      body
-        ..add(js.statement('var init = #globalsHolder.init;',
-            {'globalsHolder': globalsHolder}))
-        ..add(js.statement(
-            'var $setupProgramName = '
-            '#globalsHolder.$setupProgramName;',
-            {'globalsHolder': globalsHolder}))
-        ..add(js.statement(
-            'var ${namer.isolateName} = '
-            '#globalsHolder.${namer.isolateName};',
-            {'globalsHolder': globalsHolder}));
-      String metadataAccess =
-          generateEmbeddedGlobalAccessString(embeddedNames.METADATA);
-      String typesAccess =
-          generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
-      if (libraryDescriptor != null) {
-        // The argument to reflectionDataParser is assigned to a temporary
-        // 'dart' so that 'dart.' will appear as the prefix to dart methods
-        // in stack traces and profile entries.
-        body.add(js.statement('var dart = #', libraryDescriptor));
-
-        if (compiler.options.useContentSecurityPolicy) {
-          body.add(buildCspPrecompiledFunctionFor(outputUnit));
-        }
-        body.add(js.statement('$setupProgramName('
-            'dart, ${metadataAccess}.length, ${typesAccess}.length);'));
-      }
-
-      body
-        ..add(buildMetadata(program, outputUnit))
-        ..add(js.statement('${metadataAccess}.push.apply(${metadataAccess}, '
-            '${namer.deferredMetadataName});'))
-        ..add(js.statement('${typesAccess}.push.apply(${typesAccess}, '
-            '${namer.deferredTypesName});'));
-
-      body.add(
-          buildCompileTimeConstants(fragment.constants, isMainFragment: false));
-      body.add(buildStaticNonFinalFieldInitializations(outputUnit));
-      body.add(buildLazilyInitializedStaticFields(
-          fragment.staticLazilyInitializedFields,
-          isMainFragment: false));
-
-      List<jsAst.Statement> statements = <jsAst.Statement>[];
-
-      statements
-        ..add(buildGeneratedBy())
-        ..add(buildDeferredHeader())
-        ..add(js.statement(
-            '${deferredInitializers}.current = '
-            """function (#, ${namer.staticStateHolder}) {
-                                  #
-                                }
-                             """,
-            [globalsHolder, body]));
-
-      result[outputUnit] = new jsAst.Program(statements);
-    }
-
-    return result;
-  }
-
-  /// Returns a map from OutputUnit to a hash of its content. The hash uniquely
-  /// identifies the code of the output-unit. It does not include
-  /// boilerplate JS code, like the sourcemap directives or the hash
-  /// itself.
-  Map<OutputUnit, String> emitDeferredOutputUnits(
-      Map<OutputUnit, jsAst.Program> outputAsts) {
-    Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>();
-
-    for (OutputUnit outputUnit in outputAsts.keys) {
-      List<CodeOutputListener> outputListeners = <CodeOutputListener>[];
-      Hasher hasher = new Hasher();
-      outputListeners.add(hasher);
-
-      LocationCollector locationCollector;
-      if (generateSourceMap) {
-        locationCollector = new LocationCollector();
-        outputListeners.add(locationCollector);
-      }
-
-      String partPrefix = deferredPartFileName(
-          compiler.options, outputUnit.name,
-          addExtension: false);
-      CodeOutput output = new StreamCodeOutput(
-          compiler.outputProvider
-              .createOutputSink(partPrefix, 'part.js', OutputType.jsPart),
-          outputListeners);
-
-      outputBuffers[outputUnit] = output;
-
-      output.addBuffer(jsAst.createCodeBuffer(outputAsts[outputUnit],
-          compiler.options, backend.sourceInformationStrategy,
-          monitor: compiler.dumpInfoTask));
-
-      // Make a unique hash of the code (before the sourcemaps are added)
-      // This will be used to retrieve the initializing function from the global
-      // variable.
-      String hash = hasher.getHash();
-
-      output.add('$N${deferredInitializers}["$hash"]$_=$_'
-          '${deferredInitializers}.current$N');
-
-      if (generateSourceMap) {
-        Uri mapUri, partUri;
-        Uri sourceMapUri = compiler.options.sourceMapUri;
-        Uri outputUri = compiler.options.outputUri;
-
-        String partName = "$partPrefix.part";
-
-        if (sourceMapUri != null) {
-          String mapFileName = partName + ".js.map";
-          List<String> mapSegments = sourceMapUri.pathSegments.toList();
-          mapSegments[mapSegments.length - 1] = mapFileName;
-          mapUri =
-              compiler.options.sourceMapUri.replace(pathSegments: mapSegments);
-        }
-
-        if (outputUri != null) {
-          String partFileName = partName + ".js";
-          List<String> partSegments = outputUri.pathSegments.toList();
-          partSegments[partSegments.length - 1] = partFileName;
-          partUri =
-              compiler.options.outputUri.replace(pathSegments: partSegments);
-        }
-
-        output.add(SourceMapBuilder.generateSourceMapTag(mapUri, partUri));
-        output.close();
-        SourceMapBuilder.outputSourceMap(output, locationCollector, {}, {},
-            partName, mapUri, partUri, compiler.outputProvider);
-      } else {
-        output.close();
-      }
-
-      hunkHashes[outputUnit] = hash;
-    }
-    return hunkHashes;
-  }
-
-  jsAst.Comment buildGeneratedBy() {
-    StringBuffer flavor = new StringBuffer();
-    flavor.write('full emitter');
-    // TODO(johnniwinther): Remove this flavor.
-    flavor.write(', strong');
-    if (compiler.options.trustPrimitives) flavor.write(', trust primitives');
-    if (compiler.options.omitImplicitChecks) flavor.write(', omit checks');
-    if (compiler.options.laxRuntimeTypeToString) {
-      flavor.write(', lax runtime type');
-    }
-    if (compiler.options.useContentSecurityPolicy) flavor.write(', CSP');
-    if (_closedWorld.backendUsage.isMirrorsUsed) flavor.write(', mirrors');
-    return new jsAst.Comment(generatedBy(compiler, flavor: '$flavor'));
-  }
-
-  void outputDeferredMap() {
-    Map<String, dynamic> mapping = new Map<String, dynamic>();
-    // Json does not support comments, so we embed the explanation in the
-    // data.
-    mapping["_comment"] = "This mapping shows which compiled `.js` files are "
-        "needed for a given deferred library import.";
-    mapping.addAll(_closedWorld.outputUnitData
-        .computeDeferredMap(compiler.options, _elementEnvironment));
-    compiler.outputProvider.createOutputSink(
-        compiler.options.deferredMapUri.path, '', OutputType.deferredMap)
-      ..add(const JsonEncoder.withIndent("  ").convert(mapping))
-      ..close();
-  }
-}
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
deleted file mode 100644
index e7afba7..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
+++ /dev/null
@@ -1,109 +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.js_emitter.full_emitter.interceptor_emitter;
-
-import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
-import '../../elements/entities.dart';
-import '../../js/js.dart' as jsAst;
-import '../../js/js.dart' show js;
-import '../../world.dart' show JClosedWorld;
-import '../js_emitter.dart' hide Emitter, EmitterFactory;
-import '../model.dart';
-import 'emitter.dart';
-
-class InterceptorEmitter extends CodeEmitterHelper {
-  final JClosedWorld closedWorld;
-  final Set<jsAst.Name> interceptorInvocationNames = new Set<jsAst.Name>();
-
-  InterceptorEmitter(this.closedWorld);
-
-  void recordMangledNameOfMemberMethod(MemberEntity member, jsAst.Name name) {
-    if (closedWorld.interceptorData.isInterceptedMethod(member)) {
-      interceptorInvocationNames.add(name);
-    }
-  }
-
-  jsAst.Expression buildGetInterceptorMethod(
-      jsAst.Name key, Set<ClassEntity> classes) {
-    InterceptorStubGenerator stubGenerator = new InterceptorStubGenerator(
-        compiler.options,
-        closedWorld.commonElements,
-        backend.emitter,
-        backend.nativeCodegenEnqueuer,
-        namer,
-        backend.oneShotInterceptorData,
-        backend.customElementsCodegenAnalysis,
-        compiler.codegenWorldBuilder,
-        closedWorld);
-    jsAst.Expression function =
-        stubGenerator.generateGetInterceptorMethod(classes);
-
-    return function;
-  }
-
-  /**
-   * Emit all versions of the [:getInterceptor:] method.
-   */
-  jsAst.Statement buildGetInterceptorMethods() {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-
-    parts.add(js.comment('getInterceptor methods'));
-
-    Iterable<jsAst.Name> names =
-        backend.oneShotInterceptorData.specializedGetInterceptorNames;
-    for (jsAst.Name name in names) {
-      Set<ClassEntity> classes =
-          backend.oneShotInterceptorData.getSpecializedGetInterceptorsFor(name);
-      parts.add(js.statement('#.# = #', [
-        namer.globalObjectForLibrary(
-            closedWorld.commonElements.interceptorsLibrary),
-        name,
-        buildGetInterceptorMethod(name, classes)
-      ]));
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  jsAst.Statement buildOneShotInterceptors() {
-    List<jsAst.Statement> parts = <jsAst.Statement>[];
-    Iterable<jsAst.Name> names =
-        backend.oneShotInterceptorData.oneShotInterceptorNames;
-
-    InterceptorStubGenerator stubGenerator = new InterceptorStubGenerator(
-        compiler.options,
-        closedWorld.commonElements,
-        backend.emitter,
-        backend.nativeCodegenEnqueuer,
-        namer,
-        backend.oneShotInterceptorData,
-        backend.customElementsCodegenAnalysis,
-        compiler.codegenWorldBuilder,
-        closedWorld);
-    String globalObject = namer
-        .globalObjectForLibrary(closedWorld.commonElements.interceptorsLibrary);
-    for (jsAst.Name name in names) {
-      jsAst.Expression function =
-          stubGenerator.generateOneShotInterceptor(name);
-      parts.add(js.statement('${globalObject}.# = #', [name, function]));
-    }
-
-    return new jsAst.Block(parts);
-  }
-
-  /**
-   * Emit initializer for `typeToInterceptorMap` data structure used by
-   * `findInterceptorForType`.  See declaration of `typeToInterceptor` in
-   * `interceptors.dart`.
-   */
-  jsAst.Statement buildTypeToInterceptorMap(Program program) {
-    jsAst.Expression array = program.typeToInterceptorMap;
-    if (array == null) return js.comment("Empty type-to-interceptor map.");
-
-    jsAst.Expression typeToInterceptorMap = emitter
-        .generateEmbeddedGlobalAccess(embeddedNames.TYPE_TO_INTERCEPTOR_MAP);
-    return js.statement('# = #', [typeToInterceptorMap, array]);
-  }
-}
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
deleted file mode 100644
index b136d73..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
+++ /dev/null
@@ -1,398 +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.js_emitter.full_emitter.nsm_emitter;
-
-import '../../elements/entities.dart';
-import '../../js/js.dart' as jsAst;
-import '../../js/js.dart' show js;
-import '../../js_backend/js_backend.dart' show GetterName, SetterName;
-import '../../universe/selector.dart' show Selector;
-import 'package:front_end/src/api_unstable/dart2js.dart'
-    show $$, $A, $HASH, $Z, $a, $z;
-import '../../world.dart' show JClosedWorld;
-import '../js_emitter.dart' hide Emitter, EmitterFactory;
-import '../model.dart';
-import 'emitter.dart';
-
-class NsmEmitter extends CodeEmitterHelper {
-  final JClosedWorld closedWorld;
-  final List<Selector> trivialNsmHandlers = <Selector>[];
-
-  NsmEmitter(this.closedWorld);
-
-  /// If this is true then we can generate the noSuchMethod handlers at startup
-  /// time, instead of them being emitted as part of the Object class.
-  bool get generateTrivialNsmHandlers => true;
-
-  // If we need fewer than this many noSuchMethod handlers we can save space by
-  // just emitting them in JS, rather than emitting the JS needed to generate
-  // them at run time.
-  static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10;
-
-  static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
-
-  void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) {
-    ClassStubGenerator generator = new ClassStubGenerator(task.emitter,
-        closedWorld.commonElements, namer, codegenWorldBuilder, closedWorld,
-        enableMinification: compiler.options.enableMinification);
-
-    // Keep track of the JavaScript names we've already added so we
-    // do not introduce duplicates (bad for code size).
-    Map<jsAst.Name, Selector> addedJsNames =
-        generator.computeSelectorsForNsmHandlers();
-
-    // Set flag used by generateMethod helper below.  If we have very few
-    // handlers we use addProperty for them all, rather than try to generate
-    // them at runtime.
-    bool haveVeryFewNoSuchMemberHandlers =
-        (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
-    List<jsAst.Name> names = addedJsNames.keys.toList()..sort();
-    for (jsAst.Name jsName in names) {
-      Selector selector = addedJsNames[jsName];
-      List<jsAst.Expression> argNames = selector.callStructure
-          .getOrderedNamedArguments()
-          .map((String name) => js.string(name))
-          .toList();
-      int type = selector.invocationMirrorKind;
-      if (!haveVeryFewNoSuchMemberHandlers &&
-          isTrivialNsmHandler(type, argNames, selector, jsName)) {
-        trivialNsmHandlers.add(selector);
-      } else {
-        StubMethod method =
-            generator.generateStubForNoSuchMethod(jsName, selector);
-        addProperty(method.name, method.code);
-      }
-    }
-  }
-
-  // Identify the noSuchMethod handlers that are so simple that we can
-  // generate them programatically.
-  bool isTrivialNsmHandler(
-      int type, List argNames, Selector selector, jsAst.Name internalName) {
-    if (!generateTrivialNsmHandlers) return false;
-    // Check for named arguments.
-    if (argNames.isNotEmpty) return false;
-    if (selector.typeArgumentCount > 0) return false;
-    // Check for unexpected name (this doesn't really happen).
-    if (internalName is GetterName) return type == 1;
-    if (internalName is SetterName) return type == 2;
-    return type == 0;
-  }
-
-  /**
-   * Adds (at runtime) the handlers to the Object class which catch calls to
-   * methods that the object does not have.  The handlers create an invocation
-   * mirror object.
-   *
-   * The current version only gives you the minified name when minifying (when
-   * not minifying this method is not called).
-   *
-   * In order to generate the noSuchMethod handlers we only need the minified
-   * name of the method.  We test the first character of the minified name to
-   * determine if it is a getter or a setter, and we use the arguments array at
-   * runtime to get the number of arguments and their values.  If the method
-   * involves named arguments etc. then we don't handle it here, but emit the
-   * handler method directly on the Object class.
-   *
-   * The minified names are mostly 1-4 character names, which we emit in sorted
-   * order (primary key is length, secondary ordering is lexicographic).  This
-   * gives an order like ... dD dI dX da ...
-   *
-   * Gzip is good with repeated text, but it can't diff-encode, so we do that
-   * for it.  We encode the minified names in a comma-separated string, but all
-   * the 1-4 character names are encoded before the first comma as a series of
-   * base 26 numbers.  The last digit of each number is lower case, the others
-   * are upper case, so 1 is "b" and 26 is "Ba".
-   *
-   * We think of the minified names as base 88 numbers using the ASCII
-   * characters from # to z.  The base 26 numbers each encode the delta from
-   * the previous minified name to the next.  So if there is a minified name
-   * called Df and the next is Dh, then they are 2971 and 2973 when thought of
-   * as base 88 numbers.  The difference is 2, which is "c" in lower-case-
-   * terminated base 26.
-   *
-   * The reason we don't encode long minified names with this method is that
-   * decoding the base 88 numbers would overflow JavaScript's puny integers.
-   *
-   * There are some selectors that have a special calling convention (because
-   * they are called with the receiver as the first argument).  They need a
-   * slightly different noSuchMethod handler, so we handle these first.
-   */
-  List<jsAst.Statement> buildTrivialNsmHandlers() {
-    List<jsAst.Statement> statements = <jsAst.Statement>[];
-    if (trivialNsmHandlers.length == 0) return statements;
-
-    bool minify = compiler.options.enableMinification;
-    bool useDiffEncoding = minify && trivialNsmHandlers.length > 30;
-
-    // Find out how many selectors there are with the special calling
-    // convention.
-    Iterable<Selector> interceptedSelectors = trivialNsmHandlers.where(
-        (Selector s) => closedWorld.interceptorData.isInterceptedName(s.name));
-    Iterable<Selector> ordinarySelectors = trivialNsmHandlers.where(
-        (Selector s) => !closedWorld.interceptorData.isInterceptedName(s.name));
-
-    // Get the short names (JS names, perhaps minified).
-    Iterable<jsAst.Name> interceptedShorts =
-        interceptedSelectors.map(namer.invocationMirrorInternalName);
-    Iterable<jsAst.Name> ordinaryShorts =
-        ordinarySelectors.map(namer.invocationMirrorInternalName);
-
-    jsAst.Expression sortedShorts;
-    Iterable<String> sortedLongs;
-    if (useDiffEncoding) {
-      assert(minify);
-      sortedShorts =
-          new _DiffEncodedListOfNames([interceptedShorts, ordinaryShorts]);
-    } else {
-      Iterable<Selector> sorted =
-          [interceptedSelectors, ordinarySelectors].expand((e) => (e));
-      sortedShorts = js.concatenateStrings(
-          js.joinLiterals(sorted.map(namer.invocationMirrorInternalName),
-              js.stringPart(",")),
-          addQuotes: true);
-
-      if (!minify) {
-        sortedLongs =
-            sorted.map((selector) => selector.invocationMirrorMemberName);
-      }
-    }
-    // Startup code that loops over the method names and puts handlers on the
-    // Object class to catch noSuchMethod invocations.
-    ClassEntity objectClass = closedWorld.commonElements.objectClass;
-    jsAst.Expression createInvocationMirror = backend.emitter
-        .staticFunctionAccess(
-            closedWorld.commonElements.createInvocationMirror);
-    if (useDiffEncoding) {
-      statements.add(js.statement('''{
-          var objectClassObject = processedClasses.collected[#objectClass],
-              nameSequences = #diffEncoding.split("."),
-              shortNames = [];
-          if (objectClassObject instanceof Array)
-              objectClassObject = objectClassObject[1];
-          for (var j = 0; j < nameSequences.length; ++j) {
-              var sequence = nameSequences[j].split(","),
-                nameNumber = 0;
-            // If we are loading a deferred library the object class will not be
-            // in the collectedClasses so objectClassObject is undefined, and we
-            // skip setting up the names.
-            if (!objectClassObject) break;
-            // Likewise, if the current sequence is empty, we don't process it.
-            if (sequence.length == 0) continue;
-            var diffEncodedString = sequence[0];
-            for (var i = 0; i < diffEncodedString.length; i++) {
-              var codes = [],
-                  diff = 0,
-                  digit = diffEncodedString.charCodeAt(i);
-              for (; digit <= ${$Z};) {
-                diff *= 26;
-                diff += (digit - ${$A});
-                digit = diffEncodedString.charCodeAt(++i);
-              }
-              diff *= 26;
-              diff += (digit - ${$a});
-              nameNumber += diff;
-              for (var remaining = nameNumber;
-                   remaining > 0;
-                   remaining = (remaining / 88) | 0) {
-                codes.unshift(${$HASH} + remaining % 88);
-              }
-              shortNames.push(
-                String.fromCharCode.apply(String, codes));
-            }
-            if (sequence.length > 1) {
-              Array.prototype.push.apply(shortNames, sequence.shift());
-            }
-          }
-        }''', {
-        'objectClass': js.quoteName(namer.className(objectClass)),
-        'diffEncoding': sortedShorts
-      }));
-    } else {
-      // No useDiffEncoding version.
-      statements.add(js.statement(
-          'var objectClassObject = processedClasses.collected[#objectClass],'
-          '    shortNames = #diffEncoding.split(",")',
-          {
-            'objectClass': js.quoteName(namer.className(objectClass)),
-            'diffEncoding': sortedShorts
-          }));
-      if (!minify) {
-        statements.add(js.statement('var longNames = #longs.split(",")',
-            {'longs': js.string(sortedLongs.join(','))}));
-      }
-      statements.add(js.statement('if (objectClassObject instanceof Array)'
-          '  objectClassObject = objectClassObject[1];'));
-    }
-
-    dynamic isIntercepted = // jsAst.Expression or bool.
-        interceptedSelectors.isEmpty
-            ? false
-            : ordinarySelectors.isEmpty
-                ? true
-                : js('j < #', js.number(interceptedSelectors.length));
-
-    statements.add(js.statement('''
-      // If we are loading a deferred library the object class will not be in
-      // the collectedClasses so objectClassObject is undefined, and we skip
-      // setting up the names.
-      if (objectClassObject) {
-        for (var j = 0; j < shortNames.length; j++) {
-          var type = 0;
-          var shortName = shortNames[j];
-          if (shortName.indexOf("${namer.getterPrefix}") == 0) type = 1;
-          if (shortName.indexOf("${namer.setterPrefix}") == 0) type = 2;
-          // Generate call to:
-          //
-          //     createInvocationMirror(String name, internalName, type,
-          //         arguments, argumentNames, typeArgumentCount)
-          //
-
-          // This 'if' is either a static choice or dynamic choice depending on
-          // [isIntercepted].
-          if (#isIntercepted) {
-            objectClassObject[shortName] =
-                (function(name, shortName, type) {
-                  return function(receiver) {
-                    return this.#noSuchMethodName(
-                      receiver,
-                      #createInvocationMirror(name, shortName, type,
-                          // Create proper Array with all arguments except first
-                          // (receiver).
-                          Array.prototype.slice.call(arguments, 1),
-                          [],
-                          0));
-                  }
-                 })(#names[j], shortName, type);
-          } else {
-            objectClassObject[shortName] =
-                (function(name, shortName, type) {
-                  return function() {
-                    return this.#noSuchMethodName(
-                      // Object.noSuchMethodName ignores the explicit receiver
-                      // argument. We could pass anything in place of [this].
-                      this,
-                      #createInvocationMirror(name, shortName, type,
-                          // Create proper Array with all arguments.
-                          Array.prototype.slice.call(arguments, 0),
-                          [],
-                          0));
-                  }
-                 })(#names[j], shortName, type);
-          }
-        }
-      }''', {
-      'noSuchMethodName': namer.noSuchMethodName,
-      'createInvocationMirror': createInvocationMirror,
-      'names': minify ? 'shortNames' : 'longNames',
-      'isIntercepted': isIntercepted
-    }));
-
-    return statements;
-  }
-}
-
-/// When pretty printed, this node computes a diff-encoded string for the list
-/// of given names.
-///
-/// See [buildTrivialNsmHandlers].
-class _DiffEncodedListOfNames extends jsAst.DeferredString
-    implements jsAst.AstContainer {
-  String _cachedValue;
-  List<jsAst.ArrayInitializer> ast;
-
-  Iterable<jsAst.Node> get containedNodes => ast;
-
-  _DiffEncodedListOfNames(Iterable<Iterable<jsAst.Name>> names) {
-    // Store the names in ArrayInitializer nodes to make them discoverable
-    // by traversals of the ast.
-    ast = names
-        .map((Iterable i) => new jsAst.ArrayInitializer(i.toList()))
-        .toList();
-  }
-
-  void _computeDiffEncodingForList(
-      Iterable<jsAst.Name> names, StringBuffer diffEncoding) {
-    // Treat string as a number in base 88 with digits in ASCII order from # to
-    // z.  The short name sorting is based on length, and uses ASCII order for
-    // equal length strings so this means that names are ascending.  The hash
-    // character, #, is never given as input, but we need it because it's the
-    // implicit leading zero (otherwise we could not code names with leading
-    // dollar signs).
-    int fromBase88(String x) {
-      int answer = 0;
-      for (int i = 0; i < x.length; i++) {
-        int c = x.codeUnitAt(i);
-        // No support for Unicode minified identifiers in JS.
-        assert(c >= $$ && c <= $z);
-        answer *= 88;
-        answer += c - $HASH;
-      }
-      return answer;
-    }
-
-    // Big endian encoding, A = 0, B = 1...
-    // A lower case letter terminates the number.
-    String toBase26(int x) {
-      int c = x;
-      var encodingChars = <int>[];
-      encodingChars.add($a + (c % 26));
-      while (true) {
-        c ~/= 26;
-        if (c == 0) break;
-        encodingChars.add($A + (c % 26));
-      }
-      return new String.fromCharCodes(encodingChars.reversed.toList());
-    }
-
-    // Sort by length, then lexicographic.
-    int compare(String a, String b) {
-      if (a.length != b.length) return a.length - b.length;
-      return a.compareTo(b);
-    }
-
-    List<String> shorts = names.map((jsAst.Name name) => name.name).toList()
-      ..sort(compare);
-
-    int previous = 0;
-    for (String short in shorts) {
-      if (short.length <= NsmEmitter.MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) {
-        int base63 = fromBase88(short);
-        int diff = base63 - previous;
-        previous = base63;
-        String base26Diff = toBase26(diff);
-        diffEncoding.write(base26Diff);
-      } else {
-        if (diffEncoding.length != 0) {
-          diffEncoding.write(',');
-        }
-        diffEncoding.write(short);
-      }
-    }
-  }
-
-  String _computeDiffEncoding() {
-    StringBuffer buffer = new StringBuffer();
-    for (jsAst.ArrayInitializer list in ast) {
-      if (buffer.isNotEmpty) {
-        // Emit period that resets the diff base to zero when we switch to
-        // normal calling convention (this avoids the need to code negative
-        // diffs).
-        buffer.write(".");
-      }
-      List<jsAst.Name> names = list.elements;
-      _computeDiffEncodingForList(names, buffer);
-    }
-    return '"${buffer.toString()}"';
-  }
-
-  String get value {
-    if (_cachedValue == null) {
-      _cachedValue = _computeDiffEncoding();
-    }
-
-    return _cachedValue;
-  }
-}
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
deleted file mode 100644
index 0c1fda6..0000000
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
+++ /dev/null
@@ -1,818 +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.js_emitter.full_emitter;
-
-// TODO(ahe): Share these with js_helper.dart.
-const FUNCTION_INDEX = 0;
-const NAME_INDEX = 1;
-const CALL_NAME_INDEX = 2;
-const REQUIRED_PARAMETER_INDEX = 3;
-const OPTIONAL_PARAMETER_INDEX = 4;
-const DEFAULT_ARGUMENTS_INDEX = 5;
-
-const bool VALIDATE_DATA = false;
-
-const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1;
-const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
-const RANGE1_ADJUST = -(FIRST_FIELD_CODE - RANGE1_FIRST);
-const RANGE2_ADJUST = -(FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST);
-const RANGE3_ADJUST =
-    -(FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST);
-
-const String setupProgramName = 'setupProgram';
-// TODO(floitsch): make sure this property can't clash with anything. It's
-//   unlikely since it lives on types, but still.
-const String typeNameProperty = r'builtin$cls';
-
-jsAst.Statement buildSetupProgram(
-    Program program,
-    Compiler compiler,
-    JavaScriptBackend backend,
-    Namer namer,
-    Emitter emitter,
-    JClosedWorld closedWorld) {
-  jsAst.Expression typeInformationAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPE_INFORMATION);
-  jsAst.Expression staticsAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.STATICS);
-  jsAst.Expression mangledGlobalNamesAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES);
-  jsAst.Expression mangledNamesAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES);
-  jsAst.Expression librariesAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.LIBRARIES);
-  jsAst.Expression typesAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPES);
-  jsAst.Expression allClassesAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
-  jsAst.Expression precompiledAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED);
-  jsAst.Expression finishedClassesAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
-  jsAst.Expression interceptorsByTagAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
-  jsAst.Expression leafTagsAccess =
-      emitter.generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
-
-  String reflectableField = namer.reflectableField;
-  String reflectionInfoField = namer.reflectionInfoField;
-  String reflectionNameField = namer.reflectionNameField;
-  String metadataIndexField = namer.metadataIndexField;
-  String defaultValuesField = namer.defaultValuesField;
-  String methodsWithOptionalArgumentsField =
-      namer.methodsWithOptionalArgumentsField;
-  String unmangledNameIndex =
-      ' 2 * optionalParameterCount + requiredParameterCount + 3';
-  String receiverParamName =
-      compiler.options.enableMinification ? "r" : "receiver";
-  String valueParamName = compiler.options.enableMinification ? "v" : "value";
-  String space = compiler.options.enableMinification ? "" : " ";
-  String _ = space;
-
-  String specProperty = '"${namer.nativeSpecProperty}"'; // "%"
-  jsAst.Expression nativeInfoAccess = js('prototype[$specProperty]', []);
-  jsAst.Expression constructorAccess = js('constructor', []);
-  Function subclassReadGenerator =
-      (jsAst.Expression subclass) => js('allClasses[#]', subclass);
-  jsAst.Statement nativeInfoHandler = emitter.buildNativeInfoHandler(
-      nativeInfoAccess,
-      constructorAccess,
-      subclassReadGenerator,
-      interceptorsByTagAccess,
-      leafTagsAccess);
-
-  Map<String, dynamic> holes = {
-    'needsClassSupport': emitter.needsClassSupport,
-    'libraries': librariesAccess,
-    'mangledNames': mangledNamesAccess,
-    'mangledGlobalNames': mangledGlobalNamesAccess,
-    'statics': staticsAccess,
-    'staticsPropertyName': namer.staticsPropertyName,
-    'staticsPropertyNameString': js.quoteName(namer.staticsPropertyName),
-    'typeInformation': typeInformationAccess,
-    'notInCspMode': !compiler.options.useContentSecurityPolicy,
-    'inCspMode': compiler.options.useContentSecurityPolicy,
-    'deferredAction': namer.deferredAction,
-    'allClasses': allClassesAccess,
-    'debugFastObjects': DEBUG_FAST_OBJECTS,
-    'precompiled': precompiledAccess,
-    'finishedClassesAccess': finishedClassesAccess,
-    'needsMixinSupport': emitter.needsMixinSupport,
-    'needsNativeSupport': program.needsNativeSupport,
-    'enabledJsInterop': closedWorld.nativeData.isJsInteropUsed,
-    'jsInteropBoostrap': jsInteropAnalysis.buildJsInteropBootstrap(
-        compiler.codegenWorldBuilder, closedWorld.nativeData, namer),
-    'isInterceptorClass':
-        namer.operatorIs(closedWorld.commonElements.jsInterceptorClass),
-    'isObject': namer.operatorIs(closedWorld.commonElements.objectClass),
-    'specProperty': js.string(namer.nativeSpecProperty),
-    'trivialNsmHandlers': emitter.buildTrivialNsmHandlers(),
-    'types': typesAccess,
-    'objectClassName': js.quoteName(
-        namer.runtimeTypeName(closedWorld.commonElements.objectClass)),
-    'needsStructuredMemberInfo': emitter.needsStructuredMemberInfo,
-    'usesMangledNames': closedWorld.backendUsage.isMirrorsUsed ||
-        closedWorld.backendUsage.isFunctionApplyUsed,
-    'tearOffCode': buildTearOffCode(
-        compiler.options, emitter, namer, closedWorld.commonElements),
-    'nativeInfoHandler': nativeInfoHandler,
-    'operatorIsPrefix': js.string(namer.operatorIsPrefix),
-    'deferredActionString': js.string(namer.deferredAction),
-    'callCatchAll':
-        js.quoteName(namer.getNameForJsGetName(null, JsGetName.CALL_CATCH_ALL)),
-  };
-  String skeleton = '''
-function $setupProgramName(programData, metadataOffset, typesOffset) {
-  "use strict";
-  if (#needsClassSupport) {
-
-    function generateAccessor(fieldDescriptor, accessors, cls) {
-      var fieldInformation = fieldDescriptor.split("-");
-      var field = fieldInformation[0];
-      var len = field.length;
-      var code = field.charCodeAt(len - 1);
-      var reflectable;
-      if (fieldInformation.length > 1) reflectable = true;
-           else reflectable = false;
-      code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))
-            ? code - $RANGE1_ADJUST
-            : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))
-              ? code - $RANGE2_ADJUST
-              : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))
-                ? code - $RANGE3_ADJUST
-                : $NO_FIELD_CODE;
-
-      if (code) {  // needsAccessor
-        var getterCode = code & 3;
-        var setterCode = code >> 2;
-        var accessorName = field = field.substring(0, len - 1);
-
-        var divider = field.indexOf(":");
-        if (divider > 0) { // Colon never in first position.
-          accessorName = field.substring(0, divider);
-          field = field.substring(divider + 1);
-        }
-
-        if (getterCode) {  // needsGetter
-          var args = (getterCode & 2) ? "$receiverParamName" : "";
-          var receiver = (getterCode & 1) ? "this" : "$receiverParamName";
-          var body = "return " + receiver + "." + field;
-          var property =
-              cls + ".prototype.${namer.getterPrefix}" + accessorName + "=";
-          var fn = "function(" + args + "){" + body + "}";
-          if (reflectable)
-            accessors.push(property + "\$reflectable(" + fn + ");\\n");
-          else
-            accessors.push(property + fn + ";\\n");
-        }
-
-        if (setterCode) {  // needsSetter
-          var args = (setterCode & 2)
-              ? "$receiverParamName,${_}$valueParamName"
-              : "$valueParamName";
-          var receiver = (setterCode & 1) ? "this" : "$receiverParamName";
-          var body = receiver + "." + field + "$_=$_$valueParamName";
-          var property =
-              cls + ".prototype.${namer.setterPrefix}" + accessorName + "=";
-          var fn = "function(" + args + "){" + body + "}";
-          if (reflectable)
-            accessors.push(property + "\$reflectable(" + fn + ");\\n");
-          else
-            accessors.push(property + fn + ";\\n");
-        }
-      }
-
-      return field;
-    }
-
-    // First the class name, then the field names in an array and the members
-    // (inside an Object literal).
-    // The caller can also pass in the constructor as a function if needed.
-    //
-    // Example:
-    // defineClass("A", ["x", "y"], {
-    //  foo\$1: function(y) {
-    //   print(this.x + y);
-    //  },
-    //  bar\$2: function(t, v) {
-    //   this.x = t - v;
-    //  },
-    // });
-    function defineClass(name, fields) {
-      var accessors = [];
-
-      var str = "function " + name + "(";
-      var comma = "", body = "";
-
-      for (var i = 0; i < fields.length; i++) {
-        var fieldDescriptor = fields[i];
-        if (fieldDescriptor.charCodeAt(0) == 48) {
-          // null-initialized field.
-          fieldDescriptor = fieldDescriptor.substring(1);
-          var field = generateAccessor(fieldDescriptor, accessors, name);
-          body += ("this." + field + " = null;\\n");
-        } else {
-          var field = generateAccessor(fieldDescriptor, accessors, name);
-          var parameter = "p_" + field;
-          str += comma;
-          comma = ", ";
-          str += parameter;
-          body += ("this." + field + " = " + parameter + ";\\n");
-        }
-      }
-      if (supportsDirectProtoAccess) {
-        body += "this." + #deferredActionString + "();";
-      }
-      str += ") {\\n" + body + "}\\n";
-      str += name + ".$typeNameProperty=\\"" + name + "\\";\\n";
-      str += "\$desc=\$collectedClasses." + name + "[1];\\n";
-      str += name + ".prototype = \$desc;\\n";
-      if (typeof defineClass.name != "string") {
-        str += name + ".name=\\"" + name + "\\";\\n";
-      }
-      str += accessors.join("");
-
-      return str;
-    }
-
-    // If the browser supports changing the prototype via __proto__, we make
-    // use of that feature. Otherwise, we copy the properties into a new
-    // constructor.
-    var inheritFrom = supportsDirectProtoAccess ?
-      function(constructor, superConstructor) {
-        var prototype = constructor.prototype;
-        prototype.__proto__ = superConstructor.prototype;
-        // Use a function for `true` here, as functions are stored in the
-        // hidden class and not as properties in the object.
-        prototype.constructor = constructor;
-        prototype[#operatorIsPrefix + constructor.name] = constructor;
-        return convertToFastObject(prototype);
-      } :
-      function() {
-        function tmp() {}
-        return function (constructor, superConstructor) {
-          tmp.prototype = superConstructor.prototype;
-          var object = new tmp();
-          convertToSlowObject(object);
-          var properties = constructor.prototype;
-          var members = Object.keys(properties);
-          for (var i = 0; i < members.length; i++) {
-            var member = members[i];
-            object[member] = properties[member];
-          }
-          // Use a function for `true` here, as functions are stored in the
-          // hidden class and not as properties in the object.
-          object[#operatorIsPrefix + constructor.name] = constructor;
-          object.constructor = constructor;
-          constructor.prototype = object;
-          return object;
-        };
-      }();
-
-    // Class descriptions are collected in a JS object.
-    // 'finishClasses' takes all collected descriptions and sets up
-    // the prototype.
-    // Once set up, the constructors prototype field satisfy:
-    //  - it contains all (local) members.
-    //  - its internal prototype (__proto__) points to the superclass'
-    //    prototype field.
-    //  - the prototype's constructor field points to the JavaScript
-    //    constructor.
-    // For engines where we have access to the '__proto__' we can manipulate
-    // the object literal directly. For other engines we have to create a new
-    // object and copy over the members.
-    function finishClasses(processedClasses) {
-      if (#debugFastObjects)
-        print("Number of classes: " +
-              Object.getOwnPropertyNames(processedClasses.collected).length);
-
-      var allClasses = #allClasses;
-
-      if (#inCspMode) {
-        var constructors = #precompiled(processedClasses.collected);
-      }
-
-      if (#notInCspMode) {
-        processedClasses.combinedConstructorFunction +=
-          "return [\\n" + processedClasses.constructorsList.join(",\\n  ") +
-          "\\n]";
-       var constructors =
-         new Function("\$collectedClasses",
-             processedClasses.combinedConstructorFunction)
-                 (processedClasses.collected);
-        processedClasses.combinedConstructorFunction = null;
-      }
-
-      for (var i = 0; i < constructors.length; i++) {
-        var constructor = constructors[i];
-        var cls = constructor.name;
-        var desc = processedClasses.collected[cls];
-        var globalObject = desc[0];
-        desc = desc[1];
-        allClasses[cls] = constructor;
-        globalObject[cls] = constructor;
-      }
-      constructors = null;
-
-      var finishedClasses = #finishedClassesAccess;
-
-      function finishClass(cls) {
-
-        if (finishedClasses[cls]) return;
-        finishedClasses[cls] = true;
-
-        var superclass = processedClasses.pending[cls];
-
-        if (#needsMixinSupport) {
-          if (superclass && superclass.indexOf("+") > 0) {
-            var s = superclass.split("+");
-            superclass = s[0];
-            var mixinClass = s[1];
-            finishClass(mixinClass);
-            var mixin = allClasses[mixinClass];
-            var mixinPrototype = mixin.prototype;
-            var clsPrototype = allClasses[cls].prototype;
-
-            var properties = Object.keys(mixinPrototype);
-            for (var i = 0; i < properties.length; i++) {
-              var d = properties[i];
-              if (!hasOwnProperty.call(clsPrototype, d))
-                clsPrototype[d] = mixinPrototype[d];
-            }
-          }
-        }
-
-        // The superclass is only false (empty string) for the Dart Object
-        // class.  The minifier together with noSuchMethod can put methods on
-        // the Object.prototype object, and they show through here, so we check
-        // that we have a string.
-        if (!superclass || typeof superclass != "string") {
-          // Inlined special case of InheritFrom here for performance reasons.
-          // Fix up the Dart Object class' prototype.
-          var constructor = allClasses[cls];
-          var prototype = constructor.prototype;
-          prototype.constructor = constructor;
-          prototype.#isObject = constructor;
-          prototype.#deferredAction = function() {};
-          return;
-        }
-        finishClass(superclass);
-        var superConstructor = allClasses[superclass];
-
-        if (!superConstructor) {
-          superConstructor = existingIsolateProperties[superclass];
-        }
-
-        var constructor = allClasses[cls];
-        var prototype = inheritFrom(constructor, superConstructor);
-
-        if (#needsMixinSupport) {
-          if (mixinPrototype) {
-            prototype.#deferredAction
-              = mixinDeferredActionHelper(mixinPrototype, prototype);
-          }
-        }
-
-        if (#needsNativeSupport) {
-          if (Object.prototype.hasOwnProperty.call(prototype, #specProperty)) {
-            #nativeInfoHandler;
-            // As native classes can come into existence without a constructor
-            // call, we have to ensure that the class has been fully
-            // initialized.
-            prototype.#deferredAction();
-          }
-        }
-        // Interceptors (or rather their prototypes) are also used without
-        // first instantiating them first.
-        if (prototype.#isInterceptorClass) {
-          prototype.#deferredAction();
-        }
-      }
-
-      #trivialNsmHandlers;
-
-      var properties = Object.keys(processedClasses.pending);
-      for (var i = 0; i < properties.length; i++) finishClass(properties[i]);
-    }
-
-    // Generic handler for deferred class setup. The handler updates the
-    // prototype that it is installed on (it traverses the prototype chain
-    // of [this] to find itself) and then removes itself. It recurses by
-    // calling deferred handling again, which terminates on Object due to
-    // the final handler.
-    function finishAddStubsHelper() {
-      var prototype = this;
-      // Find the actual prototype that this handler is installed on.
-      while (!prototype.hasOwnProperty(#deferredActionString)) {
-        prototype = prototype.__proto__;
-      }
-      delete prototype.#deferredAction; // Intended to make it slow, too.
-      var properties = Object.keys(prototype);
-      for (var index = 0; index < properties.length; index++) {
-        var property = properties[index];
-        var firstChar = property.charCodeAt(0);
-        var elem;
-        // We have to filter out some special properties that are used for
-        // metadata in descriptors. Currently, we filter everything that
-        // starts with + or *. This has to stay in sync with the special
-        // properties that are used by processClassData below.
-        if (property !== "${namer.classDescriptorProperty}" &&
-            property !== "$reflectableField" &&
-            firstChar !== 43 && // 43 is aka "+".
-            firstChar !== 42 && // 42 is aka "*"
-            (elem = prototype[property]) != null &&
-            elem.constructor === Array &&
-            property !== "<>") {
-          addStubs(prototype, elem, property, false, []);
-        }
-      }
-      convertToFastObject(prototype);
-      prototype = prototype.__proto__;
-      // Call other handlers.
-      prototype.#deferredAction();
-    }
-
-    if (#needsMixinSupport) {
-      // Returns a deferred class setup handler that first invokes the
-      // handler on [mixinPrototype] and then resumes handling on
-      // [targetPrototype]. If [targetPrototype] already has a handler
-      // installed, the handler is preserved in the generated closure and
-      // thus can be safely overwritten.
-      function mixinDeferredActionHelper(mixinPrototype, targetPrototype) {
-        var chain;
-        if (targetPrototype.hasOwnProperty(#deferredActionString)) {
-          chain = targetPrototype.#deferredAction;
-        }
-        return function foo() {
-          if (!supportsDirectProtoAccess) return;
-          var prototype = this;
-          // Find the actual prototype that this handler is installed on.
-          while (!prototype.hasOwnProperty(#deferredActionString)) {
-            prototype = prototype.__proto__;
-          }
-          if (chain) {
-            prototype.#deferredAction = chain;
-          } else {
-            delete prototype.#deferredAction;
-            convertToFastObject(prototype);
-          }
-          mixinPrototype.#deferredAction();
-          prototype.#deferredAction();
-        }
-      }
-    }
-
-    function processClassData(cls, descriptor, processedClasses) {
-      descriptor = convertToSlowObject(descriptor); // Use a slow object.
-      var previousProperty;
-      var properties = Object.keys(descriptor);
-      var hasDeferredWork = false;
-      var shouldDeferWork =
-          supportsDirectProtoAccess && cls != #objectClassName;
-      for (var i = 0; i < properties.length; i++) {
-        var property = properties[i];
-        var firstChar = property.charCodeAt(0);
-        if (property === #staticsPropertyNameString) {
-          processStatics(#statics[cls] = descriptor.#staticsPropertyName,
-                         processedClasses);
-          delete descriptor.#staticsPropertyName;
-        } else if (firstChar === 43) { // 43 is "+".
-          mangledNames[previousProperty] = property.substring(1);
-          var flag = descriptor[property];
-          if (flag > 0)
-            descriptor[previousProperty].$reflectableField = flag;
-        } else if (firstChar === 42) { // 42 is "*"
-          descriptor[previousProperty].$defaultValuesField =
-              descriptor[property];
-          var optionalMethods = descriptor.$methodsWithOptionalArgumentsField;
-          if (!optionalMethods) {
-            descriptor.$methodsWithOptionalArgumentsField = optionalMethods = {}
-          }
-          optionalMethods[property] = previousProperty;
-        } else {
-          var elem = descriptor[property];
-          if (property !== "${namer.classDescriptorProperty}" &&
-              elem != null &&
-              elem.constructor === Array &&
-              property !== "<>") {
-            if (shouldDeferWork) {
-              hasDeferredWork = true;
-            } else {
-              addStubs(descriptor, elem, property, false, []);
-            }
-          } else {
-            previousProperty = property;
-          }
-        }
-      }
-
-      if (hasDeferredWork)
-        descriptor.#deferredAction = finishAddStubsHelper;
-
-      /* The 'fields' are either a constructor function or a
-       * string encoding fields, constructor and superclass. Gets the
-       * superclass and fields in the format
-       *   'Super;field1,field2'
-       * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor.
-       */
-      var classData = descriptor["${namer.classDescriptorProperty}"],
-          split, supr, fields = classData;
-
-      // ${ClassBuilder.fieldEncodingDescription}.
-      var s = fields.split(";");
-      fields = s[1] ? s[1].split(",") : [];
-      supr = s[0];
-      // ${ClassBuilder.functionTypeEncodingDescription}.
-      split = supr.split(":");
-      if (split.length == 2) {
-        supr = split[0];
-        var functionSignature = split[1];
-        if (functionSignature)
-          descriptor.${namer.operatorSignature} = function(s) {
-            return function() {
-              return #types[s];
-            };
-          }(functionSignature);
-      }
-
-      if (supr) processedClasses.pending[cls] = supr;
-      if (#notInCspMode) {
-        processedClasses.combinedConstructorFunction +=
-            defineClass(cls, fields);
-        processedClasses.constructorsList.push(cls);
-      }
-      processedClasses.collected[cls] = [globalObject, descriptor];
-      classes.push(cls);
-    }
-  }
-
-  function processStatics(descriptor, processedClasses) {
-    var properties = Object.keys(descriptor);
-    for (var i = 0; i < properties.length; i++) {
-      var property = properties[i];
-      if (property === "${namer.classDescriptorProperty}") continue;
-      var element = descriptor[property];
-      var firstChar = property.charCodeAt(0);
-      var previousProperty;
-      if (firstChar === 43) { // 43 is "+".
-        mangledGlobalNames[previousProperty] = property.substring(1);
-        var flag = descriptor[property];
-        if (flag > 0)
-          descriptor[previousProperty].$reflectableField = flag;
-        if (element && element.length)
-          #typeInformation[previousProperty] = element;
-      } else if (firstChar === 42) { // 42 is "*"
-        globalObject[previousProperty].$defaultValuesField = element;
-        var optionalMethods = descriptor.$methodsWithOptionalArgumentsField;
-        if (!optionalMethods) {
-          descriptor.$methodsWithOptionalArgumentsField = optionalMethods = {}
-        }
-        optionalMethods[property] = previousProperty;
-      } else if (typeof element === "function") {
-        globalObject[previousProperty = property] = element;
-        functions.push(property);
-      } else if (element.constructor === Array) {
-        if (#needsStructuredMemberInfo) {
-          addStubs(globalObject, element, property, true, functions);
-        }
-      } else {
-        // We will not enter this case if no classes are defined.
-        if (#needsClassSupport) {
-          previousProperty = property;
-          processClassData(property, element, processedClasses);
-        }
-      }
-    }
-  }
-
-  if (#needsStructuredMemberInfo) {
-
-    // See [dart2js.js_emitter.ContainerBuilder.addMemberMethod] for format of
-    // [array].
-
-    // Processes the stub declaration given by [array] and stores the results
-    // in the corresponding [prototype]. [name] is the property name in
-    // [prototype] that the stub declaration belongs to.
-    // If [isStatic] is true, the property being processed belongs to a static
-    // function and thus is stored as a global. In that case we also add all
-    // generated functions to the [functions] array, which is used by the
-    // mirrors system to enumerate all static functions of a library. For
-    // non-static functions we might still add some functions to [functions] but
-    // the information is thrown away at the call site. This is to avoid
-    // conditionals.
-    function addStubs(prototype, array, name, isStatic, functions) {
-      var index = $FUNCTION_INDEX, applyTrampolineIndex = index, alias = array[index], f;
-      if (typeof alias == "string") {
-        f = array[++index];
-      } else {
-        f = alias;
-        alias = name;
-      }
-      if (typeof f == "number") {
-        applyTrampolineIndex = f;
-        f = array[++index];
-      }
-      prototype[name] = prototype[alias] = f;
-      var funcs = [f];
-      f.\$stubName = name;
-      functions.push(name);
-      for (index++; index < array.length; index++) {
-        f = array[index];
-        if (typeof f != "function") break;
-        if (!isStatic) {
-          f.\$stubName = ${readString("array", "++index")};
-        }
-        funcs.push(f);
-        if (f.\$stubName) {
-          prototype[f.\$stubName] = f;
-          functions.push(f.\$stubName);
-        }
-      }
-
-      for (var i = 0; i < funcs.length; index++, i++) {
-        funcs[i].\$callName = ${readString("array", "index")};
-      }
-      var getterStubName = ${readString("array", "index")};
-      array = array.slice(++index);
-      var requiredParameterInfo = ${readInt("array", "0")};
-      var isIntercepted = (requiredParameterInfo & 1) === 1;
-      requiredParameterInfo = requiredParameterInfo >> 1;
-      var requiredParameterCount = requiredParameterInfo >> 1;
-      var isAccessor = (requiredParameterInfo & 1) === 1;
-      var isSetter = requiredParameterInfo === 3;
-      var isGetter = requiredParameterInfo === 1;
-      var optionalParameterInfo = ${readInt("array", "1")};
-      var optionalParameterCount = optionalParameterInfo >> 1;
-      var optionalParametersAreNamed = (optionalParameterInfo & 1) === 1;
-      var totalParameterCount = requiredParameterCount + optionalParameterCount;
-      var functionTypeIndex = ${readFunctionType("array", "2")};
-      if (typeof functionTypeIndex == "number")
-        ${readFunctionType("array", "2")} = functionTypeIndex + typesOffset;
-      if (metadataOffset > 0) {
-        var position = 3;
-        // Update index that refers to the parameter default value.
-        for (var i = 0; i < optionalParameterCount; i++) {
-          if (typeof ${readInt("array", "position")} == "number")
-          ${readInt("array", "position")} =
-              ${readInt("array", "position")} + metadataOffset;
-          position++;
-        }
-        for (var i = 0; i < totalParameterCount; i++) {
-          // Update index that refers to the parameter name.
-          ${readInt("array", "position")} =
-              ${readInt("array", "position")} + metadataOffset;
-          position++;
-        }
-      }
-      var unmangledNameIndex = $unmangledNameIndex;
-
-      if (getterStubName) {
-        f = tearOff(funcs, applyTrampolineIndex, array, isStatic, name, isIntercepted);
-        prototype[name].\$getter = f;
-        f.\$getterStub = true;
-        if (isStatic) {
-          functions.push(getterStubName);
-        }
-        prototype[getterStubName] = f;
-        funcs.push(f);
-        f.\$stubName = getterStubName;
-        f.\$callName = null;
-      }
-
-      if (#usesMangledNames) {
-        var isReflectable = array.length > unmangledNameIndex;
-        if (isReflectable) {
-          funcs[0].$reflectableField = 1;
-          funcs[0].$reflectionInfoField = array;
-          for (var i = 1; i < funcs.length; i++) {
-            funcs[i].$reflectableField = 2;
-            funcs[i].$reflectionInfoField = array;
-          }
-          var mangledNames = isStatic ? #mangledGlobalNames : #mangledNames;
-          var unmangledName = ${readString("array", "unmangledNameIndex")};
-          // The function is either a getter, a setter, or a method.
-          // If it is a method, it might also have a tear-off closure.
-          // The unmangledName is the same as the getter-name.
-          var reflectionName = unmangledName;
-          if (getterStubName) mangledNames[getterStubName] = reflectionName;
-          if (isSetter) {
-            reflectionName += "=";
-          } else if (!isGetter) {
-            reflectionName += ":" +
-                (requiredParameterCount + optionalParameterCount);
-          }
-          mangledNames[name] = reflectionName;
-          funcs[0].$reflectionNameField = reflectionName;
-          for (var i = unmangledNameIndex + 1; i < array.length; i++) {
-            ${readInt("array", "i")} =
-                ${readInt("array", "i")} + metadataOffset;
-          }
-          funcs[0].$metadataIndexField = unmangledNameIndex + 1;
-          // The following line installs the [${JsGetName.CALL_CATCH_ALL}]
-          // property for closures.
-          if (optionalParameterCount) prototype[#callCatchAll] = funcs[applyTrampolineIndex];
-        }
-      }
-    }
-
-    if (#enabledJsInterop) {
-      #jsInteropBoostrap
-    }
-    #tearOffCode;
-  }
-
-  var functionCounter = 0;
-  if (!#libraries) #libraries = [];
-  if (!#mangledNames) #mangledNames = map();
-  if (!#mangledGlobalNames) #mangledGlobalNames = map();
-  if (!#statics) #statics = map();
-  if (!#typeInformation) #typeInformation = map();
-  var libraries = #libraries;
-  var mangledNames = #mangledNames;
-  var mangledGlobalNames = #mangledGlobalNames;
-  var hasOwnProperty = Object.prototype.hasOwnProperty;
-  var length = programData.length;
-  var processedClasses = map();
-  processedClasses.collected = map();
-  processedClasses.pending = map();
-  if (#notInCspMode) {
-    processedClasses.constructorsList = [];
-    // For every class processed [processedClasses.combinedConstructorFunction]
-    // will be updated with the corresponding constructor function.
-    processedClasses.combinedConstructorFunction =
-        "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+
-        "var \$desc;\\n";
-  }
-  for (var i = 0; i < length; i++) {
-    var data = programData[i];
-
-// [data] contains these elements:
-// 0. The library name (not unique).
-// 1. The library URI (unique).
-// 2. A function returning the metadata associated with this library.
-// 3. The global object to use for this library.
-// 4. An object literal listing the members of the library.
-// 5. This element is optional and if present it is true and signals that this
-// library is the root library (see dart:mirrors IsolateMirror.rootLibrary).
-//
-// The entries of [data] are built in [assembleProgram] above.
-
-    var name = data[0];
-    var uri = data[1];
-    var metadata = data[2];
-    var globalObject = data[3];
-    var descriptor = data[4];
-    var isRoot = !!data[5];
-    var fields = descriptor && descriptor["${namer.classDescriptorProperty}"];
-    if (fields instanceof Array) fields = fields[0];
-    var classes = [];
-    var functions = [];
-    processStatics(descriptor, processedClasses);
-    libraries.push([name, uri, classes, functions, metadata, fields, isRoot,
-                    globalObject]);
-  }
-  if (#needsClassSupport) finishClasses(processedClasses);
-}''';
-
-  // TODO(zarah): Remove empty else branches in output when if(#hole) is false.
-  return js.statement(skeleton, holes);
-}
-
-String readString(String array, String index) {
-  return readChecked(
-      array, index, 'result != null && typeof result != "string"', 'string');
-}
-
-String readInt(String array, String index) {
-  return readChecked(
-      array,
-      index,
-      'result != null && (typeof result != "number" || (result|0) !== result)',
-      'int');
-}
-
-String readFunctionType(String array, String index) {
-  return readChecked(
-      array,
-      index,
-      'result != null && '
-      '(typeof result != "number" || (result|0) !== result) && '
-      'typeof result != "function"',
-      'function or int');
-}
-
-String readChecked(String array, String index, String check, String type) {
-  if (!VALIDATE_DATA) return '$array[$index]';
-  return '''
-(function() {
-  var result = $array[$index];
-  if ($check) {
-    throw new Error(
-        name + ": expected value of type \'$type\' at index " + ($index) +
-        " but got " + (typeof result));
-  }
-  return result;
-})()''';
-}
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 d91972f..3bbdcfa0 100644
--- a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
@@ -58,10 +58,8 @@
       return _emitterTask.interceptorPrototypeAccess(cls);
     }
 
-    /**
-     * Build a JavaScript AST node for doing a type check on
-     * [cls]. [cls] must be a non-native interceptor class.
-     */
+    /// Build a JavaScript AST node for doing a type check on
+    /// [cls]. [cls] must be a non-native interceptor class.
     jsAst.Statement buildInterceptorCheck(ClassEntity cls) {
       jsAst.Expression condition;
       assert(_interceptorData.isInterceptedClass(cls));
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 933f41c..7829d79 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -72,10 +72,8 @@
   Fragment get mainFragment => fragments.first;
 }
 
-/**
- * This class represents a JavaScript object that contains static state, like
- * classes or functions.
- */
+/// This class represents a JavaScript object that contains static state, like
+/// classes or functions.
 class Holder {
   final String name;
   final int index;
@@ -90,12 +88,10 @@
   }
 }
 
-/**
- * This class represents one output file.
- *
- * If no library is deferred, there is only one [Fragment] of type
- * [MainFragment].
- */
+/// This class represents one output file.
+///
+/// If no library is deferred, there is only one [Fragment] of type
+/// [MainFragment].
 abstract class Fragment {
   /// The outputUnit should only be used during the transition to the new model.
   /// Uses indicate missing information in the model.
@@ -122,12 +118,10 @@
   bool get isMainFragment;
 }
 
-/**
- * The main output file.
- *
- * This code emitted from this [Fragment] must be loaded first. It can then load
- * other [DeferredFragment]s.
- */
+/// The main output file.
+///
+/// This code emitted from this [Fragment] must be loaded first. It can then load
+/// other [DeferredFragment]s.
 class MainFragment extends Fragment {
   final js.Statement invokeMain;
 
@@ -149,9 +143,7 @@
   }
 }
 
-/**
- * An output (file) for deferred code.
- */
+/// An output (file) for deferred code.
 class DeferredFragment extends Fragment {
   final String name;
 
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 85230aa..2e0dca3 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -46,36 +46,35 @@
   NativeData get _nativeData => _closedWorld.nativeData;
   InterceptorData get _interceptorData => _closedWorld.interceptorData;
 
-  /**
-   * Prepares native classes for emission. Returns the unneeded classes.
-   *
-   * Removes trivial classes (that can be represented by a super type) and
-   * generates properties that have to be added to classes (native or not).
-   *
-   * Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions`
-   * fields of the given classes. This data must be emitted with the
-   * corresponding classes.
-   *
-   * The interceptors are filtered to avoid emitting trivial interceptors.  For
-   * example, if the program contains no code that can distinguish between the
-   * numerous subclasses of `Element` then we can pretend that `Element` is a
-   * leaf class, and all instances of subclasses of `Element` are instances of
-   * `Element`.
-   *
-   * There is also a performance benefit (in addition to the obvious code size
-   * benefit), due to how [getNativeInterceptor] works.  Finding the interceptor
-   * of a leaf class in the hierarchy is more efficient that a non-leaf, so it
-   * improves performance when more classes can be treated as leaves.
-   *
-   * [classes] contains native classes, mixin applications, and user subclasses
-   * of native classes.
-   *
-   * [interceptorClassesNeededByConstants] contains the interceptors that are
-   * referenced by constants.
-   *
-   * [classesModifiedByEmitRTISupport] contains the list of classes that must
-   * exist, because runtime-type support adds information to the class.
-   */
+  /// Prepares native classes for emission. Returns the unneeded classes.
+  ///
+  /// Removes trivial classes (that can be represented by a super type) and
+  /// generates properties that have to be added to classes (native or not).
+  ///
+  /// Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions`
+  /// fields of the given classes. This data must be emitted with the
+  /// corresponding classes.
+  ///
+  /// The interceptors are filtered to avoid emitting trivial interceptors.  For
+  /// example, if the program contains no code that can distinguish between the
+  /// numerous subclasses of `Element` then we can pretend that `Element` is a
+  /// leaf class, and all instances of subclasses of `Element` are instances of
+  /// `Element`.
+  ///
+  /// There is also a performance benefit (in addition to the obvious code size
+  /// benefit), due to how [getNativeInterceptor] works.  Finding the
+  /// interceptor of a leaf class in the hierarchy is more efficient that a
+  /// non-leaf, so it improves performance when more classes can be treated as
+  /// leaves.
+  ///
+  /// [classes] contains native classes, mixin applications, and user subclasses
+  /// of native classes.
+  ///
+  /// [interceptorClassesNeededByConstants] contains the interceptors that are
+  /// referenced by constants.
+  ///
+  /// [classesModifiedByEmitRTISupport] contains the list of classes that must
+  /// exist, because runtime-type support adds information to the class.
   Set<Class> prepareNativeClasses(
       List<Class> classes,
       Set<ClassEntity> interceptorClassesNeededByConstants,
@@ -219,11 +218,9 @@
         .toSet();
   }
 
-  /**
-   * Computes the native classes that are extended (subclassed) by non-native
-   * classes and the set non-mative classes that extend them.  (A List is used
-   * instead of a Set for out stability).
-   */
+  /// Computes the native classes that are extended (subclassed) by non-native
+  /// classes and the set non-mative classes that extend them.  (A List is used
+  /// instead of a Set for out stability).
   Map<Class, List<Class>> computeExtensionPoints(List<Class> classes) {
     Class nativeSuperclassOf(Class cls) {
       if (cls == null) return null;
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 6592f68..e57a3ab 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
@@ -4,12 +4,10 @@
 
 part of dart2js.js_emitter.program_builder;
 
-/**
- * Generates the code for all used classes in the program. Static fields (even
- * in classes) are ignored, since they can be treated as non-class elements.
- *
- * The code for the containing (used) methods must exist in the `universe`.
- */
+/// Generates the code for all used classes in the program. Static fields (even
+/// in classes) are ignored, since they can be treated as non-class elements.
+///
+/// The code for the containing (used) methods must exist in the `universe`.
 class Collector {
   final CompilerOptions _options;
   final JCommonElements _commonElements;
@@ -78,10 +76,8 @@
     return classes;
   }
 
-  /**
-   * Return a function that returns true if its argument is a class
-   * that needs to be emitted.
-   */
+  /// Return a function that returns true if its argument is a class
+  /// that needs to be emitted.
   Function computeClassFilter(Iterable<ClassEntity> backendTypeHelpers) {
     Set<ClassEntity> unneededClasses = new Set<ClassEntity>();
     // The [Bool] class is not marked as abstract, but has a factory
@@ -129,9 +125,7 @@
     ];
   }
 
-  /**
-   * Compute all the constants that must be emitted.
-   */
+  /// Compute all the constants that must be emitted.
   void computeNeededConstants() {
     List<ConstantValue> constants =
         _worldBuilder.getConstantsForEmission(_emitter.compareConstants);
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
index e1b0d46..493afa9 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -4,24 +4,22 @@
 
 part of dart2js.js_emitter.program_builder;
 
-/**
- * [member] is a field (instance, static, or top level).
- *
- * [name] is the field name that the [Namer] has picked for this field's
- * storage, that is, the JavaScript property name.
- *
- * [accessorName] is the name of the accessor. For instance fields this is
- * mostly the same as [name] except when [member] is shadowing a field in its
- * superclass.  For other fields, they are rarely the same.
- *
- * [needsGetter] and [needsSetter] represent if a getter or a setter
- * respectively is needed.  There are many factors in this, for example, if the
- * accessor can be inlined.
- *
- * [needsCheckedSetter] indicates that a checked getter is needed, and in this
- * case, [needsSetter] is always false. [needsCheckedSetter] is only true when
- * type assertions are enabled (checked mode).
- */
+/// [member] is a field (instance, static, or top level).
+///
+/// [name] is the field name that the [Namer] has picked for this field's
+/// storage, that is, the JavaScript property name.
+///
+/// [accessorName] is the name of the accessor. For instance fields this is
+/// mostly the same as [name] except when [member] is shadowing a field in its
+/// superclass.  For other fields, they are rarely the same.
+///
+/// [needsGetter] and [needsSetter] represent if a getter or a setter
+/// respectively is needed.  There are many factors in this, for example, if the
+/// accessor can be inlined.
+///
+/// [needsCheckedSetter] indicates that a checked getter is needed, and in this
+/// case, [needsSetter] is always false. [needsCheckedSetter] is only true when
+/// type assertions are enabled (checked mode).
 typedef void AcceptField(FieldEntity member, js.Name name, js.Name accessorName,
     bool needsGetter, bool needsSetter, bool needsCheckedSetter);
 
@@ -43,22 +41,20 @@
       this._namer,
       this._closedWorld);
 
-  /**
-   * Invokes [f] for each of the fields of [element].
-   *
-   * [element] must be a [ClassEntity] or a [LibraryEntity].
-   *
-   * If [element] is a [ClassEntity], the static fields of the class are
-   * visited if [visitStatics] is true and the instance fields are visited if
-   * [visitStatics] is false.
-   *
-   * If [element] is a [LibraryEntity], [visitStatics] must be true.
-   *
-   * When visiting the instance fields of a class, the fields of its superclass
-   * are also visited if the class is instantiated.
-   *
-   * Invariant: [element] must be a declaration element.
-   */
+  /// Invokes [f] for each of the fields of [element].
+  ///
+  /// [element] must be a [ClassEntity] or a [LibraryEntity].
+  ///
+  /// If [element] is a [ClassEntity], the static fields of the class are
+  /// visited if [visitStatics] is true and the instance fields are visited if
+  /// [visitStatics] is false.
+  ///
+  /// If [element] is a [LibraryEntity], [visitStatics] must be true.
+  ///
+  /// When visiting the instance fields of a class, the fields of its superclass
+  /// are also visited if the class is instantiated.
+  ///
+  /// Invariant: [element] must be a declaration element.
   void visitFields(AcceptField f,
       {bool visitStatics: false, LibraryEntity library, ClassEntity cls}) {
     bool isNativeClass = false;
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 7d974f3..02cdf45 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -102,13 +102,11 @@
       : _outputUnitVisitor = new _TypeContainedInOutputUnitVisitor(
             _commonElements, _outputUnitData);
 
-  /**
-   * Generate "is tests" for [cls] itself, and the "is tests" for the
-   * classes it implements and type argument substitution functions for these
-   * tests.   We don't need to add the "is tests" of the super class because
-   * they will be inherited at runtime, but we may need to generate the
-   * substitutions, because they may have changed.
-   */
+  /// Generate "is tests" for [cls] itself, and the "is tests" for the
+  /// classes it implements and type argument substitution functions for these
+  /// tests.   We don't need to add the "is tests" of the super class because
+  /// they will be inherited at runtime, but we may need to generate the
+  /// substitutions, because they may have changed.
 
   /// Generates all properties necessary for is-checks on the [classElement].
   ///
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 5ef3622..8e5224c 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
@@ -560,14 +560,12 @@
 #inheritance;
 }''';
 
-/**
- * This class builds a JavaScript tree for a given fragment.
- *
- * A fragment is generally written into a separate file so that it can be
- * loaded dynamically when a deferred library is loaded.
- *
- * This class is stateless and can be reused for different fragments.
- */
+/// This class builds a JavaScript tree for a given fragment.
+///
+/// A fragment is generally written into a separate file so that it can be
+/// loaded dynamically when a deferred library is loaded.
+///
+/// This class is stateless and can be reused for different fragments.
 class FragmentEmitter {
   final Compiler compiler;
   final Namer namer;
@@ -597,6 +595,13 @@
     return js.js('#.#', [cls.holder.name, cls.name]);
   }
 
+  void registerEntityAst(Entity entity, js.Node code, {LibraryEntity library}) {
+    compiler.dumpInfoTask.registerEntityAst(entity, code);
+    // TODO(sigmund): stop recoding associations twice, dump-info already
+    // has library to element dependencies to recover this data.
+    if (library != null) compiler.dumpInfoTask.registerEntityAst(library, code);
+  }
+
   js.Statement emitMainFragment(
       Program program, DeferredLoadingState deferredLoadingState) {
     MainFragment fragment = program.fragments.first;
@@ -792,30 +797,28 @@
         .where((Holder holder) => !holder.isStaticStateHolder)
         .toList(growable: false);
 
-    Map<Holder, Map<js.Name, js.Expression>> holderCode = {};
+    Map<Holder, List<js.Property>> holderCode = {};
 
     for (Holder holder in holders) {
-      holderCode[holder] = <js.Name, js.Expression>{};
+      holderCode[holder] = <js.Property>[];
     }
 
     for (Library library in fragment.libraries) {
       for (StaticMethod method in library.statics) {
         assert(!method.holder.isStaticStateHolder);
         var staticMethod = emitStaticMethod(method);
-        if (compiler.options.dumpInfo) {
-          for (var code in staticMethod.values) {
-            compiler.dumpInfoTask.registerEntityAst(method.element, code);
-            compiler.dumpInfoTask.registerEntityAst(library.element, code);
-          }
-        }
-        holderCode[method.holder].addAll(staticMethod);
+        staticMethod.forEach((key, value) {
+          var property = new js.Property(js.quoteName(key), value);
+          holderCode[method.holder].add(property);
+          registerEntityAst(method.element, property, library: library.element);
+        });
       }
       for (Class cls in library.classes) {
         assert(!cls.holder.isStaticStateHolder);
         var constructor = emitConstructor(cls);
-        compiler.dumpInfoTask.registerEntityAst(cls.element, constructor);
-        compiler.dumpInfoTask.registerEntityAst(library.element, constructor);
-        holderCode[cls.holder][cls.name] = constructor;
+        var property = new js.Property(js.quoteName(cls.name), constructor);
+        registerEntityAst(cls.element, property, library: library.element);
+        holderCode[cls.holder].add(property);
       }
     }
 
@@ -823,10 +826,7 @@
     List<Holder> activeHolders = [];
 
     for (Holder holder in holders) {
-      List<js.Property> properties = [];
-      holderCode[holder].forEach((js.Name key, js.Expression value) {
-        properties.add(new js.Property(js.quoteName(key), value));
-      });
+      List<js.Property> properties = holderCode[holder];
       if (properties.isEmpty) {
         holderInitializations.add(new js.VariableInitialization(
             new js.VariableDeclaration(holder.name, allowRename: false),
@@ -1006,8 +1006,7 @@
       var proto = js.js.statement(
           '#.prototype = #;', [classReference(cls), emitPrototype(cls)]);
       ClassEntity element = cls.element;
-      compiler.dumpInfoTask.registerEntityAst(element, proto);
-      compiler.dumpInfoTask.registerEntityAst(element.library, proto);
+      registerEntityAst(element, proto, library: element.library);
       return proto;
     }).toList(growable: false);
 
@@ -1050,7 +1049,7 @@
       emitInstanceMethod(method)
           .forEach((js.Expression name, js.Expression code) {
         var prop = js.Property(name, code);
-        compiler.dumpInfoTask.registerEntityAst(method.element, prop);
+        registerEntityAst(method.element, prop);
         properties.add(prop);
       });
     });
@@ -1216,11 +1215,13 @@
         if (cls.isSoftDeferred != softDeferred) continue;
         collect(cls);
         if (cls.mixinClass != null) {
-          mixinCalls.add(js.js.statement('#(#, #)', [
+          js.Statement statement = js.js.statement('#(#, #)', [
             locals.find('_mixin', 'hunkHelpers.mixin'),
             classReference(cls),
             classReference(cls.mixinClass),
-          ]));
+          ]);
+          registerEntityAst(cls.element, statement, library: library.element);
+          mixinCalls.add(statement);
         }
       }
     }
@@ -1231,13 +1232,27 @@
           ? new js.LiteralNull()
           : classReference(superclass);
       if (list.length == 1) {
-        inheritCalls.add(js.js.statement('#(#, #)', [
+        Class cls = list.single;
+        var statement = js.js.statement('#(#, #)', [
           locals.find('_inherit', 'hunkHelpers.inherit'),
-          classReference(list.single),
+          classReference(cls),
           superclassReference
-        ]));
+        ]);
+        registerEntityAst(cls.element, statement, library: cls.element.library);
+        inheritCalls.add(statement);
       } else {
-        var listElements = list.map(classReference).toList();
+        List<js.Expression> listElements = [];
+        // Since inheritMany shares the superclass reference, we attribute it
+        // only to the first subclass.
+        ClassEntity firstClass = list.first.element;
+        registerEntityAst(firstClass, superclassReference,
+            library: firstClass.library);
+        for (Class cls in list) {
+          js.Expression reference = classReference(cls);
+          registerEntityAst(cls.element, reference,
+              library: cls.element.library);
+          listElements.add(reference);
+        }
         inheritCalls.add(js.js.statement('#(#, #)', [
           locals.find('_inheritMany', 'hunkHelpers.inheritMany'),
           superclassReference,
@@ -1271,14 +1286,18 @@
           if (method.aliasName != null) {
             if (firstAlias) {
               firstAlias = false;
-              assignments.add(js.js.statement(
+              js.Statement statement = js.js.statement(
                   assignments.isEmpty
                       ? 'var _ = #.prototype;'
                       : '_ = #.prototype',
-                  classReference(cls)));
+                  classReference(cls));
+              registerEntityAst(method.element, statement);
+              assignments.add(statement);
             }
-            assignments.add(js.js.statement('_.# = _.#',
-                [js.quoteName(method.aliasName), js.quoteName(method.name)]));
+            js.Statement statement = js.js.statement('_.# = _.#',
+                [js.quoteName(method.aliasName), js.quoteName(method.name)]);
+            registerEntityAst(method.element, statement);
+            assignments.add(statement);
           }
         }
       }
@@ -1489,8 +1508,11 @@
         if (method is StaticDartMethod) {
           if (method.needsTearOff) {
             Holder holder = method.holder;
-            inits.add(
-                emitInstallTearOff(new js.VariableUse(holder.name), method));
+            js.Statement statement =
+                emitInstallTearOff(new js.VariableUse(holder.name), method);
+            registerEntityAst(method.element, statement,
+                library: library.element);
+            inits.add(statement);
           }
         }
       }
@@ -1508,7 +1530,9 @@
           reference = js.js('# = #', [temp, container]);
         }
         for (InstanceMethod method in methods) {
-          inits.add(emitInstallTearOff(reference, method));
+          js.Statement statement = emitInstallTearOff(reference, method);
+          registerEntityAst(method.element, statement);
+          inits.add(statement);
           reference = temp; // Second and subsequent calls use temp.
         }
       }
@@ -1558,8 +1582,11 @@
     //
     Iterable<js.Statement> statements = fields.map((StaticField field) {
       assert(field.holder.isStaticStateHolder);
-      return js.js
+      js.Statement statement = js.js
           .statement("#.# = #;", [field.holder.name, field.name, field.code]);
+      registerEntityAst(field.element, statement,
+          library: field.element.library);
+      return statement;
     });
     return wrapPhase('staticFields', statements.toList());
   }
@@ -1574,13 +1601,17 @@
     LocalAliases locals = LocalAliases();
     for (StaticField field in fields) {
       assert(field.holder.isStaticStateHolder);
-      statements.add(js.js.statement("#(#, #, #, #);", [
+      js.Statement statement = js.js.statement("#(#, #, #, #);", [
         locals.find('_lazy', 'hunkHelpers.lazy'),
         field.holder.name,
         js.quoteName(field.name),
         js.quoteName(field.getterName),
         field.code
-      ]));
+      ]);
+
+      registerEntityAst(field.element, statement,
+          library: field.element.library);
+      statements.add(statement);
     }
 
     if (locals.isNotEmpty) {
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index b9461da..f0b0efd 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -119,10 +119,6 @@
   /// Returns the definition information for [cls].
   ClassDefinition getClassDefinition(covariant ClassEntity cls);
 
-  /// Returns the static type of [node].
-  // TODO(johnniwinther): This should be provided directly from kernel.
-  DartType getStaticType(ir.Expression node);
-
   /// [ElementEnvironment] for library, class and member lookup.
   JElementEnvironment get elementEnvironment;
 
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index 68618f8..47433bc 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -33,6 +33,7 @@
 import '../ir/element_map.dart';
 import '../ir/types.dart';
 import '../ir/visitors.dart';
+import '../ir/static_type_base.dart';
 import '../ir/static_type_provider.dart';
 import '../ir/util.dart';
 import '../js/js.dart' as js;
@@ -99,6 +100,7 @@
   JsConstantEnvironment _constantEnvironment;
   KernelDartTypes _types;
   ir.TypeEnvironment _typeEnvironment;
+  ir.ClassHierarchy _classHierarchy;
 
   /// Library environment. Used for fast lookup.
   JProgramEnv programEnv;
@@ -1057,12 +1059,18 @@
   ir.TypeEnvironment get typeEnvironment {
     if (_typeEnvironment == null) {
       _typeEnvironment ??= new ir.TypeEnvironment(
-          new ir.CoreTypes(programEnv.mainComponent),
-          new ir.ClassHierarchy(programEnv.mainComponent));
+          new ir.CoreTypes(programEnv.mainComponent), classHierarchy);
     }
     return _typeEnvironment;
   }
 
+  ir.ClassHierarchy get classHierarchy {
+    if (_classHierarchy == null) {
+      _classHierarchy ??= new ir.ClassHierarchy(programEnv.mainComponent);
+    }
+    return _classHierarchy;
+  }
+
   StaticTypeProvider getStaticTypeProvider(MemberEntity member) {
     MemberDefinition memberDefinition = members.getData(member).definition;
     Map<ir.Expression, ir.DartType> cachedStaticTypes;
@@ -1095,29 +1103,8 @@
     }
 
     assert(cachedStaticTypes != null, "No static types cached for $member.");
-    return new CachedStaticType(
-        // We need a copy of the type environment since the `thisType` field
-        // is holds state, making the environment contextually bound.
-        new ir.TypeEnvironment(
-            typeEnvironment.coreTypes, typeEnvironment.hierarchy)
-          ..thisType = thisType,
-        cachedStaticTypes);
-  }
-
-  DartType getStaticType(ir.Expression node) {
-    ir.TreeNode enclosingClass = node;
-    while (enclosingClass != null && enclosingClass is! ir.Class) {
-      enclosingClass = enclosingClass.parent;
-    }
-    try {
-      typeEnvironment.thisType =
-          enclosingClass is ir.Class ? enclosingClass.thisType : null;
-      return getDartType(node.getStaticType(typeEnvironment));
-    } catch (e) {
-      // The static type computation crashes on type errors. Use `dynamic`
-      // as static type.
-      return commonElements.dynamicType;
-    }
+    return new CachedStaticType(typeEnvironment, cachedStaticTypes,
+        new ThisInterfaceType.from(thisType));
   }
 
   Name getName(ir.Name name) {
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index 9533b15..b6fe609 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/class_hierarchy.dart' as ir;
 import 'package:kernel/type_environment.dart' as ir;
 
 import '../constants/values.dart';
@@ -29,8 +30,12 @@
   /// Access to the [DartTypes] object.
   DartTypes get types;
 
+  /// Returns the type environment for the underlying kernel model.
   ir.TypeEnvironment get typeEnvironment;
 
+  /// Returns the class hierarchy for the underlying kernel model.
+  ir.ClassHierarchy get classHierarchy;
+
   /// Returns the [DartType] corresponding to [type].
   DartType getDartType(ir.DartType type);
 
@@ -55,6 +60,10 @@
   /// access of [node].
   Selector getSelector(ir.Expression node);
 
+  /// Returns the [Selector] corresponding to the invocation of [name] with
+  /// [arguments].
+  Selector getInvocationSelector(ir.Name name, ir.Arguments arguments);
+
   /// Returns the [MemberEntity] corresponding to the member [node].
   MemberEntity getMember(ir.Member node);
 
@@ -113,10 +122,6 @@
   /// Returns the defining node for [cls].
   ir.Class getClassNode(covariant ClassEntity cls);
 
-  /// Returns the static type of [node].
-  // TODO(johnniwinther): This should be provided directly from kernel.
-  DartType getStaticType(ir.Expression node);
-
   /// Adds libraries in [component] to the set of libraries.
   ///
   /// The main method of the first component is used as the main method for the
@@ -176,9 +181,6 @@
 
   /// Returns the defining node for [member].
   ir.Member getMemberNode(covariant MemberEntity member);
-
-  /// Returns the element type of a async/sync*/async* function.
-  DartType getFunctionAsyncOrSyncStarElementType(ir.FunctionNode functionNode);
 }
 
 /// Kinds of foreign functions.
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 6c0a91c..9a8c1d1 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -71,6 +71,7 @@
   KernelConstantEnvironment _constantEnvironment;
   KernelDartTypes _types;
   ir.TypeEnvironment _typeEnvironment;
+  ir.ClassHierarchy _classHierarchy;
 
   /// Library environment. Used for fast lookup.
   KProgramEnv env = new KProgramEnv();
@@ -413,6 +414,9 @@
     if (superClass == targetClass) {
       return target;
     }
+
+    /// This path is needed for synthetically injected superclasses like
+    /// `Interceptor` and `JavaScriptObject`.
     KClassEnv env = classes.getEnv(superClass);
     ConstructorEntity constructor = env.lookupConstructor(this, target.name);
     if (constructor != null) {
@@ -718,26 +722,16 @@
   ir.TypeEnvironment get typeEnvironment {
     if (_typeEnvironment == null) {
       _typeEnvironment ??= new ir.TypeEnvironment(
-          new ir.CoreTypes(env.mainComponent),
-          new ir.ClassHierarchy(env.mainComponent));
+          new ir.CoreTypes(env.mainComponent), classHierarchy);
     }
     return _typeEnvironment;
   }
 
-  DartType getStaticType(ir.Expression node) {
-    ir.TreeNode enclosingClass = node;
-    while (enclosingClass != null && enclosingClass is! ir.Class) {
-      enclosingClass = enclosingClass.parent;
+  ir.ClassHierarchy get classHierarchy {
+    if (_classHierarchy == null) {
+      _classHierarchy ??= new ir.ClassHierarchy(env.mainComponent);
     }
-    try {
-      typeEnvironment.thisType =
-          enclosingClass is ir.Class ? enclosingClass.thisType : null;
-      return getDartType(node.getStaticType(typeEnvironment));
-    } catch (e) {
-      // The static type computation crashes on type errors. Use `dynamic`
-      // as static type.
-      return commonElements.dynamicType;
-    }
+    return _classHierarchy;
   }
 
   Name getName(ir.Name name) {
@@ -783,7 +777,7 @@
       return getSetterSelector(node.name);
     }
     if (node is ir.InvocationExpression) {
-      return getInvocationSelector(node);
+      return getInvocationSelector(node.name, node.arguments);
     }
     throw failedAt(
         CURRENT_ELEMENT_SPANNABLE,
@@ -791,8 +785,8 @@
         "${node}");
   }
 
-  Selector getInvocationSelector(ir.InvocationExpression invocation) {
-    Name name = getName(invocation.name);
+  Selector getInvocationSelector(ir.Name irName, ir.Arguments arguments) {
+    Name name = getName(irName);
     SelectorKind kind;
     if (Selector.isOperatorName(name.text)) {
       if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
@@ -804,7 +798,7 @@
       kind = SelectorKind.CALL;
     }
 
-    CallStructure callStructure = getCallStructure(invocation.arguments);
+    CallStructure callStructure = getCallStructure(arguments);
     return new Selector(kind, name, callStructure);
   }
 
@@ -1454,27 +1448,6 @@
     return _getTypedefNode(typedef);
   }
 
-  /// Returns the element type of a async/sync*/async* function.
-  @override
-  DartType getFunctionAsyncOrSyncStarElementType(ir.FunctionNode functionNode) {
-    DartType returnType = getDartType(functionNode.returnType);
-    switch (functionNode.asyncMarker) {
-      case ir.AsyncMarker.SyncStar:
-        return elementEnvironment.getAsyncOrSyncStarElementType(
-            AsyncMarker.SYNC_STAR, returnType);
-      case ir.AsyncMarker.Async:
-        return elementEnvironment.getAsyncOrSyncStarElementType(
-            AsyncMarker.ASYNC, returnType);
-      case ir.AsyncMarker.AsyncStar:
-        return elementEnvironment.getAsyncOrSyncStarElementType(
-            AsyncMarker.ASYNC_STAR, returnType);
-      default:
-        failedAt(CURRENT_ELEMENT_SPANNABLE,
-            "Unexpected ir.AsyncMarker: ${functionNode.asyncMarker}");
-    }
-    return null;
-  }
-
   /// Returns `true` is [node] has a `@Native(...)` annotation.
   // TODO(johnniwinther): Cache this for later use.
   bool isNativeClass(ir.Class node) {
@@ -1698,46 +1671,6 @@
   }
 
   @override
-  DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function) {
-    // TODO(sra): Should be getting the DartType from the node.
-    DartType returnType = getFunctionType(function).returnType;
-    return getAsyncOrSyncStarElementType(function.asyncMarker, returnType);
-  }
-
-  @override
-  DartType getAsyncOrSyncStarElementType(
-      AsyncMarker asyncMarker, DartType returnType) {
-    switch (asyncMarker) {
-      case AsyncMarker.SYNC:
-        return returnType;
-      case AsyncMarker.SYNC_STAR:
-        if (returnType is InterfaceType) {
-          if (returnType.element == elementMap.commonElements.iterableClass) {
-            return returnType.typeArguments.first;
-          }
-        }
-        return dynamicType;
-      case AsyncMarker.ASYNC:
-        if (returnType is FutureOrType) return returnType.typeArgument;
-        if (returnType is InterfaceType) {
-          if (returnType.element == elementMap.commonElements.futureClass) {
-            return returnType.typeArguments.first;
-          }
-        }
-        return dynamicType;
-      case AsyncMarker.ASYNC_STAR:
-        if (returnType is InterfaceType) {
-          if (returnType.element == elementMap.commonElements.streamClass) {
-            return returnType.typeArguments.first;
-          }
-        }
-        return dynamicType;
-    }
-    assert(false, 'Unexpected marker ${asyncMarker}');
-    return null;
-  }
-
-  @override
   DartType getFieldType(FieldEntity field) {
     return elementMap._getFieldType(field);
   }
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index a93e7e7..c3b4306 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -2,9 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:front_end/src/api_unstable/dart2js.dart'
-    show operatorFromString;
-
 import 'package:kernel/ast.dart' as ir;
 
 import '../common.dart';
@@ -14,8 +11,10 @@
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
+import '../ir/runtime_type_analysis.dart';
 import '../ir/scope.dart';
 import '../ir/static_type.dart';
+import '../ir/impact.dart';
 import '../ir/util.dart';
 import '../js_backend/annotations.dart';
 import '../js_backend/native_data.dart';
@@ -27,22 +26,21 @@
 import '../universe/use.dart';
 import '../universe/world_builder.dart';
 import 'element_map.dart';
-import 'runtime_type_analysis.dart';
 
-class KernelImpactBuilder extends StaticTypeVisitor {
+class KernelImpactBuilder extends ImpactBuilder {
   final ResolutionWorldImpactBuilder impactBuilder;
   final KernelToElementMap elementMap;
   final DiagnosticReporter reporter;
   final CompilerOptions _options;
   final MemberEntity currentMember;
-  final VariableScopeModel variableScopeModel;
   final Set<PragmaAnnotation> _annotations;
 
   KernelImpactBuilder(this.elementMap, this.currentMember, this.reporter,
-      this._options, this.variableScopeModel, this._annotations)
+      this._options, VariableScopeModel variableScopeModel, this._annotations)
       : this.impactBuilder =
             new ResolutionWorldImpactBuilder('${currentMember}'),
-        super(elementMap.typeEnvironment);
+        super(elementMap.typeEnvironment, elementMap.classHierarchy,
+            variableScopeModel);
 
   CommonElements get commonElements => elementMap.commonElements;
 
@@ -53,22 +51,25 @@
   bool get inferEffectivelyFinalVariableTypes =>
       !_annotations.contains(PragmaAnnotation.disableFinal);
 
-  /// Add a checked-mode type use of [type] if it is not `dynamic`.
-  DartType checkType(ir.DartType irType, TypeUseKind kind) {
-    DartType type = elementMap.getDartType(irType);
-    if (kind != null && !type.isDynamic) {
-      switch (kind) {
-        case TypeUseKind.PARAMETER_CHECK:
-          impactBuilder.registerTypeUse(new TypeUse.parameterCheck(type));
-          break;
-        case TypeUseKind.IMPLICIT_CAST:
-          impactBuilder.registerTypeUse(new TypeUse.implicitCast(type));
-          break;
-        default:
-          throw new UnsupportedError("Unexpected type check kind: $kind");
+  Object _computeReceiverConstraint(
+      ir.DartType receiverType, ClassRelation relation) {
+    if (receiverType is ir.InterfaceType) {
+      if (receiverType.classNode == typeEnvironment.futureOrClass) {
+        // CFE encodes FutureOr as an interface type!
+        return null;
       }
+      return new StrongModeConstraint(commonElements, _nativeBasicData,
+          elementMap.getClass(receiverType.classNode), relation);
     }
-    return type;
+    return null;
+  }
+
+  @override
+  void registerParameterCheck(ir.DartType irType) {
+    DartType type = elementMap.getDartType(irType);
+    if (!type.isDynamic) {
+      impactBuilder.registerTypeUse(new TypeUse.parameterCheck(type));
+    }
   }
 
   List<DartType> _getTypeArguments(ir.Arguments arguments) {
@@ -76,34 +77,14 @@
     return arguments.types.map(elementMap.getDartType).toList();
   }
 
-  /// Add checked-mode type use for the parameter type and constant for the
-  /// default value of [parameter].
   @override
-  void handleParameter(ir.VariableDeclaration parameter) {
-    checkType(parameter.type, TypeUseKind.PARAMETER_CHECK);
-  }
-
-  /// Add checked-mode type use for parameter and return types, and add
-  /// constants for default values.
-  @override
-  void handleSignature(ir.FunctionNode node) {
-    for (ir.TypeParameter parameter in node.typeParameters) {
-      checkType(parameter.bound, TypeUseKind.PARAMETER_CHECK);
-    }
+  void registerLazyField() {
+    impactBuilder.registerFeature(Feature.LAZY_FIELD);
   }
 
   @override
   void handleField(ir.Field field) {
-    checkType(field.type, TypeUseKind.PARAMETER_CHECK);
-    if (field.initializer != null) {
-      if (!field.isInstanceMember &&
-          !field.isConst &&
-          field.initializer is! ir.NullLiteral) {
-        impactBuilder.registerFeature(Feature.LAZY_FIELD);
-      }
-    } else {
-      impactBuilder.registerConstantLiteral(new NullConstantExpression());
-    }
+    super.handleField(field);
 
     if (field.isInstanceMember &&
         elementMap.isNativeClass(field.enclosingClass)) {
@@ -126,49 +107,37 @@
     }
   }
 
-  void handleAsyncMarker(ir.FunctionNode function) {
-    ir.AsyncMarker asyncMarker = function.asyncMarker;
-    if (asyncMarker == ir.AsyncMarker.Sync) return;
+  @override
+  void registerSyncStar(ir.DartType elementType) {
+    impactBuilder.registerFeature(Feature.SYNC_STAR);
+    impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
+        commonElements.syncStarIterableFactory,
+        const CallStructure.unnamed(1, 1),
+        <DartType>[elementMap.getDartType(elementType)]));
+  }
 
-    DartType elementType =
-        elementMap.getFunctionAsyncOrSyncStarElementType(function);
+  @override
+  void registerAsync(ir.DartType elementType) {
+    impactBuilder.registerFeature(Feature.ASYNC);
+    impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
+        commonElements.asyncAwaitCompleterFactory,
+        const CallStructure.unnamed(0, 1),
+        <DartType>[elementMap.getDartType(elementType)]));
+  }
 
-    switch (asyncMarker) {
-      case ir.AsyncMarker.SyncStar:
-        impactBuilder.registerFeature(Feature.SYNC_STAR);
-        impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
-            commonElements.syncStarIterableFactory,
-            const CallStructure.unnamed(1, 1),
-            <DartType>[elementType]));
-        break;
-
-      case ir.AsyncMarker.Async:
-        impactBuilder.registerFeature(Feature.ASYNC);
-        var completerFactory = commonElements.asyncAwaitCompleterFactory;
-        impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
-            completerFactory,
-            const CallStructure.unnamed(0, 1),
-            <DartType>[elementType]));
-        break;
-
-      case ir.AsyncMarker.AsyncStar:
-        impactBuilder.registerFeature(Feature.ASYNC_STAR);
-        impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
-            commonElements.asyncStarStreamControllerFactory,
-            const CallStructure.unnamed(1, 1),
-            <DartType>[elementType]));
-        break;
-
-      case ir.AsyncMarker.Sync:
-      case ir.AsyncMarker.SyncYielding:
-        failedAt(CURRENT_ELEMENT_SPANNABLE,
-            "Unexpected async marker: ${asyncMarker}");
-    }
+  @override
+  void registerAsyncStar(ir.DartType elementType) {
+    impactBuilder.registerFeature(Feature.ASYNC_STAR);
+    impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
+        commonElements.asyncStarStreamControllerFactory,
+        const CallStructure.unnamed(1, 1),
+        <DartType>[elementMap.getDartType(elementType)]));
   }
 
   @override
   void handleProcedure(ir.Procedure procedure) {
-    handleAsyncMarker(procedure.function);
+    super.handleProcedure(procedure);
+
     MemberEntity member = elementMap.getMember(procedure);
     if (procedure.isExternal && !commonElements.isForeignHelper(member)) {
       bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
@@ -178,68 +147,71 @@
   }
 
   @override
-  void handleIntLiteral(ir.IntLiteral node) {
+  void registerIntLiteral(int value) {
     impactBuilder.registerConstantLiteral(
-        new IntConstantExpression(new BigInt.from(node.value).toUnsigned(64)));
+        new IntConstantExpression(new BigInt.from(value).toUnsigned(64)));
   }
 
   @override
-  void handleDoubleLiteral(ir.DoubleLiteral node) {
-    impactBuilder
-        .registerConstantLiteral(new DoubleConstantExpression(node.value));
+  void registerDoubleLiteral(double value) {
+    impactBuilder.registerConstantLiteral(new DoubleConstantExpression(value));
   }
 
   @override
-  void handleBoolLiteral(ir.BoolLiteral node) {
-    impactBuilder
-        .registerConstantLiteral(new BoolConstantExpression(node.value));
+  void registerBoolLiteral(bool value) {
+    impactBuilder.registerConstantLiteral(new BoolConstantExpression(value));
   }
 
   @override
-  void handleStringLiteral(ir.StringLiteral node) {
-    impactBuilder
-        .registerConstantLiteral(new StringConstantExpression(node.value));
+  void registerStringLiteral(String value) {
+    impactBuilder.registerConstantLiteral(new StringConstantExpression(value));
   }
 
   @override
-  void handleSymbolLiteral(ir.SymbolLiteral node) {
-    impactBuilder.registerConstSymbolName(node.value);
+  void registerSymbolLiteral(String value) {
+    impactBuilder.registerConstSymbolName(value);
   }
 
   @override
-  void handleNullLiteral(ir.NullLiteral node) {
+  void registerNullLiteral() {
     impactBuilder.registerConstantLiteral(new NullConstantExpression());
   }
 
   @override
-  void handleListLiteral(ir.ListLiteral node) {
-    DartType elementType = elementMap.getDartType(node.typeArgument);
-
+  void registerListLiteral(ir.DartType elementType,
+      {bool isConstant, bool isEmpty}) {
     impactBuilder.registerListLiteral(new ListLiteralUse(
-        commonElements.listType(elementType),
-        isConstant: node.isConst,
-        isEmpty: node.expressions.isEmpty));
+        commonElements.listType(elementMap.getDartType(elementType)),
+        isConstant: isConstant,
+        isEmpty: isEmpty));
   }
 
   @override
-  void handleMapLiteral(ir.MapLiteral node) {
-    DartType keyType = elementMap.getDartType(node.keyType);
-    DartType valueType = elementMap.getDartType(node.valueType);
+  void registerMapLiteral(ir.DartType keyType, ir.DartType valueType,
+      {bool isConstant, bool isEmpty}) {
     impactBuilder.registerMapLiteral(new MapLiteralUse(
-        commonElements.mapType(keyType, valueType),
-        isConstant: node.isConst,
-        isEmpty: node.entries.isEmpty));
+        commonElements.mapType(
+            elementMap.getDartType(keyType), elementMap.getDartType(valueType)),
+        isConstant: isConstant,
+        isEmpty: isEmpty));
   }
 
   @override
-  void handleConstructorInvocation(ir.ConstructorInvocation node,
-      ArgumentTypes argumentTypes, ir.DartType resultType) {
-    handleNew(node, node.target, isConst: node.isConst);
-  }
-
-  void handleNew(ir.InvocationExpression node, ir.Member target,
-      {bool isConst: false}) {
+  void registerNew(ir.Member target, ir.InterfaceType type,
+      ir.Arguments arguments, ir.LibraryDependency import,
+      {bool isConst}) {
     ConstructorEntity constructor = elementMap.getConstructor(target);
+    CallStructure callStructure = elementMap.getCallStructure(arguments);
+    ImportEntity deferredImport = elementMap.getImport(import);
+    impactBuilder.registerStaticUse(isConst
+        ? new StaticUse.constConstructorInvoke(constructor, callStructure,
+            elementMap.getDartType(type), deferredImport)
+        : new StaticUse.typedConstructorInvoke(constructor, callStructure,
+            elementMap.getDartType(type), deferredImport));
+    if (type.typeArguments.any((ir.DartType type) => type is! ir.DynamicType)) {
+      impactBuilder.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
+    }
+
     if (commonElements.isSymbolConstructor(constructor)) {
       impactBuilder.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
     }
@@ -252,21 +224,9 @@
       // return here.
     }
 
-    InterfaceType type = elementMap.createInterfaceType(
-        target.enclosingClass, node.arguments.types);
-    CallStructure callStructure = elementMap.getCallStructure(node.arguments);
-    ImportEntity deferredImport = elementMap.getImport(getDeferredImport(node));
-    impactBuilder.registerStaticUse(isConst
-        ? new StaticUse.constConstructorInvoke(
-            constructor, callStructure, type, deferredImport)
-        : new StaticUse.typedConstructorInvoke(
-            constructor, callStructure, type, deferredImport));
-    if (type.typeArguments.any((DartType type) => !type.isDynamic)) {
-      impactBuilder.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
-    }
     if (isConst && commonElements.isSymbolConstructor(constructor)) {
       ConstantValue value =
-          elementMap.getConstantValue(node.arguments.positional.first);
+          elementMap.getConstantValue(arguments.positional.first);
       if (!value.isString) {
         // TODO(het): Get the actual span for the Symbol constructor argument
         reporter.reportErrorMessage(
@@ -281,59 +241,38 @@
   }
 
   @override
-  Null handleSuperInitializer(
-      ir.SuperInitializer node, ArgumentTypes argumentTypes) {
+  void registerSuperInitializer(
+      ir.Constructor source, ir.Constructor target, ir.Arguments arguments) {
     // TODO(johnniwinther): Maybe rewrite `node.target` to point to a
     // synthesized unnamed mixin constructor when needed. This would require us
     // to consider impact building a required pre-step for inference and
     // ssa-building.
-    ConstructorEntity target =
-        elementMap.getSuperConstructor(node.parent, node.target);
+    ConstructorEntity constructor =
+        elementMap.getSuperConstructor(source, target);
     impactBuilder.registerStaticUse(new StaticUse.superConstructorInvoke(
-        target, elementMap.getCallStructure(node.arguments)));
+        constructor, elementMap.getCallStructure(arguments)));
+  }
+
+  @override
+  void registerStaticInvocation(ir.Procedure procedure, ir.Arguments arguments,
+      ir.LibraryDependency import) {
+    FunctionEntity target = elementMap.getMethod(procedure);
+    CallStructure callStructure = elementMap.getCallStructure(arguments);
+    List<DartType> typeArguments = _getTypeArguments(arguments);
+    if (commonElements.isExtractTypeArguments(target)) {
+      _handleExtractTypeArguments(target, typeArguments, callStructure);
+      return;
+    } else {
+      ImportEntity deferredImport = elementMap.getImport(import);
+      impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
+          target, callStructure, typeArguments, deferredImport));
+    }
   }
 
   void handleStaticInvocation(ir.StaticInvocation node,
       ArgumentTypes argumentTypes, ir.DartType returnType) {
-    if (node.target.kind == ir.ProcedureKind.Factory) {
-      // TODO(johnniwinther): We should not mark the type as instantiated but
-      // rather follow the type arguments directly.
-      //
-      // Consider this:
-      //
-      //    abstract class A<T> {
-      //      factory A.regular() => new B<T>();
-      //      factory A.redirect() = B<T>;
-      //    }
-      //
-      //    class B<T> implements A<T> {}
-      //
-      //    main() {
-      //      print(new A<int>.regular() is B<int>);
-      //      print(new A<String>.redirect() is B<String>);
-      //    }
-      //
-      // To track that B is actually instantiated as B<int> and B<String> we
-      // need to follow the type arguments passed to A.regular and A.redirect
-      // to B. Currently, we only do this soundly if we register A<int> and
-      // A<String> as instantiated. We should instead register that A.T is
-      // instantiated as int and String.
-      handleNew(node, node.target, isConst: node.isConst);
-    } else {
-      FunctionEntity target = elementMap.getMethod(node.target);
-      List<DartType> typeArguments = _getTypeArguments(node.arguments);
-      if (commonElements.isExtractTypeArguments(target)) {
-        _handleExtractTypeArguments(node, target, typeArguments);
-        return;
-      }
-      ImportEntity deferredImport =
-          elementMap.getImport(getDeferredImport(node));
-      impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
-          target,
-          elementMap.getCallStructure(node.arguments),
-          typeArguments,
-          deferredImport));
-    }
+    super.handleStaticInvocation(node, argumentTypes, returnType);
+
     switch (elementMap.getForeignKind(node)) {
       case ForeignKind.JS:
         impactBuilder
@@ -359,8 +298,8 @@
     }
   }
 
-  void _handleExtractTypeArguments(ir.StaticInvocation node,
-      FunctionEntity target, List<DartType> typeArguments) {
+  void _handleExtractTypeArguments(FunctionEntity target,
+      List<DartType> typeArguments, CallStructure callStructure) {
     // extractTypeArguments<Map>(obj, fn) has additional impacts:
     //
     //   1. All classes implementing Map need to carry type arguments (similar
@@ -368,8 +307,8 @@
     //
     //   2. There is an invocation of fn with some number of type arguments.
     //
-    impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
-        target, elementMap.getCallStructure(node.arguments), typeArguments));
+    impactBuilder.registerStaticUse(
+        new StaticUse.staticInvoke(target, callStructure, typeArguments));
 
     if (typeArguments.length != 1) return;
     DartType matchedType = typeArguments.first;
@@ -388,27 +327,26 @@
   }
 
   @override
-  void handleStaticGet(ir.StaticGet node, ir.DartType resultType) {
-    ir.Member target = node.target;
-    if (target is ir.Procedure && target.kind == ir.ProcedureKind.Method) {
-      FunctionEntity method = elementMap.getMethod(target);
-      impactBuilder.registerStaticUse(new StaticUse.staticTearOff(
-          method, elementMap.getImport(getDeferredImport(node))));
-    } else {
-      MemberEntity member = elementMap.getMember(target);
-      impactBuilder.registerStaticUse(new StaticUse.staticGet(
-          member, elementMap.getImport(getDeferredImport(node))));
-    }
+  void registerStaticTearOff(
+      ir.Procedure procedure, ir.LibraryDependency import) {
+    impactBuilder.registerStaticUse(new StaticUse.staticTearOff(
+        elementMap.getMethod(procedure), elementMap.getImport(import)));
   }
 
   @override
-  void handleStaticSet(ir.StaticSet node, ir.DartType valueType) {
-    MemberEntity member = elementMap.getMember(node.target);
-    impactBuilder.registerStaticUse(new StaticUse.staticSet(
-        member, elementMap.getImport(getDeferredImport(node))));
+  void registerStaticGet(ir.Member member, ir.LibraryDependency import) {
+    impactBuilder.registerStaticUse(new StaticUse.staticGet(
+        elementMap.getMember(member), elementMap.getImport(import)));
   }
 
-  void handleSuperInvocation(ir.Name name, ir.Node arguments) {
+  @override
+  void registerStaticSet(ir.Member member, ir.LibraryDependency import) {
+    impactBuilder.registerStaticUse(new StaticUse.staticSet(
+        elementMap.getMember(member), elementMap.getImport(import)));
+  }
+
+  @override
+  void registerSuperInvocation(ir.Name name, ir.Arguments arguments) {
     FunctionEntity method =
         elementMap.getSuperMember(currentMember, name, setter: false);
     List<DartType> typeArguments = _getTypeArguments(arguments);
@@ -424,34 +362,7 @@
   }
 
   @override
-  void handleDirectMethodInvocation(
-      ir.DirectMethodInvocation node,
-      ir.DartType receiverType,
-      ArgumentTypes argumentTypes,
-      ir.DartType returnType) {
-    List<DartType> typeArguments = _getTypeArguments(node.arguments);
-    MemberEntity member = elementMap.getMember(node.target);
-    // TODO(johnniwinther): Restrict the dynamic use to only match the known
-    // target.
-    // TODO(johnniwinther): Restrict this to subclasses?
-    Object constraint = new StrongModeConstraint(
-        commonElements, _nativeBasicData, member.enclosingClass);
-    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
-        new Selector.call(
-            member.memberName, elementMap.getCallStructure(node.arguments)),
-        constraint,
-        typeArguments));
-  }
-
-  @override
-  void handleSuperMethodInvocation(ir.SuperMethodInvocation node,
-      ArgumentTypes argumentTypes, ir.DartType returnType) {
-    // TODO(johnniwinther): Should we support this or always use the
-    // [MixinFullResolution] transformer?
-    handleSuperInvocation(node.name, node.arguments);
-  }
-
-  void handleSuperGet(ir.Name name, ir.Member target) {
+  void registerSuperGet(ir.Name name) {
     MemberEntity member =
         elementMap.getSuperMember(currentMember, name, setter: false);
     if (member != null) {
@@ -469,21 +380,7 @@
   }
 
   @override
-  void handleDirectPropertyGet(ir.DirectPropertyGet node,
-      ir.DartType receiverType, ir.DartType resultType) {
-    // TODO(johnniwinther): Restrict the dynamic use to only match the known
-    // target.
-    impactBuilder.registerDynamicUse(new DynamicUse(
-        new Selector.getter(elementMap.getMember(node.target).memberName)));
-  }
-
-  @override
-  void handleSuperPropertyGet(
-      ir.SuperPropertyGet node, ir.DartType resultType) {
-    handleSuperGet(node.name, node.interfaceTarget);
-  }
-
-  void handleSuperSet(ir.Name name, ir.Node target, ir.Node value) {
+  void registerSuperSet(ir.Name name) {
     MemberEntity member =
         elementMap.getSuperMember(currentMember, name, setter: true);
     if (member != null) {
@@ -501,275 +398,235 @@
   }
 
   @override
-  void handleDirectPropertySet(ir.DirectPropertySet node,
-      ir.DartType receiverType, ir.DartType valueType) {
-    // TODO(johnniwinther): Restrict the dynamic use to only match the known
-    // target.
-    impactBuilder.registerDynamicUse(new DynamicUse(
-        new Selector.setter(elementMap.getMember(node.target).memberName)));
+  void registerLocalFunctionInvocation(
+      ir.FunctionDeclaration localFunction, ir.Arguments arguments) {
+    CallStructure callStructure = elementMap.getCallStructure(arguments);
+    List<DartType> typeArguments = _getTypeArguments(arguments);
+    // Invocation of a local function. No need for dynamic use, but
+    // we need to track the type arguments.
+    impactBuilder.registerStaticUse(new StaticUse.closureCall(
+        elementMap.getLocalFunction(localFunction),
+        callStructure,
+        typeArguments));
+    // TODO(johnniwinther): Yet, alas, we need the dynamic use for now. Remove
+    // this when kernel adds an `isFunctionCall` flag to
+    // [ir.MethodInvocation].
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        callStructure.callSelector, null, typeArguments));
   }
 
   @override
-  void handleSuperPropertySet(ir.SuperPropertySet node, ir.DartType valueType) {
-    handleSuperSet(node.name, node.interfaceTarget, node.value);
+  void registerDynamicInvocation(ir.DartType receiverType,
+      ClassRelation relation, ir.Name name, ir.Arguments arguments) {
+    Selector selector = elementMap.getInvocationSelector(name, arguments);
+    List<DartType> typeArguments = _getTypeArguments(arguments);
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(selector,
+        _computeReceiverConstraint(receiverType, relation), typeArguments));
   }
 
   @override
-  void handleMethodInvocation(
-      ir.MethodInvocation node,
-      ir.DartType receiverType,
-      ArgumentTypes argumentTypes,
-      ir.DartType returnType) {
-    Selector selector = elementMap.getSelector(node);
-    List<DartType> typeArguments = _getTypeArguments(node.arguments);
-    ir.Expression receiver = node.receiver;
-    if (receiver is ir.VariableGet &&
-        receiver.variable.isFinal &&
-        receiver.variable.parent is ir.FunctionDeclaration) {
-      Local localFunction =
-          elementMap.getLocalFunction(receiver.variable.parent);
-      // Invocation of a local function. No need for dynamic use, but
-      // we need to track the type arguments.
-      impactBuilder.registerStaticUse(new StaticUse.closureCall(
-          localFunction, selector.callStructure, typeArguments));
-      // TODO(johnniwinther): Yet, alas, we need the dynamic use for now. Remove
-      // this when kernel adds an `isFunctionCall` flag to
-      // [ir.MethodInvocation].
-      impactBuilder.registerDynamicUse(
-          new ConstrainedDynamicUse(selector, null, typeArguments));
-    } else {
-      ClassRelation relation = receiver is ir.ThisExpression
-          ? ClassRelation.thisExpression
-          : ClassRelation.subtype;
-      DartType receiverDartType = elementMap.getDartType(receiverType);
-      Object constraint;
-      if (receiverDartType is InterfaceType) {
-        constraint = new StrongModeConstraint(commonElements, _nativeBasicData,
-            receiverDartType.element, relation);
-      }
-      ir.Member interfaceTarget = node.interfaceTarget;
-      if (interfaceTarget == null) {
-        // TODO(johnniwinther): Avoid treating a known function call as a
-        // dynamic call when CFE provides a way to distinguish the two.
-        impactBuilder.registerDynamicUse(
-            new ConstrainedDynamicUse(selector, constraint, typeArguments));
-        if (operatorFromString(node.name.name) == null &&
-            receiverDartType.isDynamic) {
-          // We might implicitly call a getter that returns a function.
-          impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
-              selector.toCallSelector(), null, typeArguments));
-        }
-      } else {
-        if (interfaceTarget is ir.Field ||
-            interfaceTarget is ir.Procedure &&
-                interfaceTarget.kind == ir.ProcedureKind.Getter) {
-          impactBuilder.registerDynamicUse(
-              new ConstrainedDynamicUse(selector, constraint, typeArguments));
-          // An `o.foo()` invocation is (potentially) an `o.foo.call()`
-          // invocation.
-          Object getterConstraint;
-          if (interfaceTarget != null) {
-            DartType receiverType =
-                elementMap.getDartType(interfaceTarget.getterType);
-            if (receiverType is InterfaceType) {
-              getterConstraint = new StrongModeConstraint(
-                  commonElements, _nativeBasicData, receiverType.element);
+  void registerFunctionInvocation(
+      ir.DartType receiverType, ir.Arguments arguments) {
+    CallStructure callStructure = elementMap.getCallStructure(arguments);
+    List<DartType> typeArguments = _getTypeArguments(arguments);
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        callStructure.callSelector,
+        _computeReceiverConstraint(receiverType, ClassRelation.subtype),
+        typeArguments));
+  }
+
+  @override
+  void registerInstanceInvocation(ir.DartType receiverType,
+      ClassRelation relation, ir.Member target, ir.Arguments arguments) {
+    List<DartType> typeArguments = _getTypeArguments(arguments);
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        elementMap.getInvocationSelector(target.name, arguments),
+        _computeReceiverConstraint(receiverType, relation),
+        typeArguments));
+  }
+
+  @override
+  void registerDynamicGet(
+      ir.DartType receiverType, ClassRelation relation, ir.Name name) {
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        new Selector.getter(elementMap.getName(name)),
+        _computeReceiverConstraint(receiverType, relation),
+        const <DartType>[]));
+  }
+
+  @override
+  void registerInstanceGet(
+      ir.DartType receiverType, ClassRelation relation, ir.Member target) {
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        new Selector.getter(elementMap.getName(target.name)),
+        _computeReceiverConstraint(receiverType, relation),
+        const <DartType>[]));
+  }
+
+  @override
+  void registerDynamicSet(
+      ir.DartType receiverType, ClassRelation relation, ir.Name name) {
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        new Selector.setter(elementMap.getName(name)),
+        _computeReceiverConstraint(receiverType, relation),
+        const <DartType>[]));
+  }
+
+  @override
+  void registerInstanceSet(
+      ir.DartType receiverType, ClassRelation relation, ir.Member target) {
+    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+        new Selector.setter(elementMap.getName(target.name)),
+        _computeReceiverConstraint(receiverType, relation),
+        const <DartType>[]));
+  }
+
+  void handleRuntimeTypeUse(ir.PropertyGet node, RuntimeTypeUseKind kind,
+      ir.DartType receiverType, ir.DartType argumentType) {
+    DartType receiverDartType = elementMap.getDartType(receiverType);
+    DartType argumentDartType =
+        argumentType == null ? null : elementMap.getDartType(argumentType);
+
+    if (_options.omitImplicitChecks) {
+      switch (kind) {
+        case RuntimeTypeUseKind.string:
+          if (!_options.laxRuntimeTypeToString) {
+            if (receiverDartType == commonElements.objectType) {
+              reporter.reportHintMessage(computeSourceSpanFromTreeNode(node),
+                  MessageKind.RUNTIME_TYPE_TO_STRING_OBJECT);
+            } else {
+              reporter.reportHintMessage(
+                  computeSourceSpanFromTreeNode(node),
+                  MessageKind.RUNTIME_TYPE_TO_STRING_SUBTYPE,
+                  {'receiverType': '${receiverDartType}.'});
             }
           }
-
-          impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
-              selector.toCallSelector(), getterConstraint, typeArguments));
-        } else {
-          impactBuilder.registerDynamicUse(
-              new ConstrainedDynamicUse(selector, constraint, typeArguments));
-        }
+          break;
+        case RuntimeTypeUseKind.equals:
+        case RuntimeTypeUseKind.unknown:
+          break;
       }
     }
+    impactBuilder.registerRuntimeTypeUse(
+        new RuntimeTypeUse(kind, receiverDartType, argumentDartType));
   }
 
   @override
-  void handlePropertyGet(
-      ir.PropertyGet node, ir.DartType receiverType, ir.DartType resultType) {
-    Object constraint;
-    DartType receiverDartType = elementMap.getDartType(receiverType);
-    if (receiverDartType is InterfaceType) {
-      ClassRelation relation = node.receiver is ir.ThisExpression
-          ? ClassRelation.thisExpression
-          : ClassRelation.subtype;
-      constraint = new StrongModeConstraint(
-          commonElements, _nativeBasicData, receiverDartType.element, relation);
-    }
-    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
-        new Selector.getter(elementMap.getName(node.name)),
-        constraint, const <DartType>[]));
-
-    if (node.name.name == Identifiers.runtimeType_) {
-      RuntimeTypeUse runtimeTypeUse = computeRuntimeTypeUse(elementMap, node);
-      if (_options.omitImplicitChecks) {
-        switch (runtimeTypeUse.kind) {
-          case RuntimeTypeUseKind.string:
-            if (!_options.laxRuntimeTypeToString) {
-              if (runtimeTypeUse.receiverType == commonElements.objectType) {
-                reporter.reportHintMessage(computeSourceSpanFromTreeNode(node),
-                    MessageKind.RUNTIME_TYPE_TO_STRING_OBJECT);
-              } else {
-                reporter.reportHintMessage(
-                    computeSourceSpanFromTreeNode(node),
-                    MessageKind.RUNTIME_TYPE_TO_STRING_SUBTYPE,
-                    {'receiverType': '${runtimeTypeUse.receiverType}.'});
-              }
-            }
-            break;
-          case RuntimeTypeUseKind.equals:
-          case RuntimeTypeUseKind.unknown:
-            break;
-        }
-      }
-      impactBuilder.registerRuntimeTypeUse(runtimeTypeUse);
-    }
-  }
-
-  @override
-  void handlePropertySet(
-      ir.PropertySet node, ir.DartType receiverType, ir.DartType valueType) {
-    Object constraint;
-    DartType receiverDartType = elementMap.getDartType(receiverType);
-    if (receiverDartType is InterfaceType) {
-      ClassRelation relation = node.receiver is ir.ThisExpression
-          ? ClassRelation.thisExpression
-          : ClassRelation.subtype;
-      constraint = new StrongModeConstraint(
-          commonElements, _nativeBasicData, receiverDartType.element, relation);
-    }
-    impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
-        new Selector.setter(elementMap.getName(node.name)),
-        constraint, const <DartType>[]));
-  }
-
-  @override
-  void handleAssertStatement(ir.AssertStatement node) {
+  void registerAssert({bool withMessage}) {
     impactBuilder.registerFeature(
-        node.message != null ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT);
+        withMessage ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT);
   }
 
   @override
-  void handleInstantiation(ir.Instantiation node,
-      ir.FunctionType expressionType, ir.DartType resultType) {
+  void registerGenericInstantiation(
+      ir.FunctionType expressionType, List<ir.DartType> typeArguments) {
     // TODO(johnniwinther): Track which arities are used in instantiation.
     impactBuilder.registerInstantiation(new GenericInstantiation(
         elementMap.getDartType(expressionType),
-        node.typeArguments.map(elementMap.getDartType).toList()));
+        typeArguments.map(elementMap.getDartType).toList()));
   }
 
   @override
-  void handleStringConcatenation(ir.StringConcatenation node) {
+  void registerStringConcatenation() {
     impactBuilder.registerFeature(Feature.STRING_INTERPOLATION);
     impactBuilder.registerFeature(Feature.STRING_JUXTAPOSITION);
   }
 
   @override
-  Null handleFunctionDeclaration(ir.FunctionDeclaration node) {
+  void registerLocalFunction(ir.TreeNode node) {
     Local function = elementMap.getLocalFunction(node);
     impactBuilder.registerStaticUse(new StaticUse.closure(function));
-    handleAsyncMarker(node.function);
   }
 
   @override
-  void handleFunctionExpression(ir.FunctionExpression node) {
-    Local function = elementMap.getLocalFunction(node);
-    impactBuilder.registerStaticUse(new StaticUse.closure(function));
-    handleAsyncMarker(node.function);
+  void registerLocalWithoutInitializer() {
+    impactBuilder.registerFeature(Feature.LOCAL_WITHOUT_INITIALIZER);
   }
 
   @override
-  void handleVariableDeclaration(ir.VariableDeclaration node) {
-    if (node.initializer == null) {
-      impactBuilder.registerFeature(Feature.LOCAL_WITHOUT_INITIALIZER);
-    }
+  void registerIsCheck(ir.DartType type) {
+    impactBuilder
+        .registerTypeUse(new TypeUse.isCheck(elementMap.getDartType(type)));
   }
 
   @override
-  void handleIsExpression(ir.IsExpression node) {
+  void registerImplicitCast(ir.DartType type) {
     impactBuilder.registerTypeUse(
-        new TypeUse.isCheck(elementMap.getDartType(node.type)));
+        new TypeUse.implicitCast(elementMap.getDartType(type)));
   }
 
   @override
-  void handleAsExpression(ir.AsExpression node, ir.DartType operandType) {
-    if (elementMap.typeEnvironment.isSubtypeOf(operandType, node.type)) {
-      // Skip unneeded casts.
-      return;
-    }
-    DartType type = elementMap.getDartType(node.type);
-    if (node.isTypeError) {
-      impactBuilder.registerTypeUse(new TypeUse.implicitCast(type));
-    } else {
-      impactBuilder.registerTypeUse(new TypeUse.asCast(type));
-    }
+  void registerAsCast(ir.DartType type) {
+    impactBuilder
+        .registerTypeUse(new TypeUse.asCast(elementMap.getDartType(type)));
   }
 
   @override
-  void handleThrow(ir.Throw node) {
+  @override
+  void registerThrow() {
     impactBuilder.registerFeature(Feature.THROW_EXPRESSION);
   }
 
-  @override
-  void handleForInStatement(ir.ForInStatement node, ir.DartType iterableType) {
+  void registerSyncForIn(ir.DartType iterableType) {
     // TODO(johnniwinther): Use receiver constraints for the dynamic uses in
     // strong mode.
-    if (node.isAsync) {
-      impactBuilder.registerFeature(Feature.ASYNC_FOR_IN);
-      impactBuilder.registerDynamicUse(new DynamicUse(Selectors.cancel));
-    } else {
-      impactBuilder.registerFeature(Feature.SYNC_FOR_IN);
-      impactBuilder.registerDynamicUse(new DynamicUse(Selectors.iterator));
-    }
+    impactBuilder.registerFeature(Feature.SYNC_FOR_IN);
+    impactBuilder.registerDynamicUse(new DynamicUse(Selectors.iterator));
     impactBuilder.registerDynamicUse(new DynamicUse(Selectors.current));
     impactBuilder.registerDynamicUse(new DynamicUse(Selectors.moveNext));
   }
 
-  @override
-  void handleCatch(ir.Catch node) {
+  void registerAsyncForIn(ir.DartType iterableType) {
+    // TODO(johnniwinther): Use receiver constraints for the dynamic uses in
+    // strong mode.
+    impactBuilder.registerFeature(Feature.ASYNC_FOR_IN);
+    impactBuilder.registerDynamicUse(new DynamicUse(Selectors.cancel));
+    impactBuilder.registerDynamicUse(new DynamicUse(Selectors.current));
+    impactBuilder.registerDynamicUse(new DynamicUse(Selectors.moveNext));
+  }
+
+  void registerCatch() {
     impactBuilder.registerFeature(Feature.CATCH_STATEMENT);
-    if (node.stackTrace != null) {
-      impactBuilder.registerFeature(Feature.STACK_TRACE_IN_CATCH);
-    }
-    if (node.guard is! ir.DynamicType) {
-      impactBuilder.registerTypeUse(
-          new TypeUse.catchType(elementMap.getDartType(node.guard)));
-    }
+  }
+
+  void registerStackTrace() {
+    impactBuilder.registerFeature(Feature.STACK_TRACE_IN_CATCH);
+  }
+
+  void registerCatchType(ir.DartType type) {
+    impactBuilder
+        .registerTypeUse(new TypeUse.catchType(elementMap.getDartType(type)));
   }
 
   @override
-  void handleTypeLiteral(ir.TypeLiteral node) {
-    ImportEntity deferredImport = elementMap.getImport(getDeferredImport(node));
-    impactBuilder.registerTypeUse(new TypeUse.typeLiteral(
-        elementMap.getDartType(node.type), deferredImport));
-    if (node.type is ir.FunctionType) {
-      ir.FunctionType functionType = node.type;
-      assert(functionType.typedef != null);
+  void registerTypeLiteral(ir.DartType type, ir.LibraryDependency import) {
+    ImportEntity deferredImport = elementMap.getImport(import);
+    impactBuilder.registerTypeUse(
+        new TypeUse.typeLiteral(elementMap.getDartType(type), deferredImport));
+    if (type is ir.FunctionType) {
+      assert(type.typedef != null);
       // TODO(johnniwinther): Can we avoid the typedef type altogether?
       // We need to ensure that the typedef is live.
-      elementMap.getTypedefType(functionType.typedef);
+      elementMap.getTypedefType(type.typedef);
     }
   }
 
   @override
-  void handleFieldInitializer(ir.FieldInitializer node) {
-    impactBuilder.registerStaticUse(
-        new StaticUse.fieldInit(elementMap.getField(node.field)));
+  void registerFieldInitializer(ir.Field node) {
+    impactBuilder
+        .registerStaticUse(new StaticUse.fieldInit(elementMap.getField(node)));
   }
 
   @override
-  void handleRedirectingInitializer(
-      ir.RedirectingInitializer node, ArgumentTypes argumentTypes) {
-    ConstructorEntity target = elementMap.getConstructor(node.target);
+  void registerRedirectingInitializer(
+      ir.Constructor constructor, ir.Arguments arguments) {
+    ConstructorEntity target = elementMap.getConstructor(constructor);
     impactBuilder.registerStaticUse(new StaticUse.superConstructorInvoke(
-        target, elementMap.getCallStructure(node.arguments)));
+        target, elementMap.getCallStructure(arguments)));
   }
 
   @override
-  void handleLoadLibrary(ir.LoadLibrary node) {
+  void registerLoadLibrary() {
     impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
         commonElements.loadDeferredLibrary, CallStructure.ONE_ARG));
     impactBuilder.registerFeature(Feature.LOAD_LIBRARY);
diff --git a/pkg/compiler/lib/src/kernel/loader.dart b/pkg/compiler/lib/src/kernel/loader.dart
index 4d14f55..19891b3 100644
--- a/pkg/compiler/lib/src/kernel/loader.dart
+++ b/pkg/compiler/lib/src/kernel/loader.dart
@@ -72,7 +72,8 @@
             new Dart2jsTarget(targetName, new TargetFlags()),
             _options.librariesSpecificationUri,
             _options.platformBinaries.resolve(platform),
-            _options.packageConfig);
+            _options.packageConfig,
+            experimentalFlags: _options.languageExperiments);
         component = await fe.compile(
             initializedCompilerState,
             false,
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index a437151..61900e4 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -94,36 +94,34 @@
   int get index => values.indexOf(this);
 }
 
-/**
- * A summary of the behavior of a native element.
- *
- * Native code can return values of one type and cause native subtypes of
- * another type to be instantiated.  By default, we compute both from the
- * declared type.
- *
- * A field might yield any native type that 'is' the field type.
- *
- * A method might create and return instances of native subclasses of its
- * declared return type, and a callback argument may be called with instances of
- * the callback parameter type (e.g. Event).
- *
- * If there is one or more `@Creates` annotations, the union of the named types
- * replaces the inferred instantiated type, and the return type is ignored for
- * the purpose of inferring instantiated types.
- *
- *     @Creates('IDBCursor')    // Created asynchronously.
- *     @Creates('IDBRequest')   // Created synchronously (for return value).
- *     IDBRequest openCursor();
- *
- * If there is one or more `@Returns` annotations, the union of the named types
- * replaces the declared return type.
- *
- *     @Returns('IDBRequest')
- *     IDBRequest openCursor();
- *
- * Types in annotations are non-nullable, so include `@Returns('Null')` if
- * `null` may be returned.
- */
+/// A summary of the behavior of a native element.
+///
+/// Native code can return values of one type and cause native subtypes of
+/// another type to be instantiated.  By default, we compute both from the
+/// declared type.
+///
+/// A field might yield any native type that 'is' the field type.
+///
+/// A method might create and return instances of native subclasses of its
+/// declared return type, and a callback argument may be called with instances
+/// of the callback parameter type (e.g. Event).
+///
+/// If there is one or more `@Creates` annotations, the union of the named types
+/// replaces the inferred instantiated type, and the return type is ignored for
+/// the purpose of inferring instantiated types.
+///
+///     @Creates('IDBCursor')    // Created asynchronously.
+///     @Creates('IDBRequest')   // Created synchronously (for return value).
+///     IDBRequest openCursor();
+///
+/// If there is one or more `@Returns` annotations, the union of the named types
+/// replaces the declared return type.
+///
+///     @Returns('IDBRequest')
+///     IDBRequest openCursor();
+///
+/// Types in annotations are non-nullable, so include `@Returns('Null')` if
+/// `null` may be returned.
 class NativeBehavior {
   /// Tag used for identifying serialized [NativeBehavior] objects in a
   /// debugging data stream.
@@ -742,11 +740,9 @@
     }
   }
 
-  /**
-   * Returns a list of type constraints from the annotations of
-   * [annotationClass].
-   * Returns `null` if no constraints.
-   */
+  /// Returns a list of type constraints from the annotations of
+  /// [annotationClass].
+  /// Returns `null` if no constraints.
   List _collect(Iterable<ConstantValue> metadata, ClassEntity annotationClass,
       TypeLookup lookupType) {
     var types = null;
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index a3a1dd2..dfd4b8f 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -14,9 +14,8 @@
 import 'behavior.dart';
 import 'resolver.dart' show NativeClassFinder;
 
-/**
- * This could be an abstract class but we use it as a stub for the dart_backend.
- */
+/// This could be an abstract class but we use it as a stub for the
+/// dart_backend.
 class NativeEnqueuer {
   /// Called when a [type] has been instantiated natively.
   void onInstantiatedType(InterfaceType type) {}
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 41c32cc..89e4c55 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -70,6 +70,9 @@
   /// flags.
   Map<String, String> environment = const <String, String>{};
 
+  /// Flags enabling language experiments.
+  Map<fe.ExperimentalFlag, bool> languageExperiments = {};
+
   /// A possibly null state object for kernel compilation.
   fe.InitializedCompilerState kernelInitializedCompilerState;
 
@@ -170,6 +173,11 @@
   // TODO(sigmund): rename to minify
   bool enableMinification = false;
 
+  /// Flag to turn off minification even if enabled elsewhere, e.g. via
+  /// -O2. Both [enableMinification] and [_disableMinification] can be true, in
+  /// which case [_disableMinification] wins.
+  bool _disableMinification = false;
+
   /// Whether to model which native classes are live based on annotations on the
   /// core libraries. If false, all native classes will be included by default.
   bool enableNativeLiveTypeAnalysis = true;
@@ -244,10 +252,6 @@
   /// (experimental)
   bool useNewSourceInfo = false;
 
-  /// Whether the user requested to use the fast startup emitter. The full
-  /// emitter might still be used if the program uses dart:mirrors.
-  bool useStartupEmitter = false;
-
   /// Enable verbose printing during compilation. Includes a time-breakdown
   /// between phases at the end.
   bool verbose = false;
@@ -312,6 +316,7 @@
       ..suppressHints = _hasOption(options, Flags.suppressHints)
       ..shownPackageWarnings =
           _extractOptionalCsvOption(options, Flags.showPackageWarnings)
+      ..languageExperiments = _extractExperiments(options)
       ..disableInlining = _hasOption(options, Flags.disableInlining)
       ..disableProgramSplit = _hasOption(options, Flags.disableProgramSplit)
       ..disableTypeInference = _hasOption(options, Flags.disableTypeInference)
@@ -323,6 +328,7 @@
       ..enableExperimentalMirrors =
           _hasOption(options, Flags.enableExperimentalMirrors)
       ..enableMinification = _hasOption(options, Flags.minify)
+      .._disableMinification = _hasOption(options, Flags.noMinify)
       ..enableNativeLiveTypeAnalysis =
           !_hasOption(options, Flags.disableNativeLiveTypeAnalysis)
       ..enableUserAssertions = _hasOption(options, Flags.enableCheckedMode) ||
@@ -358,7 +364,6 @@
           !_hasOption(options, Flags.noFrequencyBasedMinification)
       ..useMultiSourceInfo = _hasOption(options, Flags.useMultiSourceInfo)
       ..useNewSourceInfo = _hasOption(options, Flags.useNewSourceInfo)
-      ..useStartupEmitter = _hasOption(options, Flags.fastStartup)
       ..verbose = _hasOption(options, Flags.verbose)
       ..showInternalProgress = _hasOption(options, Flags.progress)
       ..readDataUri = _extractUriOption(options, '${Flags.readData}=')
@@ -391,7 +396,6 @@
 
   void deriveOptions() {
     if (benchmarkingProduction) {
-      useStartupEmitter = true;
       trustPrimitives = true;
       omitImplicitChecks = true;
     }
@@ -427,6 +431,10 @@
       parameterCheckPolicy = CheckPolicy.checked;
       implicitDowncastCheckPolicy = CheckPolicy.checked;
     }
+
+    if (_disableMinification) {
+      enableMinification = false;
+    }
   }
 
   /// Returns `true` if warnings and hints are shown for all packages.
@@ -505,4 +513,11 @@
   return null;
 }
 
+Map<fe.ExperimentalFlag, bool> _extractExperiments(List<String> options) {
+  List<String> experiments =
+      _extractOptionalCsvOption(options, Flags.enableLanguageExperiments);
+  return fe.parseExperimentalFlags(
+      experiments, (String error) => throw new ArgumentError(error));
+}
+
 const String _UNDETERMINED_BUILD_ID = "build number could not be determined";
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index 57ed4cb..e3b4f3e 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -13,23 +13,21 @@
 import 'elements/types.dart';
 import 'serialization/serialization.dart';
 
-/**
- * An ordered set of the supertypes of a class. The supertypes of a class are
- * ordered by decreasing hierarchy depth and by the order they are extended,
- * mixed in, or implemented.
- *
- * For these classes
- *
- *     class A {} // Depth = 1.
- *     class B {} // Depth = 1.
- *     class C extends B implements A {} // Depth 2.
- *
- * the ordered supertypes are
- *
- *     A: [A, Object]
- *     B: [B, Object]
- *     C: [C, B, A, Object]
- */
+/// An ordered set of the supertypes of a class. The supertypes of a class are
+/// ordered by decreasing hierarchy depth and by the order they are extended,
+/// mixed in, or implemented.
+///
+/// For these classes
+///
+///     class A {} // Depth = 1.
+///     class B {} // Depth = 1.
+///     class C extends B implements A {} // Depth 2.
+///
+/// the ordered supertypes are
+///
+///     A: [A, Object]
+///     B: [B, Object]
+///     C: [C, B, A, Object]
 class OrderedTypeSet {
   /// Tag used for identifying serialized [OrderedTypeSet] objects in a
   /// debugging data stream.
@@ -198,23 +196,21 @@
   String toString() => types.toString();
 }
 
-/**
- * Builder for creation an ordered set of the supertypes of a class. The
- * supertypes are ordered by decreasing hierarchy depth and by the order they
- * are extended, mixed in, or implemented.
- *
- * For these classes
- *
- *     class A {} // Depth = 1.
- *     class B {} // Depth = 1.
- *     class C extends B implements A {} // Depth 2.
- *
- * the ordered supertypes are
- *
- *     A: [A, Object]
- *     B: [B, Object]
- *     C: [C, B, A, Object]
- */
+/// Builder for creation an ordered set of the supertypes of a class. The
+/// supertypes are ordered by decreasing hierarchy depth and by the order they
+/// are extended, mixed in, or implemented.
+///
+/// For these classes
+///
+///     class A {} // Depth = 1.
+///     class B {} // Depth = 1.
+///     class C extends B implements A {} // Depth 2.
+///
+/// the ordered supertypes are
+///
+///     A: [A, Object]
+///     B: [B, Object]
+///     C: [C, B, A, Object]
 abstract class OrderedTypeSetBuilder {
   OrderedTypeSet createOrderedTypeSet(
       InterfaceType supertype, Link<DartType> interfaces);
@@ -257,10 +253,8 @@
     return toTypeSet();
   }
 
-  /**
-   * Adds [type] and all supertypes of [type] to [allSupertypes] while
-   * substituting type variables.
-   */
+  /// Adds [type] and all supertypes of [type] to [allSupertypes] while
+  /// substituting type variables.
   void _addAllSupertypes(InterfaceType type) {
     ClassEntity classElement = type.element;
     Link<InterfaceType> supertypes = getOrderedTypeSet(classElement).supertypes;
diff --git a/pkg/compiler/lib/src/script.dart b/pkg/compiler/lib/src/script.dart
index 403776b..5adbdae 100644
--- a/pkg/compiler/lib/src/script.dart
+++ b/pkg/compiler/lib/src/script.dart
@@ -9,18 +9,14 @@
 class Script {
   final SourceFile file;
 
-  /**
-   * The readable URI from which this script was loaded.
-   *
-   * See [LibraryLoader] for terminology on URIs.
-   */
+  /// The readable URI from which this script was loaded.
+  ///
+  /// See [LibraryLoader] for terminology on URIs.
   final Uri readableUri;
 
-  /**
-   * The resource URI from which this script was loaded.
-   *
-   * See [LibraryLoader] for terminology on URIs.
-   */
+  /// The resource URI from which this script was loaded.
+  ///
+  /// See [LibraryLoader] for terminology on URIs.
   final Uri resourceUri;
 
   /// This script was synthesized.
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
index 28da0ca..28fdf8a 100644
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -219,6 +219,8 @@
         return const ir.InvalidType();
       case DartTypeNodeKind.bottomType:
         return const ir.BottomType();
+      case DartTypeNodeKind.doesNotComplete:
+        return const DoesNotCompleteType();
       case DartTypeNodeKind.typeParameterType:
         ir.TypeParameter typeParameter = readTypeParameterNode();
         ir.DartType promotedBound = _readDartTypeNode(functionTypeVariables);
@@ -270,6 +272,16 @@
         List<ir.DartType> typeArguments =
             _readDartTypeNodes(functionTypeVariables);
         return new ir.InterfaceType(cls, typeArguments);
+      case DartTypeNodeKind.thisInterfaceType:
+        ir.Class cls = readClassNode();
+        List<ir.DartType> typeArguments =
+            _readDartTypeNodes(functionTypeVariables);
+        return new ThisInterfaceType(cls, typeArguments);
+      case DartTypeNodeKind.exactInterfaceType:
+        ir.Class cls = readClassNode();
+        List<ir.DartType> typeArguments =
+            _readDartTypeNodes(functionTypeVariables);
+        return new ExactInterfaceType(cls, typeArguments);
       case DartTypeNodeKind.typedef:
         ir.Typedef typedef = readTypedefNode();
         List<ir.DartType> typeArguments =
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index 589c6eef..a75b7e3 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -90,7 +90,7 @@
   interfaceType,
   typedef,
   dynamicType,
-  futureOr
+  futureOr,
 }
 
 /// Visitor that serializes [DartType] object together with [AbstractDataSink].
@@ -194,6 +194,9 @@
   dynamicType,
   bottomType,
   invalidType,
+  thisInterfaceType,
+  exactInterfaceType,
+  doesNotComplete,
 }
 
 const String functionTypeNodeTag = 'function-type-node';
@@ -235,12 +238,22 @@
 
   void visitBottomType(
       ir.BottomType node, List<ir.TypeParameter> functionTypeVariables) {
-    _sink.writeEnum(DartTypeNodeKind.bottomType);
+    if (node == const DoesNotCompleteType()) {
+      _sink.writeEnum(DartTypeNodeKind.doesNotComplete);
+    } else {
+      _sink.writeEnum(DartTypeNodeKind.bottomType);
+    }
   }
 
   void visitInterfaceType(
       ir.InterfaceType node, List<ir.TypeParameter> functionTypeVariables) {
-    _sink.writeEnum(DartTypeNodeKind.interfaceType);
+    if (node is ThisInterfaceType) {
+      _sink.writeEnum(DartTypeNodeKind.thisInterfaceType);
+    } else if (node is ExactInterfaceType) {
+      _sink.writeEnum(DartTypeNodeKind.exactInterfaceType);
+    } else {
+      _sink.writeEnum(DartTypeNodeKind.interfaceType);
+    }
     _sink.writeClassNode(node.classNode);
     visitTypes(node.typeArguments, functionTypeVariables);
   }
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 2d2fd9b..3348edd 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -14,6 +14,7 @@
 import '../elements/entities.dart';
 import '../elements/indexed.dart';
 import '../elements/types.dart';
+import '../ir/static_type_base.dart';
 import '../js_model/closure.dart';
 import '../js_model/locals.dart';
 
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 1c14b38..1674df2 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -4933,10 +4933,8 @@
       ..cleanUp();
   }
 
-  /**
-   * Try to inline [element] within the correct context of the builder. The
-   * insertion point is the state of the builder.
-   */
+  /// Try to inline [element] within the correct context of the builder. The
+  /// insertion point is the state of the builder.
   bool _tryInlineMethod(
       FunctionEntity function,
       Selector selector,
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 9a23841..dc941f4 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -134,26 +134,22 @@
 }
 
 class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
-  /**
-   * Returned by [expressionType] to tell how code can be generated for
-   * a subgraph.
-   * - [TYPE_STATEMENT] means that the graph must be generated as a statement,
-   * which is always possible.
-   * - [TYPE_EXPRESSION] means that the graph can be generated as an expression,
-   * or possibly several comma-separated expressions.
-   * - [TYPE_DECLARATION] means that the graph can be generated as an
-   * expression, and that it only generates expressions of the form
-   *   variable = expression
-   * which are also valid as parts of a "var" declaration.
-   */
+  /// Returned by [expressionType] to tell how code can be generated for
+  /// a subgraph.
+  /// - [TYPE_STATEMENT] means that the graph must be generated as a statement,
+  /// which is always possible.
+  /// - [TYPE_EXPRESSION] means that the graph can be generated as an expression,
+  /// or possibly several comma-separated expressions.
+  /// - [TYPE_DECLARATION] means that the graph can be generated as an
+  /// expression, and that it only generates expressions of the form
+  ///   variable = expression
+  /// which are also valid as parts of a "var" declaration.
   static const int TYPE_STATEMENT = 0;
   static const int TYPE_EXPRESSION = 1;
   static const int TYPE_DECLARATION = 2;
 
-  /**
-   * Whether we are currently generating expressions instead of statements.
-   * This includes declarations, which are generated as expressions.
-   */
+  /// Whether we are currently generating expressions instead of statements.
+  /// This includes declarations, which are generated as expressions.
   bool isGeneratingExpression = false;
 
   final CompilerOptions _options;
@@ -180,10 +176,8 @@
   List<js.Expression> expressionStack;
   List<js.Block> oldContainerStack;
 
-  /**
-   * Contains the names of the instructions, as well as the parallel
-   * copies to perform on block transitioning.
-   */
+  /// Contains the names of the instructions, as well as the parallel
+  /// copies to perform on block transitioning.
   VariableNames variableNames;
 
   /// `true` when we need to generate a `var` declaration at function entry,
@@ -191,17 +185,13 @@
   /// middle of the function.
   bool shouldGroupVarDeclarations = false;
 
-  /**
-   * While generating expressions, we can't insert variable declarations.
-   * Instead we declare them at the start of the function.  When minifying
-   * we do this most of the time, because it reduces the size unless there
-   * is only one variable.
-   */
+  /// While generating expressions, we can't insert variable declarations.
+  /// Instead we declare them at the start of the function.  When minifying
+  /// we do this most of the time, because it reduces the size unless there
+  /// is only one variable.
   final Set<String> collectedVariableDeclarations;
 
-  /**
-   * Set of variables and parameters that have already been declared.
-   */
+  /// Set of variables and parameters that have already been declared.
   final Set<String> declaredLocals;
 
   HGraph currentGraph;
@@ -332,10 +322,8 @@
     return hasNonBitOpUser(instruction, new Set<HPhi>());
   }
 
-  /**
-   * If the [instruction] is not `null` it will be used to attach the position
-   * to the [statement].
-   */
+  /// If the [instruction] is not `null` it will be used to attach the position
+  /// to the [statement].
   void pushStatement(js.Statement statement) {
     assert(expressionStack.isEmpty);
     currentContainer.statements.add(statement);
@@ -345,20 +333,16 @@
     currentContainer.statements.insert(0, statement);
   }
 
-  /**
-   * If the [instruction] is not `null` it will be used to attach the position
-   * to the [expression].
-   */
+  /// If the [instruction] is not `null` it will be used to attach the position
+  /// to the [expression].
   pushExpressionAsStatement(
       js.Expression expression, SourceInformation sourceInformation) {
     pushStatement(new js.ExpressionStatement(expression)
         .withSourceInformation(sourceInformation));
   }
 
-  /**
-   * If the [instruction] is not `null` it will be used to attach the position
-   * to the [expression].
-   */
+  /// If the [instruction] is not `null` it will be used to attach the position
+  /// to the [expression].
   push(js.Expression expression) {
     expressionStack.add(expression);
   }
@@ -507,15 +491,13 @@
     subGraph = oldSubGraph;
   }
 
-  /**
-   * Check whether a sub-graph can be generated as an expression, or even
-   * as a declaration, or if it has to fall back to being generated as
-   * a statement.
-   * Expressions are anything that doesn't generate control flow constructs.
-   * Declarations must only generate assignments on the form "id = expression",
-   * and not, e.g., expressions where the value isn't assigned, or where it's
-   * assigned to something that's not a simple variable.
-   */
+  /// Check whether a sub-graph can be generated as an expression, or even
+  /// as a declaration, or if it has to fall back to being generated as
+  /// a statement.
+  /// Expressions are anything that doesn't generate control flow constructs.
+  /// Declarations must only generate assignments on the form "id = expression",
+  /// and not, e.g., expressions where the value isn't assigned, or where it's
+  /// assigned to something that's not a simple variable.
   int expressionType(HExpressionInformation info) {
     // The only HExpressionInformation used as part of a HBlockInformation is
     // current HSubExpressionBlockInformation, so it's the only one reaching
@@ -580,12 +562,10 @@
         (limits.end.last is HConditionalBranch);
   }
 
-  /**
-   * Generate statements from block information.
-   * If the block information contains expressions, generate only
-   * assignments, and if it ends in a conditional branch, don't generate
-   * the condition.
-   */
+  /// Generate statements from block information.
+  /// If the block information contains expressions, generate only
+  /// assignments, and if it ends in a conditional branch, don't generate
+  /// the condition.
   void generateStatements(HBlockInformation block) {
     if (block is HStatementInformation) {
       block.accept(this);
@@ -604,12 +584,10 @@
     return result;
   }
 
-  /**
-   * If the [block] only contains one statement returns that statement. If the
-   * that statement itself is a block, recursively calls this method.
-   *
-   * If the block is empty, returns a new instance of [js.NOP].
-   */
+  /// If the [block] only contains one statement returns that statement. If the
+  /// that statement itself is a block, recursively calls this method.
+  ///
+  /// If the block is empty, returns a new instance of [js.NOP].
   js.Statement unwrapStatement(js.Block block) {
     int len = block.statements.length;
     if (len == 0) return new js.EmptyStatement();
@@ -621,9 +599,7 @@
     return block;
   }
 
-  /**
-   * Generate expressions from block information.
-   */
+  /// Generate expressions from block information.
   js.Expression generateExpression(HExpressionInformation expression) {
     // Currently we only handle sub-expression graphs.
     assert(expression is HSubExpressionBlockInformation);
@@ -651,9 +627,7 @@
     }
   }
 
-  /**
-    * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
-    */
+  /// Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
   List<js.Expression> visitArguments(List<HInstruction> inputs,
       {int start: HInvoke.ARGUMENTS_OFFSET}) {
     assert(inputs.length >= start);
@@ -1331,10 +1305,8 @@
     assignVariable(destination, new js.VariableUse(source), sourceInformation);
   }
 
-  /**
-   * Sequentialize a list of conceptually parallel copies. Parallel
-   * copies may contain cycles, that this method breaks.
-   */
+  /// Sequentialize a list of conceptually parallel copies. Parallel
+  /// copies may contain cycles, that this method breaks.
   void sequentializeCopies(
       Iterable<Copy<HInstruction>> instructionCopies,
       String tempName,
@@ -2194,7 +2166,10 @@
     use(node.receiver);
     js.Expression receiver = pop();
     use(node.value);
-    push(new js.Assignment(new js.PropertyAccess(receiver, name), pop())
+    push(new js.Assignment(
+            new js.PropertyAccess(receiver, name)
+                .withSourceInformation(node.sourceInformation),
+            pop())
         .withSourceInformation(node.sourceInformation));
   }
 
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 2fc43bb..78ddc04 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -12,10 +12,8 @@
 import '../world.dart' show JClosedWorld;
 import 'nodes.dart';
 
-/**
- * Replaces some instructions with specialized versions to make codegen easier.
- * Caches codegen information on nodes.
- */
+/// Replaces some instructions with specialized versions to make codegen easier.
+/// Caches codegen information on nodes.
 class SsaInstructionSelection extends HBaseVisitor {
   final JClosedWorld _closedWorld;
   final InterceptorData _interceptorData;
@@ -341,10 +339,8 @@
   }
 }
 
-/**
- * Remove [HTypeKnown] instructions from the graph, to make codegen
- * analysis easier.
- */
+/// Remove [HTypeKnown] instructions from the graph, to make codegen
+/// analysis easier.
 class SsaTypeKnownRemover extends HBaseVisitor {
   void visitGraph(HGraph graph) {
     visitDominatorTree(graph);
@@ -370,10 +366,8 @@
   }
 }
 
-/**
- * Remove [HTypeConversion] instructions from the graph in '--trust-primitives'
- * mode.
- */
+/// Remove [HTypeConversion] instructions from the graph in '--trust-primitives'
+/// mode.
 class SsaTrustedCheckRemover extends HBaseVisitor {
   final CompilerOptions _options;
 
@@ -401,29 +395,25 @@
   }
 }
 
-/**
- * Instead of emitting each SSA instruction with a temporary variable
- * mark instructions that can be emitted at their use-site.
- * For example, in:
- *   t0 = 4;
- *   t1 = 3;
- *   t2 = add(t0, t1);
- * t0 and t1 would be marked and the resulting code would then be:
- *   t2 = add(4, 3);
- */
+/// Instead of emitting each SSA instruction with a temporary variable
+/// mark instructions that can be emitted at their use-site.
+/// For example, in:
+///   t0 = 4;
+///   t1 = 3;
+///   t2 = add(t0, t1);
+/// t0 and t1 would be marked and the resulting code would then be:
+///   t2 = add(4, 3);
 class SsaInstructionMerger extends HBaseVisitor {
   final AbstractValueDomain _abstractValueDomain;
   final SuperMemberData _superMemberData;
-  /**
-   * List of [HInstruction] that the instruction merger expects in
-   * order when visiting the inputs of an instruction.
-   */
+
+  /// List of [HInstruction] that the instruction merger expects in
+  /// order when visiting the inputs of an instruction.
   List<HInstruction> expectedInputs;
-  /**
-   * Set of pure [HInstruction] that the instruction merger expects to
-   * find. The order of pure instructions do not matter, as they will
-   * not be affected by side effects.
-   */
+
+  /// Set of pure [HInstruction] that the instruction merger expects to
+  /// find. The order of pure instructions do not matter, as they will
+  /// not be affected by side effects.
   Set<HInstruction> pureInputs;
   Set<HInstruction> generateAtUseSite;
 
@@ -710,11 +700,9 @@
   }
 }
 
-/**
- *  Detect control flow arising from short-circuit logical and
- *  conditional operators, and prepare the program to be generated
- *  using these operators instead of nested ifs and boolean variables.
- */
+///  Detect control flow arising from short-circuit logical and
+///  conditional operators, and prepare the program to be generated
+///  using these operators instead of nested ifs and boolean variables.
 class SsaConditionMerger extends HGraphVisitor {
   Set<HInstruction> generateAtUseSite;
   Set<HInstruction> controlFlowOperators;
@@ -730,10 +718,8 @@
     visitPostDominatorTree(graph);
   }
 
-  /**
-   * Check if a block has at least one statement other than
-   * [instruction].
-   */
+  /// Check if a block has at least one statement other than
+  /// [instruction].
   bool hasAnyStatement(HBasicBlock block, HInstruction instruction) {
     // If [instruction] is not in [block], then if the block is not
     // empty, we know there will be a statement to emit.
diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart
index 938d1dd..7b78b8c 100644
--- a/pkg/compiler/lib/src/ssa/graph_builder.dart
+++ b/pkg/compiler/lib/src/ssa/graph_builder.dart
@@ -281,8 +281,6 @@
   /// concrete SSA builder reports an error.
   bool getFlagValue(String flagName) {
     switch (flagName) {
-      case 'IS_FULL_EMITTER':
-        return !options.useStartupEmitter;
       case 'MINIFIED':
         return options.enableMinification;
       case 'MUST_RETAIN_METADATA':
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 0ea8717..3f5d89b 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -12,26 +12,24 @@
 import 'nodes.dart';
 import 'optimize.dart';
 
-/**
- * This phase simplifies interceptors in multiple ways:
- *
- * 1) If the interceptor is for an object whose type is known, it
- * tries to use a constant interceptor instead.
- *
- * 2) Interceptors are specialized based on the selector it is used with.
- *
- * 3) If we know the object is not intercepted, we just use the object
- * instead.
- *
- * 4) Single use interceptors at dynamic invoke sites are replaced with 'one
- * shot interceptors' which are synthesized static helper functions that fetch
- * the interceptor and then call the method.  This saves code size and makes the
- * receiver of an intercepted call a candidate for being generated at use site.
- *
- * 5) Some HIs operations on an interceptor are replaced with a HIs version that
- * uses 'instanceof' rather than testing a type flag.
- *
- */
+/// This phase simplifies interceptors in multiple ways:
+///
+/// 1) If the interceptor is for an object whose type is known, it
+/// tries to use a constant interceptor instead.
+///
+/// 2) Interceptors are specialized based on the selector it is used with.
+///
+/// 3) If we know the object is not intercepted, we just use the object
+/// instead.
+///
+/// 4) Single use interceptors at dynamic invoke sites are replaced with 'one
+/// shot interceptors' which are synthesized static helper functions that fetch
+/// the interceptor and then call the method.  This saves code size and makes the
+/// receiver of an intercepted call a candidate for being generated at use site.
+///
+/// 5) Some HIs operations on an interceptor are replaced with a HIs version that
+/// uses 'instanceof' rather than testing a type flag.
+///
 class SsaSimplifyInterceptors extends HBaseVisitor
     implements OptimizationPhase {
   final String name = "SsaSimplifyInterceptors";
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index 847ad4e..18f2ce2 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
@@ -16,12 +16,10 @@
 import 'nodes.dart';
 import 'types.dart';
 
-/**
- * [InvokeDynamicSpecializer] and its subclasses are helpers to
- * optimize intercepted dynamic calls. It knows what input types
- * would be beneficial for performance, and how to change a invoke
- * dynamic to a builtin instruction (e.g. HIndex, HBitNot).
- */
+/// [InvokeDynamicSpecializer] and its subclasses are helpers to
+/// optimize intercepted dynamic calls. It knows what input types
+/// would be beneficial for performance, and how to change a invoke
+/// dynamic to a builtin instruction (e.g. HIndex, HBitNot).
 class InvokeDynamicSpecializer {
   const InvokeDynamicSpecializer();
 
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 568ae0b..dc693ef 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -510,7 +510,7 @@
 class SubExpression extends SubGraph {
   const SubExpression(HBasicBlock start, HBasicBlock end) : super(start, end);
 
-  /** Find the condition expression if this sub-expression is a condition. */
+  /// Find the condition expression if this sub-expression is a condition.
   HInstruction get conditionExpression {
     HInstruction last = end.last;
     if (last is HConditionalBranch || last is HSwitch) return last.inputs[0];
@@ -580,7 +580,7 @@
     detach(instruction);
   }
 
-  /** Linear search for [instruction]. */
+  /// Linear search for [instruction].
   bool contains(HInstruction instruction) {
     HInstruction cursor = first;
     while (cursor != null) {
@@ -760,10 +760,8 @@
     }
   }
 
-  /**
-   * Rewrites all uses of the [from] instruction to using the [to]
-   * instruction instead.
-   */
+  /// Rewrites all uses of the [from] instruction to using the [to]
+  /// instruction instead.
   void rewrite(HInstruction from, HInstruction to) {
     for (HInstruction use in from.usedBy) {
       use.rewriteInput(from, to);
@@ -772,11 +770,9 @@
     from.usedBy.clear();
   }
 
-  /**
-   * Rewrites all uses of the [from] instruction to using either the
-   * [to] instruction, or a [HCheck] instruction that has better type
-   * information on [to], and that dominates the user.
-   */
+  /// Rewrites all uses of the [from] instruction to using either the
+  /// [to] instruction, or a [HCheck] instruction that has better type
+  /// information on [to], and that dominates the user.
   void rewriteWithBetterUser(HInstruction from, HInstruction to) {
     // BUG(11841): Turn this method into a phase to be run after GVN phases.
     Link<HCheck> better = const Link<HCheck>();
@@ -992,11 +988,9 @@
 
   bool get isMovable => useGvn();
 
-  /**
-   * A pure instruction is an instruction that does not have any side
-   * effect, nor any dependency. They can be moved anywhere in the
-   * graph.
-   */
+  /// A pure instruction is an instruction that does not have any side
+  /// effect, nor any dependency. They can be moved anywhere in the
+  /// graph.
   bool isPure(AbstractValueDomain domain) {
     return !sideEffects.hasSideEffects() &&
         !sideEffects.dependsOnSomething() &&
@@ -1105,9 +1099,7 @@
   AbstractBool isPrimitiveOrNull(AbstractValueDomain domain) =>
       domain.isPrimitiveOrNull(instructionType);
 
-  /**
-   * Type of the instruction.
-   */
+  /// Type of the instruction.
   AbstractValue instructionType;
 
   Selector get selector => null;
@@ -1185,7 +1177,7 @@
     }
   }
 
-  /** Removes all occurrences of [instruction] from [list]. */
+  /// Removes all occurrences of [instruction] from [list].
   void removeFromList(List<HInstruction> list, HInstruction instruction) {
     int length = list.length;
     int i = 0;
@@ -1200,7 +1192,7 @@
     list.length = length;
   }
 
-  /** Removes all occurrences of [user] from [usedBy]. */
+  /// Removes all occurrences of [user] from [usedBy].
   void removeUser(HInstruction user) {
     removeFromList(usedBy, user);
   }
@@ -1299,10 +1291,8 @@
     }
   }
 
-  /**
-   * Return whether the instructions do not belong to a loop or
-   * belong to the same loop.
-   */
+  /// Return whether the instructions do not belong to a loop or
+  /// belong to the same loop.
   bool hasSameLoopHeaderAs(HInstruction other) {
     return block.enclosingLoopHeader == other.block.enclosingLoopHeader;
   }
@@ -1466,10 +1456,8 @@
   String toString() => 'HRef(${value})';
 }
 
-/**
- * Late instructions are used after the main optimization phases.  They capture
- * codegen decisions just prior to generating JavaScript.
- */
+/// Late instructions are used after the main optimization phases.  They capture
+/// codegen decisions just prior to generating JavaScript.
 abstract class HLateInstruction extends HInstruction {
   HLateInstruction(List<HInstruction> inputs, AbstractValue type)
       : super(inputs, type);
@@ -1488,13 +1476,11 @@
   bool dataEquals(HInstruction other) => true;
 }
 
-/**
- * A [HCheck] instruction is an instruction that might do a dynamic
- * check at runtime on another instruction. To have proper instruction
- * dependencies in the graph, instructions that depend on the check
- * being done reference the [HCheck] instruction instead of the
- * instruction itself.
- */
+/// A [HCheck] instruction is an instruction that might do a dynamic
+/// check at runtime on another instruction. To have proper instruction
+/// dependencies in the graph, instructions that depend on the check
+/// being done reference the [HCheck] instruction instead of the
+/// instruction itself.
 abstract class HCheck extends HInstruction {
   HCheck(inputs, type) : super(inputs, type) {
     setUseGvn();
@@ -1512,10 +1498,9 @@
   static const int ALWAYS_ABOVE_ZERO = 2;
   static const int ALWAYS_BELOW_LENGTH = 3;
   static const int ALWAYS_TRUE = 4;
-  /**
-   * Details which tests have been done statically during compilation.
-   * Default is that all checks must be performed dynamically.
-   */
+
+  /// Details which tests have been done statically during compilation.
+  /// Default is that all checks must be performed dynamically.
   int staticChecks = FULL_CHECK;
 
   HBoundsCheck(length, index, array, type)
@@ -1644,9 +1629,7 @@
   /// The type arguments passed in this dynamic invocation.
   List<DartType> get typeArguments;
 
-  /**
-   * Returns whether this call is on an interceptor object.
-   */
+  /// Returns whether this call is on an interceptor object.
   bool isCallOnInterceptor(JClosedWorld closedWorld) {
     return isInterceptedCall && receiver.isInterceptor(closedWorld);
   }
@@ -1776,7 +1759,7 @@
   /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations].
   List<InterfaceType> instantiatedTypes;
 
-  /** The first input must be the target. */
+  /// The first input must be the target.
   HInvokeStatic(this.element, inputs, AbstractValue type, this.typeArguments,
       {this.targetCanThrow: true, bool isIntercepted: false})
       : super(inputs, type) {
@@ -1791,7 +1774,7 @@
 }
 
 class HInvokeSuper extends HInvokeStatic {
-  /** The class where the call to super is being done. */
+  /// The class where the call to super is being done.
   final ClassEntity caller;
   final bool isSetter;
   final Selector selector;
@@ -1816,9 +1799,7 @@
     return isCallOnInterceptor(closedWorld) ? inputs[1] : inputs[0];
   }
 
-  /**
-   * Returns whether this call is on an interceptor object.
-   */
+  /// Returns whether this call is on an interceptor object.
   bool isCallOnInterceptor(JClosedWorld closedWorld) {
     return isInterceptedCall && receiver.isInterceptor(closedWorld);
   }
@@ -1974,10 +1955,8 @@
   String toString() => "GetLength()";
 }
 
-/**
- * HReadModifyWrite is a late stage instruction for a field (property) update
- * via an assignment operation or pre- or post-increment.
- */
+/// HReadModifyWrite is a late stage instruction for a field (property) update
+/// via an assignment operation or pre- or post-increment.
 class HReadModifyWrite extends HLateInstruction {
   static const ASSIGN_OP = 0;
   static const PRE_OP = 1;
@@ -2242,11 +2221,9 @@
   bool dataEquals(HInstruction other) => true;
 }
 
-/**
- * An [HSwitch] instruction has one input for the incoming
- * value, and one input per constant that it can switch on.
- * Its block has one successor per constant, and one for the default.
- */
+/// An [HSwitch] instruction has one input for the incoming
+/// value, and one input per constant that it can switch on.
+/// Its block has one successor per constant, and one for the default.
 class HSwitch extends HControlFlow {
   HSwitch(AbstractValueDomain domain, List<HInstruction> inputs)
       : super(domain, inputs);
@@ -2254,11 +2231,9 @@
   HConstant constant(int index) => inputs[index + 1];
   HInstruction get expression => inputs[0];
 
-  /**
-   * Provides the target to jump to if none of the constants match
-   * the expression. If the switch had no default case, this is the
-   * following join-block.
-   */
+  /// Provides the target to jump to if none of the constants match
+  /// the expression. If the switch had no default case, this is the
+  /// following join-block.
   HBasicBlock get defaultTarget => block.successors.last;
 
   accept(HVisitor visitor) => visitor.visitSwitch(this);
@@ -2551,11 +2526,9 @@
   bool dataEquals(HInstruction other) => true;
 }
 
-/**
-  * An [HLocalValue] represents a local. Unlike [HParameterValue]s its
-  * first use must be in an HLocalSet. That is, [HParameterValue]s have a
-  * value from the start, whereas [HLocalValue]s need to be initialized first.
-  */
+/// An [HLocalValue] represents a local. Unlike [HParameterValue]s its
+/// first use must be in an HLocalSet. That is, [HParameterValue]s have a
+/// value from the start, whereas [HLocalValue]s need to be initialized first.
 class HLocalValue extends HInstruction {
   HLocalValue(Entity variable, AbstractValue type)
       : super(<HInstruction>[], type) {
@@ -2823,15 +2796,13 @@
   }
 }
 
-/**
- * A "one-shot" interceptor is a call to a synthetized method that
- * will fetch the interceptor of its first parameter, and make a call
- * on a given selector with the remaining parameters.
- *
- * In order to share the same optimizations with regular interceptor
- * calls, this class extends [HInvokeDynamic] and also has the null
- * constant as the first input.
- */
+/// A "one-shot" interceptor is a call to a synthetized method that
+/// will fetch the interceptor of its first parameter, and make a call
+/// on a given selector with the remaining parameters.
+///
+/// In order to share the same optimizations with regular interceptor
+/// calls, this class extends [HInvokeDynamic] and also has the null
+/// constant as the first input.
 class HOneShotInterceptor extends HInvokeDynamic {
   List<DartType> typeArguments;
   Set<ClassEntity> interceptedClasses;
@@ -2855,7 +2826,7 @@
   accept(HVisitor visitor) => visitor.visitOneShotInterceptor(this);
 }
 
-/** An [HLazyStatic] is a static that is initialized lazily at first read. */
+/// An [HLazyStatic] is a static that is initialized lazily at first read.
 class HLazyStatic extends HInstruction {
   final FieldEntity element;
 
@@ -2904,10 +2875,8 @@
   bool isAllocation(AbstractValueDomain domain) => true;
 }
 
-/**
- * The primitive array indexing operation. Note that this instruction
- * does not throw because we generate the checks explicitly.
- */
+/// The primitive array indexing operation. Note that this instruction
+/// does not throw because we generate the checks explicitly.
 class HIndex extends HInstruction {
   final Selector selector;
   HIndex(HInstruction receiver, HInstruction index, this.selector,
@@ -2939,10 +2908,8 @@
   bool dataEquals(HIndex other) => true;
 }
 
-/**
- * The primitive array assignment operation. Note that this instruction
- * does not throw because we generate the checks explicitly.
- */
+/// The primitive array assignment operation. Note that this instruction
+/// does not throw because we generate the checks explicitly.
 class HIndexAssign extends HInstruction {
   final Selector selector;
   HIndexAssign(AbstractValueDomain domain, HInstruction receiver,
@@ -3065,11 +3032,9 @@
   }
 }
 
-/**
- * HIsViaInterceptor is a late-stage instruction for a type test that can be
- * done entirely on an interceptor.  It is not a HCheck because the checked
- * input is not one of the inputs.
- */
+/// HIsViaInterceptor is a late-stage instruction for a type test that can be
+/// done entirely on an interceptor.  It is not a HCheck because the checked
+/// input is not one of the inputs.
 class HIsViaInterceptor extends HLateInstruction {
   final DartType typeExpression;
   HIsViaInterceptor(
@@ -3323,10 +3288,8 @@
   toString() => "string concat";
 }
 
-/**
- * The part of string interpolation which converts and interpolated expression
- * into a String value.
- */
+/// The part of string interpolation which converts and interpolated expression
+/// into a String value.
 class HStringify extends HInstruction {
   HStringify(HInstruction input, AbstractValue type)
       : super(<HInstruction>[input], type) {
@@ -3338,7 +3301,7 @@
   toString() => "stringify";
 }
 
-/** Non-block-based (aka. traditional) loop information. */
+/// Non-block-based (aka. traditional) loop information.
 class HLoopInformation {
   final HBasicBlock header;
   final List<HBasicBlock> blocks;
@@ -3346,7 +3309,7 @@
   final List<LabelDefinition> labels;
   final JumpTarget target;
 
-  /** Corresponding block information for the loop. */
+  /// Corresponding block information for the loop.
   HLoopBlockInformation loopBlockInformation;
 
   HLoopInformation(this.header, this.target, this.labels)
@@ -3379,37 +3342,29 @@
   }
 }
 
-/**
- * Embedding of a [HBlockInformation] for block-structure based traversal
- * in a dominator based flow traversal by attaching it to a basic block.
- * To go back to dominator-based traversal, a [HSubGraphBlockInformation]
- * structure can be added in the block structure.
- */
+/// Embedding of a [HBlockInformation] for block-structure based traversal
+/// in a dominator based flow traversal by attaching it to a basic block.
+/// To go back to dominator-based traversal, a [HSubGraphBlockInformation]
+/// structure can be added in the block structure.
 class HBlockFlow {
   final HBlockInformation body;
   final HBasicBlock continuation;
   HBlockFlow(this.body, this.continuation);
 }
 
-/**
- * Information about a syntactic-like structure.
- */
+/// Information about a syntactic-like structure.
 abstract class HBlockInformation {
   HBasicBlock get start;
   HBasicBlock get end;
   bool accept(HBlockInformationVisitor visitor);
 }
 
-/**
- * Information about a statement-like structure.
- */
+/// Information about a statement-like structure.
 abstract class HStatementInformation extends HBlockInformation {
   bool accept(HStatementInformationVisitor visitor);
 }
 
-/**
- * Information about an expression-like structure.
- */
+/// Information about an expression-like structure.
 abstract class HExpressionInformation extends HBlockInformation {
   bool accept(HExpressionInformationVisitor visitor);
   HInstruction get conditionExpression;
@@ -3435,10 +3390,8 @@
 abstract class HBlockInformationVisitor
     implements HStatementInformationVisitor, HExpressionInformationVisitor {}
 
-/**
- * Generic class wrapping a [SubGraph] as a block-information until
- * all structures are handled properly.
- */
+/// Generic class wrapping a [SubGraph] as a block-information until
+/// all structures are handled properly.
 class HSubGraphBlockInformation implements HStatementInformation {
   final SubGraph subGraph;
   HSubGraphBlockInformation(this.subGraph);
@@ -3450,10 +3403,8 @@
       visitor.visitSubGraphInfo(this);
 }
 
-/**
- * Generic class wrapping a [SubExpression] as a block-information until
- * expressions structures are handled properly.
- */
+/// Generic class wrapping a [SubExpression] as a block-information until
+/// expressions structures are handled properly.
 class HSubExpressionBlockInformation implements HExpressionInformation {
   final SubExpression subExpression;
   HSubExpressionBlockInformation(this.subExpression);
@@ -3467,7 +3418,7 @@
       visitor.visitSubExpressionInfo(this);
 }
 
-/** A sequence of separate statements. */
+/// A sequence of separate statements.
 class HStatementSequenceInformation implements HStatementInformation {
   final List<HStatementInformation> statements;
   HStatementSequenceInformation(this.statements);
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 72a69eb..40917cf 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -182,10 +182,8 @@
   return false;
 }
 
-/**
- * If both inputs to known operations are available execute the operation at
- * compile-time.
- */
+/// If both inputs to known operations are available execute the operation at
+/// compile-time.
 class SsaInstructionSimplifier extends HBaseVisitor
     implements OptimizationPhase {
   // We don't produce constant-folded strings longer than this unless they have
@@ -1253,7 +1251,8 @@
           field, _globalInferenceResults);
     }
 
-    return new HFieldGet(field, receiver, type, isAssignable: isAssignable);
+    return new HFieldGet(field, receiver, type, isAssignable: isAssignable)
+      ..sourceInformation = node.sourceInformation;
   }
 
   HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
@@ -1289,7 +1288,8 @@
       }
     }
     HFieldSet result =
-        new HFieldSet(_abstractValueDomain, field, receiver, value);
+        new HFieldSet(_abstractValueDomain, field, receiver, value)
+          ..sourceInformation = node.sourceInformation;
     _log?.registerFieldSet(node, result);
     return result;
   }
@@ -2819,11 +2819,9 @@
   }
 }
 
-/**
- * Optimization phase that tries to eliminate memory loads (for example
- * [HFieldGet]), when it knows the value stored in that memory location, and
- * stores that overwrite with the same value.
- */
+/// Optimization phase that tries to eliminate memory loads (for example
+/// [HFieldGet]), when it knows the value stored in that memory location, and
+/// stores that overwrite with the same value.
 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
   final Compiler compiler;
   final JClosedWorld closedWorld;
diff --git a/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart b/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
index f6bfb90..5f2e064 100644
--- a/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
@@ -58,10 +58,8 @@
         new SubExpression(conditionBranch.block, conditionExitBlock);
   }
 
-  /**
-   * Returns true if the locals of the [fromBranch] may be reused. A [:true:]
-   * return value implies that [mayReuseFromLocals] was set to [:true:].
-   */
+  /// Returns true if the locals of the [fromBranch] may be reused. A [:true:]
+  /// return value implies that [mayReuseFromLocals] was set to [:true:].
   bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch,
       {bool mayReuseFromLocals}) {
     LocalsHandler fromLocals = fromBranch.exitLocals;
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index a4b3de8..ee7bc98 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -12,11 +12,9 @@
 import '../world.dart' show JClosedWorld;
 import 'nodes.dart';
 
-/**
- * Outputs SSA code in a format readable by Hydra IR.
- * Tracing is disabled by default, see ../tracer.dart for how
- * to enable it.
- */
+/// Outputs SSA code in a format readable by Hydra IR.
+/// Tracing is disabled by default, see ../tracer.dart for how
+/// to enable it.
 class HTracer extends HGraphVisitor with TracerUtil {
   final JClosedWorld closedWorld;
   final Namer namer;
diff --git a/pkg/compiler/lib/src/ssa/validate.dart b/pkg/compiler/lib/src/ssa/validate.dart
index 31e9125..1f93b4e 100644
--- a/pkg/compiler/lib/src/ssa/validate.dart
+++ b/pkg/compiler/lib/src/ssa/validate.dart
@@ -132,7 +132,7 @@
     super.visitBasicBlock(block);
   }
 
-  /** Returns how often [instruction] is contained in [instructions]. */
+  /// Returns how often [instruction] is contained in [instructions].
   static int countInstruction(
       List<HInstruction> instructions, HInstruction instruction) {
     int result = 0;
@@ -142,11 +142,9 @@
     return result;
   }
 
-  /**
-   * Returns true if the predicate returns true for every instruction in the
-   * list. The argument to [f] is an instruction with the count of how often
-   * it appeared in the list [instructions].
-   */
+  /// Returns true if the predicate returns true for every instruction in the
+  /// list. The argument to [f] is an instruction with the count of how often
+  /// it appeared in the list [instructions].
   static bool everyInstruction(List<HInstruction> instructions, Function f) {
     var copy = new List<HInstruction>.from(instructions);
     // TODO(floitsch): there is currently no way to sort HInstructions before
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index acdfd27..a4bfd96 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -58,11 +58,9 @@
   }
 }
 
-/**
- * A [Value] represents both symbolic values like the value of a
- * parameter, or the length of an array, and concrete values, like
- * constants.
- */
+/// A [Value] represents both symbolic values like the value of a
+/// parameter, or the length of an array, and concrete values, like
+/// constants.
 abstract class Value {
   final ValueRangeInfo info;
   const Value(this.info);
@@ -97,10 +95,8 @@
   bool get isZero => false;
 }
 
-/**
- * The [MarkerValue] class is used to recognize ranges of loop
- * updates.
- */
+/// The [MarkerValue] class is used to recognize ranges of loop
+/// updates.
 class MarkerValue extends Value {
   /// If [positive] is true (respectively false), the marker goes
   /// to [MaxIntValue] (respectively [MinIntValue]) when being added
@@ -124,9 +120,7 @@
   }
 }
 
-/**
- * An [IntValue] contains a constant integer value.
- */
+/// An [IntValue] contains a constant integer value.
 class IntValue extends Value {
   final BigInt value;
 
@@ -192,10 +186,8 @@
   bool get isZero => value == BigInt.zero;
 }
 
-/**
- * The [MaxIntValue] represents the maximum value an integer can have,
- * which is currently +infinity.
- */
+/// The [MaxIntValue] represents the maximum value an integer can have,
+/// which is currently +infinity.
 class MaxIntValue extends Value {
   const MaxIntValue() : super(null);
   Value operator +(Value other) => this;
@@ -208,10 +200,8 @@
   bool get isPositive => true;
 }
 
-/**
- * The [MinIntValue] represents the minimum value an integer can have,
- * which is currently -infinity.
- */
+/// The [MinIntValue] represents the minimum value an integer can have,
+/// which is currently -infinity.
 class MinIntValue extends Value {
   const MinIntValue() : super(null);
   Value operator +(Value other) => this;
@@ -224,10 +214,8 @@
   bool get isPositive => false;
 }
 
-/**
- * The [UnknownValue] is the sentinel in our analysis to mark an
- * operation that could not be done because of too much complexity.
- */
+/// The [UnknownValue] is the sentinel in our analysis to mark an
+/// operation that could not be done because of too much complexity.
 class UnknownValue extends Value {
   const UnknownValue() : super(null);
   Value operator +(Value other) => const UnknownValue();
@@ -240,9 +228,7 @@
   String toString() => 'Unknown';
 }
 
-/**
- * A symbolic value representing an [HInstruction].
- */
+/// A symbolic value representing an [HInstruction].
 class InstructionValue extends Value {
   final HInstruction instruction;
   InstructionValue(this.instruction, info) : super(info);
@@ -293,18 +279,14 @@
   String toString() => 'Instruction: $instruction';
 }
 
-/**
- * Special value for instructions whose type is a positive integer.
- */
+/// Special value for instructions whose type is a positive integer.
 class PositiveValue extends InstructionValue {
   PositiveValue(HInstruction instruction, info) : super(instruction, info);
   bool get isPositive => true;
 }
 
-/**
- * Represents a binary operation on two [Value], where the operation
- * did not yield a canonical value.
- */
+/// Represents a binary operation on two [Value], where the operation
+/// did not yield a canonical value.
 class BinaryOperationValue extends Value {
   final Value left;
   final Value right;
@@ -457,11 +439,9 @@
   String toString() => '-$value';
 }
 
-/**
- * A [Range] represents the possible integer values an instruction
- * can have, from its [lower] bound to its [upper] bound, both
- * included.
- */
+/// A [Range] represents the possible integer values an instruction
+/// can have, from its [lower] bound to its [upper] bound, both
+/// included.
 class Range {
   final Value lower;
   final Value upper;
@@ -473,10 +453,8 @@
 
   Range.unbound(info) : this(const MinIntValue(), const MaxIntValue(), info);
 
-  /**
-   * Checks if the given values are unknown, and creates a
-   * range that does not have any unknown values.
-   */
+  /// Checks if the given values are unknown, and creates a
+  /// range that does not have any unknown values.
   Range.normalize(Value low, Value up, info)
       : this(low == const UnknownValue() ? const MinIntValue() : low,
             up == const UnknownValue() ? const MaxIntValue() : up, info);
@@ -579,25 +557,19 @@
   String toString() => '[$lower, $upper]';
 }
 
-/**
- * Visits the graph in dominator order, and computes value ranges for
- * integer instructions. While visiting the graph, this phase also
- * removes unnecessary bounds checks, and comparisons that are proven
- * to be true or false.
- */
+/// Visits the graph in dominator order, and computes value ranges for
+/// integer instructions. While visiting the graph, this phase also
+/// removes unnecessary bounds checks, and comparisons that are proven
+/// to be true or false.
 class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
   String get name => 'SSA value range builder';
 
-  /**
-   * List of [HRangeConversion] instructions created by the phase. We
-   * save them here in order to remove them once the phase is done.
-   */
+  /// List of [HRangeConversion] instructions created by the phase. We
+  /// save them here in order to remove them once the phase is done.
   final List<HRangeConversion> conversions = <HRangeConversion>[];
 
-  /**
-   * Value ranges for integer instructions. This map gets populated by
-   * the dominator tree visit.
-   */
+  /// Value ranges for integer instructions. This map gets populated by
+  /// the dominator tree visit.
   final Map<HInstruction, Range> ranges = new Map<HInstruction, Range>();
 
   final JClosedWorld closedWorld;
@@ -1088,9 +1060,7 @@
   }
 }
 
-/**
- * Tries to find a range for the update instruction of a loop phi.
- */
+/// Tries to find a range for the update instruction of a loop phi.
 class LoopUpdateRecognizer extends HBaseVisitor {
   final JClosedWorld closedWorld;
   final Map<HInstruction, Range> ranges;
diff --git a/pkg/compiler/lib/src/ssa/variable_allocator.dart b/pkg/compiler/lib/src/ssa/variable_allocator.dart
index 3bb3c85..6837537 100644
--- a/pkg/compiler/lib/src/ssa/variable_allocator.dart
+++ b/pkg/compiler/lib/src/ssa/variable_allocator.dart
@@ -6,9 +6,7 @@
 import '../js_backend/js_backend.dart';
 import 'nodes.dart';
 
-/**
- * The [LiveRange] class covers a range where an instruction is live.
- */
+/// The [LiveRange] class covers a range where an instruction is live.
 class LiveRange {
   final int start;
   // [end] is not final because it can be updated due to loops.
@@ -20,14 +18,10 @@
   String toString() => '[$start $end[';
 }
 
-/**
- * The [LiveInterval] class contains the list of ranges where an
- * instruction is live.
- */
+/// The [LiveInterval] class contains the list of ranges where an
+/// instruction is live.
 class LiveInterval {
-  /**
-   * The id where the instruction is defined.
-   */
+  /// The id where the instruction is defined.
   int start;
   final List<LiveRange> ranges;
   LiveInterval() : ranges = <LiveRange>[];
@@ -38,10 +32,8 @@
   LiveInterval.forCheck(this.start, LiveInterval checkedInterval)
       : ranges = checkedInterval.ranges;
 
-  /**
-   * Update all ranges that are contained in [from, to[ to
-   * die at [to].
-   */
+  /// Update all ranges that are contained in [from, to[ to
+  /// die at [to].
   void loopUpdate(int from, int to) {
     for (LiveRange range in ranges) {
       if (from <= range.start && range.end < to) {
@@ -50,16 +42,12 @@
     }
   }
 
-  /**
-   * Add a new range to this interval.
-   */
+  /// Add a new range to this interval.
   void add(LiveRange interval) {
     ranges.add(interval);
   }
 
-  /**
-   * Returns true if one of the ranges of this interval dies at [at].
-   */
+  /// Returns true if one of the ranges of this interval dies at [at].
   bool diesAt(int at) {
     for (LiveRange range in ranges) {
       if (range.end == at) return true;
@@ -74,53 +62,39 @@
   }
 }
 
-/**
- * The [LiveEnvironment] class contains the liveIn set of a basic
- * block. A liveIn set of a block contains the instructions that are
- * live when entering that block.
- */
+/// The [LiveEnvironment] class contains the liveIn set of a basic
+/// block. A liveIn set of a block contains the instructions that are
+/// live when entering that block.
 class LiveEnvironment {
-  /**
-   * The instruction id where the basic block starts. See
-   * [SsaLiveIntervalBuilder.instructionId].
-   */
+  /// The instruction id where the basic block starts. See
+  /// [SsaLiveIntervalBuilder.instructionId].
   int startId;
 
-  /**
-   * The instruction id where the basic block ends.
-   */
+  /// The instruction id where the basic block ends.
   final int endId;
 
-  /**
-   * Loop markers that will be updated once the loop header is
-   * visited. The liveIn set of the loop header will be merged into this
-   * environment. [loopMarkers] is a mapping from block header to the
-   * end instruction id of the loop exit block.
-   */
+  /// Loop markers that will be updated once the loop header is
+  /// visited. The liveIn set of the loop header will be merged into this
+  /// environment. [loopMarkers] is a mapping from block header to the
+  /// end instruction id of the loop exit block.
   final Map<HBasicBlock, int> loopMarkers;
 
-  /**
-   * The instructions that are live in this basic block. The values of
-   * the map contain the instruction ids where the instructions die.
-   * It will be used when adding a range to the live interval of an
-   * instruction.
-   */
+  /// The instructions that are live in this basic block. The values of
+  /// the map contain the instruction ids where the instructions die.
+  /// It will be used when adding a range to the live interval of an
+  /// instruction.
   final Map<HInstruction, int> liveInstructions;
 
-  /**
-   * Map containing the live intervals of instructions.
-   */
+  /// Map containing the live intervals of instructions.
   final Map<HInstruction, LiveInterval> liveIntervals;
 
   LiveEnvironment(this.liveIntervals, this.endId)
       : liveInstructions = new Map<HInstruction, int>(),
         loopMarkers = new Map<HBasicBlock, int>();
 
-  /**
-   * Remove an instruction from the liveIn set. This method also
-   * updates the live interval of [instruction] to contain the new
-   * range: [id, / id contained in [liveInstructions] /].
-   */
+  /// Remove an instruction from the liveIn set. This method also
+  /// updates the live interval of [instruction] to contain the new
+  /// range: [id, / id contained in [liveInstructions] /].
   void remove(HInstruction instruction, int id) {
     LiveInterval interval =
         liveIntervals.putIfAbsent(instruction, () => new LiveInterval());
@@ -132,20 +106,16 @@
     liveInstructions.remove(instruction);
   }
 
-  /**
-   * Add [instruction] to the liveIn set. If the instruction is not
-   * already in the set, we save the id where it dies.
-   */
+  /// Add [instruction] to the liveIn set. If the instruction is not
+  /// already in the set, we save the id where it dies.
   void add(HInstruction instruction, int userId) {
     // Note that we are visiting the graph in post-dominator order, so
     // the first time we see a variable is when it dies.
     liveInstructions.putIfAbsent(instruction, () => userId);
   }
 
-  /**
-   * Merge this environment with [other]. Update the end id of
-   * instructions in case they are different between this and [other].
-   */
+  /// Merge this environment with [other]. Update the end id of
+  /// instructions in case they are different between this and [other].
   void mergeWith(LiveEnvironment other) {
     other.liveInstructions.forEach((HInstruction instruction, int existingId) {
       // If both environments have the same instruction id of where
@@ -180,31 +150,23 @@
   String toString() => liveInstructions.toString();
 }
 
-/**
- * Builds the live intervals of each instruction. The algorithm visits
- * the graph post-dominator tree to find the last uses of an
- * instruction, and computes the liveIns of each basic block.
- */
+/// Builds the live intervals of each instruction. The algorithm visits
+/// the graph post-dominator tree to find the last uses of an
+/// instruction, and computes the liveIns of each basic block.
 class SsaLiveIntervalBuilder extends HBaseVisitor {
   final Set<HInstruction> generateAtUseSite;
   final Set<HInstruction> controlFlowOperators;
 
-  /**
-   * A counter to assign start and end ids to live ranges. The initial
-   * value is not relevant. Note that instructionId goes downward to ease
-   * reasoning about live ranges (the first instruction of a graph has
-   * the lowest id).
-   */
+  /// A counter to assign start and end ids to live ranges. The initial
+  /// value is not relevant. Note that instructionId goes downward to ease
+  /// reasoning about live ranges (the first instruction of a graph has
+  /// the lowest id).
   int instructionId = 0;
 
-  /**
-   * The liveIns of basic blocks.
-   */
+  /// The liveIns of basic blocks.
   final Map<HBasicBlock, LiveEnvironment> liveInstructions;
 
-  /**
-   * The live intervals of instructions.
-   */
+  /// The live intervals of instructions.
   final Map<HInstruction, LiveInterval> liveIntervals;
 
   SsaLiveIntervalBuilder(this.generateAtUseSite, this.controlFlowOperators)
@@ -384,11 +346,9 @@
   }
 }
 
-/**
- * Represents a copy from one instruction to another. The codegen
- * also uses this class to represent a copy from one variable to
- * another.
- */
+/// Represents a copy from one instruction to another. The codegen
+/// also uses this class to represent a copy from one variable to
+/// another.
 class Copy<T> {
   final T source;
   final T destination;
@@ -398,20 +358,14 @@
   String toString() => '$destination <- $source';
 }
 
-/**
- * A copy handler contains the copies that a basic block needs to do
- * after executing all its instructions.
- */
+/// A copy handler contains the copies that a basic block needs to do
+/// after executing all its instructions.
 class CopyHandler {
-  /**
-   * The copies from an instruction to a phi of the successor.
-   */
+  /// The copies from an instruction to a phi of the successor.
   final List<Copy<HInstruction>> copies;
 
-  /**
-   * Assignments from an instruction that does not need a name (e.g. a
-   * constant) to the phi of a successor.
-   */
+  /// Assignments from an instruction that does not need a name (e.g. a
+  /// constant) to the phi of a successor.
   final List<Copy<HInstruction>> assignments;
 
   CopyHandler()
@@ -431,21 +385,18 @@
   bool get isEmpty => copies.isEmpty && assignments.isEmpty;
 }
 
-/**
- * Contains the mapping between instructions and their names for code
- * generation, as well as the [CopyHandler] for each basic block.
- */
+/// Contains the mapping between instructions and their names for code
+/// generation, as well as the [CopyHandler] for each basic block.
 class VariableNames {
   final Map<HInstruction, String> ownName;
   final Map<HBasicBlock, CopyHandler> copyHandlers;
 
   // Used to control heuristic that determines how local variables are declared.
   final Set<String> allUsedNames;
-  /**
-   * Name that is used as a temporary to break cycles in
-   * parallel copies. We make sure this name is not being used
-   * anywhere by reserving it when we allocate names for instructions.
-   */
+
+  /// Name that is used as a temporary to break cycles in
+  /// parallel copies. We make sure this name is not being used
+  /// anywhere by reserving it when we allocate names for instructions.
   final String swapTemp;
 
   String getSwapTemp() {
@@ -488,9 +439,7 @@
   }
 }
 
-/**
- * Allocates variable names for instructions, making sure they don't collide.
- */
+/// Allocates variable names for instructions, making sure they don't collide.
 class VariableNamer {
   final VariableNames names;
   final Namer _namer;
@@ -586,9 +535,7 @@
     return name;
   }
 
-  /**
-   * Frees [instruction]'s name so it can be used for other instructions.
-   */
+  /// Frees [instruction]'s name so it can be used for other instructions.
   void freeName(HInstruction instruction) {
     String ownName = names.ownName[instruction];
     if (ownName != null) {
@@ -604,18 +551,16 @@
   }
 }
 
-/**
- * Visits all blocks in the graph, sets names to instructions, and
- * creates the [CopyHandler] for each block. This class needs to have
- * the liveIns set as well as all the live intervals of instructions.
- * It visits the graph in dominator order, so that at each entry of a
- * block, the instructions in its liveIns set have names.
- *
- * When visiting a block, it goes through all instructions. For each
- * instruction, it frees the names of the inputs that die at that
- * instruction, and allocates a name to the instruction. For each phi,
- * it adds a copy to the CopyHandler of the corresponding predecessor.
- */
+/// Visits all blocks in the graph, sets names to instructions, and
+/// creates the [CopyHandler] for each block. This class needs to have
+/// the liveIns set as well as all the live intervals of instructions.
+/// It visits the graph in dominator order, so that at each entry of a
+/// block, the instructions in its liveIns set have names.
+///
+/// When visiting a block, it goes through all instructions. For each
+/// instruction, it frees the names of the inputs that die at that
+/// instruction, and allocates a name to the instruction. For each phi,
+/// it adds a copy to the CopyHandler of the corresponding predecessor.
 class SsaVariableAllocator extends HBaseVisitor {
   final Namer _namer;
   final Map<HBasicBlock, LiveEnvironment> liveInstructions;
@@ -645,10 +590,8 @@
     });
   }
 
-  /**
-   * Returns whether [instruction] needs a name. Instructions that
-   * have no users or that are generated at use site do not need a name.
-   */
+  /// Returns whether [instruction] needs a name. Instructions that
+  /// have no users or that are generated at use site do not need a name.
   bool needsName(instruction) {
     if (instruction is HThis) return false;
     if (instruction is HParameterValue) return true;
@@ -657,9 +600,7 @@
     return !instruction.nonCheck().isCodeMotionInvariant();
   }
 
-  /**
-   * Returns whether [instruction] dies at the instruction [at].
-   */
+  /// Returns whether [instruction] dies at the instruction [at].
   bool diesAt(HInstruction instruction, HInstruction at) {
     LiveInterval atInterval = liveIntervals[at];
     LiveInterval instructionInterval = liveIntervals[instruction];
diff --git a/pkg/compiler/lib/src/tracer.dart b/pkg/compiler/lib/src/tracer.dart
index 9a8f51c..f4e7870 100644
--- a/pkg/compiler/lib/src/tracer.dart
+++ b/pkg/compiler/lib/src/tracer.dart
@@ -11,10 +11,8 @@
 import 'util/util.dart' show Indentation;
 import 'world.dart' show JClosedWorld;
 
-/**
- * If non-null, we only trace methods whose name match the regexp defined by the
- * given pattern.
- */
+/// If non-null, we only trace methods whose name match the regexp defined by
+/// the given pattern.
 String get TRACE_FILTER_PATTERN =>
     TRACE_FILTER_PATTERN_FROM_ENVIRONMENT ?? TRACE_FILTER_PATTERN_FOR_TEST;
 
@@ -22,10 +20,8 @@
     const String.fromEnvironment("DUMP_IR");
 String TRACE_FILTER_PATTERN_FOR_TEST;
 
-/**
- * Dumps the intermediate representation after each phase in a format
- * readable by IR Hydra.
- */
+/// Dumps the intermediate representation after each phase in a format
+/// readable by IR Hydra.
 class Tracer extends TracerUtil {
   final JClosedWorld closedWorld;
   final Namer namer;
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
index 181714f..e5707ad 100644
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart
@@ -150,8 +150,8 @@
 }
 
 class ClassHierarchyImpl implements ClassHierarchy {
-  /// Tag used for identifying serialized [ClassHierarchy] objects in a debugging
-  /// data stream.
+  /// Tag used for identifying serialized [ClassHierarchy] objects in a
+  /// debugging data stream.
   static const String tag = 'class-hierarchy';
 
   final CommonElements _commonElements;
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index 395639e..2c9980d 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -138,11 +138,9 @@
   /// Invariant: Elements are declaration elements.
   final Set<FieldEntity> allReferencedStaticFields = new Set<FieldEntity>();
 
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: Elements are declaration elements.
-   */
+  /// Documentation wanted -- johnniwinther
+  ///
+  /// Invariant: Elements are declaration elements.
   final Set<FunctionEntity> staticFunctionsNeedingGetter =
       new Set<FunctionEntity>();
   final Set<FunctionEntity> methodsNeedingSuperGetter =
diff --git a/pkg/compiler/lib/src/universe/feature.dart b/pkg/compiler/lib/src/universe/feature.dart
index f854843..1367e6d 100644
--- a/pkg/compiler/lib/src/universe/feature.dart
+++ b/pkg/compiler/lib/src/universe/feature.dart
@@ -9,6 +9,7 @@
 library compiler.universe.feature;
 
 import '../elements/types.dart';
+import '../ir/runtime_type_analysis.dart';
 import '../util/util.dart';
 
 /// A language feature that may be seen in the program.
@@ -148,21 +149,6 @@
   }
 }
 
-/// Enum for recognized use kinds of `Object.runtimeType`.
-enum RuntimeTypeUseKind {
-  /// Unknown use of `Object.runtimeType`. This is the fallback value if the
-  /// usage didn't match any of the recogized patterns.
-  unknown,
-
-  /// `Object.runtimeType` used in a pattern like
-  /// `a.runtimeType == b.runtimeType`.
-  equals,
-
-  /// `Object.runtimeType` used in a pattern like `'${e.runtimeType}'` or
-  /// `e.runtimeType.toString()`.
-  string,
-}
-
 /// A use of `Object.runtimeType`.
 class RuntimeTypeUse {
   /// The use kind of `Object.runtimeType`.
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index 6119207..fee6d25 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -311,11 +311,9 @@
   /// Invariant: Elements are declaration elements.
   final Set<FieldEntity> allReferencedStaticFields = new Set<FieldEntity>();
 
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: Elements are declaration elements.
-   */
+  /// Documentation wanted -- johnniwinther
+  ///
+  /// Invariant: Elements are declaration elements.
   final Set<FunctionEntity> methodsNeedingSuperGetter =
       new Set<FunctionEntity>();
   final Map<String, Map<Selector, SelectorConstraints>> _invokedNames =
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 47f974e..0696300 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -233,9 +233,7 @@
   bool get isOperator => kind == SelectorKind.OPERATOR;
   bool get isUnaryOperator => isOperator && argumentCount == 0;
 
-  /**
-   * The member name for invocation mirrors created from this selector.
-   */
+  /// The member name for invocation mirrors created from this selector.
   String get invocationMirrorMemberName => isSetter ? '$name=' : name;
 
   int get invocationMirrorKind {
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 1336828..9ba793f 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -33,8 +33,8 @@
 }
 
 /// The use of a dynamic property. [selector] defined the name and kind of the
-/// property and [receiverConstraint] defines the known constraint for the object on which
-/// the property is accessed.
+/// property and [receiverConstraint] defines the known constraint for the
+/// object on which the property is accessed.
 class DynamicUse {
   final Selector selector;
 
@@ -47,9 +47,9 @@
       var constraint = receiverConstraint;
       if (constraint is StrongModeConstraint) {
         if (constraint.isThis) {
-          sb.write('<');
+          sb.write('this:');
         } else if (constraint.isExact) {
-          sb.write('=');
+          sb.write('exact:');
         }
         sb.write(constraint.cls.name);
       } else {
diff --git a/pkg/compiler/lib/src/util/features.dart b/pkg/compiler/lib/src/util/features.dart
index 57aeba2..5263b40 100644
--- a/pkg/compiler/lib/src/util/features.dart
+++ b/pkg/compiler/lib/src/util/features.dart
@@ -25,9 +25,13 @@
     _features[key] = value;
   }
 
-  String operator [](String key) => _features[key];
+  Object operator [](String key) => _features[key];
 
-  String remove(String key) => _features.remove(key);
+  Object remove(String key) => _features.remove(key);
+
+  bool get isEmpty => _features.isEmpty;
+
+  bool get isNotEmpty => _features.isNotEmpty;
 
   void forEach(void Function(String, Object) f) {
     _features.forEach(f);
diff --git a/pkg/compiler/lib/src/util/indentation.dart b/pkg/compiler/lib/src/util/indentation.dart
index 9709f78..fb7cc21 100644
--- a/pkg/compiler/lib/src/util/indentation.dart
+++ b/pkg/compiler/lib/src/util/indentation.dart
@@ -69,9 +69,7 @@
     return tag;
   }
 
-  /**
-   * Adds given string to result string.
-   */
+  /// Adds given string to result string.
   void add(String string) {
     sb.write(string);
   }
@@ -79,12 +77,10 @@
   /// Adds default parameters for [node] into [params].
   void addDefaultParameters(N node, Map params) {}
 
-  /**
-   * Adds given node type to result string.
-   * The method "opens" the node, meaning that all output after calling
-   * this method and before calling closeNode() will represent contents
-   * of given node.
-   */
+  /// Adds given node type to result string.
+  /// The method "opens" the node, meaning that all output after calling
+  /// this method and before calling closeNode() will represent contents
+  /// of given node.
   void openNode(N node, String type, [Map params]) {
     if (params == null) params = new Map();
     addCurrentIndent();
@@ -95,9 +91,7 @@
     pushTag(type);
   }
 
-  /**
-   * Adds given node to result string.
-   */
+  /// Adds given node to result string.
   void openAndCloseNode(N node, String type, [Map params]) {
     if (params == null) params = {};
     addCurrentIndent();
@@ -107,9 +101,7 @@
     sb.write("/>\n");
   }
 
-  /**
-   * Closes current node type.
-   */
+  /// Closes current node type.
   void closeNode() {
     String tag = popTag();
     addCurrentIndent();
diff --git a/pkg/compiler/lib/src/util/util.dart b/pkg/compiler/lib/src/util/util.dart
index 297efca..785253d 100644
--- a/pkg/compiler/lib/src/util/util.dart
+++ b/pkg/compiler/lib/src/util/util.dart
@@ -114,10 +114,8 @@
   return a.length == b.length && a.containsAll(b) && b.containsAll(a);
 }
 
-/**
- * File name prefix used to shorten the file name in stack traces printed by
- * [trace].
- */
+/// File name prefix used to shorten the file name in stack traces printed by
+/// [trace].
 String stackTraceFilePrefix = null;
 
 /// Writes the characters of [string] on [buffer].  The characters
diff --git a/pkg/compiler/tool/status_files/update_all.dart b/pkg/compiler/tool/status_files/update_all.dart
index cc05227..bf09b28 100644
--- a/pkg/compiler/tool/status_files/update_all.dart
+++ b/pkg/compiler/tool/status_files/update_all.dart
@@ -110,8 +110,8 @@
   }
 
   print('build create_sdk');
-  ProcessResult result = Process
-      .runSync(python, ['./tools/build.py', '-m', 'release', 'create_sdk']);
+  ProcessResult result = Process.runSync(
+      python, ['./tools/build.py', '-m', 'release', 'create_sdk']);
   if (result.exitCode != 0) {
     print(result.stdout);
     print(result.stderr);
diff --git a/pkg/compiler/tool/track_memory.dart b/pkg/compiler/tool/track_memory.dart
index f6ef38d..c5c2d03 100644
--- a/pkg/compiler/tool/track_memory.dart
+++ b/pkg/compiler/tool/track_memory.dart
@@ -172,9 +172,9 @@
   if (now < 1024) {
     string = ' ${now}b';
   } else if (now < mega) {
-    string = ' ${(now/1024).toStringAsFixed(0)}K';
+    string = ' ${(now / 1024).toStringAsFixed(0)}K';
   } else {
-    string = ' ${(now/mega).toStringAsFixed(1)}M';
+    string = ' ${(now / mega).toStringAsFixed(1)}M';
   }
   if (string.length < 10) string = '${' ' * (8 - string.length)}$string';
   sb.write(string);
diff --git a/pkg/dartfix/README.md b/pkg/dartfix/README.md
index 3b4ef5b..45f61cb 100644
--- a/pkg/dartfix/README.md
+++ b/pkg/dartfix/README.md
@@ -1,28 +1,92 @@
-# dartfix
+The `dartfix` tool is a command-line interface
+for making automated updates to your Dart code.
+The tool isn't in the Dart SDK;
+instead, it's distributed in the [`dartfix` package.][dartfix]
 
-dartfix is a tool for migrating Dart source to newer versions of the Dart SDK,
-and fixing common issues including:
-
-* Converting classes used as mixins to use the
-  [new mixin syntax](https://github.com/dart-lang/language/issues/7)
-* Converting [double literals to int literals](https://github.com/dart-lang/language/issues/4)
-  where applicable
-* Moving named constructor type arguments from the name to the type
 
 ## Usage
 
-To activate the package
-```
-  pub global activate dartfix
+> **Important:**
+> Save a copy of your source code before making changes with `dartfix`.
+> Unlike [dartfmt][], which makes only safe changes (usually to whitespace),
+> `dartfix` can make changes that you might need to undo or modify.
+
+Before you can use the `dartfix` tool, you need to
+[install it](#installing-and-updating-dartfix), as described below.
+Then invoke it with the name of the directory that you want to update.
+When you're ready to make the suggested changes,
+add the `--overwrite` option.
+
+```terminal
+$ dartfix examples/misc
+... summary of recommended changes ...
+$ dartfix examples/misc --overwrite
 ```
 
-Once activated, dart fix can be run using
+## Features
+
+As of release 0.1.3, `dartfix` can make the following changes to your code:
+
+* Convert code to use the following [features added to Dart in 2.1][]:
+  * Find classes used as mixins, and convert them to use the `mixin` keyword
+    instead of `class`.
+  * Find `double` literals that end in `.0`, and remove the `.0`.
+* Move named constructor type arguments from the name to the type. <br>
+  For example, given `class A<T> { A.from(Object obj) { } }`,
+  `dartfix` changes constructor invocations in the following way:
+
+  ```
+  Original code:
+  A.from<String>(anObject) // Invokes the `A.from` named constructor.
+
+  Code produced by dartfix:
+  A<String>.from(anObject) // Same, but the type is directly after `A`.
+  ```
+
+## Installing and updating dartfix
+
+The easiest way to use `dartfix` is to [globally install][] it,
+so that it can be [in your path][PATH]:
+
+```terminal
+$ pub global activate dartfix
 ```
-  pub global run dartfix:fix <target directory>
-```
-or if you have
-[setup your path](https://www.dartlang.org/tools/pub/cmd/pub-global#running-a-script-from-your-path)
-to include the pub bin directory, then simply
-```
-  dartfix <target directory>
-```
+
+Use the same command to update `dartfix`.
+We recommend updating `dartfix` whenever you update your Dart SDK
+or when a new feature is released.
+
+## Options
+
+<dl>
+  <dt><code>--[no-]color</code></dt>
+  <dd> Use colors when printing messages. On by default. </dd>
+
+  <dt><code>-f, --force</code></dt>
+  <dd>Apply the recommended changes even if the input code has errors.
+  </dd>
+
+  <dt><code>-h, --help</code></dt>
+  <dd>See a complete list of `dartfix` options.</dd>
+
+  <dt><code>-v, --verbose</code></dt>
+  <dd>Verbose output.</dd>
+
+  <dt><code>-w, --overwrite</code></dt>
+  <dd>Apply the recommended changes.</dd>
+</dl>
+
+
+## Filing issues
+
+If you want a new fix, first look at [dartfix issues][]
+and star the fixes you want.
+If no issue exists for the fix, [create a GitHub issue.][new issue]
+
+[dartfix]: https://pub.dartlang.org/packages/dartfix
+[dartfmt]: https://www.dartlang.org/tools/dartfmt
+[features added to Dart in 2.1]: https://github.com/dart-lang/sdk/blob/master/CHANGELOG.md#210---2018-11-15
+[globally install]: https://www.dartlang.org/tools/pub/cmd/pub-global
+[new issue]: https://github.com/dart-lang/sdk/issues/new?title=dartfix%20request%3A%20%3CSUMMARIZE%20REQUEST%20HERE%3E
+[dartfix issues]: https://github.com/dart-lang/sdk/issues?q=is%3Aissue+is%3Aopen+label%3Aanalyzer-dartfix
+[PATH]: https://www.dartlang.org/tools/pub/cmd/pub-global#running-a-script-from-your-path
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 6edbe05..d8063b5 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -74,7 +74,7 @@
   final Dart2TypeSystem rules;
 
   /// Errors that were produced during compilation, if any.
-  final List<AnalysisError> errors;
+  final ErrorCollector errors;
 
   JSTypeRep jsTypeRep;
 
@@ -5681,8 +5681,10 @@
       var nearest = (lexeme.startsWith("0x") || lexeme.startsWith("0X"))
           ? '0x${valueInJS.toRadixString(16)}'
           : '$valueInJS';
-      errors.add(AnalysisError(_currentCompilationUnit.source, node.offset,
-          node.length, invalidJSInteger, [lexeme, nearest]));
+      errors.add(
+          _currentCompilationUnit.lineInfo,
+          AnalysisError(_currentCompilationUnit.source, node.offset,
+              node.length, invalidJSInteger, [lexeme, nearest]));
     }
     return JS.LiteralNumber('$valueInJS');
   }
diff --git a/pkg/dev_compiler/lib/src/analyzer/driver.dart b/pkg/dev_compiler/lib/src/analyzer/driver.dart
index aa5d565..cec419b 100644
--- a/pkg/dev_compiler/lib/src/analyzer/driver.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/driver.dart
@@ -9,14 +9,15 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
-import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart' show AnalysisDriver;
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
+import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -241,16 +242,13 @@
     var bundle = PackageBundle.fromBuffer(summaryBytes);
 
     /// Create an analysis context to contain the state for this build unit.
-    var context =
-        AnalysisEngine.instance.createAnalysisContext() as AnalysisContextImpl;
-    context.sourceFactory = sourceFactory;
+    var context = RestrictedAnalysisContext(
+        analysisOptions, declaredVariables, sourceFactory);
     var resultProvider = InputPackagesResultProvider(
         context,
         SummaryDataStore([])
           ..addStore(summaryData)
           ..addBundle(null, bundle));
-    context.resultProvider = resultProvider;
-    context.contentCache = _ContentCacheWrapper(fsState);
 
     var resynthesizer = resultProvider.resynthesizer;
     _extensionTypes ??= ExtensionTypeSet(context.typeProvider, resynthesizer);
@@ -315,10 +313,7 @@
       this._fsState,
       this._resourceProvider);
 
-  AnalysisContextImpl get context => resynthesizer.context;
-
-  /// Clean up any state used by this driver.
-  void dispose() => context.dispose();
+  TypeProvider get typeProvider => resynthesizer.typeProvider;
 
   /// True if [uri] refers to a Dart library (i.e. a Dart source file exists
   /// with this uri, and it is not a part file).
@@ -339,9 +334,9 @@
         declaredVariables,
         resynthesizer.sourceFactory,
         (uri) => _isLibraryUri('$uri'),
-        context,
+        resynthesizer.context,
         resynthesizer,
-        InheritanceManager2(context.typeSystem),
+        InheritanceManager2(resynthesizer.typeSystem),
         libraryFile,
         _resourceProvider);
     // TODO(jmesserly): ideally we'd use the existing public `analyze()` method,
@@ -360,51 +355,3 @@
     return resynthesizer.getLibraryElement(uri);
   }
 }
-
-/// [ContentCache] wrapper around [FileSystemState].
-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) {
-    if (source.isInSystemLibrary) {
-      return true;
-    }
-    String uriStr = source.uri.toString();
-    if (fsState.externalSummaries != null &&
-        fsState.externalSummaries.hasUnlinkedUnit(uriStr)) {
-      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 fsState.getFileForPath(path);
-  }
-}
diff --git a/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart b/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart
index 0943c39..1528546 100644
--- a/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart
@@ -2,33 +2,87 @@
 // for 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/error/error.dart';
 import 'package:analyzer/source/error_processor.dart' show ErrorProcessor;
+import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptions;
 import 'package:path/path.dart' as path;
 
-/// Sorts and formats errors, returning the error messages.
-List<String> formatErrors(AnalysisContext context, List<AnalysisError> errors) {
-  sortErrors(context, errors);
-  var result = <String>[];
-  for (var e in errors) {
-    var m = formatError(context, e);
-    if (m != null) result.add(m);
-  }
-  return result;
-}
+class ErrorCollector {
+  final bool _replCompile;
+  final AnalysisOptions _options;
+  SplayTreeMap<AnalysisError, String> _errors;
 
-// TODO(jmesserly): this code was taken from analyzer_cli.
-// It really should be in some common place so we can share it.
-// TODO(jmesserly): this shouldn't depend on `context` but we need it to compute
-// `errorSeverity` due to some APIs that need fixing.
-void sortErrors(AnalysisContext context, List<AnalysisError> errors) {
-  errors.sort((AnalysisError error1, AnalysisError error2) {
+  ErrorCollector(this._options, this._replCompile) {
+    _errors = SplayTreeMap<AnalysisError, String>(_compareErrors);
+  }
+
+  bool get hasFatalErrors => _errors.keys.any(_isFatalError);
+
+  Iterable<String> get formattedErrors => _errors.values;
+
+  void add(LineInfo lineInfo, AnalysisError error) {
+    if (_shouldIgnoreError(error)) return;
+
+    // Skip hints, some like TODOs are not useful.
+    if (_errorSeverity(error).ordinal <= ErrorSeverity.INFO.ordinal) return;
+
+    _errors[error] = _formatError(lineInfo, error);
+  }
+
+  void addAll(LineInfo lineInfo, Iterable<AnalysisError> errors) {
+    for (var e in errors) add(lineInfo, e);
+  }
+
+  ErrorSeverity _errorSeverity(AnalysisError error) {
+    var errorCode = error.errorCode;
+    if (errorCode == StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK ||
+        errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_GETTER ||
+        errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_METHOD) {
+      // These are normally hints, but they should be errors when running DDC, so
+      // that users won't be surprised by behavioral differences between DDC and
+      // dart2js.
+      return ErrorSeverity.ERROR;
+    }
+
+    // TODO(jmesserly): remove support for customizing error levels via
+    // analysis_options from DDC. (it won't work with --kernel).
+    return ErrorProcessor.getProcessor(_options, error)?.severity ??
+        errorCode.errorSeverity;
+  }
+
+  String _formatError(LineInfo lineInfo, AnalysisError error) {
+    var location = lineInfo.getLocation(error.offset);
+
+    // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
+    return (StringBuffer()
+          ..write('[${_errorSeverity(error).displayName}] ')
+          ..write(error.message)
+          ..write(' (${path.prettyUri(error.source.uri)}')
+          ..write(
+              ', line ${location.lineNumber}, col ${location.columnNumber})'))
+        .toString();
+  }
+
+  bool _shouldIgnoreError(AnalysisError error) {
+    var uri = error.source.uri;
+    if (uri.scheme != 'dart') return false;
+    var sdkLib = uri.pathSegments[0];
+    if (sdkLib == 'html' || sdkLib == 'svg' || sdkLib == '_interceptors') {
+      var c = error.errorCode;
+      return c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
+          c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
+          c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS;
+    }
+    return false;
+  }
+
+  int _compareErrors(AnalysisError error1, AnalysisError error2) {
     // severity
-    var severity1 = errorSeverity(context, error1);
-    var severity2 = errorSeverity(context, error2);
-    int compare = severity2.compareTo(severity1);
+    int compare = _errorSeverity(error2).compareTo(_errorSeverity(error1));
     if (compare != 0) return compare;
 
     // path
@@ -42,64 +96,22 @@
 
     // compare message, in worst case.
     return error1.message.compareTo(error2.message);
-  });
-}
-
-// TODO(jmesserly): this was from analyzer_cli, we should factor it differently.
-String formatError(AnalysisContext context, AnalysisError error) {
-  var severity = errorSeverity(context, error);
-  // Skip hints, some like TODOs are not useful.
-  if (severity.ordinal <= ErrorSeverity.INFO.ordinal) return null;
-
-  var lineInfo = context.computeLineInfo(error.source);
-  var location = lineInfo.getLocation(error.offset);
-
-  // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
-  return (StringBuffer()
-        ..write('[${severity.displayName}] ')
-        ..write(error.message)
-        ..write(' (${path.prettyUri(error.source.uri)}')
-        ..write(', line ${location.lineNumber}, col ${location.columnNumber})'))
-      .toString();
-}
-
-ErrorSeverity errorSeverity(AnalysisContext context, AnalysisError error) {
-  var errorCode = error.errorCode;
-  if (errorCode == StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK ||
-      errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_GETTER ||
-      errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_METHOD) {
-    // These are normally hints, but they should be errors when running DDC, so
-    // that users won't be surprised by behavioral differences between DDC and
-    // dart2js.
-    return ErrorSeverity.ERROR;
   }
 
-  // TODO(jmesserly): this Analyzer API totally bonkers, but it's what
-  // analyzer_cli and server use.
-  //
-  // Among the issues with ErrorProcessor.getProcessor:
-  // * it needs to be called per-error, so it's a performance trap.
-  // * it can return null
-  // * using AnalysisError directly is now suspect, it's a correctness trap
-  // * it requires an AnalysisContext
-  return ErrorProcessor.getProcessor(context.analysisOptions, error)
-          ?.severity ??
-      errorCode.errorSeverity;
-}
+  bool _isFatalError(AnalysisError e) {
+    if (_errorSeverity(e) != ErrorSeverity.ERROR) return false;
 
-bool isFatalError(AnalysisContext context, AnalysisError e, bool replCompile) {
-  if (errorSeverity(context, e) != ErrorSeverity.ERROR) return false;
-
-  // These errors are not fatal in the REPL compile mode as we
-  // allow access to private members across library boundaries
-  // and those accesses will show up as undefined members unless
-  // additional analyzer changes are made to support them.
-  // TODO(jacobr): consider checking that the identifier name
-  // referenced by the error is private.
-  return !replCompile ||
-      (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
-          e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
-          e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
+    // These errors are not fatal in the REPL compile mode as we
+    // allow access to private members across library boundaries
+    // and those accesses will show up as undefined members unless
+    // additional analyzer changes are made to support them.
+    // TODO(jacobr): consider checking that the identifier name
+    // referenced by the error is private.
+    return !_replCompile ||
+        (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
+            e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
+            e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
+  }
 }
 
 const invalidImportDartMirrors = StrongModeCode(
diff --git a/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart b/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
index 120f7dc..851d47b 100644
--- a/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
@@ -18,7 +18,7 @@
   final ClassElement _jsString;
 
   JSTypeRep(this.rules, LinkedAnalysisDriver driver)
-      : types = driver.context.typeProvider,
+      : types = driver.typeProvider,
         _jsBool = driver.getClass('dart:_interceptors', 'JSBool'),
         _jsString = driver.getClass('dart:_interceptors', 'JSString'),
         _jsNumber = driver.getClass('dart:_interceptors', 'JSNumber');
diff --git a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
index f62c54c..179dbb1 100644
--- a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
@@ -10,7 +10,6 @@
     show LibraryElement, UriReferencedElement;
 import 'package:analyzer/error/error.dart';
 
-import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:args/args.dart' show ArgParser, ArgResults;
 import 'package:path/path.dart' as path;
@@ -57,7 +56,6 @@
     AnalyzerOptions analyzerOptions,
     CompilerOptions options) {
   var trees = <CompilationUnit>[];
-  var errors = <AnalysisError>[];
 
   var explicitSources = <Uri>[];
   var compilingSdk = false;
@@ -70,7 +68,17 @@
   }
   var driver = compilerDriver.linkLibraries(explicitSources, analyzerOptions);
 
+  var errors = ErrorCollector(driver.analysisOptions, options.replCompile);
   for (var libraryUri in driver.libraryUris) {
+    var analysisResults = driver.analyzeLibrary(libraryUri);
+
+    CompilationUnit definingUnit;
+    for (var result in analysisResults.values) {
+      if (result.file.uriStr == libraryUri) definingUnit = result.unit;
+      errors.addAll(result.unit.lineInfo, result.errors);
+      trees.add(result.unit);
+    }
+
     var library = driver.getLibrary(libraryUri);
 
     // TODO(jmesserly): remove "dart:mirrors" from DDC's SDK, and then remove
@@ -78,29 +86,19 @@
     if (!compilingSdk && !options.emitMetadata) {
       var node = _getDartMirrorsImport(library);
       if (node != null) {
-        errors.add(AnalysisError(library.source, node.uriOffset, node.uriEnd,
-            invalidImportDartMirrors));
+        errors.add(
+            definingUnit.lineInfo,
+            AnalysisError(library.source, node.uriOffset, node.uriEnd,
+                invalidImportDartMirrors));
       }
     }
-
-    var analysisResults = driver.analyzeLibrary(libraryUri);
-    for (var result in analysisResults.values) {
-      errors.addAll(_filterJsErrors(libraryUri, result.errors));
-      trees.add(result.unit);
-    }
-  }
-
-  var context = driver.context;
-
-  bool anyFatalErrors() {
-    return errors.any((e) => isFatalError(context, e, options.replCompile));
   }
 
   JS.Program jsProgram;
-  if (options.unsafeForceCompile || !anyFatalErrors()) {
+  if (options.unsafeForceCompile || !errors.hasFatalErrors) {
     var codeGenerator = CodeGenerator(
         driver,
-        driver.context.typeProvider,
+        driver.typeProvider,
         compilerDriver.summaryData,
         options,
         compilerDriver.extensionTypes,
@@ -110,37 +108,19 @@
     } catch (e) {
       // If force compilation failed, suppress the exception and report the
       // static errors instead. Otherwise, rethrow an internal compiler error.
-      if (!anyFatalErrors()) rethrow;
+      if (!errors.hasFatalErrors) rethrow;
     }
 
-    if (!options.unsafeForceCompile && anyFatalErrors()) {
+    if (!options.unsafeForceCompile && errors.hasFatalErrors) {
       jsProgram = null;
     }
   }
 
   var jsModule = JSModuleFile(
-      formatErrors(context, errors), options, jsProgram, driver.summaryBytes);
-  driver.dispose();
+      errors.formattedErrors.toList(), options, jsProgram, driver.summaryBytes);
   return jsModule;
 }
 
-Iterable<AnalysisError> _filterJsErrors(
-    String libraryUriStr, Iterable<AnalysisError> errors) {
-  if (libraryUriStr == 'dart:html' ||
-      libraryUriStr == 'dart:svg' ||
-      libraryUriStr == 'dart:_interceptors') {
-    return errors.where((error) {
-      return error.errorCode !=
-              StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 &&
-          error.errorCode !=
-              StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 &&
-          error.errorCode !=
-              StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS;
-    });
-  }
-  return errors;
-}
-
 UriReferencedElement _getDartMirrorsImport(LibraryElement library) {
   return library.imports.firstWhere(_isDartMirrorsImort, orElse: () => null) ??
       library.exports.firstWhere(_isDartMirrorsImort, orElse: () => null);
diff --git a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
index 503c60f..5c91caa 100644
--- a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
+++ b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
@@ -883,8 +883,7 @@
     summaryData.addBundle(null, sdkSummaryBundle);
   }
 
-  // TODO(jmesserly): can we avoid creating an analysis context entirely?
-  // It doesn't look like StoreBasedSummaryResynthesizer uses much of it.
+  // TODO(jmesserly): use RestrictedAnalysisContext.
   var context = a.AnalysisEngine.instance.createAnalysisContext()
       as a.AnalysisContextImpl;
   context.sourceFactory = a.SourceFactory(
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 6a31922..035611f 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -116,6 +116,8 @@
 
   final TypeEnvironment types;
 
+  final ClassHierarchy hierarchy;
+
   /// Information about virtual and overridden fields/getters/setters in the
   /// class we're currently compiling, or `null` if we aren't compiling a class.
   ClassPropertyModel _classProperties;
@@ -202,9 +204,9 @@
     var types = TypeSchemaEnvironment(coreTypes, hierarchy);
     var constants = DevCompilerConstants(types, declaredVariables);
     var nativeTypes = NativeTypeSet(coreTypes, constants);
-    var jsTypeRep = JSTypeRep(types);
+    var jsTypeRep = JSTypeRep(types, hierarchy);
     return ProgramCompiler._(coreTypes, coreTypes.index, nativeTypes, constants,
-        types, jsTypeRep, NullableInference(jsTypeRep), options);
+        types, hierarchy, jsTypeRep, NullableInference(jsTypeRep), options);
   }
 
   ProgramCompiler._(
@@ -213,6 +215,7 @@
       this._extensionTypes,
       this._constants,
       this.types,
+      this.hierarchy,
       this._typeRep,
       this._nullableInference,
       this.options)
@@ -230,8 +233,6 @@
         syncIterableClass = sdk.getClass('dart:_js_helper', 'SyncIterable'),
         asyncStarImplClass = sdk.getClass('dart:async', '_AsyncStarImpl');
 
-  ClassHierarchy get hierarchy => types.hierarchy;
-
   Uri get currentLibraryUri => _currentLibrary.importUri;
 
   bool get emitMetadata => options.emitMetadata;
@@ -5118,6 +5119,14 @@
   visitTypeLiteralConstant(node) => defaultConstant(node);
   @override
   visitPartialInstantiationConstant(node) => defaultConstant(node);
+  @override
+  visitEnvironmentBoolConstant(node) => defaultConstant(node);
+  @override
+  visitEnvironmentIntConstant(node) => defaultConstant(node);
+  @override
+  visitEnvironmentStringConstant(node) => defaultConstant(node);
+  @override
+  visitUnevaluatedConstant(node) => defaultConstant(node);
 }
 
 bool isSdkInternalRuntime(Library l) =>
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 52329f7..b05b840 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -187,8 +187,7 @@
       {bool enableAsserts: false})
       : unavailableConstant = InstanceConstant(null, [], {}),
         super(_ConstantsBackend(types.coreTypes), types, types.coreTypes,
-            enableAsserts,
-            errorReporter: const _ErrorReporter()) {
+            enableAsserts, const _ErrorReporter()) {
     env = EvaluationEnvironment();
   }
 
@@ -311,7 +310,7 @@
   lowerListConstant(constant) => constant;
 }
 
-class _ErrorReporter extends ErrorReporterBase {
+class _ErrorReporter extends SimpleErrorReporter {
   const _ErrorReporter();
 
   @override
diff --git a/pkg/dev_compiler/lib/src/kernel/js_typerep.dart b/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
index b43b1b0..7c4cba7 100644
--- a/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
+++ b/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
 import 'package:kernel/type_environment.dart';
@@ -9,13 +10,14 @@
 
 class JSTypeRep extends SharedJSTypeRep<DartType> {
   final TypeEnvironment types;
+  final ClassHierarchy hierarchy;
   final CoreTypes coreTypes;
 
   final Class _jsBool;
   final Class _jsNumber;
   final Class _jsString;
 
-  JSTypeRep(this.types)
+  JSTypeRep(this.types, this.hierarchy)
       : coreTypes = types.coreTypes,
         _jsBool =
             types.coreTypes.index.getClass('dart:_interceptors', 'JSBool'),
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index 8e212cf..76b6570 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -146,7 +146,8 @@
       // This allows us to find the `@notNull` annotation if it exists.
       var implClass = jsTypeRep.getImplementationClass(targetClass.rawType);
       if (implClass != null) {
-        var member = types.hierarchy.getDispatchTarget(implClass, target.name);
+        var member =
+            jsTypeRep.hierarchy.getDispatchTarget(implClass, target.name);
         if (member != null) target = member;
       }
     }
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index 73981f7..e7cb728 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -487,8 +487,10 @@
 
   @override
   visitComponent(Component node) {
+    var hierarchy = ClassHierarchy(node);
     inference ??= NullableInference(JSTypeRep(
-      fe.TypeSchemaEnvironment(CoreTypes(node), ClassHierarchy(node)),
+      fe.TypeSchemaEnvironment(CoreTypes(node), hierarchy),
+      hierarchy,
     ));
 
     if (useAnnotations) {
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 ab94a36..781a0c9 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
@@ -572,3 +572,30 @@
         iterator);
   }
 }
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+  @patch
+  Node _splayMin(Node node) {
+    Node current = node;
+    while (current.left != null) {
+      Node left = current.left;
+      current.left = left.right;
+      left.right = current;
+      current = left;
+    }
+    return current;
+  }
+
+  @patch
+  Node _splayMax(Node node) {
+    Node current = node;
+    while (current.right != null) {
+      Node right = current.right;
+      current.right = right.left;
+      right.left = current;
+      current = right;
+    }
+    return current;
+  }
+}
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
index 7c96274..70ccace 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
@@ -81,8 +81,8 @@
       }
     }
   }
-  return "Type '${typeName(from)}' is not a subtype of "
-      "expected type '${typeName(to)}'.";
+  return "Expected a value of type '${typeName(to)}', "
+      "but got one of type '${typeName(from)}'";
 }
 
 /// The symbol that references the thrown Dart Object (typically but not
@@ -156,8 +156,11 @@
 /// Subclass of JS `Error` that wraps a thrown Dart object, and evaluates the
 /// message lazily by calling `toString()` on the wrapped Dart object.
 ///
-/// Also creates a pointer from the Dart [Error] to the JS Error
-/// (via [_jsError]). This is used to implement [Error.stackTrace].
+/// Also creates a pointer from the thrown Dart object to the JS Error
+/// (via [_jsError]). This is used to implement [Error.stackTrace], but also
+/// provides a way to recover the stack trace if we lose track of it.
+/// [Error] requires preserving the original stack trace if an error is
+/// rethrown, so we only update the pointer if it wasn't already set.
 ///
 /// TODO(jmesserly): Dart Errors should simply be JS Errors.
 final Object DartError = JS(
@@ -166,14 +169,15 @@
       constructor(error) {
         super();
         this[#] = error;
-        if (error instanceof # && error[#] == null) error[#] = this;
+        if (error != null && typeof error == "object" && error[#] == null) {
+          error[#] = this;
+        }
       }
       get message() {
         return #(this[#]);
       }
     }''',
     _thrownValue,
-    Error,
     _jsError,
     _jsError,
     _toString,
@@ -222,7 +226,15 @@
 /// the correct JS stack trace (visible if JavaScript ends up handling it). To
 /// fix that, we use [RethrownDartError] to preserve the Dart trace and make
 /// sure it gets displayed in the JS error message.
+///
+/// If the stack trace is null, this will preserve the original stack trace
+/// on the exception, if available, otherwise it will capture the current stack
+/// trace.
 Object createErrorWithStack(Object exception, StackTrace trace) {
+  if (trace == null) {
+    var error = JS('', '#[#]', exception, _jsError);
+    return error != null ? error : JS('', 'new #(#)', DartError, exception);
+  }
   if (trace is _StackTrace) {
     /// Optimization: if this stack trace and exception already have a matching
     /// Error, we can just rethrow it.
@@ -231,9 +243,7 @@
       return originalError;
     }
   }
-  var error = JS('', 'new #(#)', RethrownDartError, exception);
-  JS('', '#[#] = #', error, _stackTrace, trace);
-  return error;
+  return JS('', 'new #(#, #)', RethrownDartError, exception, trace);
 }
 
 // This is a utility function: it is only intended to be called from dev
diff --git a/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart b/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart
index fb34f25..445f0cb 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/interceptors.dart
@@ -8,7 +8,7 @@
 import 'dart:_internal' hide Symbol;
 import 'dart:_js_helper';
 import 'dart:_foreign_helper' show JS, JSExportName;
-import 'dart:math' show Random;
+import 'dart:math' show Random, ln2;
 import 'dart:_runtime' as dart;
 
 part 'js_array.dart';
diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_number.dart b/pkg/dev_compiler/tool/input_sdk/private/js_number.dart
index f539a10..2a1fb74 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/js_number.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/js_number.dart
@@ -218,7 +218,40 @@
   }
 
   @notNull
-  int get hashCode => JS('int', '# & 0x1FFFFFFF', this);
+  int get hashCode {
+    int intValue = JS('int', '# | 0', this);
+    // Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
+    // and ensures that result fits in JavaScript engine's Smi range.
+    if (this == intValue) return 0x1FFFFFFF & intValue;
+
+    // We would like to access the exponent and mantissa as integers but there
+    // are no JavaScript operations that do this, so use log2-floor-pow-divide
+    // to extract the values.
+    num absolute = JS('num', 'Math.abs(#)', this);
+    num lnAbsolute = JS('num', 'Math.log(#)', absolute);
+    num log2 = lnAbsolute / ln2;
+    // Floor via '# | 0' converts NaN to zero so the final result is not NaN.
+    int floorLog2 = JS('int', '# | 0', log2);
+    num factor = JS('num', 'Math.pow(2, #)', floorLog2);
+    num scaled = absolute < 1 ? absolute / factor : factor / absolute;
+    // [scaled] is in the range [0.5, 1].
+
+    // Multiply and truncate to pick up all the mantissa bits. Multiplying by
+    // 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
+    // integer. There are interesting subsets where all the bit variance is in
+    // the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
+    // need to mix in the most significant bits. We do this by scaling with a
+    // constant that has many bits set to use the multiplier to mix in bits from
+    // all over the mantissa into low positions.
+    num rescaled1 = scaled * 0x20000000000000;
+    num rescaled2 = scaled * 0x0C95A6C285A6C9;
+    int d1 = JS('int', '# | 0', rescaled1);
+    int d2 = JS('int', '# | 0', rescaled2);
+    // Mix in exponent to distinguish e.g. 1.25 from 2.5.
+    int d3 = floorLog2;
+    int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
+    return h;
+  }
 
   @notNull
   JSNumber operator -() => JS('num', r'-#', this);
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index 8e2ff95..9a59d3d 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -8,6 +8,8 @@
  */
 library expect;
 
+import 'package:meta/meta.dart';
+
 /**
  * Expect is used for tests that do not want to make use of the
  * Dart unit test library - for example, the core language tests.
@@ -265,6 +267,7 @@
   }
 
   // Unconditional failure.
+  @alwaysThrows
   static void fail(String msg) {
     _fail("Expect.fail('$msg')");
   }
@@ -647,6 +650,7 @@
   static String _getMessage(String reason) =>
       (reason == null) ? "" : ", '$reason'";
 
+  @alwaysThrows
   static void _fail(String message) {
     throw new ExpectException(message);
   }
diff --git a/pkg/expect/pubspec.yaml b/pkg/expect/pubspec.yaml
index d4b48a4..2a7405d 100644
--- a/pkg/expect/pubspec.yaml
+++ b/pkg/expect/pubspec.yaml
@@ -8,3 +8,6 @@
  test assertions.
 environment:
   sdk: ">=0.8.10+6 <3.0.0"
+
+dependencies:
+  meta: any
diff --git a/pkg/front_end/analysis_options.yaml b/pkg/front_end/analysis_options.yaml
index d5ea4fe..ae13d06 100644
--- a/pkg/front_end/analysis_options.yaml
+++ b/pkg/front_end/analysis_options.yaml
@@ -9,6 +9,8 @@
     # 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).
+    # Allow cross-package deprecated calls
+    # TODO(srawlins): clean these up and remove this "ignore."
     deprecated_member_use: ignore
+    # Allow deprecated calls from within the same package
+    deprecated_member_use_from_same_package: ignore
diff --git a/pkg/front_end/lib/src/api_prototype/compiler_options.dart b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
index cb41df3..85222be 100644
--- a/pkg/front_end/lib/src/api_prototype/compiler_options.dart
+++ b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
@@ -8,7 +8,7 @@
 
 import 'diagnostic_message.dart' show DiagnosticMessageHandler;
 
-import 'experimental_flags.dart' show ExperimentalFlag;
+import 'experimental_flags.dart' show ExperimentalFlag, parseExperimentalFlag;
 
 import 'file_system.dart' show FileSystem;
 
@@ -120,12 +120,12 @@
   /// directly, while relative URIs are resolved from the [sdkRoot].
   // TODO(sigmund): provide also a flag to load this data from a file (like
   // libraries.json)
-  Map<String, List<Uri>> targetPatches = {};
+  Map<String, List<Uri>> targetPatches = <String, List<Uri>>{};
 
   /// Enable or disable experimental features. Features mapping to `true` are
   /// explicitly enabled. Features mapping to `false` are explicitly disabled.
   /// Features not mentioned in the map will have their default value.
-  Map<ExperimentalFlag, bool> experimentalFlags = {};
+  Map<ExperimentalFlag, bool> experimentalFlags = <ExperimentalFlag, bool>{};
 
   /// The target platform that will consume the compiled code.
   ///
@@ -192,4 +192,35 @@
 
   /// Whether to generate bytecode.
   bool bytecode = false;
+
+  /// Whether to write a file (e.g. a dill file) when reporting a crash.
+  bool writeFileOnCrashReport = true;
+}
+
+/// Parse experimental flags from a list of strings, each of which is either a
+/// flag name or a flag name prefixed by 'no-'. Return a map of flags to their
+/// values that can be passed to [experimentalFlags].
+///
+/// If an unknown flag is mentioned, or a flag is mentioned more than once,
+/// the supplied error handler is called with an error message.
+Map<ExperimentalFlag, bool> parseExperimentalFlags(
+    Iterable<String> experiments, void onError(String message)) {
+  Map<ExperimentalFlag, bool> flags = <ExperimentalFlag, bool>{};
+  if (experiments == null) return flags;
+  for (String experiment in experiments) {
+    bool value = true;
+    if (experiment.startsWith("no-")) {
+      value = false;
+      experiment = experiment.substring(3);
+    }
+    ExperimentalFlag flag = parseExperimentalFlag(experiment);
+    if (flag == null) {
+      onError("Unknown experiment: " + experiment);
+    } else if (flags.containsKey(flag)) {
+      onError("Experiment mentioned more than once: " + experiment);
+    } else {
+      flags[flag] = value;
+    }
+  }
+  return flags;
 }
diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart
index 82225f3..188c88b 100644
--- a/pkg/front_end/lib/src/api_unstable/dart2js.dart
+++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart
@@ -12,6 +12,8 @@
 
 import '../api_prototype/diagnostic_message.dart' show DiagnosticMessageHandler;
 
+import '../api_prototype/experimental_flags.dart' show ExperimentalFlag;
+
 import '../api_prototype/file_system.dart' show FileSystem;
 
 import '../base/processed_options.dart' show ProcessedOptions;
@@ -30,10 +32,13 @@
 
 import 'compiler_state.dart' show InitializedCompilerState;
 
-export '../api_prototype/compiler_options.dart' show CompilerOptions;
+export '../api_prototype/compiler_options.dart'
+    show CompilerOptions, parseExperimentalFlags;
 
 export '../api_prototype/diagnostic_message.dart' show DiagnosticMessage;
 
+export '../api_prototype/experimental_flags.dart' show ExperimentalFlag;
+
 export '../api_prototype/file_system.dart'
     show FileSystem, FileSystemEntity, FileSystemException;
 
@@ -98,11 +103,22 @@
     Target target,
     Uri librariesSpecificationUri,
     Uri sdkPlatformUri,
-    Uri packagesFileUri) {
+    Uri packagesFileUri,
+    {Map<ExperimentalFlag, bool> experimentalFlags}) {
+  bool mapEqual(Map<ExperimentalFlag, bool> a, Map<ExperimentalFlag, bool> b) {
+    if (a == null || b == null) return a == b;
+    if (a.length != b.length) return false;
+    for (var flag in a.keys) {
+      if (!b.containsKey(flag) || a[flag] != b[flag]) return false;
+    }
+    return true;
+  }
+
   if (oldState != null &&
       oldState.options.packagesFileUri == packagesFileUri &&
       oldState.options.librariesSpecificationUri == librariesSpecificationUri &&
-      oldState.options.linkedDependencies[0] == sdkPlatformUri) {
+      oldState.options.linkedDependencies[0] == sdkPlatformUri &&
+      mapEqual(oldState.options.experimentalFlags, experimentalFlags)) {
     return oldState;
   }
 
@@ -111,7 +127,8 @@
     ..legacyMode = target.legacyMode
     ..linkedDependencies = [sdkPlatformUri]
     ..librariesSpecificationUri = librariesSpecificationUri
-    ..packagesFileUri = packagesFileUri;
+    ..packagesFileUri = packagesFileUri
+    ..experimentalFlags = experimentalFlags;
 
   ProcessedOptions processedOpts = new ProcessedOptions(options: options);
 
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index 206df5f..4ef234d 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -291,6 +291,9 @@
   /// Whether to generate bytecode.
   bool get bytecode => _raw.bytecode;
 
+  /// Whether to write a file (e.g. a dill file) when reporting a crash.
+  bool get writeFileOnCrashReport => _raw.writeFileOnCrashReport;
+
   Target _target;
   Target get target => _target ??=
       _raw.target ?? new NoneTarget(new TargetFlags(legacyMode: legacyMode));
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 860d1cb..3c4f54a 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -61,6 +61,7 @@
   /// superclass.
   bool get isMixinApplication => mixedInType != null;
 
+  @override
   bool get isNamedMixinApplication {
     return isMixinApplication && super.isNamedMixinApplication;
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration.dart b/pkg/front_end/lib/src/fasta/builder/declaration.dart
index d340033..1584102 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration.dart
@@ -60,6 +60,10 @@
 
   bool get isTypeVariable => false;
 
+  bool get isMixinApplication => false;
+
+  bool get isNamedMixinApplication => false;
+
   /// Applies [patch] to this declaration.
   void applyPatch(Declaration patch) {
     unsupported("${runtimeType}.applyPatch", charOffset, fileUri);
diff --git a/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
index a7a9771..e4f8c41 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
@@ -29,8 +29,6 @@
 
   bool get isTypeDeclaration => true;
 
-  bool get isMixinApplication => false;
-
   @override
   String get fullNameForErrors => name;
 
diff --git a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
index 4f3acc7..7d8cea1 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
@@ -14,7 +14,7 @@
 
   TypeVariableBuilder(
       String name, this.bound, LibraryBuilder compilationUnit, int charOffset)
-      : super(null, null, name, compilationUnit, charOffset);
+      : super(null, 0, name, compilationUnit, charOffset);
 
   bool get isTypeVariable => true;
 
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
index fb395c3..bba4295 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -4,7 +4,7 @@
 
 library fasta.dill_class_builder;
 
-import 'package:kernel/ast.dart' show Class, DartType, Member;
+import 'package:kernel/ast.dart' show Class, DartType, Member, Supertype;
 
 import '../problems.dart' show unimplemented;
 
@@ -18,10 +18,10 @@
 
 import '../modifier.dart' show abstractMask;
 
-import 'dill_member_builder.dart' show DillMemberBuilder;
-
 import 'dill_library_builder.dart' show DillLibraryBuilder;
 
+import 'dill_member_builder.dart' show DillMemberBuilder;
+
 class DillClassBuilder extends KernelClassBuilder {
   final Class cls;
 
@@ -41,6 +41,17 @@
             parent,
             cls.fileOffset);
 
+  KernelTypeBuilder get supertype {
+    KernelTypeBuilder supertype = super.supertype;
+    if (supertype == null) {
+      Supertype targetSupertype = cls.supertype;
+      if (targetSupertype == null) return null;
+      super.supertype =
+          supertype = computeTypeBuilder(library, targetSupertype);
+    }
+    return supertype;
+  }
+
   @override
   Class get actualCls => cls;
 
@@ -88,7 +99,9 @@
   /// superclass.
   bool get isMixinApplication => cls.isMixinApplication;
 
-  KernelTypeBuilder get mixedInType => unimplemented("mixedInType", -1, null);
+  KernelTypeBuilder get mixedInType {
+    return computeTypeBuilder(library, cls.mixedInType);
+  }
 
   void set mixedInType(KernelTypeBuilder mixin) {
     unimplemented("mixedInType=", -1, null);
@@ -98,3 +111,10 @@
 int computeModifiers(Class cls) {
   return cls.isAbstract ? abstractMask : 0;
 }
+
+KernelTypeBuilder computeTypeBuilder(
+    DillLibraryBuilder library, Supertype supertype) {
+  return supertype == null
+      ? null
+      : library.loader.computeTypeBuilder(supertype.asInterfaceType);
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
index 2a4eb8d..026c070 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -6,14 +6,37 @@
 
 import 'dart:async' show Future;
 
-import 'package:kernel/ast.dart' show Library, Component, Source;
+import 'package:kernel/ast.dart'
+    show
+        BottomType,
+        Class,
+        Component,
+        DartType,
+        DartTypeVisitor,
+        DynamicType,
+        FunctionType,
+        InterfaceType,
+        InvalidType,
+        Library,
+        Source,
+        TypeParameter,
+        TypeParameterType,
+        TypedefType,
+        VoidType;
 
 import '../fasta_codes.dart'
     show SummaryTemplate, Template, templateDillOutlineSummary;
 
 import '../compiler_context.dart' show CompilerContext;
 
-import '../kernel/kernel_builder.dart' show LibraryBuilder;
+import '../kernel/kernel_builder.dart'
+    show
+        DynamicTypeBuilder,
+        KernelNamedTypeBuilder,
+        KernelTypeBuilder,
+        KernelTypeVariableBuilder,
+        LibraryBuilder,
+        VoidTypeBuilder;
 
 import '../loader.dart' show Loader;
 
@@ -21,6 +44,8 @@
 
 import '../target_implementation.dart' show TargetImplementation;
 
+import 'dill_class_builder.dart' show DillClassBuilder;
+
 import 'dill_library_builder.dart' show DillLibraryBuilder;
 
 class DillLoader extends Loader<Library> {
@@ -75,4 +100,72 @@
       library.finalizeExports();
     });
   }
+
+  KernelTypeBuilder computeTypeBuilder(DartType type) {
+    return type.accept(new TypeBuilderComputer(this));
+  }
+}
+
+class TypeBuilderComputer implements DartTypeVisitor<KernelTypeBuilder> {
+  final DillLoader loader;
+
+  const TypeBuilderComputer(this.loader);
+
+  KernelTypeBuilder defaultDartType(DartType node) {
+    throw "Unsupported";
+  }
+
+  KernelTypeBuilder visitInvalidType(InvalidType node) {
+    throw "Not implemented";
+  }
+
+  KernelTypeBuilder visitDynamicType(DynamicType node) {
+    return new KernelNamedTypeBuilder("dynamic", null)
+      ..bind(new DynamicTypeBuilder<KernelTypeBuilder, DartType>(
+          const DynamicType(), loader.coreLibrary, -1));
+  }
+
+  KernelTypeBuilder visitVoidType(VoidType node) {
+    return new KernelNamedTypeBuilder("dynamic", null)
+      ..bind(new VoidTypeBuilder<KernelTypeBuilder, VoidType>(
+          const VoidType(), loader.coreLibrary, -1));
+  }
+
+  KernelTypeBuilder visitBottomType(BottomType node) {
+    throw "Not implemented";
+  }
+
+  KernelTypeBuilder visitInterfaceType(InterfaceType node) {
+    Class kernelClass = node.classNode;
+    Library kernelLibrary = kernelClass.enclosingLibrary;
+    DillLibraryBuilder library = loader.builders[kernelLibrary.importUri];
+    String name = kernelClass.name;
+    DillClassBuilder cls = library[name];
+    List<KernelTypeBuilder> arguments;
+    List<DartType> kernelArguments = node.typeArguments;
+    if (kernelArguments.isNotEmpty) {
+      arguments = new List<KernelTypeBuilder>(kernelArguments.length);
+      for (int i = 0; i < kernelArguments.length; i++) {
+        arguments[i] = kernelArguments[i].accept(this);
+      }
+    }
+    return new KernelNamedTypeBuilder(name, arguments)..bind(cls);
+  }
+
+  KernelTypeBuilder visitFunctionType(FunctionType node) {
+    throw "Not implemented";
+  }
+
+  KernelTypeBuilder visitTypeParameterType(TypeParameterType node) {
+    TypeParameter parameter = node.parameter;
+    Class kernelClass = parameter.parent;
+    Library kernelLibrary = kernelClass.enclosingLibrary;
+    DillLibraryBuilder library = loader.builders[kernelLibrary.importUri];
+    return new KernelNamedTypeBuilder(parameter.name, null)
+      ..bind(new KernelTypeVariableBuilder.fromKernel(parameter, library));
+  }
+
+  KernelTypeBuilder visitTypedefType(TypedefType node) {
+    throw "Not implemented";
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
index 7b54cd3..cfd35fb 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -62,6 +62,8 @@
         name == "" &&
         (charOffset == parent.charOffset || charOffset == -1);
   }
+
+  bool get isField => member is Field;
 }
 
 int computeModifiers(Member member) {
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index bfea29e..3712941 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -3323,9 +3323,9 @@
     commas, for example, --fatal=errors,warnings.
 
   --enable-experiment=<flag>
-  --disable-experiment=<flag>
     Enable or disable an experimental flag, used to guard features currently
-    in development. Multiple experiments can be separated by commas.""");
+    in development. Prefix an experiment name with 'no-' to disable it.
+    Multiple experiments can be separated by commas.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeFastaUsageShort = messageFastaUsageShort;
@@ -4550,27 +4550,67 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
-        String
-            string)> templateInitializeFromDillNotSelfContained = const Template<
-        Message Function(String string)>(
+        String string,
+        Uri
+            uri_)> templateInitializeFromDillNotSelfContained = const Template<
+        Message Function(String string, Uri uri_)>(
     messageTemplate:
-        r"""Tried to initialize from a previous compilation (#string), but the file was not self-contained. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new.""",
+        r"""Tried to initialize from a previous compilation (#string), but the file was not self-contained. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+If you are comfortable with it, it would improve the chances of fixing any bug if you included the file #uri in your error report, but be aware that this file includes your source code.
+Either way, you should probably delete the file so it doesn't use unnecessary disk space.""",
     withArguments: _withArgumentsInitializeFromDillNotSelfContained);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String string)>
+const Code<Message Function(String string, Uri uri_)>
     codeInitializeFromDillNotSelfContained =
-    const Code<Message Function(String string)>(
+    const Code<Message Function(String string, Uri uri_)>(
         "InitializeFromDillNotSelfContained",
         templateInitializeFromDillNotSelfContained,
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsInitializeFromDillNotSelfContained(String string) {
+Message _withArgumentsInitializeFromDillNotSelfContained(
+    String string, Uri uri_) {
   if (string.isEmpty) throw 'No string provided';
+  String uri = relativizeUri(uri_);
   return new Message(codeInitializeFromDillNotSelfContained,
       message:
-          """Tried to initialize from a previous compilation (${string}), but the file was not self-contained. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new.""",
+          """Tried to initialize from a previous compilation (${string}), but the file was not self-contained. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+If you are comfortable with it, it would improve the chances of fixing any bug if you included the file ${uri} in your error report, but be aware that this file includes your source code.
+Either way, you should probably delete the file so it doesn't use unnecessary disk space.""",
+      arguments: {'string': string, 'uri': uri_});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String string)>
+    templateInitializeFromDillNotSelfContainedNoDump =
+    const Template<Message Function(String string)>(
+        messageTemplate:
+            r"""Tried to initialize from a previous compilation (#string), but the file was not self-contained. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.""",
+        withArguments: _withArgumentsInitializeFromDillNotSelfContainedNoDump);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String string)>
+    codeInitializeFromDillNotSelfContainedNoDump =
+    const Code<Message Function(String string)>(
+        "InitializeFromDillNotSelfContainedNoDump",
+        templateInitializeFromDillNotSelfContainedNoDump,
+        severity: Severity.warning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInitializeFromDillNotSelfContainedNoDump(String string) {
+  if (string.isEmpty) throw 'No string provided';
+  return new Message(codeInitializeFromDillNotSelfContainedNoDump,
+      message:
+          """Tried to initialize from a previous compilation (${string}), but the file was not self-contained. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.""",
       arguments: {'string': string});
 }
 
@@ -4578,29 +4618,74 @@
 const Template<
     Message Function(
         String string,
-        String
-            string2)> templateInitializeFromDillUnknownProblem = const Template<
-        Message Function(String string, String string2)>(
+        String string2,
+        Uri
+            uri_)> templateInitializeFromDillUnknownProblem = const Template<
+        Message Function(String string, String string2, Uri uri_)>(
     messageTemplate:
-        r"""Tried to initialize from a previous compilation (#string), but couldn't. Error message was '#string2'. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new.""",
+        r"""Tried to initialize from a previous compilation (#string), but couldn't.
+Error message was '#string2'. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+If you are comfortable with it, it would improve the chances of fixing any bug if you included the file #uri in your error report, but be aware that this file includes your source code.
+Either way, you should probably delete the file so it doesn't use unnecessary disk space.""",
     withArguments: _withArgumentsInitializeFromDillUnknownProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String string, String string2)>
+const Code<Message Function(String string, String string2, Uri uri_)>
     codeInitializeFromDillUnknownProblem =
-    const Code<Message Function(String string, String string2)>(
+    const Code<Message Function(String string, String string2, Uri uri_)>(
         "InitializeFromDillUnknownProblem",
         templateInitializeFromDillUnknownProblem,
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInitializeFromDillUnknownProblem(
+    String string, String string2, Uri uri_) {
+  if (string.isEmpty) throw 'No string provided';
+  if (string2.isEmpty) throw 'No string provided';
+  String uri = relativizeUri(uri_);
+  return new Message(codeInitializeFromDillUnknownProblem,
+      message:
+          """Tried to initialize from a previous compilation (${string}), but couldn't.
+Error message was '${string2}'. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+If you are comfortable with it, it would improve the chances of fixing any bug if you included the file ${uri} in your error report, but be aware that this file includes your source code.
+Either way, you should probably delete the file so it doesn't use unnecessary disk space.""",
+      arguments: {'string': string, 'string2': string2, 'uri': uri_});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String string, String string2)>
+    templateInitializeFromDillUnknownProblemNoDump =
+    const Template<Message Function(String string, String string2)>(
+        messageTemplate:
+            r"""Tried to initialize from a previous compilation (#string), but couldn't.
+Error message was '#string2'. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.""",
+        withArguments: _withArgumentsInitializeFromDillUnknownProblemNoDump);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String string, String string2)>
+    codeInitializeFromDillUnknownProblemNoDump =
+    const Code<Message Function(String string, String string2)>(
+        "InitializeFromDillUnknownProblemNoDump",
+        templateInitializeFromDillUnknownProblemNoDump,
+        severity: Severity.warning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInitializeFromDillUnknownProblemNoDump(
     String string, String string2) {
   if (string.isEmpty) throw 'No string provided';
   if (string2.isEmpty) throw 'No string provided';
-  return new Message(codeInitializeFromDillUnknownProblem,
+  return new Message(codeInitializeFromDillUnknownProblemNoDump,
       message:
-          """Tried to initialize from a previous compilation (${string}), but couldn't. Error message was '${string2}'. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new.""",
+          """Tried to initialize from a previous compilation (${string}), but couldn't.
+Error message was '${string2}'. This might be a bug.
+
+The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.""",
       arguments: {'string': string, 'string2': string2});
 }
 
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 91a78a6..795a5d9 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -52,10 +52,14 @@
 
 import 'dill/dill_target.dart' show DillTarget;
 
+import 'util/error_reporter_file_copier.dart' show saveAsGzip;
+
 import 'fasta_codes.dart'
     show
         templateInitializeFromDillNotSelfContained,
-        templateInitializeFromDillUnknownProblem;
+        templateInitializeFromDillNotSelfContainedNoDump,
+        templateInitializeFromDillUnknownProblem,
+        templateInitializeFromDillUnknownProblemNoDump;
 
 import 'hybrid_file_system.dart' show HybridFileSystem;
 
@@ -67,6 +71,8 @@
 
 import 'library_graph.dart' show LibraryGraph;
 
+import 'messages.dart' show Message;
+
 import 'source/source_library_builder.dart' show SourceLibraryBuilder;
 
 import 'ticker.dart' show Ticker;
@@ -121,8 +127,7 @@
         int bytesLength = prepareSummary(summaryBytes, uriTranslator, c, data);
         if (initializeFromDillUri != null) {
           try {
-            bytesLength +=
-                await initializeFromDill(summaryBytes, uriTranslator, c, data);
+            bytesLength += await initializeFromDill(uriTranslator, c, data);
           } catch (e) {
             // We might have loaded x out of y libraries into the component.
             // To avoid any unforeseen problems start over.
@@ -130,25 +135,37 @@
 
             if (e is InvalidKernelVersionError || e is PackageChangedError) {
               // Don't report any warning.
-            } else if (e is CanonicalNameError) {
-              dillLoadedData.loader.addProblem(
-                  templateInitializeFromDillNotSelfContained
-                      .withArguments(initializeFromDillUri.toString()),
-                  TreeNode.noOffset,
-                  1,
-                  null);
             } else {
-              // Unknown error: Report problem as such.
-              dillLoadedData.loader.addProblem(
-                  templateInitializeFromDillUnknownProblem.withArguments(
-                      initializeFromDillUri.toString(), "$e"),
-                  TreeNode.noOffset,
-                  1,
-                  null);
+              Uri gzInitializedFrom;
+              if (c.options.writeFileOnCrashReport) {
+                gzInitializedFrom = saveAsGzip(
+                    data.initializationBytes, "initialize_from.dill");
+                recordTemporaryFileForTesting(gzInitializedFrom);
+              }
+              if (e is CanonicalNameError) {
+                Message message = gzInitializedFrom != null
+                    ? templateInitializeFromDillNotSelfContained.withArguments(
+                        initializeFromDillUri.toString(), gzInitializedFrom)
+                    : templateInitializeFromDillNotSelfContainedNoDump
+                        .withArguments(initializeFromDillUri.toString());
+                dillLoadedData.loader
+                    .addProblem(message, TreeNode.noOffset, 1, null);
+              } else {
+                // Unknown error: Report problem as such.
+                Message message = gzInitializedFrom != null
+                    ? templateInitializeFromDillUnknownProblem.withArguments(
+                        initializeFromDillUri.toString(),
+                        "$e",
+                        gzInitializedFrom)
+                    : templateInitializeFromDillUnknownProblemNoDump
+                        .withArguments(initializeFromDillUri.toString(), "$e");
+                dillLoadedData.loader
+                    .addProblem(message, TreeNode.noOffset, 1, null);
+              }
             }
           }
         } else if (componentToInitializeFrom != null) {
-          initializeFromComponent(summaryBytes, uriTranslator, c, data);
+          initializeFromComponent(uriTranslator, c, data);
         }
         appendLibraries(data, bytesLength);
 
@@ -165,6 +182,7 @@
         });
         if (userBuilders.isEmpty) userBuilders = null;
       }
+      data.initializationBytes = null;
 
       Set<Uri> invalidatedUris = this.invalidatedUris.toSet();
       if ((data.includeUserLoadedLibraries &&
@@ -256,10 +274,10 @@
       List<Library> outputLibraries;
       if (data.includeUserLoadedLibraries || fullComponent) {
         outputLibraries = computeTransitiveClosure(compiledLibraries,
-            mainMethod, entryPoint, reusedLibraries, data, hierarchy);
+            mainMethod, entryPoint, reusedLibraries, hierarchy);
       } else {
         computeTransitiveClosure(compiledLibraries, mainMethod, entryPoint,
-            reusedLibraries, data, hierarchy);
+            reusedLibraries, hierarchy);
         outputLibraries = compiledLibraries;
       }
 
@@ -281,7 +299,6 @@
       Procedure mainMethod,
       Uri entry,
       List<LibraryBuilder> reusedLibraries,
-      IncrementalCompilerData data,
       ClassHierarchy hierarchy) {
     List<Library> result = new List<Library>.from(inputLibraries);
     Map<Uri, Library> libraryMap = <Uri, Library>{};
@@ -351,10 +368,7 @@
   }
 
   // This procedure will try to load the dill file and will crash if it cannot.
-  Future<int> initializeFromDill(
-      List<int> summaryBytes,
-      UriTranslator uriTranslator,
-      CompilerContext c,
+  Future<int> initializeFromDill(UriTranslator uriTranslator, CompilerContext c,
       IncrementalCompilerData data) async {
     int bytesLength = 0;
     FileSystemEntity entity =
@@ -363,6 +377,7 @@
       List<int> initializationBytes = await entity.readAsBytes();
       if (initializationBytes != null) {
         ticker.logMs("Read $initializeFromDillUri");
+        data.initializationBytes = initializationBytes;
 
         // We're going to output all we read here so lazy loading it
         // doesn't make sense.
@@ -393,10 +408,7 @@
   }
 
   // This procedure will set up compiler from [componentToInitializeFrom].
-  void initializeFromComponent(
-      List<int> summaryBytes,
-      UriTranslator uriTranslator,
-      CompilerContext c,
+  void initializeFromComponent(UriTranslator uriTranslator, CompilerContext c,
       IncrementalCompilerData data) {
     ticker.logMs("Read initializeFromComponent");
 
@@ -671,6 +683,7 @@
   }
 
   void recordInvalidatedImportUrisForTesting(List<Uri> uris) {}
+  void recordTemporaryFileForTesting(Uri uri) {}
 }
 
 class PackageChangedError {
@@ -681,4 +694,5 @@
   bool includeUserLoadedLibraries = false;
   Procedure userLoadedUriMain = null;
   Component component = null;
+  List<int> initializationBytes = null;
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 61fe4bd..505559d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -17,6 +17,8 @@
         messageInheritedMembersConflict,
         messageInheritedMembersConflictCause1,
         messageInheritedMembersConflictCause2,
+        templateDuplicatedDeclaration,
+        templateDuplicatedDeclarationCause,
         templateMissingImplementationCause,
         templateMissingImplementationNotAbstract;
 
@@ -45,6 +47,22 @@
   return !name.isPrivate || name.library == library.target;
 }
 
+/// Returns true if [a] is a class member conflict with [b].  [a] is assumed to
+/// be declared in the class, [b] is assumed to be inherited.
+///
+/// See the section named "Class Member Conflicts" in [Dart Programming
+/// Language Specification](
+/// ../../../../../../docs/language/dartLangSpec.tex#classMemberConflicts).
+bool isInheritanceConflict(Declaration a, Declaration b) {
+  if (a.isField) return !(b.isField || b.isGetter || b.isSetter);
+  if (b.isField) return !(a.isField || a.isGetter || a.isSetter);
+  return memberKind(a.target) != memberKind(b.target);
+}
+
+bool impliesSetter(Declaration declaration) {
+  return declaration.isField && !(declaration.isFinal || declaration.isConst);
+}
+
 class ClassHierarchyBuilder {
   final Map<KernelClassBuilder, ClassHierarchyNode> nodes =
       <KernelClassBuilder, ClassHierarchyNode>{};
@@ -53,71 +71,105 @@
 
   bool hasNoSuchMethod = false;
 
-  int abstractMemberCount = 0;
+  List<Declaration> abstractMembers = null;
 
   ClassHierarchyBuilder(this.objectClass);
 
-  Declaration handleOverride(KernelClassBuilder cls, Declaration member,
-      Declaration superMember, MergeKind mergeKind) {
-    if (member.next != null || superMember.next != null) {
+  /// A merge conflict arises when merging two lists that each have an element
+  /// with the same name.
+  ///
+  /// If [mergeKind] is `MergeKind.superclass`, [a] should override [b].
+  ///
+  /// If [mergeKind] is `MergeKind.interfaces`, we need to record them and
+  /// solve the conflict later.
+  ///
+  /// If [mergeKind] is `MergeKind.supertypes`, [a] should implement [b], and
+  /// [b] is implicitly abstract.
+  Declaration handleMergeConflict(KernelClassBuilder cls, Declaration a,
+      Declaration b, MergeKind mergeKind) {
+    if (a == b) return a;
+    if (a.next != null || b.next != null) {
       // Don't check overrides involving duplicated members.
-      return member;
+      return a;
     }
-    Member target = member.target;
-    Member superTarget = superMember.target;
-    if ((memberKind(target) ?? ProcedureKind.Getter) !=
-        (memberKind(superTarget) ?? ProcedureKind.Getter)) {
-      String name = member.fullNameForErrors;
-      if (mergeKind == MergeKind.interfaces) {
-        cls.addProblem(messageInheritedMembersConflict, cls.charOffset,
-            cls.fullNameForErrors.length,
-            context: <LocatedMessage>[
-              messageInheritedMembersConflictCause1.withLocation(
-                  member.fileUri, member.charOffset, name.length),
-              messageInheritedMembersConflictCause2.withLocation(
-                  superMember.fileUri, superMember.charOffset, name.length),
-            ]);
-      } else {
-        cls.addProblem(messageDeclaredMemberConflictsWithInheritedMember,
-            member.charOffset, name.length,
-            context: <LocatedMessage>[
-              messageDeclaredMemberConflictsWithInheritedMemberCause
-                  .withLocation(
-                      superMember.fileUri, superMember.charOffset, name.length)
-            ]);
-      }
+    if (isInheritanceConflict(a, b)) {
+      reportInheritanceConflict(cls, a, b, mergeKind);
     }
-    if (target.name == noSuchMethodName && !target.isAbstract) {
-      hasNoSuchMethod = true;
-    }
-    Declaration result = member;
+    Declaration result = a;
     if (mergeKind == MergeKind.interfaces) {
-      // TODO(ahe): Combine the signatures of member and superMember.
-    } else if (target.isAbstract) {
-      if (!superTarget.isAbstract) {
+      // TODO(ahe): Combine the signatures of a and b.  See the section named
+      // "Combined Member Signatures" in [Dart Programming Language
+      // Specification](
+      // ../../../../../../docs/language/dartLangSpec.tex#combinedMemberSignatures).
+    } else if (a.target.isAbstract) {
+      if (mergeKind == MergeKind.superclass && !b.target.isAbstract) {
         // An abstract method doesn't override an implemention inherited from a
         // superclass.
-        result = superMember;
+        result = b;
       } else {
-        abstractMemberCount++;
+        (abstractMembers ??= <Declaration>[]).add(a);
       }
     }
+
+    if (mergeKind == MergeKind.superclass &&
+        result.fullNameForErrors == noSuchMethodName.name &&
+        result.parent != objectClass) {
+      hasNoSuchMethod = true;
+    }
+
     return result;
   }
 
-  void handleNewMember(Declaration member, MergeKind mergeKind) {
-    Member target = member.target;
-    if (mergeKind == MergeKind.superclass && target.isAbstract) {
-      abstractMemberCount++;
+  void reportInheritanceConflict(KernelClassBuilder cls, Declaration a,
+      Declaration b, MergeKind mergeKind) {
+    String name = a.fullNameForErrors;
+    if (mergeKind == MergeKind.interfaces) {
+      cls.addProblem(messageInheritedMembersConflict, cls.charOffset,
+          cls.fullNameForErrors.length,
+          context: <LocatedMessage>[
+            messageInheritedMembersConflictCause1.withLocation(
+                a.fileUri, a.charOffset, name.length),
+            messageInheritedMembersConflictCause2.withLocation(
+                b.fileUri, b.charOffset, name.length),
+          ]);
+    } else {
+      cls.addProblem(messageDeclaredMemberConflictsWithInheritedMember,
+          a.charOffset, name.length,
+          context: <LocatedMessage>[
+            messageDeclaredMemberConflictsWithInheritedMemberCause.withLocation(
+                b.fileUri, b.charOffset, name.length)
+          ]);
     }
   }
 
-  void handleInheritance(
-      KernelClassBuilder cls, Declaration member, MergeKind mergeKind) {
+  /// If [mergeKind] is `MergeKind.superclass` [member] is declared in current
+  /// class, and isn't overriding a method from the superclass.
+  ///
+  /// If [mergeKind] is `MergeKind.interfaces`, [member] is ignored for now.
+  ///
+  /// If [mergeKind] is `MergeKind.supertypes`, [member] isn't
+  /// implementing/overriding anything.
+  void handleOnlyA(Declaration member, MergeKind mergeKind) {
     Member target = member.target;
     if (mergeKind == MergeKind.superclass && target.isAbstract) {
+      (abstractMembers ??= <Declaration>[]).add(member);
+    }
+  }
+
+  /// If [mergeKind] is `MergeKind.superclass` [member] is being inherited from
+  /// a superclass.
+  ///
+  /// If [mergeKind] is `MergeKind.interfaces`, [member] is ignored for now.
+  ///
+  /// If [mergeKind] is `MergeKind.supertypes`, [member] is implicitly
+  /// abstract, and not implemented.
+  void handleOnlyB(
+      KernelClassBuilder cls, Declaration member, MergeKind mergeKind) {
+    Member target = member.target;
+    if (mergeKind == MergeKind.supertypes ||
+        (mergeKind == MergeKind.superclass && target.isAbstract)) {
       if (isNameVisibleIn(target.name, cls.library)) {
-        abstractMemberCount++;
+        (abstractMembers ??= <Declaration>[]).add(member);
       }
     }
     if (member.parent != objectClass &&
@@ -128,6 +180,8 @@
   }
 
   void add(KernelClassBuilder cls) {
+    assert(!hasNoSuchMethod);
+    assert(abstractMembers == null);
     if (cls.isPatch) {
       // TODO(ahe): What about patch classes. Have we injected patched members
       // into the class-builder's scope?
@@ -153,65 +207,80 @@
         scope = mixin.scope;
       }
     }
-    List<Declaration> sortedLocals =
+    // TODO(ahe): Consider if removing static members from [localMembers] and
+    // [localSetters] makes sense. It depends on what semantic checks we need
+    // to perform with respect to static members and inherited members with the
+    // same name.
+    List<Declaration> localMembers =
         new List<Declaration>.from(scope.local.values)
           ..sort(compareDeclarations);
-    List<Declaration> sortedSetters =
+    List<Declaration> localSetters =
         new List<Declaration>.from(scope.setters.values)
           ..sort(compareDeclarations);
-    List<Declaration> allMembers;
-    List<Declaration> allSetters;
+    localSetters = mergeAccessors(cls, localMembers, localSetters);
+    List<Declaration> classMembers;
+    List<Declaration> classSetters;
     List<Declaration> interfaceMembers;
     List<Declaration> interfaceSetters;
     if (supernode == null) {
       // This should be Object.
-      interfaceMembers = allMembers = sortedLocals;
-      interfaceSetters = allSetters = sortedSetters;
+      classMembers = localMembers;
+      classSetters = localSetters;
     } else {
-      allMembers = merge(
-          cls, sortedLocals, supernode.classMembers, MergeKind.superclass);
-      allSetters = merge(
-          cls, sortedSetters, supernode.classSetters, MergeKind.superclass);
+      classMembers = merge(
+          cls, localMembers, supernode.classMembers, MergeKind.superclass);
+      classSetters = merge(
+          cls, localSetters, supernode.classSetters, MergeKind.superclass);
       List<KernelTypeBuilder> interfaces = cls.interfaces;
       if (interfaces != null) {
         MergeResult result = mergeInterfaces(cls, supernode, interfaces);
         interfaceMembers = result.mergedMembers;
         interfaceSetters = result.mergedSetters;
       } else {
-        interfaceMembers = allMembers;
-        interfaceSetters = allSetters;
+        interfaceMembers = supernode.interfaceMembers;
+        interfaceSetters = supernode.interfaceSetters;
+      }
+      if (interfaceMembers != null) {
+        interfaceMembers =
+            merge(cls, classMembers, interfaceMembers, MergeKind.supertypes);
+      }
+      if (interfaceMembers != null) {
+        interfaceSetters =
+            merge(cls, classSetters, interfaceSetters, MergeKind.supertypes);
       }
     }
-    nodes[cls] = new ClassHierarchyNode(
-        cls, scope, allMembers, allSetters, interfaceMembers, interfaceSetters);
-    mergeAccessors(cls, allMembers, allSetters);
+    nodes[cls] = new ClassHierarchyNode(cls, scope, classMembers, classSetters,
+        interfaceMembers, interfaceSetters);
 
-    if (abstractMemberCount != 0 && !cls.isAbstract) {
+    if (abstractMembers != null && !cls.isAbstract) {
       if (!hasNoSuchMethod) {
-        reportMissingMembers(cls, allMembers, allSetters);
+        reportMissingMembers(cls);
+      } else {
+        installNsmHandlers(cls);
       }
-      installNsmHandlers(cls);
     }
     hasNoSuchMethod = false;
-    abstractMemberCount = 0;
+    abstractMembers = null;
   }
 
   MergeResult mergeInterfaces(KernelClassBuilder cls,
       ClassHierarchyNode supernode, List<KernelTypeBuilder> interfaces) {
     List<List<Declaration>> memberLists =
-        List<List<Declaration>>(interfaces.length + 1);
+        new List<List<Declaration>>(interfaces.length + 1);
     List<List<Declaration>> setterLists =
-        List<List<Declaration>>(interfaces.length + 1);
+        new List<List<Declaration>>(interfaces.length + 1);
     memberLists[0] = supernode.interfaceMembers;
     setterLists[0] = supernode.interfaceSetters;
     for (int i = 0; i < interfaces.length; i++) {
       ClassHierarchyNode interfaceNode = getNode(interfaces[i]);
       if (interfaceNode == null) {
-        memberLists[i + 1] = <Declaration>[];
-        setterLists[i + 1] = <Declaration>[];
+        memberLists[i + 1] = null;
+        setterLists[i + 1] = null;
       } else {
-        memberLists[i + 1] = interfaceNode.interfaceMembers;
-        setterLists[i + 1] = interfaceNode.interfaceSetters;
+        memberLists[i + 1] =
+            interfaceNode.interfaceMembers ?? interfaceNode.classMembers;
+        setterLists[i + 1] =
+            interfaceNode.interfaceSetters ?? interfaceNode.classSetters;
       }
     }
     return new MergeResult(
@@ -226,7 +295,15 @@
     while (input.length > 1) {
       List<List<Declaration>> output = <List<Declaration>>[];
       for (int i = 0; i < input.length - 1; i += 2) {
-        output.add(merge(cls, input[i], input[i + 1], MergeKind.interfaces));
+        List<Declaration> first = input[i];
+        List<Declaration> second = input[i + 1];
+        if (first == null) {
+          output.add(second);
+        } else if (second == null) {
+          output.add(first);
+        } else {
+          output.add(merge(cls, first, second, MergeKind.interfaces));
+        }
       }
       if (input.length.isOdd) {
         output.add(input.last);
@@ -236,99 +313,94 @@
     return input.single;
   }
 
-  /// Merge [and check] accessors. This entails removing setters corresponding
-  /// to fields, and checking that setters don't override regular methods.
-  void mergeAccessors(KernelClassBuilder cls, List<Declaration> allMembers,
-      List<Declaration> allSetters) {
-    List<Declaration> overriddenSetters;
+  /// Merge [and check] accessors. This entails copying mutable fields to
+  /// setters to simulate implied setters, and checking that setters don't
+  /// override regular methods.
+  List<Declaration> mergeAccessors(KernelClassBuilder cls,
+      List<Declaration> members, List<Declaration> setters) {
+    final List<Declaration> mergedSetters = new List<Declaration>.filled(
+        members.length + setters.length, null,
+        growable: true);
+    int storeIndex = 0;
     int i = 0;
     int j = 0;
-    while (i < allMembers.length && j < allSetters.length) {
-      Declaration member = allMembers[i];
-      Declaration setter = allSetters[j];
+    while (i < members.length && j < setters.length) {
+      final Declaration member = members[i];
+      final Declaration setter = setters[j];
       final int compare = compareDeclarations(member, setter);
       if (compare == 0) {
-        if (member.isField) {
-          // TODO(ahe): What happens if we have both a field and a setter
-          // declared in the same class?
-          if (!member.isFinal && !member.isConst) {
-            // The field overrides the setter.
-            (overriddenSetters ??= <Declaration>[]).add(setter);
-            Member target = setter.target;
-            if (target.isAbstract) {
-              abstractMemberCount--;
-            }
-          }
-        } else if (!member.isGetter) {
-          String name = member.fullNameForErrors;
+        if (member.isField ? impliesSetter(member) : !member.isGetter) {
+          // [member] conflicts with [setter].
+          final String name = member.fullNameForErrors;
           cls.library.addProblem(
-              messageDeclaredMemberConflictsWithInheritedMember,
-              member.charOffset,
+              templateDuplicatedDeclaration.withArguments(name),
+              setter.charOffset,
               name.length,
-              member.fileUri,
+              setter.fileUri,
               context: <LocatedMessage>[
-                messageDeclaredMemberConflictsWithInheritedMemberCause
+                templateDuplicatedDeclarationCause
+                    .withArguments(name)
                     .withLocation(
-                        setter.fileUri, setter.charOffset, name.length)
+                        member.fileUri, member.charOffset, name.length)
               ]);
         }
+        mergedSetters[storeIndex++] = setter;
         i++;
         j++;
       } else if (compare < 0) {
+        if (impliesSetter(member)) {
+          mergedSetters[storeIndex++] = member;
+        }
         i++;
       } else {
+        mergedSetters[storeIndex++] = setters[j];
         j++;
       }
     }
-    // One of of the two lists is now exhausted. What remains in the other list
-    // cannot be a conflict.
+    while (i < members.length) {
+      final Declaration member = members[i];
+      if (impliesSetter(member)) {
+        mergedSetters[storeIndex++] = member;
+      }
+      i++;
+    }
+    while (j < setters.length) {
+      mergedSetters[storeIndex++] = setters[j];
+      j++;
+    }
 
-    if (overriddenSetters != null) {
-      // Remove [overriddenSetters] from [allSetters] by copying [allSetters]
-      // to itself.
-      int i = 0;
-      int j = 0;
-      int storeIndex = 0;
-      while (i < allSetters.length && j < overriddenSetters.length) {
-        if (allSetters[i] == overriddenSetters[j]) {
-          i++;
-          j++;
-        } else {
-          allSetters[storeIndex++] = allSetters[i++];
-        }
-      }
-      while (i < allSetters.length) {
-        allSetters[storeIndex++] = allSetters[i++];
-      }
-      allSetters.length = storeIndex;
+    if (storeIndex == j) {
+      return setters;
+    } else {
+      return mergedSetters..length = storeIndex;
     }
   }
 
-  void reportMissingMembers(KernelClassBuilder cls,
-      List<Declaration> allMembers, List<Declaration> allSetters) {
-    List<LocatedMessage> context = <LocatedMessage>[];
-    List<String> missingNames = <String>[];
-    for (int j = 0; j < 2; j++) {
-      List<Declaration> members = j == 0 ? allMembers : allSetters;
-      for (int i = 0; i < members.length; i++) {
-        Declaration declaration = members[i];
-        Member target = declaration.target;
-        if (target.isAbstract && isNameVisibleIn(target.name, cls.library)) {
-          String name = declaration.fullNameForErrors;
-          String parentName = declaration.parent.fullNameForErrors;
-          String displayName =
-              declaration.isSetter ? "$parentName.$name=" : "$parentName.$name";
-          missingNames.add(displayName);
-          context.add(templateMissingImplementationCause
-              .withArguments(displayName)
-              .withLocation(
-                  declaration.fileUri, declaration.charOffset, name.length));
-        }
+  void reportMissingMembers(KernelClassBuilder cls) {
+    Map<String, LocatedMessage> contextMap = <String, LocatedMessage>{};
+    for (int i = 0; i < abstractMembers.length; i++) {
+      Declaration declaration = abstractMembers[i];
+      Member target = declaration.target;
+      if (isNameVisibleIn(target.name, cls.library)) {
+        String name = declaration.fullNameForErrors;
+        String parentName = declaration.parent.fullNameForErrors;
+        String displayName =
+            declaration.isSetter ? "$parentName.$name=" : "$parentName.$name";
+        contextMap[displayName] = templateMissingImplementationCause
+            .withArguments(displayName)
+            .withLocation(
+                declaration.fileUri, declaration.charOffset, name.length);
       }
     }
+    if (contextMap.isEmpty) return;
+    List<String> names = new List<String>.from(contextMap.keys)..sort();
+    List<LocatedMessage> context = <LocatedMessage>[];
+    for (int i = 0; i < names.length; i++) {
+      context.add(contextMap[names[i]]);
+    }
     cls.addProblem(
         templateMissingImplementationNotAbstract.withArguments(
-            cls.fullNameForErrors, missingNames),
+            cls.fullNameForErrors, names),
         cls.charOffset,
         cls.fullNameForErrors.length,
         context: context);
@@ -339,16 +411,20 @@
   }
 
   ClassHierarchyNode getNode(KernelTypeBuilder type) {
-    if (type is KernelNamedTypeBuilder) {
-      Declaration declaration = type.declaration;
-      if (declaration is KernelClassBuilder) {
-        ClassHierarchyNode node = nodes[declaration];
-        if (node == null && declaration is KernelClassBuilder) {
-          add(declaration);
-          node = nodes[declaration];
-        }
-        return node;
+    Declaration declaration = getDeclaration(type);
+    if (declaration is KernelClassBuilder) {
+      ClassHierarchyNode node = nodes[declaration];
+      if (node == null) {
+        bool savedHasNoSuchMethod = hasNoSuchMethod;
+        hasNoSuchMethod = false;
+        List<Declaration> savedAbstractMembers = abstractMembers;
+        abstractMembers = null;
+        add(declaration);
+        hasNoSuchMethod = savedHasNoSuchMethod;
+        abstractMembers = savedAbstractMembers;
+        node = nodes[declaration];
       }
+      return node;
     }
     return null;
   }
@@ -357,51 +433,57 @@
     return type is KernelNamedTypeBuilder ? type.declaration : null;
   }
 
-  List<Declaration> merge(
-      KernelClassBuilder cls,
-      List<Declaration> localMembers,
-      List<Declaration> superMembers,
-      MergeKind mergeKind) {
-    final List<Declaration> mergedMembers = new List<Declaration>.filled(
-        localMembers.length + superMembers.length, null,
+  List<Declaration> merge(KernelClassBuilder cls, List<Declaration> aList,
+      List<Declaration> bList, MergeKind mergeKind) {
+    final List<Declaration> result = new List<Declaration>.filled(
+        aList.length + bList.length, null,
         growable: true);
-
-    int mergedMemberCount = 0;
-
+    int storeIndex = 0;
     int i = 0;
     int j = 0;
-    while (i < localMembers.length && j < superMembers.length) {
-      final Declaration localMember = localMembers[i];
-      final Declaration superMember = superMembers[j];
-      final int compare = compareDeclarations(localMember, superMember);
+    while (i < aList.length && j < bList.length) {
+      final Declaration a = aList[i];
+      final Declaration b = bList[j];
+      if (a.isStatic) {
+        i++;
+        continue;
+      }
+      if (b.isStatic) {
+        j++;
+        continue;
+      }
+      final int compare = compareDeclarations(a, b);
       if (compare == 0) {
-        mergedMembers[mergedMemberCount++] =
-            handleOverride(cls, localMember, superMember, mergeKind);
+        result[storeIndex++] = handleMergeConflict(cls, a, b, mergeKind);
         i++;
         j++;
       } else if (compare < 0) {
-        handleNewMember(localMember, mergeKind);
-        mergedMembers[mergedMemberCount++] = localMember;
+        handleOnlyA(a, mergeKind);
+        result[storeIndex++] = a;
         i++;
       } else {
-        handleInheritance(cls, superMember, mergeKind);
-        mergedMembers[mergedMemberCount++] = superMember;
+        handleOnlyB(cls, b, mergeKind);
+        result[storeIndex++] = b;
         j++;
       }
     }
-    while (i < localMembers.length) {
-      final Declaration localMember = localMembers[i];
-      handleNewMember(localMember, mergeKind);
-      mergedMembers[mergedMemberCount++] = localMember;
+    while (i < aList.length) {
+      final Declaration a = aList[i];
+      if (!a.isStatic) {
+        handleOnlyA(a, mergeKind);
+        result[storeIndex++] = a;
+      }
       i++;
     }
-    while (j < superMembers.length) {
-      final Declaration superMember = superMembers[j];
-      handleInheritance(cls, superMember, mergeKind);
-      mergedMembers[mergedMemberCount++] = superMember;
+    while (j < bList.length) {
+      final Declaration b = bList[j];
+      if (!b.isStatic) {
+        handleOnlyB(cls, b, mergeKind);
+        result[storeIndex++] = b;
+      }
       j++;
     }
-    return mergedMembers..length = mergedMemberCount;
+    return result..length = storeIndex;
   }
 }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 08834e4..7d20b9c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -740,15 +740,15 @@
       DartType context =
           inferrer.typeSchemaEnvironment.unfutureType(typeContext);
       if (context is InterfaceType) {
-        if (inferrer.classHierarchy
-                .isSubclassOf(inferrer.coreTypes.setClass, context.classNode) &&
+        if (inferrer.classHierarchy.isSubtypeOf(
+                context.classNode, inferrer.coreTypes.iterableClass) &&
             !inferrer.classHierarchy
-                .isSubclassOf(inferrer.coreTypes.mapClass, context.classNode)) {
+                .isSubtypeOf(context.classNode, inferrer.coreTypes.mapClass)) {
           // Set literal
           SetLiteralJudgment setLiteral = new SetLiteralJudgment([],
-              typeArgument: const ImplicitTypeArgument(),
-              isConst: node.isConst);
-          node.replaceWith(setLiteral);
+              typeArgument: const ImplicitTypeArgument(), isConst: node.isConst)
+            ..fileOffset = node.fileOffset;
+          node.parent.replaceChild(node, setLiteral);
           visitSetLiteralJudgment(setLiteral, typeContext);
           node.inferredType = setLiteral.inferredType;
           return;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
index b7372a5..06cdc67 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
@@ -8,16 +8,20 @@
     show
         Constant,
         DartType,
+        EnvironmentBoolConstant,
+        EnvironmentIntConstant,
+        EnvironmentStringConstant,
         ListConstant,
         MapConstant,
         NullConstant,
         StaticInvocation,
+        StringConstant,
         TreeNode;
 
 import 'package:kernel/transformations/constants.dart'
     show ConstantsBackend, ErrorReporter;
 
-import '../problems.dart' show unimplemented;
+import '../problems.dart' show unexpected, unimplemented;
 
 class KernelConstantsBackend extends ConstantsBackend {
   @override
@@ -40,7 +44,24 @@
     if (nativeName == 'Bool_fromEnvironment' ||
         nativeName == 'Integer_fromEnvironment' ||
         nativeName == 'String_fromEnvironment') {
-      return namedArguments['defaultValue'] ?? new NullConstant();
+      if (positionalArguments.length == 1 &&
+          positionalArguments.first is StringConstant &&
+          (namedArguments.length == 0 ||
+              (namedArguments.length == 1 &&
+                  namedArguments.containsKey('defaultValue')))) {
+        StringConstant name = positionalArguments.first;
+        Constant defaultValue =
+            namedArguments['defaultValue'] ?? new NullConstant();
+        if (nativeName == 'Bool_fromEnvironment') {
+          return new EnvironmentBoolConstant(name.value, defaultValue);
+        }
+        if (nativeName == 'Integer_fromEnvironment') {
+          return new EnvironmentIntConstant(name.value, defaultValue);
+        }
+        return new EnvironmentStringConstant(name.value, defaultValue);
+      }
+      return unexpected('valid constructor invocation', node.toString(),
+          node.fileOffset, node.location.file);
     }
     return unimplemented('constant evaluation of ${nativeName}',
         node.fileOffset, node.location.file);
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
index 4f966c7..d34ba34 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
@@ -133,9 +133,9 @@
     /// }
 
     members["index"] = new KernelFieldBuilder(null, intType, "index",
-        finalMask | hasInitializerMask, parent, charOffset);
+        finalMask | hasInitializerMask, parent, charOffset, charOffset);
     members["_name"] = new KernelFieldBuilder(null, stringType, "_name",
-        finalMask | hasInitializerMask, parent, charOffset);
+        finalMask | hasInitializerMask, parent, charOffset, charOffset);
     KernelConstructorBuilder constructorBuilder = new KernelConstructorBuilder(
         null,
         constMask,
@@ -160,6 +160,7 @@
         "values",
         constMask | staticMask | hasInitializerMask,
         parent,
+        charOffset,
         charOffset);
     members["values"] = valuesBuilder;
     KernelProcedureBuilder toStringBuilder = new KernelProcedureBuilder(
@@ -218,6 +219,7 @@
             name,
             constMask | staticMask | hasInitializerMask,
             parent,
+            enumConstantInfo.charOffset,
             enumConstantInfo.charOffset);
         metadataCollector?.setDocumentationComment(
             fieldBuilder.target, documentationComment);
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
index 9870fb2..adf0f98 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
@@ -33,10 +33,11 @@
   final KernelTypeBuilder type;
 
   KernelFieldBuilder(this.metadata, this.type, String name, int modifiers,
-      Declaration compilationUnit, int charOffset)
+      Declaration compilationUnit, int charOffset, int charEndOffset)
       : field = new ShadowField(null, type == null,
             fileUri: compilationUnit?.fileUri)
-          ..fileOffset = charOffset,
+          ..fileOffset = charOffset
+          ..fileEndOffset = charEndOffset,
         super(name, modifiers, compilationUnit, charOffset);
 
   void set initializer(Expression value) {
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
index 3f46eb3..96f2460 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -39,6 +39,8 @@
         VariableDeclaration,
         VoidType;
 
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+
 import 'package:kernel/clone.dart' show CloneVisitor;
 
 import 'package:kernel/src/bounds_checks.dart'
@@ -597,13 +599,14 @@
       KernelTypeBuilder type,
       String name,
       int charOffset,
+      int charEndOffset,
       Token initializerTokenForInference,
       bool hasInitializer) {
     if (hasInitializer) {
       modifiers |= hasInitializerMask;
     }
     KernelFieldBuilder field = new KernelFieldBuilder(
-        metadata, type, name, modifiers, this, charOffset);
+        metadata, type, name, modifiers, this, charOffset, charEndOffset);
     addBuilder(name, field, charOffset);
     if (initializerTokenForInference != null) {
       assert(type == null);
@@ -1651,6 +1654,7 @@
   void checkBoundsInMethodInvocation(
       DartType receiverType,
       TypeEnvironment typeEnvironment,
+      ClassHierarchy hierarchy,
       TypeInferrerImpl typeInferrer,
       Name name,
       Member interfaceTarget,
@@ -1668,14 +1672,13 @@
       return;
     }
     // TODO(dmitryas): Find a better way than relying on [interfaceTarget].
-    Member method = typeEnvironment.hierarchy.getDispatchTarget(klass, name) ??
-        interfaceTarget;
+    Member method = hierarchy.getDispatchTarget(klass, name) ?? interfaceTarget;
     if (method == null || method is! Procedure) {
       return;
     }
     if (klass != method.enclosingClass) {
-      Supertype parent = typeEnvironment.hierarchy
-          .getClassAsInstanceOf(klass, method.enclosingClass);
+      Supertype parent =
+          hierarchy.getClassAsInstanceOf(klass, method.enclosingClass);
       klass = method.enclosingClass;
       receiverTypeArguments = parent.typeArguments;
     }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 39ea072..75f57a8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -44,7 +44,7 @@
 import 'package:kernel/type_environment.dart' show TypeEnvironment;
 
 import 'package:kernel/transformations/constants.dart' as constants
-    show transformLibraries;
+    show SimpleErrorReporter, transformLibraries;
 
 import '../../api_prototype/file_system.dart' show FileSystem;
 
@@ -754,7 +754,8 @@
           new KernelConstantsBackend(),
           loader.coreTypes,
           new TypeEnvironment(loader.coreTypes, loader.hierarchy,
-              legacyMode: false));
+              legacyMode: false),
+          const constants.SimpleErrorReporter());
       ticker.logMs("Evaluated constants");
     }
     backendTarget.performModularTransformationsOnLibraries(
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
index 241bb28..c427799 100644
--- 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
@@ -36,7 +36,7 @@
         super(name, bound, compilationUnit, charOffset);
 
   KernelTypeVariableBuilder.fromKernel(
-      TypeParameter parameter, KernelLibraryBuilder compilationUnit)
+      TypeParameter parameter, LibraryBuilder compilationUnit)
       : actualParameter = parameter,
         super(parameter.name, null, compilationUnit, parameter.fileOffset);
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
index 049af7e..38fa92c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
@@ -14,6 +14,9 @@
         DartType,
         DoubleConstant,
         DynamicType,
+        EnvironmentBoolConstant,
+        EnvironmentIntConstant,
+        EnvironmentStringConstant,
         Field,
         FunctionType,
         InvalidType,
@@ -32,6 +35,7 @@
         TypeLiteralConstant,
         TypeParameter,
         TypeParameterType,
+        UnevaluatedConstant,
         VoidType;
 
 import 'package:kernel/visitor.dart' show ConstantVisitor, DartTypeVisitor;
@@ -41,6 +45,8 @@
 import '../fasta_codes.dart'
     show Message, templateTypeOrigin, templateTypeOriginWithFileUri;
 
+import '../problems.dart' show unsupported;
+
 /// A pretty-printer for Kernel types and constants with the ability to label
 /// raw types with numeric markers in Dart comments (e.g. `/*1*/`) to
 /// distinguish different types with the same name. This is used in diagnostic
@@ -306,6 +312,22 @@
   void visitTypeLiteralConstant(TypeLiteralConstant node) {
     node.type.accept(this);
   }
+
+  void visitEnvironmentBoolConstant(EnvironmentBoolConstant node) {
+    unsupported('printing unevaluated constants', -1, null);
+  }
+
+  void visitEnvironmentIntConstant(EnvironmentIntConstant node) {
+    unsupported('printing unevaluated constants', -1, null);
+  }
+
+  void visitEnvironmentStringConstant(EnvironmentStringConstant node) {
+    unsupported('printing unevaluated constants', -1, null);
+  }
+
+  void visitUnevaluatedConstant(UnevaluatedConstant node) {
+    unsupported('printing unevaluated constants', -1, null);
+  }
 }
 
 class LabeledClassName {
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index 2063d4d..6d670a1 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -397,7 +397,9 @@
   /// Type arguments were seen during analysis.
   final TypeParamOrArgInfo typeArguments;
 
-  /// The token before the trailing question mark or `null` if none.
+  /// The token before the trailing question mark or `null` if either
+  /// 1) there is no trailing question mark, or
+  /// 2) the trailing question mark is not part of the type reference.
   Token beforeQuestionMark;
 
   /// The last token in the type reference.
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 72901f5..d5c1cd8 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -1305,6 +1305,7 @@
     List<FieldInfo> fieldInfos = new List<FieldInfo>(count);
     bool isParserRecovery = false;
     for (int i = count - 1; i != -1; i--) {
+      int charEndOffset = pop();
       Token beforeLast = pop();
       Token initializerTokenForInference = pop();
       int charOffset = pop();
@@ -1312,8 +1313,8 @@
       if (name is ParserRecovery) {
         isParserRecovery = true;
       } else {
-        fieldInfos[i] = new FieldInfo(
-            name, charOffset, initializerTokenForInference, beforeLast);
+        fieldInfos[i] = new FieldInfo(name, charOffset,
+            initializerTokenForInference, beforeLast, charEndOffset);
       }
     }
     return isParserRecovery ? null : fieldInfos;
@@ -1515,6 +1516,7 @@
     }
     push(assignmentOperator.next);
     push(beforeLast);
+    push(token.charOffset);
   }
 
   @override
@@ -1522,6 +1524,7 @@
     debugEvent("NoFieldInitializer");
     push(NullValue.FieldInitializer);
     push(NullValue.FieldInitializer);
+    push(token.charOffset);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 1f1afc5..2fa5d91 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -389,6 +389,7 @@
       T type,
       String name,
       int charOffset,
+      int charEndOffset,
       Token initializerTokenForInference,
       bool hasInitializer);
 
@@ -397,6 +398,7 @@
     for (FieldInfo info in fieldInfos) {
       String name = info.name;
       int charOffset = info.charOffset;
+      int charEndOffset = info.charEndOffset;
       bool hasInitializer = info.initializerTokenForInference != null;
       Token initializerTokenForInference =
           type != null || legacyMode ? null : info.initializerTokenForInference;
@@ -404,8 +406,16 @@
         Token beforeLast = info.beforeLast;
         beforeLast.setNext(new Token.eof(beforeLast.next.offset));
       }
-      addField(documentationComment, metadata, modifiers, type, name,
-          charOffset, initializerTokenForInference, hasInitializer);
+      addField(
+          documentationComment,
+          metadata,
+          modifiers,
+          type,
+          name,
+          charOffset,
+          charEndOffset,
+          initializerTokenForInference,
+          hasInitializer);
     }
   }
 
@@ -1001,7 +1011,8 @@
   final int charOffset;
   final Token initializerTokenForInference;
   final Token beforeLast;
+  final int charEndOffset;
 
   const FieldInfo(this.name, this.charOffset, this.initializerTokenForInference,
-      this.beforeLast);
+      this.beforeLast, this.charEndOffset);
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart b/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart
index b0f3d1e..3c999dc 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart
@@ -33,7 +33,8 @@
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/src/hierarchy_based_type_environment.dart'
+    show HierarchyBasedTypeEnvironment;
 
 import '../../base/instrumentation.dart'
     show
@@ -675,7 +676,7 @@
 class InterfaceResolver {
   final TypeInferenceEngine _typeInferenceEngine;
 
-  final TypeEnvironment _typeEnvironment;
+  final HierarchyBasedTypeEnvironment _typeEnvironment;
 
   final Instrumentation _instrumentation;
 
@@ -1244,8 +1245,8 @@
   /// Determines the appropriate substitution to translate type parameters
   /// mentioned in the given [candidate] to type parameters on [class_].
   Substitution _substitutionFor(Procedure candidate, Class class_) {
-    return Substitution.fromInterfaceType(_typeEnvironment.hierarchy
-        .getTypeAsInstanceOf(class_.thisType, candidate.enclosingClass));
+    return Substitution.fromInterfaceType(_typeEnvironment.getTypeAsInstanceOf(
+        class_.thisType, candidate.enclosingClass));
   }
 
   /// Executes [callback] once for each uniquely named member of [candidates].
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 23402c5..91df6f16 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -181,7 +181,7 @@
     // above is irrelevant; we just need to find the matched superclass,
     // substitute, and then iterate through type variables.
     var matchingSupertypeOfSubtype =
-        environment.hierarchy.getTypeAsInstanceOf(subtype, supertype.classNode);
+        environment.getTypeAsInstanceOf(subtype, supertype.classNode);
     if (matchingSupertypeOfSubtype == null) return false;
     for (int i = 0; i < supertype.classNode.typeParameters.length; i++) {
       if (!_isSubtypeMatch(matchingSupertypeOfSubtype.typeArguments[i],
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 6e93c77..393c70b 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -1607,6 +1607,7 @@
       library.checkBoundsInMethodInvocation(
           actualReceiverType,
           typeSchemaEnvironment,
+          classHierarchy,
           this,
           actualMethodName,
           interfaceTarget,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index 1efa0e5..3aa0279 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -23,7 +23,8 @@
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/src/hierarchy_based_type_environment.dart'
+    show HierarchyBasedTypeEnvironment;
 
 import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
 
@@ -89,7 +90,7 @@
       '${typeSchemaToString(lower)} <: <type> <: ${typeSchemaToString(upper)}';
 }
 
-class TypeSchemaEnvironment extends TypeEnvironment {
+class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment {
   TypeSchemaEnvironment(CoreTypes coreTypes, ClassHierarchy hierarchy)
       : super(coreTypes, hierarchy);
 
diff --git a/pkg/front_end/lib/src/fasta/util/error_reporter_file_copier.dart b/pkg/front_end/lib/src/fasta/util/error_reporter_file_copier.dart
new file mode 100644
index 0000000..4cddf72
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/error_reporter_file_copier.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show Directory, File, GZipCodec;
+
+Uri saveAsGzip(List<int> data, String filename) {
+  // TODO(jensj): This should be done via the FileSystem instead, but it
+  // currently doesn't support writing.
+  GZipCodec gZipCodec = new GZipCodec();
+  List<int> gzippedInitializedFromData = gZipCodec.encode(data);
+  Directory tempDir = Directory.systemTemp.createTempSync("$filename");
+  File file = new File("${tempDir.path}/${filename}.gz");
+  file.writeAsBytesSync(gzippedInitializedFromData);
+  return file.uri;
+}
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index eb90f60..a885932 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1587,9 +1587,9 @@
         commas, for example, --fatal=errors,warnings.
 
       --enable-experiment=<flag>
-      --disable-experiment=<flag>
         Enable or disable an experimental flag, used to guard features currently
-        in development. Multiple experiments can be separated by commas.
+        in development. Prefix an experiment name with 'no-' to disable it.
+        Multiple experiments can be separated by commas.
 
 FastaCLIArgumentRequired:
   template: "Expected value after '#name'."
@@ -2978,13 +2978,47 @@
   severity: IGNORED
 
 InitializeFromDillNotSelfContained:
-  template: "Tried to initialize from a previous compilation (#string), but the file was not self-contained. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new."
+  template: |
+    Tried to initialize from a previous compilation (#string), but the file was not self-contained. This might be a bug.
+
+    The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+    If you are comfortable with it, it would improve the chances of fixing any bug if you included the file #uri in your error report, but be aware that this file includes your source code.
+    Either way, you should probably delete the file so it doesn't use unnecessary disk space.
+
+  severity: WARNING
+  frontendInternal: true
+  external: test/incremental_load_from_invalid_dill_test.dart
+
+InitializeFromDillNotSelfContainedNoDump:
+  template: |
+    Tried to initialize from a previous compilation (#string), but the file was not self-contained. This might be a bug.
+
+    The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+
   severity: WARNING
   frontendInternal: true
   external: test/incremental_load_from_invalid_dill_test.dart
 
 InitializeFromDillUnknownProblem:
-  template: "Tried to initialize from a previous compilation (#string), but couldn't. Error message was '#string2'. This might be a bug. The Dart team would greatly appreciate if you would take a moment to report this problem at http://dartbug.com/new."
+  template: |
+    Tried to initialize from a previous compilation (#string), but couldn't.
+    Error message was '#string2'. This might be a bug.
+
+    The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+    If you are comfortable with it, it would improve the chances of fixing any bug if you included the file #uri in your error report, but be aware that this file includes your source code.
+    Either way, you should probably delete the file so it doesn't use unnecessary disk space.
+
+  severity: WARNING
+  frontendInternal: true
+  external: test/incremental_load_from_invalid_dill_test.dart
+
+InitializeFromDillUnknownProblemNoDump:
+  template: |
+    Tried to initialize from a previous compilation (#string), but couldn't.
+    Error message was '#string2'. This might be a bug.
+
+    The Dart team would greatly appreciate it if you would take a moment to report this problem at http://dartbug.com/new.
+
   severity: WARNING
   frontendInternal: true
   external: test/incremental_load_from_invalid_dill_test.dart
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 8a89ddc..2934b93 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -36,6 +36,9 @@
 import 'package:front_end/src/api_prototype/compiler_options.dart'
     show CompilerOptions, DiagnosticMessage;
 
+import 'package:front_end/src/api_prototype/experimental_flags.dart'
+    show ExperimentalFlag;
+
 import 'package:front_end/src/api_prototype/standard_file_system.dart'
     show StandardFileSystem;
 
@@ -118,6 +121,7 @@
   final Uri vm;
   final bool legacyMode;
   final bool onlyCrashes;
+  final bool enableSetLiterals;
   final Map<Component, KernelTarget> componentToTarget =
       <Component, KernelTarget>{};
   final Map<Component, StringBuffer> componentToDiagnostics =
@@ -135,6 +139,7 @@
       this.legacyMode,
       this.platformBinaries,
       this.onlyCrashes,
+      this.enableSetLiterals,
       bool ignoreExpectations,
       bool updateExpectations,
       bool updateComments,
@@ -211,13 +216,17 @@
     Uri sdk = Uri.base.resolve("sdk/");
     Uri vm = Uri.base.resolveUri(new Uri.file(Platform.resolvedExecutable));
     Uri packages = Uri.base.resolve(".packages");
+    bool enableSetLiterals = environment["enableSetLiterals"] != "false";
     var options = new ProcessedOptions(
         options: new CompilerOptions()
           ..onDiagnostic = (DiagnosticMessage message) {
             throw message.plainTextFormatted.join("\n");
           }
           ..sdkRoot = sdk
-          ..packagesFileUri = packages);
+          ..packagesFileUri = packages
+          ..experimentalFlags = <ExperimentalFlag, bool>{
+            ExperimentalFlag.setLiterals: enableSetLiterals
+          });
     UriTranslator uriTranslator = await options.getUriTranslator();
     bool legacyMode = environment.containsKey(LEGACY_MODE);
     bool onlyCrashes = environment["onlyCrashes"] == "true";
@@ -238,6 +247,7 @@
             ? computePlatformBinariesLocation(forceBuildDir: true)
             : Uri.base.resolve(platformBinaries),
         onlyCrashes,
+        enableSetLiterals,
         ignoreExpectations,
         updateExpectations,
         updateComments,
@@ -302,6 +312,9 @@
               errors.write("\n\n");
             }
             errors.writeAll(message.plainTextFormatted, "\n");
+          }
+          ..experimentalFlags = <ExperimentalFlag, bool>{
+            ExperimentalFlag.setLiterals: context.enableSetLiterals
           },
         inputs: <Uri>[description.uri]);
     return await CompilerContext.runWithOptions(options, (_) async {
diff --git a/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart b/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
index 9ae979a..cf270cb 100644
--- a/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
@@ -75,7 +75,7 @@
     stopwatch.reset();
     bool initializeResult = await initializedCompile(
         dart2jsUrl, fullDillFromInitialized, initializeWith, [invalidateUri]);
-    Expect.equals(initializeExpect, initializeResult);
+    Expect.equals(initializeResult, initializeExpect);
     print("Initialized compile(s) from ${initializeWith.pathSegments.last} "
         "took ${stopwatch.elapsedMilliseconds} ms");
 
diff --git a/pkg/front_end/test/incremental_load_from_invalid_dill_test.dart b/pkg/front_end/test/incremental_load_from_invalid_dill_test.dart
index 8167690..9dc2941 100644
--- a/pkg/front_end/test/incremental_load_from_invalid_dill_test.dart
+++ b/pkg/front_end/test/incremental_load_from_invalid_dill_test.dart
@@ -29,7 +29,9 @@
     show
         Code,
         codeInitializeFromDillNotSelfContained,
-        codeInitializeFromDillUnknownProblem;
+        codeInitializeFromDillNotSelfContainedNoDump,
+        codeInitializeFromDillUnknownProblem,
+        codeInitializeFromDillUnknownProblemNoDump;
 
 import 'package:front_end/src/fasta/incremental_compiler.dart'
     show IncrementalCompiler;
@@ -63,13 +65,15 @@
   CompilerOptions options;
 
   compileExpectInitializeFailAndSpecificWarning(
-      Code expectedWarningCode) async {
+      Code expectedWarningCode, bool writeFileOnCrashReport) async {
     errorMessages.clear();
     warningMessages.clear();
-    IncrementalCompiler compiler = new IncrementalCompiler(
-        new CompilerContext(
-            new ProcessedOptions(options: options, inputs: [entryPoint])),
-        initializeFrom);
+    options.writeFileOnCrashReport = writeFileOnCrashReport;
+    DeleteTempFilesIncrementalCompiler compiler =
+        new DeleteTempFilesIncrementalCompiler(
+            new CompilerContext(
+                new ProcessedOptions(options: options, inputs: [entryPoint])),
+            initializeFrom);
     await compiler.computeDelta();
     if (compiler.initializedFromDill) {
       Expect.fail("Expected to not be able to initialized from dill, but did.");
@@ -166,13 +170,28 @@
 
     // Initializing from partial dill should not be ok.
     await compileExpectInitializeFailAndSpecificWarning(
-        codeInitializeFromDillNotSelfContained);
+        codeInitializeFromDillNotSelfContained, true);
+    await compileExpectInitializeFailAndSpecificWarning(
+        codeInitializeFromDillNotSelfContainedNoDump, false);
 
     // Create a invalid dill file to load from: Should not be ok.
     data = new List<int>.filled(42, 42);
     fs.entityForUri(initializeFrom).writeAsBytesSync(data);
     await compileExpectInitializeFailAndSpecificWarning(
-        codeInitializeFromDillUnknownProblem);
+        codeInitializeFromDillUnknownProblem, true);
+    await compileExpectInitializeFailAndSpecificWarning(
+        codeInitializeFromDillUnknownProblemNoDump, false);
+  }
+}
+
+class DeleteTempFilesIncrementalCompiler extends IncrementalCompiler {
+  DeleteTempFilesIncrementalCompiler(CompilerContext context,
+      [Uri initializeFromDillUri])
+      : super(context, initializeFromDillUri);
+
+  void recordTemporaryFileForTesting(Uri uri) {
+    File f = new File.fromUri(uri);
+    if (f.existsSync()) f.deleteSync();
   }
 }
 
diff --git a/pkg/front_end/testcases/abstract_members.dart b/pkg/front_end/testcases/abstract_members.dart
index 00f4f14..058cbe9 100644
--- a/pkg/front_end/testcases/abstract_members.dart
+++ b/pkg/front_end/testcases/abstract_members.dart
@@ -38,4 +38,21 @@
   cMethod() {}
 }
 
+// This class should have no errors, as it has a non-trivial noSuchMethod.
+class MyMock1 extends B {
+  noSuchMethod(_) => null;
+}
+
+// This class should have no errors, as the abstract method doesn't override
+// the non-trivial noSuchMethod inherited from MyMock1.
+class MyMock2 extends MyMock1 {
+  noSuchMethod(_);
+}
+
+// This class should have an error, the abstract method isn't considered
+// non-trivial.
+class MyMock3 extends B {
+  noSuchMethod(_);
+}
+
 main() {}
diff --git a/pkg/front_end/testcases/abstract_members.dart.legacy.expect b/pkg/front_end/testcases/abstract_members.dart.legacy.expect
index 3ac995d..0c85dd2 100644
--- a/pkg/front_end/testcases/abstract_members.dart.legacy.expect
+++ b/pkg/front_end/testcases/abstract_members.dart.legacy.expect
@@ -12,8 +12,12 @@
 //
 // pkg/front_end/testcases/abstract_members.dart:33:7: Error: The non-abstract class 'MyClass' is missing implementations for these members:
 //  - A.abstractMethod
-//  - A.property3=
 //  - A.property1=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
 // Try to either
 //  - provide an implementation,
 //  - inherit an implementation from a superclass or mixin,
@@ -25,12 +29,66 @@
 // pkg/front_end/testcases/abstract_members.dart:21:3: Context: 'A.abstractMethod' is defined here.
 //   abstractMethod();
 //   ^^^^^^^^^^^^^^
-// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'A.property3=' is defined here.
-//   void set property3(_);
-//            ^^^^^^^^^
 // pkg/front_end/testcases/abstract_members.dart:22:12: Context: 'A.property1=' is defined here.
 //   void set property1(_);
 //            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'A.property3=' is defined here.
+//   void set property3(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:6:8: Context: 'Interface1.interfaceMethod1' is defined here.
+//   void interfaceMethod1() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:12:7: Context: 'Interface2.interfaceMethod1' is defined here.
+//   var interfaceMethod1;
+//       ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:10:8: Context: 'Interface2.interfaceMethod2' is defined here.
+//   void interfaceMethod2() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:16:8: Context: 'Interface3.interfaceMethod3' is defined here.
+//   void interfaceMethod3() {}
+//        ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/abstract_members.dart:54:7: Error: The non-abstract class 'MyMock3' is missing implementations for these members:
+//  - A.abstractMethod
+//  - A.property1=
+//  - A.property2=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+//
+// class MyMock3 extends B {
+//       ^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:21:3: Context: 'A.abstractMethod' is defined here.
+//   abstractMethod();
+//   ^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:22:12: Context: 'A.property1=' is defined here.
+//   void set property1(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:23:12: Context: 'A.property2=' is defined here.
+//   void set property2(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'A.property3=' is defined here.
+//   void set property3(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:6:8: Context: 'Interface1.interfaceMethod1' is defined here.
+//   void interfaceMethod1() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:12:7: Context: 'Interface2.interfaceMethod1' is defined here.
+//   var interfaceMethod1;
+//       ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:10:8: Context: 'Interface2.interfaceMethod2' is defined here.
+//   void interfaceMethod2() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:16:8: Context: 'Interface3.interfaceMethod3' is defined here.
+//   void interfaceMethod3() {}
+//        ^^^^^^^^^^^^^^^^
 
 // Unhandled errors:
 //
@@ -40,8 +98,12 @@
 //
 // pkg/front_end/testcases/abstract_members.dart:33:7: Error: The non-abstract class 'MyClass' is missing implementations for these members:
 //  - A.abstractMethod
-//  - A.property3=
 //  - A.property1=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
 // Try to either
 //  - provide an implementation,
 //  - inherit an implementation from a superclass or mixin,
@@ -50,6 +112,24 @@
 // 
 // class MyClass extends B {
 //       ^^^^^^^
+//
+// pkg/front_end/testcases/abstract_members.dart:54:7: Error: The non-abstract class 'MyMock3' is missing implementations for these members:
+//  - A.abstractMethod
+//  - A.property1=
+//  - A.property2=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+// 
+// class MyMock3 extends B {
+//       ^^^^^^^
 
 library;
 import self as self;
@@ -110,4 +190,49 @@
   no-such-method-forwarder set property1(dynamic _) → void
     return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
 }
+class MyMock1 extends self::B {
+  synthetic constructor •() → self::MyMock1
+    : super self::B::•()
+    ;
+  method noSuchMethod(dynamic _) → dynamic
+    return null;
+  no-such-method-forwarder method interfaceMethod2() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod2, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#abstractMethod, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method interfaceMethod3() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod3, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
+class MyMock2 extends self::MyMock1 {
+  synthetic constructor •() → self::MyMock2
+    : super self::MyMock1::•()
+    ;
+  abstract method noSuchMethod(dynamic _) → dynamic;
+}
+class MyMock3 extends self::B {
+  synthetic constructor •() → self::MyMock3
+    : super self::B::•()
+    ;
+  abstract method noSuchMethod(dynamic _) → dynamic;
+  no-such-method-forwarder get interfaceMethod1() → dynamic
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/abstract_members.dart.legacy.transformed.expect b/pkg/front_end/testcases/abstract_members.dart.legacy.transformed.expect
index 1e1ebac..7e489f3 100644
--- a/pkg/front_end/testcases/abstract_members.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/abstract_members.dart.legacy.transformed.expect
@@ -6,8 +6,12 @@
 //
 // pkg/front_end/testcases/abstract_members.dart:33:7: Error: The non-abstract class 'MyClass' is missing implementations for these members:
 //  - A.abstractMethod
-//  - A.property3=
 //  - A.property1=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
 // Try to either
 //  - provide an implementation,
 //  - inherit an implementation from a superclass or mixin,
@@ -16,6 +20,24 @@
 // 
 // class MyClass extends B {
 //       ^^^^^^^
+//
+// pkg/front_end/testcases/abstract_members.dart:54:7: Error: The non-abstract class 'MyMock3' is missing implementations for these members:
+//  - A.abstractMethod
+//  - A.property1=
+//  - A.property2=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+// 
+// class MyMock3 extends B {
+//       ^^^^^^^
 
 library;
 import self as self;
@@ -76,4 +98,49 @@
   no-such-method-forwarder set property1(dynamic _) → void
     return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
 }
+class MyMock1 extends self::B {
+  synthetic constructor •() → self::MyMock1
+    : super self::B::•()
+    ;
+  method noSuchMethod(dynamic _) → dynamic
+    return null;
+  no-such-method-forwarder method interfaceMethod2() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod2, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#abstractMethod, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method interfaceMethod3() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod3, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
+class MyMock2 extends self::MyMock1 {
+  synthetic constructor •() → self::MyMock2
+    : super self::MyMock1::•()
+    ;
+  abstract method noSuchMethod(dynamic _) → dynamic;
+}
+class MyMock3 extends self::B {
+  synthetic constructor •() → self::MyMock3
+    : super self::B::•()
+    ;
+  abstract method noSuchMethod(dynamic _) → dynamic;
+  no-such-method-forwarder get interfaceMethod1() → dynamic
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/abstract_members.dart.outline.expect b/pkg/front_end/testcases/abstract_members.dart.outline.expect
index 1c95548..e2bf105 100644
--- a/pkg/front_end/testcases/abstract_members.dart.outline.expect
+++ b/pkg/front_end/testcases/abstract_members.dart.outline.expect
@@ -12,8 +12,12 @@
 //
 // pkg/front_end/testcases/abstract_members.dart:33:7: Error: The non-abstract class 'MyClass' is missing implementations for these members:
 //  - A.abstractMethod
-//  - A.property3=
 //  - A.property1=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
 // Try to either
 //  - provide an implementation,
 //  - inherit an implementation from a superclass or mixin,
@@ -25,12 +29,66 @@
 // pkg/front_end/testcases/abstract_members.dart:21:3: Context: 'A.abstractMethod' is defined here.
 //   abstractMethod();
 //   ^^^^^^^^^^^^^^
-// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'A.property3=' is defined here.
-//   void set property3(_);
-//            ^^^^^^^^^
 // pkg/front_end/testcases/abstract_members.dart:22:12: Context: 'A.property1=' is defined here.
 //   void set property1(_);
 //            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'A.property3=' is defined here.
+//   void set property3(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:6:8: Context: 'Interface1.interfaceMethod1' is defined here.
+//   void interfaceMethod1() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:12:7: Context: 'Interface2.interfaceMethod1' is defined here.
+//   var interfaceMethod1;
+//       ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:10:8: Context: 'Interface2.interfaceMethod2' is defined here.
+//   void interfaceMethod2() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:16:8: Context: 'Interface3.interfaceMethod3' is defined here.
+//   void interfaceMethod3() {}
+//        ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/abstract_members.dart:54:7: Error: The non-abstract class 'MyMock3' is missing implementations for these members:
+//  - A.abstractMethod
+//  - A.property1=
+//  - A.property2=
+//  - A.property3=
+//  - Interface1.interfaceMethod1
+//  - Interface2.interfaceMethod1
+//  - Interface2.interfaceMethod2
+//  - Interface3.interfaceMethod3
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+//
+// class MyMock3 extends B {
+//       ^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:21:3: Context: 'A.abstractMethod' is defined here.
+//   abstractMethod();
+//   ^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:22:12: Context: 'A.property1=' is defined here.
+//   void set property1(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:23:12: Context: 'A.property2=' is defined here.
+//   void set property2(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'A.property3=' is defined here.
+//   void set property3(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:6:8: Context: 'Interface1.interfaceMethod1' is defined here.
+//   void interfaceMethod1() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:12:7: Context: 'Interface2.interfaceMethod1' is defined here.
+//   var interfaceMethod1;
+//       ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:10:8: Context: 'Interface2.interfaceMethod2' is defined here.
+//   void interfaceMethod2() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:16:8: Context: 'Interface3.interfaceMethod3' is defined here.
+//   void interfaceMethod3() {}
+//        ^^^^^^^^^^^^^^^^
 
 library;
 import self as self;
@@ -95,5 +153,47 @@
   no-such-method-forwarder set property1(dynamic _) → void
     return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
 }
+class MyMock1 extends self::B {
+  synthetic constructor •() → self::MyMock1
+    ;
+  method noSuchMethod(dynamic _) → dynamic
+    ;
+  no-such-method-forwarder method interfaceMethod2() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod2, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#abstractMethod, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method interfaceMethod3() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod3, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
+class MyMock2 extends self::MyMock1 {
+  synthetic constructor •() → self::MyMock2
+    ;
+  abstract method noSuchMethod(dynamic _) → dynamic;
+}
+class MyMock3 extends self::B {
+  synthetic constructor •() → self::MyMock3
+    ;
+  abstract method noSuchMethod(dynamic _) → dynamic;
+  no-such-method-forwarder get interfaceMethod1() → dynamic
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/abstract_members.dart.strong.expect b/pkg/front_end/testcases/abstract_members.dart.strong.expect
index 81ff760..c568386 100644
--- a/pkg/front_end/testcases/abstract_members.dart.strong.expect
+++ b/pkg/front_end/testcases/abstract_members.dart.strong.expect
@@ -51,6 +51,52 @@
 // pkg/front_end/testcases/abstract_members.dart:22:12: Context: 'property1=' is defined here.
 //   void set property1(_);
 //            ^^^^^^^^^
+//
+// pkg/front_end/testcases/abstract_members.dart:54:7: Error: The non-abstract class 'MyMock3' is missing implementations for these members:
+//  - 'interfaceMethod2'
+//  - 'abstractMethod'
+//  - 'interfaceMethod1'
+//  - 'interfaceMethod1'
+//  - 'interfaceMethod3'
+//  - 'property3='
+//  - 'interfaceMethod1='
+//  - 'property1='
+//  - 'property2='
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+//
+// class MyMock3 extends B {
+//       ^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:10:8: Context: 'interfaceMethod2' is defined here.
+//   void interfaceMethod2() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:21:3: Context: 'abstractMethod' is defined here.
+//   abstractMethod();
+//   ^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:6:8: Context: 'interfaceMethod1' is defined here.
+//   void interfaceMethod1() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:12:7: Context: 'interfaceMethod1' is defined here.
+//   var interfaceMethod1;
+//       ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:16:8: Context: 'interfaceMethod3' is defined here.
+//   void interfaceMethod3() {}
+//        ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:24:12: Context: 'property3=' is defined here.
+//   void set property3(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:12:7: Context: 'interfaceMethod1=' is defined here.
+//   var interfaceMethod1;
+//       ^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:22:12: Context: 'property1=' is defined here.
+//   void set property1(_);
+//            ^^^^^^^^^
+// pkg/front_end/testcases/abstract_members.dart:23:12: Context: 'property2=' is defined here.
+//   void set property2(_);
+//            ^^^^^^^^^
 
 // Unhandled errors:
 //
@@ -75,6 +121,25 @@
 // 
 // class MyClass extends B {
 //       ^^^^^^^
+//
+// pkg/front_end/testcases/abstract_members.dart:54:7: Error: The non-abstract class 'MyMock3' is missing implementations for these members:
+//  - 'interfaceMethod2'
+//  - 'abstractMethod'
+//  - 'interfaceMethod1'
+//  - 'interfaceMethod1'
+//  - 'interfaceMethod3'
+//  - 'property3='
+//  - 'interfaceMethod1='
+//  - 'property1='
+//  - 'property2='
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+// 
+// class MyMock3 extends B {
+//       ^^^^^^^
 
 library;
 import self as self;
@@ -135,4 +200,49 @@
   no-such-method-forwarder set property1(dynamic _) → void
     return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
 }
+class MyMock1 extends self::B {
+  synthetic constructor •() → self::MyMock1
+    : super self::B::•()
+    ;
+  method noSuchMethod(core::Invocation _) → dynamic
+    return null;
+  no-such-method-forwarder method interfaceMethod2() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod2, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#abstractMethod, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder method interfaceMethod3() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod3, 0, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
+class MyMock2 extends self::MyMock1 {
+  synthetic constructor •() → self::MyMock2
+    : super self::MyMock1::•()
+    ;
+  abstract method noSuchMethod(core::Invocation _) → dynamic;
+}
+class MyMock3 extends self::B {
+  synthetic constructor •() → self::MyMock3
+    : super self::B::•()
+    ;
+  abstract method noSuchMethod(core::Invocation _) → dynamic;
+  no-such-method-forwarder get interfaceMethod1() → dynamic
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+  no-such-method-forwarder set property3(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property1(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+  no-such-method-forwarder set property2(dynamic _) → void
+    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/incremental_bulk_compiler_full.status b/pkg/front_end/testcases/incremental_bulk_compiler_full.status
index 3c112db..9ceffba 100644
--- a/pkg/front_end/testcases/incremental_bulk_compiler_full.status
+++ b/pkg/front_end/testcases/incremental_bulk_compiler_full.status
@@ -9,6 +9,5 @@
 language_2/mixin_type_parameter_inference_error_test: Crash # non-identical '#errors'
 language_2/part_of_multiple_libs_test: Crash # missing "#errors"
 language_2/part_refers_to_core_library_test: Crash # non-identical '#errors'
-language_2/regress_27957_test: Crash # isSynthetic becomes false on C1 SuperInitializer.
 language_2/script1_negative_test: Crash # missing "#errors", missing empty library that shouldn't have been there in the first place
 language_2/script2_negative_test: Crash # missing "#errors", missing empty library that shouldn't have been there in the first place
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart
index 3796335..aafc9ff 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart
@@ -12,16 +12,16 @@
 }
 
 Stream<List<int>> foo() async* {
-  yield /*@typeArgs=int*/ [];
+  yield new /*@typeArgs=int*/ List();
   yield /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ MyStream();
-  yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic*/ [];
+  yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
   yield* new /*@typeArgs=List<int>*/ MyStream();
 }
 
 Iterable<Map<int, int>> bar() sync* {
-  yield /*@typeArgs=int, int*/ {};
+  yield new /*@typeArgs=int, int*/ Map();
   yield /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
-  yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic, dynamic*/ {};
+  yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic, dynamic*/ Map();
   yield* new /*@typeArgs=Map<int, int>*/ List();
 }
 
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.expect
index bbe604f..4a22da5 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.expect
@@ -8,15 +8,15 @@
     return null;
 }
 static method foo() → asy::Stream<core::List<core::int>> async* {
-  yield<dynamic>[];
+  yield core::List::•<dynamic>();
   yield self::MyStream::•<dynamic>();
-  yield*<dynamic>[];
+  yield* core::List::•<dynamic>();
   yield* self::MyStream::•<dynamic>();
 }
 static method bar() → core::Iterable<core::Map<core::int, core::int>> sync* {
-  yield<dynamic, dynamic>{};
+  yield core::Map::•<dynamic, dynamic>();
   yield core::List::•<dynamic>();
-  yield*<dynamic, dynamic>{};
+  yield* core::Map::•<dynamic, dynamic>();
   yield* core::List::•<dynamic>();
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.transformed.expect
index 3c303a7..4d12a56 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.legacy.transformed.expect
@@ -22,7 +22,7 @@
       try {
         #L1:
         {
-          if(:controller.{asy::_AsyncStarStreamController::add}(<dynamic>[]))
+          if(:controller.{asy::_AsyncStarStreamController::add}(core::_GrowableList::•<dynamic>(0)))
             return null;
           else
             [yield] null;
@@ -30,7 +30,7 @@
             return null;
           else
             [yield] null;
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(<dynamic>[]))
+          if(:controller.{asy::_AsyncStarStreamController::addStream}(core::_GrowableList::•<dynamic>(0)))
             return null;
           else
             [yield] null;
@@ -60,7 +60,7 @@
   function :sync_op(core::_SyncIterator<core::Map<core::int, core::int>> :iterator) → core::bool yielding {
     {
       {
-        :iterator.{core::_SyncIterator::_current} = <dynamic, dynamic>{};
+        :iterator.{core::_SyncIterator::_current} = core::Map::•<dynamic, dynamic>();
         [yield] true;
       }
       {
@@ -68,7 +68,7 @@
         [yield] true;
       }
       {
-        :iterator.{core::_SyncIterator::_yieldEachIterable} = <dynamic, dynamic>{};
+        :iterator.{core::_SyncIterator::_yieldEachIterable} = core::Map::•<dynamic, dynamic>();
         [yield] true;
       }
       {
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.expect
index ea7b44c..5504acd 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.expect
@@ -7,12 +7,12 @@
 //   yield /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ MyStream();
 //                                                                   ^
 //
-// pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:64: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
+// pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:68: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
 //  - 'List' is from 'dart:core'.
 //  - 'Stream' is from 'dart:async'.
 // Try changing the type of the left hand side, or casting the right hand side to 'Stream<List<int>>'.
-//   yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic*/ [];
-//                                                                ^
+//   yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
+//                                                                    ^
 //
 // pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:23:67: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Map<int, int>'.
 //  - 'List' is from 'dart:core'.
@@ -21,12 +21,12 @@
 //   yield /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
 //                                                                   ^
 //
-// pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:73: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
+// pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:77: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
 //  - 'Map' is from 'dart:core'.
 //  - 'Iterable' is from 'dart:core'.
 // Try changing the type of the left hand side, or casting the right hand side to 'Iterable<Map<int, int>>'.
-//   yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic, dynamic*/ {};
-//                                                                         ^
+//   yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic, dynamic*/ Map();
+//                                                                             ^
 
 library test;
 import self as self;
@@ -38,35 +38,35 @@
     return null;
 }
 static method foo() → asy::Stream<core::List<core::int>> async* {
-  yield<core::int>[];
+  yield core::List::•<core::int>();
   yield let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:16:67: Error: A value of type 'MyStream<dynamic>' can't be assigned to a variable of type 'List<int>'.
  - 'MyStream' is from 'pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart'.
  - 'List' is from 'dart:core'.
 Try changing the type of the left hand side, or casting the right hand side to 'List<int>'.
   yield /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ MyStream();
                                                                   ^" in self::MyStream::•<dynamic>() as{TypeError} core::List<core::int>;
-  yield* let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:64: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
+  yield* let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:68: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
  - 'List' is from 'dart:core'.
  - 'Stream' is from 'dart:async'.
 Try changing the type of the left hand side, or casting the right hand side to 'Stream<List<int>>'.
-  yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic*/ [];
-                                                               ^" in <dynamic>[] as{TypeError} asy::Stream<core::List<core::int>>;
+  yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
+                                                                   ^" in core::List::•<dynamic>() as{TypeError} asy::Stream<core::List<core::int>>;
   yield* self::MyStream::•<core::List<core::int>>();
 }
 static method bar() → core::Iterable<core::Map<core::int, core::int>> sync* {
-  yield<core::int, core::int>{};
+  yield core::Map::•<core::int, core::int>();
   yield let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:23:67: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Map<int, int>'.
  - 'List' is from 'dart:core'.
  - 'Map' is from 'dart:core'.
 Try changing the type of the left hand side, or casting the right hand side to 'Map<int, int>'.
   yield /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
                                                                   ^" in core::List::•<dynamic>() as{TypeError} core::Map<core::int, core::int>;
-  yield* let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:73: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
+  yield* let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:77: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
  - 'Map' is from 'dart:core'.
  - 'Iterable' is from 'dart:core'.
 Try changing the type of the left hand side, or casting the right hand side to 'Iterable<Map<int, int>>'.
-  yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic, dynamic*/ {};
-                                                                        ^" in <dynamic, dynamic>{} as{TypeError} core::Iterable<core::Map<core::int, core::int>>;
+  yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic, dynamic*/ Map();
+                                                                            ^" in core::Map::•<dynamic, dynamic>() as{TypeError} core::Iterable<core::Map<core::int, core::int>>;
   yield* core::List::•<core::Map<core::int, core::int>>();
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect
index 85ffbbc7..4ff259f 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect
@@ -22,7 +22,7 @@
       try {
         #L1:
         {
-          if(:controller.{asy::_AsyncStarStreamController::add}(<core::int>[]))
+          if(:controller.{asy::_AsyncStarStreamController::add}(core::_GrowableList::•<core::int>(0)))
             return null;
           else
             [yield] null;
@@ -35,12 +35,12 @@
             return null;
           else
             [yield] null;
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:64: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
+          if(:controller.{asy::_AsyncStarStreamController::addStream}(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:68: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
  - 'List' is from 'dart:core'.
  - 'Stream' is from 'dart:async'.
 Try changing the type of the left hand side, or casting the right hand side to 'Stream<List<int>>'.
-  yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic*/ [];
-                                                               ^" in <dynamic>[] as{TypeError} asy::Stream<core::List<core::int>>))
+  yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic*/ List();
+                                                                   ^" in core::_GrowableList::•<dynamic>(0) as{TypeError} asy::Stream<core::List<core::int>>))
             return null;
           else
             [yield] null;
@@ -70,7 +70,7 @@
   function :sync_op(core::_SyncIterator<core::Map<core::int, core::int>> :iterator) → core::bool yielding {
     {
       {
-        :iterator.{core::_SyncIterator::_current} = <core::int, core::int>{};
+        :iterator.{core::_SyncIterator::_current} = core::Map::•<core::int, core::int>();
         [yield] true;
       }
       {
@@ -83,12 +83,12 @@
         [yield] true;
       }
       {
-        :iterator.{core::_SyncIterator::_yieldEachIterable} = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:73: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
+        :iterator.{core::_SyncIterator::_yieldEachIterable} = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:77: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
  - 'Map' is from 'dart:core'.
  - 'Iterable' is from 'dart:core'.
 Try changing the type of the left hand side, or casting the right hand side to 'Iterable<Map<int, int>>'.
-  yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic, dynamic*/ {};
-                                                                        ^" in <dynamic, dynamic>{} as{TypeError} core::Iterable<core::Map<core::int, core::int>>;
+  yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@typeArgs=dynamic, dynamic*/ Map();
+                                                                            ^" in core::Map::•<dynamic, dynamic>() as{TypeError} core::Iterable<core::Map<core::int, core::int>>;
         [yield] true;
       }
       {
diff --git a/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart b/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart
index 03941bd..3b9b207 100644
--- a/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart
+++ b/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart
@@ -40,9 +40,9 @@
   b = /*error:INVALID_ASSIGNMENT*/ "hi";
   b = new B(3);
   c1 = /*@typeArgs=dynamic*/ [];
-  c1 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic, dynamic*/ {};
+  c1 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic*/ {};
   c2 = /*@typeArgs=dynamic*/ [];
-  c2 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic, dynamic*/ {};
+  c2 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic*/ {};
   d = /*@typeArgs=dynamic, dynamic*/ {};
   d = /*error:INVALID_ASSIGNMENT*/ 3;
   e = new A();
diff --git a/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart.strong.expect b/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart.strong.expect
index bee075a..9075c6f 100644
--- a/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart.strong.expect
@@ -26,19 +26,19 @@
 //   b = /*error:INVALID_ASSIGNMENT*/ "hi";
 //                                    ^
 //
-// pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:43:68: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'List<dynamic>'.
-//  - 'Map' is from 'dart:core'.
+// pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:43:59: Error: A value of type 'Set<dynamic>' can't be assigned to a variable of type 'List<dynamic>'.
+//  - 'Set' is from 'dart:core'.
 //  - 'List' is from 'dart:core'.
 // Try changing the type of the left hand side, or casting the right hand side to 'List<dynamic>'.
-//   c1 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic, dynamic*/ {};
-//                                                                    ^
+//   c1 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic*/ {};
+//                                                           ^
 //
-// pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:45:68: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'List<dynamic>'.
-//  - 'Map' is from 'dart:core'.
+// pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:45:59: Error: A value of type 'Set<dynamic>' can't be assigned to a variable of type 'List<dynamic>'.
+//  - 'Set' is from 'dart:core'.
 //  - 'List' is from 'dart:core'.
 // Try changing the type of the left hand side, or casting the right hand side to 'List<dynamic>'.
-//   c2 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic, dynamic*/ {};
-//                                                                    ^
+//   c2 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic*/ {};
+//                                                           ^
 //
 // pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:47:36: Error: A value of type 'int' can't be assigned to a variable of type 'Map<dynamic, dynamic>'.
 //  - 'Map' is from 'dart:core'.
@@ -85,6 +85,7 @@
 library test;
 import self as self;
 import "dart:core" as core;
+import "dart:collection" as col;
 
 class A extends core::Object {
   field core::int x = null;
@@ -132,19 +133,9 @@
                                    ^" in "hi" as{TypeError} self::B;
   self::b = new self::B::•(3);
   self::c1 = <dynamic>[];
-  self::c1 = let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:43:68: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'List<dynamic>'.
- - 'Map' is from 'dart:core'.
- - 'List' is from 'dart:core'.
-Try changing the type of the left hand side, or casting the right hand side to 'List<dynamic>'.
-  c1 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic, dynamic*/ {};
-                                                                   ^" in <dynamic, dynamic>{} as{TypeError} core::List<dynamic>;
+  self::c1 = let final core::Set<dynamic> #t6 = col::LinkedHashSet::•<dynamic>() in #t6;
   self::c2 = <dynamic>[];
-  self::c2 = let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:45:68: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'List<dynamic>'.
- - 'Map' is from 'dart:core'.
- - 'List' is from 'dart:core'.
-Try changing the type of the left hand side, or casting the right hand side to 'List<dynamic>'.
-  c2 = /*error:INVALID_ASSIGNMENT*/ /*@typeArgs=dynamic, dynamic*/ {};
-                                                                   ^" in <dynamic, dynamic>{} as{TypeError} core::List<dynamic>;
+  self::c2 = let final core::Set<dynamic> #t7 = col::LinkedHashSet::•<dynamic>() in #t7;
   self::d = <dynamic, dynamic>{};
   self::d = let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/inference/infer_from_complex_expressions_if_outer_most_value_is_precise.dart:47:36: Error: A value of type 'int' can't be assigned to a variable of type 'Map<dynamic, dynamic>'.
  - 'Map' is from 'dart:core'.
diff --git a/pkg/front_end/testcases/legacy.status b/pkg/front_end/testcases/legacy.status
index 04f06f8..e603fd2 100644
--- a/pkg/front_end/testcases/legacy.status
+++ b/pkg/front_end/testcases/legacy.status
@@ -125,6 +125,7 @@
 runtime_checks_new/mixin_forwarding_stub_getter: RuntimeError # Test exercises strong mode semantics
 runtime_checks_new/mixin_forwarding_stub_setter: RuntimeError # Test exercises strong mode semantics
 runtime_checks_new/stub_checked_via_target: RuntimeError # Test exercises strong mode semantics
+set_literals/disambiguation_rule: RuntimeError
 type_variable_as_super: Fail
 uninitialized_fields: Fail # Fasta and dartk disagree on static initializers
 void_methods: Fail # Bad return from setters.
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect
index af73d67..6742c9b 100644
--- a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect
+++ b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect
@@ -1,17 +1,17 @@
 // Formatted problems:
 //
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void foo(int x) {}
-//        ^^^
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Context: This is the inherited member.
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
 //   void set foo(int x);
 //            ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Context: Previous declaration of 'foo'.
+//   void foo(int x) {}
+//        ^^^
 
 // Unhandled errors:
 //
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void foo(int x) {}
-//        ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
+//   void set foo(int x);
+//            ^^^
 
 library;
 import self as self;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect
index 37f1f55..e9e7677 100644
--- a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect
@@ -1,8 +1,8 @@
 // Unhandled errors:
 //
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void foo(int x) {}
-//        ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
+//   void set foo(int x);
+//            ^^^
 
 library;
 import self as self;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect
index 51ebf0c..d8c8b38 100644
--- a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect
+++ b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect
@@ -1,11 +1,11 @@
 // Formatted problems:
 //
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void foo(int x) {}
-//        ^^^
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Context: This is the inherited member.
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
 //   void set foo(int x);
 //            ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Context: Previous declaration of 'foo'.
+//   void foo(int x) {}
+//        ^^^
 
 library;
 import self as self;
diff --git a/pkg/front_end/testcases/rasta/super.dart.legacy.expect b/pkg/front_end/testcases/rasta/super.dart.legacy.expect
index ffacfe6..473cece 100644
--- a/pkg/front_end/testcases/rasta/super.dart.legacy.expect
+++ b/pkg/front_end/testcases/rasta/super.dart.legacy.expect
@@ -1,11 +1,11 @@
 // Formatted problems:
 //
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void n() {}
-//        ^
-// pkg/front_end/testcases/rasta/super.dart:27:7: Context: This is the inherited member.
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
 //   set n(_) {}
 //       ^
+// pkg/front_end/testcases/rasta/super.dart:26:8: Context: Previous declaration of 'n'.
+//   void n() {}
+//        ^
 //
 // pkg/front_end/testcases/rasta/super.dart:43:5: Error: '+' is not a prefix operator.
 // Try removing '+'.
@@ -239,9 +239,9 @@
 
 // Unhandled errors:
 //
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void n() {}
-//        ^
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
+//   set n(_) {}
+//       ^
 //
 // pkg/front_end/testcases/rasta/super.dart:43:5: Error: '+' is not a prefix operator.
 // Try removing '+'.
diff --git a/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect b/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect
index 3a83d7b..f92047d 100644
--- a/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect
@@ -1,8 +1,8 @@
 // Unhandled errors:
 //
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void n() {}
-//        ^
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
+//   set n(_) {}
+//       ^
 //
 // pkg/front_end/testcases/rasta/super.dart:43:5: Error: '+' is not a prefix operator.
 // Try removing '+'.
diff --git a/pkg/front_end/testcases/rasta/super.dart.outline.expect b/pkg/front_end/testcases/rasta/super.dart.outline.expect
index 8798c49..c3496aa 100644
--- a/pkg/front_end/testcases/rasta/super.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/super.dart.outline.expect
@@ -1,11 +1,11 @@
 // Formatted problems:
 //
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-//   void n() {}
-//        ^
-// pkg/front_end/testcases/rasta/super.dart:27:7: Context: This is the inherited member.
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
 //   set n(_) {}
 //       ^
+// pkg/front_end/testcases/rasta/super.dart:26:8: Context: Previous declaration of 'n'.
+//   void n() {}
+//        ^
 
 library;
 import self as self;
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart
new file mode 100644
index 0000000..15f76e8
--- /dev/null
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async' show FutureOr;
+
+import 'dart:collection' show LinkedHashMap, LinkedHashSet;
+
+main() async {
+  Map<int, bool> m = {};
+  Set<int> s = {};
+  Iterable<int> i = {};
+  LinkedHashSet<int> lhs = {};
+  LinkedHashMap<int, bool> lhm = {};
+
+  Map<int, bool> fm = await mapfun();
+  Set<int> fs = await setfun();
+  Iterable<int> fi = await iterablefun();
+  LinkedHashSet<int> flhs = await lhsfun();
+  LinkedHashMap<int, bool> flhm = await lhmfun();
+
+  Map<int, bool> fm2 = await mapfun2();
+  Set<int> fs2 = await setfun2();
+  Iterable<int> fi2 = await iterablefun2();
+  LinkedHashSet<int> flhs2 = await lhsfun2();
+  LinkedHashMap<int, bool> flhm2 = await lhmfun2();
+}
+
+Future<Map<int, bool>> mapfun() async => {};
+Future<Set<int>> setfun() async => {};
+Future<Iterable<int>> iterablefun() async => {};
+Future<LinkedHashSet<int>> lhsfun() async => {};
+Future<LinkedHashMap<int, bool>> lhmfun() async => {};
+
+FutureOr<Map<int, bool>> mapfun2() => {};
+FutureOr<Set<int>> setfun2() => {};
+FutureOr<Iterable<int>> iterablefun2() => {};
+FutureOr<LinkedHashSet<int>> lhsfun2() => {};
+FutureOr<LinkedHashMap<int, bool>> lhmfun2() => {};
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.legacy.expect b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.legacy.expect
new file mode 100644
index 0000000..932c7ea
--- /dev/null
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.legacy.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+import "dart:async" as asy;
+
+static method main() → dynamic async {
+  core::Map<core::int, core::bool> m = <dynamic, dynamic>{};
+  core::Set<core::int> s = <dynamic, dynamic>{};
+  core::Iterable<core::int> i = <dynamic, dynamic>{};
+  col::LinkedHashSet<core::int> lhs = <dynamic, dynamic>{};
+  col::LinkedHashMap<core::int, core::bool> lhm = <dynamic, dynamic>{};
+  core::Map<core::int, core::bool> fm = await self::mapfun();
+  core::Set<core::int> fs = await self::setfun();
+  core::Iterable<core::int> fi = await self::iterablefun();
+  col::LinkedHashSet<core::int> flhs = await self::lhsfun();
+  col::LinkedHashMap<core::int, core::bool> flhm = await self::lhmfun();
+  core::Map<core::int, core::bool> fm2 = await self::mapfun2();
+  core::Set<core::int> fs2 = await self::setfun2();
+  core::Iterable<core::int> fi2 = await self::iterablefun2();
+  col::LinkedHashSet<core::int> flhs2 = await self::lhsfun2();
+  col::LinkedHashMap<core::int, core::bool> flhm2 = await self::lhmfun2();
+}
+static method mapfun() → asy::Future<core::Map<core::int, core::bool>> async 
+  return <dynamic, dynamic>{};
+static method setfun() → asy::Future<core::Set<core::int>> async 
+  return <dynamic, dynamic>{};
+static method iterablefun() → asy::Future<core::Iterable<core::int>> async 
+  return <dynamic, dynamic>{};
+static method lhsfun() → asy::Future<col::LinkedHashSet<core::int>> async 
+  return <dynamic, dynamic>{};
+static method lhmfun() → asy::Future<col::LinkedHashMap<core::int, core::bool>> async 
+  return <dynamic, dynamic>{};
+static method mapfun2() → asy::FutureOr<core::Map<core::int, core::bool>>
+  return <dynamic, dynamic>{};
+static method setfun2() → asy::FutureOr<core::Set<core::int>>
+  return <dynamic, dynamic>{};
+static method iterablefun2() → asy::FutureOr<core::Iterable<core::int>>
+  return <dynamic, dynamic>{};
+static method lhsfun2() → asy::FutureOr<col::LinkedHashSet<core::int>>
+  return <dynamic, dynamic>{};
+static method lhmfun2() → asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>
+  return <dynamic, dynamic>{};
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.legacy.transformed.expect b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.legacy.transformed.expect
new file mode 100644
index 0000000..7ed15e3
--- /dev/null
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.legacy.transformed.expect
@@ -0,0 +1,202 @@
+library;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+static method main() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L1:
+      {
+        core::Map<core::int, core::bool> m = <dynamic, dynamic>{};
+        core::Set<core::int> s = <dynamic, dynamic>{};
+        core::Iterable<core::int> i = <dynamic, dynamic>{};
+        col::LinkedHashSet<core::int> lhs = <dynamic, dynamic>{};
+        col::LinkedHashMap<core::int, core::bool> lhm = <dynamic, dynamic>{};
+        [yield] let dynamic #t1 = asy::_awaitHelper(self::mapfun(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Map<core::int, core::bool> fm = :result;
+        [yield] let dynamic #t2 = asy::_awaitHelper(self::setfun(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Set<core::int> fs = :result;
+        [yield] let dynamic #t3 = asy::_awaitHelper(self::iterablefun(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Iterable<core::int> fi = :result;
+        [yield] let dynamic #t4 = asy::_awaitHelper(self::lhsfun(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashSet<core::int> flhs = :result;
+        [yield] let dynamic #t5 = asy::_awaitHelper(self::lhmfun(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashMap<core::int, core::bool> flhm = :result;
+        [yield] let dynamic #t6 = asy::_awaitHelper(self::mapfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Map<core::int, core::bool> fm2 = :result;
+        [yield] let dynamic #t7 = asy::_awaitHelper(self::setfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Set<core::int> fs2 = :result;
+        [yield] let dynamic #t8 = asy::_awaitHelper(self::iterablefun2(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Iterable<core::int> fi2 = :result;
+        [yield] let dynamic #t9 = asy::_awaitHelper(self::lhsfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashSet<core::int> flhs2 = :result;
+        [yield] let dynamic #t10 = asy::_awaitHelper(self::lhmfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashMap<core::int, core::bool> flhm2 = :result;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method mapfun() → asy::Future<core::Map<core::int, core::bool>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<core::Map<core::int, core::bool>> :async_completer = new asy::_AsyncAwaitCompleter::•<core::Map<core::int, core::bool>>();
+  asy::FutureOr<core::Map<core::int, core::bool>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L2:
+      {
+        :return_value = <dynamic, dynamic>{};
+        break #L2;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method setfun() → asy::Future<core::Set<core::int>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<core::Set<core::int>> :async_completer = new asy::_AsyncAwaitCompleter::•<core::Set<core::int>>();
+  asy::FutureOr<core::Set<core::int>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L3:
+      {
+        :return_value = <dynamic, dynamic>{};
+        break #L3;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method iterablefun() → asy::Future<core::Iterable<core::int>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<core::Iterable<core::int>> :async_completer = new asy::_AsyncAwaitCompleter::•<core::Iterable<core::int>>();
+  asy::FutureOr<core::Iterable<core::int>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L4:
+      {
+        :return_value = <dynamic, dynamic>{};
+        break #L4;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method lhsfun() → asy::Future<col::LinkedHashSet<core::int>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<col::LinkedHashSet<core::int>> :async_completer = new asy::_AsyncAwaitCompleter::•<col::LinkedHashSet<core::int>>();
+  asy::FutureOr<col::LinkedHashSet<core::int>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L5:
+      {
+        :return_value = <dynamic, dynamic>{};
+        break #L5;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method lhmfun() → asy::Future<col::LinkedHashMap<core::int, core::bool>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<col::LinkedHashMap<core::int, core::bool>> :async_completer = new asy::_AsyncAwaitCompleter::•<col::LinkedHashMap<core::int, core::bool>>();
+  asy::FutureOr<col::LinkedHashMap<core::int, core::bool>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L6:
+      {
+        :return_value = <dynamic, dynamic>{};
+        break #L6;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method mapfun2() → asy::FutureOr<core::Map<core::int, core::bool>>
+  return <dynamic, dynamic>{};
+static method setfun2() → asy::FutureOr<core::Set<core::int>>
+  return <dynamic, dynamic>{};
+static method iterablefun2() → asy::FutureOr<core::Iterable<core::int>>
+  return <dynamic, dynamic>{};
+static method lhsfun2() → asy::FutureOr<col::LinkedHashSet<core::int>>
+  return <dynamic, dynamic>{};
+static method lhmfun2() → asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>
+  return <dynamic, dynamic>{};
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.outline.expect b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.outline.expect
new file mode 100644
index 0000000..4c67211
--- /dev/null
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+static method main() → dynamic
+  ;
+static method mapfun() → asy::Future<core::Map<core::int, core::bool>>
+  ;
+static method setfun() → asy::Future<core::Set<core::int>>
+  ;
+static method iterablefun() → asy::Future<core::Iterable<core::int>>
+  ;
+static method lhsfun() → asy::Future<col::LinkedHashSet<core::int>>
+  ;
+static method lhmfun() → asy::Future<col::LinkedHashMap<core::int, core::bool>>
+  ;
+static method mapfun2() → asy::FutureOr<core::Map<core::int, core::bool>>
+  ;
+static method setfun2() → asy::FutureOr<core::Set<core::int>>
+  ;
+static method iterablefun2() → asy::FutureOr<core::Iterable<core::int>>
+  ;
+static method lhsfun2() → asy::FutureOr<col::LinkedHashSet<core::int>>
+  ;
+static method lhmfun2() → asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>
+  ;
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.expect b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.expect
new file mode 100644
index 0000000..e5e3a65
--- /dev/null
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.expect
@@ -0,0 +1,97 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/set_literals/disambiguation_rule.dart:14:34: Error: The map literal type 'Map<dynamic, dynamic>' isn't of expected type 'LinkedHashMap<int, bool>'.
+//  - 'Map' is from 'dart:core'.
+//  - 'LinkedHashMap' is from 'dart:collection'.
+// Change the type of the map literal or the context in which it is used.
+//   LinkedHashMap<int, bool> lhm = {};
+//                                  ^
+//
+// pkg/front_end/testcases/set_literals/disambiguation_rule.dart:33:52: Error: The map literal type 'Map<dynamic, dynamic>' isn't of expected type 'LinkedHashMap<int, bool>'.
+//  - 'Map' is from 'dart:core'.
+//  - 'LinkedHashMap' is from 'dart:collection'.
+// Change the type of the map literal or the context in which it is used.
+// Future<LinkedHashMap<int, bool>> lhmfun() async => {};
+//                                                    ^
+//
+// pkg/front_end/testcases/set_literals/disambiguation_rule.dart:38:43: Error: A value of type 'Set<dynamic>' can't be assigned to a variable of type 'FutureOr<LinkedHashSet<int>>'.
+//  - 'Set' is from 'dart:core'.
+//  - 'FutureOr' is from 'dart:async'.
+//  - 'LinkedHashSet' is from 'dart:collection'.
+// Try changing the type of the left hand side, or casting the right hand side to 'FutureOr<LinkedHashSet<int>>'.
+// FutureOr<LinkedHashSet<int>> lhsfun2() => {};
+//                                           ^
+//
+// pkg/front_end/testcases/set_literals/disambiguation_rule.dart:39:49: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'FutureOr<LinkedHashMap<int, bool>>'.
+//  - 'Map' is from 'dart:core'.
+//  - 'FutureOr' is from 'dart:async'.
+//  - 'LinkedHashMap' is from 'dart:collection'.
+// Try changing the type of the left hand side, or casting the right hand side to 'FutureOr<LinkedHashMap<int, bool>>'.
+// FutureOr<LinkedHashMap<int, bool>> lhmfun2() => {};
+//                                                 ^
+
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+import "dart:async" as asy;
+
+static method main() → dynamic async {
+  core::Map<core::int, core::bool> m = <core::int, core::bool>{};
+  core::Set<core::int> s = let final core::Set<core::int> #t1 = col::LinkedHashSet::•<core::int>() in #t1;
+  core::Iterable<core::int> i = let final core::Set<core::int> #t2 = col::LinkedHashSet::•<core::int>() in #t2;
+  col::LinkedHashSet<core::int> lhs = (let final core::Set<dynamic> #t3 = col::LinkedHashSet::•<dynamic>() in #t3) as{TypeError} col::LinkedHashSet<core::int>;
+  col::LinkedHashMap<core::int, core::bool> lhm = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:14:34: Error: The map literal type 'Map<dynamic, dynamic>' isn't of expected type 'LinkedHashMap<int, bool>'.
+ - 'Map' is from 'dart:core'.
+ - 'LinkedHashMap' is from 'dart:collection'.
+Change the type of the map literal or the context in which it is used.
+  LinkedHashMap<int, bool> lhm = {};
+                                 ^" in <dynamic, dynamic>{};
+  core::Map<core::int, core::bool> fm = await self::mapfun();
+  core::Set<core::int> fs = await self::setfun();
+  core::Iterable<core::int> fi = await self::iterablefun();
+  col::LinkedHashSet<core::int> flhs = await self::lhsfun();
+  col::LinkedHashMap<core::int, core::bool> flhm = await self::lhmfun();
+  core::Map<core::int, core::bool> fm2 = await self::mapfun2();
+  core::Set<core::int> fs2 = await self::setfun2();
+  core::Iterable<core::int> fi2 = await self::iterablefun2();
+  col::LinkedHashSet<core::int> flhs2 = await self::lhsfun2();
+  col::LinkedHashMap<core::int, core::bool> flhm2 = await self::lhmfun2();
+}
+static method mapfun() → asy::Future<core::Map<core::int, core::bool>> async 
+  return <core::int, core::bool>{};
+static method setfun() → asy::Future<core::Set<core::int>> async 
+  return let final core::Set<core::int> #t5 = col::LinkedHashSet::•<core::int>() in #t5;
+static method iterablefun() → asy::Future<core::Iterable<core::int>> async 
+  return let final core::Set<core::int> #t6 = col::LinkedHashSet::•<core::int>() in #t6;
+static method lhsfun() → asy::Future<col::LinkedHashSet<core::int>> async 
+  return (let final core::Set<dynamic> #t7 = col::LinkedHashSet::•<dynamic>() in #t7) as{TypeError} asy::FutureOr<col::LinkedHashSet<core::int>>;
+static method lhmfun() → asy::Future<col::LinkedHashMap<core::int, core::bool>> async 
+  return let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:33:52: Error: The map literal type 'Map<dynamic, dynamic>' isn't of expected type 'LinkedHashMap<int, bool>'.
+ - 'Map' is from 'dart:core'.
+ - 'LinkedHashMap' is from 'dart:collection'.
+Change the type of the map literal or the context in which it is used.
+Future<LinkedHashMap<int, bool>> lhmfun() async => {};
+                                                   ^" in <dynamic, dynamic>{};
+static method mapfun2() → asy::FutureOr<core::Map<core::int, core::bool>>
+  return <core::int, core::bool>{};
+static method setfun2() → asy::FutureOr<core::Set<core::int>>
+  return let final core::Set<core::int> #t9 = col::LinkedHashSet::•<core::int>() in #t9;
+static method iterablefun2() → asy::FutureOr<core::Iterable<core::int>>
+  return let final core::Set<core::int> #t10 = col::LinkedHashSet::•<core::int>() in #t10;
+static method lhsfun2() → asy::FutureOr<col::LinkedHashSet<core::int>>
+  return let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:38:43: Error: A value of type 'Set<dynamic>' can't be assigned to a variable of type 'FutureOr<LinkedHashSet<int>>'.
+ - 'Set' is from 'dart:core'.
+ - 'FutureOr' is from 'dart:async'.
+ - 'LinkedHashSet' is from 'dart:collection'.
+Try changing the type of the left hand side, or casting the right hand side to 'FutureOr<LinkedHashSet<int>>'.
+FutureOr<LinkedHashSet<int>> lhsfun2() => {};
+                                          ^" in (let final core::Set<dynamic> #t12 = col::LinkedHashSet::•<dynamic>() in #t12) as{TypeError} asy::FutureOr<col::LinkedHashSet<core::int>>;
+static method lhmfun2() → asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>
+  return let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:39:49: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'FutureOr<LinkedHashMap<int, bool>>'.
+ - 'Map' is from 'dart:core'.
+ - 'FutureOr' is from 'dart:async'.
+ - 'LinkedHashMap' is from 'dart:collection'.
+Try changing the type of the left hand side, or casting the right hand side to 'FutureOr<LinkedHashMap<int, bool>>'.
+FutureOr<LinkedHashMap<int, bool>> lhmfun2() => {};
+                                                ^" in <dynamic, dynamic>{} as{TypeError} asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>;
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect
new file mode 100644
index 0000000..9b60cf8
--- /dev/null
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect
@@ -0,0 +1,224 @@
+library;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+static method main() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L1:
+      {
+        core::Map<core::int, core::bool> m = <core::int, core::bool>{};
+        core::Set<core::int> s = let final core::Set<core::int> #t1 = col::LinkedHashSet::•<core::int>() in #t1;
+        core::Iterable<core::int> i = let final core::Set<core::int> #t2 = col::LinkedHashSet::•<core::int>() in #t2;
+        col::LinkedHashSet<core::int> lhs = (let final core::Set<dynamic> #t3 = col::LinkedHashSet::•<dynamic>() in #t3) as{TypeError} col::LinkedHashSet<core::int>;
+        col::LinkedHashMap<core::int, core::bool> lhm = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:14:34: Error: The map literal type 'Map<dynamic, dynamic>' isn't of expected type 'LinkedHashMap<int, bool>'.
+ - 'Map' is from 'dart:core'.
+ - 'LinkedHashMap' is from 'dart:collection'.
+Change the type of the map literal or the context in which it is used.
+  LinkedHashMap<int, bool> lhm = {};
+                                 ^" in <dynamic, dynamic>{};
+        [yield] let dynamic #t5 = asy::_awaitHelper(self::mapfun(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Map<core::int, core::bool> fm = :result;
+        [yield] let dynamic #t6 = asy::_awaitHelper(self::setfun(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Set<core::int> fs = :result;
+        [yield] let dynamic #t7 = asy::_awaitHelper(self::iterablefun(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Iterable<core::int> fi = :result;
+        [yield] let dynamic #t8 = asy::_awaitHelper(self::lhsfun(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashSet<core::int> flhs = :result;
+        [yield] let dynamic #t9 = asy::_awaitHelper(self::lhmfun(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashMap<core::int, core::bool> flhm = :result;
+        [yield] let dynamic #t10 = asy::_awaitHelper(self::mapfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Map<core::int, core::bool> fm2 = :result;
+        [yield] let dynamic #t11 = asy::_awaitHelper(self::setfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Set<core::int> fs2 = :result;
+        [yield] let dynamic #t12 = asy::_awaitHelper(self::iterablefun2(), :async_op_then, :async_op_error, :async_op) in null;
+        core::Iterable<core::int> fi2 = :result;
+        [yield] let dynamic #t13 = asy::_awaitHelper(self::lhsfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashSet<core::int> flhs2 = :result;
+        [yield] let dynamic #t14 = asy::_awaitHelper(self::lhmfun2(), :async_op_then, :async_op_error, :async_op) in null;
+        col::LinkedHashMap<core::int, core::bool> flhm2 = :result;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method mapfun() → asy::Future<core::Map<core::int, core::bool>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<core::Map<core::int, core::bool>> :async_completer = new asy::_AsyncAwaitCompleter::•<core::Map<core::int, core::bool>>();
+  asy::FutureOr<core::Map<core::int, core::bool>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L2:
+      {
+        :return_value = <core::int, core::bool>{};
+        break #L2;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method setfun() → asy::Future<core::Set<core::int>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<core::Set<core::int>> :async_completer = new asy::_AsyncAwaitCompleter::•<core::Set<core::int>>();
+  asy::FutureOr<core::Set<core::int>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L3:
+      {
+        :return_value = let final core::Set<core::int> #t15 = col::LinkedHashSet::•<core::int>() in #t15;
+        break #L3;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method iterablefun() → asy::Future<core::Iterable<core::int>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<core::Iterable<core::int>> :async_completer = new asy::_AsyncAwaitCompleter::•<core::Iterable<core::int>>();
+  asy::FutureOr<core::Iterable<core::int>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L4:
+      {
+        :return_value = let final core::Set<core::int> #t16 = col::LinkedHashSet::•<core::int>() in #t16;
+        break #L4;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method lhsfun() → asy::Future<col::LinkedHashSet<core::int>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<col::LinkedHashSet<core::int>> :async_completer = new asy::_AsyncAwaitCompleter::•<col::LinkedHashSet<core::int>>();
+  asy::FutureOr<col::LinkedHashSet<core::int>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L5:
+      {
+        :return_value = (let final core::Set<dynamic> #t17 = col::LinkedHashSet::•<dynamic>() in #t17) as{TypeError} asy::FutureOr<col::LinkedHashSet<core::int>>;
+        break #L5;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method lhmfun() → asy::Future<col::LinkedHashMap<core::int, core::bool>> /* originally async */ {
+  final asy::_AsyncAwaitCompleter<col::LinkedHashMap<core::int, core::bool>> :async_completer = new asy::_AsyncAwaitCompleter::•<col::LinkedHashMap<core::int, core::bool>>();
+  asy::FutureOr<col::LinkedHashMap<core::int, core::bool>> :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  dynamic :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L6:
+      {
+        :return_value = let final<BottomType> #t18 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:33:52: Error: The map literal type 'Map<dynamic, dynamic>' isn't of expected type 'LinkedHashMap<int, bool>'.
+ - 'Map' is from 'dart:core'.
+ - 'LinkedHashMap' is from 'dart:collection'.
+Change the type of the map literal or the context in which it is used.
+Future<LinkedHashMap<int, bool>> lhmfun() async => {};
+                                                   ^" in <dynamic, dynamic>{};
+        break #L6;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method mapfun2() → asy::FutureOr<core::Map<core::int, core::bool>>
+  return <core::int, core::bool>{};
+static method setfun2() → asy::FutureOr<core::Set<core::int>>
+  return let final core::Set<core::int> #t19 = col::LinkedHashSet::•<core::int>() in #t19;
+static method iterablefun2() → asy::FutureOr<core::Iterable<core::int>>
+  return let final core::Set<core::int> #t20 = col::LinkedHashSet::•<core::int>() in #t20;
+static method lhsfun2() → asy::FutureOr<col::LinkedHashSet<core::int>>
+  return let final<BottomType> #t21 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:38:43: Error: A value of type 'Set<dynamic>' can't be assigned to a variable of type 'FutureOr<LinkedHashSet<int>>'.
+ - 'Set' is from 'dart:core'.
+ - 'FutureOr' is from 'dart:async'.
+ - 'LinkedHashSet' is from 'dart:collection'.
+Try changing the type of the left hand side, or casting the right hand side to 'FutureOr<LinkedHashSet<int>>'.
+FutureOr<LinkedHashSet<int>> lhsfun2() => {};
+                                          ^" in (let final core::Set<dynamic> #t22 = col::LinkedHashSet::•<dynamic>() in #t22) as{TypeError} asy::FutureOr<col::LinkedHashSet<core::int>>;
+static method lhmfun2() → asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>
+  return let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/set_literals/disambiguation_rule.dart:39:49: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'FutureOr<LinkedHashMap<int, bool>>'.
+ - 'Map' is from 'dart:core'.
+ - 'FutureOr' is from 'dart:async'.
+ - 'LinkedHashMap' is from 'dart:collection'.
+Try changing the type of the left hand side, or casting the right hand side to 'FutureOr<LinkedHashMap<int, bool>>'.
+FutureOr<LinkedHashMap<int, bool>> lhmfun2() => {};
+                                                ^" in <dynamic, dynamic>{} as{TypeError} asy::FutureOr<col::LinkedHashMap<core::int, core::bool>>;
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 20f95d6..f42074f 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -44,6 +44,7 @@
 inference/generic_methods_handle_override_of_non_generic_with_generic: TypeCheckError
 inference/generic_methods_infer_js_builtin: InstrumentationMismatch # Issue #30029
 inference/infer_field_override_multiple: TypeCheckError
+inference/infer_from_complex_expressions_if_outer_most_value_is_precise: TypeCheckError # Issue #35630
 inference/infer_method_missing_params: TypeCheckError
 inference/infer_type_regardless_of_declaration_order_or_cycles: RuntimeError
 inference/infer_types_on_generic_instantiations_4: RuntimeError
@@ -145,6 +146,7 @@
 runtime_checks_new/mixin_forwarding_stub_field: TypeCheckError
 runtime_checks_new/mixin_forwarding_stub_getter: TypeCheckError
 runtime_checks_new/mixin_forwarding_stub_setter: TypeCheckError
+set_literals/disambiguation_rule: RuntimeError
 statements: Crash
 type_variable_as_super: RuntimeError
 type_variable_prefix: RuntimeError
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 08fd945..c4a93e2 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -60,7 +60,7 @@
 closure: TextSerializationFailure # Was: Pass
 co19_language_metadata_syntax_t04: TextSerializationFailure # Was: Pass
 constructor_const_inference: TextSerializationFailure # Was: Pass
-constructor_cycle: Crash # Was: Pass
+constructor_cycle: TextSerializationFailure # Was: Pass
 constructor_function_types: TextSerializationFailure # Was: Pass
 constructor_initializer_invalid: TextSerializationFailure # Was: RuntimeError # Fails execution after recovery
 continue_inference_after_error_lib: TextSerializationFailure # Was: Pass
@@ -312,7 +312,7 @@
 inference/infer_final_field_getter_and_setter: TextSerializationFailure # Was: Pass
 inference/infer_final_field_getter_only: TextSerializationFailure # Was: Pass
 inference/infer_final_field_setter_only: TextSerializationFailure # Was: Pass
-inference/infer_from_complex_expressions_if_outer_most_value_is_precise: TextSerializationFailure # Was: Pass
+inference/infer_from_complex_expressions_if_outer_most_value_is_precise: TypeCheckError # Issue #35630
 inference/infer_from_rhs_only_if_it_wont_conflict_with_overridden_fields2: TextSerializationFailure # Was: Pass
 inference/infer_from_rhs_only_if_it_wont_conflict_with_overridden_fields: TextSerializationFailure # Was: Pass
 inference/infer_from_variables_in_cycle_libs_when_flag_is_on2_a: TextSerializationFailure # Was: Pass
@@ -770,7 +770,7 @@
 rasta/issue_000034: TextSerializationFailure # Was: RuntimeError
 rasta/issue_000035a: TextSerializationFailure # Was: Pass
 rasta/issue_000035: TextSerializationFailure # Was: Pass
-rasta/issue_000036: TextSerializationFailure # Was: RuntimeError
+rasta/issue_000036: RuntimeError
 rasta/issue_000039: VerificationError
 rasta/issue_000041: TextSerializationFailure # Was: RuntimeError
 rasta/issue_000042: TextSerializationFailure # Was: RuntimeError
@@ -950,6 +950,7 @@
 runtime_checks_new/stub_from_interface_covariantImpl_from_interface: TextSerializationFailure # Was: Pass
 runtime_checks_new/stub_from_interface_covariantImpl_from_super: TextSerializationFailure # Was: Pass
 runtime_checks_new/stub_from_interface_covariantInterface_from_class: TextSerializationFailure # Was: Pass
+set_literals/disambiguation_rule: TextSerializationFailure # Was: RuntimeError
 statements: Crash
 static_setter: TextSerializationFailure # Was: Pass
 store_load: TextSerializationFailure # Was: Pass
diff --git a/pkg/front_end/tool/_fasta/command_line.dart b/pkg/front_end/tool/_fasta/command_line.dart
index 7728f88..d4ccb3a 100644
--- a/pkg/front_end/tool/_fasta/command_line.dart
+++ b/pkg/front_end/tool/_fasta/command_line.dart
@@ -12,10 +12,10 @@
     show SingleRootFileSystem;
 
 import 'package:front_end/src/api_prototype/compiler_options.dart'
-    show CompilerOptions;
+    show CompilerOptions, parseExperimentalFlags;
 
 import 'package:front_end/src/api_prototype/experimental_flags.dart'
-    show ExperimentalFlag, parseExperimentalFlag;
+    show ExperimentalFlag;
 
 import 'package:front_end/src/api_prototype/file_system.dart' show FileSystem;
 
@@ -240,7 +240,6 @@
 const Map<String, dynamic> optionSpecification = const <String, dynamic>{
   "--bytecode": false,
   "--compile-sdk": Uri,
-  "--disable-experiment": ",",
   "--dump-ir": false,
   "--enable-experiment": ",",
   "--exclude-source": false,
@@ -269,6 +268,10 @@
   "/h": "--help",
 };
 
+void throwCommandLineProblem(String message) {
+  throw new CommandLineProblem.deprecated(message);
+}
+
 ProcessedOptions analyzeCommandLine(
     String programName,
     ParsedArguments parsedArguments,
@@ -343,30 +346,8 @@
     });
   }
 
-  final List<String> enabledExperiments = options["--enable-experiment"];
-  final List<String> disabledExperiments = options["--disable-experiment"];
-
-  Map<ExperimentalFlag, bool> experimentalFlags = {};
-
-  void setExperimentalFlags(List<String> experiments, bool value) {
-    if (experiments != null) {
-      for (String experiment in experiments) {
-        ExperimentalFlag flag = parseExperimentalFlag(experiment);
-        if (flag == null) {
-          throw new CommandLineProblem.deprecated(
-              "Unknown experiment: " + experiment);
-        }
-        if (experimentalFlags.containsKey(flag)) {
-          throw new CommandLineProblem.deprecated(
-              "Experiment mentioned more than once: " + experiment);
-        }
-        experimentalFlags[flag] = value;
-      }
-    }
-  }
-
-  setExperimentalFlags(enabledExperiments, true);
-  setExperimentalFlags(disabledExperiments, false);
+  Map<ExperimentalFlag, bool> experimentalFlags = parseExperimentalFlags(
+      options["--enable-experiment"], throwCommandLineProblem);
 
   if (programName == "compile_platform") {
     if (arguments.length != 5) {
diff --git a/pkg/kernel/bin/transform.dart b/pkg/kernel/bin/transform.dart
index a2d90ae..157aa9c 100755
--- a/pkg/kernel/bin/transform.dart
+++ b/pkg/kernel/bin/transform.dart
@@ -12,13 +12,15 @@
 import 'package:kernel/kernel.dart';
 import 'package:kernel/src/tool/batch_util.dart';
 import 'package:kernel/target/targets.dart';
-import 'package:kernel/transformations/constants.dart' as constants;
+
+import 'package:kernel/transformations/constants.dart' as constants
+    show SimpleErrorReporter, transformComponent;
+
 import 'package:kernel/transformations/continuation.dart' as cont;
 import 'package:kernel/transformations/empty.dart' as empty;
 import 'package:kernel/transformations/method_call.dart' as method_call;
 import 'package:kernel/transformations/mixin_full_resolution.dart' as mix;
 import 'package:kernel/transformations/treeshaker.dart' as treeshaker;
-// import 'package:kernel/verifier.dart';
 import 'package:kernel/transformations/coq.dart' as coq;
 import 'package:kernel/vm/constants_native_effects.dart';
 import 'package:kernel/src/tool/command_line_util.dart';
@@ -97,8 +99,9 @@
       final Map<String, String> defines = null;
       final VmConstantsBackend backend =
           new VmConstantsBackend(defines, coreTypes);
-      component =
-          constants.transformComponent(component, backend, legacyMode: true);
+      component = constants.transformComponent(
+          component, backend, const constants.SimpleErrorReporter(),
+          legacyMode: true);
       break;
     case 'treeshake':
       component = treeshaker.transformComponent(coreTypes, hierarchy, component,
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 865beb6..9408027 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -131,7 +131,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 15;
+  UInt32 formatVersion = 16;
   Library[] libraries;
   UriSource sourceMap;
   List<CanonicalName> canonicalNames;
@@ -926,6 +926,29 @@
   DartType type;
 }
 
+type EnvironmentBoolConstant extends Constant {
+  Byte tag = 12;
+  StringReference name;
+  ConstantReference defaultValue;
+}
+
+type EnvironmentIntConstant extends Constant {
+  Byte tag = 13;
+  StringReference name;
+  ConstantReference defaultValue;
+}
+
+type EnvironmentStringConstant extends Constant {
+  Byte tag = 14;
+  StringReference name;
+  ConstantReference defaultValue;
+}
+
+type UnevaluatedConstant extends Constant {
+  Byte tag = 15;
+  Expression expression;
+}
+
 abstract type Statement extends Node {}
 
 type ExpressionStatement extends Statement {
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 4f16b8a..2bddaf9 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -83,7 +83,7 @@
   const Node();
 
   accept(Visitor v);
-  visitChildren(Visitor v);
+  void visitChildren(Visitor v);
 
   /// Returns the textual representation of this node for use in debugging.
   ///
@@ -2190,7 +2190,7 @@
       type = (type as TypeParameterType).parameter.bound;
     }
     if (type is InterfaceType) {
-      var upcastType = types.hierarchy.getTypeAsInstanceOf(type, superclass);
+      var upcastType = types.getTypeAsInstanceOf(type, superclass);
       if (upcastType != null) return upcastType;
     } else if (type is BottomType) {
       return superclass.bottomType;
@@ -2558,8 +2558,7 @@
     if (declaringClass.typeParameters.isEmpty) {
       return interfaceTarget.getterType;
     }
-    var receiver =
-        types.hierarchy.getTypeAsInstanceOf(types.thisType, declaringClass);
+    var receiver = types.getTypeAsInstanceOf(types.thisType, declaringClass);
     return Substitution.fromInterfaceType(receiver)
         .substituteType(interfaceTarget.getterType);
   }
@@ -2881,8 +2880,7 @@
   DartType getStaticType(TypeEnvironment types) {
     if (interfaceTarget == null) return const DynamicType();
     Class superclass = interfaceTarget.enclosingClass;
-    var receiverType =
-        types.hierarchy.getTypeAsInstanceOf(types.thisType, superclass);
+    var receiverType = types.getTypeAsInstanceOf(types.thisType, superclass);
     var returnType = Substitution.fromInterfaceType(receiverType)
         .substituteType(interfaceTarget.function.returnType);
     return Substitution.fromPairs(
@@ -5442,6 +5440,67 @@
   DartType getType(TypeEnvironment types) => types.typeType;
 }
 
+abstract class EnvironmentConstant extends Constant {
+  final String name;
+  final Constant defaultValue;
+
+  EnvironmentConstant(this.name, this.defaultValue);
+  visitChildren(Visitor v) {
+    defaultValue.acceptReference(v);
+  }
+}
+
+class EnvironmentBoolConstant extends EnvironmentConstant {
+  EnvironmentBoolConstant(String name, Constant defaultValue)
+      : super(name, defaultValue);
+
+  accept(ConstantVisitor v) => v.visitEnvironmentBoolConstant(this);
+  acceptReference(Visitor v) {
+    return v.visitEnvironmentBoolConstantReference(this);
+  }
+
+  DartType getType(TypeEnvironment types) => types.boolType;
+}
+
+class EnvironmentIntConstant extends EnvironmentConstant {
+  EnvironmentIntConstant(String name, Constant defaultValue)
+      : super(name, defaultValue);
+
+  accept(ConstantVisitor v) => v.visitEnvironmentIntConstant(this);
+  acceptReference(Visitor v) {
+    return v.visitEnvironmentIntConstantReference(this);
+  }
+
+  DartType getType(TypeEnvironment types) => types.intType;
+}
+
+class EnvironmentStringConstant extends EnvironmentConstant {
+  EnvironmentStringConstant(String name, Constant defaultValue)
+      : super(name, defaultValue);
+
+  accept(ConstantVisitor v) => v.visitEnvironmentStringConstant(this);
+  acceptReference(Visitor v) {
+    return v.visitEnvironmentStringConstantReference(this);
+  }
+
+  DartType getType(TypeEnvironment types) => types.stringType;
+}
+
+class UnevaluatedConstant extends Constant {
+  final Expression expression;
+
+  UnevaluatedConstant(this.expression);
+
+  visitChildren(Visitor v) {
+    expression.accept(v);
+  }
+
+  accept(ConstantVisitor v) => v.visitUnevaluatedConstant(this);
+  acceptReference(Visitor v) => v.visitUnevaluatedConstantReference(this);
+
+  DartType getType(TypeEnvironment types) => expression.getStaticType(types);
+}
+
 // ------------------------------------------------------------------------
 //                                COMPONENT
 // ------------------------------------------------------------------------
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 0c9b61b..59148f3 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -270,6 +270,21 @@
       case ConstantTag.TypeLiteralConstant:
         final DartType type = readDartType();
         return new TypeLiteralConstant(type);
+      case ConstantTag.EnvironmentBoolConstant:
+        final String name = readStringReference();
+        final Constant defaultValue = readConstantReference();
+        return new EnvironmentBoolConstant(name, defaultValue);
+      case ConstantTag.EnvironmentIntConstant:
+        final String name = readStringReference();
+        final Constant defaultValue = readConstantReference();
+        return new EnvironmentIntConstant(name, defaultValue);
+      case ConstantTag.EnvironmentStringConstant:
+        final String name = readStringReference();
+        final Constant defaultValue = readConstantReference();
+        return new EnvironmentStringConstant(name, defaultValue);
+      case ConstantTag.UnevaluatedConstant:
+        final Expression expression = readExpression();
+        return new UnevaluatedConstant(expression);
     }
 
     throw fail('unexpected constant tag: $constantTag');
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 892a72b..2e5bb5d 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -243,6 +243,21 @@
     } else if (constant is TypeLiteralConstant) {
       writeByte(ConstantTag.TypeLiteralConstant);
       writeDartType(constant.type);
+    } else if (constant is EnvironmentBoolConstant) {
+      writeByte(ConstantTag.EnvironmentBoolConstant);
+      writeStringReference(constant.name);
+      writeConstantReference(constant.defaultValue);
+    } else if (constant is EnvironmentIntConstant) {
+      writeByte(ConstantTag.EnvironmentIntConstant);
+      writeStringReference(constant.name);
+      writeConstantReference(constant.defaultValue);
+    } else if (constant is EnvironmentStringConstant) {
+      writeByte(ConstantTag.EnvironmentStringConstant);
+      writeStringReference(constant.name);
+      writeConstantReference(constant.defaultValue);
+    } else if (constant is UnevaluatedConstant) {
+      writeByte(ConstantTag.UnevaluatedConstant);
+      writeNode(constant.expression);
     } else {
       throw new ArgumentError('Unsupported constant $constant');
     }
@@ -2048,6 +2063,39 @@
   }
 
   @override
+  void visitEnvironmentBoolConstant(EnvironmentBoolConstant node) {
+    throw new UnsupportedError('serialization of EnvironmentBoolConstants');
+  }
+
+  @override
+  void visitEnvironmentBoolConstantReference(EnvironmentBoolConstant node) {
+    throw new UnsupportedError(
+        'serialization of EnvironmentBoolConstant references');
+  }
+
+  @override
+  void visitEnvironmentIntConstant(EnvironmentIntConstant node) {
+    throw new UnsupportedError('serialization of EnvironmentIntConstants');
+  }
+
+  @override
+  void visitEnvironmentIntConstantReference(EnvironmentIntConstant node) {
+    throw new UnsupportedError(
+        'serialization of EnvironmentIntConstant references');
+  }
+
+  @override
+  void visitEnvironmentStringConstant(EnvironmentStringConstant node) {
+    throw new UnsupportedError('serialization of EnvironmentStringConstants');
+  }
+
+  @override
+  void visitEnvironmentStringConstantReference(EnvironmentStringConstant node) {
+    throw new UnsupportedError(
+        'serialization of EnvironmentStringConstant references');
+  }
+
+  @override
   void visitFieldReference(Field node) {
     throw new UnsupportedError('serialization of Field references');
   }
@@ -2192,6 +2240,17 @@
   void visitTypedefReference(Typedef node) {
     throw new UnsupportedError('serialization of Typedef references');
   }
+
+  @override
+  void visitUnevaluatedConstant(UnevaluatedConstant node) {
+    throw new UnsupportedError('serialization of UnevaluatedConstants');
+  }
+
+  @override
+  void visitUnevaluatedConstantReference(UnevaluatedConstant node) {
+    throw new UnsupportedError(
+        'serialization of UnevaluatedConstant references');
+  }
 }
 
 typedef bool LibraryFilter(Library _);
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index a53ccc7..6a34a73 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -117,9 +117,10 @@
   static const int MemberReference = 101;
 
   static const int ConstantExpression = 107;
-  // 108 is occupied by [RedirectingFactoryConstructor] (member).
-  // 109 is occupied by [SetLiteral] (expression).
-  // 110 is occupied by [ConstSetLiteral] (expression).
+
+  /// 108 is occupied by [RedirectingFactoryConstructor] (member).
+  /// 109 is occupied by [SetLiteral] (expression).
+  /// 110 is occupied by [ConstSetLiteral] (expression).
 
   static const int SpecializedTagHighBit = 0x80; // 10000000
   static const int SpecializedTagMask = 0xF8; // 11111000
@@ -136,7 +137,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 15;
+  static const int BinaryFormatVersion = 16;
 }
 
 abstract class ConstantTag {
@@ -152,4 +153,8 @@
   static const int PartialInstantiationConstant = 9;
   static const int TearOffConstant = 10;
   static const int TypeLiteralConstant = 11;
+  static const int EnvironmentBoolConstant = 12;
+  static const int EnvironmentIntConstant = 13;
+  static const int EnvironmentStringConstant = 14;
+  static const int UnevaluatedConstant = 15;
 }
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 1a7de5c..9fa31ec 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -39,9 +39,6 @@
   /// [unordered], they are not included.
   Iterable<Class> getOrderedClasses(Iterable<Class> unordered);
 
-  /// True if the component contains another class that is a subtype of given one.
-  bool hasProperSubtypes(Class class_);
-
   // Returns the instantition of each generic supertype implemented by this
   // class (e.g. getClassAsInstanceOf applied to all superclasses and
   // interfaces).
@@ -697,14 +694,6 @@
   }
 
   @override
-  bool hasProperSubtypes(Class class_) {
-    _ClassInfo info = _infoFor[class_];
-    return info.directExtenders.isNotEmpty ||
-        info.directImplementers.isNotEmpty ||
-        info.directMixers.isNotEmpty;
-  }
-
-  @override
   List<Supertype> genericSupertypesOf(Class class_) {
     final supertypes = _infoFor[class_].genericSuperTypes;
     if (supertypes == null) return const <Supertype>[];
diff --git a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
new file mode 100644
index 0000000..beae19b
--- /dev/null
+++ b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library kernel.hierarchy_based_type_environment;
+
+import '../ast.dart' show Class, InterfaceType;
+
+import '../class_hierarchy.dart' show ClassHierarchy;
+
+import '../core_types.dart' show CoreTypes;
+
+import '../type_environment.dart' show TypeEnvironment;
+
+class HierarchyBasedTypeEnvironment extends TypeEnvironment {
+  final ClassHierarchy hierarchy;
+
+  HierarchyBasedTypeEnvironment(CoreTypes coreTypes, this.hierarchy,
+      {bool legacyMode: false})
+      : super.fromSubclass(coreTypes, legacyMode: legacyMode);
+
+  @override
+  InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass) {
+    return hierarchy.getTypeAsInstanceOf(type, superclass);
+  }
+}
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 57eb05c..2f74c96 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1911,6 +1911,24 @@
     endLine(sb.toString());
   }
 
+  visitEnvironmentBoolConstant(EnvironmentBoolConstant node) {
+    final String name = syntheticNames.nameConstant(node);
+    final String defaultValue = syntheticNames.nameConstant(node.defaultValue);
+    endLine('  $name = bool.fromEnvironment(${node.name}, ${defaultValue})');
+  }
+
+  visitEnvironmentIntConstant(EnvironmentIntConstant node) {
+    final String name = syntheticNames.nameConstant(node);
+    final String defaultValue = syntheticNames.nameConstant(node.defaultValue);
+    endLine('  $name = int.fromEnvironment(${node.name}, ${defaultValue})');
+  }
+
+  visitEnvironmentStringConstant(EnvironmentStringConstant node) {
+    final String name = syntheticNames.nameConstant(node);
+    final String defaultValue = syntheticNames.nameConstant(node.defaultValue);
+    endLine('  $name = String.fromEnvironment(${node.name}, ${defaultValue})');
+  }
+
   defaultNode(Node node) {
     write('<${node.runtimeType}>');
   }
diff --git a/pkg/kernel/lib/text/serializer_combinators.dart b/pkg/kernel/lib/text/serializer_combinators.dart
index 46d0237..4b34e70 100644
--- a/pkg/kernel/lib/text/serializer_combinators.dart
+++ b/pkg/kernel/lib/text/serializer_combinators.dart
@@ -9,11 +9,71 @@
 import '../ast.dart' show Node;
 import 'text_serializer.dart' show Tagger;
 
+class DeserializationEnvironment<T extends Node> {
+  final Map<String, T> locals = <String, T>{};
+
+  final DeserializationEnvironment<T> parent;
+
+  final Set<String> usedNames = new Set<String>();
+
+  DeserializationEnvironment(this.parent) {
+    if (parent != null) {
+      usedNames.addAll(parent.usedNames);
+    }
+  }
+
+  T lookup(String name) => locals[name] ?? parent?.lookup(name);
+
+  T add(String name, T node) {
+    if (usedNames.contains(name)) {
+      throw StateError("name '$name' is already declared in this scope");
+    }
+    usedNames.add(name);
+    return locals[name] = node;
+  }
+}
+
+class SerializationEnvironment<T extends Node> {
+  final Map<T, String> locals = new Map<T, String>.identity();
+
+  int nameCount;
+
+  final SerializationEnvironment<T> parent;
+
+  static const String separator = "^";
+
+  static final int codeOfZero = "0".codeUnitAt(0);
+
+  static final int codeOfNine = "9".codeUnitAt(0);
+
+  SerializationEnvironment(this.parent) {
+    nameCount = (parent?.nameCount ?? 0);
+  }
+
+  String lookup(T node) => locals[node] ?? parent?.lookup(node);
+
+  String add(T node, String name) {
+    int prefixLength = name.length - 1;
+    bool isOnlyDigits = true;
+    while (prefixLength >= 0 && name[prefixLength] != separator) {
+      int code = name.codeUnitAt(prefixLength);
+      isOnlyDigits = isOnlyDigits && (codeOfZero <= code && code <= codeOfNine);
+      --prefixLength;
+    }
+    if (prefixLength < 0 || !isOnlyDigits) {
+      prefixLength = name.length;
+    }
+    String prefix = name.substring(0, prefixLength);
+    return locals[node] = "$prefix$separator${nameCount++}";
+  }
+}
+
 abstract class TextSerializer<T> {
   const TextSerializer();
 
-  T readFrom(Iterator<Object> stream);
-  void writeTo(StringBuffer buffer, T object);
+  T readFrom(Iterator<Object> stream, DeserializationEnvironment environment);
+  void writeTo(
+      StringBuffer buffer, T object, SerializationEnvironment environment);
 
   /// True if this serializer/deserializer writes/reads nothing.  This is true
   /// for the serializer [Nothing] and also some serializers derived from it.
@@ -23,9 +83,9 @@
 class Nothing extends TextSerializer<void> {
   const Nothing();
 
-  void readFrom(Iterator<Object> stream) {}
+  void readFrom(Iterator<Object> stream, DeserializationEnvironment _) {}
 
-  void writeTo(StringBuffer buffer, void ignored) {}
+  void writeTo(StringBuffer buffer, void ignored, SerializationEnvironment _) {}
 
   bool get isEmpty => true;
 }
@@ -33,7 +93,7 @@
 class DartString extends TextSerializer<String> {
   const DartString();
 
-  String readFrom(Iterator<Object> stream) {
+  String readFrom(Iterator<Object> stream, DeserializationEnvironment _) {
     if (stream.current is! String) {
       throw StateError("expected an atom, found a list");
     }
@@ -42,7 +102,7 @@
     return result;
   }
 
-  void writeTo(StringBuffer buffer, String object) {
+  void writeTo(StringBuffer buffer, String object, SerializationEnvironment _) {
     buffer.write(json.encode(object));
   }
 }
@@ -50,7 +110,7 @@
 class DartInt extends TextSerializer<int> {
   const DartInt();
 
-  int readFrom(Iterator<Object> stream) {
+  int readFrom(Iterator<Object> stream, DeserializationEnvironment _) {
     if (stream.current is! String) {
       throw StateError("expected an atom, found a list");
     }
@@ -59,7 +119,7 @@
     return result;
   }
 
-  void writeTo(StringBuffer buffer, int object) {
+  void writeTo(StringBuffer buffer, int object, SerializationEnvironment _) {
     buffer.write(object);
   }
 }
@@ -67,7 +127,7 @@
 class DartDouble extends TextSerializer<double> {
   const DartDouble();
 
-  double readFrom(Iterator<Object> stream) {
+  double readFrom(Iterator<Object> stream, DeserializationEnvironment _) {
     if (stream.current is! String) {
       throw StateError("expected an atom, found a list");
     }
@@ -76,7 +136,7 @@
     return result;
   }
 
-  void writeTo(StringBuffer buffer, double object) {
+  void writeTo(StringBuffer buffer, double object, SerializationEnvironment _) {
     buffer.write(object);
   }
 }
@@ -84,7 +144,7 @@
 class DartBool extends TextSerializer<bool> {
   const DartBool();
 
-  bool readFrom(Iterator<Object> stream) {
+  bool readFrom(Iterator<Object> stream, DeserializationEnvironment _) {
     if (stream.current is! String) {
       throw StateError("expected an atom, found a list");
     }
@@ -100,7 +160,7 @@
     return result;
   }
 
-  void writeTo(StringBuffer buffer, bool object) {
+  void writeTo(StringBuffer buffer, bool object, SerializationEnvironment _) {
     buffer.write(object ? 'true' : 'false');
   }
 }
@@ -121,7 +181,7 @@
       : tags = [],
         serializers = [];
 
-  T readFrom(Iterator<Object> stream) {
+  T readFrom(Iterator<Object> stream, DeserializationEnvironment environment) {
     if (stream.current is! Iterator) {
       throw StateError("expected list, found atom");
     }
@@ -134,7 +194,7 @@
     for (int i = 0; i < tags.length; ++i) {
       if (tags[i] == tag) {
         nested.moveNext();
-        T result = serializers[i].readFrom(nested);
+        T result = serializers[i].readFrom(nested, environment);
         if (nested.moveNext()) {
           throw StateError("extra cruft in tagged '${tag}'");
         }
@@ -145,7 +205,8 @@
     throw StateError("unrecognized tag '${tag}'");
   }
 
-  void writeTo(StringBuffer buffer, T object) {
+  void writeTo(
+      StringBuffer buffer, T object, SerializationEnvironment environment) {
     String tag = tagger.tag(object);
     for (int i = 0; i < tags.length; ++i) {
       if (tags[i] == tag) {
@@ -153,7 +214,7 @@
         if (!serializers[i].isEmpty) {
           buffer.write(" ");
         }
-        serializers[i].writeTo(buffer, object);
+        serializers[i].writeTo(buffer, object, environment);
         buffer.write(")");
         return;
       }
@@ -171,17 +232,33 @@
 
   Wrapped(this.unwrap, this.wrap, this.contents);
 
-  K readFrom(Iterator<Object> stream) {
-    return wrap(contents.readFrom(stream));
+  K readFrom(Iterator<Object> stream, DeserializationEnvironment environment) {
+    return wrap(contents.readFrom(stream, environment));
   }
 
-  void writeTo(StringBuffer buffer, K object) {
-    contents.writeTo(buffer, unwrap(object));
+  void writeTo(
+      StringBuffer buffer, K object, SerializationEnvironment environment) {
+    contents.writeTo(buffer, unwrap(object), environment);
   }
 
   bool get isEmpty => contents.isEmpty;
 }
 
+class ScopedReference<T extends Node> extends TextSerializer<T> {
+  final DartString stringSerializer = const DartString();
+
+  const ScopedReference();
+
+  T readFrom(Iterator<Object> stream, DeserializationEnvironment environment) {
+    return environment.lookup(stringSerializer.readFrom(stream, null));
+  }
+
+  void writeTo(
+      StringBuffer buffer, T object, SerializationEnvironment environment) {
+    stringSerializer.writeTo(buffer, environment.lookup(object), null);
+  }
+}
+
 // A serializer/deserializer for pairs.
 class Tuple2Serializer<T1, T2> extends TextSerializer<Tuple2<T1, T2>> {
   final TextSerializer<T1> first;
@@ -189,14 +266,17 @@
 
   const Tuple2Serializer(this.first, this.second);
 
-  Tuple2<T1, T2> readFrom(Iterator<Object> stream) {
-    return new Tuple2(first.readFrom(stream), second.readFrom(stream));
+  Tuple2<T1, T2> readFrom(
+      Iterator<Object> stream, DeserializationEnvironment environment) {
+    return new Tuple2(first.readFrom(stream, environment),
+        second.readFrom(stream, environment));
   }
 
-  void writeTo(StringBuffer buffer, Tuple2<T1, T2> object) {
-    first.writeTo(buffer, object.first);
+  void writeTo(StringBuffer buffer, Tuple2<T1, T2> object,
+      SerializationEnvironment environment) {
+    first.writeTo(buffer, object.first, environment);
     buffer.write(' ');
-    second.writeTo(buffer, object.second);
+    second.writeTo(buffer, object.second, environment);
   }
 }
 
@@ -214,17 +294,21 @@
 
   const Tuple3Serializer(this.first, this.second, this.third);
 
-  Tuple3<T1, T2, T3> readFrom(Iterator<Object> stream) {
-    return new Tuple3(first.readFrom(stream), second.readFrom(stream),
-        third.readFrom(stream));
+  Tuple3<T1, T2, T3> readFrom(
+      Iterator<Object> stream, DeserializationEnvironment environment) {
+    return new Tuple3(
+        first.readFrom(stream, environment),
+        second.readFrom(stream, environment),
+        third.readFrom(stream, environment));
   }
 
-  void writeTo(StringBuffer buffer, Tuple3<T1, T2, T3> object) {
-    first.writeTo(buffer, object.first);
+  void writeTo(StringBuffer buffer, Tuple3<T1, T2, T3> object,
+      SerializationEnvironment environment) {
+    first.writeTo(buffer, object.first, environment);
     buffer.write(' ');
-    second.writeTo(buffer, object.second);
+    second.writeTo(buffer, object.second, environment);
     buffer.write(' ');
-    third.writeTo(buffer, object.third);
+    third.writeTo(buffer, object.third, environment);
   }
 }
 
@@ -245,19 +329,24 @@
 
   const Tuple4Serializer(this.first, this.second, this.third, this.fourth);
 
-  Tuple4<T1, T2, T3, T4> readFrom(Iterator<Object> stream) {
-    return new Tuple4(first.readFrom(stream), second.readFrom(stream),
-        third.readFrom(stream), fourth.readFrom(stream));
+  Tuple4<T1, T2, T3, T4> readFrom(
+      Iterator<Object> stream, DeserializationEnvironment environment) {
+    return new Tuple4(
+        first.readFrom(stream, environment),
+        second.readFrom(stream, environment),
+        third.readFrom(stream, environment),
+        fourth.readFrom(stream, environment));
   }
 
-  void writeTo(StringBuffer buffer, Tuple4<T1, T2, T3, T4> object) {
-    first.writeTo(buffer, object.first);
+  void writeTo(StringBuffer buffer, Tuple4<T1, T2, T3, T4> object,
+      SerializationEnvironment environment) {
+    first.writeTo(buffer, object.first, environment);
     buffer.write(' ');
-    second.writeTo(buffer, object.second);
+    second.writeTo(buffer, object.second, environment);
     buffer.write(' ');
-    third.writeTo(buffer, object.third);
+    third.writeTo(buffer, object.third, environment);
     buffer.write(' ');
-    fourth.writeTo(buffer, object.fourth);
+    fourth.writeTo(buffer, object.fourth, environment);
   }
 }
 
@@ -276,7 +365,8 @@
 
   const ListSerializer(this.elements);
 
-  List<T> readFrom(Iterator<Object> stream) {
+  List<T> readFrom(
+      Iterator<Object> stream, DeserializationEnvironment environment) {
     if (stream.current is! Iterator) {
       throw StateError("expected a list, found an atom");
     }
@@ -284,17 +374,18 @@
     list.moveNext();
     List<T> result = [];
     while (list.current != null) {
-      result.add(elements.readFrom(list));
+      result.add(elements.readFrom(list, environment));
     }
     stream.moveNext();
     return result;
   }
 
-  void writeTo(StringBuffer buffer, List<T> object) {
+  void writeTo(StringBuffer buffer, List<T> object,
+      SerializationEnvironment environment) {
     buffer.write('(');
     for (int i = 0; i < object.length; ++i) {
       if (i != 0) buffer.write(' ');
-      elements.writeTo(buffer, object[i]);
+      elements.writeTo(buffer, object[i], environment);
     }
     buffer.write(')');
   }
@@ -305,19 +396,20 @@
 
   const Optional(this.contents);
 
-  T readFrom(Iterator<Object> stream) {
+  T readFrom(Iterator<Object> stream, DeserializationEnvironment environment) {
     if (stream.current == '_') {
       stream.moveNext();
       return null;
     }
-    return contents.readFrom(stream);
+    return contents.readFrom(stream, environment);
   }
 
-  void writeTo(StringBuffer buffer, T object) {
+  void writeTo(
+      StringBuffer buffer, T object, SerializationEnvironment environment) {
     if (object == null) {
       buffer.write('_');
     } else {
-      contents.writeTo(buffer, object);
+      contents.writeTo(buffer, object, environment);
     }
   }
 }
diff --git a/pkg/kernel/lib/text/text_serialization_verifier.dart b/pkg/kernel/lib/text/text_serialization_verifier.dart
index 9ab7e77..644f15a 100644
--- a/pkg/kernel/lib/text/text_serialization_verifier.dart
+++ b/pkg/kernel/lib/text/text_serialization_verifier.dart
@@ -80,7 +80,7 @@
     stream.moveNext();
     T result;
     try {
-      result = serializer.readFrom(stream);
+      result = serializer.readFrom(stream, null);
     } catch (exception) {
       failures.add(
           new TextDeserializationFailure(exception.toString(), uri, offset));
@@ -96,7 +96,7 @@
       T node, TextSerializer<T> serializer, Uri uri, int offset) {
     StringBuffer buffer = new StringBuffer();
     try {
-      serializer.writeTo(buffer, node);
+      serializer.writeTo(buffer, node, null);
     } catch (exception) {
       failures
           .add(new TextSerializationFailure(exception.toString(), uri, offset));
@@ -217,28 +217,16 @@
 
   @override
   void visitRedirectingFactoryConstructorReference(
-      RedirectingFactoryConstructor node) {
-    storeLastSeenUriAndOffset(node);
-    node.visitChildren(this);
-  }
+      RedirectingFactoryConstructor node) {}
 
   @override
-  void visitProcedureReference(Procedure node) {
-    storeLastSeenUriAndOffset(node);
-    node.visitChildren(this);
-  }
+  void visitProcedureReference(Procedure node) {}
 
   @override
-  void visitConstructorReference(Constructor node) {
-    storeLastSeenUriAndOffset(node);
-    node.visitChildren(this);
-  }
+  void visitConstructorReference(Constructor node) {}
 
   @override
-  void visitFieldReference(Field node) {
-    storeLastSeenUriAndOffset(node);
-    node.visitChildren(this);
-  }
+  void visitFieldReference(Field node) {}
 
   @override
   void visitTypeLiteralConstantReference(TypeLiteralConstant node) {
@@ -314,18 +302,36 @@
   }
 
   @override
-  void visitTypedefReference(Typedef node) {
+  void visitEnvironmentBoolConstantReference(EnvironmentBoolConstant node) {
     storeLastSeenUriAndOffset(node);
     node.visitChildren(this);
   }
 
   @override
-  void visitClassReference(Class node) {
+  void visitEnvironmentIntConstantReference(EnvironmentIntConstant node) {
     storeLastSeenUriAndOffset(node);
     node.visitChildren(this);
   }
 
   @override
+  void visitEnvironmentStringConstantReference(EnvironmentStringConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitUnevaluatedConstantReference(UnevaluatedConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitTypedefReference(Typedef node) {}
+
+  @override
+  void visitClassReference(Class node) {}
+
+  @override
   void visitTypeLiteralConstant(TypeLiteralConstant node) {
     storeLastSeenUriAndOffset(node);
     node.visitChildren(this);
@@ -398,6 +404,30 @@
   }
 
   @override
+  void visitEnvironmentBoolConstant(EnvironmentBoolConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitEnvironmentIntConstant(EnvironmentIntConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitEnvironmentStringConstant(EnvironmentStringConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitUnevaluatedConstant(UnevaluatedConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitTypedefType(TypedefType node) {
     storeLastSeenUriAndOffset(node);
     makeDartTypeRoundTrip(node);
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 2848583..06799f1 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -88,6 +88,16 @@
   }
 
   String visitLet(Let _) => "let";
+
+  String visitPropertyGet(PropertyGet _) => "get-prop";
+  String visitPropertySet(PropertySet _) => "set-prop";
+  String visitSuperPropertyGet(SuperPropertyGet _) => "get-super";
+  String visitSuperPropertySet(SuperPropertySet _) => "set-super";
+  String visitMethodInvocation(MethodInvocation _) => "invoke-method";
+  String visitSuperMethodInvocation(SuperMethodInvocation _) => "invoke-super";
+
+  String visitVariableGet(VariableGet _) => "get-var";
+  String visitVariableSet(VariableSet _) => "set-var";
 }
 
 TextSerializer<InvalidExpression> invalidExpressionSerializer = new Wrapped(
@@ -361,20 +371,180 @@
       keyType: tuple.first, valueType: tuple.second, isConst: true);
 }
 
-TextSerializer<Let> letSerializer = new Wrapped(unwrapLet, wrapLet,
-    new Tuple2Serializer(variableDeclarationSerializer, expressionSerializer));
+class LetSerializer extends TextSerializer<Let> {
+  const LetSerializer();
 
-Tuple2<VariableDeclaration, Expression> unwrapLet(Let expression) {
-  return new Tuple2(expression.variable, expression.body);
+  Let readFrom(
+      Iterator<Object> stream, DeserializationEnvironment environment) {
+    VariableDeclaration variable =
+        variableDeclarationSerializer.readFrom(stream, environment);
+    Expression body = expressionSerializer.readFrom(
+        stream,
+        new DeserializationEnvironment(environment)
+          ..add(variable.name, variable));
+    return new Let(variable, body);
+  }
+
+  void writeTo(
+      StringBuffer buffer, Let object, SerializationEnvironment environment) {
+    SerializationEnvironment bodyScope =
+        new SerializationEnvironment(environment);
+    VariableDeclaration variable = object.variable;
+    String oldVariableName = variable.name;
+    String newVariableName = bodyScope.add(variable, oldVariableName);
+    variableDeclarationSerializer.writeTo(
+        buffer, variable..name = newVariableName, environment);
+    variable.name = oldVariableName;
+    buffer.write(' ');
+    expressionSerializer.writeTo(buffer, object.body, bodyScope);
+  }
 }
 
-Let wrapLet(Tuple2<VariableDeclaration, Expression> tuple) {
-  return new Let(tuple.first, tuple.second);
+TextSerializer<Let> letSerializer = const LetSerializer();
+
+TextSerializer<PropertyGet> propertyGetSerializer = new Wrapped(
+    unwrapPropertyGet,
+    wrapPropertyGet,
+    new Tuple2Serializer(expressionSerializer, nameSerializer));
+
+Tuple2<Expression, Name> unwrapPropertyGet(PropertyGet expression) {
+  return new Tuple2(expression.receiver, expression.name);
+}
+
+PropertyGet wrapPropertyGet(Tuple2<Expression, Name> tuple) {
+  return new PropertyGet(tuple.first, tuple.second);
+}
+
+TextSerializer<PropertySet> propertySetSerializer = new Wrapped(
+    unwrapPropertySet,
+    wrapPropertySet,
+    new Tuple3Serializer(
+        expressionSerializer, nameSerializer, expressionSerializer));
+
+Tuple3<Expression, Name, Expression> unwrapPropertySet(PropertySet expression) {
+  return new Tuple3(expression.receiver, expression.name, expression.value);
+}
+
+PropertySet wrapPropertySet(Tuple3<Expression, Name, Expression> tuple) {
+  return new PropertySet(tuple.first, tuple.second, tuple.third);
+}
+
+TextSerializer<SuperPropertyGet> superPropertyGetSerializer =
+    new Wrapped(unwrapSuperPropertyGet, wrapSuperPropertyGet, nameSerializer);
+
+Name unwrapSuperPropertyGet(SuperPropertyGet expression) {
+  return expression.name;
+}
+
+SuperPropertyGet wrapSuperPropertyGet(Name name) {
+  return new SuperPropertyGet(name);
+}
+
+TextSerializer<SuperPropertySet> superPropertySetSerializer = new Wrapped(
+    unwrapSuperPropertySet,
+    wrapSuperPropertySet,
+    new Tuple2Serializer(nameSerializer, expressionSerializer));
+
+Tuple2<Name, Expression> unwrapSuperPropertySet(SuperPropertySet expression) {
+  return new Tuple2(expression.name, expression.value);
+}
+
+SuperPropertySet wrapSuperPropertySet(Tuple2<Name, Expression> tuple) {
+  return new SuperPropertySet(tuple.first, tuple.second, null);
+}
+
+TextSerializer<MethodInvocation> methodInvocationSerializer = new Wrapped(
+    unwrapMethodInvocation,
+    wrapMethodInvocation,
+    new Tuple3Serializer(
+        expressionSerializer, nameSerializer, argumentsSerializer));
+
+Tuple3<Expression, Name, Arguments> unwrapMethodInvocation(
+    MethodInvocation expression) {
+  return new Tuple3(expression.receiver, expression.name, expression.arguments);
+}
+
+MethodInvocation wrapMethodInvocation(
+    Tuple3<Expression, Name, Arguments> tuple) {
+  return new MethodInvocation(tuple.first, tuple.second, tuple.third);
+}
+
+TextSerializer<SuperMethodInvocation> superMethodInvocationSerializer =
+    new Wrapped(unwrapSuperMethodInvocation, wrapSuperMethodInvocation,
+        new Tuple2Serializer(nameSerializer, argumentsSerializer));
+
+Tuple2<Name, Arguments> unwrapSuperMethodInvocation(
+    SuperMethodInvocation expression) {
+  return new Tuple2(expression.name, expression.arguments);
+}
+
+SuperMethodInvocation wrapSuperMethodInvocation(Tuple2<Name, Arguments> tuple) {
+  return new SuperMethodInvocation(tuple.first, tuple.second);
+}
+
+TextSerializer<VariableGet> variableGetSerializer = new Wrapped(
+    unwrapVariableGet,
+    wrapVariableGet,
+    new Tuple2Serializer(const ScopedReference<VariableDeclaration>(),
+        new Optional(dartTypeSerializer)));
+
+Tuple2<VariableDeclaration, DartType> unwrapVariableGet(VariableGet node) {
+  return new Tuple2<VariableDeclaration, DartType>(
+      node.variable, node.promotedType);
+}
+
+VariableGet wrapVariableGet(Tuple2<VariableDeclaration, DartType> tuple) {
+  return new VariableGet(tuple.first, tuple.second);
+}
+
+TextSerializer<VariableSet> variableSetSerializer = new Wrapped(
+    unwrapVariableSet,
+    wrapVariableSet,
+    new Tuple2Serializer(
+        const ScopedReference<VariableDeclaration>(), expressionSerializer));
+
+Tuple2<VariableDeclaration, Expression> unwrapVariableSet(VariableSet node) {
+  return new Tuple2<VariableDeclaration, Expression>(node.variable, node.value);
+}
+
+VariableSet wrapVariableSet(Tuple2<VariableDeclaration, Expression> tuple) {
+  return new VariableSet(tuple.first, tuple.second);
 }
 
 Case<Expression> expressionSerializer =
     new Case.uninitialized(const ExpressionTagger());
 
+TextSerializer<NamedExpression> namedExpressionSerializer = new Wrapped(
+    unwrapNamedExpression,
+    wrapNamedExpression,
+    new Tuple2Serializer(const DartString(), expressionSerializer));
+
+Tuple2<String, Expression> unwrapNamedExpression(NamedExpression expression) {
+  return new Tuple2(expression.name, expression.value);
+}
+
+NamedExpression wrapNamedExpression(Tuple2<String, Expression> tuple) {
+  return new NamedExpression(tuple.first, tuple.second);
+}
+
+TextSerializer<Arguments> argumentsSerializer = new Wrapped(
+    unwrapArguments,
+    wrapArguments,
+    Tuple3Serializer(
+        new ListSerializer(dartTypeSerializer),
+        new ListSerializer(expressionSerializer),
+        new ListSerializer(namedExpressionSerializer)));
+
+Tuple3<List<DartType>, List<Expression>, List<NamedExpression>> unwrapArguments(
+    Arguments arguments) {
+  return new Tuple3(arguments.types, arguments.positional, arguments.named);
+}
+
+Arguments wrapArguments(
+    Tuple3<List<DartType>, List<Expression>, List<NamedExpression>> tuple) {
+  return new Arguments(tuple.second, types: tuple.first, named: tuple.third);
+}
+
 class VariableDeclarationTagger implements Tagger<VariableDeclaration> {
   const VariableDeclarationTagger();
 
@@ -539,6 +709,14 @@
     "map",
     "const-map",
     "let",
+    "get-prop",
+    "set-prop",
+    "get-super",
+    "set-super",
+    "invoke-method",
+    "invoke-super",
+    "get-var",
+    "set-var",
   ]);
   expressionSerializer.serializers.addAll([
     stringLiteralSerializer,
@@ -567,6 +745,14 @@
     mapLiteralSerializer,
     constMapLiteralSerializer,
     letSerializer,
+    propertyGetSerializer,
+    propertySetSerializer,
+    superPropertyGetSerializer,
+    superPropertySetSerializer,
+    methodInvocationSerializer,
+    superMethodInvocationSerializer,
+    variableGetSerializer,
+    variableSetSerializer,
   ]);
   dartTypeSerializer.tags.addAll([
     "invalid",
diff --git a/pkg/kernel/lib/transformations/constants.dart b/pkg/kernel/lib/transformations/constants.dart
index 4b1208c..17bd047 100644
--- a/pkg/kernel/lib/transformations/constants.dart
+++ b/pkg/kernel/lib/transformations/constants.dart
@@ -28,37 +28,40 @@
 import '../type_algebra.dart';
 import '../type_environment.dart';
 
-Component transformComponent(Component component, ConstantsBackend backend,
+Component transformComponent(
+    Component component, ConstantsBackend backend, ErrorReporter errorReporter,
     {bool keepFields: false,
     bool legacyMode: false,
     bool enableAsserts: false,
     bool evaluateAnnotations: true,
     CoreTypes coreTypes,
-    ClassHierarchy hierarchy,
-    ErrorReporter errorReporter: const _SimpleErrorReporter()}) {
+    ClassHierarchy hierarchy}) {
   coreTypes ??= new CoreTypes(component);
   hierarchy ??= new ClassHierarchy(component);
 
   final typeEnvironment =
       new TypeEnvironment(coreTypes, hierarchy, legacyMode: legacyMode);
 
-  transformLibraries(component.libraries, backend, coreTypes, typeEnvironment,
+  transformLibraries(
+      component.libraries, backend, coreTypes, typeEnvironment, errorReporter,
       keepFields: keepFields,
       legacyMode: legacyMode,
       enableAsserts: enableAsserts,
-      evaluateAnnotations: evaluateAnnotations,
-      errorReporter: errorReporter);
+      evaluateAnnotations: evaluateAnnotations);
   return component;
 }
 
-void transformLibraries(List<Library> libraries, ConstantsBackend backend,
-    CoreTypes coreTypes, TypeEnvironment typeEnvironment,
+void transformLibraries(
+    List<Library> libraries,
+    ConstantsBackend backend,
+    CoreTypes coreTypes,
+    TypeEnvironment typeEnvironment,
+    ErrorReporter errorReporter,
     {bool keepFields: false,
     bool legacyMode: false,
     bool keepVariables: false,
     bool evaluateAnnotations: true,
-    bool enableAsserts: false,
-    ErrorReporter errorReporter: const _SimpleErrorReporter()}) {
+    bool enableAsserts: false}) {
   final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
       backend,
       keepFields,
@@ -95,8 +98,8 @@
       ErrorReporter errorReporter,
       {bool legacyMode: false})
       : constantEvaluator = new ConstantEvaluator(
-            backend, typeEnvironment, coreTypes, enableAsserts,
-            legacyMode: legacyMode, errorReporter: errorReporter);
+            backend, typeEnvironment, coreTypes, enableAsserts, errorReporter,
+            legacyMode: legacyMode);
 
   // Transform the library/class members:
 
@@ -235,32 +238,32 @@
   visitVariableDeclaration(VariableDeclaration node) {
     transformAnnotations(node.annotations, node);
 
-    if (node.isConst) {
-      final Constant constant = tryEvaluateWithContext(node, node.initializer);
-
-      // If there was a constant evaluation error we will not continue and
-      // simply keep the old [node].
-      if (constant == null) {
-        return node;
-      }
-
-      constantEvaluator.env.addVariableValue(node, constant);
-
-      if (keepVariables) {
-        // So the value of the variable is still available for debugging
-        // purposes we convert the constant variable to be a final variable
-        // initialized to the evaluated constant expression.
-        node.initializer = new ConstantExpression(constant)..parent = node;
-        node.isFinal = true;
-        node.isConst = false;
-      } else {
-        // Since we convert all use-sites of constants, the constant
-        // [VariableDeclaration] is unused and we'll therefore remove it.
-        return null;
-      }
-    }
     if (node.initializer != null) {
-      node.initializer = node.initializer.accept(this)..parent = node;
+      if (node.isConst) {
+        final Constant constant =
+            tryEvaluateWithContext(node, node.initializer);
+
+        // If there was a constant evaluation error we will not continue and
+        // simply keep the old [node].
+        if (constant != null) {
+          constantEvaluator.env.addVariableValue(node, constant);
+
+          if (keepVariables) {
+            // So the value of the variable is still available for debugging
+            // purposes we convert the constant variable to be a final variable
+            // initialized to the evaluated constant expression.
+            node.initializer = new ConstantExpression(constant)..parent = node;
+            node.isFinal = true;
+            node.isConst = false;
+          } else {
+            // Since we convert all use-sites of constants, the constant
+            // [VariableDeclaration] is unused and we'll therefore remove it.
+            return null;
+          }
+        }
+      } else {
+        node.initializer = node.initializer.accept(this)..parent = node;
+      }
     }
     return node;
   }
@@ -388,10 +391,9 @@
   InstanceBuilder instanceBuilder;
   EvaluationEnvironment env;
 
-  ConstantEvaluator(
-      this.backend, this.typeEnvironment, this.coreTypes, this.enableAsserts,
-      {this.legacyMode: false,
-      this.errorReporter = const _SimpleErrorReporter()})
+  ConstantEvaluator(this.backend, this.typeEnvironment, this.coreTypes,
+      this.enableAsserts, this.errorReporter,
+      {this.legacyMode: false})
       : canonicalizationCache = <Constant, Constant>{},
         nodeCache = <Node, Constant>{};
 
@@ -817,6 +819,11 @@
     });
   }
 
+  visitInvalidExpression(InvalidExpression node) {
+    // Invalid expressions are always distinct, we do not canonicalize them.
+    return new UnevaluatedConstant(node);
+  }
+
   visitMethodInvocation(MethodInvocation node) {
     // We have no support for generic method invocation atm.
     assert(node.arguments.named.isEmpty);
@@ -1472,54 +1479,64 @@
 abstract class ErrorReporter {
   const ErrorReporter();
 
-  freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type);
-  invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
-      DartType expectedType);
-  invalidBinaryOperandType(List<TreeNode> context, TreeNode node,
-      Constant receiver, String op, DartType expectedType, DartType actualType);
-  invalidMethodInvocation(
-      List<TreeNode> context, TreeNode node, Constant receiver, String op);
-  invalidStaticInvocation(
-      List<TreeNode> context, TreeNode node, Procedure target);
-  invalidStringInterpolationOperand(
-      List<TreeNode> context, TreeNode node, Constant constant);
-  invalidSymbolName(List<TreeNode> context, TreeNode node, Constant constant);
-  zeroDivisor(
-      List<TreeNode> context, TreeNode node, IntConstant receiver, String op);
-  negativeShift(List<TreeNode> context, TreeNode node, IntConstant receiver,
-      String op, IntConstant argument);
-  nonConstLiteral(List<TreeNode> context, TreeNode node, String klass);
-  duplicateKey(List<TreeNode> context, TreeNode node, Constant key);
-  failedAssertion(List<TreeNode> context, TreeNode node, String message);
-  nonConstantVariableGet(
-      List<TreeNode> context, TreeNode node, String variableName);
-  deferredLibrary(List<TreeNode> context, TreeNode node, String importName);
-}
-
-abstract class ErrorReporterBase implements ErrorReporter {
-  const ErrorReporterBase();
-
-  report(List<TreeNode> context, String message, TreeNode node);
-
-  getFileUri(TreeNode node) {
+  Uri getFileUri(TreeNode node) {
     while (node is! FileUriNode) {
       node = node.parent;
     }
     return (node as FileUriNode).fileUri;
   }
 
-  getFileOffset(TreeNode node) {
+  int getFileOffset(TreeNode node) {
     while (node.fileOffset == TreeNode.noOffset) {
       node = node.parent;
     }
     return node == null ? TreeNode.noOffset : node.fileOffset;
   }
 
-  freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
+  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type);
+  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
+      DartType expectedType);
+  void invalidBinaryOperandType(List<TreeNode> context, TreeNode node,
+      Constant receiver, String op, DartType expectedType, DartType actualType);
+  void invalidMethodInvocation(
+      List<TreeNode> context, TreeNode node, Constant receiver, String op);
+  void invalidStaticInvocation(
+      List<TreeNode> context, TreeNode node, Procedure target);
+  void invalidStringInterpolationOperand(
+      List<TreeNode> context, TreeNode node, Constant constant);
+  void invalidSymbolName(
+      List<TreeNode> context, TreeNode node, Constant constant);
+  void zeroDivisor(
+      List<TreeNode> context, TreeNode node, IntConstant receiver, String op);
+  void negativeShift(List<TreeNode> context, TreeNode node,
+      IntConstant receiver, String op, IntConstant argument);
+  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass);
+  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key);
+  void failedAssertion(List<TreeNode> context, TreeNode node, String message);
+  void nonConstantVariableGet(
+      List<TreeNode> context, TreeNode node, String variableName);
+  void deferredLibrary(
+      List<TreeNode> context, TreeNode node, String importName);
+}
+
+class SimpleErrorReporter extends ErrorReporter {
+  const SimpleErrorReporter();
+
+  void report(List<TreeNode> context, String message, TreeNode node) {
+    io.exitCode = 42;
+    final Uri uri = getFileUri(node);
+    final int fileOffset = getFileOffset(node);
+
+    io.stderr.writeln('$uri:$fileOffset Constant evaluation error: $message');
+  }
+
+  @override
+  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
     report(context, 'Expected type to be instantiated but was ${type}', node);
   }
 
-  invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
+  @override
+  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
       DartType expectedType) {
     report(
         context,
@@ -1527,7 +1544,8 @@
         node);
   }
 
-  invalidBinaryOperandType(
+  @override
+  void invalidBinaryOperandType(
       List<TreeNode> context,
       TreeNode node,
       Constant receiver,
@@ -1541,19 +1559,22 @@
         node);
   }
 
-  invalidMethodInvocation(
+  @override
+  void invalidMethodInvocation(
       List<TreeNode> context, TreeNode node, Constant receiver, String op) {
     report(context, 'Cannot call "$op" on "$receiver" in constant expression',
         node);
   }
 
-  invalidStaticInvocation(
+  @override
+  void invalidStaticInvocation(
       List<TreeNode> context, TreeNode node, Procedure target) {
     report(
         context, 'Cannot invoke "$target" inside a constant expression', node);
   }
 
-  invalidStringInterpolationOperand(
+  @override
+  void invalidStringInterpolationOperand(
       List<TreeNode> context, TreeNode node, Constant constant) {
     report(
         context,
@@ -1562,7 +1583,9 @@
         node);
   }
 
-  invalidSymbolName(List<TreeNode> context, TreeNode node, Constant constant) {
+  @override
+  void invalidSymbolName(
+      List<TreeNode> context, TreeNode node, Constant constant) {
     report(
         context,
         'The symbol name must be a valid public Dart member name, public '
@@ -1570,7 +1593,8 @@
         node);
   }
 
-  zeroDivisor(
+  @override
+  void zeroDivisor(
       List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
     report(
         context,
@@ -1579,8 +1603,9 @@
         node);
   }
 
-  negativeShift(List<TreeNode> context, TreeNode node, IntConstant receiver,
-      String op, IntConstant argument) {
+  @override
+  void negativeShift(List<TreeNode> context, TreeNode node,
+      IntConstant receiver, String op, IntConstant argument) {
     report(
         context,
         "Binary operator '$op' on '${receiver.value}' requires non-negative "
@@ -1588,28 +1613,32 @@
         node);
   }
 
-  nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
+  @override
+  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
     report(
         context,
         'Cannot have a non-constant $klass literal within a const context.',
         node);
   }
 
-  duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
+  @override
+  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
     report(
         context,
         'Duplicate keys are not allowed in constant maps (found duplicate key "$key")',
         node);
   }
 
-  failedAssertion(List<TreeNode> context, TreeNode node, String message) {
+  @override
+  void failedAssertion(List<TreeNode> context, TreeNode node, String message) {
     report(
         context,
         'The assertion condition evaluated to "false" with message "$message"',
         node);
   }
 
-  nonConstantVariableGet(
+  @override
+  void nonConstantVariableGet(
       List<TreeNode> context, TreeNode node, String variableName) {
     report(
         context,
@@ -1618,7 +1647,9 @@
         node);
   }
 
-  deferredLibrary(List<TreeNode> context, TreeNode node, String importName) {
+  @override
+  void deferredLibrary(
+      List<TreeNode> context, TreeNode node, String importName) {
     report(
         context,
         'Deferred "$importName" cannot be used inside a constant '
@@ -1627,18 +1658,6 @@
   }
 }
 
-class _SimpleErrorReporter extends ErrorReporterBase {
-  const _SimpleErrorReporter();
-
-  report(List<TreeNode> context, String message, TreeNode node) {
-    io.exitCode = 42;
-    final Uri uri = getFileUri(node);
-    final int fileOffset = getFileOffset(node);
-
-    io.stderr.writeln('$uri:$fileOffset Constant evaluation error: $message');
-  }
-}
-
 class IsInstantiatedVisitor extends DartTypeVisitor<bool> {
   final _availableVariables = new Set<TypeParameter>();
 
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 8fa6ea8..11503d0 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -34,7 +34,7 @@
         });
       }
     }
-    var visitor = new TypeCheckingVisitor(this, environment);
+    var visitor = new TypeCheckingVisitor(this, environment, hierarchy);
     for (var library in component.libraries) {
       if (ignoreSdk && library.importUri.scheme == 'dart') continue;
       for (var class_ in library.classes) {
@@ -116,12 +116,12 @@
         InitializerVisitor<Null> {
   final TypeChecker checker;
   final TypeEnvironment environment;
+  final ClassHierarchy hierarchy;
 
   CoreTypes get coreTypes => environment.coreTypes;
-  ClassHierarchy get hierarchy => environment.hierarchy;
   Class get currentClass => environment.thisType.classNode;
 
-  TypeCheckingVisitor(this.checker, this.environment);
+  TypeCheckingVisitor(this.checker, this.environment, this.hierarchy);
 
   void checkAssignable(TreeNode where, DartType from, DartType to) {
     checker.checkAssignable(where, from, to);
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index d0603b8..b532e87 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -8,11 +8,13 @@
 import 'core_types.dart';
 import 'type_algebra.dart';
 
+import 'src/hierarchy_based_type_environment.dart'
+    show HierarchyBasedTypeEnvironment;
+
 typedef void ErrorHandler(TreeNode node, String message);
 
-class TypeEnvironment extends SubtypeTester {
+abstract class TypeEnvironment extends SubtypeTester {
   final CoreTypes coreTypes;
-  final ClassHierarchy hierarchy;
 
   @override
   final bool legacyMode;
@@ -27,7 +29,13 @@
   /// be tolerated.  See [typeError].
   ErrorHandler errorHandler;
 
-  TypeEnvironment(this.coreTypes, this.hierarchy, {this.legacyMode: false});
+  TypeEnvironment.fromSubclass(this.coreTypes, {this.legacyMode: false});
+
+  factory TypeEnvironment(CoreTypes coreTypes, ClassHierarchy hierarchy,
+      {bool legacyMode: false}) {
+    return new HierarchyBasedTypeEnvironment(coreTypes, hierarchy,
+        legacyMode: legacyMode);
+  }
 
   InterfaceType get objectType => coreTypes.objectClass.rawType;
   InterfaceType get nullType => coreTypes.nullClass.rawType;
@@ -82,8 +90,7 @@
       // we aren't concerned with it.  If a class implements multiple
       // instantiations of Future, getTypeAsInstanceOf is responsible for
       // picking the least one in the sense required by the spec.
-      InterfaceType future =
-          hierarchy.getTypeAsInstanceOf(type, coreTypes.futureClass);
+      InterfaceType future = getTypeAsInstanceOf(type, coreTypes.futureClass);
       if (future != null) {
         return future.typeArguments[0];
       }
@@ -143,21 +150,6 @@
     if (type1 == doubleType || type2 == doubleType) return doubleType;
     return numType;
   }
-
-  /// Returns true if [class_] has no proper subtypes that are usable as type
-  /// argument.
-  bool isSealedClass(Class class_) {
-    // The sealed core classes have subtypes in the patched SDK, but those
-    // classes cannot occur as type argument.
-    if (class_ == coreTypes.intClass ||
-        class_ == coreTypes.doubleClass ||
-        class_ == coreTypes.stringClass ||
-        class_ == coreTypes.boolClass ||
-        class_ == coreTypes.nullClass) {
-      return true;
-    }
-    return !hierarchy.hasProperSubtypes(class_);
-  }
 }
 
 /// The part of [TypeEnvironment] that deals with subtype tests.
@@ -167,11 +159,12 @@
   InterfaceType get objectType;
   InterfaceType get nullType;
   InterfaceType get rawFunctionType;
-  ClassHierarchy get hierarchy;
   Class get futureOrClass;
   InterfaceType futureType(DartType type);
   bool get legacyMode;
 
+  InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass);
+
   /// Determines if the given type is at the bottom of the type hierarchy.  May
   /// be overridden in subclasses.
   bool isBottom(DartType type) =>
@@ -221,8 +214,7 @@
     }
 
     if (subtype is InterfaceType && supertype is InterfaceType) {
-      var upcastType =
-          hierarchy.getTypeAsInstanceOf(subtype, supertype.classNode);
+      var upcastType = getTypeAsInstanceOf(subtype, supertype.classNode);
       if (upcastType == null) return false;
       for (int i = 0; i < upcastType.typeArguments.length; ++i) {
         // Termination: the 'supertype' parameter decreases in size.
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index 177a883..79a3be8 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -295,6 +295,13 @@
       defaultConstant(node);
   R visitTearOffConstant(TearOffConstant node) => defaultConstant(node);
   R visitTypeLiteralConstant(TypeLiteralConstant node) => defaultConstant(node);
+  R visitEnvironmentBoolConstant(EnvironmentBoolConstant node) =>
+      defaultConstant(node);
+  R visitEnvironmentIntConstant(EnvironmentIntConstant node) =>
+      defaultConstant(node);
+  R visitEnvironmentStringConstant(EnvironmentStringConstant node) =>
+      defaultConstant(node);
+  R visitUnevaluatedConstant(UnevaluatedConstant node) => defaultConstant(node);
 }
 
 class MemberReferenceVisitor<R> {
@@ -348,6 +355,13 @@
       defaultConstant(node);
   R visitTearOffConstant(TearOffConstant node) => defaultConstant(node);
   R visitTypeLiteralConstant(TypeLiteralConstant node) => defaultConstant(node);
+  R visitEnvironmentBoolConstant(EnvironmentBoolConstant node) =>
+      defaultConstant(node);
+  R visitEnvironmentIntConstant(EnvironmentIntConstant node) =>
+      defaultConstant(node);
+  R visitEnvironmentStringConstant(EnvironmentStringConstant node) =>
+      defaultConstant(node);
+  R visitUnevaluatedConstant(UnevaluatedConstant node) => defaultConstant(node);
 
   // Class references
   R visitClassReference(Class node) => null;
@@ -380,6 +394,14 @@
       defaultConstantReference(node);
   R visitTypeLiteralConstantReference(TypeLiteralConstant node) =>
       defaultConstantReference(node);
+  R visitEnvironmentBoolConstantReference(EnvironmentBoolConstant node) =>
+      defaultConstantReference(node);
+  R visitEnvironmentIntConstantReference(EnvironmentIntConstant node) =>
+      defaultConstantReference(node);
+  R visitEnvironmentStringConstantReference(EnvironmentStringConstant node) =>
+      defaultConstantReference(node);
+  R visitUnevaluatedConstantReference(UnevaluatedConstant node) =>
+      defaultConstantReference(node);
 
   // Member references
   R defaultMemberReference(Member node) => null;
diff --git a/pkg/kernel/test/class_hierarchy_bench.dart b/pkg/kernel/test/class_hierarchy_bench.dart
index cab6148..92ef9cf 100644
--- a/pkg/kernel/test/class_hierarchy_bench.dart
+++ b/pkg/kernel/test/class_hierarchy_bench.dart
@@ -68,15 +68,6 @@
     return hierarchies[currentHierarchy];
   }
 
-  {
-    var classHierarchy = getClassHierarchy();
-    if (classHierarchy is ClosedWorldClassHierarchy) {
-      for (Class class_ in classes) {
-        classHierarchy.hasProperSubtypes(class_);
-      }
-    }
-  }
-
   Random rnd = new Random(12345);
   const int numQueryTrials = 100000;
 
diff --git a/pkg/kernel/test/class_hierarchy_test.dart b/pkg/kernel/test/class_hierarchy_test.dart
index 28b6038..956c0cf 100644
--- a/pkg/kernel/test/class_hierarchy_test.dart
+++ b/pkg/kernel/test/class_hierarchy_test.dart
@@ -45,7 +45,6 @@
 
     // No updated classes, the same hierarchy.
     expect(hierarchy.applyTreeChanges([], []), same(hierarchy));
-    expect(hierarchy.hasProperSubtypes(a), true);
 
     // Has updated classes, still the same hierarchy (instance). Can answer
     // queries about the new classes.
@@ -59,11 +58,9 @@
     expect(hierarchy.applyTreeChanges([libWithB], [libWithC]), same(hierarchy));
     expect(hierarchy.isSubclassOf(a, c), false);
     expect(hierarchy.isSubclassOf(c, a), true);
-    expect(hierarchy.hasProperSubtypes(a), true);
 
     // Remove so A should no longer be a super of anything.
     expect(hierarchy.applyTreeChanges([libWithC], []), same(hierarchy));
-    expect(hierarchy.hasProperSubtypes(a), false);
   }
 
   void test_applyMemberChanges() {
diff --git a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
new file mode 100644
index 0000000..f934baa
--- /dev/null
+++ b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library kernel.text_serializer_from_kernel_nodes_test;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/text/serializer_combinators.dart';
+import 'package:kernel/text/text_reader.dart';
+import 'package:kernel/text/text_serializer.dart';
+
+void main() {
+  initializeSerializers();
+  test();
+}
+
+// Wrappers for testing.
+Expression readExpression(
+    String input, DeserializationEnvironment environment) {
+  TextIterator stream = new TextIterator(input, 0);
+  stream.moveNext();
+  Expression result = expressionSerializer.readFrom(stream, environment);
+  if (stream.moveNext()) {
+    throw StateError("extra cruft in basic literal");
+  }
+  return result;
+}
+
+String writeExpression(
+    Expression expression, SerializationEnvironment environment) {
+  StringBuffer buffer = new StringBuffer();
+  expressionSerializer.writeTo(buffer, expression, environment);
+  return buffer.toString();
+}
+
+class TestCase {
+  final String name;
+  final Node node;
+  final SerializationEnvironment serializationEnvironment;
+  final DeserializationEnvironment deserializationEnvironment;
+  final String expectation;
+
+  TestCase(
+      {this.name,
+      this.node,
+      this.expectation,
+      this.serializationEnvironment,
+      this.deserializationEnvironment});
+}
+
+void test() {
+  List<String> failures = [];
+  List<TestCase> tests = <TestCase>[
+    new TestCase(
+        name: "let dynamic x = 42 in x",
+        node: () {
+          VariableDeclaration x = new VariableDeclaration("x",
+              type: const DynamicType(), initializer: new IntLiteral(42));
+          return new Let(x, new VariableGet(x));
+        }(),
+        expectation:
+            "(let (var \"x^0\" (dynamic) (int 42) ()) (get-var \"x^0\" _))"),
+    new TestCase(
+        name: "let dynamic x = 42 in let Bottom x^0 = null in x",
+        node: () {
+          VariableDeclaration outterLetVar = new VariableDeclaration("x",
+              type: const DynamicType(), initializer: new IntLiteral(42));
+          VariableDeclaration innerLetVar = new VariableDeclaration("x",
+              type: const BottomType(), initializer: new NullLiteral());
+          return new Let(outterLetVar,
+              new Let(innerLetVar, new VariableGet(outterLetVar)));
+        }(),
+        expectation: ""
+            "(let (var \"x^0\" (dynamic) (int 42) ())"
+            " (let (var \"x^1\" (bottom) (null) ())"
+            " (get-var \"x^0\" _)))"),
+    new TestCase(
+        name: "let dynamic x = 42 in let Bottom x^0 = null in x^0",
+        node: () {
+          VariableDeclaration outterLetVar = new VariableDeclaration("x",
+              type: const DynamicType(), initializer: new IntLiteral(42));
+          VariableDeclaration innerLetVar = new VariableDeclaration("x",
+              type: const BottomType(), initializer: new NullLiteral());
+          return new Let(
+              outterLetVar, new Let(innerLetVar, new VariableGet(innerLetVar)));
+        }(),
+        expectation: ""
+            "(let (var \"x^0\" (dynamic) (int 42) ())"
+            " (let (var \"x^1\" (bottom) (null) ())"
+            " (get-var \"x^1\" _)))"),
+    () {
+      VariableDeclaration x =
+          new VariableDeclaration("x", type: const DynamicType());
+      return new TestCase(
+          name: "/* suppose: dynamic x; */ x = 42",
+          node: () {
+            return new VariableSet(x, new IntLiteral(42));
+          }(),
+          expectation: "(set-var \"x^0\" (int 42))",
+          serializationEnvironment: new SerializationEnvironment(null)
+            ..add(x, "x^0"),
+          deserializationEnvironment: new DeserializationEnvironment(null)
+            ..add("x^0", x));
+    }(),
+  ];
+  for (TestCase testCase in tests) {
+    String roundTripInput =
+        writeExpression(testCase.node, testCase.serializationEnvironment);
+    if (roundTripInput != testCase.expectation) {
+      failures.add(''
+          '* initial serialization for test "${testCase.name}"'
+          ' gave output "${roundTripInput}"');
+    }
+
+    TreeNode deserialized =
+        readExpression(roundTripInput, testCase.deserializationEnvironment);
+    String roundTripOutput =
+        writeExpression(deserialized, testCase.serializationEnvironment);
+    if (roundTripOutput != roundTripInput) {
+      failures.add(''
+          '* input "${testCase.name}" gave output "${roundTripOutput}"');
+    }
+  }
+  if (failures.isNotEmpty) {
+    print('Round trip failures:');
+    failures.forEach(print);
+    throw StateError('Round trip failures');
+  }
+}
diff --git a/pkg/kernel/test/text_serializer_test.dart b/pkg/kernel/test/text_serializer_test.dart
index f19b5b8..029b91b 100644
--- a/pkg/kernel/test/text_serializer_test.dart
+++ b/pkg/kernel/test/text_serializer_test.dart
@@ -16,7 +16,7 @@
 Expression readExpression(String input) {
   TextIterator stream = new TextIterator(input, 0);
   stream.moveNext();
-  Expression result = expressionSerializer.readFrom(stream);
+  Expression result = expressionSerializer.readFrom(stream, null);
   if (stream.moveNext()) {
     throw StateError("extra cruft in basic literal");
   }
@@ -25,19 +25,24 @@
 
 String writeExpression(Expression expression) {
   StringBuffer buffer = new StringBuffer();
-  expressionSerializer.writeTo(buffer, expression);
+  expressionSerializer.writeTo(buffer, expression, null);
   return buffer.toString();
 }
 
 void test() {
   List<String> failures = [];
   List<String> tests = [
-    "(let (var \"x\" (dynamic) (int 0) ()) (null))",
-    "(let (var \"x\" (dynamic) _ ()) (null))",
-    "(let (const \"x\" (dynamic) (int 0) ()) (null))",
-    "(let (const \"x\" (dynamic) _ ()) (null))",
-    "(let (final \"x\" (dynamic) (int 0) ()) (null))",
-    "(let (final \"x\" (dynamic) _ ()) (null))",
+    "(get-prop (int 0) (public \"hashCode\"))",
+    "(get-super (public \"hashCode\"))",
+    "(invoke-method (int 0) (public \"foo\") () ((int 1) (int 2)) ())",
+    "(invoke-method (int 0) (public \"foo\") ((dynamic) (void)) "
+        "((int 1) (int 2)) (\"others\" (list (dynamic) ((int 3) (int 4)))))",
+    "(let (var \"x^0\" (dynamic) (int 0) ()) (null))",
+    "(let (var \"x^0\" (dynamic) _ ()) (null))",
+    "(let (const \"x^0\" (dynamic) (int 0) ()) (null))",
+    "(let (const \"x^0\" (dynamic) _ ()) (null))",
+    "(let (final \"x^0\" (dynamic) (int 0) ()) (null))",
+    "(let (final \"x^0\" (dynamic) _ ()) (null))",
     "(string \"Hello, 'string'!\")",
     "(string \"Hello, \\\"string\\\"!\")",
     "(string \"Yeah nah yeah, here is\\nthis really long string haiku\\n"
diff --git a/pkg/kernel/test/type_subtype_test.dart b/pkg/kernel/test/type_subtype_test.dart
index d97c690..753e525 100644
--- a/pkg/kernel/test/type_subtype_test.dart
+++ b/pkg/kernel/test/type_subtype_test.dart
@@ -200,11 +200,16 @@
   Class futureClass;
   Class futureOrClass;
   LazyTypeEnvironment environment;
-  bool legacyMode = true;
+  bool legacyMode = false;
 
   InterfaceType futureType(DartType type) =>
       new InterfaceType(futureClass, [type]);
 
+  @override
+  InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass) {
+    return hierarchy.getTypeAsInstanceOf(type, superclass);
+  }
+
   MockSubtypeTester(
       this.hierarchy,
       this.objectType,
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 30c3b6c..e1e6bc8 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -37,6 +37,8 @@
 import 'package:vm/kernel_front_end.dart' show runWithFrontEndCompilerContext;
 import 'package:vm/http_filesystem.dart';
 import 'package:vm/target/vm.dart' show VmTarget;
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+    show CompilerOptions, parseExperimentalFlags;
 
 final bool verbose = new bool.fromEnvironment('DFE_VERBOSE');
 const String platformKernelFile = 'virtual_platform_kernel.dill';
@@ -67,6 +69,7 @@
   final FileSystem fileSystem;
   final Uri platformKernelPath;
   bool suppressWarnings;
+  List<String> experimentalFlags;
   bool bytecode;
   String packageConfig;
 
@@ -76,6 +79,7 @@
 
   Compiler(this.fileSystem, this.platformKernelPath,
       {this.suppressWarnings: false,
+      this.experimentalFlags: null,
       this.bytecode: false,
       this.packageConfig: null}) {
     Uri packagesUri = null;
@@ -92,6 +96,13 @@
       print("DFE: platformKernelPath: ${platformKernelPath}");
     }
 
+    var expFlags = List<String>();
+    if (experimentalFlags != null) {
+      for (String flag in experimentalFlags) {
+        expFlags.addAll(flag.split(","));
+      }
+    }
+
     options = new CompilerOptions()
       ..fileSystem = fileSystem
       ..target = new VmTarget(new TargetFlags())
@@ -99,6 +110,8 @@
       ..sdkSummary = platformKernelPath
       ..verbose = verbose
       ..bytecode = bytecode
+      ..experimentalFlags =
+          parseExperimentalFlags(expFlags, (msg) => errors.add(msg))
       ..onDiagnostic = (DiagnosticMessage message) {
         bool printMessage;
         switch (message.severity) {
@@ -163,10 +176,12 @@
 
   IncrementalCompilerWrapper(FileSystem fileSystem, Uri platformKernelPath,
       {bool suppressWarnings: false,
+      List<String> experimentalFlags: null,
       bool bytecode: false,
       String packageConfig: null})
       : super(fileSystem, platformKernelPath,
             suppressWarnings: suppressWarnings,
+            experimentalFlags: experimentalFlags,
             bytecode: bytecode,
             packageConfig: packageConfig);
 
@@ -186,6 +201,7 @@
     IncrementalCompilerWrapper clone = IncrementalCompilerWrapper(
         fileSystem, platformKernelPath,
         suppressWarnings: suppressWarnings,
+        experimentalFlags: experimentalFlags,
         bytecode: bytecode,
         packageConfig: packageConfig);
 
@@ -213,10 +229,12 @@
   SingleShotCompilerWrapper(FileSystem fileSystem, Uri platformKernelPath,
       {this.requireMain: false,
       bool suppressWarnings: false,
+      List<String> experimentalFlags: null,
       bool bytecode: false,
       String packageConfig: null})
       : super(fileSystem, platformKernelPath,
             suppressWarnings: suppressWarnings,
+            experimentalFlags: experimentalFlags,
             bytecode: bytecode,
             packageConfig: packageConfig);
 
@@ -240,6 +258,7 @@
 Future<Compiler> lookupOrBuildNewIncrementalCompiler(int isolateId,
     List sourceFiles, Uri platformKernelPath, List<int> platformKernel,
     {bool suppressWarnings: false,
+    List<String> experimentalFlags: null,
     bool bytecode: false,
     String packageConfig: null,
     String multirootFilepaths,
@@ -268,6 +287,7 @@
       // isolate was shut down. Message should be handled here in this script.
       compiler = new IncrementalCompilerWrapper(fileSystem, platformKernelPath,
           suppressWarnings: suppressWarnings,
+          experimentalFlags: experimentalFlags,
           bytecode: bytecode,
           packageConfig: packageConfig);
     }
@@ -445,10 +465,12 @@
   final int isolateId = request[6];
   final List sourceFiles = request[7];
   final bool suppressWarnings = request[8];
-  final bool bytecode = request[9];
-  final String packageConfig = request[10];
-  final String multirootFilepaths = request[11];
-  final String multirootScheme = request[12];
+  final List<String> experimentalFlags =
+      request[9] != null ? request[9].cast<String>() : null;
+  final bool bytecode = request[10];
+  final String packageConfig = request[11];
+  final String multirootFilepaths = request[12];
+  final String multirootScheme = request[13];
 
   if (bytecode) {
     // Bytecode generator is hooked into kernel service after kernel component
@@ -507,6 +529,7 @@
     compiler = await lookupOrBuildNewIncrementalCompiler(
         isolateId, sourceFiles, platformKernelPath, platformKernel,
         suppressWarnings: suppressWarnings,
+        experimentalFlags: experimentalFlags,
         bytecode: bytecode,
         packageConfig: packageConfig,
         multirootFilepaths: multirootFilepaths,
@@ -517,6 +540,7 @@
     compiler = new SingleShotCompilerWrapper(fileSystem, platformKernelPath,
         requireMain: false,
         suppressWarnings: suppressWarnings,
+        experimentalFlags: experimentalFlags,
         bytecode: bytecode,
         packageConfig: packageConfig);
   }
@@ -641,6 +665,7 @@
     1 /* isolateId chosen randomly */,
     [] /* source files */,
     false /* suppress warnings */,
+    null /* experimental_flags */,
     false /* generate bytecode */,
     null /* package_config */,
     null /* multirootFilepaths */,
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 11f5bcf..04a58fb 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -830,8 +830,7 @@
     locals = new LocalVariables(node);
     // TODO(alexmarkov): improve caching in ConstantEvaluator and reuse it
     constantEvaluator = new ConstantEvaluator(constantsBackend, typeEnvironment,
-        coreTypes, /* enableAsserts = */ true,
-        errorReporter: errorReporter)
+        coreTypes, /* enableAsserts = */ true, errorReporter)
       ..env = new EvaluationEnvironment();
     labeledStatements = <LabeledStatement, Label>{};
     switchCases = <SwitchCase, Label>{};
diff --git a/pkg/vm/lib/constants_error_reporter.dart b/pkg/vm/lib/constants_error_reporter.dart
index eba53b4..cadbc0e 100644
--- a/pkg/vm/lib/constants_error_reporter.dart
+++ b/pkg/vm/lib/constants_error_reporter.dart
@@ -12,11 +12,11 @@
 import 'package:front_end/src/api_unstable/vm.dart' as codes;
 
 import 'package:kernel/ast.dart'
-    show Constant, DartType, FileUriNode, IntConstant, Procedure, TreeNode;
+    show Constant, DartType, IntConstant, Procedure, TreeNode;
 import 'package:kernel/transformations/constants.dart' as constants;
 import 'package:kernel/type_environment.dart' show TypeEnvironment;
 
-class ForwardConstantEvaluationErrors implements constants.ErrorReporter {
+class ForwardConstantEvaluationErrors extends constants.ErrorReporter {
   // This will get the currently active [CompilerContext] from a zone variable.
   // If there is no active context, this will throw.
   final CompilerContext compilerContext = CompilerContext.current;
@@ -25,25 +25,29 @@
 
   ForwardConstantEvaluationErrors(this.typeEnvironment);
 
-  freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
+  @override
+  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
     final message =
         codes.templateConstEvalFreeTypeParameter.withArguments(type);
     reportIt(context, message, node);
   }
 
-  duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
+  @override
+  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
     final message = codes.templateConstEvalDuplicateKey.withArguments(key);
     reportIt(context, message, node);
   }
 
-  invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
+  @override
+  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
       DartType expectedType) {
     final message = codes.templateConstEvalInvalidType.withArguments(
         receiver, expectedType, receiver.getType(typeEnvironment));
     reportIt(context, message, node);
   }
 
-  invalidBinaryOperandType(
+  @override
+  void invalidBinaryOperandType(
       List<TreeNode> context,
       TreeNode node,
       Constant receiver,
@@ -55,54 +59,63 @@
     reportIt(context, message, node);
   }
 
-  invalidMethodInvocation(
+  @override
+  void invalidMethodInvocation(
       List<TreeNode> context, TreeNode node, Constant receiver, String op) {
     final message = codes.templateConstEvalInvalidMethodInvocation
         .withArguments(op, receiver);
     reportIt(context, message, node);
   }
 
-  invalidStaticInvocation(
+  @override
+  void invalidStaticInvocation(
       List<TreeNode> context, TreeNode node, Procedure target) {
     final message = codes.templateConstEvalInvalidStaticInvocation
         .withArguments(target.name.toString());
     reportIt(context, message, node);
   }
 
-  invalidStringInterpolationOperand(
+  @override
+  void invalidStringInterpolationOperand(
       List<TreeNode> context, TreeNode node, Constant constant) {
     final message = codes.templateConstEvalInvalidStringInterpolationOperand
         .withArguments(constant);
     reportIt(context, message, node);
   }
 
-  invalidSymbolName(List<TreeNode> context, TreeNode node, Constant constant) {
+  @override
+  void invalidSymbolName(
+      List<TreeNode> context, TreeNode node, Constant constant) {
     final message =
         codes.templateConstEvalInvalidSymbolName.withArguments(constant);
     reportIt(context, message, node);
   }
 
-  zeroDivisor(
+  @override
+  void zeroDivisor(
       List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
     final message = codes.templateConstEvalZeroDivisor
         .withArguments(op, '${receiver.value}');
     reportIt(context, message, node);
   }
 
-  negativeShift(List<TreeNode> context, TreeNode node, IntConstant receiver,
-      String op, IntConstant argument) {
+  @override
+  void negativeShift(List<TreeNode> context, TreeNode node,
+      IntConstant receiver, String op, IntConstant argument) {
     final message = codes.templateConstEvalNegativeShift
         .withArguments(op, '${receiver.value}', '${argument.value}');
     reportIt(context, message, node);
   }
 
-  nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
+  @override
+  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
     final message =
         codes.templateConstEvalNonConstantLiteral.withArguments(klass);
     reportIt(context, message, node);
   }
 
-  failedAssertion(List<TreeNode> context, TreeNode node, String string) {
+  @override
+  void failedAssertion(List<TreeNode> context, TreeNode node, String string) {
     final message = string == null
         ? codes.messageConstEvalFailedAssertion
         : codes.templateConstEvalFailedAssertionWithMessage
@@ -110,20 +123,23 @@
     reportIt(context, message, node);
   }
 
-  nonConstantVariableGet(
+  @override
+  void nonConstantVariableGet(
       List<TreeNode> context, TreeNode node, String variableName) {
     final message = codes.templateConstEvalNonConstantVariableGet
         .withArguments(variableName);
     reportIt(context, message, node);
   }
 
-  deferredLibrary(List<TreeNode> context, TreeNode node, String importName) {
+  @override
+  void deferredLibrary(
+      List<TreeNode> context, TreeNode node, String importName) {
     final message =
         codes.templateConstEvalDeferredLibrary.withArguments(importName);
     reportIt(context, message, node);
   }
 
-  reportIt(List<TreeNode> context, codes.Message message, TreeNode node) {
+  void reportIt(List<TreeNode> context, codes.Message message, TreeNode node) {
     final Uri uri = getFileUri(node);
     final int fileOffset = getFileOffset(node);
 
@@ -141,18 +157,4 @@
     compilerContext.options
         .report(locatedMessage, Severity.error, context: contextMessages);
   }
-
-  getFileUri(TreeNode node) {
-    while (node is! FileUriNode) {
-      node = node.parent;
-    }
-    return (node as FileUriNode).fileUri;
-  }
-
-  getFileOffset(TreeNode node) {
-    while (node?.fileOffset == TreeNode.noOffset) {
-      node = node.parent;
-    }
-    return node == null ? TreeNode.noOffset : node.fileOffset;
-  }
 }
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index d84850d..2105181 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -385,10 +385,10 @@
     // TFA will remove constants fields which are unused (and respects the
     // vm/embedder entrypoints).
     constants.transformComponent(component, vmConstants,
+        new ForwardConstantEvaluationErrors(typeEnvironment),
         keepFields: true,
         evaluateAnnotations: true,
-        enableAsserts: enableAsserts,
-        errorReporter: new ForwardConstantEvaluationErrors(typeEnvironment));
+        enableAsserts: enableAsserts);
   });
 }
 
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 71d48cb..f403b43 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -220,6 +220,7 @@
         }
         fieldValue.setValue(initializerResult, typeFlowAnalysis,
             field.isStatic ? null : args.receiver);
+        fieldValue.isInitialized = true;
         return const EmptyType();
     }
 
@@ -732,6 +733,9 @@
   final Summary typeGuardSummary;
   Type value;
 
+  /// Flag indicating if field initializer was executed.
+  bool isInitialized = false;
+
   _FieldValue(this.field, this.typeGuardSummary)
       : staticType = new Type.fromStatic(field.type) {
     if (field.initializer == null && _isDefaultValueOfFieldObservable()) {
@@ -1357,7 +1361,7 @@
     hierarchyCache = new _ClassHierarchyCache(
         this, hierarchy, _genericInterfacesInfo, environment);
     summaryCollector = new SummaryCollector(
-        target, environment, this, nativeCodeOracle, hierarchyCache);
+        target, environment, hierarchy, this, nativeCodeOracle, hierarchyCache);
     _invocationsCache = new _InvocationsCache(this);
     workList = new _WorkList(this);
 
@@ -1385,6 +1389,8 @@
     hierarchyCache.seal();
   }
 
+  /// Returns true if analysis found that given member
+  /// could be executed / field could be accessed.
   bool isMemberUsed(Member member) {
     if (member is Field) {
       return _fieldValues.containsKey(member);
@@ -1393,6 +1399,16 @@
     }
   }
 
+  /// Returns true if analysis found that initializer of the given [field]
+  /// could be executed.
+  bool isFieldInitializerUsed(Field field) {
+    final fieldValue = _fieldValues[field];
+    if (fieldValue != null) {
+      return fieldValue.isInitialized;
+    }
+    return false;
+  }
+
   bool isClassAllocated(Class c) => hierarchyCache.allocatedClasses.contains(c);
 
   Call callSite(TreeNode node) => summaryCollector.callSites[node];
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index af0e734..e9d777b 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -10,6 +10,7 @@
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/ast.dart' hide Statement, StatementVisitor;
 import 'package:kernel/ast.dart' as ast show Statement, StatementVisitor;
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/type_environment.dart' show TypeEnvironment;
 import 'package:kernel/type_algebra.dart' show Substitution;
 
@@ -278,6 +279,7 @@
 class SummaryCollector extends RecursiveVisitor<TypeExpr> {
   final Target target;
   final TypeEnvironment _environment;
+  final ClassHierarchy _hierarchy;
   final EntryPointsListener _entryPointsListener;
   final NativeCodeOracle _nativeCodeOracle;
   final GenericInterfacesInfo _genericInterfacesInfo;
@@ -298,8 +300,13 @@
   // Currently only used for factory constructors.
   Map<TypeParameter, TypeExpr> _fnTypeVariables;
 
-  SummaryCollector(this.target, this._environment, this._entryPointsListener,
-      this._nativeCodeOracle, this._genericInterfacesInfo) {
+  SummaryCollector(
+      this.target,
+      this._environment,
+      this._hierarchy,
+      this._entryPointsListener,
+      this._nativeCodeOracle,
+      this._genericInterfacesInfo) {
     assertx(_genericInterfacesInfo != null);
     constantAllocationCollector = new ConstantAllocationCollector(this);
   }
@@ -992,8 +999,7 @@
     assertx(_receiver != null, details: node);
     final args = _visitArguments(_receiver, node.arguments);
     // Re-resolve target due to partial mixin resolution.
-    final target =
-        _environment.hierarchy.getDispatchTarget(_superclass, node.name);
+    final target = _hierarchy.getDispatchTarget(_superclass, node.name);
     if (target == null) {
       return new Type.empty();
     } else {
@@ -1021,8 +1027,7 @@
     assertx(_receiver != null, details: node);
     final args = new Args<TypeExpr>([_receiver]);
     // Re-resolve target due to partial mixin resolution.
-    final target =
-        _environment.hierarchy.getDispatchTarget(_superclass, node.name);
+    final target = _hierarchy.getDispatchTarget(_superclass, node.name);
     if (target == null) {
       return new Type.empty();
     } else {
@@ -1038,8 +1043,8 @@
     final value = _visit(node.value);
     final args = new Args<TypeExpr>([_receiver, value]);
     // Re-resolve target due to partial mixin resolution.
-    final target = _environment.hierarchy
-        .getDispatchTarget(_superclass, node.name, setter: true);
+    final target =
+        _hierarchy.getDispatchTarget(_superclass, node.name, setter: true);
     if (target != null) {
       assertx((target is Field) || ((target is Procedure) && target.isSetter));
       _entryPointsListener.recordMemberCalledViaThis(target);
@@ -1539,14 +1544,15 @@
   final TypeEnvironment _environment;
   final SummaryCollector _summaryCollector;
 
-  CreateAllSummariesVisitor(
-      Target target, this._environment, GenericInterfacesInfo hierarchy)
+  CreateAllSummariesVisitor(Target target, this._environment,
+      ClassHierarchy hierarchy, GenericInterfacesInfo genericInterfacesInfo)
       : _summaryCollector = new SummaryCollector(
             target,
             _environment,
+            hierarchy,
             new EmptyEntryPointsListener(),
             new NativeCodeOracle(null, null),
-            hierarchy);
+            genericInterfacesInfo);
 
   @override
   defaultMember(Member m) {
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 837baeb..4e3103d 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -46,7 +46,8 @@
 
   if (kDumpAllSummaries) {
     Statistics.reset();
-    new CreateAllSummariesVisitor(target, types, genericInterfacesInfo)
+    new CreateAllSummariesVisitor(
+            target, types, hierarchy, genericInterfacesInfo)
         .visitComponent(component);
     Statistics.print("All summaries statistics");
   }
@@ -73,7 +74,7 @@
 
   new TreeShaker(component, typeFlowAnalysis).transformComponent(component);
 
-  new TFADevirtualization(component, typeFlowAnalysis)
+  new TFADevirtualization(component, typeFlowAnalysis, hierarchy)
       .visitComponent(component);
 
   new AnnotateKernel(component, typeFlowAnalysis).visitComponent(component);
@@ -92,9 +93,9 @@
 class TFADevirtualization extends Devirtualization {
   final TypeFlowAnalysis _typeFlowAnalysis;
 
-  TFADevirtualization(Component component, this._typeFlowAnalysis)
-      : super(_typeFlowAnalysis.environment.coreTypes, component,
-            _typeFlowAnalysis.environment.hierarchy);
+  TFADevirtualization(
+      Component component, this._typeFlowAnalysis, ClassHierarchy hierarchy)
+      : super(_typeFlowAnalysis.environment.coreTypes, component, hierarchy);
 
   @override
   DirectCallMetadata getDirectCall(TreeNode node, Member interfaceTarget,
@@ -366,6 +367,8 @@
   bool isClassAllocated(Class c) => typeFlowAnalysis.isClassAllocated(c);
   bool isMemberUsed(Member m) => _usedMembers.contains(m);
   bool isMemberBodyReachable(Member m) => typeFlowAnalysis.isMemberUsed(m);
+  bool isFieldInitializerReachable(Field f) =>
+      typeFlowAnalysis.isFieldInitializerUsed(f);
   bool isMemberReferencedFromNativeCode(Member m) =>
       typeFlowAnalysis.nativeCodeOracle.isMemberReferencedFromNativeCode(m);
   bool isTypedefUsed(Typedef t) => _usedTypedefs.contains(t);
@@ -602,6 +605,30 @@
   }
 
   @override
+  TreeNode visitField(Field node) {
+    if (shaker.isMemberBodyReachable(node)) {
+      if (kPrintTrace) {
+        tracePrint("Visiting $node");
+      }
+      shaker.addUsedMember(node);
+      if (node.initializer != null) {
+        if (shaker.isFieldInitializerReachable(node)) {
+          node.transformChildren(this);
+        } else {
+          node.initializer = _makeUnreachableCall([]);
+        }
+      }
+    } else if (shaker.isMemberReferencedFromNativeCode(node)) {
+      // Preserve members referenced from native code to satisfy lookups, even
+      // if they are not reachable. An instance member could be added via
+      // native code entry point but still unreachable if no instances of
+      // its enclosing class are allocated.
+      shaker.addUsedMember(node);
+    }
+    return node;
+  }
+
+  @override
   TreeNode visitMethodInvocation(MethodInvocation node) {
     node.transformChildren(this);
     if (_isUnreachable(node)) {
diff --git a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
index 1ec8d87..022c7e1 100644
--- a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
+++ b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
@@ -23,15 +23,16 @@
   final SummaryCollector _summaryCollector;
   final StringBuffer _buf = new StringBuffer();
 
-  PrintSummaries(
-      Target target, TypeEnvironment environment, CoreTypes coreTypes)
+  PrintSummaries(Target target, TypeEnvironment environment,
+      CoreTypes coreTypes, ClassHierarchy hierarchy)
       : _summaryCollector = new SummaryCollector(
             target,
             environment,
+            hierarchy,
             new EmptyEntryPointsListener(),
             new NativeCodeOracle(
                 null, new ExpressionPragmaAnnotationParser(coreTypes)),
-            new GenericInterfacesInfoImpl(environment.hierarchy));
+            new GenericInterfacesInfoImpl(hierarchy));
 
   String print(TreeNode node) {
     visitLibrary(node);
@@ -54,11 +55,12 @@
   final Library library = component.mainMethod.enclosingLibrary;
   final CoreTypes coreTypes = new CoreTypes(component);
 
-  final typeEnvironment =
-      new TypeEnvironment(coreTypes, new ClassHierarchy(component));
+  final ClassHierarchy hierarchy = new ClassHierarchy(component);
+  final typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);
 
   final actual =
-      new PrintSummaries(target, typeEnvironment, coreTypes).print(library);
+      new PrintSummaries(target, typeEnvironment, coreTypes, hierarchy)
+          .print(library);
 
   compareResultWithExpectationsFile(source, actual);
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart
new file mode 100644
index 0000000..6abe2d5
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests tree shaking of field initializer for a write-only field.
+// Regression test for https://github.com/dart-lang/sdk/issues/35632.
+
+class A {
+  A() {
+    print('A');
+  }
+}
+
+var field = A();
+
+class B {
+  B() {
+    print('B');
+  }
+}
+
+class C {
+  var instanceField = new B();
+}
+
+void main() {
+  field = null;
+  new C().instanceField = null;
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect
new file mode 100644
index 0000000..d8d8757
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect
@@ -0,0 +1,23 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+}
+class B extends core::Object {
+  constructor •() → self::B
+    : super core::Object::•() {
+    core::print("B");
+  }
+}
+class C extends core::Object {
+[@vm.inferred-type.metadata=#lib::B?] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  field self::B instanceField = new self::B::•();
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+}
+[@vm.inferred-type.metadata=dart.core::Null?]static field self::A field = throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
+static method main() → void {
+  self::field = null;
+  [@vm.direct-call.metadata=#lib::C::instanceField] new self::C::•().{self::C::instanceField} = null;
+}
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 3eb59b3..0e3e2e2 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -191,6 +191,11 @@
     if (defined(is_tsan) && is_tsan) {
       ldflags += [ "-fsanitize=thread" ]
     }
+
+    if (is_fuchsia) {
+      # safe-stack does not work with the interpreter.
+      cflags += [ "-fno-sanitize=safe-stack" ]
+    }
   }
 }
 
diff --git a/runtime/bin/extensions_fuchsia.cc b/runtime/bin/extensions_fuchsia.cc
index a177c4c..64df6b6 100644
--- a/runtime/bin/extensions_fuchsia.cc
+++ b/runtime/bin/extensions_fuchsia.cc
@@ -24,17 +24,7 @@
     "_kDartIsolateSnapshotInstructions";
 
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
-  int fd = open(library_file, O_RDONLY);
-  if (fd < 0) {
-    return NULL;
-  }
-  zx_handle_t vmo;
-  zx_status_t status = fdio_get_vmo_clone(fd, &vmo);
-  close(fd);
-  if (status != ZX_OK) {
-    return NULL;
-  }
-  return dlopen_vmo(vmo, RTLD_LAZY);
+  return dlopen(library_file, RTLD_LAZY);
 }
 
 void* Extensions::ResolveSymbol(void* lib_handle, const char* symbol) {
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 98654fe..3cb0462 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -72,6 +72,7 @@
   kCore,
   kCoreJIT,
   kCoreJITAll,
+  kApp,
   kAppJIT,
   kAppAOTBlobs,
   kAppAOTAssembly,
@@ -99,6 +100,7 @@
     "core",
     "core-jit",
     "core-jit-all",
+    "app",
     "app-jit",
     "app-aot-blobs",
     "app-aot-assembly",
@@ -124,6 +126,7 @@
   V(assembly, assembly_filename)                                               \
   V(dependencies, dependencies_filename)                                       \
   V(load_compilation_trace, load_compilation_trace_filename)                   \
+  V(load_type_feedback, load_type_feedback_filename)                           \
   V(package_root, commandline_package_root)                                    \
   V(packages, commandline_packages_file)                                       \
   V(save_obfuscation_map, obfuscation_map_filename)
@@ -297,6 +300,7 @@
       }
       break;
     }
+    case kApp:
     case kAppJIT: {
       if ((load_vm_snapshot_data_filename == NULL) ||
           (isolate_snapshot_data_filename == NULL) ||
@@ -452,6 +456,7 @@
       case kAppAOTAssembly:
         WriteDependenciesWithTarget(assembly_filename);
         break;
+      case kApp:
       case kAppJIT:
         WriteDependenciesWithTarget(isolate_snapshot_data_filename);
         // WriteDependenciesWithTarget(isolate_snapshot_instructions_filename);
@@ -563,6 +568,14 @@
     Dart_Handle result = Dart_LoadCompilationTrace(buffer, size);
     CHECK_RESULT(result);
   }
+  if ((load_type_feedback_filename != NULL) &&
+      ((snapshot_kind == kCoreJIT) || (snapshot_kind == kAppJIT))) {
+    uint8_t* buffer = NULL;
+    intptr_t size = 0;
+    ReadFile(load_type_feedback_filename, &buffer, &size);
+    Dart_Handle result = Dart_LoadTypeFeedback(buffer, size);
+    CHECK_RESULT(result);
+  }
 }
 
 static void CompileAll() {
@@ -594,11 +607,15 @@
   WriteFile(vm_snapshot_data_filename, vm_snapshot_data_buffer,
             vm_snapshot_data_size);
   if (vm_snapshot_instructions_filename != NULL) {
+    // Create empty file for the convenience of build systems. Makes things
+    // polymorphic with generating core-jit snapshots.
     WriteFile(vm_snapshot_instructions_filename, NULL, 0);
   }
   WriteFile(isolate_snapshot_data_filename, isolate_snapshot_data_buffer,
             isolate_snapshot_data_size);
   if (isolate_snapshot_instructions_filename != NULL) {
+    // Create empty file for the convenience of build systems. Makes things
+    // polymorphic with generating core-jit snapshots.
     WriteFile(isolate_snapshot_instructions_filename, NULL, 0);
   }
 }
@@ -666,6 +683,27 @@
             isolate_snapshot_instructions_size);
 }
 
+static void CreateAndWriteAppSnapshot() {
+  ASSERT(snapshot_kind == kApp);
+  ASSERT(isolate_snapshot_data_filename != NULL);
+
+  Dart_Handle result;
+  uint8_t* isolate_snapshot_data_buffer = NULL;
+  intptr_t isolate_snapshot_data_size = 0;
+
+  result = Dart_CreateSnapshot(NULL, NULL, &isolate_snapshot_data_buffer,
+                               &isolate_snapshot_data_size);
+  CHECK_RESULT(result);
+
+  WriteFile(isolate_snapshot_data_filename, isolate_snapshot_data_buffer,
+            isolate_snapshot_data_size);
+  if (isolate_snapshot_instructions_filename != NULL) {
+    // Create empty file for the convenience of build systems. Makes things
+    // polymorphic with generating core-jit snapshots.
+    WriteFile(isolate_snapshot_instructions_filename, NULL, 0);
+  }
+}
+
 static void CreateAndWriteAppJITSnapshot() {
   ASSERT(snapshot_kind == kAppJIT);
   ASSERT(isolate_snapshot_data_filename != NULL);
@@ -898,6 +936,9 @@
       LoadCompilationTrace();
       CreateAndWriteCoreJITSnapshot();
       break;
+    case kApp:
+      CreateAndWriteAppSnapshot();
+      break;
     case kAppJIT:
       LoadBytecode();
       LoadCompilationTrace();
@@ -981,7 +1022,9 @@
   } else if ((snapshot_kind == kCoreJITAll) || (snapshot_kind == kCoreJIT) ||
              (snapshot_kind == kAppJIT)) {
     vm_options.AddArgument("--fields_may_be_reset");
+#if !defined(TARGET_ARCH_IA32)
     vm_options.AddArgument("--link_natives_lazily");
+#endif
 #if !defined(PRODUCT)
     vm_options.AddArgument("--collect_code=false");
 #endif
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index bd32e22..cb1dd8d 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -879,11 +879,11 @@
       LoadBytecode();
     }
 
-    if (Options::load_compilation_trace_filename() != NULL) {
+    if (Options::load_type_feedback_filename() != NULL) {
       uint8_t* buffer = NULL;
       intptr_t size = 0;
-      ReadFile(Options::load_compilation_trace_filename(), &buffer, &size);
-      result = Dart_LoadCompilationTrace(buffer, size);
+      ReadFile(Options::load_type_feedback_filename(), &buffer, &size);
+      result = Dart_LoadTypeFeedback(buffer, size);
       CHECK_RESULT(result);
     }
 
@@ -922,12 +922,12 @@
     }
     CHECK_RESULT(result);
 
-    if (Options::save_compilation_trace_filename() != NULL) {
+    if (Options::save_type_feedback_filename() != NULL) {
       uint8_t* buffer = NULL;
       intptr_t size = 0;
-      result = Dart_SaveCompilationTrace(&buffer, &size);
+      result = Dart_SaveTypeFeedback(&buffer, &size);
       CHECK_RESULT(result);
-      WriteFile(Options::save_compilation_trace_filename(), buffer, size);
+      WriteFile(Options::save_type_feedback_filename(), buffer, size);
     }
   }
 
diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
index 5a0377e..2b668ac 100644
--- a/runtime/bin/main_options.h
+++ b/runtime/bin/main_options.h
@@ -24,8 +24,8 @@
   V(depfile, depfile)                                                          \
   V(depfile_output_filename, depfile_output_filename)                          \
   V(shared_blobs, shared_blobs_filename)                                       \
-  V(save_compilation_trace, save_compilation_trace_filename)                   \
-  V(load_compilation_trace, load_compilation_trace_filename)                   \
+  V(save_type_feedback, save_type_feedback_filename)                           \
+  V(load_type_feedback, load_type_feedback_filename)                           \
   V(root_certs_file, root_certs_file)                                          \
   V(root_certs_cache, root_certs_cache)                                        \
   V(namespace, namespc)
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 5ac0f25..a560eb2 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3152,6 +3152,12 @@
  */
 DART_EXPORT Dart_Port Dart_ServiceWaitForLoadPort();
 
+/*
+ * ====================
+ * Compilation Feedback
+ * ====================
+ */
+
 /**
  * Record all functions which have been compiled in the current isolate.
  *
@@ -3175,6 +3181,29 @@
 DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
 Dart_LoadCompilationTrace(uint8_t* buffer, intptr_t buffer_length);
 
+/**
+ * Record runtime feedback for the current isolate, including type feedback
+ * and usage counters.
+ *
+ * \param buffer Returns a pointer to a buffer containing the trace.
+ *   This buffer is scope allocated and is only valid  until the next call to
+ *   Dart_ExitScope.
+ * \param size Returns the size of the buffer.
+ * \return Returns an valid handle upon success.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_SaveTypeFeedback(uint8_t** buffer, intptr_t* buffer_length);
+
+/**
+ * Compile functions using data from Dart_SaveTypeFeedback. The data must from a
+ * VM with the same version and compiler flags.
+ *
+ * \return Returns an error handle if a compilation error was encountered or a
+ *   version mismatch is detected.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadTypeFeedback(uint8_t* buffer, intptr_t buffer_length);
+
 /*
  * ==============
  * Precompilation
diff --git a/runtime/lib/array_patch.dart b/runtime/lib/array_patch.dart
index 1ec264d..7bea7c9 100644
--- a/runtime/lib/array_patch.dart
+++ b/runtime/lib/array_patch.dart
@@ -24,7 +24,7 @@
 
   @patch
   factory List.from(Iterable elements, {bool growable: true}) {
-    if (elements is EfficientLengthIterable) {
+    if (elements is EfficientLengthIterable<E>) {
       int length = elements.length;
       var list = growable ? new _GrowableList<E>(length) : new _List<E>(length);
       if (length > 0) {
@@ -36,12 +36,25 @@
       }
       return list;
     }
-    List<E> list = new _GrowableList<E>(0);
-    for (E e in elements) {
-      list.add(e);
+    // If elements is an Iterable<E>, we won't need a type-test for each
+    // element. In the "common case" that elements is an Iterable<E>, this
+    // replaces a type-test on every element with a single type-test before
+    // starting the loop.
+    if (elements is Iterable<E>) {
+      List<E> list = new _GrowableList<E>(0);
+      for (E e in elements) {
+        list.add(e);
+      }
+      if (growable) return list;
+      return makeListFixedLength(list);
+    } else {
+      List<E> list = new _GrowableList<E>(0);
+      for (E e in elements) {
+        list.add(e);
+      }
+      if (growable) return list;
+      return makeListFixedLength(list);
     }
-    if (growable) return list;
-    return makeListFixedLength(list);
   }
 
   @patch
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 07d6afb5..83f12ca 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -908,3 +908,31 @@
   @patch
   factory LinkedHashSet.identity() => new _CompactLinkedIdentityHashSet<E>();
 }
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+  // We override _splayMin and _splayMax to optimize type-checks.
+  @patch
+  Node _splayMin(Node node) {
+    Node current = node;
+    while (current.left != null) {
+      Node left = internal.unsafeCast<Node>(current.left);
+      current.left = left.right;
+      left.right = current;
+      current = left;
+    }
+    return current;
+  }
+
+  @patch
+  Node _splayMax(Node node) {
+    Node current = node;
+    while (current.right != null) {
+      Node right = internal.unsafeCast<Node>(current.right);
+      current.right = right.left;
+      right.left = current;
+      current = right;
+    }
+    return current;
+  }
+}
diff --git a/runtime/lib/compact_hash.dart b/runtime/lib/compact_hash.dart
index 20ddf7a..8123b0f 100644
--- a/runtime/lib/compact_hash.dart
+++ b/runtime/lib/compact_hash.dart
@@ -433,7 +433,8 @@
   final int _checkSum;
   E current;
 
-  _CompactIterator(table, this._data, this._len, this._offset, this._step)
+  _CompactIterator(
+      _HashBase table, this._data, this._len, this._offset, this._step)
       : _table = table,
         _checkSum = table._checkSum;
 
@@ -445,7 +446,7 @@
       _offset += _step;
     } while (_offset < _len && _HashBase._isDeleted(_data, _data[_offset]));
     if (_offset < _len) {
-      current = _data[_offset];
+      current = internal.unsafeCast<E>(_data[_offset]);
       return true;
     } else {
       current = null;
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 1b0f849..7b1876d6 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -24,7 +24,8 @@
         is64Bit,
         makeFixedListUnmodifiable,
         makeListFixedLength,
-        patch;
+        patch,
+        unsafeCast;
 
 import "dart:async" show Completer, Future, Timer;
 
@@ -116,8 +117,8 @@
   Iterator<T> get iterator {
     // Note: _Closure._clone returns _Closure which is not related to
     // _SyncGeneratorCallback, which means we need explicit cast.
-    return new _SyncIterator<T>(
-        (_moveNextFn as _Closure)._clone() as _SyncGeneratorCallback<T>);
+    return new _SyncIterator<T>(unsafeCast<_SyncGeneratorCallback<T>>(
+        unsafeCast<_Closure>(_moveNextFn)._clone()));
   }
 }
 
diff --git a/runtime/tools/create_snapshot_file.py b/runtime/tools/create_snapshot_file.py
index d862a45..19ea870 100755
--- a/runtime/tools/create_snapshot_file.py
+++ b/runtime/tools/create_snapshot_file.py
@@ -12,7 +12,7 @@
 import string
 import subprocess
 import sys
-import google3.third_party.dart_lang.v2_1_1_dev_0_1.runtime.tools.utils as utils
+import utils
 
 
 HOST_OS = utils.GuessOS()
diff --git a/runtime/tools/layering_check.py b/runtime/tools/layering_check.py
new file mode 100755
index 0000000..50a9b25
--- /dev/null
+++ b/runtime/tools/layering_check.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Simple tool for verifying that sources from one layer do not reference
+# sources from another layer.
+#
+# Currently it only checks that core runtime headers RUNTIME_LAYER_HEADERS
+# are not included into any sources listed in SHOULD_NOT_DEPEND_ON_RUNTIME.
+
+import glob
+import os
+import re
+import sys
+
+INCLUDE_DIRECTIVE_RE = re.compile(r'^#include "(.*)"')
+
+RUNTIME_LAYER_HEADERS = [
+  'runtime/vm/isolate.h',
+  'runtime/vm/object.h',
+  'runtime/vm/raw_object.h',
+  'runtime/vm/thread.h',
+]
+
+SHOULD_NOT_DEPEND_ON_RUNTIME = [
+  'runtime/vm/allocation.h',
+  'runtime/vm/growable_array.h',
+]
+
+class LayeringChecker(object):
+  def __init__(self, root):
+    self.root = root
+    self.worklist = set()
+    # Mapping from header to a set of files it is included into.
+    self.included_into = dict()
+    # Set of files that were parsed to avoid double parsing.
+    self.loaded = set()
+    # Mapping from headers to their layer.
+    self.file_layers = {file: 'runtime' for file in RUNTIME_LAYER_HEADERS}
+
+  def Check(self):
+    self.AddAllSourcesToWorklist(os.path.join(self.root, 'runtime/vm'))
+    self.BuildIncludesGraph()
+    errors = self.PropagateLayers()
+    errors += self.CheckNotInRuntime(SHOULD_NOT_DEPEND_ON_RUNTIME)
+    return errors
+
+  def CheckNotInRuntime(self, files):
+    """Check that given files do not depend on runtime layer."""
+    errors = []
+    for file in files:
+      if not os.path.exists(os.path.join(self.root, file)):
+        errors.append('File %s does not exist.' % (file))
+      if self.file_layers.get(file) is not None:
+        errors.append(
+            'LAYERING ERROR: %s includes object.h or raw_object.h' % (file))
+    return errors
+
+  def BuildIncludesGraph(self):
+    while self.worklist:
+      file = self.worklist.pop()
+      deps = self.ExtractIncludes(file)
+      self.loaded.add(file)
+      for d in deps:
+        if d not in self.included_into:
+          self.included_into[d] = set()
+        self.included_into[d].add(file)
+        if d not in self.loaded:
+          self.worklist.add(d)
+
+  def PropagateLayers(self):
+    """Propagate layering information through include graph.
+
+    If A is in layer L and A is included into B then B is in layer L.
+    """
+    errors = []
+    self.worklist = set(self.file_layers.keys())
+    while self.worklist:
+      file = self.worklist.pop()
+      if file not in self.included_into:
+        continue
+      file_layer = self.file_layers[file]
+      for tgt in self.included_into[file]:
+        if tgt in self.file_layers:
+          if self.file_layers[tgt] != file_layer:
+            errors.add('Layer mismatch: %s (%s) is included into %s (%s)' % (
+                file, file_layer, tgt, self.file_layers[tgt]))
+        self.file_layers[tgt] = file_layer
+        self.worklist.add(tgt)
+    return errors
+
+  def AddAllSourcesToWorklist(self, dir):
+    """Add all *.cc and *.h files from dir recursively into worklist."""
+    for file in os.listdir(dir):
+      path = os.path.join(dir, file)
+      if os.path.isdir(path):
+        self.AddAllSourcesToWorklist(path)
+      elif path.endswith('.cc') or path.endswith('.h'):
+        self.worklist.add(os.path.relpath(path, self.root))
+
+  def ExtractIncludes(self, file):
+    """Extract the list of includes from the given file."""
+    deps = set()
+    with open(os.path.join(self.root, file)) as file:
+      for line in file:
+        if line.startswith('namespace dart {'):
+          break
+
+        m = INCLUDE_DIRECTIVE_RE.match(line)
+        if m is not None:
+          header = os.path.join('runtime', m.group(1))
+          if os.path.isfile(os.path.join(self.root,header)):
+            deps.add(header)
+    return deps
+
+def DoCheck(sdk_root):
+  """Run layering check at the given root folder."""
+  return LayeringChecker(sdk_root).Check()
+
+if __name__ == '__main__':
+  errors = DoCheck('.')
+  print '\n'.join(errors)
+  if errors:
+    sys.exit(-1)
+
diff --git a/runtime/vm/allocation.cc b/runtime/vm/allocation.cc
index b1a7e93..aa36221 100644
--- a/runtime/vm/allocation.cc
+++ b/runtime/vm/allocation.cc
@@ -37,16 +37,11 @@
 #if defined(DEBUG)
   if (thread_ != NULL) {
     ASSERT(Thread::Current() == thread_);
-    BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
   }
 #endif
 }
 
-Isolate* StackResource::isolate() const {
-  return thread_ == NULL ? NULL : thread_->isolate();
-}
-
-void StackResource::Init(Thread* thread) {
+void StackResource::Init(ThreadState* thread) {
   // We can only have longjumps and exceptions when there is a current
   // thread and isolate.  If there is no current thread, we don't need to
   // protect this case.
@@ -60,7 +55,7 @@
   }
 }
 
-void StackResource::UnwindAbove(Thread* thread, StackResource* new_top) {
+void StackResource::UnwindAbove(ThreadState* thread, StackResource* new_top) {
   StackResource* current_resource = thread->top_resource();
   while (current_resource != new_top) {
     current_resource->~StackResource();
@@ -68,16 +63,4 @@
   }
 }
 
-#if defined(DEBUG)
-NoSafepointScope::NoSafepointScope(Thread* current_thread)
-    : StackResource(current_thread != nullptr ? current_thread
-                                              : Thread::Current()) {
-  thread()->IncrementNoSafepointScopeDepth();
-}
-
-NoSafepointScope::~NoSafepointScope() {
-  thread()->DecrementNoSafepointScopeDepth();
-}
-#endif  // defined(DEBUG)
-
 }  // namespace dart
diff --git a/runtime/vm/allocation.h b/runtime/vm/allocation.h
index b9af2f9..420b85e 100644
--- a/runtime/vm/allocation.h
+++ b/runtime/vm/allocation.h
@@ -13,8 +13,7 @@
 namespace dart {
 
 // Forward declarations.
-class Isolate;
-class Thread;
+class ThreadState;
 
 // Stack resources subclass from this base class. The VM will ensure that the
 // destructors of these objects are called before the stack is unwound past the
@@ -23,27 +22,24 @@
 // to a stack frame above the frame where these objects were allocated.
 class StackResource {
  public:
-  explicit StackResource(Thread* thread) : thread_(NULL), previous_(NULL) {
+  explicit StackResource(ThreadState* thread) : thread_(NULL), previous_(NULL) {
     Init(thread);
   }
 
   virtual ~StackResource();
 
-  // Convenient access to the isolate of the thread of this resource.
-  Isolate* isolate() const;
-
   // The thread that owns this resource.
-  Thread* thread() const { return thread_; }
+  ThreadState* thread() const { return thread_; }
 
   // Destroy stack resources of thread until top exit frame.
-  static void Unwind(Thread* thread) { UnwindAbove(thread, NULL); }
+  static void Unwind(ThreadState* thread) { UnwindAbove(thread, NULL); }
   // Destroy stack resources of thread above new_top, exclusive.
-  static void UnwindAbove(Thread* thread, StackResource* new_top);
+  static void UnwindAbove(ThreadState* thread, StackResource* new_top);
 
  private:
-  void Init(Thread* thread);
+  void Init(ThreadState* thread);
 
-  Thread* thread_;
+  ThreadState* thread_;
   StackResource* previous_;
 
   DISALLOW_ALLOCATION();
@@ -77,27 +73,6 @@
   DISALLOW_COPY_AND_ASSIGN(ZoneAllocated);
 };
 
-// Within a NoSafepointScope, the thread must not reach any safepoint. Used
-// around code that manipulates raw object pointers directly without handles.
-#if defined(DEBUG)
-class NoSafepointScope : public StackResource {
- public:
-  explicit NoSafepointScope(Thread* thread = nullptr);
-  ~NoSafepointScope();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NoSafepointScope);
-};
-#else   // defined(DEBUG)
-class NoSafepointScope : public ValueObject {
- public:
-  explicit NoSafepointScope(Thread* thread = nullptr) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NoSafepointScope);
-};
-#endif  // defined(DEBUG)
-
 }  // namespace dart
 
 #endif  // RUNTIME_VM_ALLOCATION_H_
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 00a16a7..572175d 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1155,6 +1155,9 @@
   const Class& super = Class::Handle(cls.SuperClass());
   if (!super.IsNull()) {
     FinalizeClass(super);
+    if (cls.is_finalized()) {
+      return;
+    }
   }
   // Mark as loaded and finalized.
   cls.Finalize();
@@ -1181,154 +1184,17 @@
   }
 }
 
-static void AddRelatedClassesToList(
-    const Class& cls,
-    GrowableHandlePtrArray<const Class>* load_class_list,
-    GrowableHandlePtrArray<const Class>* load_patchclass_list) {
-  Zone* zone = Thread::Current()->zone();
-  Class& load_class = Class::Handle(zone);
-  AbstractType& interface_type = Type::Handle(zone);
-  Array& interfaces = Array::Handle(zone);
-
-  // Add all the interfaces implemented by the class that have not been
-  // already loaded to the load list. Mark the interface as loading so that
-  // we don't recursively add it back into the list.
-  interfaces ^= cls.interfaces();
-  for (intptr_t i = 0; i < interfaces.Length(); i++) {
-    interface_type ^= interfaces.At(i);
-    load_class ^= interface_type.type_class();
-    if (!load_class.is_finalized() &&
-        !load_class.is_marked_for_lazy_loading()) {
-      load_class_list->Add(load_class);
-      load_class.set_is_marked_for_lazy_loading();
-    }
-  }
-
-  // Walk up the super_class chain and add these classes to the list if they
-  // have not been already added to the load class list. Mark the class as
-  // loading so that we don't recursively add it back into the list.
-  load_class ^= cls.SuperClass();
-  while (!load_class.IsNull()) {
-    if (!load_class.is_finalized() &&
-        !load_class.is_marked_for_lazy_loading()) {
-      load_class_list->Add(load_class);
-      load_class.set_is_marked_for_lazy_loading();
-    }
-    load_class ^= load_class.SuperClass();
-  }
-
-  // Add patch classes if they exist to the load patchclass list if they have
-  // not already been loaded and patched. Mark the class as loading so that
-  // we don't recursively add it back into the list.
-  load_class ^= cls.GetPatchClass();
-  if (!load_class.IsNull()) {
-    if (!load_class.is_finalized() &&
-        !load_class.is_marked_for_lazy_loading()) {
-      load_patchclass_list->Add(load_class);
-      load_class.set_is_marked_for_lazy_loading();
-    }
-  }
-}
-
 RawError* ClassFinalizer::LoadClassMembers(const Class& cls) {
   ASSERT(Thread::Current()->IsMutatorThread());
   // If class is a top level class it is already loaded.
   if (cls.IsTopLevel()) {
     return Error::null();
   }
-  // If the class is already marked for loading return immediately.
-  if (cls.is_marked_for_lazy_loading()) {
-    return Error::null();
-  }
-  // If the class is a typedef class there is no need to try and
-  // compile it. Just finalize it directly.
-  if (cls.IsTypedefClass()) {
-#if defined(DEBUG)
-    const Class& closure_cls =
-        Class::Handle(Isolate::Current()->object_store()->closure_class());
-    ASSERT(closure_cls.is_finalized());
-#endif
-    LongJumpScope jump;
-    if (setjmp(*jump.Set()) == 0) {
-      ClassFinalizer::FinalizeClass(cls);
-      return Error::null();
-    } else {
-      return Thread::Current()->StealStickyError();
-    }
-  }
-
-  Thread* const thread = Thread::Current();
-  StackZone zone(thread);
-#if !defined(PRODUCT)
-  VMTagScope tagScope(thread, VMTag::kClassLoadingTagId);
-  TimelineDurationScope tds(thread, Timeline::GetCompilerStream(),
-                            "ClassLoading");
-  if (tds.enabled()) {
-    tds.SetNumArguments(1);
-    tds.CopyArgument(0, "class", cls.ToCString());
-  }
-#endif  // !defined(PRODUCT)
-
-  // We remember all the classes that are being lazy loaded in these lists.
-  // This also allows us to reset the marked_for_loading state in case we see
-  // an error.
-  GrowableHandlePtrArray<const Class> load_class_list(thread->zone(), 4);
-  GrowableHandlePtrArray<const Class> load_patchclass_list(thread->zone(), 4);
-
-  // Load the class and all the interfaces it implements and super classes.
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
-    if (FLAG_trace_class_finalization) {
-      THR_Print("Lazy Loading Class '%s'\n", cls.ToCString());
-    }
-
-    // Add the primary class which needs to be load to the load list.
-    // Mark the class as loading so that we don't recursively add the same
-    // class back into the list.
-    load_class_list.Add(cls);
-    cls.set_is_marked_for_lazy_loading();
-
-    // Add all super classes, interface classes and patch class if one
-    // exists to the corresponding lists.
-    // NOTE: The load_class_list array keeps growing as more classes are added
-    // to it by AddRelatedClassesToList. It is not OK to hoist
-    // load_class_list.Length() into a local variable and iterate using the
-    // local variable.
-    for (intptr_t i = 0; i < load_class_list.length(); i++) {
-      AddRelatedClassesToList(load_class_list.At(i), &load_class_list,
-                              &load_patchclass_list);
-    }
-
-    // Finish lazy loading of these classes and finialize them.
-    for (intptr_t i = (load_class_list.length() - 1); i >= 0; i--) {
-      const Class& load_class = load_class_list.At(i);
-      ASSERT(!load_class.IsNull());
-      ClassFinalizer::FinalizeClass(load_class);
-      load_class.reset_is_marked_for_lazy_loading();
-    }
-    for (intptr_t i = (load_patchclass_list.length() - 1); i >= 0; i--) {
-      const Class& load_class = load_patchclass_list.At(i);
-      ASSERT(!load_class.IsNull());
-      ClassFinalizer::FinalizeClass(load_class);
-      load_class.reset_is_marked_for_lazy_loading();
-    }
-
+    ClassFinalizer::FinalizeClass(cls);
     return Error::null();
   } else {
-    // Reset the marked for parsing flags.
-    for (intptr_t i = 0; i < load_class_list.length(); i++) {
-      const Class& load_class = load_class_list.At(i);
-      if (load_class.is_marked_for_lazy_loading()) {
-        load_class.reset_is_marked_for_lazy_loading();
-      }
-    }
-    for (intptr_t i = 0; i < load_patchclass_list.length(); i++) {
-      const Class& load_class = load_patchclass_list.At(i);
-      if (load_class.is_marked_for_lazy_loading()) {
-        load_class.reset_is_marked_for_lazy_loading();
-      }
-    }
-
     return Thread::Current()->StealStickyError();
   }
 }
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 27536c5..779e9fe 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -4202,7 +4202,7 @@
                        ImageWriter* image_writer,
                        bool vm,
                        V8SnapshotProfileWriter* profile_writer)
-    : StackResource(thread),
+    : ThreadStackResource(thread),
       heap_(thread->isolate()->heap()),
       zone_(thread->zone()),
       kind_(kind),
@@ -4616,7 +4616,7 @@
   intptr_t code_order_length = 0;
 #if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32) &&                 \
     !defined(TARGET_ARCH_DBC)
-  if (Snapshot::IncludesCode(kind_)) {
+  if (kind_ == Snapshot::kFullAOT) {
     auto code_objects =
         static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
             ->discovered_objects();
@@ -4866,7 +4866,7 @@
                            const uint8_t* instructions_buffer,
                            const uint8_t* shared_data_buffer,
                            const uint8_t* shared_instructions_buffer)
-    : StackResource(thread),
+    : ThreadStackResource(thread),
       heap_(thread->isolate()->heap()),
       zone_(thread->zone()),
       kind_(kind),
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index f1eb0c9..420742d 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -128,7 +128,7 @@
 
 typedef DirectChainedHashMap<SmiObjectIdPairTrait> SmiObjectIdMap;
 
-class Serializer : public StackResource {
+class Serializer : public ThreadStackResource {
  public:
   Serializer(Thread* thread,
              Snapshot::Kind kind,
@@ -431,7 +431,7 @@
   Serializer* serializer_;
 };
 
-class Deserializer : public StackResource {
+class Deserializer : public ThreadStackResource {
  public:
   Deserializer(Thread* thread,
                Snapshot::Kind kind,
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index a05f94f..2a9f62d 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -4,12 +4,14 @@
 
 #include "vm/compilation_trace.h"
 
+#include "vm/compiler/jit/compiler.h"
 #include "vm/globals.h"
 #include "vm/log.h"
 #include "vm/longjump.h"
 #include "vm/object_store.h"
 #include "vm/resolver.h"
 #include "vm/symbols.h"
+#include "vm/version.h"
 
 namespace dart {
 
@@ -303,6 +305,557 @@
   return Compiler::CompileFunction(thread_, function);
 }
 
+TypeFeedbackSaver::TypeFeedbackSaver(WriteStream* stream)
+    : stream_(stream),
+      cls_(Class::Handle()),
+      lib_(Library::Handle()),
+      str_(String::Handle()),
+      fields_(Array::Handle()),
+      field_(Field::Handle()),
+      code_(Code::Handle()),
+      call_sites_(Array::Handle()),
+      call_site_(ICData::Handle()) {}
+
+void TypeFeedbackSaver::WriteHeader() {
+  const char* expected_version = Version::SnapshotString();
+  ASSERT(expected_version != NULL);
+  const intptr_t version_len = strlen(expected_version);
+  stream_->WriteBytes(reinterpret_cast<const uint8_t*>(expected_version),
+                      version_len);
+}
+
+void TypeFeedbackSaver::SaveClasses() {
+  ClassTable* table = Isolate::Current()->class_table();
+
+  intptr_t num_cids = table->NumCids();
+  WriteInt(num_cids);
+
+  for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+    cls_ = table->At(cid);
+    WriteClassByName(cls_);
+  }
+}
+
+void TypeFeedbackSaver::SaveFields() {
+  ClassTable* table = Isolate::Current()->class_table();
+  intptr_t num_cids = table->NumCids();
+  for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+    cls_ = table->At(cid);
+    WriteClassByName(cls_);
+
+    fields_ = cls_.fields();
+    WriteInt(fields_.Length());
+    for (intptr_t i = 0; i < fields_.Length(); i++) {
+      field_ ^= fields_.At(i);
+
+      str_ = field_.name();
+      str_ = String::RemovePrivateKey(str_);
+      WriteString(str_);
+
+      WriteInt(field_.guarded_cid());
+      WriteInt(field_.is_nullable());
+    }
+  }
+}
+
+void TypeFeedbackSaver::Visit(const Function& function) {
+  if (!function.HasCode()) {
+    return;  // Not compiled.
+  }
+
+  cls_ = function.Owner();
+  WriteClassByName(cls_);
+
+  str_ = function.name();
+  str_ = String::RemovePrivateKey(str_);
+  WriteString(str_);
+
+  WriteInt(function.kind());
+  WriteInt(function.token_pos().value());
+
+  code_ = function.CurrentCode();
+  intptr_t usage = function.usage_counter();
+  if (usage < 0) {
+    // Usage is set to INT_MIN while in the background compilation queue ...
+    usage = (usage - INT_MIN) + FLAG_optimization_counter_threshold;
+  } else if (code_.is_optimized()) {
+    // ... and set to 0 when an optimizing compile completes.
+    usage = usage + FLAG_optimization_counter_threshold;
+  }
+  WriteInt(usage);
+
+  WriteInt(function.inlining_depth());
+
+  call_sites_ = function.ic_data_array();
+  if (call_sites_.IsNull()) {
+    call_sites_ = Object::empty_array().raw();  // Remove edge case.
+  }
+
+  // First element is edge counters.
+  WriteInt(call_sites_.Length() - 1);
+  for (intptr_t i = 1; i < call_sites_.Length(); i++) {
+    call_site_ ^= call_sites_.At(i);
+
+    WriteInt(call_site_.deopt_id());
+    WriteInt(call_site_.rebind_rule());
+
+    str_ = call_site_.target_name();
+    str_ = String::RemovePrivateKey(str_);
+    WriteString(str_);
+
+    intptr_t num_checked_arguments = call_site_.NumArgsTested();
+    WriteInt(num_checked_arguments);
+
+    intptr_t num_entries = call_site_.NumberOfChecks();
+    WriteInt(num_entries);
+
+    for (intptr_t entry_index = 0; entry_index < num_entries; entry_index++) {
+      WriteInt(call_site_.GetCountAt(entry_index));
+
+      for (intptr_t argument_index = 0; argument_index < num_checked_arguments;
+           argument_index++) {
+        WriteInt(call_site_.GetClassIdAt(entry_index, argument_index));
+      }
+    }
+  }
+}
+
+void TypeFeedbackSaver::WriteClassByName(const Class& cls) {
+  lib_ = cls.library();
+
+  str_ = lib_.url();
+  WriteString(str_);
+
+  str_ = cls_.Name();
+  str_ = String::RemovePrivateKey(str_);
+  WriteString(str_);
+}
+
+void TypeFeedbackSaver::WriteString(const String& value) {
+  const char* cstr = value.ToCString();
+  intptr_t len = strlen(cstr);
+  stream_->WriteUnsigned(len);
+  stream_->WriteBytes(cstr, len);
+}
+
+TypeFeedbackLoader::TypeFeedbackLoader(Thread* thread)
+    : thread_(thread),
+      zone_(thread->zone()),
+      stream_(nullptr),
+      uri_(String::Handle(zone_)),
+      lib_(Library::Handle(zone_)),
+      cls_name_(String::Handle(zone_)),
+      cls_(Class::Handle(zone_)),
+      field_name_(String::Handle(zone_)),
+      fields_(Array::Handle(zone_)),
+      field_(Field::Handle(zone_)),
+      func_name_(String::Handle(zone_)),
+      func_(Function::Handle(zone_)),
+      call_sites_(Array::Handle(zone_)),
+      call_site_(ICData::Handle(zone_)),
+      target_name_(String::Handle(zone_)),
+      target_(Function::Handle(zone_)),
+      args_desc_(Array::Handle(zone_)),
+      functions_to_compile_(
+          GrowableObjectArray::Handle(zone_, GrowableObjectArray::New())),
+      error_(Error::Handle(zone_)) {}
+
+RawObject* TypeFeedbackLoader::LoadFeedback(ReadStream* stream) {
+  stream_ = stream;
+
+  error_ = CheckHeader();
+  if (error_.IsError()) {
+    return error_.raw();
+  }
+
+  error_ = LoadClasses();
+  if (error_.IsError()) {
+    return error_.raw();
+  }
+
+  error_ = LoadFields();
+  if (error_.IsError()) {
+    return error_.raw();
+  }
+
+  while (stream_->PendingBytes() > 0) {
+    error_ = LoadFunction();
+    if (error_.IsError()) {
+      return error_.raw();
+    }
+  }
+
+  while (functions_to_compile_.Length() > 0) {
+    func_ ^= functions_to_compile_.RemoveLast();
+
+    if (Compiler::CanOptimizeFunction(thread_, func_) &&
+        (func_.usage_counter() >= FLAG_optimization_counter_threshold)) {
+      error_ = Compiler::CompileOptimizedFunction(thread_, func_);
+      if (error_.IsError()) {
+        return error_.raw();
+      }
+    }
+  }
+
+  if (FLAG_trace_compilation_trace) {
+    THR_Print("Done loading feedback\n");
+  }
+
+  return Error::null();
+}
+
+RawObject* TypeFeedbackLoader::CheckHeader() {
+  const char* expected_version = Version::SnapshotString();
+  ASSERT(expected_version != NULL);
+  const intptr_t version_len = strlen(expected_version);
+  if (stream_->PendingBytes() < version_len) {
+    const intptr_t kMessageBufferSize = 128;
+    char message_buffer[kMessageBufferSize];
+    Utils::SNPrint(message_buffer, kMessageBufferSize,
+                   "No snapshot version found, expected '%s'",
+                   expected_version);
+    const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
+    return ApiError::New(msg, Heap::kOld);
+  }
+
+  const char* version =
+      reinterpret_cast<const char*>(stream_->AddressOfCurrentPosition());
+  ASSERT(version != NULL);
+  if (strncmp(version, expected_version, version_len)) {
+    const intptr_t kMessageBufferSize = 256;
+    char message_buffer[kMessageBufferSize];
+    char* actual_version = Utils::StrNDup(version, version_len);
+    Utils::SNPrint(message_buffer, kMessageBufferSize,
+                   "Wrong snapshot version, expected '%s' found '%s'",
+                   expected_version, actual_version);
+    free(actual_version);
+    const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
+    return ApiError::New(msg, Heap::kOld);
+  }
+  stream_->Advance(version_len);
+
+  return Error::null();
+}
+
+RawObject* TypeFeedbackLoader::LoadClasses() {
+  num_cids_ = ReadInt();
+
+  cid_map_ = new intptr_t[num_cids_];
+  for (intptr_t cid = 0; cid < num_cids_; cid++) {
+    cid_map_[cid] = kIllegalCid;
+  }
+  for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) {
+    cid_map_[cid] = cid;
+  }
+
+  for (intptr_t cid = kNumPredefinedCids; cid < num_cids_; cid++) {
+    cls_ = ReadClassByName();
+    if (!cls_.IsNull()) {
+      cid_map_[cid] = cls_.id();
+    }
+  }
+
+  return Error::null();
+}
+
+RawObject* TypeFeedbackLoader::LoadFields() {
+  for (intptr_t cid = kNumPredefinedCids; cid < num_cids_; cid++) {
+    cls_ = ReadClassByName();
+    bool skip = cls_.IsNull();
+
+    intptr_t num_fields = ReadInt();
+    if (!skip && (num_fields > 0)) {
+      error_ = cls_.EnsureIsFinalized(thread_);
+      if (error_.IsError()) {
+        return error_.raw();
+      }
+      fields_ = cls_.fields();
+    }
+
+    for (intptr_t i = 0; i < num_fields; i++) {
+      field_name_ = ReadString();
+      intptr_t guarded_cid = cid_map_[ReadInt()];
+      intptr_t is_nullable = ReadInt();
+
+      if (skip) {
+        continue;
+      }
+
+      if (i >= fields_.Length()) {
+        if (FLAG_trace_compilation_trace) {
+          THR_Print("Missing field %s\n", field_name_.ToCString());
+        }
+        continue;
+      }
+
+      field_ ^= fields_.At(i);
+      if (!String::EqualsIgnoringPrivateKey(String::Handle(field_.name()),
+                                            field_name_)) {
+        if (FLAG_trace_compilation_trace) {
+          THR_Print("Missing field %s\n", field_name_.ToCString());
+        }
+        continue;
+      }
+
+      if (guarded_cid == kIllegalCid) {
+        // Guarded CID from feedback is not in current program: assume the field
+        // will become polymorphic.
+        field_.set_guarded_cid(kDynamicCid);
+        field_.set_is_nullable(true);
+      } else if ((field_.guarded_cid() != kIllegalCid) &&
+                 (field_.guarded_cid() == guarded_cid)) {
+        // Guarded CID from feedback is different from initialized guarded CID
+        // in the current program: assume the field will become polymorphic.
+        field_.set_guarded_cid(kDynamicCid);
+        field_.set_is_nullable(true);
+      } else {
+        field_.set_guarded_cid(guarded_cid);
+        field_.set_is_nullable(is_nullable || field_.is_nullable());
+      }
+
+      // TODO(rmacnak): Merge other field type feedback.
+      field_.set_guarded_list_length(Field::kNoFixedLength);
+      field_.set_guarded_list_length_in_object_offset(
+          Field::kUnknownLengthOffset);
+      field_.set_static_type_exactness_state(
+          StaticTypeExactnessState::NotTracking());
+      field_.DeoptimizeDependentCode();
+    }
+  }
+
+  return Error::null();
+}
+
+RawObject* TypeFeedbackLoader::LoadFunction() {
+  bool skip = false;
+
+  cls_ = ReadClassByName();
+  if (!cls_.IsNull()) {
+    error_ = cls_.EnsureIsFinalized(thread_);
+    if (error_.IsError()) {
+      return error_.raw();
+    }
+  } else {
+    skip = true;
+  }
+
+  func_name_ = ReadString();  // Without private mangling.
+  RawFunction::Kind kind = static_cast<RawFunction::Kind>(ReadInt());
+  intptr_t token_pos = ReadInt();
+  intptr_t usage = ReadInt();
+  intptr_t inlining_depth = ReadInt();
+  intptr_t num_call_sites = ReadInt();
+
+  if (!skip) {
+    func_ = FindFunction(kind, token_pos);
+    if (func_.IsNull()) {
+      skip = true;
+      if (FLAG_trace_compilation_trace) {
+        THR_Print("Missing function %s %s\n", func_name_.ToCString(),
+                  Function::KindToCString(kind));
+      }
+    }
+  }
+
+  if (!skip) {
+    error_ = Compiler::CompileFunction(thread_, func_);
+    if (error_.IsError()) {
+      return error_.raw();
+    }
+    call_sites_ = func_.ic_data_array();
+    if (call_sites_.IsNull()) {
+      call_sites_ = Object::empty_array().raw();  // Remove edge case.
+    }
+    if (call_sites_.Length() != num_call_sites + 1) {
+      skip = true;
+      if (FLAG_trace_compilation_trace) {
+        THR_Print("Mismatched call site count %s %" Pd " %" Pd "\n",
+                  func_name_.ToCString(), call_sites_.Length(), num_call_sites);
+      }
+    }
+  }
+
+  // First element is edge counters.
+  for (intptr_t i = 1; i <= num_call_sites; i++) {
+    intptr_t deopt_id = ReadInt();
+    intptr_t rebind_rule = ReadInt();
+    target_name_ = ReadString();
+    intptr_t num_checked_arguments = ReadInt();
+    intptr_t num_entries = ReadInt();
+
+    if (!skip) {
+      call_site_ ^= call_sites_.At(i);
+      if ((call_site_.deopt_id() != deopt_id) ||
+          (call_site_.rebind_rule() != rebind_rule) ||
+          (call_site_.NumArgsTested() != num_checked_arguments)) {
+        skip = true;
+        if (FLAG_trace_compilation_trace) {
+          THR_Print("Mismatched call site %s\n", call_site_.ToCString());
+        }
+      }
+    }
+
+    for (intptr_t entry_index = 0; entry_index < num_entries; entry_index++) {
+      intptr_t entry_usage = ReadInt();
+      bool skip_entry = skip;
+      GrowableArray<intptr_t> cids(num_checked_arguments);
+
+      for (intptr_t argument_index = 0; argument_index < num_checked_arguments;
+           argument_index++) {
+        intptr_t cid = cid_map_[ReadInt()];
+        cids.Add(cid);
+        if (cid == kIllegalCid) {
+          // Alternative: switch to a sentinel value such as kDynamicCid and
+          // have the optimizer generate a megamorphic call.
+          skip_entry = true;
+        }
+      }
+
+      if (skip_entry) {
+        continue;
+      }
+
+      intptr_t reuse_index = call_site_.FindCheck(cids);
+      if (reuse_index == -1) {
+        cls_ = thread_->isolate()->class_table()->At(cids[0]);
+        // Use target name and args descriptor from the current program
+        // instead of saved feedback to get the correct private mangling and
+        // ensure no arity mismatch crashes.
+        target_name_ = call_site_.target_name();
+        args_desc_ = call_site_.arguments_descriptor();
+        target_ = Resolver::ResolveDynamicForReceiverClass(
+            cls_, target_name_, ArgumentsDescriptor(args_desc_));
+        if (!target_.IsNull()) {
+          if (num_checked_arguments == 1) {
+            call_site_.AddReceiverCheck(cids[0], target_, entry_usage);
+          } else {
+            call_site_.AddCheck(cids, target_, entry_usage);
+          }
+        }
+      } else {
+        call_site_.IncrementCountAt(reuse_index, entry_usage);
+      }
+    }
+  }
+
+  if (!skip) {
+    func_.set_usage_counter(usage);
+    func_.set_inlining_depth(inlining_depth);
+
+    // Delay compilation until all feedback is loaded so feedback is available
+    // for inlined functions.
+    functions_to_compile_.Add(func_);
+  }
+
+  return Error::null();
+}
+
+RawFunction* TypeFeedbackLoader::FindFunction(RawFunction::Kind kind,
+                                              intptr_t token_pos) {
+  if (cls_name_.Equals(Symbols::TopLevel())) {
+    func_ = lib_.LookupFunctionAllowPrivate(func_name_);
+  } else {
+    func_ = cls_.LookupFunctionAllowPrivate(func_name_);
+  }
+
+  if (!func_.IsNull()) {
+    // Found regular method.
+  } else if (kind == RawFunction::kMethodExtractor) {
+    ASSERT(Field::IsGetterName(func_name_));
+    // Without private mangling:
+    String& name = String::Handle(zone_, Field::NameFromGetter(func_name_));
+    func_ = cls_.LookupFunctionAllowPrivate(name);
+    if (!func_.IsNull() && func_.IsDynamicFunction()) {
+      name = func_.name();  // With private mangling.
+      name = Field::GetterName(name);
+      func_ = func_.GetMethodExtractor(name);
+    } else {
+      func_ = Function::null();
+    }
+  } else if (kind == RawFunction::kDynamicInvocationForwarder) {
+    // Without private mangling:
+    String& name = String::Handle(
+        zone_, Function::DemangleDynamicInvocationForwarderName(func_name_));
+    func_ = cls_.LookupFunctionAllowPrivate(name);
+    if (!func_.IsNull() && func_.IsDynamicFunction()) {
+      name = func_.name();  // With private mangling.
+      name = Function::CreateDynamicInvocationForwarderName(name);
+      func_ = func_.CreateDynamicInvocationForwarder(name);
+    } else {
+      func_ = Function::null();
+    }
+  } else if (kind == RawFunction::kClosureFunction) {
+    // Note this lookup relies on parent functions appearing before child
+    // functions in the serialized feedback, so the parent will have already
+    // been unoptimized compilated and the child function created and added to
+    // ObjectStore::closure_functions_.
+    const GrowableObjectArray& closure_functions = GrowableObjectArray::Handle(
+        zone_, thread_->isolate()->object_store()->closure_functions());
+    bool found = false;
+    for (intptr_t i = 0; i < closure_functions.Length(); i++) {
+      func_ ^= closure_functions.At(i);
+      if ((func_.Owner() == cls_.raw()) &&
+          (func_.token_pos().value() == token_pos)) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      func_ = Function::null();
+    }
+  } else {
+    // This leaves unhandled:
+    // - kInvokeFieldDispatcher (how to get a valid args descriptor?)
+    // - static field getters
+    // - static field initializers (not retained by the field object)
+  }
+
+  if (!func_.IsNull()) {
+    if (kind == RawFunction::kImplicitClosureFunction) {
+      func_ = func_.ImplicitClosureFunction();
+    }
+    if (func_.is_abstract() || (func_.kind() != kind)) {
+      func_ = Function::null();
+    }
+  }
+
+  return func_.raw();
+}
+
+RawClass* TypeFeedbackLoader::ReadClassByName() {
+  uri_ = ReadString();
+  cls_name_ = ReadString();
+
+  lib_ = Library::LookupLibrary(thread_, uri_);
+  if (lib_.IsNull()) {
+    if (FLAG_trace_compilation_trace) {
+      THR_Print("Missing library %s\n", uri_.ToCString());
+    }
+    return Class::null();
+  }
+
+  if (cls_name_.Equals(Symbols::TopLevel())) {
+    cls_ = lib_.toplevel_class();
+  } else {
+    cls_ = lib_.SlowLookupClassAllowMultiPartPrivate(cls_name_);
+    if (cls_.IsNull()) {
+      if (FLAG_trace_compilation_trace) {
+        THR_Print("Missing class %s %s\n", uri_.ToCString(),
+                  cls_name_.ToCString());
+      }
+    }
+  }
+  return cls_.raw();
+}
+
+RawString* TypeFeedbackLoader::ReadString() {
+  intptr_t len = stream_->ReadUnsigned();
+  const char* cstr =
+      reinterpret_cast<const char*>(stream_->AddressOfCurrentPosition());
+  stream_->Advance(len);
+  return Symbols::New(thread_, cstr, len);
+}
+
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
 }  // namespace dart
diff --git a/runtime/vm/compilation_trace.h b/runtime/vm/compilation_trace.h
index 7e489d9..106dbbe 100644
--- a/runtime/vm/compilation_trace.h
+++ b/runtime/vm/compilation_trace.h
@@ -6,7 +6,6 @@
 #define RUNTIME_VM_COMPILATION_TRACE_H_
 
 #include "platform/assert.h"
-#include "vm/compiler/jit/compiler.h"
 #include "vm/object.h"
 #include "vm/program_visitor.h"
 #include "vm/zone_text_buffer.h"
@@ -58,6 +57,71 @@
   Object& error_;
 };
 
+class TypeFeedbackSaver : public FunctionVisitor {
+ public:
+  explicit TypeFeedbackSaver(WriteStream* stream);
+
+  void WriteHeader();
+  void SaveClasses();
+  void SaveFields();
+  void Visit(const Function& function);
+
+ private:
+  void WriteClassByName(const Class& cls);
+  void WriteString(const String& value);
+  void WriteInt(intptr_t value) { stream_->Write(static_cast<int32_t>(value)); }
+
+  WriteStream* const stream_;
+  Class& cls_;
+  Library& lib_;
+  String& str_;
+  Array& fields_;
+  Field& field_;
+  Code& code_;
+  Array& call_sites_;
+  ICData& call_site_;
+};
+
+class TypeFeedbackLoader : public ValueObject {
+ public:
+  explicit TypeFeedbackLoader(Thread* thread);
+
+  RawObject* LoadFeedback(ReadStream* stream);
+
+ private:
+  RawObject* CheckHeader();
+  RawObject* LoadClasses();
+  RawObject* LoadFields();
+  RawObject* LoadFunction();
+  RawFunction* FindFunction(RawFunction::Kind kind, intptr_t token_pos);
+
+  RawClass* ReadClassByName();
+  RawString* ReadString();
+  intptr_t ReadInt() { return stream_->Read<int32_t>(); }
+
+  Thread* thread_;
+  Zone* zone_;
+  ReadStream* stream_;
+  intptr_t num_cids_;
+  intptr_t* cid_map_;
+  String& uri_;
+  Library& lib_;
+  String& cls_name_;
+  Class& cls_;
+  String& field_name_;
+  Array& fields_;
+  Field& field_;
+  String& func_name_;
+  Function& func_;
+  Array& call_sites_;
+  ICData& call_site_;
+  String& target_name_;
+  Function& target_;
+  Array& args_desc_;
+  GrowableObjectArray& functions_to_compile_;
+  Object& error_;
+};
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_COMPILATION_TRACE_H_
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 1e6a8b3..9c0544a 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -415,6 +415,44 @@
          TryOptimizeDoubleOperation(instr, op_kind);
 }
 
+// Modulo against a constant power-of-two can be optimized into a mask.
+// x % y -> x & (y - 1)
+Definition* AotCallSpecializer::TryOptimizeMod(TemplateDartCall<0>* instr,
+                                               Token::Kind op_kind,
+                                               Value* left_value,
+                                               Value* right_value) {
+  if (!right_value->BindsToConstant()) {
+    return nullptr;
+  }
+
+  const Object& rhs = right_value->BoundConstant();
+  int64_t modulus = Utils::Abs(rhs.IsSmi() ? Smi::Cast(rhs).Value()
+                                           : Mint::Cast(rhs).value());
+  if (!Utils::IsPowerOfTwo(modulus) || !Smi::IsValid(modulus - 1)) {
+    return nullptr;
+  }
+
+  left_value = PrepareStaticOpInput(left_value, kMintCid, instr);
+
+#if defined(TARGET_ARCH_ARM)
+  Definition* right_definition = new (Z) UnboxedConstantInstr(
+      Smi::ZoneHandle(Z, Smi::New(modulus - 1)), kUnboxedInt32);
+  InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
+  right_definition = new (Z)
+      UnboxedIntConverterInstr(kUnboxedInt32, kUnboxedInt64,
+                               new (Z) Value(right_definition), DeoptId::kNone);
+  InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
+#else
+  Definition* right_definition = new (Z) UnboxedConstantInstr(
+      Smi::ZoneHandle(Z, Smi::New(modulus - 1)), kUnboxedInt64);
+  InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
+#endif
+  right_value = new (Z) Value(right_definition);
+  return new (Z)
+      BinaryInt64OpInstr(Token::kBIT_AND, left_value, right_value,
+                         DeoptId::kNone, Instruction::kNotSpeculative);
+}
+
 bool AotCallSpecializer::TryOptimizeIntegerOperation(TemplateDartCall<0>* instr,
                                                      Token::Kind op_kind) {
   if (instr->type_args_len() != 0) {
@@ -500,10 +538,13 @@
         }
         break;
       }
-#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
-        // TODO(ajcbik): 32-bit archs too?
       case Token::kMOD:
+        replacement = TryOptimizeMod(instr, op_kind, left_value, right_value);
+        if (replacement != nullptr) break;
       case Token::kTRUNCDIV:
+#if !defined(TARGET_ARCH_X64) && !defined(TARGET_ARCH_ARM64)
+        // TODO(ajcbik): 32-bit archs too?
+        break;
 #endif
       case Token::kSHL:
       case Token::kSHR:
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.h b/runtime/vm/compiler/aot/aot_call_specializer.h
index 404f2ba..c40aa8b 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.h
+++ b/runtime/vm/compiler/aot/aot_call_specializer.h
@@ -66,6 +66,11 @@
   bool TryExpandCallThroughGetter(const Class& receiver_class,
                                   InstanceCallInstr* call);
 
+  Definition* TryOptimizeMod(TemplateDartCall<0>* instr,
+                             Token::Kind op_kind,
+                             Value* left_value,
+                             Value* right_value);
+
   Precompiler* precompiler_;
 
   bool has_unique_no_such_method_;
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index d250b51..1fc69d6 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -1901,9 +1901,9 @@
 }
 
 void Precompiler::BindStaticCalls() {
-  class BindStaticCallsVisitor : public FunctionVisitor {
+  class BindAOTStaticCallsVisitor : public FunctionVisitor {
    public:
-    explicit BindStaticCallsVisitor(Zone* zone)
+    explicit BindAOTStaticCallsVisitor(Zone* zone)
         : code_(Code::Handle(zone)),
           table_(Array::Handle(zone)),
           kind_and_offset_(Smi::Handle(zone)),
@@ -1962,7 +1962,7 @@
     Code& target_code_;
   };
 
-  BindStaticCallsVisitor visitor(Z);
+  BindAOTStaticCallsVisitor visitor(Z);
 
   // We need both iterations to ensure we visit all the functions that might end
   // up in the snapshot. The ProgramVisitor will miss closures from duplicated
diff --git a/runtime/vm/compiler/assembler/assembler.h b/runtime/vm/compiler/assembler/assembler.h
index 8d600d5..2ecb376 100644
--- a/runtime/vm/compiler/assembler/assembler.h
+++ b/runtime/vm/compiler/assembler/assembler.h
@@ -11,6 +11,7 @@
 #include "vm/growable_array.h"
 #include "vm/hash_map.h"
 #include "vm/object.h"
+#include "vm/thread.h"
 
 namespace dart {
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 3d80504..c711b59 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -1142,7 +1142,9 @@
   if (function.HasOptionalParameters() || function.IsGeneric()) {
     __ LoadObject(R4, arguments_descriptor);
   } else {
-    __ LoadImmediate(R4, 0);  // GC safe smi zero because of stub.
+    if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions)) {
+      __ LoadImmediate(R4, 0);  // GC safe smi zero because of stub.
+    }
   }
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index a2400a3..408f0c7 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -1140,7 +1140,9 @@
   if (function.HasOptionalParameters() || function.IsGeneric()) {
     __ LoadObject(R4, arguments_descriptor);
   } else {
-    __ LoadImmediate(R4, 0);  // GC safe smi zero because of stub.
+    if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions)) {
+      __ LoadImmediate(R4, 0);  // GC safe smi zero because of stub.
+    }
   }
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 7d0bb49..aa1c822 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -1120,7 +1120,9 @@
   if (function.HasOptionalParameters() || function.IsGeneric()) {
     __ LoadObject(R10, arguments_descriptor);
   } else {
-    __ xorl(R10, R10);  // GC safe smi zero because of stub.
+    if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions)) {
+      __ xorl(R10, R10);  // GC safe smi zero because of stub.
+    }
   }
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 9d4fc4e..7020590 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -181,10 +181,10 @@
 
 typedef MallocGrowableArray<CidRange> CidRangeVector;
 
-class HierarchyInfo : public StackResource {
+class HierarchyInfo : public ThreadStackResource {
  public:
   explicit HierarchyInfo(Thread* thread)
-      : StackResource(thread),
+      : ThreadStackResource(thread),
         cid_subtype_ranges_(NULL),
         cid_subtype_ranges_abstract_(NULL),
         cid_subclass_ranges_(NULL) {
@@ -7276,6 +7276,8 @@
   // ArgumentError constructor), so it can lazily deopt.
   virtual bool ComputeCanDeoptimize() const { return true; }
 
+  bool IsRedundant(const RangeBoundary& length);
+
   // Give a name to the location/input indices.
   enum { kLengthPos = 0, kIndexPos = 1 };
 
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 3bc424f..94c7519 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -2988,8 +2988,12 @@
                                                               bool opt) const {
   const intptr_t kNumInputs = 0;
   const intptr_t kNumTemps = 1;
-  LocationSummary* summary = new (zone) LocationSummary(
-      zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+  const bool using_shared_stub = UseSharedSlowPathStub(opt);
+  ASSERT((kReservedCpuRegisters & (1 << LR)) != 0);
+  LocationSummary* summary = new (zone)
+      LocationSummary(zone, kNumInputs, kNumTemps,
+                      using_shared_stub ? LocationSummary::kCallOnSharedSlowPath
+                                        : LocationSummary::kCallOnSlowPath);
   summary->set_temp(0, Location::RequiresRegister());
   return summary;
 }
@@ -3030,7 +3034,6 @@
               ? Thread::stack_overflow_shared_with_fpu_regs_entry_point_offset()
               : Thread::
                     stack_overflow_shared_without_fpu_regs_entry_point_offset();
-      ASSERT(kReservedCpuRegisters & (1 << LR));
       __ ldr(LR, Address(THR, entry_point_offset));
       __ blx(LR);
       compiler->RecordSafepoint(instruction()->locs(), kNumSlowPathArgs);
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index a3a7868..9c03a18 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -2676,8 +2676,12 @@
                                                               bool opt) const {
   const intptr_t kNumInputs = 0;
   const intptr_t kNumTemps = 1;
-  LocationSummary* summary = new (zone) LocationSummary(
-      zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+  const bool using_shared_stub = UseSharedSlowPathStub(opt);
+  ASSERT((kReservedCpuRegisters & (1 << LR)) != 0);
+  LocationSummary* summary = new (zone)
+      LocationSummary(zone, kNumInputs, kNumTemps,
+                      using_shared_stub ? LocationSummary::kCallOnSharedSlowPath
+                                        : LocationSummary::kCallOnSlowPath);
   summary->set_temp(0, Location::RequiresRegister());
   return summary;
 }
@@ -2718,8 +2722,6 @@
               ? Thread::stack_overflow_shared_with_fpu_regs_entry_point_offset()
               : Thread::
                     stack_overflow_shared_without_fpu_regs_entry_point_offset();
-      ASSERT(instruction()->locs()->temp(1).IsRegister() &&
-             instruction()->locs()->temp(1).reg() == LR);
       __ ldr(LR, Address(THR, entry_point_offset));
       __ blr(LR);
       compiler->RecordSafepoint(instruction()->locs(), kNumSlowPathArgs);
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 9bd6ebb..3b48fc5 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -1782,6 +1782,7 @@
 
   FunctionEntryInstr* entry = nullptr;
   Instruction* last = nullptr;
+  Definition* result = nullptr;
   // Replace the receiver argument with a redefinition to prevent code from
   // the inlined body from being hoisted above the inlined entry.
   GrowableArray<Definition*> arguments(call_->ArgumentCount());
@@ -1794,22 +1795,26 @@
           owner_->caller_graph(), receiver_cid, target, call_, redefinition,
           call_->instance_call()->token_pos(),
           call_->instance_call()->ic_data(), graph_entry, &entry, &last,
-          owner_->inliner_->speculative_policy())) {
+          &result, owner_->inliner_->speculative_policy())) {
+    // The empty Object constructor is the only case where the inlined body is
+    // empty and there is no result.
+    ASSERT((last != nullptr && result != nullptr) ||
+           MethodRecognizer::RecognizeKind(target) ==
+               MethodRecognizer::kObjectConstructor);
     graph_entry->set_normal_entry(entry);
-    ASSERT(last->IsDefinition());
     // Create a graph fragment.
     redefinition->InsertAfter(entry);
     InlineExitCollector* exit_collector =
         new (Z) InlineExitCollector(owner_->caller_graph(), call_);
-    ReturnInstr* result = new (Z)
-        ReturnInstr(call_->instance_call()->token_pos(),
-                    new (Z) Value(last->AsDefinition()), DeoptId::kNone);
+    ReturnInstr* return_result =
+        new (Z) ReturnInstr(call_->instance_call()->token_pos(),
+                            new (Z) Value(result), DeoptId::kNone);
     owner_->caller_graph()->AppendTo(
-        last, result,
+        last, return_result,
         call_->env(),  // Return can become deoptimization target.
         FlowGraph::kEffect);
-    entry->set_last_instruction(result);
-    exit_collector->AddExit(result);
+    entry->set_last_instruction(return_result);
+    exit_collector->AddExit(return_result);
 
     // Update polymorphic inliner state.
     inlined_entries_.Add(graph_entry);
@@ -2391,7 +2396,8 @@
                              Definition* receiver,
                              GraphEntryInstr* graph_entry,
                              FunctionEntryInstr** entry,
-                             Instruction** last) {
+                             Instruction** last,
+                             Definition** result) {
   intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind);
 
   Definition* array = receiver;
@@ -2428,6 +2434,7 @@
                          deopt_id != DeoptId::kNone ? call->env() : NULL,
                          FlowGraph::kValue);
   }
+  *result = (*last)->AsDefinition();
   return true;
 }
 
@@ -2441,7 +2448,8 @@
                              FlowGraphInliner::ExactnessInfo* exactness,
                              GraphEntryInstr* graph_entry,
                              FunctionEntryInstr** entry,
-                             Instruction** last) {
+                             Instruction** last,
+                             Definition** result) {
   intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind);
 
   Definition* array = receiver;
@@ -2591,6 +2599,9 @@
       needs_store_barrier, index_scale, array_cid, kAlignedAccess,
       call->deopt_id(), call->token_pos());
   flow_graph->AppendTo(cursor, *last, call->env(), FlowGraph::kEffect);
+  // We need a return value to replace uses of the original definition. However,
+  // the final instruction is a use of 'void operator[]=()', so we use null.
+  *result = flow_graph->constant_null();
   return true;
 }
 
@@ -2600,7 +2611,8 @@
                            Definition* receiver,
                            GraphEntryInstr* graph_entry,
                            FunctionEntryInstr** entry,
-                           Instruction** last) {
+                           Instruction** last,
+                           Definition** result) {
   if (!CanUnboxDouble()) {
     return false;
   }
@@ -2617,6 +2629,7 @@
                           call->deopt_id(), call->token_pos());
   flow_graph->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue);
   *last = double_bin_op;
+  *result = double_bin_op->AsDefinition();
 
   return true;
 }
@@ -2627,7 +2640,8 @@
                                MethodRecognizer::Kind kind,
                                GraphEntryInstr* graph_entry,
                                FunctionEntryInstr** entry,
-                               Instruction** last) {
+                               Instruction** last,
+                               Definition** result) {
   if (!CanUnboxDouble()) {
     return false;
   }
@@ -2642,6 +2656,7 @@
       kind, new (Z) Value(receiver), call->deopt_id(), call->token_pos());
   flow_graph->AppendTo(*entry, double_test_op, call->env(), FlowGraph::kValue);
   *last = double_test_op;
+  *result = double_test_op->AsDefinition();
 
   return true;
 }
@@ -2651,7 +2666,8 @@
                                    Definition* receiver,
                                    GraphEntryInstr* graph_entry,
                                    FunctionEntryInstr** entry,
-                                   Instruction** last) {
+                                   Instruction** last,
+                                   Definition** result) {
   Definition* left = receiver;
   Definition* right = call->ArgumentAt(1);
 
@@ -2665,6 +2681,7 @@
                                new (Z) Value(right), call->deopt_id());
   flow_graph->AppendTo(*entry, smi_op, call->env(), FlowGraph::kValue);
   *last = smi_op;
+  *result = smi_op->AsDefinition();
 
   return true;
 }
@@ -2676,7 +2693,8 @@
                                       Definition* receiver,
                                       GraphEntryInstr* graph_entry,
                                       FunctionEntryInstr** entry,
-                                      Instruction** last) {
+                                      Instruction** last,
+                                      Definition** result) {
   Definition* array = receiver;
   Definition* value = call->ArgumentAt(1);
 
@@ -2691,6 +2709,9 @@
                               store_barrier_type, call->token_pos());
   flow_graph->AppendTo(*entry, store, call->env(), FlowGraph::kEffect);
   *last = store;
+  // We need a return value to replace uses of the original definition. However,
+  // the last instruction is a field setter, which returns void, so we use null.
+  *result = flow_graph->constant_null();
 
   return true;
 }
@@ -2699,7 +2720,8 @@
                               Instruction* call,
                               GraphEntryInstr* graph_entry,
                               FunctionEntryInstr** entry,
-                              Instruction** last) {
+                              Instruction** last,
+                              Definition** result) {
   *entry =
       new (Z) FunctionEntryInstr(graph_entry, flow_graph->allocate_block_id(),
                                  call->GetBlock()->try_index(), DeoptId::kNone);
@@ -2708,6 +2730,7 @@
       LoadClassIdInstr(call->PushArgumentAt(0)->value()->CopyWithType(Z));
   flow_graph->InsertBefore(call, load_cid, nullptr, FlowGraph::kValue);
   *last = load_cid;
+  *result = load_cid->AsDefinition();
   return true;
 }
 
@@ -2840,7 +2863,8 @@
                                     intptr_t view_cid,
                                     GraphEntryInstr* graph_entry,
                                     FunctionEntryInstr** entry,
-                                    Instruction** last) {
+                                    Instruction** last,
+                                    Definition** result) {
   ASSERT(array_cid != kIllegalCid);
 
   // Dynamic calls are polymorphic due to:
@@ -2916,6 +2940,7 @@
                                        DeoptId::kNone);
     flow_graph->AppendTo(cursor, *last, nullptr, FlowGraph::kValue);
   }
+  *result = (*last)->AsDefinition();
   return true;
 }
 
@@ -2939,7 +2964,8 @@
                                      intptr_t view_cid,
                                      GraphEntryInstr* graph_entry,
                                      FunctionEntryInstr** entry,
-                                     Instruction** last) {
+                                     Instruction** last,
+                                     Definition** result) {
   ASSERT(array_cid != kIllegalCid);
 
   // Dynamic calls are polymorphic due to:
@@ -3123,6 +3149,9 @@
         FlowGraph::kEffect);
     *last = store;
   }
+  // We need a return value to replace uses of the original definition. However,
+  // the final instruction is a use of 'void operator[]=()', so we use null.
+  *result = flow_graph->constant_null();
   return true;
 }
 
@@ -3168,7 +3197,8 @@
                                    intptr_t cid,
                                    GraphEntryInstr* graph_entry,
                                    FunctionEntryInstr** entry,
-                                   Instruction** last) {
+                                   Instruction** last,
+                                   Definition** result) {
   if ((cid != kOneByteStringCid) && (cid != kExternalOneByteStringCid)) {
     return false;
   }
@@ -3187,6 +3217,7 @@
 
   flow_graph->AppendTo(*last, char_at, NULL, FlowGraph::kValue);
   *last = char_at;
+  *result = char_at->AsDefinition();
 
   return true;
 }
@@ -3197,7 +3228,8 @@
                                    intptr_t cid,
                                    GraphEntryInstr* graph_entry,
                                    FunctionEntryInstr** entry,
-                                   Instruction** last) {
+                                   Instruction** last,
+                                   Definition** result) {
   if (cid == kDynamicCid) {
     ASSERT(call->IsStaticCall());
     return false;
@@ -3215,6 +3247,7 @@
   (*entry)->InheritDeoptTarget(Z, call);
 
   *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry);
+  *result = (*last)->AsDefinition();
 
   return true;
 }
@@ -3231,12 +3264,19 @@
   const intptr_t receiver_cid = class_ids[0];
   FunctionEntryInstr* entry = nullptr;
   Instruction* last = nullptr;
+  Definition* result = nullptr;
   auto exactness = call->ic_data()->GetExactnessAt(0);
   ExactnessInfo exactness_info{exactness.IsExact(), false};
   if (FlowGraphInliner::TryInlineRecognizedMethod(
           flow_graph, receiver_cid, target, call,
           call->Receiver()->definition(), call->token_pos(), call->ic_data(),
-          /*graph_entry=*/nullptr, &entry, &last, policy, &exactness_info)) {
+          /*graph_entry=*/nullptr, &entry, &last, &result, policy,
+          &exactness_info)) {
+    // The empty Object constructor is the only case where the inlined body is
+    // empty and there is no result.
+    ASSERT((last != nullptr && result != nullptr) ||
+           MethodRecognizer::RecognizeKind(target) ==
+               MethodRecognizer::kObjectConstructor);
     // Determine if inlining instance methods needs a check.
     FlowGraph::ToCheck check = FlowGraph::ToCheck::kNoCheck;
     if (MethodRecognizer::PolymorphicTarget(target)) {
@@ -3280,17 +3320,8 @@
     }
     // Replace all uses of this definition with the result.
     if (call->HasUses()) {
-      ASSERT(last->IsDefinition());
-      Definition* ret = last->AsDefinition();
-      if (!ret->HasSSATemp()) {
-        // Currently, StoreIndexed and StoreInstanceField are defined as
-        // definitions despite producing no value. For now, catch the case
-        // where the new inlined code ends with one of those and replace
-        // the old uses of the original definition with uses of null.
-        ASSERT(ret->IsStoreIndexed() || ret->IsStoreInstanceField());
-        ret = flow_graph->constant_null();
-      }
-      call->ReplaceUsesWith(ret);
+      ASSERT(result->HasSSATemp());
+      call->ReplaceUsesWith(result);
     }
     // Finally insert the sequence other definition in place of this one in the
     // graph.
@@ -3319,6 +3350,7 @@
     SpeculativeInliningPolicy* policy) {
   FunctionEntryInstr* entry = nullptr;
   Instruction* last = nullptr;
+  Definition* result = nullptr;
   Definition* receiver = nullptr;
   intptr_t receiver_cid = kIllegalCid;
   if (!call->function().is_static()) {
@@ -3328,7 +3360,12 @@
   if (FlowGraphInliner::TryInlineRecognizedMethod(
           flow_graph, receiver_cid, call->function(), call, receiver,
           call->token_pos(), call->ic_data(), /*graph_entry=*/nullptr, &entry,
-          &last, policy)) {
+          &last, &result, policy)) {
+    // The empty Object constructor is the only case where the inlined body is
+    // empty and there is no result.
+    ASSERT((last != nullptr && result != nullptr) ||
+           MethodRecognizer::RecognizeKind(call->function()) ==
+               MethodRecognizer::kObjectConstructor);
     // Remove the original push arguments.
     for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
       PushArgumentInstr* push = call->PushArgumentAt(i);
@@ -3337,17 +3374,8 @@
     }
     // Replace all uses of this definition with the result.
     if (call->HasUses()) {
-      ASSERT(last->IsDefinition());
-      Definition* ret = last->AsDefinition();
-      if (!ret->HasSSATemp()) {
-        // Currently, StoreIndexed and StoreInstanceField are defined as
-        // definitions despite producing no value. For now, catch the case
-        // where the new inlined code ends with one of those and replace
-        // the old uses of the original definition with uses of null.
-        ASSERT(ret->IsStoreIndexed() || ret->IsStoreInstanceField());
-        ret = flow_graph->constant_null();
-      }
-      call->ReplaceUsesWith(ret);
+      ASSERT(result->HasSSATemp());
+      call->ReplaceUsesWith(result);
     }
     // Finally insert the sequence other definition in place of this one in the
     // graph.
@@ -3409,7 +3437,8 @@
                          MethodRecognizer::Kind kind,
                          GraphEntryInstr* graph_entry,
                          FunctionEntryInstr** entry,
-                         Instruction** last) {
+                         Instruction** last,
+                         Definition** result) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -3471,6 +3500,7 @@
   flow_graph->AppendTo(cursor, *last,
                        call->deopt_id() != DeoptId::kNone ? call->env() : NULL,
                        FlowGraph::kValue);
+  *result = (*last)->AsDefinition();
   return true;
 }
 
@@ -3479,7 +3509,8 @@
                                 MethodRecognizer::Kind kind,
                                 GraphEntryInstr* graph_entry,
                                 FunctionEntryInstr** entry,
-                                Instruction** last) {
+                                Instruction** last,
+                                Definition** result) {
   if (!CanUnboxDouble()) {
     return false;
   }
@@ -3510,6 +3541,7 @@
   flow_graph->AppendTo(cursor, *last,
                        call->deopt_id() != DeoptId::kNone ? call->env() : NULL,
                        FlowGraph::kValue);
+  *result = (*last)->AsDefinition();
   return true;
 }
 
@@ -3527,7 +3559,8 @@
                              Instruction* call,
                              GraphEntryInstr* graph_entry,
                              FunctionEntryInstr** entry,
-                             Instruction** last) {
+                             Instruction** last,
+                             Definition** result) {
   // Invoking the _intPow(x, y) implies that both:
   // (1) x, y are int
   // (2) y >= 0.
@@ -3541,9 +3574,11 @@
   if (IsSmiValue(y, &val)) {
     if (val == 0) {
       *last = flow_graph->GetConstant(Smi::ZoneHandle(Smi::New(1)));
+      *result = (*last)->AsDefinition();
       return true;
     } else if (val == 1) {
       *last = x->definition();
+      *result = (*last)->AsDefinition();
       return true;
     } else if (1 < val && val <= small_exponent) {
       // Lazily construct entry only in this case.
@@ -3555,18 +3590,22 @@
       Definition* square =
           InlineMul(flow_graph, *entry, x_def, x_def)->AsDefinition();
       *last = square;
+      *result = square;
       switch (val) {
         case 2:
           return true;
         case 3:
           *last = InlineMul(flow_graph, *last, x_def, square);
+          *result = (*last)->AsDefinition();
           return true;
         case 4:
           *last = InlineMul(flow_graph, *last, square, square);
+          *result = (*last)->AsDefinition();
           return true;
         case 5:
           *last = InlineMul(flow_graph, *last, square, square);
           *last = InlineMul(flow_graph, *last, x_def, (*last)->AsDefinition());
+          *result = (*last)->AsDefinition();
           return true;
       }
     }
@@ -3575,6 +3614,7 @@
   if (IsSmiValue(x, &val)) {
     if (val == 1) {
       *last = x->definition();
+      *result = x->definition();
       return true;
     }
   }
@@ -3592,6 +3632,7 @@
     GraphEntryInstr* graph_entry,
     FunctionEntryInstr** entry,
     Instruction** last,
+    Definition** result,
     SpeculativeInliningPolicy* policy,
     FlowGraphInliner::ExactnessInfo* exactness) {
   const bool can_speculate = policy->IsAllowedForInlining(call->deopt_id());
@@ -3610,37 +3651,38 @@
     case MethodRecognizer::kInt16ArrayGetIndexed:
     case MethodRecognizer::kUint16ArrayGetIndexed:
       return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
-                              entry, last);
+                              entry, last, result);
     case MethodRecognizer::kFloat32ArrayGetIndexed:
     case MethodRecognizer::kFloat64ArrayGetIndexed:
       if (!CanUnboxDouble()) {
         return false;
       }
       return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
-                              entry, last);
+                              entry, last, result);
     case MethodRecognizer::kFloat32x4ArrayGetIndexed:
     case MethodRecognizer::kFloat64x2ArrayGetIndexed:
       if (!ShouldInlineSimd()) {
         return false;
       }
       return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
-                              entry, last);
+                              entry, last, result);
     case MethodRecognizer::kInt32ArrayGetIndexed:
     case MethodRecognizer::kUint32ArrayGetIndexed:
       if (!CanUnboxInt32()) {
         return false;
       }
       return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
-                              entry, last);
+                              entry, last, result);
     case MethodRecognizer::kInt64ArrayGetIndexed:
     case MethodRecognizer::kUint64ArrayGetIndexed:
       if (!ShouldInlineInt64ArrayOps()) {
         return false;
       }
       return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
-                              entry, last);
+                              entry, last, result);
     case MethodRecognizer::kClassIDgetID:
-      return InlineLoadClassId(flow_graph, call, graph_entry, entry, last);
+      return InlineLoadClassId(flow_graph, call, graph_entry, entry, last,
+                               result);
     default:
       break;
   }
@@ -3658,7 +3700,7 @@
     case MethodRecognizer::kGrowableArraySetIndexedUnchecked:
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, /* value_check = */ NULL, exactness,
-                              graph_entry, entry, last);
+                              graph_entry, entry, last, result);
     case MethodRecognizer::kInt8ArraySetIndexed:
     case MethodRecognizer::kUint8ArraySetIndexed:
     case MethodRecognizer::kUint8ClampedArraySetIndexed:
@@ -3674,7 +3716,7 @@
       Cids* value_check = Cids::CreateMonomorphic(Z, kSmiCid);
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, value_check, exactness, graph_entry,
-                              entry, last);
+                              entry, last, result);
     }
     case MethodRecognizer::kInt32ArraySetIndexed:
     case MethodRecognizer::kUint32ArraySetIndexed: {
@@ -3682,7 +3724,7 @@
       // implicitly contain unboxing instructions which check for right type.
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, /* value_check = */ NULL, exactness,
-                              graph_entry, entry, last);
+                              graph_entry, entry, last, result);
     }
     case MethodRecognizer::kInt64ArraySetIndexed:
     case MethodRecognizer::kUint64ArraySetIndexed:
@@ -3691,7 +3733,7 @@
       }
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, /* value_check = */ NULL, exactness,
-                              graph_entry, entry, last);
+                              graph_entry, entry, last, result);
     case MethodRecognizer::kFloat32ArraySetIndexed:
     case MethodRecognizer::kFloat64ArraySetIndexed: {
       if (!CanUnboxDouble()) {
@@ -3700,7 +3742,7 @@
       Cids* value_check = Cids::CreateMonomorphic(Z, kDoubleCid);
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, value_check, exactness, graph_entry,
-                              entry, last);
+                              entry, last, result);
     }
     case MethodRecognizer::kFloat32x4ArraySetIndexed: {
       if (!ShouldInlineSimd()) {
@@ -3709,7 +3751,7 @@
       Cids* value_check = Cids::CreateMonomorphic(Z, kFloat32x4Cid);
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, value_check, exactness, graph_entry,
-                              entry, last);
+                              entry, last, result);
     }
     case MethodRecognizer::kFloat64x2ArraySetIndexed: {
       if (!ShouldInlineSimd()) {
@@ -3718,171 +3760,171 @@
       Cids* value_check = Cids::CreateMonomorphic(Z, kFloat64x2Cid);
       return InlineSetIndexed(flow_graph, kind, target, call, receiver,
                               token_pos, value_check, exactness, graph_entry,
-                              entry, last);
+                              entry, last, result);
     }
     case MethodRecognizer::kByteArrayBaseGetInt8:
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataInt8ArrayCid, graph_entry, entry,
-                                     last);
+                                     last, result);
     case MethodRecognizer::kByteArrayBaseGetUint8:
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataUint8ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetInt16:
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataInt16ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetUint16:
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataUint16ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetInt32:
       if (!CanUnboxInt32()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataInt32ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetUint32:
       if (!CanUnboxInt32()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataUint32ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetInt64:
       if (!ShouldInlineInt64ArrayOps()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataInt64ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetUint64:
       if (!ShouldInlineInt64ArrayOps()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataUint64ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetFloat32:
       if (!CanUnboxDouble()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataFloat32ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetFloat64:
       if (!CanUnboxDouble()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataFloat64ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetFloat32x4:
       if (!ShouldInlineSimd()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataFloat32x4ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseGetInt32x4:
       if (!ShouldInlineSimd()) {
         return false;
       }
       return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
                                      kTypedDataInt32x4ArrayCid, graph_entry,
-                                     entry, last);
+                                     entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetInt8:
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataInt8ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetUint8:
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataUint8ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetInt16:
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataInt16ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetUint16:
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataUint16ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetInt32:
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataInt32ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetUint32:
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataUint32ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetInt64:
       if (!ShouldInlineInt64ArrayOps()) {
         return false;
       }
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataInt64ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetUint64:
       if (!ShouldInlineInt64ArrayOps()) {
         return false;
       }
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataUint64ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetFloat32:
       if (!CanUnboxDouble()) {
         return false;
       }
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataFloat32ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetFloat64:
       if (!CanUnboxDouble()) {
         return false;
       }
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataFloat64ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetFloat32x4:
       if (!ShouldInlineSimd()) {
         return false;
       }
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataFloat32x4ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kByteArrayBaseSetInt32x4:
       if (!ShouldInlineSimd()) {
         return false;
       }
       return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
                                       receiver_cid, kTypedDataInt32x4ArrayCid,
-                                      graph_entry, entry, last);
+                                      graph_entry, entry, last, result);
     case MethodRecognizer::kOneByteStringCodeUnitAt:
     case MethodRecognizer::kTwoByteStringCodeUnitAt:
     case MethodRecognizer::kExternalOneByteStringCodeUnitAt:
     case MethodRecognizer::kExternalTwoByteStringCodeUnitAt:
       return InlineStringCodeUnitAt(flow_graph, call, receiver, receiver_cid,
-                                    graph_entry, entry, last);
+                                    graph_entry, entry, last, result);
     case MethodRecognizer::kStringBaseCharAt:
       return InlineStringBaseCharAt(flow_graph, call, receiver, receiver_cid,
-                                    graph_entry, entry, last);
+                                    graph_entry, entry, last, result);
     case MethodRecognizer::kDoubleAdd:
       return InlineDoubleOp(flow_graph, Token::kADD, call, receiver,
-                            graph_entry, entry, last);
+                            graph_entry, entry, last, result);
     case MethodRecognizer::kDoubleSub:
       return InlineDoubleOp(flow_graph, Token::kSUB, call, receiver,
-                            graph_entry, entry, last);
+                            graph_entry, entry, last, result);
     case MethodRecognizer::kDoubleMul:
       return InlineDoubleOp(flow_graph, Token::kMUL, call, receiver,
-                            graph_entry, entry, last);
+                            graph_entry, entry, last, result);
     case MethodRecognizer::kDoubleDiv:
       return InlineDoubleOp(flow_graph, Token::kDIV, call, receiver,
-                            graph_entry, entry, last);
+                            graph_entry, entry, last, result);
     case MethodRecognizer::kDouble_getIsNaN:
     case MethodRecognizer::kDouble_getIsInfinite:
       return InlineDoubleTestOp(flow_graph, call, receiver, kind, graph_entry,
-                                entry, last);
+                                entry, last, result);
     case MethodRecognizer::kGrowableArraySetData:
       ASSERT((receiver_cid == kGrowableObjectArrayCid) ||
              ((receiver_cid == kDynamicCid) && call->IsStaticCall()));
@@ -3890,7 +3932,7 @@
              (ic_data == NULL || ic_data->NumberOfChecksIs(1)));
       return InlineGrowableArraySetter(
           flow_graph, Slot::GrowableObjectArray_data(), kEmitStoreBarrier, call,
-          receiver, graph_entry, entry, last);
+          receiver, graph_entry, entry, last, result);
     case MethodRecognizer::kGrowableArraySetLength:
       ASSERT((receiver_cid == kGrowableObjectArrayCid) ||
              ((receiver_cid == kDynamicCid) && call->IsStaticCall()));
@@ -3898,10 +3940,10 @@
              (ic_data == NULL || ic_data->NumberOfChecksIs(1)));
       return InlineGrowableArraySetter(
           flow_graph, Slot::GrowableObjectArray_length(), kNoStoreBarrier, call,
-          receiver, graph_entry, entry, last);
+          receiver, graph_entry, entry, last, result);
     case MethodRecognizer::kSmi_bitAndFromSmi:
       return InlineSmiBitAndFromSmi(flow_graph, call, receiver, graph_entry,
-                                    entry, last);
+                                    entry, last, result);
 
     case MethodRecognizer::kFloat32x4Abs:
     case MethodRecognizer::kFloat32x4Clamp:
@@ -3965,7 +4007,7 @@
     case MethodRecognizer::kFloat32x4Shuffle:
     case MethodRecognizer::kInt32x4Shuffle:
       return InlineSimdOp(flow_graph, call, receiver, kind, graph_entry, entry,
-                          last);
+                          last, result);
 
     case MethodRecognizer::kMathSqrt:
     case MethodRecognizer::kMathDoublePow:
@@ -3977,10 +4019,11 @@
     case MethodRecognizer::kMathAtan:
     case MethodRecognizer::kMathAtan2:
       return InlineMathCFunction(flow_graph, call, kind, graph_entry, entry,
-                                 last);
+                                 last, result);
 
     case MethodRecognizer::kMathIntPow:
-      return InlineMathIntPow(flow_graph, call, graph_entry, entry, last);
+      return InlineMathIntPow(flow_graph, call, graph_entry, entry, last,
+                              result);
 
     case MethodRecognizer::kObjectConstructor: {
       *entry = new (Z)
@@ -3989,6 +4032,7 @@
       (*entry)->InheritDeoptTarget(Z, call);
       ASSERT(!call->HasUses());
       *last = NULL;  // Empty body.
+      *result = NULL;  // Since no uses of original call, result will be unused.
       return true;
     }
 
@@ -4011,6 +4055,7 @@
           *entry, *last,
           call->deopt_id() != DeoptId::kNone ? call->env() : NULL,
           FlowGraph::kValue);
+      *result = (*last)->AsDefinition();
       return true;
     }
 
@@ -4030,6 +4075,7 @@
               *entry, *last,
               call->deopt_id() != DeoptId::kNone ? call->env() : NULL,
               FlowGraph::kValue);
+          *result = (*last)->AsDefinition();
           return true;
         }
       }
@@ -4064,6 +4110,7 @@
             *entry, *last,
             call->deopt_id() != DeoptId::kNone ? call->env() : NULL,
             FlowGraph::kValue);
+        *result = (*last)->AsDefinition();
         return true;
       }
       return false;
@@ -4089,6 +4136,9 @@
           *entry, *last,
           call->deopt_id() != DeoptId::kNone ? call->env() : NULL,
           FlowGraph::kEffect);
+      // We need a return value to replace uses of the original definition.
+      // The final instruction is a use of 'void operator[]=()', so we use null.
+      *result = flow_graph->constant_null();
       return true;
     }
 
diff --git a/runtime/vm/compiler/backend/inliner.h b/runtime/vm/compiler/backend/inliner.h
index a516847..34366cf 100644
--- a/runtime/vm/compiler/backend/inliner.h
+++ b/runtime/vm/compiler/backend/inliner.h
@@ -7,6 +7,7 @@
 
 #include "vm/allocation.h"
 #include "vm/growable_array.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -139,6 +140,7 @@
                                         GraphEntryInstr* graph_entry,
                                         FunctionEntryInstr** entry,
                                         Instruction** last,
+                                        Definition** result,
                                         SpeculativeInliningPolicy* policy,
                                         ExactnessInfo* exactness = nullptr);
 
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 7fa08c0..28f2199 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -107,8 +107,8 @@
           }
         }
       }
-      if (current->IsCheckArrayBound()) {
-        bounds_checks_.Add(current->AsCheckArrayBound());
+      if (current->IsCheckArrayBound() || current->IsGenericCheckBound()) {
+        bounds_checks_.Add(current);
       }
     }
   }
@@ -1017,8 +1017,8 @@
       return phi;
     }
     // Decide between direct or indirect bound.
-    Definition* bounded_phi = UnwrapConstraint(limit->value()->definition());
-    if (bounded_phi == phi) {
+    Definition* bounded_def = UnwrapConstraint(limit->value()->definition());
+    if (bounded_def == phi) {
       // Given a smi bounded loop with smi induction variable
       //
       //          x <- phi(x0, x + 1)
@@ -1037,7 +1037,7 @@
       //
       //          y <= y0 + (M - x0)
       //
-      InductionVar* bounded_induc = GetSmiInduction(loop, bounded_phi);
+      InductionVar* bounded_induc = GetSmiInduction(loop, bounded_def);
       Definition* x0 = GenerateInvariant(bounded_induc->initial());
       Definition* y0 = GenerateInvariant(induc->initial());
       Definition* m = RangeBoundaryToDefinition(limit->constraint()->max());
@@ -1321,7 +1321,21 @@
     BoundsCheckGeneralizer generalizer(this, flow_graph_);
 
     for (intptr_t i = 0; i < bounds_checks_.length(); i++) {
-      CheckArrayBoundInstr* check = bounds_checks_[i];
+      // Is this a non-speculative check bound?
+      GenericCheckBoundInstr* aot_check =
+          bounds_checks_[i]->AsGenericCheckBound();
+      if (aot_check != nullptr) {
+        RangeBoundary array_length =
+            RangeBoundary::FromDefinition(aot_check->length()->definition());
+        if (aot_check->IsRedundant(array_length)) {
+          aot_check->ReplaceUsesWith(aot_check->index()->definition());
+          aot_check->RemoveFromGraph();
+        }
+        continue;
+      }
+      // Must be a speculative check bound.
+      CheckArrayBoundInstr* check = bounds_checks_[i]->AsCheckArrayBound();
+      ASSERT(check != nullptr);
       RangeBoundary array_length =
           RangeBoundary::FromDefinition(check->length()->definition());
       if (check->IsRedundant(array_length)) {
@@ -2928,6 +2942,52 @@
   return false;
 }
 
+// Check if range boundary and invariant limit are the same boundary.
+static bool IsSameBound(const RangeBoundary& a, InductionVar* b) {
+  ASSERT(InductionVar::IsInvariant(b));
+  if (a.IsSymbol()) {
+    // Check for exactly the same symbol as length.
+    return a.symbol() == b->def() && b->mult() == 1 &&
+           a.offset() == b->offset();
+  } else if (a.IsConstant()) {
+    // Check for constant in right range 0 < c <= length.
+    int64_t c = 0;
+    return InductionVar::IsConstant(b, &c) && 0 < c && c <= a.ConstantValue();
+  }
+  return false;
+}
+
+bool GenericCheckBoundInstr::IsRedundant(const RangeBoundary& length) {
+  // In loop, with index as induction?
+  LoopInfo* loop = GetBlock()->loop_info();
+  if (loop == nullptr) {
+    return false;
+  }
+  InductionVar* induc = loop->LookupInduction(index()->definition());
+  if (induc == nullptr) {
+    return false;
+  }
+  // Under 64-bit wrap-around arithmetic, it is always safe to remove the
+  // bounds check from the following, if initial >= 0 and the corresponding
+  // exit branch dominates the bounds check:
+  //   for (int i = initial; i < length; i++)
+  //     .... a[i] ....
+  int64_t stride = 0;
+  int64_t initial = 0;
+  if (InductionVar::IsLinear(induc, &stride) &&
+      InductionVar::IsConstant(induc->initial(), &initial)) {
+    if (stride == 1 && initial >= 0) {
+      for (auto bound : induc->bounds()) {
+        if (IsSameBound(length, bound.limit_) &&
+            this->IsDominatedBy(bound.branch_)) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
 }  // namespace dart
 
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/backend/range_analysis.h b/runtime/vm/compiler/backend/range_analysis.h
index 56dc78e..24adeed 100644
--- a/runtime/vm/compiler/backend/range_analysis.h
+++ b/runtime/vm/compiler/backend/range_analysis.h
@@ -605,8 +605,8 @@
   GrowableArray<BinaryInt64OpInstr*> binary_int64_ops_;
   GrowableArray<ShiftIntegerOpInstr*> shift_int64_ops_;
 
-  // All CheckArrayBound instructions.
-  GrowableArray<CheckArrayBoundInstr*> bounds_checks_;
+  // All CheckArrayBound/GenericCheckBound instructions.
+  GrowableArray<Instruction*> bounds_checks_;
 
   // All Constraints inserted during InsertConstraints phase. They are treated
   // as smi values.
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index 128343a..1e0f613 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -51,6 +51,7 @@
 class Function;
 class Precompiler;
 class SpeculativeInliningPolicy;
+class TimelineStream;
 
 struct CompilerPassState {
   CompilerPassState(Thread* thread,
diff --git a/runtime/vm/compiler/compiler_state.h b/runtime/vm/compiler/compiler_state.h
index e9bc675..774f74d 100644
--- a/runtime/vm/compiler/compiler_state.h
+++ b/runtime/vm/compiler/compiler_state.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_COMPILER_COMPILER_STATE_H_
 
 #include "vm/compiler/cha.h"
+#include "vm/heap/safepoint.h"
 #include "vm/thread.h"
 
 namespace dart {
@@ -53,9 +54,10 @@
 };
 
 // Global compiler state attached to the thread.
-class CompilerState : public StackResource {
+class CompilerState : public ThreadStackResource {
  public:
-  explicit CompilerState(Thread* thread) : StackResource(thread), cha_(thread) {
+  explicit CompilerState(Thread* thread)
+      : ThreadStackResource(thread), cha_(thread) {
     previous_ = thread->SetCompilerState(this);
   }
 
@@ -127,10 +129,10 @@
   CompilerState* previous_;
 };
 
-class DeoptIdScope : public StackResource {
+class DeoptIdScope : public ThreadStackResource {
  public:
   DeoptIdScope(Thread* thread, intptr_t deopt_id)
-      : StackResource(thread),
+      : ThreadStackResource(thread),
         prev_deopt_id_(thread->compiler_state().deopt_id()) {
     thread->compiler_state().set_deopt_id(deopt_id);
   }
@@ -145,10 +147,10 @@
 
 /// Ensures that there were no deopt id allocations during the lifetime of this
 /// object.
-class AssertNoDeoptIdsAllocatedScope : public StackResource {
+class AssertNoDeoptIdsAllocatedScope : public ThreadStackResource {
  public:
   explicit AssertNoDeoptIdsAllocatedScope(Thread* thread)
-      : StackResource(thread),
+      : ThreadStackResource(thread),
         prev_deopt_id_(thread->compiler_state().deopt_id()) {}
 
   ~AssertNoDeoptIdsAllocatedScope() {
diff --git a/runtime/vm/compiler/frontend/constant_evaluator.cc b/runtime/vm/compiler/frontend/constant_evaluator.cc
index 8d1c6da..3ac3ecc 100644
--- a/runtime/vm/compiler/frontend/constant_evaluator.cc
+++ b/runtime/vm/compiler/frontend/constant_evaluator.cc
@@ -1293,6 +1293,14 @@
         // Note: This is already lowered to InstanceConstant/ListConstant.
         UNREACHABLE();
         break;
+      case kEnvironmentBoolConstant:
+      case kEnvironmentIntConstant:
+      case kEnvironmentStringConstant:
+      case kUnevaluatedConstant:
+        // We should not see unevaluated constants in the constant table, they
+        // should have been fully evaluated before we get them.
+        UNREACHABLE();
+        break;
       default:
         UNREACHABLE();
     }
diff --git a/runtime/vm/compiler/method_recognizer.h b/runtime/vm/compiler/method_recognizer.h
index c3310b8..e901118 100644
--- a/runtime/vm/compiler/method_recognizer.h
+++ b/runtime/vm/compiler/method_recognizer.h
@@ -504,6 +504,7 @@
 // Forward declarations.
 class Function;
 class Library;
+class Object;
 class RawFunction;
 class RawGrowableObjectArray;
 class String;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index e1ee86a..a951991 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -84,16 +84,19 @@
 };
 
 static void CheckOffsets() {
+  bool ok = true;
 #define CHECK_OFFSET(expr, offset)                                             \
   if ((expr) != (offset)) {                                                    \
-    FATAL2("%s == %" Pd, #expr, (expr));                                       \
+    OS::PrintErr("%s got %" Pd " expected %" Pd "\n", #expr, (expr),           \
+                 static_cast<intptr_t>(offset));                               \
+    ok = false;                                                                \
   }
 
 #if defined(TARGET_ARCH_ARM)
   // These offsets are embedded in precompiled instructions. We need simarm
   // (compiler) and arm (runtime) to agree.
-  CHECK_OFFSET(Thread::stack_limit_offset(), 4);
-  CHECK_OFFSET(Thread::object_null_offset(), 64);
+  CHECK_OFFSET(Thread::stack_limit_offset(), 28);
+  CHECK_OFFSET(Thread::object_null_offset(), 88);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 14);
   CHECK_OFFSET(Isolate::object_store_offset(), 20);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 168));
@@ -101,12 +104,16 @@
 #if defined(TARGET_ARCH_ARM64)
   // These offsets are embedded in precompiled instructions. We need simarm64
   // (compiler) and arm64 (runtime) to agree.
-  CHECK_OFFSET(Thread::stack_limit_offset(), 8);
-  CHECK_OFFSET(Thread::object_null_offset(), 120);
+  CHECK_OFFSET(Thread::stack_limit_offset(), 56);
+  CHECK_OFFSET(Thread::object_null_offset(), 168);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 26);
   CHECK_OFFSET(Isolate::object_store_offset(), 40);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 288));
 #endif
+
+  if (!ok) {
+    FATAL("CheckOffsets failed.");
+  }
 #undef CHECK_OFFSET
 }
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 7d9b8f5..b01af49 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -5922,6 +5922,29 @@
 }
 
 DART_EXPORT
+Dart_Handle Dart_SaveTypeFeedback(uint8_t** buffer, intptr_t* buffer_length) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
+#else
+  Thread* thread = Thread::Current();
+  API_TIMELINE_DURATION(thread);
+  DARTSCOPE(thread);
+  CHECK_NULL(buffer);
+  CHECK_NULL(buffer_length);
+
+  WriteStream stream(buffer, ApiReallocate, MB);
+  TypeFeedbackSaver saver(&stream);
+  saver.WriteHeader();
+  saver.SaveClasses();
+  saver.SaveFields();
+  ProgramVisitor::VisitFunctions(&saver);
+  *buffer_length = stream.bytes_written();
+
+  return Api::Success();
+#endif  // defined(DART_PRECOMPILED_RUNTIME)
+}
+
+DART_EXPORT
 Dart_Handle Dart_LoadCompilationTrace(uint8_t* buffer, intptr_t buffer_length) {
 #if defined(DART_PRECOMPILED_RUNTIME)
   return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
@@ -5940,6 +5963,25 @@
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 }
 
+DART_EXPORT
+Dart_Handle Dart_LoadTypeFeedback(uint8_t* buffer, intptr_t buffer_length) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
+#else
+  Thread* thread = Thread::Current();
+  API_TIMELINE_DURATION(thread);
+  DARTSCOPE(thread);
+  CHECK_NULL(buffer);
+  ReadStream stream(buffer, buffer_length);
+  TypeFeedbackLoader loader(thread);
+  const Object& error = Object::Handle(loader.LoadFeedback(&stream));
+  if (error.IsError()) {
+    return Api::NewHandle(T, Error::Cast(error).raw());
+  }
+  return Api::Success();
+#endif  // defined(DART_PRECOMPILED_RUNTIME)
+}
+
 DART_EXPORT Dart_Handle Dart_SortClasses() {
 #if defined(DART_PRECOMPILED_RUNTIME)
   return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index adb7182..8d91094 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -131,9 +131,9 @@
 class Api : AllStatic {
  public:
   // Create on the stack to provide a new throw-safe api scope.
-  class Scope : public StackResource {
+  class Scope : public ThreadStackResource {
    public:
-    explicit Scope(Thread* thread) : StackResource(thread) {
+    explicit Scope(Thread* thread) : ThreadStackResource(thread) {
       thread->EnterApiScope();
     }
     ~Scope() { thread()->ExitApiScope(); }
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 4e0acbc..a741a5e 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -93,10 +93,11 @@
 
 // Clears/restores Thread::long_jump_base on construction/destruction.
 // Ensures that we do not attempt to long jump across Dart frames.
-class SuspendLongJumpScope : public StackResource {
+class SuspendLongJumpScope : public ThreadStackResource {
  public:
   explicit SuspendLongJumpScope(Thread* thread)
-      : StackResource(thread), saved_long_jump_base_(thread->long_jump_base()) {
+      : ThreadStackResource(thread),
+        saved_long_jump_base_(thread->long_jump_base()) {
     thread->set_long_jump_base(NULL);
   }
 
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 360585e..43f2d64 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -372,7 +372,7 @@
     WriteByte(static_cast<uint8_t>(value + kEndUnsignedByteMarker));
   }
 
-  void WriteBytes(const uint8_t* addr, intptr_t len) {
+  void WriteBytes(const void* addr, intptr_t len) {
     if ((end_ - current_) < len) {
       Resize(len);
     }
diff --git a/runtime/vm/growable_array.h b/runtime/vm/growable_array.h
index 4788bff..5cd2d0b 100644
--- a/runtime/vm/growable_array.h
+++ b/runtime/vm/growable_array.h
@@ -11,7 +11,7 @@
 #define RUNTIME_VM_GROWABLE_ARRAY_H_
 
 #include "platform/growable_array.h"
-#include "vm/thread.h"
+#include "vm/thread_state.h"
 #include "vm/zone.h"
 
 namespace dart {
@@ -25,10 +25,10 @@
   explicit GrowableArray(intptr_t initial_capacity)
       : BaseGrowableArray<T, ValueObject, Zone>(
             initial_capacity,
-            ASSERT_NOTNULL(Thread::Current()->zone())) {}
+            ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
   GrowableArray()
       : BaseGrowableArray<T, ValueObject, Zone>(
-            ASSERT_NOTNULL(Thread::Current()->zone())) {}
+            ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
 };
 
 template <typename T>
@@ -40,10 +40,10 @@
   explicit ZoneGrowableArray(intptr_t initial_capacity)
       : BaseGrowableArray<T, ZoneAllocated, Zone>(
             initial_capacity,
-            ASSERT_NOTNULL(Thread::Current()->zone())) {}
+            ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
   ZoneGrowableArray()
       : BaseGrowableArray<T, ZoneAllocated, Zone>(
-            ASSERT_NOTNULL(Thread::Current()->zone())) {}
+            ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
 };
 
 // T must be a Handle type.
diff --git a/runtime/vm/handles.cc b/runtime/vm/handles.cc
index 33e2e70..3c429ef 100644
--- a/runtime/vm/handles.cc
+++ b/runtime/vm/handles.cc
@@ -84,7 +84,7 @@
 #endif
 }
 
-HandleScope::HandleScope(Thread* thread) : StackResource(thread) {
+HandleScope::HandleScope(Thread* thread) : ThreadStackResource(thread) {
   Initialize();
 }
 
diff --git a/runtime/vm/handles.h b/runtime/vm/handles.h
index 7eaf8a6..522aa02 100644
--- a/runtime/vm/handles.h
+++ b/runtime/vm/handles.h
@@ -8,6 +8,7 @@
 #include "vm/allocation.h"
 #include "vm/flags.h"
 #include "vm/os.h"
+#include "vm/thread_stack_resource.h"
 
 namespace dart {
 
@@ -278,7 +279,7 @@
 //   code that creates some scoped handles.
 //   ....
 // }
-class HandleScope : public StackResource {
+class HandleScope : public ThreadStackResource {
  public:
   explicit HandleScope(Thread* thread);
   ~HandleScope();
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 0a2b76c..1582c79 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -374,7 +374,7 @@
  public:
   DirectChainedHashMap()
       : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
-            ASSERT_NOTNULL(Thread::Current()->zone())) {}
+            ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
 
   explicit DirectChainedHashMap(Zone* zone)
       : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index a9c9e5d..da5e831 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -8,6 +8,7 @@
 #include "platform/utils.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/flags.h"
+#include "vm/heap/become.h"
 #include "vm/heap/pages.h"
 #include "vm/heap/safepoint.h"
 #include "vm/heap/scavenger.h"
@@ -61,23 +62,72 @@
   }
 }
 
+void Heap::MakeTLABIterable(Thread* thread) {
+  uword start = thread->top();
+  uword end = thread->end();
+  ASSERT(end >= start);
+  intptr_t size = end - start;
+  ASSERT(Utils::IsAligned(size, kObjectAlignment));
+  if (size >= kObjectAlignment) {
+    // ForwardingCorpse(forwarding to default null) will work as filler.
+    ForwardingCorpse::AsForwarder(start, size);
+    ASSERT(RawObject::FromAddr(start)->Size() == size);
+  }
+}
+
+void Heap::AbandonRemainingTLAB(Thread* thread) {
+  MakeTLABIterable(thread);
+  thread->set_top(0);
+  thread->set_end(0);
+}
+
+intptr_t Heap::CalculateTLABSize() {
+  intptr_t size = new_space_.end() - new_space_.top();
+  return Utils::RoundDown(size, kObjectAlignment);
+}
+
 uword Heap::AllocateNew(intptr_t size) {
   ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
   // Currently, only the Dart thread may allocate in new space.
   isolate()->AssertCurrentThreadIsMutator();
   Thread* thread = Thread::Current();
   uword addr = new_space_.TryAllocateInTLAB(thread, size);
-  if (addr == 0) {
-    // This call to CollectGarbage might end up "reusing" a collection spawned
-    // from a different thread and will be racing to allocate the requested
-    // memory with other threads being released after the collection.
-    CollectGarbage(kNew);
-    addr = new_space_.TryAllocateInTLAB(thread, size);
-    if (addr == 0) {
-      return AllocateOld(size, HeapPage::kData);
+  if (addr != 0) {
+    return addr;
+  }
+
+  intptr_t tlab_size = CalculateTLABSize();
+  if ((tlab_size > 0) && (size > tlab_size)) {
+    return AllocateOld(size, HeapPage::kData);
+  }
+
+  AbandonRemainingTLAB(thread);
+  if (tlab_size > 0) {
+    uword tlab_top = new_space_.TryAllocateNewTLAB(thread, tlab_size);
+    if (tlab_top != 0) {
+      addr = new_space_.TryAllocateInTLAB(thread, size);
+      ASSERT(addr != 0);
+      return addr;
     }
   }
-  return addr;
+
+  ASSERT(!thread->HasActiveTLAB());
+
+  // This call to CollectGarbage might end up "reusing" a collection spawned
+  // from a different thread and will be racing to allocate the requested
+  // memory with other threads being released after the collection.
+  CollectGarbage(kNew);
+  tlab_size = CalculateTLABSize();
+  uword tlab_top = new_space_.TryAllocateNewTLAB(thread, tlab_size);
+  if (tlab_top != 0) {
+    addr = new_space_.TryAllocateInTLAB(thread, size);
+    // It is possible a GC doesn't clear enough space.
+    // In that case, we must fall through and allocate into old space.
+    if (addr != 0) {
+      return addr;
+    }
+  }
+  return AllocateOld(size, HeapPage::kData);
 }
 
 uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) {
@@ -200,7 +250,7 @@
 }
 
 HeapIterationScope::HeapIterationScope(Thread* thread, bool writable)
-    : StackResource(thread),
+    : ThreadStackResource(thread),
       heap_(isolate()->heap()),
       old_space_(heap_->old_space()),
       writable_(writable) {
@@ -647,7 +697,7 @@
   StackZone stack_zone(Thread::Current());
 
   // Change the new space's top_ with the more up-to-date thread's view of top_
-  new_space_.FlushTLS();
+  new_space_.MakeNewSpaceIterable();
 
   ObjectSet* allocated_set =
       CreateAllocatedObjectSet(stack_zone.GetZone(), mark_expectation);
@@ -955,7 +1005,7 @@
 }
 
 NoHeapGrowthControlScope::NoHeapGrowthControlScope()
-    : StackResource(Thread::Current()) {
+    : ThreadStackResource(Thread::Current()) {
   Heap* heap = reinterpret_cast<Isolate*>(isolate())->heap();
   current_growth_controller_state_ = heap->GrowthControlState();
   heap->DisableGrowthControl();
@@ -967,7 +1017,7 @@
 }
 
 WritableVMIsolateScope::WritableVMIsolateScope(Thread* thread)
-    : StackResource(thread) {
+    : ThreadStackResource(thread) {
   if (FLAG_write_protect_vm_isolate) {
     Dart::vm_isolate()->heap()->WriteProtect(false);
   }
@@ -990,7 +1040,7 @@
 }
 
 BumpAllocateScope::BumpAllocateScope(Thread* thread)
-    : StackResource(thread), no_reload_scope_(thread->isolate(), thread) {
+    : ThreadStackResource(thread), no_reload_scope_(thread->isolate(), thread) {
   ASSERT(!thread->bump_allocate());
   // If the background compiler thread is not disabled, there will be a cycle
   // between the symbol table lock and the old space data lock.
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 8cedd89..6935bd1 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -281,6 +281,10 @@
 
   static const intptr_t kNewAllocatableSize = 256 * KB;
 
+  intptr_t CalculateTLABSize();
+  void MakeTLABIterable(Thread* thread);
+  void AbandonRemainingTLAB(Thread* thread);
+
  private:
   class GCStats : public ValueObject {
    public:
@@ -391,7 +395,7 @@
   DISALLOW_COPY_AND_ASSIGN(Heap);
 };
 
-class HeapIterationScope : public StackResource {
+class HeapIterationScope : public ThreadStackResource {
  public:
   explicit HeapIterationScope(Thread* thread, bool writable = false);
   ~HeapIterationScope();
@@ -416,7 +420,7 @@
   DISALLOW_COPY_AND_ASSIGN(HeapIterationScope);
 };
 
-class NoHeapGrowthControlScope : public StackResource {
+class NoHeapGrowthControlScope : public ThreadStackResource {
  public:
   NoHeapGrowthControlScope();
   ~NoHeapGrowthControlScope();
@@ -428,7 +432,7 @@
 
 // Note: During this scope all pages are writable and the code pages are
 // non-executable.
-class WritableVMIsolateScope : StackResource {
+class WritableVMIsolateScope : ThreadStackResource {
  public:
   explicit WritableVMIsolateScope(Thread* thread);
   ~WritableVMIsolateScope();
@@ -446,7 +450,7 @@
 // This scope forces heap growth, forces use of the bump allocator, and
 // takes the page lock. It is useful e.g. at program startup when allocating
 // many objects into old gen (like libraries, classes, and functions).
-class BumpAllocateScope : StackResource {
+class BumpAllocateScope : ThreadStackResource {
  public:
   explicit BumpAllocateScope(Thread* thread);
   ~BumpAllocateScope();
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index c47ff50..af5236c 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -267,12 +267,14 @@
   for (size_t space = 0; space < ARRAY_SIZE(spaces); ++space) {
     const String& obj = String::Handle(String::New("x", spaces[space]));
     {
+      HeapIterationScope iteration(thread);
       NoSafepointScope no_safepoint;
       FindOnly find_only(obj.raw());
       EXPECT(obj.raw() == heap->FindObject(&find_only));
     }
   }
   {
+    HeapIterationScope iteration(thread);
     NoSafepointScope no_safepoint;
     FindNothing find_nothing;
     EXPECT(Object::null() == heap->FindObject(&find_nothing));
diff --git a/runtime/vm/heap/safepoint.cc b/runtime/vm/heap/safepoint.cc
index bf5def1..c231b9c 100644
--- a/runtime/vm/heap/safepoint.cc
+++ b/runtime/vm/heap/safepoint.cc
@@ -11,7 +11,8 @@
 
 DEFINE_FLAG(bool, trace_safepoint, false, "Trace Safepoint logic.");
 
-SafepointOperationScope::SafepointOperationScope(Thread* T) : StackResource(T) {
+SafepointOperationScope::SafepointOperationScope(Thread* T)
+    : ThreadStackResource(T) {
   ASSERT(T != NULL);
   Isolate* I = T->isolate();
   ASSERT(I != NULL);
diff --git a/runtime/vm/heap/safepoint.h b/runtime/vm/heap/safepoint.h
index 191323f..ce84f85 100644
--- a/runtime/vm/heap/safepoint.h
+++ b/runtime/vm/heap/safepoint.h
@@ -8,13 +8,14 @@
 #include "vm/globals.h"
 #include "vm/lockers.h"
 #include "vm/thread.h"
+#include "vm/thread_stack_resource.h"
 
 namespace dart {
 
 // A stack based scope that can be used to perform an operation after getting
 // all threads to a safepoint. At the end of the operation all the threads are
 // resumed.
-class SafepointOperationScope : public StackResource {
+class SafepointOperationScope : public ThreadStackResource {
  public:
   explicit SafepointOperationScope(Thread* T);
   ~SafepointOperationScope();
@@ -136,9 +137,9 @@
  *   ==> kThreadInGenerated
  *       - Invalid transition.
  */
-class TransitionSafepointState : public StackResource {
+class TransitionSafepointState : public ThreadStackResource {
  public:
-  explicit TransitionSafepointState(Thread* T) : StackResource(T) {}
+  explicit TransitionSafepointState(Thread* T) : ThreadStackResource(T) {}
   ~TransitionSafepointState() {}
 
   SafepointHandler* handler() const {
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 9e3a457..b07afe9 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -447,13 +447,6 @@
   resolved_top_ = top_;
   end_ = to_->end();
 
-  // Throw out the old information about the from space
-  if (isolate->IsMutatorThreadScheduled()) {
-    Thread* mutator_thread = isolate->mutator_thread();
-    mutator_thread->set_top(top_);
-    mutator_thread->set_end(end_);
-  }
-
   return from;
 }
 
@@ -461,13 +454,10 @@
   // All objects in the to space have been copied from the from space at this
   // moment.
 
-  // Ensure the mutator thread now has the up-to-date top_ and end_ of the
-  // semispace
-  if (isolate->IsMutatorThreadScheduled()) {
-    Thread* thread = isolate->mutator_thread();
-    thread->set_top(top_);
-    thread->set_end(end_);
-  }
+  // Ensure the mutator thread will fail the next allocation. This will force
+  // mutator to allocate a new TLAB
+  Thread* mutator_thread = isolate->mutator_thread();
+  ASSERT((mutator_thread == NULL) || (!mutator_thread->HasActiveTLAB()));
 
   double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction();
   if (stats_history_.Size() >= 2) {
@@ -844,11 +834,45 @@
   }
 }
 
-void Scavenger::FlushTLS() const {
+void Scavenger::MakeAllTLABsIterable(Isolate* isolate) const {
+  MonitorLocker ml(isolate->threads_lock(), false);
+  ASSERT(Thread::Current()->IsAtSafepoint() ||
+         (Thread::Current()->task_kind() == Thread::kMarkerTask) ||
+         (Thread::Current()->task_kind() == Thread::kCompactorTask));
+  Thread* current = heap_->isolate()->thread_registry()->active_list();
+  while (current != NULL) {
+    if (current->HasActiveTLAB()) {
+      heap_->MakeTLABIterable(current);
+    }
+    current = current->next();
+  }
+  Thread* mutator_thread = isolate->mutator_thread();
+  if ((mutator_thread != NULL) && (!isolate->IsMutatorThreadScheduled())) {
+    heap_->MakeTLABIterable(mutator_thread);
+  }
+}
+
+void Scavenger::MakeNewSpaceIterable() const {
   ASSERT(heap_ != NULL);
-  if (heap_->isolate()->IsMutatorThreadScheduled()) {
-    Thread* mutator_thread = heap_->isolate()->mutator_thread();
-    mutator_thread->heap()->new_space()->set_top(mutator_thread->top());
+  ASSERT(Thread::Current()->IsAtSafepoint() ||
+         (Thread::Current()->task_kind() == Thread::kMarkerTask) ||
+         (Thread::Current()->task_kind() == Thread::kCompactorTask));
+  if (!scavenging_) {
+    MakeAllTLABsIterable(heap_->isolate());
+  }
+}
+
+void Scavenger::AbandonAllTLABs(Isolate* isolate) {
+  ASSERT(Thread::Current()->IsAtSafepoint());
+  MonitorLocker ml(isolate->threads_lock(), false);
+  Thread* current = isolate->thread_registry()->active_list();
+  while (current != NULL) {
+    heap_->AbandonRemainingTLAB(current);
+    current = current->next();
+  }
+  Thread* mutator_thread = isolate->mutator_thread();
+  if ((mutator_thread != NULL) && (!isolate->IsMutatorThreadScheduled())) {
+    heap_->AbandonRemainingTLAB(mutator_thread);
   }
 }
 
@@ -856,7 +880,7 @@
   ASSERT(Thread::Current()->IsAtSafepoint() ||
          (Thread::Current()->task_kind() == Thread::kMarkerTask) ||
          (Thread::Current()->task_kind() == Thread::kCompactorTask));
-  FlushTLS();
+  MakeNewSpaceIterable();
   uword cur = FirstObjectStart();
   while (cur < top_) {
     RawObject* raw_obj = RawObject::FromAddr(cur);
@@ -867,7 +891,7 @@
 void Scavenger::VisitObjects(ObjectVisitor* visitor) const {
   ASSERT(Thread::Current()->IsAtSafepoint() ||
          (Thread::Current()->task_kind() == Thread::kMarkerTask));
-  FlushTLS();
+  MakeNewSpaceIterable();
   uword cur = FirstObjectStart();
   while (cur < top_) {
     RawObject* raw_obj = RawObject::FromAddr(cur);
@@ -882,7 +906,7 @@
 
 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const {
   ASSERT(!scavenging_);
-  FlushTLS();
+  MakeNewSpaceIterable();
   uword cur = FirstObjectStart();
   if (visitor->VisitRange(cur, top_)) {
     while (cur < top_) {
@@ -898,6 +922,26 @@
   return Object::null();
 }
 
+uword Scavenger::TryAllocateNewTLAB(Thread* thread, intptr_t size) {
+  ASSERT(Utils::IsAligned(size, kObjectAlignment));
+  ASSERT(heap_ != Dart::vm_isolate()->heap());
+  ASSERT(!scavenging_);
+  MutexLocker ml(&space_lock_);
+  uword result = top_;
+  intptr_t remaining = end_ - top_;
+  if (remaining < size) {
+    return 0;
+  }
+  ASSERT(to_->Contains(result));
+  ASSERT((result & kObjectAlignmentMask) == object_alignment_);
+  top_ += size;
+  ASSERT(to_->Contains(top_) || (top_ == to_->end()));
+  ASSERT(result < top_);
+  thread->set_top(result);
+  thread->set_end(top_);
+  return result;
+}
+
 void Scavenger::Scavenge() {
   Isolate* isolate = heap_->isolate();
   // Ensure that all threads for this isolate are at a safepoint (either stopped
@@ -923,6 +967,13 @@
   int64_t safe_point = OS::GetCurrentMonotonicMicros();
   heap_->RecordTime(kSafePoint, safe_point - start);
 
+  AbandonAllTLABs(isolate);
+
+  Thread* mutator_thread = isolate->mutator_thread();
+  if ((mutator_thread != NULL) && (mutator_thread->HasActiveTLAB())) {
+    heap_->AbandonRemainingTLAB(mutator_thread);
+  }
+
   // TODO(koda): Make verification more compatible with concurrent sweep.
   if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) {
     OS::PrintErr("Verifying before Scavenge...");
@@ -931,7 +982,7 @@
   }
 
   // Prepare for a scavenge.
-  FlushTLS();
+  MakeNewSpaceIterable();
   SpaceUsage usage_before = GetCurrentUsage();
   intptr_t promo_candidate_words =
       (survivor_end_ - FirstObjectStart()) / kWordSize;
@@ -1040,11 +1091,6 @@
   // Forces the next scavenge to promote all the objects in the new space.
   survivor_end_ = top_;
 
-  if (heap_->isolate()->IsMutatorThreadScheduled()) {
-    Thread* mutator_thread = heap_->isolate()->mutator_thread();
-    survivor_end_ = mutator_thread->top();
-  }
-
   Scavenge();
 
   // It is possible for objects to stay in the new space
diff --git a/runtime/vm/heap/scavenger.h b/runtime/vm/heap/scavenger.h
index 412395d..bd8ad4f 100644
--- a/runtime/vm/heap/scavenger.h
+++ b/runtime/vm/heap/scavenger.h
@@ -11,6 +11,7 @@
 #include "vm/flags.h"
 #include "vm/globals.h"
 #include "vm/heap/spaces.h"
+#include "vm/lockers.h"
 #include "vm/raw_object.h"
 #include "vm/ring_buffer.h"
 #include "vm/virtual_memory.h"
@@ -126,6 +127,8 @@
 
   RawObject* FindObject(FindObjectVisitor* visitor) const;
 
+  uword TryAllocateNewTLAB(Thread* thread, intptr_t size);
+
   uword AllocateGC(intptr_t size) {
     ASSERT(Utils::IsAligned(size, kObjectAlignment));
     ASSERT(heap_ != Dart::vm_isolate()->heap());
@@ -139,7 +142,7 @@
     ASSERT(to_->Contains(result));
     ASSERT((result & kObjectAlignmentMask) == object_alignment_);
     top_ += size;
-    ASSERT(to_->Contains(top_) || (top_ == to_->end()));
+    ASSERT((to_->Contains(top_)) || (top_ == to_->end()));
     return result;
   }
 
@@ -148,6 +151,8 @@
     ASSERT(heap_ != Dart::vm_isolate()->heap());
     ASSERT(thread->IsMutatorThread());
     ASSERT(thread->isolate()->IsMutatorThreadScheduled());
+    ASSERT(thread->top() <= top_);
+    ASSERT((thread->end() == 0) || (thread->end() == top_));
 #if defined(DEBUG)
     if (FLAG_gc_at_alloc) {
       ASSERT(!scavenging_);
@@ -164,7 +169,7 @@
     ASSERT(to_->Contains(result));
     ASSERT((result & kObjectAlignmentMask) == object_alignment_);
     top += size;
-    ASSERT(to_->Contains(top) || (top == to_->end()));
+    ASSERT((to_->Contains(top)) || (top == to_->end()));
     thread->set_top(top);
     return result;
   }
@@ -221,7 +226,10 @@
   void AllocateExternal(intptr_t cid, intptr_t size);
   void FreeExternal(intptr_t size);
 
-  void FlushTLS() const;
+  void MakeNewSpaceIterable() const;
+  int64_t FreeSpaceInWords(Isolate* isolate) const;
+  void MakeAllTLABsIterable(Isolate* isolate) const;
+  void AbandonAllTLABs(Isolate* isolate);
 
  private:
   // Ids for time and data records in Heap::GCStats.
@@ -323,6 +331,9 @@
 
   bool failed_to_promote_;
 
+  // Protects new space during the allocation of new TLABs
+  Mutex space_lock_;
+
   friend class ScavengerVisitor;
   friend class ScavengerWeakVisitor;
 
diff --git a/runtime/vm/heap/sweeper.cc b/runtime/vm/heap/sweeper.cc
index 8292a7d..7e477d7 100644
--- a/runtime/vm/heap/sweeper.cc
+++ b/runtime/vm/heap/sweeper.cc
@@ -4,6 +4,7 @@
 
 #include "vm/heap/sweeper.h"
 
+#include "vm/compiler/assembler/assembler.h"
 #include "vm/globals.h"
 #include "vm/heap/freelist.h"
 #include "vm/heap/heap.h"
@@ -48,7 +49,13 @@
       }
       obj_size = free_end - current;
       if (is_executable) {
-        memset(reinterpret_cast<void*>(current), 0xcc, obj_size);
+        uword cursor = current;
+        uword end = current + obj_size;
+        while (cursor < end) {
+          *reinterpret_cast<uword*>(cursor) =
+              Assembler::GetBreakInstructionFiller();
+          cursor += kWordSize;
+        }
       } else {
 #if defined(DEBUG)
         memset(reinterpret_cast<void*>(current), Heap::kZapByte, obj_size);
diff --git a/runtime/vm/heap/verifier.cc b/runtime/vm/heap/verifier.cc
index 29bbe385..8ea2fdb 100644
--- a/runtime/vm/heap/verifier.cc
+++ b/runtime/vm/heap/verifier.cc
@@ -20,7 +20,7 @@
   if (raw_obj->IsHeapObject()) {
     uword raw_addr = RawObject::ToAddr(raw_obj);
     if (raw_obj->IsFreeListElement() || raw_obj->IsForwardingCorpse()) {
-      if (raw_obj->IsMarked()) {
+      if (raw_obj->IsOldObject() && raw_obj->IsMarked()) {
         FATAL1("Marked free list element encountered %#" Px "\n", raw_addr);
       }
     } else {
diff --git a/runtime/vm/heap/verifier.h b/runtime/vm/heap/verifier.h
index f12ba82..d811be6 100644
--- a/runtime/vm/heap/verifier.h
+++ b/runtime/vm/heap/verifier.h
@@ -8,6 +8,7 @@
 #include "vm/flags.h"
 #include "vm/globals.h"
 #include "vm/handles.h"
+#include "vm/thread.h"
 #include "vm/visitor.h"
 
 namespace dart {
diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h
index 22d27a2..4e98f3e 100644
--- a/runtime/vm/interpreter.h
+++ b/runtime/vm/interpreter.h
@@ -24,6 +24,7 @@
 class RawArray;
 class RawObjectPool;
 class RawFunction;
+class RawString;
 class RawSubtypeTestCache;
 class ObjectPointerVisitor;
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index df87172..7f1e8a2 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -148,7 +148,8 @@
   return Isolate::IsVMInternalIsolate(isolate);
 }
 
-NoOOBMessageScope::NoOOBMessageScope(Thread* thread) : StackResource(thread) {
+NoOOBMessageScope::NoOOBMessageScope(Thread* thread)
+    : ThreadStackResource(thread) {
   thread->DeferOOBMessageInterrupts();
 }
 
@@ -157,7 +158,7 @@
 }
 
 NoReloadScope::NoReloadScope(Isolate* isolate, Thread* thread)
-    : StackResource(thread), isolate_(isolate) {
+    : ThreadStackResource(thread), isolate_(isolate) {
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
   ASSERT(isolate_ != NULL);
   AtomicOperations::FetchAndIncrement(&(isolate_->no_reload_scope_depth_));
@@ -2836,10 +2837,6 @@
     os_thread->set_thread(thread);
     if (is_mutator) {
       scheduled_mutator_thread_ = thread;
-      if (this != Dart::vm_isolate()) {
-        scheduled_mutator_thread_->set_top(heap()->new_space()->top());
-        scheduled_mutator_thread_->set_end(heap()->new_space()->end());
-      }
     }
     Thread::SetCurrent(thread);
     os_thread->EnableThreadInterrupts();
@@ -2865,7 +2862,7 @@
     }
   } else {
     ASSERT(thread->api_top_scope_ == NULL);
-    ASSERT(thread->zone_ == NULL);
+    ASSERT(thread->zone() == NULL);
     ASSERT(thread->sticky_error() == Error::null());
   }
   if (!bypass_safepoint) {
@@ -2878,12 +2875,6 @@
   os_thread->set_thread(NULL);
   OSThread::SetCurrent(os_thread);
   if (is_mutator) {
-    if (this != Dart::vm_isolate()) {
-      heap()->new_space()->set_top(scheduled_mutator_thread_->top_);
-      heap()->new_space()->set_end(scheduled_mutator_thread_->end_);
-    }
-    scheduled_mutator_thread_->top_ = 0;
-    scheduled_mutator_thread_->end_ = 0;
     scheduled_mutator_thread_ = NULL;
   }
   // Even if we unschedule the mutator thread, e.g. via calling
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 278857f..ffa2a03 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -21,6 +21,7 @@
 #include "vm/random.h"
 #include "vm/tags.h"
 #include "vm/thread.h"
+#include "vm/thread_stack_resource.h"
 #include "vm/token_position.h"
 
 namespace dart {
@@ -106,7 +107,7 @@
 };
 
 // Disallow OOB message handling within this scope.
-class NoOOBMessageScope : public StackResource {
+class NoOOBMessageScope : public ThreadStackResource {
  public:
   explicit NoOOBMessageScope(Thread* thread);
   ~NoOOBMessageScope();
@@ -116,7 +117,7 @@
 };
 
 // Disallow isolate reload.
-class NoReloadScope : public StackResource {
+class NoReloadScope : public ThreadStackResource {
  public:
   NoReloadScope(Isolate* isolate, Thread* thread);
   ~NoReloadScope();
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index ddc9884..4710aad 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -17,7 +17,7 @@
 // package:kernel/binary.md.
 
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
-static const uint32_t kBinaryFormatVersion = 15;
+static const uint32_t kBinaryFormatVersion = 16;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
@@ -147,6 +147,12 @@
   kPartialInstantiationConstant = 9,
   kTearOffConstant = 10,
   kTypeLiteralConstant = 11,
+  // These constants are not expected to be seen by the VM, because all
+  // constants are fully evaluated.
+  kEnvironmentBoolConstant = 12,
+  kEnvironmentIntConstant = 13,
+  kEnvironmentStringConstant = 14,
+  kUnevaluatedConstant = 15,
 };
 
 static const int SpecializedIntLiteralBias = 3;
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index d629c76..693078c 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -9,6 +9,7 @@
 #include "vm/compiler/jit/compiler.h"
 #include "vm/dart_api_impl.h"
 #include "vm/dart_entry.h"
+#include "vm/flags.h"
 #include "vm/isolate.h"
 #include "vm/lockers.h"
 #include "vm/message.h"
@@ -343,6 +344,17 @@
                                  Dart_WeakPersistentHandle handle,
                                  void* peer) {}
 
+MallocGrowableArray<char*>* KernelIsolate::experimental_flags_ =
+    new MallocGrowableArray<char*>();
+
+void KernelIsolate::AddExperimentalFlag(const char* value) {
+  experimental_flags_->Add(strdup(value));
+}
+
+DEFINE_OPTION_HANDLER(KernelIsolate::AddExperimentalFlag,
+                      enable_experiment,
+                      "Comma separated list of experimental features.");
+
 class KernelCompilationRequest : public ValueObject {
  public:
   KernelCompilationRequest()
@@ -373,7 +385,8 @@
       const Array& type_definitions,
       char const* library_uri,
       char const* klass,
-      bool is_static) {
+      bool is_static,
+      const MallocGrowableArray<char*>* experimental_flags) {
     Thread* thread = Thread::Current();
     TransitionNativeToVM transition(thread);
     Dart_CObject tag;
@@ -443,12 +456,25 @@
     isolate_id.value.as_int64 =
         isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
 
-    Dart_CObject message;
-    message.type = Dart_CObject_kArray;
     Dart_CObject suppress_warnings;
     suppress_warnings.type = Dart_CObject_kBool;
     suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
 
+    intptr_t num_experimental_flags = experimental_flags->length();
+    Dart_CObject** experimental_flags_array =
+        new Dart_CObject*[num_experimental_flags];
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      experimental_flags_array[i] = new Dart_CObject;
+      experimental_flags_array[i]->type = Dart_CObject_kString;
+      experimental_flags_array[i]->value.as_string = (*experimental_flags)[i];
+    }
+    Dart_CObject experimental_flags_object;
+    experimental_flags_object.type = Dart_CObject_kArray;
+    experimental_flags_object.value.as_array.values = experimental_flags_array;
+    experimental_flags_object.value.as_array.length = num_experimental_flags;
+
+    Dart_CObject message;
+    message.type = Dart_CObject_kArray;
     Dart_CObject* message_arr[] = {&tag,
                                    &send_port,
                                    &isolate_id,
@@ -458,7 +484,8 @@
                                    &library_uri_object,
                                    &class_object,
                                    &is_static_object,
-                                   &suppress_warnings};
+                                   &suppress_warnings,
+                                   &experimental_flags_object};
     message.value.as_array.values = message_arr;
     message.value.as_array.length = ARRAY_SIZE(message_arr);
 
@@ -486,6 +513,11 @@
     }
     delete[] type_definitions_array;
 
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      delete experimental_flags_array[i];
+    }
+    delete[] experimental_flags_array;
+
     return result_;
   }
 
@@ -500,7 +532,8 @@
       bool incremental_compile,
       const char* package_config,
       const char* multiroot_filepaths,
-      const char* multiroot_scheme) {
+      const char* multiroot_scheme,
+      const MallocGrowableArray<char*>* experimental_flags) {
     // Build the [null, send_port, script_uri, platform_kernel,
     // incremental_compile, isolate_id, [files]] message for the Kernel isolate.
     // tag is used to specify which operation the frontend should perform.
@@ -570,6 +603,19 @@
     suppress_warnings.type = Dart_CObject_kBool;
     suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
 
+    intptr_t num_experimental_flags = experimental_flags->length();
+    Dart_CObject** experimental_flags_array =
+        new Dart_CObject*[num_experimental_flags];
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      experimental_flags_array[i] = new Dart_CObject;
+      experimental_flags_array[i]->type = Dart_CObject_kString;
+      experimental_flags_array[i]->value.as_string = (*experimental_flags)[i];
+    }
+    Dart_CObject experimental_flags_object;
+    experimental_flags_object.type = Dart_CObject_kArray;
+    experimental_flags_object.value.as_array.values = experimental_flags_array;
+    experimental_flags_object.value.as_array.length = num_experimental_flags;
+
     Dart_CObject bytecode;
     bytecode.type = Dart_CObject_kBool;
     // Interpreter is supported only on x64 and arm64.
@@ -625,6 +671,7 @@
                                    &isolate_id,
                                    &files,
                                    &suppress_warnings,
+                                   &experimental_flags_object,
                                    &bytecode,
                                    &package_config_uri,
                                    &multiroot_filepaths_object,
@@ -643,6 +690,11 @@
       ml.Wait();
     }
 
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      delete experimental_flags_array[i];
+    }
+    delete[] experimental_flags_array;
+
     return result_;
   }
 
@@ -774,11 +826,11 @@
   }
 
   KernelCompilationRequest request;
-  return request.SendAndWaitForResponse(kCompileTag, kernel_port, script_uri,
-                                        platform_kernel, platform_kernel_size,
-                                        source_file_count, source_files,
-                                        incremental_compile, package_config,
-                                        multiroot_filepaths, multiroot_scheme);
+  return request.SendAndWaitForResponse(
+      kCompileTag, kernel_port, script_uri, platform_kernel,
+      platform_kernel_size, source_file_count, source_files,
+      incremental_compile, package_config, multiroot_filepaths,
+      multiroot_scheme, experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::ListDependencies() {
@@ -793,7 +845,7 @@
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
                                         NULL, 0, 0, NULL, false, NULL, NULL,
-                                        NULL);
+                                        NULL, experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
@@ -809,7 +861,8 @@
 
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0,
-                                        0, NULL, true, NULL, NULL, NULL);
+                                        0, NULL, true, NULL, NULL, NULL,
+                                        experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
@@ -831,7 +884,7 @@
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(kernel_port, expression, definitions,
                                         type_definitions, library_url, klass,
-                                        is_static);
+                                        is_static, experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::UpdateInMemorySources(
@@ -848,9 +901,9 @@
   }
 
   KernelCompilationRequest request;
-  return request.SendAndWaitForResponse(kUpdateSourcesTag, kernel_port, NULL,
-                                        NULL, 0, source_files_count,
-                                        source_files, true, NULL, NULL, NULL);
+  return request.SendAndWaitForResponse(
+      kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count,
+      source_files, true, NULL, NULL, NULL, experimental_flags_);
 }
 
 void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index a271351..284177b 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_KERNEL_ISOLATE_H_
 #define RUNTIME_VM_KERNEL_ISOLATE_H_
 
+#include <vector>
+
 #include "include/dart_api.h"
 #include "include/dart_native_api.h"
 
@@ -65,6 +67,8 @@
 
   static void NotifyAboutIsolateShutdown(const Isolate* isolate);
 
+  static void AddExperimentalFlag(const char* value);
+
  protected:
   static Monitor* monitor_;
   static Dart_IsolateCreateCallback create_callback_;
@@ -82,6 +86,8 @@
     return create_callback_;
   }
 
+  static MallocGrowableArray<char*>* experimental_flags_;
+
   friend class Dart;
   friend class Isolate;
   friend class RunKernelTask;
diff --git a/runtime/vm/log.h b/runtime/vm/log.h
index b644884..1c4a6d0 100644
--- a/runtime/vm/log.h
+++ b/runtime/vm/log.h
@@ -74,13 +74,13 @@
 // Can be nested.
 class LogBlock : public StackResource {
  public:
-  LogBlock(Thread* thread, Log* log)
+  LogBlock(ThreadState* thread, Log* log)
       : StackResource(thread), log_(log), cursor_(log->cursor()) {
     Initialize();
   }
 
   LogBlock()
-      : StackResource(Thread::Current()),
+      : StackResource(ThreadState::Current()),
         log_(Log::Current()),
         cursor_(Log::Current()->cursor()) {
     Initialize();
diff --git a/runtime/vm/longjump.h b/runtime/vm/longjump.h
index 9da35b9..a334f15 100644
--- a/runtime/vm/longjump.h
+++ b/runtime/vm/longjump.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
@@ -8,7 +8,7 @@
 #include <setjmp.h>
 
 #include "vm/allocation.h"
-#include "vm/isolate.h"
+#include "vm/thread_state.h"
 
 namespace dart {
 
@@ -17,14 +17,14 @@
 class LongJumpScope : public StackResource {
  public:
   LongJumpScope()
-      : StackResource(Thread::Current()),
-        top_(NULL),
+      : StackResource(ThreadState::Current()),
+        top_(nullptr),
         base_(thread()->long_jump_base()) {
     thread()->set_long_jump_base(this);
   }
 
   ~LongJumpScope() {
-    ASSERT(thread() == Thread::Current());
+    ASSERT(thread() == ThreadState::Current());
     thread()->set_long_jump_base(base_);
   }
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 55009dc..18b69c3 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3943,15 +3943,6 @@
                                             raw_ptr()->state_bits_));
 }
 
-void Class::set_is_marked_for_lazy_loading() const {
-  set_state_bits(MarkedForLazyLoadingBit::update(true, raw_ptr()->state_bits_));
-}
-
-void Class::reset_is_marked_for_lazy_loading() const {
-  set_state_bits(
-      MarkedForLazyLoadingBit::update(false, raw_ptr()->state_bits_));
-}
-
 void Class::set_interfaces(const Array& value) const {
   ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->interfaces_, value.raw());
@@ -13046,6 +13037,11 @@
 #if defined(DEBUG)
 // Used in asserts to verify that a check is not added twice.
 bool ICData::HasCheck(const GrowableArray<intptr_t>& cids) const {
+  return FindCheck(cids) != -1;
+}
+#endif  // DEBUG
+
+intptr_t ICData::FindCheck(const GrowableArray<intptr_t>& cids) const {
   const intptr_t len = NumberOfChecks();
   for (intptr_t i = 0; i < len; i++) {
     GrowableArray<intptr_t> class_ids;
@@ -13059,12 +13055,11 @@
       }
     }
     if (matches) {
-      return true;
+      return i;
     }
   }
-  return false;
+  return -1;
 }
-#endif  // DEBUG
 
 void ICData::WriteSentinelAt(intptr_t index) const {
   const intptr_t len = Length();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 22bd10f..f1de141 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -6,7 +6,6 @@
 #define RUNTIME_VM_OBJECT_H_
 
 #include <tuple>
-
 #include "include/dart_api.h"
 #include "platform/assert.h"
 #include "platform/utils.h"
@@ -1130,12 +1129,6 @@
 
   void ResetFinalization() const;
 
-  bool is_marked_for_lazy_loading() const {
-    return MarkedForLazyLoadingBit::decode(raw_ptr()->state_bits_);
-  }
-  void set_is_marked_for_lazy_loading() const;
-  void reset_is_marked_for_lazy_loading() const;
-
   bool is_const() const { return ConstBit::decode(raw_ptr()->state_bits_); }
   void set_is_const() const;
 
@@ -1318,15 +1311,14 @@
     kClassFinalizedSize = 2,
     kAbstractBit = kClassFinalizedPos + kClassFinalizedSize,  // = 5
     kPatchBit = 6,
-    kSynthesizedClassBit = 7,
-    kMarkedForLazyLoadingBit = 8,
-    kMixinAppAliasBit = 9,
-    kMixinTypeAppliedBit = 10,
-    kFieldsMarkedNullableBit = 11,
-    kCycleFreeBit = 12,
-    kEnumBit = 13,
-    kTransformedMixinApplicationBit = 14,
-    kIsAllocatedBit = 15,
+    kSynthesizedClassBit,
+    kMixinAppAliasBit,
+    kMixinTypeAppliedBit,
+    kFieldsMarkedNullableBit,
+    kCycleFreeBit,
+    kEnumBit,
+    kTransformedMixinApplicationBit,
+    kIsAllocatedBit,
   };
   class ConstBit : public BitField<uint16_t, bool, kConstBit, 1> {};
   class ImplementedBit : public BitField<uint16_t, bool, kImplementedBit, 1> {};
@@ -1340,8 +1332,6 @@
   class PatchBit : public BitField<uint16_t, bool, kPatchBit, 1> {};
   class SynthesizedClassBit
       : public BitField<uint16_t, bool, kSynthesizedClassBit, 1> {};
-  class MarkedForLazyLoadingBit
-      : public BitField<uint16_t, bool, kMarkedForLazyLoadingBit, 1> {};
   class FieldsMarkedNullableBit
       : public BitField<uint16_t, bool, kFieldsMarkedNullableBit, 1> {};
   class CycleFreeBit : public BitField<uint16_t, bool, kCycleFreeBit, 1> {};
@@ -1978,6 +1968,8 @@
 
   bool is_static_call() const;
 
+  intptr_t FindCheck(const GrowableArray<intptr_t>& cids) const;
+
  private:
   static RawICData* New();
 
@@ -4129,7 +4121,8 @@
   }
   void SetObjectAt(intptr_t index, const Object& obj) const {
     ASSERT((TypeAt(index) == kTaggedObject) ||
-           (TypeAt(index) == kNativeEntryData));
+           (TypeAt(index) == kNativeEntryData) ||
+           (TypeAt(index) == kImmediate && obj.IsSmi()));
     StorePointer(&EntryAddr(index)->raw_obj_, obj.raw());
   }
 
@@ -9311,7 +9304,9 @@
   class TupleView {
    public:
     TupleView(const Array& array, intptr_t index)
-        : array_(array), index_(index) {}
+        : array_(array), index_(index) {
+      ASSERT(!array.IsNull());
+    }
 
     template <EnumType kElement>
     typename std::tuple_element<kElement, TupleT>::type::RawObjectType* Get()
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 89fe81a..6edb424 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -199,7 +199,7 @@
   }
 }
 
-ObjectGraph::ObjectGraph(Thread* thread) : StackResource(thread) {
+ObjectGraph::ObjectGraph(Thread* thread) : ThreadStackResource(thread) {
   // The VM isolate has all its objects pre-marked, so iterating over it
   // would be a no-op.
   ASSERT(thread->isolate() != Dart::vm_isolate());
diff --git a/runtime/vm/object_graph.h b/runtime/vm/object_graph.h
index 838c61d..deb700f 100644
--- a/runtime/vm/object_graph.h
+++ b/runtime/vm/object_graph.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_OBJECT_GRAPH_H_
 
 #include "vm/allocation.h"
+#include "vm/thread_stack_resource.h"
 
 namespace dart {
 
@@ -19,7 +20,7 @@
 // Example uses:
 // - find a retaining path from the isolate roots to a particular object, or
 // - determine how much memory is retained by some particular object(s).
-class ObjectGraph : public StackResource {
+class ObjectGraph : public ThreadStackResource {
  public:
   class Stack;
 
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
index 2120380..22abcbb 100644
--- a/runtime/vm/os_thread.cc
+++ b/runtime/vm/os_thread.cc
@@ -20,7 +20,7 @@
 bool OSThread::creation_enabled_ = false;
 
 #if defined(HAS_C11_THREAD_LOCAL)
-thread_local Thread* OSThread::current_vm_thread_ = NULL;
+thread_local ThreadState* OSThread::current_vm_thread_ = NULL;
 #endif
 
 OSThread::OSThread()
@@ -214,7 +214,7 @@
   creation_enabled_ = true;
 }
 
-OSThread* OSThread::GetOSThreadFromThread(Thread* thread) {
+OSThread* OSThread::GetOSThreadFromThread(ThreadState* thread) {
   ASSERT(thread->os_thread() != NULL);
   return thread->os_thread();
 }
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index aefca34..1fcf0da 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -35,7 +35,7 @@
 // Forward declarations.
 class Log;
 class Mutex;
-class Thread;
+class ThreadState;
 class TimelineEventBlock;
 
 class BaseThread {
@@ -48,6 +48,7 @@
 
   bool is_os_thread_;
 
+  friend class ThreadState;
   friend class Thread;
   friend class OSThread;
 
@@ -140,7 +141,7 @@
       if (thread->is_os_thread()) {
         os_thread = reinterpret_cast<OSThread*>(thread);
       } else {
-        Thread* vm_thread = reinterpret_cast<Thread*>(thread);
+        ThreadState* vm_thread = reinterpret_cast<ThreadState*>(thread);
         os_thread = GetOSThreadFromThread(vm_thread);
       }
     }
@@ -159,7 +160,7 @@
   static void SetCurrent(OSThread* current) { SetCurrentTLS(current); }
 
 #if defined(HAS_C11_THREAD_LOCAL)
-  static Thread* CurrentVMThread() { return current_vm_thread_; }
+  static ThreadState* CurrentVMThread() { return current_vm_thread_; }
 #endif
 
   // TODO(5411455): Use flag to override default value and Validate the
@@ -225,14 +226,14 @@
   // in the windows thread interrupter which is used for profiling.
   // We could eliminate this requirement if the windows thread interrupter
   // is implemented differently.
-  Thread* thread() const { return thread_; }
-  void set_thread(Thread* value) { thread_ = value; }
+  ThreadState* thread() const { return thread_; }
+  void set_thread(ThreadState* value) { thread_ = value; }
 
   static void Cleanup();
 #ifndef PRODUCT
   static ThreadId GetCurrentThreadTraceId();
 #endif  // PRODUCT
-  static OSThread* GetOSThreadFromThread(Thread* thread);
+  static OSThread* GetOSThreadFromThread(ThreadState* thread);
   static void AddThreadToListLocked(OSThread* thread);
   static void RemoveThreadFromList(OSThread* thread);
   static OSThread* CreateAndSetUnknownThread();
@@ -260,7 +261,7 @@
   Log* log_;
   uword stack_base_;
   uword stack_limit_;
-  Thread* thread_;
+  ThreadState* thread_;
 
   // thread_list_lock_ cannot have a static lifetime because the order in which
   // destructors run is undefined. At the moment this lock cannot be deleted
@@ -272,7 +273,7 @@
   static bool creation_enabled_;
 
 #if defined(HAS_C11_THREAD_LOCAL)
-  static thread_local Thread* current_vm_thread_;
+  static thread_local ThreadState* current_vm_thread_;
 #endif
 
   friend class Isolate;  // to access set_thread(Thread*).
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index 8b8ce38..885009c 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -79,7 +79,7 @@
                                          : zone_information.StandardName;
   intptr_t utf8_len =
       WideCharToMultiByte(CP_UTF8, 0, wchar_name, -1, NULL, 0, NULL, NULL);
-  char* name = Thread::Current()->zone()->Alloc<char>(utf8_len + 1);
+  char* name = ThreadState::Current()->zone()->Alloc<char>(utf8_len + 1);
   WideCharToMultiByte(CP_UTF8, 0, wchar_name, -1, name, utf8_len, NULL, NULL);
   name[utf8_len] = '\0';
   return name;
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index 2eecb7b..ec0513f 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -4,6 +4,7 @@
 
 #include "vm/program_visitor.h"
 
+#include "vm/code_patcher.h"
 #include "vm/deopt_instructions.h"
 #include "vm/hash_map.h"
 #include "vm/object.h"
@@ -114,6 +115,66 @@
   }
 }
 
+void ProgramVisitor::BindStaticCalls() {
+#if !defined(TARGET_ARCH_DBC)
+  if (FLAG_precompiled_mode) {
+    return;
+  }
+
+  class BindJITStaticCallsVisitor : public FunctionVisitor {
+   public:
+    explicit BindJITStaticCallsVisitor(Zone* zone)
+        : code_(Code::Handle(zone)),
+          table_(Array::Handle(zone)),
+          kind_and_offset_(Smi::Handle(zone)),
+          target_(Object::Handle(zone)),
+          target_code_(Code::Handle(zone)) {}
+
+    void Visit(const Function& function) {
+      if (!function.HasCode()) {
+        return;
+      }
+      code_ = function.CurrentCode();
+      table_ = code_.static_calls_target_table();
+      StaticCallsTable static_calls(table_);
+      for (const auto& view : static_calls) {
+        kind_and_offset_ = view.Get<Code::kSCallTableKindAndOffset>();
+        Code::CallKind kind = Code::KindField::decode(kind_and_offset_.Value());
+        if (kind != Code::kCallViaCode) {
+          continue;
+        }
+        int32_t pc_offset = Code::OffsetField::decode(kind_and_offset_.Value());
+        target_ = view.Get<Code::kSCallTableFunctionTarget>();
+        if (target_.IsNull()) {
+          target_ = view.Get<Code::kSCallTableCodeTarget>();
+          ASSERT(!Code::Cast(target_).IsFunctionCode());
+          // Allocation stub or AllocateContext or AllocateArray or ...
+        } else {
+          const Function& target_func = Function::Cast(target_);
+          if (target_func.HasCode()) {
+            target_code_ = target_func.CurrentCode();
+          } else {
+            target_code_ = StubCode::CallStaticFunction().raw();
+          }
+          uword pc = pc_offset + code_.PayloadStart();
+          CodePatcher::PatchStaticCallAt(pc, code_, target_code_);
+        }
+      }
+    }
+
+   private:
+    Code& code_;
+    Array& table_;
+    Smi& kind_and_offset_;
+    Object& target_;
+    Code& target_code_;
+  };
+
+  BindJITStaticCallsVisitor visitor(Thread::Current()->zone());
+  ProgramVisitor::VisitFunctions(&visitor);
+#endif  // !defined(TARGET_ARCH_DBC)
+}
+
 void ProgramVisitor::ShareMegamorphicBuckets() {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
@@ -821,8 +882,7 @@
   StackZone stack_zone(thread);
   HANDLESCOPE(thread);
 
-  // TODO(rmacnak): Bind static calls whose target has been compiled. Forward
-  // references to disabled code.
+  BindStaticCalls();
   ShareMegamorphicBuckets();
   DedupStackMaps();
   DedupPcDescriptors();
diff --git a/runtime/vm/program_visitor.h b/runtime/vm/program_visitor.h
index c24abe5..5583cc3 100644
--- a/runtime/vm/program_visitor.h
+++ b/runtime/vm/program_visitor.h
@@ -30,6 +30,7 @@
   static void Dedup();
 
  private:
+  static void BindStaticCalls();
   static void ShareMegamorphicBuckets();
   static void DedupStackMaps();
   static void DedupPcDescriptors();
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3fcb8cf..dcde53e 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -10,6 +10,7 @@
 #include "vm/compiler/method_recognizer.h"
 #include "vm/exceptions.h"
 #include "vm/globals.h"
+#include "vm/object_graph.h"
 #include "vm/snapshot.h"
 #include "vm/token.h"
 #include "vm/token_position.h"
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 2ae6c18..c6cee03 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -2174,11 +2174,13 @@
   CodePatcher::PatchStaticCallAt(frame->pc(), caller_code, current_target_code);
   caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code);
   if (FLAG_trace_patching) {
-    OS::PrintErr("FixCallersTarget: caller %#" Px
-                 " "
-                 "target '%s' -> %#" Px "\n",
-                 frame->pc(), target_function.ToFullyQualifiedCString(),
-                 current_target_code.EntryPoint());
+    OS::PrintErr(
+        "FixCallersTarget: caller %#" Px
+        " "
+        "target '%s' -> %#" Px " (%s)\n",
+        frame->pc(), target_function.ToFullyQualifiedCString(),
+        current_target_code.EntryPoint(),
+        current_target_code.is_optimized() ? "optimized" : "unoptimized");
   }
   ASSERT(!current_target_code.IsDisabled());
   arguments.SetReturn(current_target_code);
diff --git a/runtime/vm/runtime_entry_arm.cc b/runtime/vm/runtime_entry_arm.cc
index 4b19f0d..3ff5758 100644
--- a/runtime/vm/runtime_entry_arm.cc
+++ b/runtime/vm/runtime_entry_arm.cc
@@ -50,6 +50,8 @@
     __ blx(TMP);
     __ LoadImmediate(TMP, VMTag::kDartCompiledTagId);
     __ str(TMP, Address(THR, Thread::vm_tag_offset()));
+    ASSERT((kAbiPreservedCpuRegs & (1 << THR)) != 0);
+    ASSERT((kAbiPreservedCpuRegs & (1 << PP)) != 0);
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
diff --git a/runtime/vm/runtime_entry_arm64.cc b/runtime/vm/runtime_entry_arm64.cc
index 250e05f..a17870c 100644
--- a/runtime/vm/runtime_entry_arm64.cc
+++ b/runtime/vm/runtime_entry_arm64.cc
@@ -67,6 +67,8 @@
     __ str(TMP, Address(THR, Thread::vm_tag_offset()));
     __ mov(SP, R25);
     __ mov(CSP, R23);
+    ASSERT((kAbiPreservedCpuRegs & (1 << THR)) != 0);
+    ASSERT((kAbiPreservedCpuRegs & (1 << PP)) != 0);
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
diff --git a/runtime/vm/runtime_entry_x64.cc b/runtime/vm/runtime_entry_x64.cc
index 0875c69..f84db6b 100644
--- a/runtime/vm/runtime_entry_x64.cc
+++ b/runtime/vm/runtime_entry_x64.cc
@@ -32,6 +32,8 @@
     __ movq(Assembler::VMTagAddress(), RAX);
     __ CallCFunction(RAX);
     __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
+    ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << THR)) != 0);
+    ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << PP)) != 0);
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 25fd47c..282f198 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -4110,6 +4110,7 @@
 };
 
 static RawObject* GetObjectHelper(Thread* thread, uword addr) {
+  HeapIterationScope iteration(thread);
   Object& object = Object::Handle(thread->zone());
 
   {
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 44351459b3c1..015ecfb 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -901,7 +901,7 @@
 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
+If the client is already subscribed to the stream, the _103_ (Stream already
 subscribed) error code is returned.
 
 The _streamId_ parameter may have the following published values:
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 5759658..e6ecc405f 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -12,6 +12,7 @@
 
 namespace dart {
 
+class Isolate;
 class ObjectPointerVisitor;
 class SendPort;
 
diff --git a/runtime/vm/simulator_dbc.h b/runtime/vm/simulator_dbc.h
index 03608d0..8b87a7a 100644
--- a/runtime/vm/simulator_dbc.h
+++ b/runtime/vm/simulator_dbc.h
@@ -14,18 +14,19 @@
 
 namespace dart {
 
-class Isolate;
-class RawObject;
-class SimulatorSetjmpBuffer;
-class Thread;
-class Code;
 class Array;
+class Code;
+class Isolate;
+class ObjectPointerVisitor;
+class RawArray;
+class RawCode;
+class RawFunction;
 class RawICData;
 class RawImmutableArray;
-class RawArray;
+class RawObject;
 class RawObjectPool;
-class RawFunction;
-class ObjectPointerVisitor;
+class SimulatorSetjmpBuffer;
+class Thread;
 
 // Simulator intrinsic handler. It is invoked on entry to the intrinsified
 // function via Intrinsic bytecode before the frame is setup.
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 9fea664..7ce25de 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -475,15 +475,7 @@
     cls = it.GetNextClass();
     if (!cls.is_finalized()) {
       if (compile_mode_ == kForceCompile) {
-        Error& err = Error::Handle();
-        if (cls.is_marked_for_lazy_loading()) {
-          const String& error_message = String::Handle(
-              String::New("Unable to process 'force compile' request, "
-                          "while the class is being finalized."));
-          err = ApiError::New(error_message);
-        } else {
-          err = cls.EnsureIsFinalized(thread());
-        }
+        Error& err = Error::Handle(cls.EnsureIsFinalized(thread()));
         if (!err.IsNull()) {
           // Emit an uncompiled range for this class with error information.
           JSONObject range(jsarr);
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 71a8559..6709e31 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -102,6 +102,12 @@
   __ LoadImmediate(R2, 0);
   __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
 
+  // Restore the global object pool after returning from runtime (old space is
+  // moving, so the GOP could have been relocated).
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    __ ldr(PP, Address(THR, Thread::global_object_pool_offset()));
+  }
+
   __ LeaveStubFrame();
 
   // The following return can jump to a lazy-deopt stub, which assumes R0
@@ -118,50 +124,25 @@
                                   const RuntimeEntry* target,
                                   intptr_t self_code_stub_offset_from_thread,
                                   bool allow_return) {
-  __ Push(LR);
-
   // We want the saved registers to appear like part of the caller's frame, so
   // we push them before calling EnterStubFrame.
   RegisterSet all_registers;
   all_registers.AddAllNonReservedRegisters(save_fpu_registers);
+
+  // To make the stack map calculation architecture independent we do the same
+  // as on intel.
+  __ Push(LR);
+
   __ PushRegisters(all_registers);
-
-  const intptr_t kSavedCpuRegisterSlots =
-      Utils::CountOneBitsWord(kDartAvailableCpuRegs);
-
-  const intptr_t kSavedFpuRegisterSlots =
-      save_fpu_registers ? kNumberOfFpuRegisters * kFpuRegisterSize / kWordSize
-                         : 0;
-
-  const intptr_t kAllSavedRegistersSlots =
-      kSavedCpuRegisterSlots + kSavedFpuRegisterSlots;
-
-  // Copy down the return address so the stack layout is correct.
-  __ ldr(TMP, Address(SPREG, kAllSavedRegistersSlots * kWordSize));
-  __ Push(TMP);
-
   __ ldr(CODE_REG, Address(THR, self_code_stub_offset_from_thread));
-
   __ EnterStubFrame();
-
-  __ ldr(CODE_REG, Address(THR, Thread::call_to_runtime_stub_offset()));
-  __ ldr(R9, Address(THR, Thread::OffsetFromThread(target)));
-  __ mov(R4, Operand(/*argument_count=*/0));
-  __ ldr(TMP, Address(THR, Thread::call_to_runtime_entry_point_offset()));
-  __ blx(TMP);
-
+  __ CallRuntime(*target, /*argument_count=*/0);
   if (!allow_return) {
     __ Breakpoint();
     return;
   }
   __ LeaveStubFrame();
-
-  // Drop "official" return address -- we can just use the one stored above the
-  // saved registers.
-  __ Drop(1);
-
   __ PopRegisters(all_registers);
-
   __ Pop(LR);
   __ bx(LR);
 }
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 91996d9..182a355f 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -125,6 +125,13 @@
   // Reset exit frame information in Isolate structure.
   __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
 
+  // Restore the global object pool after returning from runtime (old space is
+  // moving, so the GOP could have been relocated).
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    __ ldr(PP, Address(THR, Thread::global_object_pool_offset()));
+    __ sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
+  }
+
   __ LeaveStubFrame();
 
   // The following return can jump to a lazy-deopt stub, which assumes R0
@@ -141,50 +148,24 @@
                                   const RuntimeEntry* target,
                                   intptr_t self_code_stub_offset_from_thread,
                                   bool allow_return) {
-  __ Push(LR);
-
   // We want the saved registers to appear like part of the caller's frame, so
   // we push them before calling EnterStubFrame.
   RegisterSet all_registers;
   all_registers.AddAllNonReservedRegisters(save_fpu_registers);
+
+  // To make the stack map calculation architecture independent we do the same
+  // as on intel.
+  __ Push(LR);
   __ PushRegisters(all_registers);
-
-  const intptr_t kSavedCpuRegisterSlots =
-      Utils::CountOneBitsWord(kDartAvailableCpuRegs);
-
-  const intptr_t kSavedFpuRegisterSlots =
-      save_fpu_registers ? kNumberOfFpuRegisters * kFpuRegisterSize / kWordSize
-                         : 0;
-
-  const intptr_t kAllSavedRegistersSlots =
-      kSavedCpuRegisterSlots + kSavedFpuRegisterSlots;
-
-  // Copy down the return address so the stack layout is correct.
-  __ ldr(TMP, Address(SPREG, kAllSavedRegistersSlots * kWordSize));
-  __ Push(TMP);
-
   __ ldr(CODE_REG, Address(THR, self_code_stub_offset_from_thread));
-
   __ EnterStubFrame();
-
-  __ ldr(CODE_REG, Address(THR, Thread::call_to_runtime_stub_offset()));
-  __ ldr(R5, Address(THR, Thread::OffsetFromThread(target)));
-  __ LoadImmediate(R4, /*argument_count=*/0);
-  __ ldr(TMP, Address(THR, Thread::call_to_runtime_entry_point_offset()));
-  __ blr(TMP);
-
+  __ CallRuntime(*target, /*argument_count=*/0);
   if (!allow_return) {
     __ Breakpoint();
     return;
   }
   __ LeaveStubFrame();
-
-  // Drop "official" return address -- we can just use the one stored above the
-  // saved registers.
-  __ Drop(1);
-
   __ PopRegisters(all_registers);
-
   __ Pop(LR);
   __ ret(LR);
 }
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 7184e25..bcc2198 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -99,6 +99,12 @@
   // Reset exit frame information in Isolate structure.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
 
+  // Restore the global object pool after returning from runtime (old space is
+  // moving, so the GOP could have been relocated).
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    __ movq(PP, Address(THR, Thread::global_object_pool_offset()));
+  }
+
   __ LeaveStubFrame();
 
   // The following return can jump to a lazy-deopt stub, which assumes RAX
@@ -136,12 +142,7 @@
   __ movq(CODE_REG, Address(THR, self_code_stub_offset_from_thread));
 
   __ EnterStubFrame();
-
-  __ movq(CODE_REG, Address(THR, Thread::call_to_runtime_stub_offset()));
-  __ movq(RBX, Address(THR, Thread::OffsetFromThread(target)));
-  __ movq(R10, Immediate(/*argument_count=*/0));
-  __ call(Address(THR, Thread::call_to_runtime_entry_point_offset()));
-
+  __ CallRuntime(*target, /*argument_count=*/0);
   if (!allow_return) {
     __ Breakpoint();
     return;
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index fad8fe7..b20b42e 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -77,7 +77,7 @@
 };
 
 VMTagScope::VMTagScope(Thread* thread, uword tag, bool conditional_set)
-    : StackResource(thread) {
+    : ThreadStackResource(thread) {
   ASSERT(isolate() != NULL);
   previous_tag_ = thread->vm_tag();
   if (conditional_set) {
diff --git a/runtime/vm/tags.h b/runtime/vm/tags.h
index 7bd6aa9..4f3b665 100644
--- a/runtime/vm/tags.h
+++ b/runtime/vm/tags.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_TAGS_H_
 
 #include "vm/allocation.h"
+#include "vm/thread_stack_resource.h"
 
 namespace dart {
 
@@ -75,7 +76,7 @@
   static TagEntry entries_[];
 };
 
-class VMTagScope : StackResource {
+class VMTagScope : ThreadStackResource {
  public:
   VMTagScope(Thread* thread, uword tag, bool conditional_set = true);
   ~VMTagScope();
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 109ccd4..8756113 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -58,7 +58,7 @@
 #define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(NULL),
 
 Thread::Thread(Isolate* isolate)
-    : BaseThread(false),
+    : ThreadState(false),
       stack_limit_(0),
       stack_overflow_flags_(0),
       write_barrier_mask_(RawObject::kGenerationalBarrierMask),
@@ -77,15 +77,9 @@
       resume_pc_(0),
       task_kind_(kUnknownTask),
       dart_stream_(NULL),
-      os_thread_(NULL),
       thread_lock_(new Monitor()),
-      zone_(NULL),
-      current_zone_capacity_(0),
-      zone_high_watermark_(0),
       api_reusable_scope_(NULL),
       api_top_scope_(NULL),
-      top_resource_(NULL),
-      long_jump_base_(NULL),
       no_callback_scope_depth_(0),
 #if defined(DEBUG)
       top_handle_scope_(NULL),
@@ -141,20 +135,6 @@
   if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) {
     InitVMConstants();
   }
-
-  // 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_zone_capacity_ == 0);
-  } else {
-    Zone* current = zone_;
-    uintptr_t total_zone_capacity = 0;
-    while (current != NULL) {
-      total_zone_capacity += current->CapacityInBytes();
-      current = current->previous();
-    }
-    ASSERT(current_zone_capacity_ == total_zone_capacity);
-  }
 }
 
 static const double double_nan_constant = NAN;
@@ -245,8 +225,8 @@
   jsobj.AddPropertyF("id", "threads/%" Pd "",
                      OSThread::ThreadIdToIntPtr(os_thread()->trace_id()));
   jsobj.AddProperty("kind", TaskKindToCString(task_kind()));
-  jsobj.AddPropertyF("_zoneHighWatermark", "%" Pu "", zone_high_watermark_);
-  jsobj.AddPropertyF("_zoneCapacity", "%" Pu "", current_zone_capacity_);
+  jsobj.AddPropertyF("_zoneHighWatermark", "%" Pu "", zone_high_watermark());
+  jsobj.AddPropertyF("_zoneCapacity", "%" Pu "", current_zone_capacity());
 }
 #endif
 
@@ -471,18 +451,6 @@
   return interrupt_bits;
 }
 
-bool Thread::ZoneIsOwnedByThread(Zone* zone) const {
-  ASSERT(zone != NULL);
-  Zone* current = zone_;
-  while (current != NULL) {
-    if (current == zone) {
-      return true;
-    }
-    current = current->previous();
-  }
-  return false;
-}
-
 void Thread::DeferOOBMessageInterrupts() {
   MonitorLocker ml(thread_lock_);
   defer_oob_messages_count_++;
@@ -687,8 +655,8 @@
                                  ValidationPolicy validation_policy) {
   ASSERT(visitor != NULL);
 
-  if (zone_ != NULL) {
-    zone_->VisitObjectPointers(visitor);
+  if (zone() != NULL) {
+    zone()->VisitObjectPointers(visitor);
   }
 
   // Visit objects in thread specific handles area.
@@ -832,7 +800,7 @@
 
 #if defined(DEBUG)
 bool Thread::TopErrorHandlerIsSetJump() const {
-  if (long_jump_base_ == nullptr) return false;
+  if (long_jump_base() == nullptr) return false;
   if (top_exit_frame_info_ == 0) return true;
 #if defined(USING_SIMULATOR) || defined(USING_SAFE_STACK)
   // False positives: simulator stack and native stack are unordered.
@@ -843,13 +811,13 @@
   if ((interpreter_ != nullptr) && interpreter_->HasFrame(top_exit_frame_info_))
     return true;
 #endif
-  return reinterpret_cast<uword>(long_jump_base_) < top_exit_frame_info_;
+  return reinterpret_cast<uword>(long_jump_base()) < top_exit_frame_info_;
 #endif
 }
 
 bool Thread::TopErrorHandlerIsExitFrame() const {
   if (top_exit_frame_info_ == 0) return false;
-  if (long_jump_base_ == nullptr) return true;
+  if (long_jump_base() == nullptr) return true;
 #if defined(USING_SIMULATOR) || defined(USING_SAFE_STACK)
   // False positives: simulator stack and native stack are unordered.
   return true;
@@ -859,7 +827,7 @@
   if ((interpreter_ != nullptr) && interpreter_->HasFrame(top_exit_frame_info_))
     return true;
 #endif
-  return top_exit_frame_info_ < reinterpret_cast<uword>(long_jump_base_);
+  return top_exit_frame_info_ < reinterpret_cast<uword>(long_jump_base());
 #endif
 }
 #endif  // defined(DEBUG)
@@ -891,7 +859,7 @@
 }
 
 bool Thread::IsValidZoneHandle(Dart_Handle object) const {
-  Zone* zone = zone_;
+  Zone* zone = this->zone();
   while (zone != NULL) {
     if (zone->handles()->IsValidZoneHandle(reinterpret_cast<uword>(object))) {
       return true;
@@ -903,7 +871,7 @@
 
 intptr_t Thread::CountZoneHandles() const {
   intptr_t count = 0;
-  Zone* zone = zone_;
+  Zone* zone = this->zone();
   while (zone != NULL) {
     count += zone->handles()->CountZoneHandles();
     zone = zone->previous();
@@ -913,7 +881,7 @@
 }
 
 bool Thread::IsValidScopedHandle(Dart_Handle object) const {
-  Zone* zone = zone_;
+  Zone* zone = this->zone();
   while (zone != NULL) {
     if (zone->handles()->IsValidScopedHandle(reinterpret_cast<uword>(object))) {
       return true;
@@ -925,7 +893,7 @@
 
 intptr_t Thread::CountScopedHandles() const {
   intptr_t count = 0;
-  Zone* zone = zone_;
+  Zone* zone = this->zone();
   while (zone != NULL) {
     count += zone->handles()->CountScopedHandles();
     zone = zone->previous();
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 9cd5fb5..0df7b36 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -16,6 +16,7 @@
 #include "vm/heap/pointer_block.h"
 #include "vm/os_thread.h"
 #include "vm/runtime_entry_list.h"
+#include "vm/thread_state.h"
 
 namespace dart {
 
@@ -38,7 +39,6 @@
 class Interpreter;
 class Isolate;
 class Library;
-class LongJumpScope;
 class Object;
 class OSThread;
 class JSONObject;
@@ -201,7 +201,7 @@
 // a thread is allocated by EnsureInit before entering an isolate, and destroyed
 // automatically when the underlying OS thread exits. NOTE: On Windows, CleanUp
 // must currently be called manually (issue 23474).
-class Thread : public BaseThread {
+class Thread : public ThreadState {
  public:
   // The kind of task this thread is performing. Sampled by the profiler.
   enum TaskKind {
@@ -220,13 +220,13 @@
   // The currently executing thread, or NULL if not yet initialized.
   static Thread* Current() {
 #if defined(HAS_C11_THREAD_LOCAL)
-    return OSThread::CurrentVMThread();
+    return static_cast<Thread*>(OSThread::CurrentVMThread());
 #else
     BaseThread* thread = OSThread::GetCurrentTLS();
     if (thread == NULL || thread->is_os_thread()) {
       return NULL;
     }
-    return reinterpret_cast<Thread*>(thread);
+    return static_cast<Thread*>(thread);
 #endif
   }
 
@@ -317,36 +317,9 @@
     return (stack_limit_ & kInterruptsMask) != 0;
   }
 
-  // OSThread corresponding to this thread.
-  OSThread* os_thread() const { return os_thread_; }
-  void set_os_thread(OSThread* os_thread) { os_thread_ = os_thread; }
-
   // Monitor corresponding to this thread.
   Monitor* thread_lock() const { return thread_lock_; }
 
-  // The topmost zone used for allocation in this thread.
-  Zone* zone() const { return zone_; }
-
-  bool ZoneIsOwnedByThread(Zone* zone) const;
-
-  void IncrementMemoryCapacity(uintptr_t value) {
-    current_zone_capacity_ += value;
-    if (current_zone_capacity_ > zone_high_watermark_) {
-      zone_high_watermark_ = current_zone_capacity_;
-    }
-  }
-
-  void DecrementMemoryCapacity(uintptr_t value) {
-    ASSERT(current_zone_capacity_ >= value);
-    current_zone_capacity_ -= value;
-  }
-
-  uintptr_t current_zone_capacity() { return current_zone_capacity_; }
-
-  uintptr_t zone_high_watermark() const { return zone_high_watermark_; }
-
-  void ResetHighWatermark() { zone_high_watermark_ = current_zone_capacity_; }
-
   // The reusable api local scope for this thread.
   ApiLocalScope* api_reusable_scope() const { return api_reusable_scope_; }
   void set_api_reusable_scope(ApiLocalScope* value) {
@@ -454,28 +427,22 @@
     return OFFSET_OF(Thread, top_exit_frame_info_);
   }
 
-  StackResource* top_resource() const { return top_resource_; }
-  void set_top_resource(StackResource* value) { top_resource_ = value; }
-  static intptr_t top_resource_offset() {
-    return OFFSET_OF(Thread, top_resource_);
-  }
-
   // Heap of the isolate that this thread is operating on.
   Heap* heap() const { return heap_; }
   static intptr_t heap_offset() { return OFFSET_OF(Thread, heap_); }
 
   void set_top(uword value) {
-    ASSERT(heap_ != NULL);
     top_ = value;
   }
   void set_end(uword value) {
-    ASSERT(heap_ != NULL);
     end_ = value;
   }
 
   uword top() { return top_; }
   uword end() { return end_; }
 
+  bool HasActiveTLAB() { return end_ > 0; }
+
   static intptr_t top_offset() { return OFFSET_OF(Thread, top_); }
   static intptr_t end_offset() { return OFFSET_OF(Thread, end_); }
 
@@ -564,9 +531,6 @@
   static bool ObjectAtOffset(intptr_t offset, Object* object);
   static intptr_t OffsetFromThread(const RuntimeEntry* runtime_entry);
 
-  LongJumpScope* long_jump_base() const { return long_jump_base_; }
-  void set_long_jump_base(LongJumpScope* value) { long_jump_base_ = value; }
-
 #if defined(DEBUG)
   // For asserts only. Has false positives when running with a simulator or
   // SafeStack.
@@ -869,15 +833,9 @@
 
   TaskKind task_kind_;
   TimelineStream* dart_stream_;
-  OSThread* os_thread_;
   Monitor* thread_lock_;
-  Zone* zone_;
-  uintptr_t current_zone_capacity_;
-  uintptr_t zone_high_watermark_;
   ApiLocalScope* api_reusable_scope_;
   ApiLocalScope* api_top_scope_;
-  StackResource* top_resource_;
-  LongJumpScope* long_jump_base_;
   int32_t no_callback_scope_depth_;
 #if defined(DEBUG)
   HandleScope* top_handle_scope_;
@@ -939,8 +897,6 @@
   void DeferredMarkingStackRelease();
   void DeferredMarkingStackAcquire();
 
-  void set_zone(Zone* zone) { zone_ = zone; }
-
   void set_safepoint_state(uint32_t value) { safepoint_state_ = value; }
   void EnterSafepointUsingLock();
   void ExitSafepointUsingLock();
@@ -981,6 +937,30 @@
   ~DisableThreadInterruptsScope();
 };
 
+// Within a NoSafepointScope, the thread must not reach any safepoint. Used
+// around code that manipulates raw object pointers directly without handles.
+#if defined(DEBUG)
+class NoSafepointScope : public ThreadStackResource {
+ public:
+  explicit NoSafepointScope(Thread* thread = nullptr)
+      : ThreadStackResource(thread != nullptr ? thread : Thread::Current()) {
+    this->thread()->IncrementNoSafepointScopeDepth();
+  }
+  ~NoSafepointScope() { thread()->DecrementNoSafepointScopeDepth(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoSafepointScope);
+};
+#else   // defined(DEBUG)
+class NoSafepointScope : public ValueObject {
+ public:
+  explicit NoSafepointScope(Thread* thread = nullptr) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoSafepointScope);
+};
+#endif  // defined(DEBUG)
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_THREAD_H_
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 1de2c0c..d8d56b1 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -36,16 +36,6 @@
 // The ThreadInterrupter has a single monitor (monitor_). This monitor is used
 // to synchronize startup, shutdown, and waking up from a deep sleep.
 //
-// A thread can only register and unregister itself. Each thread has a heap
-// allocated ThreadState. A thread's ThreadState is lazily allocated the first
-// time the thread is registered. A pointer to a thread's ThreadState is stored
-// in the list of threads registered to receive interrupts (threads_) and in
-// thread local storage. When a thread's ThreadState is being modified, the
-// thread local storage pointer is temporarily set to NULL while the
-// modification is occurring. After the ThreadState has been updated, the
-// thread local storage pointer is set again. This has an important side
-// effect: if the thread is interrupted by a signal handler during a ThreadState
-// update the signal handler will immediately return.
 
 DEFINE_FLAG(bool, trace_thread_interrupter, false, "Trace thread interrupter");
 
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index 13c6f8d..c862a22 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -81,7 +81,7 @@
     // Currently we sample only threads that are associated
     // with an isolate. It is safe to call 'os_thread->thread()'
     // here as the thread which is being queried is suspended.
-    Thread* thread = os_thread->thread();
+    Thread* thread = static_cast<Thread*>(os_thread->thread());
     if (thread != NULL) {
       Profiler::SampleThread(thread, its);
     }
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
index a390528..2052d4a 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -192,7 +192,7 @@
 
 void ThreadRegistry::ReturnToFreelistLocked(Thread* thread) {
   ASSERT(thread != NULL);
-  ASSERT(thread->os_thread_ == NULL);
+  ASSERT(thread->os_thread() == NULL);
   ASSERT(thread->isolate_ == NULL);
   ASSERT(thread->heap_ == NULL);
   ASSERT(threads_lock()->IsOwnedByCurrentThread());
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index 2d6ad35..fda9474 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -83,6 +83,7 @@
 
   friend class Isolate;
   friend class SafepointHandler;
+  friend class Scavenger;
   DISALLOW_COPY_AND_ASSIGN(ThreadRegistry);
 };
 
diff --git a/runtime/vm/thread_stack_resource.cc b/runtime/vm/thread_stack_resource.cc
new file mode 100644
index 0000000..69faf94
--- /dev/null
+++ b/runtime/vm/thread_stack_resource.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/thread_stack_resource.h"
+
+#include "platform/assert.h"
+#include "vm/isolate.h"
+#include "vm/thread.h"
+#include "vm/zone.h"
+
+namespace dart {
+
+ThreadStackResource::~ThreadStackResource() {
+#if defined(DEBUG)
+  if (thread() != nullptr) {
+    BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
+  }
+#endif
+}
+
+Isolate* ThreadStackResource::isolate() const {
+  return thread()->isolate();
+}
+
+}  // namespace dart
diff --git a/runtime/vm/thread_stack_resource.h b/runtime/vm/thread_stack_resource.h
new file mode 100644
index 0000000..abbf521
--- /dev/null
+++ b/runtime/vm/thread_stack_resource.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_THREAD_STACK_RESOURCE_H_
+#define RUNTIME_VM_THREAD_STACK_RESOURCE_H_
+
+#include "vm/allocation.h"
+#include "vm/globals.h"
+
+namespace dart {
+
+class Isolate;
+class ThreadState;
+class Thread;
+
+class ThreadStackResource : public StackResource {
+ public:
+  explicit ThreadStackResource(Thread* T)
+      : StackResource(reinterpret_cast<ThreadState*>(T)) {}
+
+  ~ThreadStackResource();
+
+  Thread* thread() const {
+    return reinterpret_cast<Thread*>(StackResource::thread());
+  }
+  Isolate* isolate() const;
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_THREAD_STACK_RESOURCE_H_
diff --git a/runtime/vm/thread_state.cc b/runtime/vm/thread_state.cc
new file mode 100644
index 0000000..d5e37e3
--- /dev/null
+++ b/runtime/vm/thread_state.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/thread_state.h"
+
+#include "vm/zone.h"
+
+namespace dart {
+
+ThreadState::ThreadState(bool is_os_thread) : BaseThread(is_os_thread) {
+  // 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_ == nullptr) {
+    ASSERT(current_zone_capacity_ == 0);
+  } else {
+    Zone* current = zone_;
+    uintptr_t total_zone_capacity = 0;
+    while (current != nullptr) {
+      total_zone_capacity += current->CapacityInBytes();
+      current = current->previous();
+    }
+    ASSERT(current_zone_capacity_ == total_zone_capacity);
+  }
+}
+
+ThreadState::~ThreadState() {}
+
+bool ThreadState::ZoneIsOwnedByThread(Zone* zone) const {
+  ASSERT(zone != nullptr);
+  Zone* current = zone_;
+  while (current != nullptr) {
+    if (current == zone) {
+      return true;
+    }
+    current = current->previous();
+  }
+  return false;
+}
+
+}  // namespace dart
diff --git a/runtime/vm/thread_state.h b/runtime/vm/thread_state.h
new file mode 100644
index 0000000..85106d2
--- /dev/null
+++ b/runtime/vm/thread_state.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_THREAD_STATE_H_
+#define RUNTIME_VM_THREAD_STATE_H_
+
+#include "vm/os_thread.h"
+
+namespace dart {
+
+class LongJumpScope;
+class Zone;
+
+// ThreadState is a container for auxiliary thread-local state: e.g. it
+// owns a stack of Zones for allocation and a stack of StackResources
+// for stack unwinding.
+//
+// Important: this class is shared between compiler and runtime and
+// as such it should not expose any runtime internals due to layering
+// restrictions.
+class ThreadState : public BaseThread {
+ public:
+  // The currently executing thread, or NULL if not yet initialized.
+  static ThreadState* Current() {
+#if defined(HAS_C11_THREAD_LOCAL)
+    return OSThread::CurrentVMThread();
+#else
+    BaseThread* thread = OSThread::GetCurrentTLS();
+    if (thread == NULL || thread->is_os_thread()) {
+      return NULL;
+    }
+    return static_cast<ThreadState*>(thread);
+#endif
+  }
+
+  explicit ThreadState(bool is_os_thread);
+  ~ThreadState();
+
+  // OSThread corresponding to this thread.
+  OSThread* os_thread() const { return os_thread_; }
+  void set_os_thread(OSThread* os_thread) { os_thread_ = os_thread; }
+
+  // The topmost zone used for allocation in this thread.
+  Zone* zone() const { return zone_; }
+
+  bool ZoneIsOwnedByThread(Zone* zone) const;
+
+  void IncrementMemoryCapacity(uintptr_t value) {
+    current_zone_capacity_ += value;
+    if (current_zone_capacity_ > zone_high_watermark_) {
+      zone_high_watermark_ = current_zone_capacity_;
+    }
+  }
+
+  void DecrementMemoryCapacity(uintptr_t value) {
+    ASSERT(current_zone_capacity_ >= value);
+    current_zone_capacity_ -= value;
+  }
+
+  uintptr_t current_zone_capacity() const { return current_zone_capacity_; }
+  uintptr_t zone_high_watermark() const { return zone_high_watermark_; }
+
+  void ResetHighWatermark() { zone_high_watermark_ = current_zone_capacity_; }
+
+  StackResource* top_resource() const { return top_resource_; }
+  void set_top_resource(StackResource* value) { top_resource_ = value; }
+  static intptr_t top_resource_offset() {
+    return OFFSET_OF(ThreadState, top_resource_);
+  }
+
+  LongJumpScope* long_jump_base() const { return long_jump_base_; }
+  void set_long_jump_base(LongJumpScope* value) { long_jump_base_ = value; }
+
+ private:
+  void set_zone(Zone* zone) { zone_ = zone; }
+
+  OSThread* os_thread_ = nullptr;
+  Zone* zone_ = nullptr;
+  uintptr_t current_zone_capacity_ = 0;
+  uintptr_t zone_high_watermark_ = 0;
+  StackResource* top_resource_ = nullptr;
+  LongJumpScope* long_jump_base_ = nullptr;
+
+  friend class ApiZone;
+  friend class StackZone;
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_THREAD_STATE_H_
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index c38fd76..bca4938 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -748,7 +748,7 @@
 }
 
 TypeUsageInfo::TypeUsageInfo(Thread* thread)
-    : StackResource(thread),
+    : ThreadStackResource(thread),
       zone_(thread->zone()),
       finder_(zone_),
       assert_assignable_types_(),
diff --git a/runtime/vm/type_testing_stubs.h b/runtime/vm/type_testing_stubs.h
index 423b4d7..e8c7044 100644
--- a/runtime/vm/type_testing_stubs.h
+++ b/runtime/vm/type_testing_stubs.h
@@ -317,7 +317,7 @@
 };
 
 // Collects data on how [Type] objects are used in generated code.
-class TypeUsageInfo : public StackResource {
+class TypeUsageInfo : public ThreadStackResource {
  public:
   explicit TypeUsageInfo(Thread* thread);
   ~TypeUsageInfo();
diff --git a/runtime/vm/uri.cc b/runtime/vm/uri.cc
index 67fbcbf..5e75ef1 100644
--- a/runtime/vm/uri.cc
+++ b/runtime/vm/uri.cc
@@ -80,7 +80,7 @@
 
 static char* NormalizeEscapes(const char* str, intptr_t len) {
   // Allocate the buffer.
-  Zone* zone = Thread::Current()->zone();
+  Zone* zone = ThreadState::Current()->zone();
   // We multiply len by three because a percent-escape sequence is
   // three characters long (e.g. ' ' -> '%20).  +1 for '\0'.  We could
   // take two passes through the string and avoid the excess
@@ -156,7 +156,7 @@
 }
 
 static intptr_t ParseAuthority(const char* authority, ParsedUri* parsed_uri) {
-  Zone* zone = Thread::Current()->zone();
+  Zone* zone = ThreadState::Current()->zone();
   const char* current = authority;
   intptr_t len = 0;
 
@@ -191,7 +191,7 @@
 // Performs a simple parse of a uri into its components.
 // See RFC 3986 Section 3: Syntax.
 bool ParseUri(const char* uri, ParsedUri* parsed_uri) {
-  Zone* zone = Thread::Current()->zone();
+  Zone* zone = ThreadState::Current()->zone();
 
   // The first ':' separates the scheme from the rest of the uri.  If
   // a ':' occurs after the first '/' it doesn't count.
@@ -284,7 +284,7 @@
 
   // The output path will always be less than or equal to the size of
   // the input path.
-  Zone* zone = Thread::Current()->zone();
+  Zone* zone = ThreadState::Current()->zone();
   char* buffer = zone->Alloc<char>(strlen(path) + 1);  // +1 for '\0'
   char* output = buffer;
 
@@ -342,7 +342,7 @@
 
 // See RFC 3986 Section 5.2.3: Merge Paths.
 static const char* MergePaths(const char* base_path, const char* ref_path) {
-  Zone* zone = Thread::Current()->zone();
+  Zone* zone = ThreadState::Current()->zone();
   if (base_path[0] == '\0') {
     // If the base_path is empty, we prepend '/'.
     return zone->PrintToString("/%s", ref_path);
@@ -378,7 +378,7 @@
 }
 
 static char* BuildUri(const ParsedUri& uri) {
-  Zone* zone = Thread::Current()->zone();
+  Zone* zone = ThreadState::Current()->zone();
   ASSERT(uri.path != NULL);
 
   const char* fragment = uri.fragment == NULL ? "" : uri.fragment;
@@ -436,7 +436,7 @@
   ParsedUri target;
   if (ref.scheme != NULL) {
     if (strcmp(ref.scheme, "dart") == 0) {
-      Zone* zone = Thread::Current()->zone();
+      Zone* zone = ThreadState::Current()->zone();
       *target_uri = zone->MakeCopyOfString(ref_uri);
       return true;
     }
@@ -461,7 +461,7 @@
   }
 
   if ((base.scheme != NULL) && strcmp(base.scheme, "dart") == 0) {
-    Zone* zone = Thread::Current()->zone();
+    Zone* zone = ThreadState::Current()->zone();
     *target_uri = zone->MakeCopyOfString(ref_uri);
     return true;
   }
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index 593b76d..82b9645 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -312,6 +312,10 @@
   "thread_pool.h",
   "thread_registry.cc",
   "thread_registry.h",
+  "thread_stack_resource.cc",
+  "thread_stack_resource.h",
+  "thread_state.cc",
+  "thread_state.h",
   "timeline.cc",
   "timeline.h",
   "timeline_analysis.cc",
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index 313e452..8227e48 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -75,7 +75,7 @@
 }
 
 void Zone::Segment::IncrementMemoryCapacity(uintptr_t size) {
-  Thread* current_thread = Thread::Current();
+  ThreadState* current_thread = ThreadState::Current();
   if (current_thread != NULL) {
     current_thread->IncrementMemoryCapacity(size);
   } else if (ApiNativeScope::Current() != NULL) {
@@ -85,7 +85,7 @@
 }
 
 void Zone::Segment::DecrementMemoryCapacity(uintptr_t size) {
-  Thread* current_thread = Thread::Current();
+  ThreadState* current_thread = ThreadState::Current();
   if (current_thread != NULL) {
     current_thread->DecrementMemoryCapacity(size);
   } else if (ApiNativeScope::Current() != NULL) {
@@ -288,7 +288,7 @@
   return OS::VSCreate(this, format, args);
 }
 
-StackZone::StackZone(Thread* thread) : StackResource(thread), zone_() {
+StackZone::StackZone(ThreadState* thread) : StackResource(thread), zone_() {
   if (FLAG_trace_zones) {
     OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
                  reinterpret_cast<intptr_t>(this),
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index b892cdc..b4aba7f 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -8,9 +8,8 @@
 #include "platform/utils.h"
 #include "vm/allocation.h"
 #include "vm/handles.h"
-#include "vm/json_stream.h"
 #include "vm/memory_region.h"
-#include "vm/thread.h"
+#include "vm/thread_state.h"
 
 namespace dart {
 
@@ -175,7 +174,7 @@
 class StackZone : public StackResource {
  public:
   // Create an empty zone and set is at the current zone for the Thread.
-  explicit StackZone(Thread* thread);
+  explicit StackZone(ThreadState* thread);
 
   // Delete all memory associated with the zone.
   ~StackZone();
diff --git a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
index 7138c65..fc7a3bf 100644
--- a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
@@ -21,6 +21,8 @@
 
 const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
 
+const int _mask30 = 0x3fffffff; // Low 30 bits.
+
 @patch
 class HashMap<K, V> {
   @patch
@@ -306,14 +308,14 @@
     // Only treat unsigned 30-bit integers as numeric keys. This way,
     // we avoid converting them to strings when we use them as keys in
     // the JavaScript hash table object.
-    return key is num && JS('bool', '(# & 0x3ffffff) === #', key, key);
+    return key is num && JS('bool', '(# & #) === #', key, _mask30, key);
   }
 
   int _computeHashCode(var key) {
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', key.hashCode);
+    return JS('int', '# & #', key.hashCode, _mask30);
   }
 
   static bool _hasTableEntry(var table, var key) {
@@ -382,7 +384,7 @@
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', identityHashCode(key));
+    return JS('int', '# & #', identityHashCode(key), _mask30);
   }
 
   int _findBucketIndex(var bucket, var key) {
@@ -426,7 +428,7 @@
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', _hashCode(key));
+    return JS('int', '# & #', _hashCode(key), _mask30);
   }
 
   int _findBucketIndex(var bucket, var key) {
@@ -576,7 +578,7 @@
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', identityHashCode(key));
+    return JS('int', '# & #', identityHashCode(key), _mask30);
   }
 
   int internalFindBucketIndex(var bucket, var key) {
@@ -669,7 +671,7 @@
     // always unboxed (Smi) values. Modification detection will be missed if you
     // make exactly some multiple of 2^30 modifications between advances of an
     // iterator.
-    _modifications = (_modifications + 1) & 0x3ffffff;
+    _modifications = _mask30 & (_modifications + 1);
   }
 }
 
@@ -779,7 +781,7 @@
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', _hashCode(key));
+    return JS('int', '# & #', _hashCode(key), _mask30);
   }
 
   int internalFindBucketIndex(var bucket, var key) {
@@ -1050,7 +1052,7 @@
     // way, we avoid converting them to strings when we use them as
     // keys in the JavaScript hash table object.
     return element is num &&
-        JS('bool', '(# & 0x3ffffff) === #', element, element);
+        JS('bool', '(# & #) === #', element, _mask30, element);
   }
 
   int _computeHashCode(var element) {
@@ -1058,7 +1060,7 @@
     // issues with problematic elements like '__proto__'. Another
     // option would be to throw an exception if the hash code isn't a
     // number.
-    return JS('int', '# & 0x3ffffff', element.hashCode);
+    return JS('int', '# & #', element.hashCode, _mask30);
   }
 
   static bool _hasTableEntry(var table, var key) {
@@ -1114,7 +1116,7 @@
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', identityHashCode(key));
+    return JS('int', '# & #', identityHashCode(key), _mask30);
   }
 
   int _findBucketIndex(var bucket, var element) {
@@ -1151,7 +1153,7 @@
     // issues with problematic elements like '__proto__'. Another
     // option would be to throw an exception if the hash code isn't a
     // number.
-    return JS('int', '# & 0x3ffffff', _hasher(element));
+    return JS('int', '# & #', _hasher(element), _mask30);
   }
 
   bool add(E object) => super._add(object);
@@ -1451,7 +1453,7 @@
     // Value cycles after 2^30 modifications. If you keep hold of an
     // iterator for that long, you might miss a modification
     // detection, and iteration can go sour. Don't do that.
-    _modifications = (_modifications + 1) & 0x3ffffff;
+    _modifications = _mask30 & (_modifications + 1);
   }
 
   // Create a new cell and link it in as the last one in the list.
@@ -1498,7 +1500,7 @@
     // way, we avoid converting them to strings when we use them as
     // keys in the JavaScript hash table object.
     return element is num &&
-        JS('bool', '(# & 0x3ffffff) === #', element, element);
+        JS('bool', '(# & #) === #', element, _mask30, element);
   }
 
   int _computeHashCode(var element) {
@@ -1506,7 +1508,7 @@
     // issues with problematic elements like '__proto__'. Another
     // option would be to throw an exception if the hash code isn't a
     // number.
-    return JS('int', '# & 0x3ffffff', element.hashCode);
+    return JS('int', '# & #', element.hashCode, _mask30);
   }
 
   static _getTableEntry(var table, var key) {
@@ -1559,7 +1561,7 @@
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
-    return JS('int', '# & 0x3ffffff', identityHashCode(key));
+    return JS('int', '# & #', identityHashCode(key), _mask30);
   }
 
   int _findBucketIndex(var bucket, var element) {
@@ -1600,7 +1602,7 @@
     // issues with problematic elements like '__proto__'. Another
     // option would be to throw an exception if the hash code isn't a
     // number.
-    return JS('int', '# & 0x3ffffff', _hasher(element));
+    return JS('int', '# & #', _hasher(element), _mask30);
   }
 
   bool add(E element) => super._add(element);
@@ -1671,3 +1673,30 @@
     }
   }
 }
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+  @patch
+  Node _splayMin(Node node) {
+    Node current = node;
+    while (current.left != null) {
+      Node left = current.left;
+      current.left = left.right;
+      left.right = current;
+      current = left;
+    }
+    return current;
+  }
+
+  @patch
+  Node _splayMax(Node node) {
+    Node current = node;
+    while (current.right != null) {
+      Node right = current.right;
+      current.right = right.left;
+      right.left = current;
+      current = right;
+    }
+    return current;
+  }
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/convert_patch.dart b/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
index afb5062..a8dcc31 100644
--- a/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
@@ -11,22 +11,20 @@
 import 'dart:collection' show LinkedHashMap, MapBase;
 import 'dart:_native_typed_data' show NativeUint8List;
 
-/**
- * Parses [json] and builds the corresponding parsed JSON value.
- *
- * Parsed JSON values Nare of the types [num], [String], [bool], [Null],
- * [List]s of parsed JSON values or [Map]s from [String] to parsed
- * JSON values.
- *
- * The optional [reviver] function, if provided, is called once for each object
- * or list property parsed. The arguments are the property name ([String]) or
- * list index ([int]), and the value is the parsed value.  The return value of
- * the reviver will be used as the value of that property instead of the parsed
- * value.  The top level value is passed to the reviver with the empty string as
- * a key.
- *
- * Throws [FormatException] if the input is not valid JSON text.
- */
+/// Parses [json] and builds the corresponding parsed JSON value.
+///
+/// Parsed JSON values Nare of the types [num], [String], [bool], [Null],
+/// [List]s of parsed JSON values or [Map]s from [String] to parsed
+/// JSON values.
+///
+/// The optional [reviver] function, if provided, is called once for each object
+/// or list property parsed. The arguments are the property name ([String]) or
+/// list index ([int]), and the value is the parsed value.  The return value of
+/// the reviver will be used as the value of that property instead of the parsed
+/// value.  The top level value is passed to the reviver with the empty string
+/// as a key.
+///
+/// Throws [FormatException] if the input is not valid JSON text.
 @patch
 _parseJson(String source, reviver(key, value)) {
   if (source is! String) throw argumentErrorValue(source);
@@ -46,11 +44,9 @@
   }
 }
 
-/**
- * Walks the raw JavaScript value [json], replacing JavaScript Objects with
- * Maps. [json] is expected to be freshly allocated so elements can be replaced
- * in-place.
- */
+/// Walks the raw JavaScript value [json], replacing JavaScript Objects with
+/// Maps. [json] is expected to be freshly allocated so elements can be replaced
+/// in-place.
 _convertJsonToDart(json, reviver(key, value)) {
   assert(reviver != null);
   walk(e) {
@@ -365,12 +361,10 @@
   }
 }
 
-/**
- * Implements the chunked conversion from a JSON string to its corresponding
- * object.
- *
- * The sink only creates one object, but its input can be chunked.
- */
+/// Implements the chunked conversion from a JSON string to its corresponding
+/// object.
+///
+/// The sink only creates one object, but its input can be chunked.
 // TODO(floitsch): don't accumulate everything before starting to decode.
 class _JsonDecoderSink extends _StringSinkConversionSink {
   final _Reviver _reviver;
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index a5438a4..27d7d25 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -80,14 +80,6 @@
   @patch
   static apply(Function function, List positionalArguments,
       [Map<Symbol, dynamic> namedArguments]) {
-    // The lazy and startup emitter use a different implementation. To keep the
-    // method small and inlinable, just select the method.
-    return JS_GET_FLAG("IS_FULL_EMITTER")
-        ? _apply1(function, positionalArguments, namedArguments)
-        : _apply2(function, positionalArguments, namedArguments);
-  }
-
-  static _apply1(function, positionalArguments, namedArguments) {
     return Primitives.applyFunction(
         function,
         positionalArguments,
@@ -95,15 +87,6 @@
         // tree-shake _symbolMapToStringMap.
         namedArguments == null ? null : _symbolMapToStringMap(namedArguments));
   }
-
-  static _apply2(function, positionalArguments, namedArguments) {
-    return Primitives.applyFunction2(
-        function,
-        positionalArguments,
-        // Use this form so that if namedArguments is always null, we can
-        // tree-shake _symbolMapToStringMap.
-        namedArguments == null ? null : _symbolMapToStringMap(namedArguments));
-  }
 }
 
 // Patch for Expando implementation.
@@ -702,11 +685,9 @@
   // are not encoded by any encoding table.
   static final RegExp _needsNoEncoding = new RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
 
-  /**
-   * This is the internal implementation of JavaScript's encodeURI function.
-   * It encodes all characters in the string [text] except for those
-   * that appear in [canonicalTable], and returns the escaped string.
-   */
+  /// This is the internal implementation of JavaScript's encodeURI function.
+  /// It encodes all characters in the string [text] except for those
+  /// that appear in [canonicalTable], and returns the escaped string.
   @patch
   static String _uriEncode(List<int> canonicalTable, String text,
       Encoding encoding, bool spaceToPlus) {
@@ -896,12 +877,10 @@
  * and disclaimer.
  */
 
-/**
- * An implementation for the arbitrarily large integer.
- *
- * The integer number is represented by a sign, an array of 16-bit unsigned
- * integers in little endian format, and a number of used digits in that array.
- */
+/// An implementation for the arbitrarily large integer.
+///
+/// The integer number is represented by a sign, an array of 16-bit unsigned
+/// integers in little endian format, and a number of used digits in that array.
 class _BigIntImpl implements BigInt {
   // Bits per digit.
   static const int _digitBits = 16;
@@ -942,29 +921,27 @@
   /// replaced.
   final int _used;
 
-  /**
-   * Parses [source] as a, possibly signed, integer literal and returns its
-   * value.
-   *
-   * The [source] must be a non-empty sequence of base-[radix] digits,
-   * optionally prefixed with a minus or plus sign ('-' or '+').
-   *
-   * The [radix] must be in the range 2..36. The digits used are
-   * first the decimal digits 0..9, and then the letters 'a'..'z' with
-   * values 10 through 35. Also accepts upper-case letters with the same
-   * values as the lower-case ones.
-   *
-   * If no [radix] is given then it defaults to 10. In this case, the [source]
-   * digits may also start with `0x`, in which case the number is interpreted
-   * as a hexadecimal literal, which effectively means that the `0x` is ignored
-   * and the radix is instead set to 16.
-   *
-   * For any int `n` and radix `r`, it is guaranteed that
-   * `n == int.parse(n.toRadixString(r), radix: r)`.
-   *
-   * Throws a [FormatException] if the [source] is not a valid integer literal,
-   * optionally prefixed by a sign.
-   */
+  /// Parses [source] as a, possibly signed, integer literal and returns its
+  /// value.
+  ///
+  /// The [source] must be a non-empty sequence of base-[radix] digits,
+  /// optionally prefixed with a minus or plus sign ('-' or '+').
+  ///
+  /// The [radix] must be in the range 2..36. The digits used are
+  /// first the decimal digits 0..9, and then the letters 'a'..'z' with
+  /// values 10 through 35. Also accepts upper-case letters with the same
+  /// values as the lower-case ones.
+  ///
+  /// If no [radix] is given then it defaults to 10. In this case, the [source]
+  /// digits may also start with `0x`, in which case the number is interpreted
+  /// as a hexadecimal literal, which effectively means that the `0x` is ignored
+  /// and the radix is instead set to 16.
+  ///
+  /// For any int `n` and radix `r`, it is guaranteed that
+  /// `n == int.parse(n.toRadixString(r), radix: r)`.
+  ///
+  /// Throws a [FormatException] if the [source] is not a valid integer literal,
+  /// optionally prefixed by a sign.
   static _BigIntImpl parse(String source, {int radix}) {
     var result = _tryParse(source, radix: radix);
     if (result == null) {
@@ -1250,22 +1227,18 @@
     return absResult;
   }
 
-  /**
-   * Return the negative value of this integer.
-   *
-   * The result of negating an integer always has the opposite sign, except
-   * for zero, which is its own negation.
-   */
+  /// Return the negative value of this integer.
+  ///
+  /// The result of negating an integer always has the opposite sign, except
+  /// for zero, which is its own negation.
   _BigIntImpl operator -() {
     if (_used == 0) return this;
     return new _BigIntImpl._(!_isNegative, _used, _digits);
   }
 
-  /**
-   * Returns the absolute value of this integer.
-   *
-   * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
-   */
+  /// Returns the absolute value of this integer.
+  ///
+  /// For any integer `x`, the result is the same as `x < 0 ? -x : x`.
   _BigIntImpl abs() => _isNegative ? -this : this;
 
   /// Returns this << n *_DIGIT_BITS.
@@ -1355,18 +1328,16 @@
     resultDigits[digitShift] = carry;
   }
 
-  /**
-   * Shift the bits of this integer to the left by [shiftAmount].
-   *
-   * Shifting to the left makes the number larger, effectively multiplying
-   * the number by `pow(2, shiftIndex)`.
-   *
-   * There is no limit on the size of the result. It may be relevant to
-   * limit intermediate values by using the "and" operator with a suitable
-   * mask.
-   *
-   * It is an error if [shiftAmount] is negative.
-   */
+  /// Shift the bits of this integer to the left by [shiftAmount].
+  ///
+  /// Shifting to the left makes the number larger, effectively multiplying
+  /// the number by `pow(2, shiftIndex)`.
+  ///
+  /// There is no limit on the size of the result. It may be relevant to
+  /// limit intermediate values by using the "and" operator with a suitable
+  /// mask.
+  ///
+  /// It is an error if [shiftAmount] is negative.
   _BigIntImpl operator <<(int shiftAmount) {
     if (shiftAmount < 0) {
       throw new ArgumentError("shift-amount must be posititve $shiftAmount");
@@ -1422,15 +1393,13 @@
     resultDigits[last] = carry;
   }
 
-  /**
-   * Shift the bits of this integer to the right by [shiftAmount].
-   *
-   * Shifting to the right makes the number smaller and drops the least
-   * significant bits, effectively doing an integer division by
-   *`pow(2, shiftIndex)`.
-   *
-   * It is an error if [shiftAmount] is negative.
-   */
+  /// Shift the bits of this integer to the right by [shiftAmount].
+  ///
+  /// Shifting to the right makes the number smaller and drops the least
+  /// significant bits, effectively doing an integer division by
+  /// `pow(2, shiftIndex)`.
+  ///
+  /// It is an error if [shiftAmount] is negative.
   _BigIntImpl operator >>(int shiftAmount) {
     if (shiftAmount < 0) {
       throw new ArgumentError("shift-amount must be posititve $shiftAmount");
@@ -1473,12 +1442,10 @@
     return _compareDigits(_digits, _used, other._digits, other._used);
   }
 
-  /**
-   * Compares this to `other`.
-   *
-   * Returns a negative number if `this` is less than `other`, zero if they are
-   * equal, and a positive number if `this` is greater than `other`.
-   */
+  /// Compares this to `other`.
+  ///
+  /// Returns a negative number if `this` is less than `other`, zero if they are
+  /// equal, and a positive number if `this` is greater than `other`.
   int compareTo(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (_isNegative == other._isNegative) {
@@ -1666,16 +1633,14 @@
     return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
   }
 
-  /**
-   * Bit-wise and operator.
-   *
-   * Treating both `this` and [other] as sufficiently large two's component
-   * integers, the result is a number with only the bits set that are set in
-   * both `this` and [other]
-   *
-   * Of both operands are negative, the result is negative, otherwise
-   * the result is non-negative.
-   */
+  /// Bit-wise and operator.
+  ///
+  /// Treating both `this` and [other] as sufficiently large two's component
+  /// integers, the result is a number with only the bits set that are set in
+  /// both `this` and [other]
+  ///
+  /// Of both operands are negative, the result is negative, otherwise
+  /// the result is non-negative.
   _BigIntImpl operator &(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (_isZero || other._isZero) return zero;
@@ -1706,16 +1671,14 @@
     return p._absAndNotSetSign(n1, false);
   }
 
-  /**
-   * Bit-wise or operator.
-   *
-   * Treating both `this` and [other] as sufficiently large two's component
-   * integers, the result is a number with the bits set that are set in either
-   * of `this` and [other]
-   *
-   * If both operands are non-negative, the result is non-negative,
-   * otherwise the result us negative.
-   */
+  /// Bit-wise or operator.
+  ///
+  /// Treating both `this` and [other] as sufficiently large two's component
+  /// integers, the result is a number with the bits set that are set in either
+  /// of `this` and [other]
+  ///
+  /// If both operands are non-negative, the result is non-negative,
+  /// otherwise the result us negative.
   _BigIntImpl operator |(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (_isZero) return other;
@@ -1748,16 +1711,14 @@
     return n1._absAndNotSetSign(p, true)._absAddSetSign(one, true);
   }
 
-  /**
-   * Bit-wise exclusive-or operator.
-   *
-   * Treating both `this` and [other] as sufficiently large two's component
-   * integers, the result is a number with the bits set that are set in one,
-   * but not both, of `this` and [other]
-   *
-   * If the operands have the same sign, the result is non-negative,
-   * otherwise the result is negative.
-   */
+  /// Bit-wise exclusive-or operator.
+  ///
+  /// Treating both `this` and [other] as sufficiently large two's component
+  /// integers, the result is a number with the bits set that are set in one,
+  /// but not both, of `this` and [other]
+  ///
+  /// If the operands have the same sign, the result is non-negative,
+  /// otherwise the result is negative.
   _BigIntImpl operator ^(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (_isZero) return other;
@@ -1787,14 +1748,12 @@
     return p._absXorSetSign(n1, true)._absAddSetSign(one, true);
   }
 
-  /**
-   * The bit-wise negate operator.
-   *
-   * Treating `this` as a sufficiently large two's component integer,
-   * the result is a number with the opposite bits set.
-   *
-   * This maps any integer `x` to `-x - 1`.
-   */
+  /// The bit-wise negate operator.
+  ///
+  /// Treating `this` as a sufficiently large two's component integer,
+  /// the result is a number with the opposite bits set.
+  ///
+  /// This maps any integer `x` to `-x - 1`.
   _BigIntImpl operator ~() {
     if (_isZero) return _minusOne;
     if (_isNegative) {
@@ -2090,65 +2049,59 @@
     return finish(hash);
   }
 
-  /**
-   * Test whether this value is numerically equal to `other`.
-   *
-   * If [other] is a [_BigIntImpl] returns whether the two operands have the same
-   * value.
-   *
-   * Returns false if `other` is not a [_BigIntImpl].
-   */
+  /// Test whether this value is numerically equal to `other`.
+  ///
+  /// If [other] is a [_BigIntImpl] returns whether the two operands have the
+  /// same value.
+  ///
+  /// Returns false if `other` is not a [_BigIntImpl].
   bool operator ==(Object other) =>
       other is _BigIntImpl && compareTo(other) == 0;
 
-  /**
-   * Returns the minimum number of bits required to store this big integer.
-   *
-   * The number of bits excludes the sign bit, which gives the natural length
-   * for non-negative (unsigned) values.  Negative values are complemented to
-   * return the bit position of the first bit that differs from the sign bit.
-   *
-   * To find the number of bits needed to store the value as a signed value,
-   * add one, i.e. use `x.bitLength + 1`.
-   *
-   * ```
-   * x.bitLength == (-x-1).bitLength
-   *
-   * new BigInt.from(3).bitLength == 2;   // 00000011
-   * new BigInt.from(2).bitLength == 2;   // 00000010
-   * new BigInt.from(1).bitLength == 1;   // 00000001
-   * new BigInt.from(0).bitLength == 0;   // 00000000
-   * new BigInt.from(-1).bitLength == 0;  // 11111111
-   * new BigInt.from(-2).bitLength == 1;  // 11111110
-   * new BigInt.from(-3).bitLength == 2;  // 11111101
-   * new BigInt.from(-4).bitLength == 2;  // 11111100
-   * ```
-   */
+  /// Returns the minimum number of bits required to store this big integer.
+  ///
+  /// The number of bits excludes the sign bit, which gives the natural length
+  /// for non-negative (unsigned) values.  Negative values are complemented to
+  /// return the bit position of the first bit that differs from the sign bit.
+  ///
+  /// To find the number of bits needed to store the value as a signed value,
+  /// add one, i.e. use `x.bitLength + 1`.
+  ///
+  /// ```
+  /// x.bitLength == (-x-1).bitLength
+  ///
+  /// new BigInt.from(3).bitLength == 2;   // 00000011
+  /// new BigInt.from(2).bitLength == 2;   // 00000010
+  /// new BigInt.from(1).bitLength == 1;   // 00000001
+  /// new BigInt.from(0).bitLength == 0;   // 00000000
+  /// new BigInt.from(-1).bitLength == 0;  // 11111111
+  /// new BigInt.from(-2).bitLength == 1;  // 11111110
+  /// new BigInt.from(-3).bitLength == 2;  // 11111101
+  /// new BigInt.from(-4).bitLength == 2;  // 11111100
+  /// ```
   int get bitLength {
     if (_used == 0) return 0;
     if (_isNegative) return (~this).bitLength;
     return _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
   }
 
-  /**
-   * Truncating division operator.
-   *
-   * Performs a truncating integer division, where the remainder is discarded.
-   *
-   * The remainder can be computed using the [remainder] method.
-   *
-   * Examples:
-   * ```
-   * var seven = new BigInt.from(7);
-   * var three = new BigInt.from(3);
-   * seven ~/ three;    // => 2
-   * (-seven) ~/ three; // => -2
-   * seven ~/ -three;   // => -2
-   * seven.remainder(three);    // => 1
-   * (-seven).remainder(three); // => -1
-   * seven.remainder(-three);   // => 1
-   * ```
-   */
+  /// Truncating division operator.
+  ///
+  /// Performs a truncating integer division, where the remainder is discarded.
+  ///
+  /// The remainder can be computed using the [remainder] method.
+  ///
+  /// Examples:
+  /// ```
+  /// var seven = new BigInt.from(7);
+  /// var three = new BigInt.from(3);
+  /// seven ~/ three;    // => 2
+  /// (-seven) ~/ three; // => -2
+  /// seven ~/ -three;   // => -2
+  /// seven.remainder(three);    // => 1
+  /// (-seven).remainder(three); // => -1
+  /// seven.remainder(-three);   // => 1
+  /// ```
   _BigIntImpl operator ~/(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (other._used == 0) {
@@ -2157,13 +2110,12 @@
     return _div(other);
   }
 
-  /**
-   * Returns the remainder of the truncating division of `this` by [other].
-   *
-   * The result `r` of this operation satisfies:
-   * `this == (this ~/ other) * other + r`.
-   * As a consequence the remainder `r` has the same sign as the divider `this`.
-   */
+  /// Returns the remainder of the truncating division of `this` by [other].
+  ///
+  /// The result `r` of this operation satisfies:
+  /// `this == (this ~/ other) * other + r`.
+  /// As a consequence the remainder `r` has the same sign as the divider
+  /// `this`.
   _BigIntImpl remainder(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (other._used == 0) {
@@ -2175,29 +2127,27 @@
   /// Division operator.
   double operator /(BigInt other) => this.toDouble() / other.toDouble();
 
-  /** Relational less than operator. */
+  /// Relational less than operator.
   bool operator <(BigInt other) => compareTo(other) < 0;
 
-  /** Relational less than or equal operator. */
+  /// Relational less than or equal operator.
   bool operator <=(BigInt other) => compareTo(other) <= 0;
 
-  /** Relational greater than operator. */
+  /// Relational greater than operator.
   bool operator >(BigInt other) => compareTo(other) > 0;
 
-  /** Relational greater than or equal operator. */
+  /// Relational greater than or equal operator.
   bool operator >=(BigInt other) => compareTo(other) >= 0;
 
-  /**
-   * Euclidean modulo operator.
-   *
-   * Returns the remainder of the Euclidean division. The Euclidean division of
-   * two integers `a` and `b` yields two integers `q` and `r` such that
-   * `a == b * q + r` and `0 <= r < b.abs()`.
-   *
-   * The sign of the returned value `r` is always positive.
-   *
-   * See [remainder] for the remainder of the truncating division.
-   */
+  /// Euclidean modulo operator.
+  ///
+  /// Returns the remainder of the Euclidean division. The Euclidean division of
+  /// two integers `a` and `b` yields two integers `q` and `r` such that
+  /// `a == b * q + r` and `0 <= r < b.abs()`.
+  ///
+  /// The sign of the returned value `r` is always positive.
+  ///
+  /// See [remainder] for the remainder of the truncating division.
   _BigIntImpl operator %(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (other._used == 0) {
@@ -2214,12 +2164,10 @@
     return result;
   }
 
-  /**
-   * Returns the sign of this big integer.
-   *
-   * Returns 0 for zero, -1 for values less than zero and
-   * +1 for values greater than zero.
-   */
+  /// Returns the sign of this big integer.
+  ///
+  /// Returns 0 for zero, -1 for values less than zero and
+  /// +1 for values greater than zero.
   int get sign {
     if (_used == 0) return 0;
     return _isNegative ? -1 : 1;
@@ -2256,12 +2204,10 @@
     return result;
   }
 
-  /**
-   * Returns this integer to the power of [exponent] modulo [modulus].
-   *
-   * The [exponent] must be non-negative and [modulus] must be
-   * positive.
-   */
+  /// Returns this integer to the power of [exponent] modulo [modulus].
+  ///
+  /// The [exponent] must be non-negative and [modulus] must be
+  /// positive.
   _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
     _BigIntImpl exponent = bigExponent;
     _BigIntImpl modulus = bigModulus;
@@ -2554,14 +2500,12 @@
     return new _BigIntImpl._(false, maxUsed, dDigits);
   }
 
-  /**
-   * Returns the modular multiplicative inverse of this big integer
-   * modulo [modulus].
-   *
-   * The [modulus] must be positive.
-   *
-   * It is an error if no modular inverse exists.
-   */
+  /// Returns the modular multiplicative inverse of this big integer
+  /// modulo [modulus].
+  ///
+  /// The [modulus] must be positive.
+  ///
+  /// It is an error if no modular inverse exists.
   // Returns 1/this % modulus, with modulus > 0.
   _BigIntImpl modInverse(BigInt bigInt) {
     _BigIntImpl modulus = bigInt;
@@ -2576,19 +2520,17 @@
     return _binaryGcd(modulus, tmp, true);
   }
 
-  /**
-   * Returns the greatest common divisor of this big integer and [other].
-   *
-   * If either number is non-zero, the result is the numerically greatest
-   * integer dividing both `this` and `other`.
-   *
-   * The greatest common divisor is independent of the order,
-   * so `x.gcd(y)` is  always the same as `y.gcd(x)`.
-   *
-   * For any integer `x`, `x.gcd(x)` is `x.abs()`.
-   *
-   * If both `this` and `other` is zero, the result is also zero.
-   */
+  /// Returns the greatest common divisor of this big integer and [other].
+  ///
+  /// If either number is non-zero, the result is the numerically greatest
+  /// integer dividing both `this` and `other`.
+  ///
+  /// The greatest common divisor is independent of the order,
+  /// so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+  ///
+  /// For any integer `x`, `x.gcd(x)` is `x.abs()`.
+  ///
+  /// If both `this` and `other` is zero, the result is also zero.
   _BigIntImpl gcd(BigInt bigInt) {
     _BigIntImpl other = bigInt;
     if (_isZero) return other.abs();
@@ -2596,70 +2538,67 @@
     return _binaryGcd(this, other, false);
   }
 
-  /**
-   * Returns the least significant [width] bits of this big integer as a
-   * non-negative number (i.e. unsigned representation).  The returned value has
-   * zeros in all bit positions higher than [width].
-   *
-   * ```
-   * new BigInt.from(-1).toUnsigned(5) == 31   // 11111111  ->  00011111
-   * ```
-   *
-   * This operation can be used to simulate arithmetic from low level languages.
-   * For example, to increment an 8 bit quantity:
-   *
-   * ```
-   * q = (q + 1).toUnsigned(8);
-   * ```
-   *
-   * `q` will count from `0` up to `255` and then wrap around to `0`.
-   *
-   * If the input fits in [width] bits without truncation, the result is the
-   * same as the input.  The minimum width needed to avoid truncation of `x` is
-   * given by `x.bitLength`, i.e.
-   *
-   * ```
-   * x == x.toUnsigned(x.bitLength);
-   * ```
-   */
+  /// Returns the least significant [width] bits of this big integer as a
+  /// non-negative number (i.e. unsigned representation).  The returned value
+  /// has zeros in all bit positions higher than [width].
+  ///
+  /// ```
+  /// new BigInt.from(-1).toUnsigned(5) == 31   // 11111111  ->  00011111
+  /// ```
+  ///
+  /// This operation can be used to simulate arithmetic from low level
+  /// languages.  For example, to increment an 8 bit quantity:
+  ///
+  /// ```
+  /// q = (q + 1).toUnsigned(8);
+  /// ```
+  ///
+  /// `q` will count from `0` up to `255` and then wrap around to `0`.
+  ///
+  /// If the input fits in [width] bits without truncation, the result is the
+  /// same as the input.  The minimum width needed to avoid truncation of `x` is
+  /// given by `x.bitLength`, i.e.
+  ///
+  /// ```
+  /// x == x.toUnsigned(x.bitLength);
+  /// ```
   _BigIntImpl toUnsigned(int width) {
     return this & ((one << width) - one);
   }
 
-  /**
-   * Returns the least significant [width] bits of this integer, extending the
-   * highest retained bit to the sign.  This is the same as truncating the value
-   * to fit in [width] bits using an signed 2-s complement representation.  The
-   * returned value has the same bit value in all positions higher than [width].
-   *
-   * ```
-   * var big15 = new BigInt.from(15);
-   * var big16 = new BigInt.from(16);
-   * var big239 = new BigInt.from(239);
-   *                                      V--sign bit-V
-   * big16.toSigned(5) == -big16   //  00010000 -> 11110000
-   * big239.toSigned(5) == big15   //  11101111 -> 00001111
-   *                                      ^           ^
-   * ```
-   *
-   * This operation can be used to simulate arithmetic from low level languages.
-   * For example, to increment an 8 bit signed quantity:
-   *
-   * ```
-   * q = (q + 1).toSigned(8);
-   * ```
-   *
-   * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
-   * `127`.
-   *
-   * If the input value fits in [width] bits without truncation, the result is
-   * the same as the input.  The minimum width needed to avoid truncation of `x`
-   * is `x.bitLength + 1`, i.e.
-   *
-   * ```
-   * x == x.toSigned(x.bitLength + 1);
-   * ```
-   */
+  /// Returns the least significant [width] bits of this integer, extending the
+  /// highest retained bit to the sign.  This is the same as truncating the
+  /// value to fit in [width] bits using an signed 2-s complement
+  /// representation.  The returned value has the same bit value in all
+  /// positions higher than [width].
+  ///
+  /// ```
+  /// var big15 = new BigInt.from(15);
+  /// var big16 = new BigInt.from(16);
+  /// var big239 = new BigInt.from(239);
+  ///                                      V--sign bit-V
+  /// big16.toSigned(5) == -big16   //  00010000 -> 11110000
+  /// big239.toSigned(5) == big15   //  11101111 -> 00001111
+  ///                                      ^           ^
+  /// ```
+  ///
+  /// This operation can be used to simulate arithmetic from low level
+  /// languages.  For example, to increment an 8 bit signed quantity:
+  ///
+  /// ```
+  /// q = (q + 1).toSigned(8);
+  /// ```
+  ///
+  /// `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+  /// `127`.
+  ///
+  /// If the input value fits in [width] bits without truncation, the result is
+  /// the same as the input.  The minimum width needed to avoid truncation of
+  /// `x` is `x.bitLength + 1`, i.e.
+  ///
+  /// ```
+  /// x == x.toSigned(x.bitLength + 1);
+  /// ```
   _BigIntImpl toSigned(int width) {
     // The value of binary number weights each bit by a power of two.  The
     // twos-complement value weights the sign bit negatively.  We compute the
@@ -2688,13 +2627,11 @@
     return _isNegative ? -result : result;
   }
 
-  /**
-   * Returns this [_BigIntImpl] as a [double].
-   *
-   * If the number is not representable as a [double], an
-   * approximation is returned. For numerically large integers, the
-   * approximation may be infinite.
-   */
+  /// Returns this [_BigIntImpl] as a [double].
+  ///
+  /// If the number is not representable as a [double], an
+  /// approximation is returned. For numerically large integers, the
+  /// approximation may be infinite.
   double toDouble() {
     const int exponentBias = 1075;
     // There are 11 bits for the exponent.
@@ -2790,13 +2727,11 @@
     return resultBits.buffer.asByteData().getFloat64(0, Endian.little);
   }
 
-  /**
-   * Returns a String-representation of this integer.
-   *
-   * The returned string is parsable by [parse].
-   * For any `_BigIntImpl` `i`, it is guaranteed that
-   * `i == _BigIntImpl.parse(i.toString())`.
-   */
+  /// Returns a String-representation of this integer.
+  ///
+  /// The returned string is parsable by [parse].
+  /// For any `_BigIntImpl` `i`, it is guaranteed that
+  /// `i == _BigIntImpl.parse(i.toString())`.
   String toString() {
     if (_used == 0) return "0";
     if (_used == 1) {
@@ -2828,14 +2763,12 @@
     return _a + digit - 10;
   }
 
-  /**
-   * Converts [this] to a string representation in the given [radix].
-   *
-   * In the string representation, lower-case letters are used for digits above
-   * '9', with 'a' being 10 an 'z' being 35.
-   *
-   * The [radix] argument must be an integer in the range 2 to 36.
-   */
+  /// Converts [this] to a string representation in the given [radix].
+  ///
+  /// In the string representation, lower-case letters are used for digits above
+  /// '9', with 'a' being 10 an 'z' being 35.
+  ///
+  /// The [radix] argument must be an integer in the range 2 to 36.
   String toRadixString(int radix) {
     if (radix > 36) throw new RangeError.range(radix, 2, 36);
 
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 4f549a0..5377630 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -6,152 +6,151 @@
 
 import 'dart:_js_embedded_names' show JsGetName, JsBuiltin;
 
-/**
- * Emits a JavaScript code fragment parametrized by arguments.
- *
- * Hash characters `#` in the [codeTemplate] are replaced in left-to-right order
- * with expressions that contain the values of, or evaluate to, the arguments.
- * The number of hash marks must match the number or arguments.  Although
- * declared with arguments [arg0] through [arg2], the form actually has no limit
- * on the number of arguments.
- *
- * The [typeDescription] argument is interpreted as a description of the
- * behavior of the JavaScript code.  Currently it describes the side effects
- * types that may be returned by the expression, with the additional behavior
- * that the returned values may be fresh instances of the types.  The type
- * information must be correct as it is trusted by the compiler in
- * optimizations, and it must be precise as possible since it is used for native
- * live type analysis to tree-shake large parts of the DOM libraries.  If poorly
- * written, the [typeDescription] will cause unnecessarily bloated programs.
- * (You can check for this by compiling with `--verbose`; there is an info
- * message describing the number of native (DOM) types that can be removed,
- * which usually should be greater than zero.)
- *
- * The [typeDescription] must be a [String]. Two forms of it are supported:
- *
- * 1) a union of types separated by vertical bar `|` symbols, e.g.
- *    `"num|String"` describes the union of numbers and Strings.  There is no
- *    type in Dart that is this precise.  The Dart alternative would be `Object`
- *    or `dynamic`, but these types imply that the JS-code might also be
- *    creating instances of all the DOM types.
- *
- *    If `null` is possible, it must be specified explicitly, e.g.
- *    `"String|Null"`. [typeDescription] has several extensions to help describe
- *    the behavior more accurately.  In addition to the union type already
- *    described:
- *
- *    + `=Object` is a plain JavaScript object.  Some DOM methods return
- *       instances that have no corresponding Dart type (e.g. cross-frame
- *       documents), `=Object` can be used to describe these untyped' values.
- *
- *    + `var` or empty string.  If the entire [typeDescription] is `var` (or
- *      empty string) then the type is `dynamic` but the code is known to not
- *      create any instances.
- *
- *   Examples:
- *
- *       // Parent window might be an opaque cross-frame window.
- *       var thing = JS('=Object|Window', '#.parent', myWindow);
- *
- * 2) a sequence of the form `<tag>:<value>;` where `<tag>` is one of
- *    `creates`, `returns`, `effects` or `depends`.
- *
- *    The first two tags are used to specify the created and returned types of
- *    the expression. The value of `creates` and `returns` is a type string as
- *    defined in 1).
- *
- *    The tags `effects` and `depends` encode the side effects of this call.
- *    They can be omitted, in which case the expression is parsed and a safe
- *    conservative side-effect estimation is computed.
- *
- *    The values of `effects` and `depends` may be 'all', 'none' or a
- *    comma-separated list of 'no-index', 'no-instance' and 'no-static'.
- *
- *    The value 'all' indicates that the call affects/depends on every
- *    side-effect. The flag 'none' signals that the call does not affect
- *    (resp. depends on) anything.
- *
- *    The value 'no-index' indicates that the call does *not* do (resp. depends
- *    on) any array index-store. The flag 'no-instance' indicates that the call
- *    does not modify (resp. depends on) any instance variable. Similarly,
- *    the 'no-static' value indicates that the call does not modify (resp.
- *    depends on) any static variable.
- *
- *    The `effects` and `depends` flag must be used in tandem. Either both are
- *    specified or none is.
- *
- *    Each tag (including the type tags) may only occur once in the sequence.
- *
- * Guidelines:
- *
- *  + Do not use any parameter, local, method or field names in the
- *    [codeTemplate].  These names are all subject to arbitrary renaming by the
- *    compiler.  Pass the values in via `#` substition, and test with the
- *    `--minify` dart2js command-line option.
- *
- *  + The substituted expressions are values, not locations.
- *
- *        JS('void', '# += "x"', this.field);
- *
- *    `this.field` might not be a substituted as a reference to the field.  The
- *    generated code might accidentally work as intended, but it also might be
- *
- *        var t1 = this.field;
- *        t1 += "x";
- *
- *    or
- *
- *        this.get$field() += "x";
- *
- *    The remedy in this case is to expand the `+=` operator, leaving all
- *    references to the Dart field as Dart code:
- *
- *        this.field = JS('String', '# + "x"', this.field);
- *
- *  + Never use `#` in function bodies.
- *
- *    This is a variation on the previous guideline.  Since `#` is replaced with
- *    an *expression* and the expression is only valid in the immediate context,
- *    `#` should never appear in a function body.  Doing so might defer the
- *    evaluation of the expression, and its side effects, until the function is
- *    called.
- *
- *    For example,
- *
- *        var value = foo();
- *        var f = JS('', 'function(){return #}', value)
- *
- *    might result in no immediate call to `foo` and a call to `foo` on every
- *    call to the JavaScript function bound to `f`.  This is better:
- *
- *        var f = JS('',
- *            '(function(val) { return function(){return val}; })(#)', value);
- *
- *    Since `#` occurs in the immediately evaluated expression, the expression
- *    is immediately evaluated and bound to `val` in the immediate call.
- *
- *
- * Type argument.
- *
- * In Dart 2.0, the type argument additionally constrains the returned type.
- * So, with type inference filling in the type argumemnt,
- *
- *     String s = JS('', 'JSON.stringify(#)', x);
- *
- * will be the same as the current meaning of
- *
- *     var s = JS('String|Null', 'JSON.stringify(#)', x);
- *
- *
- * Additional notes.
- *
- * In the future we may extend [typeDescription] to include other aspects of the
- * behavior, for example, separating the returned types from the instantiated
- * types to allow the compiler to perform more optimizations around the code.
- *
- * This might be an extension of [JS] or a new function similar to [JS] with
- * additional arguments for the new information.
- */
+/// Emits a JavaScript code fragment parametrized by arguments.
+///
+/// Hash characters `#` in the [codeTemplate] are replaced in left-to-right
+/// order with expressions that contain the values of, or evaluate to, the
+/// arguments.  The number of hash marks must match the number or arguments.
+/// Although declared with arguments [arg0] through [arg2], the form actually
+/// has no limit on the number of arguments.
+///
+/// The [typeDescription] argument is interpreted as a description of the
+/// behavior of the JavaScript code.  Currently it describes the side effects
+/// types that may be returned by the expression, with the additional behavior
+/// that the returned values may be fresh instances of the types.  The type
+/// information must be correct as it is trusted by the compiler in
+/// optimizations, and it must be precise as possible since it is used for
+/// native live type analysis to tree-shake large parts of the DOM libraries.
+/// If poorly written, the [typeDescription] will cause unnecessarily bloated
+/// programs.  (You can check for this by compiling with `--verbose`; there is
+/// an info message describing the number of native (DOM) types that can be
+/// removed, which usually should be greater than zero.)
+///
+/// The [typeDescription] must be a [String]. Two forms of it are supported:
+///
+/// 1) a union of types separated by vertical bar `|` symbols, e.g.
+///    `"num|String"` describes the union of numbers and Strings.  There is no
+///    type in Dart that is this precise.  The Dart alternative would be
+///    `Object` or `dynamic`, but these types imply that the JS-code might also
+///    be creating instances of all the DOM types.
+///
+///    If `null` is possible, it must be specified explicitly, e.g.
+///    `"String|Null"`. [typeDescription] has several extensions to help
+///    describe the behavior more accurately.  In addition to the union type
+///    already described:
+///
+///    + `=Object` is a plain JavaScript object.  Some DOM methods return
+///       instances that have no corresponding Dart type (e.g. cross-frame
+///       documents), `=Object` can be used to describe these untyped' values.
+///
+///    + `var` or empty string.  If the entire [typeDescription] is `var` (or
+///      empty string) then the type is `dynamic` but the code is known to not
+///      create any instances.
+///
+///   Examples:
+///
+///       // Parent window might be an opaque cross-frame window.
+///       var thing = JS('=Object|Window', '#.parent', myWindow);
+///
+/// 2) a sequence of the form `<tag>:<value>;` where `<tag>` is one of
+///    `creates`, `returns`, `effects` or `depends`.
+///
+///    The first two tags are used to specify the created and returned types of
+///    the expression. The value of `creates` and `returns` is a type string as
+///    defined in 1).
+///
+///    The tags `effects` and `depends` encode the side effects of this call.
+///    They can be omitted, in which case the expression is parsed and a safe
+///    conservative side-effect estimation is computed.
+///
+///    The values of `effects` and `depends` may be 'all', 'none' or a
+///    comma-separated list of 'no-index', 'no-instance' and 'no-static'.
+///
+///    The value 'all' indicates that the call affects/depends on every
+///    side-effect. The flag 'none' signals that the call does not affect
+///    (resp. depends on) anything.
+///
+///    The value 'no-index' indicates that the call does *not* do (resp. depends
+///    on) any array index-store. The flag 'no-instance' indicates that the call
+///    does not modify (resp. depends on) any instance variable. Similarly,
+///    the 'no-static' value indicates that the call does not modify (resp.
+///    depends on) any static variable.
+///
+///    The `effects` and `depends` flag must be used in tandem. Either both are
+///    specified or none is.
+///
+///    Each tag (including the type tags) may only occur once in the sequence.
+///
+/// Guidelines:
+///
+///  + Do not use any parameter, local, method or field names in the
+///    [codeTemplate].  These names are all subject to arbitrary renaming by the
+///    compiler.  Pass the values in via `#` substition, and test with the
+///    `--minify` dart2js command-line option.
+///
+///  + The substituted expressions are values, not locations.
+///
+///        JS('void', '# += "x"', this.field);
+///
+///    `this.field` might not be a substituted as a reference to the field.  The
+///    generated code might accidentally work as intended, but it also might be
+///
+///        var t1 = this.field;
+///        t1 += "x";
+///
+///    or
+///
+///        this.get$field() += "x";
+///
+///    The remedy in this case is to expand the `+=` operator, leaving all
+///    references to the Dart field as Dart code:
+///
+///        this.field = JS('String', '# + "x"', this.field);
+///
+///  + Never use `#` in function bodies.
+///
+///    This is a variation on the previous guideline.  Since `#` is replaced
+///    with an *expression* and the expression is only valid in the immediate
+///    context, `#` should never appear in a function body.  Doing so might
+///    defer the evaluation of the expression, and its side effects, until the
+///    function is called.
+///
+///    For example,
+///
+///        var value = foo();
+///        var f = JS('', 'function(){return #}', value)
+///
+///    might result in no immediate call to `foo` and a call to `foo` on every
+///    call to the JavaScript function bound to `f`.  This is better:
+///
+///        var f = JS('',
+///            '(function(val) { return function(){return val}; })(#)', value);
+///
+///    Since `#` occurs in the immediately evaluated expression, the expression
+///    is immediately evaluated and bound to `val` in the immediate call.
+///
+///
+/// Type argument.
+///
+/// In Dart 2.0, the type argument additionally constrains the returned type.
+/// So, with type inference filling in the type argumemnt,
+///
+///     String s = JS('', 'JSON.stringify(#)', x);
+///
+/// will be the same as the current meaning of
+///
+///     var s = JS('String|Null', 'JSON.stringify(#)', x);
+///
+///
+/// Additional notes.
+///
+/// In the future we may extend [typeDescription] to include other aspects of
+/// the behavior, for example, separating the returned types from the
+/// instantiated types to allow the compiler to perform more optimizations
+/// around the code.
+///
+/// This might be an extension of [JS] or a new function similar to [JS] with
+/// additional arguments for the new information.
 // Add additional optional arguments if needed. The method is treated internally
 // as a variable argument method.
 external T JS<T>(String typeDescription, String codeTemplate,
@@ -176,39 +175,31 @@
     arg18,
     arg19]);
 
-/**
- * Converts the Dart closure [function] into a JavaScript closure.
- *
- * Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care
- * must be taken to store the current isolate.
- */
+/// Converts the Dart closure [function] into a JavaScript closure.
+///
+/// Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care
+/// must be taken to store the current isolate.
 external DART_CLOSURE_TO_JS(Function function);
 
-/**
- * Returns a raw reference to the JavaScript function which implements
- * [function].
- *
- * Warning: this is dangerous, you should probably use
- * [DART_CLOSURE_TO_JS] instead. The returned object is not a valid
- * Dart closure, does not store the isolate context or arity.
- *
- * A valid example of where this can be used is as the second argument
- * to V8's Error.captureStackTrace. See
- * https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
- */
+/// Returns a raw reference to the JavaScript function which implements
+/// [function].
+///
+/// Warning: this is dangerous, you should probably use
+/// [DART_CLOSURE_TO_JS] instead. The returned object is not a valid
+/// Dart closure, does not store the isolate context or arity.
+///
+/// A valid example of where this can be used is as the second argument
+/// to V8's Error.captureStackTrace. See
+/// https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
 external RAW_DART_FUNCTION_REF(Function function);
 
-/**
- * Sets the current static state to [staticState].
- */
+/// Sets the current static state to [staticState].
 external void JS_SET_STATIC_STATE(staticState);
 
-/**
- * Returns the interceptor for class [type].  The interceptor is the type's
- * constructor's `prototype` property.  [type] will typically be the class, not
- * an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
- * `JS_INTERCEPTOR_CONSTANT(int)`.
- */
+/// Returns the interceptor for class [type].  The interceptor is the type's
+/// constructor's `prototype` property.  [type] will typically be the class, not
+/// an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
+/// `JS_INTERCEPTOR_CONSTANT(int)`.
 external JS_INTERCEPTOR_CONSTANT(Type type);
 
 /// Returns the interceptor for [object].
@@ -216,9 +207,7 @@
 /// Calls are replaced with the [HInterceptor] SSA instruction.
 external getInterceptor(object);
 
-/**
- * Returns the object corresponding to Namer.staticStateHolder.
- */
+/// Returns the object corresponding to Namer.staticStateHolder.
 external JS_GET_STATIC_STATE();
 
 /// Returns the JS name for [name] from the Namer.
@@ -242,42 +231,36 @@
 /// when the program has been analyzed.
 external bool JS_GET_FLAG(String name);
 
-/**
- * Pretend [code] is executed.  Generates no executable code.  This is used to
- * model effects at some other point in external code.  For example, the
- * following models an assignment to foo with an unknown value.
- *
- *     var foo;
- *
- *     main() {
- *       JS_EFFECT((_){ foo = _; })
- *     }
- *
- * TODO(sra): Replace this hack with something to mark the volatile or
- * externally initialized elements.
- */
+/// Pretend [code] is executed.  Generates no executable code.  This is used to
+/// model effects at some other point in external code.  For example, the
+/// following models an assignment to foo with an unknown value.
+///
+///     var foo;
+///
+///     main() {
+///       JS_EFFECT((_){ foo = _; })
+///     }
+///
+/// TODO(sra): Replace this hack with something to mark the volatile or
+/// externally initialized elements.
 void JS_EFFECT(Function code) {
   code(null);
 }
 
-/**
- * Use this class for creating constants that hold JavaScript code.
- * For example:
- *
- * const constant = JS_CONST('typeof window != "undefined");
- *
- * This code will generate:
- * $.JS_CONST_1 = typeof window != "undefined";
- */
+/// Use this class for creating constants that hold JavaScript code.
+/// For example:
+///
+/// const constant = JS_CONST('typeof window != "undefined");
+///
+/// This code will generate:
+/// $.JS_CONST_1 = typeof window != "undefined";
 class JS_CONST {
   final String code;
   const JS_CONST(this.code);
 }
 
-/**
- * JavaScript string concatenation. Inputs must be Strings.  Corresponds to the
- * HStringConcat SSA instruction and may be constant-folded.
- */
+/// JavaScript string concatenation. Inputs must be Strings.  Corresponds to the
+/// HStringConcat SSA instruction and may be constant-folded.
 String JS_STRING_CONCAT(String a, String b) {
   // This body is unused, only here for type analysis.
   return JS('String', '# + #', a, b);
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
index a9fcb75..3344d39 100644
--- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
@@ -52,7 +52,7 @@
         JS_EMBEDDED_GLOBAL,
         JS_INTERCEPTOR_CONSTANT,
         JS_STRING_CONCAT;
-import 'dart:math' show Random;
+import 'dart:math' show Random, ln2;
 
 part 'js_array.dart';
 part 'js_number.dart';
@@ -123,10 +123,8 @@
 dispatchRecordExtension(record) => JS('', '#.e', record);
 dispatchRecordIndexability(record) => JS('bool|Null', '#.x', record);
 
-/**
- * Returns the interceptor for a native class instance. Used by
- * [getInterceptor].
- */
+/// Returns the interceptor for a native class instance. Used by
+/// [getInterceptor].
 getNativeInterceptor(object) {
   var record = getDispatchProperty(object);
 
@@ -220,20 +218,18 @@
   JS('', '#.set(#, #)', constructorToInterceptor, constructor, interceptor);
 }
 
-/**
- * Data structure used to map a [Type] to the [Interceptor] and constructors for
- * that type.  It is JavaScript array of 3N entries of adjacent slots containing
- * a [Type], followed by an [Interceptor] class for the type, followed by a
- * JavaScript object map for the constructors.
- *
- * The value of this variable is set by the compiler and contains only types
- * that are user extensions of native classes where the type occurs as a
- * constant in the program.
- *
- * The compiler, in CustomElementsAnalysis, assumes that [typeToInterceptorMap]
- * is accessed only by code that also calls [findIndexForWebComponentType].  If
- * this assumption is invalidated, the compiler will have to be updated.
- */
+/// Data structure used to map a [Type] to the [Interceptor] and constructors
+/// for that type.  It is JavaScript array of 3N entries of adjacent slots
+/// containing a [Type], followed by an [Interceptor] class for the type,
+/// followed by a JavaScript object map for the constructors.
+///
+/// The value of this variable is set by the compiler and contains only types
+/// that are user extensions of native classes where the type occurs as a
+/// constant in the program.
+///
+/// The compiler, in CustomElementsAnalysis, assumes that [typeToInterceptorMap]
+/// is accessed only by code that also calls [findIndexForWebComponentType].  If
+/// this assumption is invalidated, the compiler will have to be updated.
 get typeToInterceptorMap {
   return JS_EMBEDDED_GLOBAL('', TYPE_TO_INTERCEPTOR_MAP);
 }
@@ -256,12 +252,10 @@
   return map[index + 1];
 }
 
-/**
- * Returns a JavaScript function that runs the constructor on its argument, or
- * `null` if there is no such constructor.
- *
- * The returned function takes one argument, the web component object.
- */
+/// Returns a JavaScript function that runs the constructor on its argument, or
+/// `null` if there is no such constructor.
+///
+/// The returned function takes one argument, the web component object.
 findConstructorForNativeSubclassType(Type type, String name) {
   var index = findIndexForNativeSubclassType(type);
   if (index == null) return null;
@@ -277,54 +271,52 @@
   return JS('', '#.prototype', constructor);
 }
 
-/**
- * The base interceptor class.
- *
- * The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`.  The
- * value returned by [getInterceptor] holds the methods separately from the
- * state of the instance.  The compiler converts the methods on an interceptor
- * to take the Dart `this` argument as an explicit `receiver` argument.  The
- * JavaScript `this` parameter is bound to the interceptor.
- *
- * In order to have uniform call sites, if a method is defined on an
- * interceptor, methods of that name on plain unintercepted classes also use the
- * interceptor calling convention.  The plain classes are _self-interceptors_,
- * and for them, `getInterceptor(r)` returns `r`.  Methods on plain
- * unintercepted classes have a redundant `receiver` argument and, to enable
- * some optimizations, must ignore `receiver` in favour of `this`.
- *
- * In the case of mixins, a method may be placed on both an intercepted class
- * and an unintercepted class.  In this case, the method must use the `receiver`
- * parameter.
- *
- *
- * There are various optimizations of the general call pattern.
- *
- * When the interceptor can be statically determined, it can be used directly:
- *
- *     CONSTANT_INTERCEPTOR.foo$1(r, a)
- *
- * If there are only a few classes, [getInterceptor] can be specialized with a
- * more efficient dispatch:
- *
- *     getInterceptor$specialized(r).foo$1(r, a)
- *
- * If it can be determined that the receiver is an unintercepted class, it can
- * be called directly:
- *
- *     r.foo$1(r, a)
- *
- * If, further, it is known that the call site cannot call a foo that is
- * mixed-in to a native class, then it is known that the explicit receiver is
- * ignored, and space-saving dummy value can be passed instead:
- *
- *     r.foo$1(0, a)
- *
- * This class defines implementations of *all* methods on [Object] so no
- * interceptor inherits an implementation from [Object].  This enables the
- * implementations on Object to ignore the explicit receiver argument, which
- * allows dummy receiver optimization.
- */
+/// The base interceptor class.
+///
+/// The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`.  The
+/// value returned by [getInterceptor] holds the methods separately from the
+/// state of the instance.  The compiler converts the methods on an interceptor
+/// to take the Dart `this` argument as an explicit `receiver` argument.  The
+/// JavaScript `this` parameter is bound to the interceptor.
+///
+/// In order to have uniform call sites, if a method is defined on an
+/// interceptor, methods of that name on plain unintercepted classes also use
+/// the interceptor calling convention.  The plain classes are
+/// _self-interceptors_, and for them, `getInterceptor(r)` returns `r`.  Methods
+/// on plain unintercepted classes have a redundant `receiver` argument and, to
+/// enable some optimizations, must ignore `receiver` in favour of `this`.
+///
+/// In the case of mixins, a method may be placed on both an intercepted class
+/// and an unintercepted class.  In this case, the method must use the
+/// `receiver` parameter.
+///
+///
+/// There are various optimizations of the general call pattern.
+///
+/// When the interceptor can be statically determined, it can be used directly:
+///
+///     CONSTANT_INTERCEPTOR.foo$1(r, a)
+///
+/// If there are only a few classes, [getInterceptor] can be specialized with a
+/// more efficient dispatch:
+///
+///     getInterceptor$specialized(r).foo$1(r, a)
+///
+/// If it can be determined that the receiver is an unintercepted class, it can
+/// be called directly:
+///
+///     r.foo$1(r, a)
+///
+/// If, further, it is known that the call site cannot call a foo that is
+/// mixed-in to a native class, then it is known that the explicit receiver is
+/// ignored, and space-saving dummy value can be passed instead:
+///
+///     r.foo$1(0, a)
+///
+/// This class defines implementations of *all* methods on [Object] so no
+/// interceptor inherits an implementation from [Object].  This enables the
+/// implementations on Object to ignore the explicit receiver argument, which
+/// allows dummy receiver optimization.
 abstract class Interceptor {
   const Interceptor();
 
@@ -356,9 +348,7 @@
   Type get runtimeType => getRuntimeType(this);
 }
 
-/**
- * The interceptor class for [bool].
- */
+/// The interceptor class for [bool].
 class JSBool extends Interceptor implements bool {
   const JSBool();
 
@@ -378,13 +368,11 @@
   Type get runtimeType => bool;
 }
 
-/**
- * The interceptor class for [Null].
- *
- * This class defines implementations for *all* methods on [Object] since
- * the methods on Object assume the receiver is non-null.  This means that
- * JSNull will always be in the interceptor set for methods defined on Object.
- */
+/// The interceptor class for [Null].
+///
+/// This class defines implementations for *all* methods on [Object] since
+/// the methods on Object assume the receiver is non-null.  This means that
+/// JSNull will always be in the interceptor set for methods defined on Object.
 class JSNull extends Interceptor implements Null {
   const JSNull();
 
@@ -403,37 +391,29 @@
   dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
-/**
- * The supertype for JSString and JSArray. Used by the backend as to
- * have a type mask that contains the objects that we can use the
- * native JS [] operator and length on.
- */
+/// The supertype for JSString and JSArray. Used by the backend as to
+/// have a type mask that contains the objects that we can use the
+/// native JS [] operator and length on.
 abstract class JSIndexable<E> {
   int get length;
   E operator [](int index);
 }
 
-/**
- * The supertype for JSMutableArray and
- * JavaScriptIndexingBehavior. Used by the backend to have a type mask
- * that contains the objects we can use the JS []= operator on.
- */
+/// The supertype for JSMutableArray and
+/// JavaScriptIndexingBehavior. Used by the backend to have a type mask
+/// that contains the objects we can use the JS []= operator on.
 abstract class JSMutableIndexable<E> extends JSIndexable<E> {
   operator []=(int index, E value);
 }
 
-/**
- * The interface implemented by JavaScript objects.  These are methods in
- * addition to the regular Dart Object methods like [Object.hashCode].
- *
- * This is the type that should be exported by a JavaScript interop library.
- */
+/// The interface implemented by JavaScript objects.  These are methods in
+/// addition to the regular Dart Object methods like [Object.hashCode].
+///
+/// This is the type that should be exported by a JavaScript interop library.
 abstract class JSObject {}
 
-/**
- * Interceptor base class for JavaScript objects not recognized as some more
- * specific native type.
- */
+/// Interceptor base class for JavaScript objects not recognized as some more
+/// specific native type.
 class JavaScriptObject extends Interceptor implements JSObject {
   const JavaScriptObject();
 
@@ -442,36 +422,28 @@
 
   Type get runtimeType => JSObject;
 
-  /**
-   * Returns the result of the JavaScript objects `toString` method.
-   */
+  /// Returns the result of the JavaScript objects `toString` method.
   String toString() => JS('String', 'String(#)', this);
 }
 
-/**
- * Interceptor for plain JavaScript objects created as JavaScript object
- * literals or `new Object()`.
- */
+/// Interceptor for plain JavaScript objects created as JavaScript object
+/// literals or `new Object()`.
 class PlainJavaScriptObject extends JavaScriptObject {
   const PlainJavaScriptObject();
 }
 
-/**
- * Interceptor for unclassified JavaScript objects, typically objects with a
- * non-trivial prototype chain.
- *
- * This class also serves as a fallback for unknown JavaScript exceptions.
- */
+/// Interceptor for unclassified JavaScript objects, typically objects with a
+/// non-trivial prototype chain.
+///
+/// This class also serves as a fallback for unknown JavaScript exceptions.
 class UnknownJavaScriptObject extends JavaScriptObject {
   const UnknownJavaScriptObject();
 }
 
-/**
- * Interceptor for JavaScript function objects and Dart functions that have
- * been converted to JavaScript functions.
- * These interceptor methods are not always used as the JavaScript function
- * object has also been mangled to support Dart function calling conventions.
- */
+/// Interceptor for JavaScript function objects and Dart functions that have
+/// been converted to JavaScript functions.
+/// These interceptor methods are not always used as the JavaScript function
+/// object has also been mangled to support Dart function calling conventions.
 class JavaScriptFunction extends JavaScriptObject implements Function {
   const JavaScriptFunction();
 
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index 9d0a48e..c6956d9 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -10,12 +10,10 @@
 
 const _ListConstructorSentinel = const _Growable();
 
-/**
- * The interceptor class for [List]. The compiler recognizes this
- * class as an interceptor, and changes references to [:this:] to
- * actually use the receiver of the method, which is generated as an extra
- * argument added to each member.
- */
+/// The interceptor class for [List]. The compiler recognizes this
+/// class as an interceptor, and changes references to [:this:] to
+/// actually use the receiver of the method, which is generated as an extra
+/// argument added to each member.
 class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
   const JSArray();
 
@@ -28,11 +26,9 @@
     return new JSArray<E>.fixed(length);
   }
 
-  /**
-   * Returns a fresh JavaScript Array, marked as fixed-length.
-   *
-   * [length] must be a non-negative integer.
-   */
+  /// Returns a fresh JavaScript Array, marked as fixed-length.
+  ///
+  /// [length] must be a non-negative integer.
   factory JSArray.fixed(int length) {
     // Explicit type test is necessary to guard against JavaScript conversions
     // in unchecked mode, and against `new Array(null)` which creates a single
@@ -49,16 +45,12 @@
     return new JSArray<E>.markFixed(JS('', 'new Array(#)', length));
   }
 
-  /**
-   * Returns a fresh growable JavaScript Array of zero length length.
-   */
+  /// Returns a fresh growable JavaScript Array of zero length length.
   factory JSArray.emptyGrowable() => new JSArray<E>.markGrowable(JS('', '[]'));
 
-  /**
-   * Returns a fresh growable JavaScript Array with initial length.
-   *
-   * [validatedLength] must be a non-negative integer.
-   */
+  /// Returns a fresh growable JavaScript Array with initial length.
+  ///
+  /// [validatedLength] must be a non-negative integer.
   factory JSArray.growable(int length) {
     // Explicit type test is necessary to guard against JavaScript conversions
     // in unchecked mode.
@@ -68,20 +60,18 @@
     return new JSArray<E>.markGrowable(JS('', 'new Array(#)', length));
   }
 
-  /**
-   * Constructor for adding type parameters to an existing JavaScript Array.
-   * The compiler specially recognizes this constructor.
-   *
-   *     var a = new JSArray<int>.typed(JS('JSExtendableArray', '[]'));
-   *     a is List<int>    --> true
-   *     a is List<String> --> false
-   *
-   * Usually either the [JSArray.markFixed] or [JSArray.markGrowable]
-   * constructors is used instead.
-   *
-   * The input must be a JavaScript Array.  The JS form is just a re-assertion
-   * to help type analysis when the input type is sloppy.
-   */
+  /// Constructor for adding type parameters to an existing JavaScript Array.
+  /// The compiler specially recognizes this constructor.
+  ///
+  ///     var a = new JSArray<int>.typed(JS('JSExtendableArray', '[]'));
+  ///     a is List<int>    --> true
+  ///     a is List<String> --> false
+  ///
+  /// Usually either the [JSArray.markFixed] or [JSArray.markGrowable]
+  /// constructors is used instead.
+  ///
+  /// The input must be a JavaScript Array.  The JS form is just a re-assertion
+  /// to help type analysis when the input type is sloppy.
   factory JSArray.typed(allocation) => JS('JSArray', '#', allocation);
 
   factory JSArray.markFixed(allocation) =>
@@ -181,9 +171,7 @@
     return false;
   }
 
-  /**
-   * Removes elements matching [test] from [this] List.
-   */
+  /// Removes elements matching [test] from [this] List.
   void removeWhere(bool test(E element)) {
     checkGrowable('removeWhere');
     _removeWhere(test, true);
@@ -677,17 +665,15 @@
   }
 }
 
-/**
- * Dummy subclasses that allow the backend to track more precise
- * information about arrays through their type. The CPA type inference
- * relies on the fact that these classes do not override [] nor []=.
- *
- * These classes are really a fiction, and can have no methods, since
- * getInterceptor always returns JSArray.  We should consider pushing the
- * 'isGrowable' and 'isMutable' checks into the getInterceptor implementation so
- * these classes can have specialized implementations. Doing so will challenge
- * many assumptions in the JS backend.
- */
+/// Dummy subclasses that allow the backend to track more precise
+/// information about arrays through their type. The CPA type inference
+/// relies on the fact that these classes do not override [] nor []=.
+///
+/// These classes are really a fiction, and can have no methods, since
+/// getInterceptor always returns JSArray.  We should consider pushing the
+/// 'isGrowable' and 'isMutable' checks into the getInterceptor implementation
+/// so these classes can have specialized implementations. Doing so will
+/// challenge many assumptions in the JS backend.
 class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {}
 
 class JSFixedArray<E> extends JSMutableArray<E> {}
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 3338e9d..9457101 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -646,7 +646,7 @@
     return result;
   }
 
-  /** [: r"$".codeUnitAt(0) :] */
+  /// [: r"$".codeUnitAt(0) :]
   static const int DOLLAR_CHAR_VALUE = 36;
 
   /// Creates a string containing the complete type for the class [className]
@@ -1099,40 +1099,38 @@
         0));
   }
 
-  /**
-   * Implements [Function.apply] for the lazy and startup emitters.
-   *
-   * There are two types of closures that can reach this function:
-   *
-   * 1. tear-offs (including tear-offs of static functions).
-   * 2. anonymous closures.
-   *
-   * They are treated differently (although there are lots of similarities).
-   * Both have in common that they have
-   * a [JsGetName.CALL_CATCH_ALL] and
-   * a [JsGetName.REQUIRED_PARAMETER_PROPERTY] property.
-   *
-   * If the closure supports optional parameters, then they also feature
-   * a [JsGetName.DEFAULT_VALUES_PROPERTY] property.
-   *
-   * The catch-all property is a method that takes all arguments (including
-   * all optional positional or named arguments). If the function accepts
-   * optional arguments, then the default-values property stores (potentially
-   * wrapped in a function) the default values for the optional arguments. If
-   * the function accepts optional positional arguments, then the value is a
-   * JavaScript array with the default values. Otherwise, when the function
-   * accepts optional named arguments, it is a JavaScript object.
-   *
-   * The default-values property may either contain the value directly, or
-   * it can be a function that returns the default-values when invoked.
-   *
-   * If the function is an anonymous closure, then the catch-all property
-   * only contains a string pointing to the property that should be used
-   * instead. For example, if the catch-all property contains the string
-   * "call$4", then the object's "call$4" property should be used as if it was
-   * the value of the catch-all property.
-   */
-  static applyFunction2(Function function, List positionalArguments,
+  /// Implements [Function.apply] for the lazy and startup emitters.
+  ///
+  /// There are two types of closures that can reach this function:
+  ///
+  /// 1. tear-offs (including tear-offs of static functions).
+  /// 2. anonymous closures.
+  ///
+  /// They are treated differently (although there are lots of similarities).
+  /// Both have in common that they have
+  /// a [JsGetName.CALL_CATCH_ALL] and
+  /// a [JsGetName.REQUIRED_PARAMETER_PROPERTY] property.
+  ///
+  /// If the closure supports optional parameters, then they also feature
+  /// a [JsGetName.DEFAULT_VALUES_PROPERTY] property.
+  ///
+  /// The catch-all property is a method that takes all arguments (including
+  /// all optional positional or named arguments). If the function accepts
+  /// optional arguments, then the default-values property stores (potentially
+  /// wrapped in a function) the default values for the optional arguments. If
+  /// the function accepts optional positional arguments, then the value is a
+  /// JavaScript array with the default values. Otherwise, when the function
+  /// accepts optional named arguments, it is a JavaScript object.
+  ///
+  /// The default-values property may either contain the value directly, or
+  /// it can be a function that returns the default-values when invoked.
+  ///
+  /// If the function is an anonymous closure, then the catch-all property
+  /// only contains a string pointing to the property that should be used
+  /// instead. For example, if the catch-all property contains the string
+  /// "call$4", then the object's "call$4" property should be used as if it was
+  /// the value of the catch-all property.
+  static applyFunction(Function function, List positionalArguments,
       Map<String, dynamic> namedArguments) {
     // Fast shortcut for the common case.
     if (JS('bool', '# instanceof Array', positionalArguments) &&
@@ -1300,162 +1298,6 @@
     }
   }
 
-  static applyFunction(Function function, List positionalArguments,
-      Map<String, dynamic> namedArguments) {
-    // Dispatch on presence of named arguments to improve tree-shaking.
-    //
-    // This dispatch is as simple as possible to help the compiler detect the
-    // common case of `null` namedArguments, either via inlining or
-    // specialization.
-    return namedArguments == null
-        ? applyFunctionWithPositionalArguments(function, positionalArguments)
-        : applyFunctionWithNamedArguments(
-            function, positionalArguments, namedArguments);
-  }
-
-  static applyFunctionWithPositionalArguments(
-      Function function, List positionalArguments) {
-    List arguments;
-
-    if (positionalArguments != null) {
-      if (JS('bool', '# instanceof Array', positionalArguments)) {
-        arguments = JS('JSArray', '#', positionalArguments);
-      } else {
-        arguments = new List.from(positionalArguments);
-      }
-    } else {
-      arguments = [];
-    }
-
-    if (arguments.length == 0) {
-      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX0);
-      if (JS('bool', '!!#[#]', function, selectorName)) {
-        return JS('', '#[#]()', function, selectorName);
-      }
-    } else if (arguments.length == 1) {
-      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX1);
-      if (JS('bool', '!!#[#]', function, selectorName)) {
-        return JS('', '#[#](#[0])', function, selectorName, arguments);
-      }
-    } else if (arguments.length == 2) {
-      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX2);
-      if (JS('bool', '!!#[#]', function, selectorName)) {
-        return JS('', '#[#](#[0],#[1])', function, selectorName, arguments,
-            arguments);
-      }
-    } else if (arguments.length == 3) {
-      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX3);
-      if (JS('bool', '!!#[#]', function, selectorName)) {
-        return JS('', '#[#](#[0],#[1],#[2])', function, selectorName, arguments,
-            arguments, arguments);
-      }
-    } else if (arguments.length == 4) {
-      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
-      if (JS('bool', '!!#[#]', function, selectorName)) {
-        return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
-            arguments, arguments, arguments, arguments);
-      }
-    } else if (arguments.length == 5) {
-      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
-      if (JS('bool', '!!#[#]', function, selectorName)) {
-        return JS('', '#[#](#[0],#[1],#[2],#[3],#[4])', function, selectorName,
-            arguments, arguments, arguments, arguments, arguments);
-      }
-    }
-    return _genericApplyFunctionWithPositionalArguments(function, arguments);
-  }
-
-  static _genericApplyFunctionWithPositionalArguments(
-      Function function, List arguments) {
-    int argumentCount = arguments.length;
-    String selectorName =
-        '${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount';
-    var jsFunction = JS('var', '#[#]', function, selectorName);
-    if (jsFunction == null) {
-      var interceptor = getInterceptor(function);
-      jsFunction =
-          JS('', '#[#]', interceptor, JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
-
-      if (jsFunction == null) {
-        return functionNoSuchMethod(function, arguments, null);
-      }
-      ReflectionInfo info = new ReflectionInfo(jsFunction);
-      int requiredArgumentCount = info.requiredParameterCount;
-      int maxArgumentCount =
-          requiredArgumentCount + info.optionalParameterCount;
-      if (info.areOptionalParametersNamed ||
-          requiredArgumentCount > argumentCount ||
-          maxArgumentCount < argumentCount) {
-        return functionNoSuchMethod(function, arguments, null);
-      }
-      arguments = new List.from(arguments);
-      for (int pos = argumentCount; pos < maxArgumentCount; pos++) {
-        arguments.add(getMetadata(info.defaultValue(pos)));
-      }
-    }
-    // We bound 'this' to [function] because of how we compile
-    // closures: escaped local variables are stored and accessed through
-    // [function].
-    return JS('var', '#.apply(#, #)', jsFunction, function, arguments);
-  }
-
-  static applyFunctionWithNamedArguments(Function function,
-      List positionalArguments, Map<String, dynamic> namedArguments) {
-    if (namedArguments.isEmpty) {
-      return applyFunctionWithPositionalArguments(
-          function, positionalArguments);
-    }
-    // TODO(ahe): The following code can be shared with
-    // JsInstanceMirror.invoke.
-    var interceptor = getInterceptor(function);
-    var jsFunction =
-        JS('', '#[#]', interceptor, JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
-
-    if (jsFunction == null) {
-      return functionNoSuchMethod(
-          function, positionalArguments, namedArguments);
-    }
-    ReflectionInfo info = new ReflectionInfo(jsFunction);
-    if (info == null || !info.areOptionalParametersNamed) {
-      return functionNoSuchMethod(
-          function, positionalArguments, namedArguments);
-    }
-
-    if (positionalArguments != null) {
-      positionalArguments = new List.from(positionalArguments);
-    } else {
-      positionalArguments = [];
-    }
-    // Check the number of positional arguments is valid.
-    if (info.requiredParameterCount != positionalArguments.length) {
-      return functionNoSuchMethod(
-          function, positionalArguments, namedArguments);
-    }
-    var defaultArguments = new Map();
-    for (int i = 0; i < info.optionalParameterCount; i++) {
-      int index = i + info.requiredParameterCount;
-      var parameterName = info.parameterNameInOrder(index);
-      var value = info.defaultValueInOrder(index);
-      var defaultValue = getMetadata(value);
-      defaultArguments[parameterName] = defaultValue;
-    }
-    bool bad = false;
-    namedArguments.forEach((String parameter, value) {
-      if (defaultArguments.containsKey(parameter)) {
-        defaultArguments[parameter] = value;
-      } else {
-        // Extraneous named argument.
-        bad = true;
-      }
-    });
-    if (bad) {
-      return functionNoSuchMethod(
-          function, positionalArguments, namedArguments);
-    }
-    positionalArguments.addAll(defaultArguments.values);
-    return JS('', '#.apply(#, #)', jsFunction, function, positionalArguments);
-  }
-
   static StackTrace extractStackTrace(Error error) {
     return getTraceFromException(JS('', r'#.$thrownJsError', error));
   }
@@ -1484,32 +1326,27 @@
   }
 }
 
-/**
- * Called by generated code to throw an illegal-argument exception,
- * for example, if a non-integer index is given to an optimized
- * indexed access.
- */
+/// Called by generated code to throw an illegal-argument exception,
+/// for example, if a non-integer index is given to an optimized
+/// indexed access.
 @NoInline()
 iae(argument) {
   throw argumentErrorValue(argument);
 }
 
-/**
- * Called by generated code to throw an index-out-of-range exception, for
- * example, if a bounds check fails in an optimized indexed access.  This may
- * also be called when the index is not an integer, in which case it throws an
- * illegal-argument exception instead, like [iae], or when the receiver is null.
- */
+/// Called by generated code to throw an index-out-of-range exception, for
+/// example, if a bounds check fails in an optimized indexed access.  This may
+/// also be called when the index is not an integer, in which case it throws an
+/// illegal-argument exception instead, like [iae], or when the receiver is
+/// null.
 @NoInline()
 ioore(receiver, index) {
   if (receiver == null) receiver.length; // Force a NoSuchMethodError.
   throw diagnoseIndexError(receiver, index);
 }
 
-/**
- * Diagnoses an indexing error. Returns the ArgumentError or RangeError that
- * describes the problem.
- */
+/// Diagnoses an indexing error. Returns the ArgumentError or RangeError that
+/// describes the problem.
 @NoInline()
 Error diagnoseIndexError(indexable, index) {
   if (index is! int) return new ArgumentError.value(index, 'index');
@@ -1523,10 +1360,8 @@
   return new RangeError.value(index, 'index');
 }
 
-/**
- * Diagnoses a range error. Returns the ArgumentError or RangeError that
- * describes the problem.
- */
+/// Diagnoses a range error. Returns the ArgumentError or RangeError that
+/// describes the problem.
 @NoInline()
 Error diagnoseRangeError(start, end, length) {
   if (start is! int) {
@@ -1582,12 +1417,10 @@
   return value;
 }
 
-/**
- * Wrap the given Dart object and record a stack trace.
- *
- * The code in [unwrapException] deals with getting the original Dart
- * object out of the wrapper again.
- */
+/// Wrap the given Dart object and record a stack trace.
+///
+/// The code in [unwrapException] deals with getting the original Dart
+/// object out of the wrapper again.
 @NoInline()
 wrapException(ex) {
   if (ex == null) ex = new NullThrownError();
@@ -1619,12 +1452,10 @@
   return JS('', r'this.dartException').toString();
 }
 
-/**
- * This wraps the exception and does the throw.  It is possible to call this in
- * a JS expression context, where the throw statement is not allowed.  Helpers
- * are never inlined, so we don't risk inlining the throw statement into an
- * expression context.
- */
+/// This wraps the exception and does the throw.  It is possible to call this in
+/// a JS expression context, where the throw statement is not allowed.  Helpers
+/// are never inlined, so we don't risk inlining the throw statement into an
+/// expression context.
 throwExpression(ex) {
   JS('void', 'throw #', wrapException(ex));
 }
@@ -1666,9 +1497,7 @@
   throw new ConcurrentModificationError(collection);
 }
 
-/**
- * Helper class for building patterns recognizing native type errors.
- */
+/// Helper class for building patterns recognizing native type errors.
 class TypeErrorDecoder {
   // Field names are private to help tree-shaking.
 
@@ -2047,14 +1876,12 @@
   ExceptionAndStackTrace(this.dartException, this.stackTrace);
 }
 
-/**
- * Called from catch blocks in generated code to extract the Dart
- * exception from the thrown value. The thrown value may have been
- * created by [wrapException] or it may be a 'native' JS exception.
- *
- * Some native exceptions are mapped to new Dart instances, others are
- * returned unmodified.
- */
+/// Called from catch blocks in generated code to extract the Dart
+/// exception from the thrown value. The thrown value may have been
+/// created by [wrapException] or it may be a 'native' JS exception.
+///
+/// Some native exceptions are mapped to new Dart instances, others are
+/// returned unmodified.
 unwrapException(ex) {
   /// If error implements Error, save [ex] in [error.$thrownJsError].
   /// Otherwise, do nothing. Later, the stack trace can then be extracted from
@@ -2204,10 +2031,8 @@
       ex);
 }
 
-/**
- * Called by generated code to fetch the stack trace from an
- * exception. Should never return null.
- */
+/// Called by generated code to fetch the stack trace from an
+/// exception. Should never return null.
 StackTrace getTraceFromException(exception) {
   if (exception is ExceptionAndStackTrace) {
     return exception.stackTrace;
@@ -2244,10 +2069,8 @@
   }
 }
 
-/**
- * Called by generated code to build a map literal. [keyValuePairs] is
- * a list of key, value, key, value, ..., etc.
- */
+/// Called by generated code to build a map literal. [keyValuePairs] is
+/// a list of key, value, key, value, ..., etc.
 fillLiteralMap(keyValuePairs, Map result) {
   // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
   // [getLength] and [getIndex].
@@ -2278,10 +2101,8 @@
   throw new Exception('Unsupported number of arguments for wrapped closure');
 }
 
-/**
- * Called by generated code to convert a Dart closure to a JS
- * closure when the Dart closure is passed to the DOM.
- */
+/// Called by generated code to convert a Dart closure to a JS
+/// closure when the Dart closure is passed to the DOM.
 convertDartClosureToJS(closure, int arity) {
   if (closure == null) return null;
   var function = JS('var', r'#.$identity', closure);
@@ -2318,40 +2139,36 @@
   static const OPTIONAL_PARAMETER_INDEX = 4;
   static const DEFAULT_ARGUMENTS_INDEX = 5;
 
-  /**
-   * Global counter to prevent reusing function code objects.
-   *
-   * V8 will share the underlying function code objects when the same string is
-   * passed to "new Function".  Shared function code objects can lead to
-   * sub-optimal performance due to polymorphism, and can be prevented by
-   * ensuring the strings are different, for example, by generating a local
-   * variable with a name dependent on [functionCounter].
-   */
+  /// Global counter to prevent reusing function code objects.
+  ///
+  /// V8 will share the underlying function code objects when the same string is
+  /// passed to "new Function".  Shared function code objects can lead to
+  /// sub-optimal performance due to polymorphism, and can be prevented by
+  /// ensuring the strings are different, for example, by generating a local
+  /// variable with a name dependent on [functionCounter].
   static int functionCounter = 0;
 
   Closure();
 
-  /**
-   * Creates a new closure class for use by implicit getters associated with a
-   * method.
-   *
-   * In other words, creates a tear-off closure.
-   *
-   * Called from [closureFromTearOff] as well as from reflection when tearing
-   * of a method via `getField`.
-   *
-   * This method assumes that [functions] was created by the JavaScript function
-   * `addStubs` in `reflection_data_parser.dart`. That is, a list of JavaScript
-   * function objects with properties `$stubName` and `$callName`.
-   *
-   * Further assumes that [reflectionInfo] is the end of the array created by
-   * [dart2js.js_emitter.ContainerBuilder.addMemberMethod] starting with
-   * required parameter count or, in case of the new emitter, the runtime
-   * representation of the function's type.
-   *
-   * Caution: this function may be called when building constants.
-   * TODO(ahe): Don't call this function when building constants.
-   */
+  /// Creates a new closure class for use by implicit getters associated with a
+  /// method.
+  ///
+  /// In other words, creates a tear-off closure.
+  ///
+  /// Called from [closureFromTearOff] as well as from reflection when tearing
+  /// of a method via `getField`.
+  ///
+  /// This method assumes that [functions] was created by the JavaScript
+  /// function `addStubs` in `reflection_data_parser.dart`. That is, a list of
+  /// JavaScript function objects with properties `$stubName` and `$callName`.
+  ///
+  /// Further assumes that [reflectionInfo] is the end of the array created by
+  /// [dart2js.js_emitter.ContainerBuilder.addMemberMethod] starting with
+  /// required parameter count or, in case of the new emitter, the runtime
+  /// representation of the function's type.
+  ///
+  /// Caution: this function may be called when building constants.
+  /// TODO(ahe): Don't call this function when building constants.
   static fromTearOff(
     receiver,
     List functions,
@@ -2913,101 +2730,91 @@
   return JS('var', r'#[#]', jsObject, property);
 }
 
-/**
- * Called at the end of unaborted switch cases to get the singleton
- * FallThroughError exception that will be thrown.
- */
+/// Called at the end of unaborted switch cases to get the singleton
+/// FallThroughError exception that will be thrown.
 getFallThroughError() => new FallThroughErrorImplementation();
 
-/**
- * A metadata annotation describing the types instantiated by a native element.
- *
- * The annotation is valid on a native method and a field of a native class.
- *
- * By default, a field of a native class is seen as an instantiation point for
- * all native classes that are a subtype of the field's type, and a native
- * method is seen as an instantiation point fo all native classes that are a
- * subtype of the method's return type, or the argument types of the declared
- * type of the method's callback parameter.
- *
- * An @[Creates] annotation overrides the default set of instantiated types.  If
- * one or more @[Creates] annotations are present, the type of the native
- * element is ignored, and the union of @[Creates] annotations is used instead.
- * The names in the strings are resolved and the program will fail to compile
- * with dart2js if they do not name types.
- *
- * The argument to [Creates] is a string.  The string is parsed as the names of
- * one or more types, separated by vertical bars `|`.  There are some special
- * names:
- *
- * * `=Object`. This means 'exactly Object', which is a plain JavaScript object
- *   with properties and none of the subtypes of Object.
- *
- * Example: we may know that a method always returns a specific implementation:
- *
- *     @Creates('_NodeList')
- *     List<Node> getElementsByTagName(String tag) native;
- *
- * Useful trick: A method can be marked as not instantiating any native classes
- * with the annotation `@Creates('Null')`.  This is useful for fields on native
- * classes that are used only in Dart code.
- *
- *     @Creates('Null')
- *     var _cachedFoo;
- */
+/// A metadata annotation describing the types instantiated by a native element.
+///
+/// The annotation is valid on a native method and a field of a native class.
+///
+/// By default, a field of a native class is seen as an instantiation point for
+/// all native classes that are a subtype of the field's type, and a native
+/// method is seen as an instantiation point fo all native classes that are a
+/// subtype of the method's return type, or the argument types of the declared
+/// type of the method's callback parameter.
+///
+/// An @[Creates] annotation overrides the default set of instantiated types.
+/// If one or more @[Creates] annotations are present, the type of the native
+/// element is ignored, and the union of @[Creates] annotations is used instead.
+/// The names in the strings are resolved and the program will fail to compile
+/// with dart2js if they do not name types.
+///
+/// The argument to [Creates] is a string.  The string is parsed as the names of
+/// one or more types, separated by vertical bars `|`.  There are some special
+/// names:
+///
+/// * `=Object`. This means 'exactly Object', which is a plain JavaScript object
+///   with properties and none of the subtypes of Object.
+///
+/// Example: we may know that a method always returns a specific implementation:
+///
+///     @Creates('_NodeList')
+///     List<Node> getElementsByTagName(String tag) native;
+///
+/// Useful trick: A method can be marked as not instantiating any native classes
+/// with the annotation `@Creates('Null')`.  This is useful for fields on native
+/// classes that are used only in Dart code.
+///
+///     @Creates('Null')
+///     var _cachedFoo;
 class Creates {
   final String types;
   const Creates(this.types);
 }
 
-/**
- * A metadata annotation describing the types returned or yielded by a native
- * element.
- *
- * The annotation is valid on a native method and a field of a native class.
- *
- * By default, a native method or field is seen as returning or yielding all
- * subtypes if the method return type or field type.  This annotation allows a
- * more precise set of types to be specified.
- *
- * See [Creates] for the syntax of the argument.
- *
- * Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
- *
- *     @Returns('String|num|JSExtendableArray')
- *     dynamic key;
- *
- *     // Equivalent:
- *     @Returns('String') @Returns('num') @Returns('JSExtendableArray')
- *     dynamic key;
- */
+/// A metadata annotation describing the types returned or yielded by a native
+/// element.
+///
+/// The annotation is valid on a native method and a field of a native class.
+///
+/// By default, a native method or field is seen as returning or yielding all
+/// subtypes if the method return type or field type.  This annotation allows a
+/// more precise set of types to be specified.
+///
+/// See [Creates] for the syntax of the argument.
+///
+/// Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
+///
+///     @Returns('String|num|JSExtendableArray')
+///     dynamic key;
+///
+///     // Equivalent:
+///     @Returns('String') @Returns('num') @Returns('JSExtendableArray')
+///     dynamic key;
 class Returns {
   final String types;
   const Returns(this.types);
 }
 
-/**
- * A metadata annotation placed on native methods and fields of native classes
- * to specify the JavaScript name.
- *
- * This example declares a Dart field + getter + setter called `$dom_title` that
- * corresponds to the JavaScript property `title`.
- *
- *     class Document native "*Foo" {
- *       @JSName('title')
- *       String $dom_title;
- *     }
- */
+/// A metadata annotation placed on native methods and fields of native classes
+/// to specify the JavaScript name.
+///
+/// This example declares a Dart field + getter + setter called `$dom_title`
+/// that corresponds to the JavaScript property `title`.
+///
+///     class Document native "*Foo" {
+///       @JSName('title')
+///       String $dom_title;
+///     }
 class JSName {
   final String name;
   const JSName(this.name);
 }
 
-/**
- * The following methods are called by the runtime to implement
- * checked mode and casts. We specialize each primitive type (eg int, bool), and
- * use the compiler's convention to do is-checks on regular objects.
- */
+/// The following methods are called by the runtime to implement checked mode
+/// and casts. We specialize each primitive type (eg int, bool), and use the
+/// compiler's convention to do is-checks on regular objects.
 boolConversionCheck(value) {
   if (value is bool) return value;
   // One of the following checks will always fail.
@@ -3082,32 +2889,26 @@
   throw new CastErrorImplementation(value, unminifyOrTag(name));
 }
 
-/**
- * For types that are not supertypes of native (eg DOM) types,
- * we emit a simple property check to check that an object implements
- * that type.
- */
+/// For types that are not supertypes of native (eg DOM) types,
+/// we emit a simple property check to check that an object implements
+/// that type.
 propertyTypeCheck(value, property) {
   if (value == null) return value;
   if (JS('bool', '!!#[#]', value, property)) return value;
   propertyTypeError(value, property);
 }
 
-/**
- * For types that are not supertypes of native (eg DOM) types,
- * we emit a simple property check to check that an object implements
- * that type.
- */
+/// For types that are not supertypes of native (eg DOM) types,
+/// we emit a simple property check to check that an object implements
+/// that type.
 propertyTypeCast(value, property) {
   if (value == null || JS('bool', '!!#[#]', value, property)) return value;
   propertyTypeCastError(value, property);
 }
 
-/**
- * For types that are supertypes of native (eg DOM) types, we use the
- * interceptor for the class because we cannot add a JS property to the
- * prototype at load time.
- */
+/// For types that are supertypes of native (eg DOM) types, we use the
+/// interceptor for the class because we cannot add a JS property to the
+/// prototype at load time.
 interceptedTypeCheck(value, property) {
   if (value == null) return value;
   if ((JS('bool', 'typeof # === "object"', value) ||
@@ -3118,11 +2919,9 @@
   propertyTypeError(value, property);
 }
 
-/**
- * For types that are supertypes of native (eg DOM) types, we use the
- * interceptor for the class because we cannot add a JS property to the
- * prototype at load time.
- */
+/// For types that are supertypes of native (eg DOM) types, we use the
+/// interceptor for the class because we cannot add a JS property to the
+/// prototype at load time.
 interceptedTypeCast(value, property) {
   if (value == null ||
       ((JS('bool', 'typeof # === "object"', value) ||
@@ -3133,10 +2932,8 @@
   propertyTypeCastError(value, property);
 }
 
-/**
- * Specialization of the type check for num and String and their
- * supertype since [value] can be a JS primitive.
- */
+/// Specialization of the type check for num and String and their
+/// supertype since [value] can be a JS primitive.
 numberOrStringSuperTypeCheck(value, property) {
   if (value == null) return value;
   if (value is String) return value;
@@ -3167,10 +2964,8 @@
   propertyTypeCastError(value, property);
 }
 
-/**
- * Specialization of the type check for String and its supertype
- * since [value] can be a JS primitive.
- */
+/// Specialization of the type check for String and its supertype
+/// since [value] can be a JS primitive.
 stringSuperTypeCheck(value, property) {
   if (value == null) return value;
   if (value is String) return value;
@@ -3196,10 +2991,8 @@
   propertyTypeCastError(value, property);
 }
 
-/**
- * Specialization of the type check for List and its supertypes,
- * since [value] can be a JS array.
- */
+/// Specialization of the type check for List and its supertypes,
+/// since [value] can be a JS array.
 listTypeCheck(value) {
   if (value == null) return value;
   if (value is List) return value;
@@ -3314,17 +3107,15 @@
   }
 }
 
-/**
- * Special interface recognized by the compiler and implemented by DOM
- * objects that support integer indexing. This interface is not
- * visible to anyone, and is only injected into special libraries.
- */
+/// Special interface recognized by the compiler and implemented by DOM
+/// objects that support integer indexing. This interface is not
+/// visible to anyone, and is only injected into special libraries.
 abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
 
 // TODO(lrn): These exceptions should be implemented in core.
 // When they are, remove the 'Implementation' here.
 
-/** Thrown by type assertions that fail. */
+/// Thrown by type assertions that fail.
 class TypeErrorImplementation extends Error implements TypeError {
   final String message;
 
@@ -3338,7 +3129,7 @@
   String toString() => message;
 }
 
-/** Thrown by the 'as' operator if the cast isn't valid. */
+/// Thrown by the 'as' operator if the cast isn't valid.
 class CastErrorImplementation extends Error implements CastError {
   // TODO(lrn): Rename to CastError (and move implementation into core).
   final String message;
@@ -3367,12 +3158,11 @@
   String toString() => 'Switch case fall-through.';
 }
 
-/**
- * Helper function for implementing asserts. The compiler treats this specially.
- *
- * Returns the negation of the condition. That is: `true` if the assert should
- * fail.
- */
+/// Helper function for implementing asserts. The compiler treats this
+/// specially.
+///
+/// Returns the negation of the condition. That is: `true` if the assert should
+/// fail.
 bool assertTest(condition) {
   // Do bool success check first, it is common and faster than 'is Function'.
   if (true == condition) return false;
@@ -3380,44 +3170,34 @@
   throw new TypeErrorImplementation(condition, 'bool');
 }
 
-/**
- * Helper function for implementing asserts with messages.
- * The compiler treats this specially.
- */
+/// Helper function for implementing asserts with messages.
+/// The compiler treats this specially.
 void assertThrow(Object message) {
   throw new _AssertionError(message);
 }
 
-/**
- * Helper function for implementing asserts without messages.
- * The compiler treats this specially.
- */
+/// Helper function for implementing asserts without messages.
+/// The compiler treats this specially.
 @NoInline()
 void assertHelper(condition) {
   if (assertTest(condition)) throw new AssertionError();
 }
 
-/**
- * Called by generated code when a method that must be statically
- * resolved cannot be found.
- */
+/// Called by generated code when a method that must be statically
+/// resolved cannot be found.
 void throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {
   Symbol memberName = new _symbol_dev.Symbol.unvalidated(name);
   throw new NoSuchMethodError(obj, memberName, arguments,
       new Map<Symbol, dynamic>(), expectedArgumentNames);
 }
 
-/**
- * Called by generated code when a static field's initializer references the
- * field that is currently being initialized.
- */
+/// Called by generated code when a static field's initializer references the
+/// field that is currently being initialized.
 void throwCyclicInit(String staticName) {
   throw new CyclicInitializationError(staticName);
 }
 
-/**
- * Error thrown when a runtime error occurs.
- */
+/// Error thrown when a runtime error occurs.
 class RuntimeError extends Error {
   final message;
   RuntimeError(this.message);
@@ -3444,11 +3224,9 @@
   String toString() => 'Unsupported operation: $_message';
 }
 
-/**
- * Creates a random number with 64 bits of randomness.
- *
- * This will be truncated to the 53 bits available in a double.
- */
+/// Creates a random number with 64 bits of randomness.
+///
+/// This will be truncated to the 53 bits available in a double.
 int random64() {
   // TODO(lrn): Use a secure random source.
   int int32a = JS('int', '(Math.random() * 0x100000000) >>> 0');
@@ -3460,14 +3238,12 @@
   return JS('String', 'JSON.stringify(#)', string);
 }
 
-/**
- * Returns a property name for placing data on JavaScript objects shared between
- * DOM isolates.  This happens when multiple programs are loaded in the same
- * JavaScript context (i.e. page).  The name is based on [name] but with an
- * additional part that is unique for each isolate.
- *
- * The form of the name is '___dart_$name_$id'.
- */
+/// Returns a property name for placing data on JavaScript objects shared
+/// between DOM isolates.  This happens when multiple programs are loaded in the
+/// same JavaScript context (i.e. page).  The name is based on [name] but with
+/// an additional part that is unique for each isolate.
+///
+/// The form of the name is '___dart_$name_$id'.
 String getIsolateAffinityTag(String name) {
   var isolateTagGetter = JS_EMBEDDED_GLOBAL('', GET_ISOLATE_TAG);
   return JS('String', '#(#)', isolateTagGetter, name);
diff --git a/sdk/lib/_internal/js_runtime/lib/js_names.dart b/sdk/lib/_internal/js_runtime/lib/js_names.dart
index d3eaa07..572d354 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_names.dart
@@ -139,17 +139,15 @@
   return new JSArray.markFixed(result);
 }
 
-/**
- * Returns the (global) unmangled version of [name].
- *
- * Normally, you should use [mangledGlobalNames] directly, but this method
- * doesn't tell the compiler to preserve names. So this method only returns a
- * non-null value if some other component has made the compiler preserve names.
- *
- * This is used, for example, to return unmangled names from TypeImpl.toString
- * *if* names are being preserved for other reasons (use of dart:mirrors, for
- * example).
- */
+/// Returns the (global) unmangled version of [name].
+///
+/// Normally, you should use [mangledGlobalNames] directly, but this method
+/// doesn't tell the compiler to preserve names. So this method only returns a
+/// non-null value if some other component has made the compiler preserve names.
+///
+/// This is used, for example, to return unmangled names from TypeImpl.toString
+/// *if* names are being preserved for other reasons (use of dart:mirrors, for
+/// example).
 String unmangleGlobalNameIfPreservedAnyways(String name) {
   var names = JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES);
   return JsCache.fetch(names, name);
diff --git a/sdk/lib/_internal/js_runtime/lib/js_number.dart b/sdk/lib/_internal/js_runtime/lib/js_number.dart
index 58e5e55..1c030f3 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_number.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_number.dart
@@ -4,15 +4,13 @@
 
 part of _interceptors;
 
-/**
- * The super interceptor class for [JSInt] and [JSDouble]. The compiler
- * recognizes this class as an interceptor, and changes references to
- * [:this:] to actually use the receiver of the method, which is
- * generated as an extra argument added to each member.
- *
- * Note that none of the methods here delegate to a method defined on JSInt or
- * JSDouble.  This is exploited in [tryComputeConstantInterceptor].
- */
+/// The super interceptor class for [JSInt] and [JSDouble]. The compiler
+/// recognizes this class as an interceptor, and changes references to
+/// [:this:] to actually use the receiver of the method, which is
+/// generated as an extra argument added to each member.
+///
+/// Note that none of the methods here delegate to a method defined on JSInt or
+/// JSDouble.  This is exploited in [tryComputeConstantInterceptor].
 class JSNumber extends Interceptor implements double {
   const JSNumber();
 
@@ -241,7 +239,40 @@
     }
   }
 
-  int get hashCode => JS('int', '# & 0x1FFFFFFF', this);
+  int get hashCode {
+    int intValue = JS('int', '# | 0', this);
+    // Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
+    // and ensures that result fits in JavaScript engine's Smi range.
+    if (this == intValue) return 0x1FFFFFFF & intValue;
+
+    // We would like to access the exponent and mantissa as integers but there
+    // are no JavaScript operations that do this, so use log2-floor-pow-divide
+    // to extract the values.
+    num absolute = JS('num', 'Math.abs(#)', this);
+    num lnAbsolute = JS('num', 'Math.log(#)', absolute);
+    num log2 = lnAbsolute / ln2;
+    // Floor via '# | 0' converts NaN to zero so the final result is not NaN.
+    int floorLog2 = JS('int', '# | 0', log2);
+    num factor = JS('num', 'Math.pow(2, #)', floorLog2);
+    num scaled = absolute < 1 ? absolute / factor : factor / absolute;
+    // [scaled] is in the range [0.5, 1].
+
+    // Multiply and truncate to pick up all the mantissa bits. Multiplying by
+    // 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
+    // integer. There are interesting subsets where all the bit variance is in
+    // the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
+    // need to mix in the most significant bits. We do this by scaling with a
+    // constant that has many bits set to use the multiplier to mix in bits from
+    // all over the mantissa into low positions.
+    num rescaled1 = scaled * 0x20000000000000;
+    num rescaled2 = scaled * 0x0C95A6C285A6C9;
+    int d1 = JS('int', '# | 0', rescaled1);
+    int d2 = JS('int', '# | 0', rescaled2);
+    // Mix in exponent to distinguish e.g. 1.25 from 2.5.
+    int d3 = floorLog2;
+    int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
+    return h;
+  }
 
   JSNumber operator -() => JS('num', r'-#', this);
 
@@ -411,14 +442,12 @@
   Type get runtimeType => num;
 }
 
-/**
- * The interceptor class for [int]s.
- *
- * This class implements double (indirectly through JSNumber) since in
- * JavaScript all numbers are doubles, so while we want to treat `2.0` as an
- * integer for some operations, its interceptor should answer `true` to `is
- * double`.
- */
+/// The interceptor class for [int]s.
+///
+/// This class implements double (indirectly through JSNumber) since in
+/// JavaScript all numbers are doubles, so while we want to treat `2.0` as an
+/// integer for some operations, its interceptor should answer `true` to `is
+/// double`.
 class JSInt extends JSNumber implements int {
   const JSInt();
 
diff --git a/sdk/lib/_internal/js_runtime/lib/js_primitives.dart b/sdk/lib/_internal/js_runtime/lib/js_primitives.dart
index 40c451c..97577a0 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_primitives.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_primitives.dart
@@ -8,15 +8,13 @@
 
 import 'dart:_foreign_helper' show JS;
 
-/**
- * This is the low-level method that is used to implement [print].  It is
- * possible to override this function from JavaScript by defining a function in
- * JavaScript called "dartPrint".
- *
- * Notice that it is also possible to intercept calls to [print] from within a
- * Dart program using zones. This means that there is no guarantee that a call
- * to print ends in this method.
- */
+/// This is the low-level method that is used to implement [print].  It is
+/// possible to override this function from JavaScript by defining a function in
+/// JavaScript called "dartPrint".
+///
+/// Notice that it is also possible to intercept calls to [print] from within a
+/// Dart program using zones. This means that there is no guarantee that a call
+/// to print ends in this method.
 void printString(String string) {
   if (JS('bool', r'typeof dartPrint == "function"')) {
     // Support overriding print from JavaScript.
diff --git a/sdk/lib/_internal/js_runtime/lib/js_rti.dart b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
index b5e84fa..9a6ef99 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
@@ -2,43 +2,41 @@
 // for 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 part contains helpers for supporting runtime type information.
- *
- * The helper use a mixture of Dart and JavaScript objects. To indicate which is
- * used where we adopt the scheme of using explicit type annotation for Dart
- * objects and 'var' or omitted return type for JavaScript objects.
- *
- * Since bool, int, and String values are represented by the same JavaScript
- * primitives, type annotations are used for these types in all cases.
- *
- * Several methods use a common JavaScript encoding of runtime type information.
- * This encoding is referred to as the type representation which is one of
- * these:
- *  1) a JavaScript constructor for a class C: the represented type is the raw
- *     type C.
- *  2) a JavaScript array: the first entry is of type 1 and contains the
- *     subtyping flags and the substitution of the type and the rest of the
- *     array are the type arguments.
- *  3) `null`: the dynamic type.
- *  4) a JavaScript object representing the function type. For instance, it has
- *     the form {ret: rti, args: [rti], opt: [rti], named: {name: rti}} for a
- *     function with a return type, regular, optional and named arguments.
- *     Generic function types have a 'bounds' property.
- *
- * To check subtype relations between generic classes we use a JavaScript
- * expression that describes the necessary substitution for type arguments.
- * Such a substitution expression can be:
- *  1) `null`, if no substituted check is necessary, because the
- *     type variables are the same or there are no type variables in the class
- *     that is checked for.
- *  2) A list expression describing the type arguments to be used in the
- *     subtype check, if the type arguments to be used in the check do not
- *     depend on the type arguments of the object.
- *  3) A function mapping the type variables of the object to be checked to
- *     a list expression. The function may also return null, which is equivalent
- *     to an array containing only null values.
- */
+/// This part contains helpers for supporting runtime type information.
+///
+/// The helper use a mixture of Dart and JavaScript objects. To indicate which
+/// is used where we adopt the scheme of using explicit type annotation for Dart
+/// objects and 'var' or omitted return type for JavaScript objects.
+///
+/// Since bool, int, and String values are represented by the same JavaScript
+/// primitives, type annotations are used for these types in all cases.
+///
+/// Several methods use a common JavaScript encoding of runtime type
+/// information.  This encoding is referred to as the type representation which
+/// is one of these:
+///  1) a JavaScript constructor for a class C: the represented type is the raw
+///     type C.
+///  2) a JavaScript array: the first entry is of type 1 and contains the
+///     subtyping flags and the substitution of the type and the rest of the
+///     array are the type arguments.
+///  3) `null`: the dynamic type.
+///  4) a JavaScript object representing the function type. For instance, it has
+///     the form {ret: rti, args: [rti], opt: [rti], named: {name: rti}} for a
+///     function with a return type, regular, optional and named arguments.
+///     Generic function types have a 'bounds' property.
+///
+/// To check subtype relations between generic classes we use a JavaScript
+/// expression that describes the necessary substitution for type arguments.
+/// Such a substitution expression can be:
+///  1) `null`, if no substituted check is necessary, because the
+///     type variables are the same or there are no type variables in the class
+///     that is checked for.
+///  2) A list expression describing the type arguments to be used in the
+///     subtype check, if the type arguments to be used in the check do not
+///     depend on the type arguments of the object.
+///  3) A function mapping the type variables of the object to be checked to a
+///     list expression. The function may also return null, which is equivalent
+///     to an array containing only null values.
 
 part of _js_helper;
 
@@ -67,12 +65,10 @@
   }
 }
 
-/**
- * Represents a type variable.
- *
- * This class holds the information needed when reflecting on generic classes
- * and their members.
- */
+/// Represents a type variable.
+///
+/// This class holds the information needed when reflecting on generic classes
+/// and their members.
 class TypeVariable {
   final Type owner;
   final String name;
@@ -157,10 +153,8 @@
   return rti == null ? null : getIndex(rti, index);
 }
 
-/**
- * Retrieves the class name from type information stored on the constructor
- * of [object].
- */
+/// Retrieves the class name from type information stored on the constructor
+/// of [object].
 String getClassName(var object) {
   return rawRtiToJsConstructorName(getRawRuntimeType(getInterceptor(object)));
 }
@@ -327,11 +321,9 @@
   return '${typeParameters}(${argumentsText}) => ${returnTypeText}';
 }
 
-/**
- * Creates a comma-separated string of human-readable representations of the
- * type representations in the JavaScript array [types] starting at index
- * [startIndex].
- */
+/// Creates a comma-separated string of human-readable representations of the
+/// type representations in the JavaScript array [types] starting at index
+/// [startIndex].
 String joinArguments(var types, int startIndex) {
   return _joinArguments(types, startIndex, null);
 }
@@ -354,11 +346,9 @@
   return '<$buffer>';
 }
 
-/**
- * Returns a human-readable representation of the type of [object].
- *
- * In minified mode does *not* use unminified identifiers (even when present).
- */
+/// Returns a human-readable representation of the type of [object].
+///
+/// In minified mode does *not* use unminified identifiers (even when present).
 String getRuntimeTypeString(var object) {
   if (object is Closure) {
     // This excludes classes that implement Function via a `call` method, but
@@ -403,12 +393,10 @@
   return new TypeImpl(getRti(object));
 }
 
-/**
- * Applies the [substitution] on the [arguments].
- *
- * See the comment in the beginning of this file for a description of the
- * possible values for [substitution].
- */
+/// Applies the [substitution] on the [arguments].
+///
+/// See the comment in the beginning of this file for a description of the
+/// possible values for [substitution].
 substitute(var substitution, var arguments) {
   if (substitution == null) return arguments;
   assert(isJsFunction(substitution));
@@ -429,18 +417,16 @@
   return arguments;
 }
 
-/**
- * Perform a type check with arguments on the Dart object [object].
- *
- * Parameters:
- * - [isField]: the name of the flag/function to check if the object
- *   is of the correct class.
- * - [checks]: the (JavaScript) list of type representations for the
- *   arguments to check against.
- * - [asField]: the name of the function that transforms the type
- *   arguments of [objects] to an instance of the class that we check
- *   against.
- */
+/// Perform a type check with arguments on the Dart object [object].
+///
+/// Parameters:
+/// - [isField]: the name of the flag/function to check if the object
+///   is of the correct class.
+/// - [checks]: the (JavaScript) list of type representations for the
+///   arguments to check against.
+/// - [asField]: the name of the function that transforms the type
+///   arguments of [objects] to an instance of the class that we check
+///   against.
 bool checkSubtype(Object object, String isField, List checks, String asField) {
   if (object == null) return false;
   var arguments = getRuntimeTypeInfo(object);
@@ -507,17 +493,15 @@
   return areSubtypes(substitute(substitution, arguments), sEnv, checks, tEnv);
 }
 
-/**
- * Checks whether the types of [s] are all subtypes of the types of [t].
- *
- * [s] and [t] are either `null` or JavaScript arrays of type representations,
- * A `null` argument is interpreted as the arguments of a raw type, that is a
- * list of `dynamic`. If [s] and [t] are JavaScript arrays they must be of the
- * same length.
- *
- * See the comment in the beginning of this file for a description of type
- * representations.
- */
+/// Checks whether the types of [s] are all subtypes of the types of [t].
+///
+/// [s] and [t] are either `null` or JavaScript arrays of type representations,
+/// A `null` argument is interpreted as the arguments of a raw type, that is a
+/// list of `dynamic`. If [s] and [t] are JavaScript arrays they must be of the
+/// same length.
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
 
 bool areSubtypes(var s, var sEnv, var t, var tEnv) {
   // `null` means a raw type.
@@ -545,10 +529,8 @@
   return true;
 }
 
-/**
- * Computes the signature by applying the type arguments of [context] as an
- * instance of [contextName] to the signature function [signature].
- */
+/// Computes the signature by applying the type arguments of [context] as an
+/// instance of [contextName] to the signature function [signature].
 computeSignature(var signature, var context, var contextName) {
   var interceptor = getInterceptor(context);
   var typeArguments =
@@ -619,13 +601,11 @@
       : null;
 }
 
-/**
- * Tests whether the Dart object [o] is a subtype of the runtime type
- * representation [t].
- *
- * See the comment in the beginning of this file for a description of type
- * representations.
- */
+/// Tests whether the Dart object [o] is a subtype of the runtime type
+/// representation [t].
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
 bool checkSubtypeOfRuntimeType(o, t) {
   if (o == null) return isSupertypeOfNull(t);
   if (isTopType(t)) return true;
@@ -678,24 +658,20 @@
   return object;
 }
 
-/**
- * Extracts the type arguments from a type representation. The result is a
- * JavaScript array or `null`.
- */
+/// Extracts the type arguments from a type representation. The result is a
+/// JavaScript array or `null`.
 getArguments(var type) {
   return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null;
 }
 
-/**
- * Checks whether the type represented by the type representation [s] is a
- * subtype of the type represented by the type representation [t].
- *
- * See the comment in the beginning of this file for a description of type
- * representations.
- *
- * The arguments [s] and [t] must be types, usually represented by the
- * constructor of the class, or an array (for generic class types).
- */
+/// Checks whether the type represented by the type representation [s] is a
+/// subtype of the type represented by the type representation [t].
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+///
+/// The arguments [s] and [t] must be types, usually represented by the
+/// constructor of the class, or an array (for generic class types).
 bool isSubtype(var s, var t) {
   return _isSubtype(s, null, t, null);
 }
@@ -1075,16 +1051,12 @@
   return array;
 }
 
-/**
- * Calls the JavaScript [function] with the [arguments] with the global scope
- * as the `this` context.
- */
+/// Calls the JavaScript [function] with the [arguments] with the global scope
+/// as the `this` context.
 invoke(var function, var arguments) => invokeOn(function, null, arguments);
 
-/**
- * Calls the JavaScript [function] with the [arguments] with [receiver] as the
- * `this` context.
- */
+/// Calls the JavaScript [function] with the [arguments] with [receiver] as the
+/// `this` context.
 Object invokeOn(function, receiver, arguments) {
   assert(isJsFunction(function));
   assert(arguments == null || isJsArray(arguments));
@@ -1132,18 +1104,14 @@
 /// Returns `true` if [o] is a JavaScript object.
 bool isJsObject(var o) => JS('bool', r"typeof # == 'object'", o);
 
-/**
- * Returns `true` if the JavaScript values [s] and [t] are identical. We use
- * this helper instead of [identical] because `identical` needs to merge
- * `null` and `undefined` (which we can avoid).
- */
+/// Returns `true` if the JavaScript values [s] and [t] are identical. We use
+/// this helper instead of [identical] because `identical` needs to merge
+/// `null` and `undefined` (which we can avoid).
 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t);
 
-/**
- * Returns `true` if the JavaScript values [s] and [t] are not identical. We use
- * this helper instead of [identical] because `identical` needs to merge
- * `null` and `undefined` (which we can avoid).
- */
+/// Returns `true` if the JavaScript values [s] and [t] are not identical. We
+/// use this helper instead of [identical] because `identical` needs to merge
+/// `null` and `undefined` (which we can avoid).
 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t);
 
 /// 'Top' bounds are uninteresting: null/undefined and Object.
diff --git a/sdk/lib/_internal/js_runtime/lib/js_string.dart b/sdk/lib/_internal/js_runtime/lib/js_string.dart
index 91e9734..baa47b6 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_string.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_string.dart
@@ -4,12 +4,10 @@
 
 part of _interceptors;
 
-/**
- * The interceptor class for [String]. The compiler recognizes this
- * class as an interceptor, and changes references to [:this:] to
- * actually use the receiver of the method, which is generated as an extra
- * argument added to each member.
- */
+/// The interceptor class for [String]. The compiler recognizes this
+/// class as an interceptor, and changes references to [:this:] to
+/// actually use the receiver of the method, which is generated as an extra
+/// argument added to each member.
 class JSString extends Interceptor implements String, JSIndexable {
   const JSString();
 
@@ -443,12 +441,10 @@
   // Note: if you change this, also change the function [S].
   String toString() => this;
 
-  /**
-   * This is the [Jenkins hash function][1] but using masking to keep
-   * values in SMI range.
-   *
-   * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
-   */
+  /// This is the [Jenkins hash function][1] but using masking to keep
+  /// values in SMI range.
+  ///
+  /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
   int get hashCode {
     // TODO(ahe): This method shouldn't have to use JS. Update when our
     // optimizations are smarter.
diff --git a/sdk/lib/_internal/js_runtime/lib/math_patch.dart b/sdk/lib/_internal/js_runtime/lib/math_patch.dart
index 68bae9a..a3d3fc9 100644
--- a/sdk/lib/_internal/js_runtime/lib/math_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/math_patch.dart
@@ -84,15 +84,11 @@
     return JS('int', '(Math.random() * #) >>> 0', max);
   }
 
-  /**
-   * Generates a positive random floating point value uniformly distributed on
-   * the range from 0.0, inclusive, to 1.0, exclusive.
-   */
+  /// Generates a positive random floating point value uniformly distributed on
+  /// the range from 0.0, inclusive, to 1.0, exclusive.
   double nextDouble() => JS('double', 'Math.random()');
 
-  /**
-   * Generates a random boolean value.
-   */
+  /// Generates a random boolean value.
   bool nextBool() => JS('bool', 'Math.random() < 0.5');
 }
 
diff --git a/sdk/lib/_internal/js_runtime/lib/native_helper.dart b/sdk/lib/_internal/js_runtime/lib/native_helper.dart
index fa11112..59a3719 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_helper.dart
@@ -38,27 +38,21 @@
   return JS('var', 'Object.getPrototypeOf(#)[#]', object, name);
 }
 
-/**
- * Returns a String tag identifying the type of the native object, or `null`.
- * The tag is not the name of the type, but usually the name of the JavaScript
- * constructor function.  Initialized by [initHooks].
- */
+/// Returns a String tag identifying the type of the native object, or `null`.
+/// The tag is not the name of the type, but usually the name of the JavaScript
+/// constructor function.  Initialized by [initHooks].
 Function getTagFunction;
 
-/**
- * If a lookup via [getTagFunction] on an object [object] that has [tag] fails,
- * this function is called to provide an alternate tag.  This allows us to fail
- * gracefully if we can make a good guess, for example, when browsers add novel
- * kinds of HTMLElement that we have never heard of.  Initialized by
- * [initHooks].
- */
+/// If a lookup via [getTagFunction] on an object [object] that has [tag] fails,
+/// this function is called to provide an alternate tag.  This allows us to fail
+/// gracefully if we can make a good guess, for example, when browsers add novel
+/// kinds of HTMLElement that we have never heard of.  Initialized by
+/// [initHooks].
 Function alternateTagFunction;
 
-/**
- * Returns the prototype for the JavaScript constructor named by an input tag.
- * Returns `null` if there is no such constructor, or if pre-patching of the
- * constructor is to be avoided.  Initialized by [initHooks].
- */
+/// Returns the prototype for the JavaScript constructor named by an input tag.
+/// Returns `null` if there is no such constructor, or if pre-patching of the
+/// constructor is to be avoided.  Initialized by [initHooks].
 Function prototypeForTagFunction;
 
 String toStringForNativeObject(var obj) {
@@ -73,9 +67,7 @@
 
 int hashCodeForNativeObject(object) => Primitives.objectHashCode(object);
 
-/**
- * Sets a JavaScript property on an object.
- */
+/// Sets a JavaScript property on an object.
 void defineProperty(var obj, String property, var value) {
   JS(
       'void',
@@ -97,20 +89,16 @@
           'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
 }
 
-/**
- * A JavaScript object mapping tags to the constructors of interceptors.
- * This is a JavaScript object with no prototype.
- *
- * Example: 'HTMLImageElement' maps to the ImageElement class constructor.
- */
+/// A JavaScript object mapping tags to the constructors of interceptors.
+/// This is a JavaScript object with no prototype.
+///
+/// Example: 'HTMLImageElement' maps to the ImageElement class constructor.
 get interceptorsByTag => JS_EMBEDDED_GLOBAL('=Object', INTERCEPTORS_BY_TAG);
 
-/**
- * A JavaScript object mapping tags to `true` or `false`.
- *
- * Example: 'HTMLImageElement' maps to `true` since, as there are no subclasses
- * of ImageElement, it is a leaf class in the native class hierarchy.
- */
+/// A JavaScript object mapping tags to `true` or `false`.
+///
+/// Example: 'HTMLImageElement' maps to `true` since, as there are no subclasses
+/// of ImageElement, it is a leaf class in the native class hierarchy.
 get leafTags => JS_EMBEDDED_GLOBAL('=Object', LEAF_TAGS);
 
 String findDispatchTagForInterceptorClass(interceptorClassConstructor) {
@@ -118,17 +106,13 @@
       '', r'#.#', interceptorClassConstructor, NATIVE_SUPERCLASS_TAG_NAME);
 }
 
-/**
- * Cache of dispatch records for instances.  This is a JavaScript object used as
- * a map.  Keys are instance tags, e.g. "!SomeThing".  The cache permits the
- * sharing of one dispatch record between multiple instances.
- */
+/// Cache of dispatch records for instances.  This is a JavaScript object used
+/// as a map.  Keys are instance tags, e.g. "!SomeThing".  The cache permits the
+/// sharing of one dispatch record between multiple instances.
 var dispatchRecordsForInstanceTags;
 
-/**
- * Cache of interceptors indexed by uncacheable tags, e.g. "~SomeThing".
- * This is a JavaScript object used as a map.
- */
+/// Cache of interceptors indexed by uncacheable tags, e.g. "~SomeThing".
+/// This is a JavaScript object used as a map.
 var interceptorsForUncacheableTags;
 
 lookupInterceptor(String tag) {
@@ -155,12 +139,10 @@
 /// A 'discriminator' function is to be used. TBD.
 const DISCRIMINATED_MARK = '*';
 
-/**
- * Returns the interceptor for a native object, or returns `null` if not found.
- *
- * A dispatch record is cached according to the specification of the dispatch
- * tag for [obj].
- */
+/// Returns the interceptor for a native object, or returns `null` if not found.
+///
+/// A dispatch record is cached according to the specification of the dispatch
+/// tag for [obj].
 @NoInline()
 lookupAndCacheInterceptor(obj) {
   assert(!isDartObject(obj));
@@ -270,10 +252,8 @@
   }
 }
 
-/**
- * [proto] should have no shadowing prototypes that are not also assigned a
- * dispatch rescord.
- */
+/// [proto] should have no shadowing prototypes that are not also assigned a
+/// dispatch rescord.
 setNativeSubclassDispatchRecord(proto, interceptor) {
   setDispatchProperty(proto, makeLeafDispatchRecord(interceptor));
 }
@@ -338,41 +318,39 @@
   }
 }
 
-/**
- * Initializes [getTagFunction] and [alternateTagFunction].
- *
- * These functions are 'hook functions', collectively 'hooks'.  They initialized
- * by applying a series of hooks transformers.  Built-in hooks transformers deal
- * with various known browser behaviours.
- *
- * Each hook tranformer takes a 'hooks' input which is a JavaScript object
- * containing the hook functions, and returns the same or a new object with
- * replacements.  The replacements can wrap the originals to provide alternate
- * or modified behaviour.
- *
- *     { getTag: function(obj) {...},
- *       getUnknownTag: function(obj, tag) {...},
- *       prototypeForTag: function(tag) {...},
- *       discriminator: function(tag) {...},
- *      }
- *
- * * getTag(obj) returns the dispatch tag, or `null`.
- * * getUnknownTag(obj, tag) returns a tag when [getTag] fails.
- * * prototypeForTag(tag) returns the prototype of the constructor for tag,
- *   or `null` if not available or prepatching is undesirable.
- * * discriminator(tag) returns a function TBD.
- *
- * The web site can adapt a dart2js application by loading code ahead of the
- * dart2js application that defines hook transformers to be after the built in
- * ones.  Code defining a transformer HT should use the following pattern to
- * ensure multiple transformers can be composed:
- *
- *     (dartNativeDispatchHooksTransformer =
- *      window.dartNativeDispatchHooksTransformer || []).push(HT);
- *
- *
- * TODO: Implement and describe dispatch tags and their caching methods.
- */
+/// Initializes [getTagFunction] and [alternateTagFunction].
+///
+/// These functions are 'hook functions', collectively 'hooks'.  They
+/// initialized by applying a series of hooks transformers.  Built-in hooks
+/// transformers deal with various known browser behaviours.
+///
+/// Each hook tranformer takes a 'hooks' input which is a JavaScript object
+/// containing the hook functions, and returns the same or a new object with
+/// replacements.  The replacements can wrap the originals to provide alternate
+/// or modified behaviour.
+///
+///     { getTag: function(obj) {...},
+///       getUnknownTag: function(obj, tag) {...},
+///       prototypeForTag: function(tag) {...},
+///       discriminator: function(tag) {...},
+///      }
+///
+/// * getTag(obj) returns the dispatch tag, or `null`.
+/// * getUnknownTag(obj, tag) returns a tag when [getTag] fails.
+/// * prototypeForTag(tag) returns the prototype of the constructor for tag,
+///   or `null` if not available or prepatching is undesirable.
+/// * discriminator(tag) returns a function TBD.
+///
+/// The web site can adapt a dart2js application by loading code ahead of the
+/// dart2js application that defines hook transformers to be after the built in
+/// ones.  Code defining a transformer HT should use the following pattern to
+/// ensure multiple transformers can be composed:
+///
+///     (dartNativeDispatchHooksTransformer =
+///      window.dartNativeDispatchHooksTransformer || []).push(HT);
+///
+///
+/// TODO: Implement and describe dispatch tags and their caching methods.
 void initHooks() {
   // The initial simple hooks:
   var hooks = JS('', '#()', _baseHooks);
@@ -478,14 +456,12 @@
     discriminator: discriminator };
 }''');
 
-/**
- * Returns the name of the constructor function for browsers where
- * `object.constructor.name` is not reliable.
- *
- * This function is split out of [_fallbackConstructorHooksTransformerGenerator]
- * as it is called from both the dispatch hooks and via
- * [constructorNameFallback] from objectToString.
- */
+/// Returns the name of the constructor function for browsers where
+/// `object.constructor.name` is not reliable.
+///
+/// This function is split out of
+/// [_fallbackConstructorHooksTransformerGenerator] as it is called from both
+/// the dispatch hooks and via [constructorNameFallback] from objectToString.
 const _constructorNameFallback = const JS_CONST(r'''
 function getTagFallback(o) {
   var s = Object.prototype.toString.call(o);
diff --git a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
index 7889c36..9fa9070 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -2,10 +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.
 
-/**
- * Specialized integers and floating point numbers,
- * with SIMD support and efficient lists.
- */
+/// Specialized integers and floating point numbers,
+/// with SIMD support and efficient lists.
 library dart.typed_data.implementation;
 
 import 'dart:collection' show ListMixin;
@@ -99,20 +97,16 @@
   }
 }
 
-/**
- * A fixed-length list of Float32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeFloat32x4List extends Object
     with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
     implements Float32x4List {
   final NativeFloat32List _storage;
 
-  /**
-   * Creates a [Float32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Float32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeFloat32x4List(int length)
       : _storage = new NativeFloat32List(length * 4);
 
@@ -131,10 +125,8 @@
 
   Type get runtimeType => Float32x4List;
 
-  /**
-   * Creates a [Float32x4List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Float32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeFloat32x4List.fromList(List<Float32x4> list) {
     if (list is NativeFloat32x4List) {
       return new NativeFloat32x4List._externalStorage(
@@ -178,20 +170,16 @@
   }
 }
 
-/**
- * A fixed-length list of Int32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Int32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeInt32x4List extends Object
     with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
     implements Int32x4List {
   final Int32List _storage;
 
-  /**
-   * Creates a [Int32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Int32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeInt32x4List(int length) : _storage = new NativeInt32List(length * 4);
 
   NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
@@ -209,10 +197,8 @@
 
   Type get runtimeType => Int32x4List;
 
-  /**
-   * Creates a [Int32x4List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Int32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeInt32x4List.fromList(List<Int32x4> list) {
     if (list is NativeInt32x4List) {
       return new NativeInt32x4List._externalStorage(
@@ -256,20 +242,16 @@
   }
 }
 
-/**
- * A fixed-length list of Float64x2 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float64x2 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeFloat64x2List extends Object
     with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
     implements Float64x2List {
   final NativeFloat64List _storage;
 
-  /**
-   * Creates a [Float64x2List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Float64x2List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeFloat64x2List(int length)
       : _storage = new NativeFloat64List(length * 2);
 
@@ -284,10 +266,8 @@
     }
   }
 
-  /**
-   * Creates a [Float64x2List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Float64x2List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeFloat64x2List.fromList(List<Float64x2> list) {
     if (list is NativeFloat64x2List) {
       return new NativeFloat64x2List._externalStorage(
@@ -331,30 +311,22 @@
 
 @Native('ArrayBufferView')
 class NativeTypedData implements TypedData {
-  /**
-   * Returns the byte buffer associated with this object.
-   */
+  /// Returns the byte buffer associated with this object.
   @Creates('NativeByteBuffer')
   // May be Null for IE's CanvasPixelArray.
   @Returns('NativeByteBuffer|Null')
   final ByteBuffer buffer;
 
-  /**
-   * Returns the length of this view, in bytes.
-   */
+  /// Returns the length of this view, in bytes.
   @JSName('byteLength')
   final int lengthInBytes;
 
-  /**
-   * Returns the offset in bytes into the underlying byte buffer of this view.
-   */
+  /// Returns the offset in bytes into the underlying byte buffer of this view.
   @JSName('byteOffset')
   final int offsetInBytes;
 
-  /**
-   * Returns the number of bytes in the representation of each element in this
-   * list.
-   */
+  /// Returns the number of bytes in the representation of each element in this
+  /// list.
   @JSName('BYTES_PER_ELEMENT')
   final int elementSizeInBytes;
 
@@ -413,24 +385,20 @@
 
 @Native('DataView')
 class NativeByteData extends NativeTypedData implements ByteData {
-  /**
-   * Creates a [ByteData] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   */
+  /// Creates a [ByteData] of the specified length (in elements), all of
+  /// whose elements are initially zero.
   factory NativeByteData(int length) => _create1(_checkLength(length));
 
-  /**
-   * Creates an [ByteData] _view_ of the specified region in the specified
-   * byte buffer. Changes in the [ByteData] will be visible in the byte
-   * buffer and vice versa. If the [offsetInBytes] index of the region is not
-   * specified, it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to null, which indicates
-   * that the view extends to the end of the byte buffer.
-   *
-   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
-   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
-   * the length of [buffer].
-   */
+  /// Creates an [ByteData] _view_ of the specified region in the specified
+  /// byte buffer. Changes in the [ByteData] will be visible in the byte
+  /// buffer and vice versa. If the [offsetInBytes] index of the region is not
+  /// specified, it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not specified, it defaults to null, which indicates
+  /// that the view extends to the end of the byte buffer.
+  ///
+  /// Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+  /// if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+  /// the length of [buffer].
   factory NativeByteData.view(
       ByteBuffer buffer, int offsetInBytes, int length) {
     _checkViewArguments(buffer, offsetInBytes, length);
@@ -443,14 +411,12 @@
 
   int get elementSizeInBytes => 1;
 
-  /**
-   * Returns the floating point number represented by the four bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * single-precision binary floating-point format (binary32).
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the floating point number represented by the four bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// single-precision binary floating-point format (binary32).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
       _getFloat32(byteOffset, Endian.little == endian);
 
@@ -458,14 +424,12 @@
   @Returns('num')
   num _getFloat32(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the floating point number represented by the eight bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * double-precision binary floating-point format (binary64).
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the floating point number represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// double-precision binary floating-point format (binary64).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
       _getFloat64(byteOffset, Endian.little == endian);
 
@@ -473,16 +437,14 @@
   @Returns('num')
   num _getFloat64(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the two bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the two bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
       _getInt16(byteOffset, Endian.little == endian);
 
@@ -490,16 +452,14 @@
   @Returns('int')
   int _getInt16(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the four bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the four bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
       _getInt32(byteOffset, Endian.little == endian);
 
@@ -507,39 +467,33 @@
   @Returns('int')
   int _getInt32(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the eight bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   int getInt64(int byteOffset, [Endian endian = Endian.big]) {
     throw new UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Returns the (possibly negative) integer represented by the byte at the
-   * specified [byteOffset] in this object, in two's complement binary
-   * representation. The return value will be between -128 and 127, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the byte at the
+  /// specified [byteOffset] in this object, in two's complement binary
+  /// representation. The return value will be between -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   int getInt8(int byteOffset) native;
 
-  /**
-   * Returns the positive integer represented by the two bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the two bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
       _getUint16(byteOffset, Endian.little == endian);
 
@@ -547,15 +501,13 @@
   @Returns('JSUInt31')
   int _getUint16(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the positive integer represented by the four bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the four bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
       _getUint32(byteOffset, Endian.little == endian);
 
@@ -563,172 +515,148 @@
   @Returns('JSUInt32')
   int _getUint32(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the positive integer represented by the eight bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the eight bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   int getUint64(int byteOffset, [Endian endian = Endian.big]) {
     throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Returns the positive integer represented by the byte at the specified
-   * [byteOffset] in this object, in unsigned binary form. The
-   * return value will be between 0 and 255, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Returns the positive integer represented by the byte at the specified
+  /// [byteOffset] in this object, in unsigned binary form. The
+  /// return value will be between 0 and 255, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   int getUint8(int byteOffset) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 single-precision binary floating-point
-   * (binary32) representation of the specified [value].
-   *
-   * **Note that this method can lose precision.** The input [value] is
-   * a 64-bit floating point value, which will be converted to 32-bit
-   * floating point value by IEEE 754 rounding rules before it is stored.
-   * If [value] cannot be represented exactly as a binary32, it will be
-   * converted to the nearest binary32 value.  If two binary32 values are
-   * equally close, the one whose least significant bit is zero will be used.
-   * Note that finite (but large) values can be converted to infinity, and
-   * small non-zero values can be converted to zero.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 single-precision binary floating-point
+  /// (binary32) representation of the specified [value].
+  ///
+  /// **Note that this method can lose precision.** The input [value] is
+  /// a 64-bit floating point value, which will be converted to 32-bit
+  /// floating point value by IEEE 754 rounding rules before it is stored.
+  /// If [value] cannot be represented exactly as a binary32, it will be
+  /// converted to the nearest binary32 value.  If two binary32 values are
+  /// equally close, the one whose least significant bit is zero will be used.
+  /// Note that finite (but large) values can be converted to infinity, and
+  /// small non-zero values can be converted to zero.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
       _setFloat32(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat32')
   void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 double-precision binary floating-point
-   * (binary64) representation of the specified [value].
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 double-precision binary floating-point
+  /// (binary64) representation of the specified [value].
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
       _setFloat64(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat64')
   void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in two bytes. In other words, [value] must lie
-   * between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in two bytes. In other words, [value] must lie
+  /// between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setInt16(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt16')
   void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in four bytes. In other words, [value] must lie
-   * between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in four bytes. In other words, [value] must lie
+  /// between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setInt32(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt32')
   void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in eight bytes. In other words, [value] must lie
-   * between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in eight bytes. In other words, [value] must lie
+  /// between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
     throw new UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * two's complement binary representation of the specified [value], which
-   * must fit in a single byte. In other words, [value] must be between
-   * -128 and 127, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// two's complement binary representation of the specified [value], which
+  /// must fit in a single byte. In other words, [value] must be between
+  /// -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   void setInt8(int byteOffset, int value) native;
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in two bytes. in other words, [value] must be between
-   * 0 and 2<sup>16</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in two bytes. in other words, [value] must be between
+  /// 0 and 2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setUint16(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint16')
   void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in four bytes. in other words, [value] must be between
-   * 0 and 2<sup>32</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in four bytes. in other words, [value] must be between
+  /// 0 and 2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setUint32(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint32')
   void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in eight bytes. in other words, [value] must be between
-   * 0 and 2<sup>64</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in eight bytes. in other words, [value] must be between
+  /// 0 and 2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
     throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * unsigned binary representation of the specified [value], which must fit
-   * in a single byte. in other words, [value] must be between 0 and 255,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative,
-   * or greater than or equal to the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// unsigned binary representation of the specified [value], which must fit
+  /// in a single byte. in other words, [value] must be between 0 and 255,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative,
+  /// or greater than or equal to the length of this object.
   void setUint8(int byteOffset, int value) native;
 
   static NativeByteData _create1(arg) =>
@@ -1159,11 +1087,9 @@
       JS('NativeUint8List', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
 }
 
-/**
- * Implementation of Dart Float32x4 immutable value type and operations.
- * Float32x4 stores 4 32-bit floating point values in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Implementation of Dart Float32x4 immutable value type and operations.
+/// Float32x4 stores 4 32-bit floating point values in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 class NativeFloat32x4 implements Float32x4 {
   final double x;
   final double y;
@@ -1494,11 +1420,9 @@
   }
 }
 
-/**
- * Interface of Dart Int32x4 and operations.
- * Int32x4 stores 4 32-bit bit-masks in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Interface of Dart Int32x4 and operations.
+/// Int32x4 stores 4 32-bit bit-masks in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 class NativeInt32x4 implements Int32x4 {
   final int x;
   final int y;
diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
index a588b08..77f746b 100644
--- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -7,31 +7,27 @@
 // Helper method used by internal libraries.
 regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
 
-/**
- * Returns a native version of the RegExp with the global flag set.
- *
- * The RegExp's `lastIndex` property is zero when it is returned.
- *
- * The returned regexp is shared, and its `lastIndex` property may be
- * modified by other uses, so the returned regexp must be used immediately
- * when it's returned, with no user-provided code run in between.
- */
+/// Returns a native version of the RegExp with the global flag set.
+///
+/// The RegExp's `lastIndex` property is zero when it is returned.
+///
+/// The returned regexp is shared, and its `lastIndex` property may be
+/// modified by other uses, so the returned regexp must be used immediately
+/// when it's returned, with no user-provided code run in between.
 regExpGetGlobalNative(JSSyntaxRegExp regexp) {
   var nativeRegexp = regexp._nativeGlobalVersion;
   JS('void', '#.lastIndex = 0', nativeRegexp);
   return nativeRegexp;
 }
 
-/**
- * Computes the number of captures in a regexp.
- *
- * This currently involves creating a new RegExp object with a different
- * source and running it against the empty string (the last part is usually
- * fast).
- *
- * The JSSyntaxRegExp could cache the result, and set the cache any time
- * it finds a match.
- */
+/// Computes the number of captures in a regexp.
+///
+/// This currently involves creating a new RegExp object with a different
+/// source and running it against the empty string (the last part is usually
+/// fast).
+///
+/// The JSSyntaxRegExp could cache the result, and set the cache any time
+/// it finds a match.
 int regExpCaptureCount(JSSyntaxRegExp regexp) {
   var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
   var match = JS('JSExtendableArray', '#.exec("")', nativeAnchoredRegExp);
@@ -239,7 +235,7 @@
   }
 }
 
-/** Find the first match of [regExp] in [string] at or after [start]. */
+/// Find the first match of [regExp] in [string] at or after [start].
 Match firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
   return regExp._execGlobal(string, start);
 }
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 5bc9a6c..9856d55 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -147,32 +147,14 @@
   // anchored at [node].
   // and that node is returned. It should replace the reference to [node]
   // in any parent tree or root pointer.
-  Node _splayMin(Node node) {
-    Node current = node;
-    while (current.left != null) {
-      Node left = current.left;
-      current.left = left.right;
-      left.right = current;
-      current = left;
-    }
-    return current;
-  }
+  external Node _splayMin(Node node);
 
   // Emulates splaying with a key that is greater than any in the subtree
   // anchored at [node].
   // After this, the largest element in the tree is the root of the subtree,
   // and that node is returned. It should replace the reference to [node]
   // in any parent tree or root pointer.
-  Node _splayMax(Node node) {
-    Node current = node;
-    while (current.right != null) {
-      Node right = current.right;
-      current.right = right.left;
-      right.left = current;
-      current = right;
-    }
-    return current;
-  }
+  external Node _splayMax(Node node);
 
   Node _remove(K key) {
     if (_root == null) return null;
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 1f46d11..b24c0ea 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -237,10 +237,10 @@
    *   The time part is a two digit hour,
    *   then optionally a two digit minutes value,
    *   then optionally a two digit seconds value, and
-   *   then optionally a '.' followed by a one-to-six digit second fraction.
+   *   then optionally a '.' or ',' followed by a one-to-six digit second fraction.
    *   The minutes and seconds may be separated from the previous parts by a
    *   ':'.
-   *   Examples: "12", "12:30:24.124", "123010.50".
+   *   Examples: "12", "12:30:24.124", "12:30:24,124", "123010.50".
    * * An optional time-zone offset part,
    *   possibly separated from the previous by a space.
    *   The time zone is either 'z' or 'Z', or it is a signed two digit hour
@@ -261,6 +261,7 @@
    *
    * * `"2012-02-27 13:27:00"`
    * * `"2012-02-27 13:27:00.123456z"`
+   * * `"2012-02-27 13:27:00,123456z"`
    * * `"20120227 13:27:00"`
    * * `"20120227T132700"`
    * * `"20120227"`
@@ -852,7 +853,7 @@
    * time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
    * minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
    * seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
-   * micros_opt ::= <empty> | '.' digit{1,6}
+   * micros_opt ::= <empty> | ('.' | ',') digit{1,6}
    * timezone_opt ::= <empty> | space_opt timezone
    * space_opt :: ' ' | <empty>
    * timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
@@ -860,6 +861,6 @@
    */
   static final RegExp _parseFormat = new RegExp(
       r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)' // Day part.
-      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{1,6}))?)?)?' // Time part.
+      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,6}))?)?)?' // Time part.
       r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.
 }
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index a293b48..4cf78b9 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -21,6 +21,13 @@
  * This does not wait for any asynchronous operations to terminate. Using
  * [exit] is therefore very likely to lose data.
  *
+ * While debugging, the VM will not respect the `--pause-isolates-on-exit`
+ * flag if [exit] is called as invoking this method causes the Dart VM
+ * process to shutdown immediately. To properly break on exit, consider
+ * calling [debugger] from `dart:developer` or [Isolate.pause] from
+ * `dart:isolate` on [Isolate.current] to pause the isolate before
+ * invoking [exit].
+ *
  * The handling of exit codes is platform specific.
  *
  * On Linux and OS X an exit code for normal termination will always
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 658c834..f33a7a8 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -145,8 +145,9 @@
  *
  * This corresponds to the `pow` function defined in the IEEE Standard 754-2008.
  *
- * Notice that an [int] result cannot overflow, but a [double] result might
- * be [double.infinity].
+ * Notice that the result may overflow. If integers are represented as 64-bit
+ * numbers, an integer result may be truncated, and a double result may overflow 
+ * to positive or negative [double.infinity].
  */
 external num pow(num x, num exponent);
 
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 10ad9d2..b620f62 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -56,7 +56,55 @@
 [ $compiler == fasta ]
 Language/Statements/For/syntax_t13: Crash # Assertion error: kernel_shadow_ast.dart: 'receiver == null': is not true.
 Language/Statements/For/syntax_t20: Crash # Assertion error: kernel_shadow_ast.dart: 'receiver == null': is not true.
-Language/Statements/For/syntax_t20 tatements/For/syntax_t20: Crash # Assertion error: kernel_shadow_ast.dart: 'receiver == null': is not true.
+LanguageFeatures/Constant_update2018/*: Crash, Pass # Please triage these failures
+LanguageFeatures/Set-literals/constant_set_literals_A02_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/03: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/04: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/03: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A03_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/03: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/04: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/05: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/06: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/07: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/08: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/09: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/04: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/05: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/06: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/08: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/semantics_A04_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/semantics_A01_t01/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/semantics_A01_t01/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/semantics_A01_t01/09: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/semantics_A01_t01/10: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/semantics_A05_t01: Pass
+LanguageFeatures/Set-literals/semantics_A05_t05/01: MissingCompileTimeError # Exact types
+LanguageFeatures/Set-literals/semantics_A05_t05/02: MissingCompileTimeError # Exact types
+LanguageFeatures/Set-literals/semantics_A05_t05/03: MissingCompileTimeError # Exact types
+LanguageFeatures/Set-literals/set_literals_A01_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/set_literals_A02_t01: Pass # CompileTimeError on $fasta
+LanguageFeatures/Set-literals/set_literals_A04_t02/01: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/02: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/03: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/04: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/05: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/11: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/12: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/set_literals_A04_t02/13: MissingCompileTimeError # Issue 35608
+LanguageFeatures/Set-literals/syntax_compatibility_A01_t01: Pass # CompileTimeError on $fasta
 
 [ $runtime == vm ]
 LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Slow # Does many calls
@@ -769,6 +817,93 @@
 LibTest/isolate/ReceivePort/firstWhere_A02_t01: RuntimeError
 LibTest/isolate/ReceivePort/transform_A01_t01: RuntimeError
 
+[ $runtime == vm && $arch != simdbc64 && ($compiler == dartk || $compiler == dartkb) ]
+LanguageFeatures/Constant_update2018/CastOperator_A01_t01: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A02_t01: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/02: Pass
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/03: Pass
+LanguageFeatures/Constant_update2018/CastOperator_A03_t02/01: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A04_t01: Pass
+LanguageFeatures/Constant_update2018/CastOperator_A04_t02: DartkCrash
+LanguageFeatures/Constant_update2018/EqualityOperator_A01_t03: DartkCrash
+LanguageFeatures/Constant_update2018/EqualityOperator_A01_t04: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A01_t01: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A01_t02: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t01: Fail
+LanguageFeatures/Constant_update2018/NewOperators_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t03: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t04: Fail
+LanguageFeatures/Constant_update2018/NewOperators_A02_t05: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t06: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t07: Fail
+LanguageFeatures/Constant_update2018/NewOperators_A02_t08: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t09: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t05: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t05: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t06: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t01: Pass
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t02: Pass
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A04_t01: Pass
+LanguageFeatures/Constant_update2018/TypeTestOperator_A04_t02: Pass
+LanguageFeatures/Set-literals/constant_set_literals_A02_t01: Pass
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A03_t01: Pass
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/05: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/06: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/07: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/08: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/09: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/05: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/06: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/08: MissingCompileTimeError
+LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: Pass
+LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: RuntimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/09: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/10: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A04_t01: Pass
+LanguageFeatures/Set-literals/semantics_A05_t05/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A05_t05/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A05_t05/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A05_t01: RuntimeError
+LanguageFeatures/Set-literals/set_literals_A01_t01: Pass
+LanguageFeatures/Set-literals/set_literals_A02_t01: Pass
+LanguageFeatures/Set-literals/set_literals_A04_t02/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/05: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/11: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/12: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/13: MissingCompileTimeError
+LanguageFeatures/Set-literals/syntax_compatibility_A01_t01: Pass
+
 [ $runtime != vm && $fasta ]
 Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: MissingCompileTimeError # Issue 34192
 
diff --git a/tests/compiler/dart2js/analyses/analysis_helper.dart b/tests/compiler/dart2js/analyses/analysis_helper.dart
index 9e1560e..715352e 100644
--- a/tests/compiler/dart2js/analyses/analysis_helper.dart
+++ b/tests/compiler/dart2js/analyses/analysis_helper.dart
@@ -71,9 +71,11 @@
 class StaticTypeVisitorBase extends StaticTypeVisitor {
   VariableScopeModel variableScopeModel;
 
-  StaticTypeVisitorBase(ir.Component component)
-      : super(new ir.TypeEnvironment(
-            new ir.CoreTypes(component), new ir.ClassHierarchy(component)));
+  StaticTypeVisitorBase(
+      ir.Component component, ir.ClassHierarchy classHierarchy)
+      : super(
+            new ir.TypeEnvironment(new ir.CoreTypes(component), classHierarchy),
+            classHierarchy);
 
   @override
   bool get useAsserts => false;
@@ -132,7 +134,7 @@
 
   DynamicVisitor(this.reporter, this.component, this._allowedListPath,
       this.analyzedUrisFilter)
-      : super(component);
+      : super(component, new ir.ClassHierarchy(component));
 
   void run({bool verbose = false, bool generate = false}) {
     if (!generate && _allowedListPath != null) {
diff --git a/tests/compiler/dart2js/analyses/dart2js_allowed.json b/tests/compiler/dart2js/analyses/dart2js_allowed.json
index cb3e829..5f6fdad 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -264,9 +264,6 @@
   "pkg/compiler/lib/src/ssa/value_set.dart": {
     "Dynamic invocation of 'add'.": 2
   },
-  "pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart": {
-    "Dynamic access of 'scheme'.": 1
-  },
   "pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart": {
     "Dynamic access of 'keys'.": 1,
     "Dynamic invocation of 'toSet'.": 1,
@@ -281,4 +278,4 @@
     "Dynamic access of 'superclass'.": 1,
     "Dynamic access of 'needsTearOff'.": 1
   }
-}
\ No newline at end of file
+}
diff --git a/tests/compiler/dart2js/analyses/static_type_visitor_test.dart b/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
index 6d8613f..d546a06 100644
--- a/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
+++ b/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
@@ -31,7 +31,8 @@
 }
 
 class Visitor extends StaticTypeVisitorBase {
-  Visitor(ir.Component component) : super(component);
+  Visitor(ir.Component component)
+      : super(component, new ir.ClassHierarchy(component));
 
   ir.DartType getStaticType(ir.Expression node) {
     if (typeEnvironment == null) {
diff --git a/tests/compiler/dart2js/codegen/class_codegen_test.dart b/tests/compiler/dart2js/codegen/class_codegen_test.dart
index a9439f9..bb22e20 100644
--- a/tests/compiler/dart2js/codegen/class_codegen_test.dart
+++ b/tests/compiler/dart2js/codegen/class_codegen_test.dart
@@ -66,14 +66,14 @@
 
 twoClasses() async {
   String generated = await compileAll(TEST_ONE);
-  Expect.isTrue(generated.contains(new RegExp('A: {[ \n]*"\\^": "Object;"')));
-  Expect.isTrue(generated.contains(new RegExp('B: {[ \n]*"\\^": "Object;"')));
+  Expect.isTrue(generated.contains('A: function A()'));
+  Expect.isTrue(generated.contains('B: function B()'));
 }
 
 subClass() async {
   checkOutput(String generated) {
-    Expect.isTrue(generated.contains(new RegExp('A: {[ \n]*"\\^": "Object;"')));
-    Expect.isTrue(generated.contains(new RegExp('B: {[ \n]*"\\^": "A;"')));
+    Expect.isTrue(generated.contains(RegExp(r'_inherit\(.\.A, .\.Object\)')));
+    Expect.isTrue(generated.contains(RegExp(r'_inherit\(.\.B, .\.A\)')));
   }
 
   checkOutput(await compileAll(TEST_TWO));
@@ -82,12 +82,15 @@
 
 fieldTest() async {
   String generated = await compileAll(TEST_FOUR);
-  Expect.isTrue(generated
-      .contains(new RegExp('B: {[ \n]*"\\^": "A;y,z,x",[ \n]*static:')));
+  Expect.isTrue(generated.contains(RegExp(r'B: function B\(t0, t1, t2\) {'
+      r'\s*this.y = t0;'
+      r'\s*this.z = t1;'
+      r'\s*this.x = t2;')));
 }
 
 constructor1() async {
   String generated = await compileAll(TEST_FIVE);
+  print('--------------------\n$generated\n');
   Expect.isTrue(generated.contains(new RegExp(r"new [$A-Z]+\.A\(a\);")));
 }
 
diff --git a/tests/compiler/dart2js/codegen/gvn_test.dart b/tests/compiler/dart2js/codegen/gvn_test.dart
index 54f4d30..678d9fc 100644
--- a/tests/compiler/dart2js/codegen/gvn_test.dart
+++ b/tests/compiler/dart2js/codegen/gvn_test.dart
@@ -108,24 +108,22 @@
 main() {
   runTests() async {
     await compile(TEST_ONE, entry: 'foo', check: (String generated) {
-      RegExp regexp = new RegExp(r"1 \+ [a-z]+");
+      RegExp regexp = RegExp(r"1 \+ [a-z]+");
       checkNumberOfMatches(regexp.allMatches(generated).iterator, 1);
     });
     await compile(TEST_TWO, entry: 'foo', check: (String generated) {
-      checkNumberOfMatches(
-          new RegExp("length").allMatches(generated).iterator, 1);
+      checkNumberOfMatches(RegExp("length").allMatches(generated).iterator, 1);
     });
     await compile(TEST_THREE, entry: 'foo', check: (String generated) {
-      checkNumberOfMatches(
-          new RegExp("number").allMatches(generated).iterator, 1);
+      checkNumberOfMatches(RegExp("number").allMatches(generated).iterator, 1);
     });
     await compile(TEST_FOUR, entry: 'foo', check: (String generated) {
-      checkNumberOfMatches(new RegExp("shr").allMatches(generated).iterator, 1);
+      checkNumberOfMatches(RegExp("shr").allMatches(generated).iterator, 1);
     });
 
     await compileAll(TEST_FIVE).then((generated) {
       checkNumberOfMatches(
-          new RegExp("get\\\$foo").allMatches(generated).iterator, 1);
+          RegExp(r"get\$foo\(").allMatches(generated).iterator, 1);
     });
     await compileAll(TEST_SIX).then((generated) {
       Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
diff --git a/tests/compiler/dart2js/codegen/no_constructor_body_test.dart b/tests/compiler/dart2js/codegen/no_constructor_body_test.dart
index e34f13c..7edc700 100644
--- a/tests/compiler/dart2js/codegen/no_constructor_body_test.dart
+++ b/tests/compiler/dart2js/codegen/no_constructor_body_test.dart
@@ -20,9 +20,8 @@
 main() {
   runTest() async {
     String generated = await compileAll(TEST);
-
-    Expect.isTrue(generated
-        .contains(new RegExp('A: {[ \n]*"\\^": "Object;",[ \n]*static:')));
+    // No methods (including no constructor body method.
+    Expect.isTrue(generated.contains('.A.prototype = {}'));
   }
 
   asyncTest(() async {
diff --git a/tests/compiler/dart2js/codegen/no_duplicate_constructor_body_test.dart b/tests/compiler/dart2js/codegen/no_duplicate_constructor_body_test.dart
index 194fce2..8d18091 100644
--- a/tests/compiler/dart2js/codegen/no_duplicate_constructor_body_test.dart
+++ b/tests/compiler/dart2js/codegen/no_duplicate_constructor_body_test.dart
@@ -18,9 +18,14 @@
 main() {
   runTest() async {
     String generated = await compileAll(CODE);
-    RegExp regexp = new RegExp(r'\A: {[ \n]*"\^": "[A-Za-z]+;"');
+
+    RegExp regexp = RegExp(r'\.A\.prototype = {');
     Iterator<Match> matches = regexp.allMatches(generated).iterator;
     checkNumberOfMatches(matches, 1);
+
+    RegExp regexp2 = RegExp(r'A\$\w+: function');
+    Iterator<Match> matches2 = regexp2.allMatches(generated).iterator;
+    checkNumberOfMatches(matches2, 1);
   }
 
   asyncTest(() async {
diff --git a/tests/compiler/dart2js/deferred/inline_restrictions_test.dart b/tests/compiler/dart2js/deferred/inline_restrictions_test.dart
index 4d11985..70df323 100644
--- a/tests/compiler/dart2js/deferred/inline_restrictions_test.dart
+++ b/tests/compiler/dart2js/deferred/inline_restrictions_test.dart
@@ -57,7 +57,8 @@
 
     // Test that inlineSameContext was inlined into lib1.
     RegExp re4 = new RegExp(r"inline same context");
-    Expect.isFalse(re4.hasMatch(lib3Output));
+    // Output can be null when it contains no code.
+    Expect.isTrue(lib3Output == null || !re4.hasMatch(lib3Output));
     Expect.isTrue(re4.hasMatch(lib1Output));
   });
 }
diff --git a/tests/compiler/dart2js/end_to_end/exit_code_test.dart b/tests/compiler/dart2js/end_to_end/exit_code_test.dart
index 35e36e9..c891f34 100644
--- a/tests/compiler/dart2js/end_to_end/exit_code_test.dart
+++ b/tests/compiler/dart2js/end_to_end/exit_code_test.dart
@@ -103,7 +103,6 @@
       : this.compiler = compiler,
         super(compiler,
             generateSourceMap: compiler.options.generateSourceMap,
-            useStartupEmitter: compiler.options.useStartupEmitter,
             useMultiSourceInfo: compiler.options.useMultiSourceInfo,
             useNewSourceInfo: compiler.options.useNewSourceInfo);
 
diff --git a/tests/compiler/dart2js/end_to_end/uri_retention_test.dart b/tests/compiler/dart2js/end_to_end/uri_retention_test.dart
deleted file mode 100644
index 1fb8a72..0000000
--- a/tests/compiler/dart2js/end_to_end/uri_retention_test.dart
+++ /dev/null
@@ -1,64 +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.test.uri_retention_test;
-
-import 'dart:async';
-
-import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
-import 'package:compiler/src/commandline_options.dart';
-import 'package:expect/expect.dart';
-import '../helpers/memory_compiler.dart' show runCompiler, OutputCollector;
-
-Future<String> compileSources(sources, {bool minify}) async {
-  var options = <String>[];
-  if (minify) options.add(Flags.minify);
-  OutputCollector outputCollector = new OutputCollector();
-  await runCompiler(
-      memorySourceFiles: sources,
-      options: options,
-      outputProvider: outputCollector);
-  return outputCollector.getOutput('', OutputType.js);
-}
-
-Future test(sources, {bool libName, bool fileName}) {
-  return compileSources(sources, minify: false).then((output) {
-    // Unminified the sources should always contain the library name and the
-    // file name.
-    Expect.isTrue(output.contains("main_lib"));
-    Expect.isTrue(output.contains("main.dart"));
-  }).then((_) {
-    compileSources(sources, minify: true).then((output) {
-      Expect.equals(libName, output.contains("main_lib"));
-      Expect.isFalse(output.contains("main.dart"));
-    });
-  });
-}
-
-void main() {
-  runTests() async {
-    await test(MEMORY_SOURCE_FILES1, libName: false, fileName: false);
-  }
-
-  asyncTest(() async {
-    print('--test from kernel------------------------------------------------');
-    await runTests();
-  });
-}
-
-const MEMORY_SOURCE_FILES1 = const <String, String>{
-  'main.dart': """
-library main_lib;
-
-class A {
-  final uri = "foo";
-}
-
-main() {
-  print(Uri.base);
-  print(new A().uri);
-}
-""",
-};
diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
index f9b8ebf..e7becbd 100644
--- a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
+++ b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
@@ -11,6 +11,7 @@
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
+import 'package:compiler/src/util/features.dart';
 import 'package:expect/expect.dart';
 import 'package:sourcemap_testing/src/annotated_code_helper.dart';
 
@@ -687,6 +688,87 @@
   }
 }
 
+class FeaturesDataInterpreter implements DataInterpreter<Features> {
+  const FeaturesDataInterpreter();
+
+  @override
+  String isAsExpected(Features actualFeatures, String expectedData) {
+    if (expectedData == '*') {
+      return null;
+    } else if (expectedData == '') {
+      return actualFeatures.isNotEmpty ? "Expected empty data." : null;
+    } else {
+      List<String> errorsFound = [];
+      Features expectedFeatures = Features.fromText(expectedData);
+      expectedFeatures.forEach((String key, Object expectedValue) {
+        Object actualValue = actualFeatures[key] ?? '';
+        if (expectedValue == '') {
+          if (actualValue != '') {
+            errorsFound.add('Non-empty data found for $key');
+          }
+        } else if (expectedValue == '*') {
+          return;
+        } else if (expectedValue is List) {
+          if (actualValue is List) {
+            List actualList = actualValue.toList();
+            for (Object expectedObject in expectedValue) {
+              String expectedText = '$expectedObject';
+              bool matchFound = false;
+              if (expectedText.endsWith('*')) {
+                // Wildcard matcher.
+                String prefix =
+                    expectedText.substring(0, expectedText.indexOf('*'));
+                List matches = [];
+                for (Object actualObject in actualList) {
+                  if ('$actualObject'.startsWith(prefix)) {
+                    matches.add(actualObject);
+                    matchFound = true;
+                  }
+                }
+                for (Object match in matches) {
+                  actualList.remove(match);
+                }
+              } else {
+                for (Object actualObject in actualList) {
+                  if (expectedText == '$actualObject') {
+                    actualList.remove(actualObject);
+                    matchFound = true;
+                    break;
+                  }
+                }
+              }
+              if (!matchFound) {
+                errorsFound.add("No match found for $key=[$expectedText]");
+              }
+            }
+            if (actualList.isNotEmpty) {
+              errorsFound
+                  .add("Extra data found $key=[${actualList.join(',')}]");
+            }
+          } else {
+            errorsFound.add("List data expected for $key: "
+                "expected '$expectedValue', found '${actualValue}'");
+          }
+        } else if (expectedValue != actualValue) {
+          errorsFound.add(
+              "Mismatch for $key: expected '$expectedValue', found '${actualValue}");
+        }
+      });
+      return errorsFound.isNotEmpty ? errorsFound.join(', ') : null;
+    }
+  }
+
+  @override
+  String getText(Features actualData) {
+    return actualData.getText();
+  }
+
+  @override
+  bool isEmpty(Features actualData) {
+    return actualData == null || actualData.isEmpty;
+  }
+}
+
 /// Checks [compiledData] against the expected data in [expectedMap] derived
 /// from [code].
 Future<bool> checkCode<T>(
@@ -715,8 +797,9 @@
           reportError(
               data.compiler.reporter,
               actualData.sourceSpan,
-              'EXTRA $mode DATA for ${id.descriptor} = '
-              '${colorizeActual('${IdValue.idToString(id, actualText)}')} for ${actualData.objectText}. '
+              'EXTRA $mode DATA for ${id.descriptor}:\n '
+              'object   : ${actualData.objectText}\n '
+              'actual   : ${colorizeActual('${IdValue.idToString(id, actualText)}')}\n '
               'Data was expected for these ids: ${expectedMap.keys}');
           if (filterActualData == null || filterActualData(null, actualData)) {
             hasLocalFailure = true;
@@ -730,7 +813,7 @@
           reportError(
               data.compiler.reporter,
               actualData.sourceSpan,
-              'UNEXPECTED $mode DATA for ${id.descriptor}: \n '
+              'UNEXPECTED $mode DATA for ${id.descriptor}:\n '
               'detail  : ${colorizeMessage(unexpectedMessage)}\n '
               'object  : ${actualData.objectText}\n '
               'expected: ${colorizeExpected('$expected')}\n '
diff --git a/tests/compiler/dart2js/impact/data/classes.dart b/tests/compiler/dart2js/impact/data/classes.dart
index a31b32f..bacab72 100644
--- a/tests/compiler/dart2js/impact/data/classes.dart
+++ b/tests/compiler/dart2js/impact/data/classes.dart
@@ -240,7 +240,7 @@
 }
 
 /*strong.element: testInstanceGenericMethod:
- dynamic=[GenericClass.genericMethod<bool>(1)],
+ dynamic=[exact:GenericClass.genericMethod<bool>(1)],
  static=[
   GenericClass.generative(0),
   assertIsSubtype,
diff --git a/tests/compiler/dart2js/impact/data/exact.dart b/tests/compiler/dart2js/impact/data/exact.dart
new file mode 100644
index 0000000..11a6d2d
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/exact.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*element: A.:static=[Object.(0)]*/
+class A {
+  method1() {}
+  method2() {}
+  method3() {}
+}
+
+/*element: B.:static=[A.(0)]*/
+class B extends A {
+  method1() {}
+  method2() {}
+  method3() {}
+}
+
+/*element: C.:static=[B.(0)]*/
+class C extends B {
+  method1() {}
+  method2() {}
+  method3() {}
+}
+
+/*element: main:static=[callOnEffectivelyFinalB(0),callOnNewB(0),callOnNewC(0)]*/
+main() {
+  callOnNewB();
+  callOnNewC();
+  callOnEffectivelyFinalB();
+  callOnEffectivelyFinalB();
+}
+
+/*element: callOnNewB:dynamic=[exact:B.method1(0)],static=[B.(0)]*/
+callOnNewB() {
+  new B().method1();
+}
+
+/*element: callOnNewC:dynamic=[exact:C.method2(0)],static=[C.(0)]*/
+callOnNewC() {
+  new C().method2();
+}
+
+/*element: callOnEffectivelyFinalB:dynamic=[exact:B.method3(0)],static=[B.(0)]*/
+callOnEffectivelyFinalB() {
+  A a = new B();
+  a.method3();
+}
diff --git a/tests/compiler/dart2js/impact/data/future_or.dart b/tests/compiler/dart2js/impact/data/future_or.dart
new file mode 100644
index 0000000..c119fbe
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/future_or.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+
+/*element: main:
+ dynamic=[runtimeType],
+ runtimeType=[unknown:FutureOr<int>],
+ static=[Future.value(1),assertIsSubtype,print(1),throwTypeError],
+ type=[inst:JSDouble,inst:JSInt,inst:JSNumber,inst:JSPositiveInt,inst:JSUInt31,inst:JSUInt32]
+*/
+@pragma('dart2js:disableFinal')
+void main() {
+  FutureOr<int> i = new Future<int>.value(0);
+  print(i.runtimeType);
+}
diff --git a/tests/compiler/dart2js/impact/data/runtime_type.dart b/tests/compiler/dart2js/impact/data/runtime_type.dart
index 32fa0a7..96fac37 100644
--- a/tests/compiler/dart2js/impact/data/runtime_type.dart
+++ b/tests/compiler/dart2js/impact/data/runtime_type.dart
@@ -5,8 +5,8 @@
 /*element: Class1a.:static=[Object.(0)]*/
 class Class1a<T> {
   /*element: Class1a.==:
-   dynamic=[<Class1a.runtimeType,Object.runtimeType,Type.==],
-   runtimeType=[equals:Class1a<Class1a.T>/dynamic]
+   dynamic=[this:Class1a.runtimeType,Object.runtimeType,Type.==],
+   runtimeType=[equals:Class1a<Class1a.T>/Object]
   */
   bool operator ==(other) {
     return runtimeType == other.runtimeType;
@@ -16,8 +16,8 @@
 /*element: Class1b.:static=[Class1a.(0)]*/
 class Class1b<T> extends Class1a<T> {
   /*element: Class1b.==:
-   dynamic=[<Class1b.runtimeType,Object.runtimeType,Type.==],
-   runtimeType=[equals:dynamic/Class1b<Class1b.T>]
+   dynamic=[this:Class1b.runtimeType,Object.runtimeType,Type.==],
+   runtimeType=[equals:Object/Class1b<Class1b.T>]
   */
   bool operator ==(other) {
     return other.runtimeType == runtimeType;
@@ -27,8 +27,8 @@
 /*element: Class1c.:static=[Object.(0)]*/
 class Class1c<T> implements Class1a<T> {
   /*element: Class1c.==:
-   dynamic=[<Class1c.runtimeType,Object.==,Object.runtimeType,Type.==],
-   runtimeType=[equals:Class1c<Class1c.T>/dynamic],
+   dynamic=[this:Class1c.runtimeType,Object.==,Object.runtimeType,Type.==],
+   runtimeType=[equals:Class1c<Class1c.T>/Object],
    type=[inst:JSNull]
   */
   bool operator ==(other) {
@@ -39,8 +39,8 @@
 /*element: Class1d.:static=[Object.(0)]*/
 class Class1d<T> implements Class1a<T> {
   /*element: Class1d.==:
-   dynamic=[<Class1d.runtimeType,Object.==,Object.runtimeType,Type.==],
-   runtimeType=[equals:dynamic/Class1d<Class1d.T>],
+   dynamic=[this:Class1d.runtimeType,Object.==,Object.runtimeType,Type.==],
+   runtimeType=[equals:Object/Class1d<Class1d.T>],
    type=[inst:JSNull]
   */
   bool operator ==(other) {
@@ -379,7 +379,7 @@
 notEquals4(Class3 a, Class4 b) => a?.runtimeType != b?.runtimeType;
 
 /*element: main:
- dynamic=[Class1a.==],
+ dynamic=[exact:Class1a.==],
  static=[
   Class1a.(0),
   Class1b.(0),
diff --git a/tests/compiler/dart2js/impact/data/this.dart b/tests/compiler/dart2js/impact/data/this.dart
index 2579dda..73a03d1 100644
--- a/tests/compiler/dart2js/impact/data/this.dart
+++ b/tests/compiler/dart2js/impact/data/this.dart
@@ -10,12 +10,12 @@
   /*element: Class.field2:type=[inst:JSNull]*/
   var field2;
 
-  /*element: Class.method1:dynamic=[<Class.method2(0)]*/
+  /*element: Class.method1:dynamic=[this:Class.method2(0)]*/
   method1() {
     method2();
   }
 
-  /*element: Class.method2:dynamic=[<Class.field1=,<Class.field2]*/
+  /*element: Class.method2:dynamic=[this:Class.field1=,this:Class.field2]*/
   method2() {
     field1 = field2;
   }
@@ -31,7 +31,7 @@
   /*element: Subclass.method1:*/
   method1() {}
 
-  /*element: Subclass.method2:dynamic=[<Subclass.method3(0)]*/
+  /*element: Subclass.method2:dynamic=[this:Subclass.method3(0)]*/
   method2() {
     method3();
   }
diff --git a/tests/compiler/dart2js/impact/impact_test.dart b/tests/compiler/dart2js/impact/impact_test.dart
index d1cc0b1b..e59b077 100644
--- a/tests/compiler/dart2js/impact/impact_test.dart
+++ b/tests/compiler/dart2js/impact/impact_test.dart
@@ -33,12 +33,12 @@
   static const String runtimeTypeUse = 'runtimeType';
 }
 
-class ImpactDataComputer extends DataComputer<String> {
+class ImpactDataComputer extends DataComputer<Features> {
   const ImpactDataComputer();
 
   @override
   void computeMemberData(Compiler compiler, MemberEntity member,
-      Map<Id, ActualData<String>> actualMap,
+      Map<Id, ActualData<Features>> actualMap,
       {bool verbose: false}) {
     KernelFrontEndStrategy frontendStrategy = compiler.frontendStrategy;
     WorldImpact impact = compiler.impactCache[member];
@@ -72,10 +72,11 @@
       }
     }
     Id id = computeEntityId(node);
-    actualMap[id] = new ActualData<String>(
-        id, features.getText(), computeSourceSpanFromTreeNode(node), member);
+    actualMap[id] = new ActualData<Features>(
+        id, features, computeSourceSpanFromTreeNode(node), member);
   }
 
   @override
-  DataInterpreter<String> get dataValidator => const StringDataInterpreter();
+  DataInterpreter<Features> get dataValidator =>
+      const FeaturesDataInterpreter();
 }
diff --git a/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart b/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart
index d721dc7..aeb3108 100644
--- a/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart
+++ b/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart
@@ -17,11 +17,18 @@
 }
 
 runTest() async {
-  CompilationResult result = await runCompiler(memorySourceFiles: {
-    'main.dart': '''
+  // Pretend this is a dart2js_native test to allow use of 'native' keyword
+  // and import of private libraries.
+  String main = 'sdk/tests/compiler/dart2js_native/main.dart';
+  Uri entryPoint = Uri.parse('memory:$main');
+
+  CompilationResult result =
+      await runCompiler(entryPoint: entryPoint, memorySourceFiles: {
+    main: '''
 class A {
   method1() {}
   method2() {}
+  method4() {}
   get getter => 42;
   set setter(_) {}
 }
@@ -29,6 +36,7 @@
 class B {
   method1() {}
   method2() {}
+  method5() {}
   get getter => 42;
   set setter(_) {}
 }
@@ -36,6 +44,7 @@
 class C extends A {
   method1() {}
   method2() {}
+  method4() {} 
   get getter => 42;
   set setter(_) {}
 }
@@ -43,6 +52,7 @@
 class D implements B {
   method1() {}
   method2() {}
+  method5() {}
   get getter => 42;
   set setter(_) {}
 }
@@ -50,6 +60,7 @@
 class E implements A {
   method1() {}
   method2() {}
+  method4() {}
   get getter => 42;
   set setter(_) {}
 }
@@ -57,6 +68,7 @@
 class F extends B {
   method1() {}
   method2() {}
+  method5() {}
   get getter => 42;
   set setter(_) {}
 }
@@ -64,6 +76,7 @@
 class G {
   method1() {}
   method2() {}
+  method4() {} 
   get getter => 42;
   set setter(_) {}
 }
@@ -73,6 +86,7 @@
 class I {
   method1() {}
   method2() {}
+  method4() {}
   get getter => 42;
   set setter(_) {}
 }
@@ -124,6 +138,12 @@
 }
 
 main() {
+  method1();
+  method2();
+}
+
+@pragma('dart2js:disableFinal')
+method1() {
   A a = new A();
   B b = new B();
   a.method1();
@@ -148,14 +168,21 @@
   new Class1b();
   new Class2().c(0, 1, 2);
 }
+
+method2() {
+  A a = new A();
+  B b = new B();
+  a.method4();
+  b.method5();
+}
 '''
   });
   Expect.isTrue(result.isSuccess);
   Compiler compiler = result.compiler;
 
   Map<String, List<String>> expectedLiveMembersMap = <String, List<String>>{
-    'A': ['method1', 'getter'],
-    'B': ['method2', 'setter'],
+    'A': ['method1', 'getter', 'method4'],
+    'B': ['method2', 'setter', 'method5'],
     'C': ['method1', 'getter'],
     'D': ['method2', 'setter'],
     'G': ['method1', 'getter'],
diff --git a/tests/compiler/dart2js/rti/emission/closure_function_type.dart b/tests/compiler/dart2js/rti/emission/closure_function_type.dart
index 56d1d56..aed5de1 100644
--- a/tests/compiler/dart2js/rti/emission/closure_function_type.dart
+++ b/tests/compiler/dart2js/rti/emission/closure_function_type.dart
@@ -8,7 +8,7 @@
 test(o) => o is Function();
 
 main() {
-  test(/*checks=[],functionType,instance*/ () {});
+  test(/*checks=[$signature],instance*/ () {});
   test(
 
       /*strong.checks=[],instance*/
diff --git a/tests/compiler/dart2js/rti/emission/closure_signature.dart b/tests/compiler/dart2js/rti/emission/closure_signature.dart
index b1250b0..aedf5f6 100644
--- a/tests/compiler/dart2js/rti/emission/closure_signature.dart
+++ b/tests/compiler/dart2js/rti/emission/closure_signature.dart
@@ -13,7 +13,7 @@
 
   @NoInline()
   f() {
-    return /*checks=[],functionType,instance*/ (int t) {};
+    return /*checks=[$signature],instance*/ (int t) {};
   }
 }
 
diff --git a/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1.dart b/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1.dart
index 3123b79..dc43c4b 100644
--- a/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1.dart
+++ b/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 main() {
-  /*strong.checks=[],functionType,instance*/
+  /*strong.checks=[$signature],instance*/
   /*omit.checks=[],instance*/
   T id<T>(T t) => t;
   int Function(int) x = id;
diff --git a/tests/compiler/dart2js/rti/emission/subtype_named_args.dart b/tests/compiler/dart2js/rti/emission/subtype_named_args.dart
index 759210b..cb83d5e 100644
--- a/tests/compiler/dart2js/rti/emission/subtype_named_args.dart
+++ b/tests/compiler/dart2js/rti/emission/subtype_named_args.dart
@@ -53,50 +53,50 @@
 
 main() {
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({D a, B b, C c, A d}) {} is classesFunc);
   Expect.isTrue(
-      /*checks=[],functionType,instance*/
+      /*checks=[$signature],instance*/
       ({A a, A b, A c, A d}) {} is classesFunc);
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({D a, A1 b, A1 c, A1 d}) {} is classesFunc);
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({D a, A2 b, A2 c, A2 d}) {} is classesFunc);
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({D a, D b, D c, D d}) {} is classesFunc);
   Expect.isTrue(
-      /*checks=[],functionType,instance*/
+      /*checks=[$signature],instance*/
       ({var a, var b, var c, var d}) {} is classesFunc);
-  Expect.isTrue(/*checks=[],functionType,instance*/
+  Expect.isTrue(/*checks=[$signature],instance*/
       ({Object a, Object b, Object c, Object d}) {} is classesFunc);
 
-  Expect.isTrue(/*checks=[],functionType,instance*/
+  Expect.isTrue(/*checks=[$signature],instance*/
       ({Map<num, num> m, List<List<A1>> l, G<A, A1, A1, A1> g}) {}
           is genericsFunc);
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({Map<int, int> m, List<List<D>> l, G<D, D, D, D> g}) {} is genericsFunc);
   Expect.isTrue(
-      /*checks=[],functionType,instance*/
+      /*checks=[$signature],instance*/
       ({var m, var l, var g}) {} is genericsFunc);
   Expect.isTrue(
-      /*checks=[],functionType,instance*/
+      /*checks=[$signature],instance*/
       ({Object m, Object l, Object g}) {} is genericsFunc);
 
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({A x, G y, mixFunc z, var v}) {} is dynamicFunc);
   Expect.isTrue(
-      /*strong.checks=[],functionType,instance*/
+      /*strong.checks=[$signature],instance*/
       /*omit.checks=[],instance*/
       ({int x, bool y, List<Map> z, classesFunc v}) {} is dynamicFunc);
 
@@ -106,7 +106,7 @@
           {okWithClassesFunc_1 f1,
           okWithGenericsFunc_1 f2,
           okWithDynamicFunc_1 f3}) {} is funcFunc);
-  Expect.isTrue(/*checks=[],functionType,instance*/
+  Expect.isTrue(/*checks=[$signature],instance*/
       (
           {okWithClassesFunc_2 f1,
           okWithGenericsFunc_2 f2,
diff --git a/tests/compiler/dart2js/serialization/data/custom_types.dart b/tests/compiler/dart2js/serialization/data/custom_types.dart
new file mode 100644
index 0000000..a301473
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/data/custom_types.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+  method() {
+    Object c = this;
+    return c;
+  }
+}
+
+main() {
+  exactInterfaceType();
+  thisInterfaceType();
+  doesNotCompleteType();
+}
+
+exactInterfaceType() {
+  Object c = new A();
+  return c;
+}
+
+thisInterfaceType() {
+  new A().method();
+}
+
+doesNotCompleteType() {
+  Object c = throw '';
+  // ignore: dead_code
+  return c;
+}
diff --git a/tests/compiler/dart2js/sourcemaps/helpers/js_tracer.dart b/tests/compiler/dart2js/sourcemaps/helpers/js_tracer.dart
index aacf1c6..bc504c76 100644
--- a/tests/compiler/dart2js/sourcemaps/helpers/js_tracer.dart
+++ b/tests/compiler/dart2js/sourcemaps/helpers/js_tracer.dart
@@ -53,6 +53,7 @@
             CallPosition.getSemanticPositionForCall(node);
         sourcePositionKind = callPosition.sourcePositionKind;
         break;
+      case StepKind.ACCESS:
       case StepKind.NEW:
       case StepKind.RETURN:
       case StepKind.BREAK:
diff --git a/tests/compiler/dart2js/sourcemaps/helpers/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/helpers/sourcemap_helper.dart
index 7b45545..8826468 100644
--- a/tests/compiler/dart2js/sourcemaps/helpers/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/helpers/sourcemap_helper.dart
@@ -523,6 +523,7 @@
   /// Called when [node] defines a step of the given [kind] at the given
   /// [offset] when the generated JavaScript code.
   void onStep(js.Node node, Offset offset, StepKind kind) {
+    if (kind == StepKind.ACCESS) return;
     register(kind, node);
   }
 
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/getter_inlining.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/getter_inlining.dart
new file mode 100644
index 0000000..ea1874b
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/getter_inlining.dart
@@ -0,0 +1,16 @@
+class MyClass {
+  int fieldName;
+
+  MyClass(this.fieldName);
+
+  int get getterName => /*1:getterName(inlined)*/ fieldName;
+}
+
+@pragma('dart2js:noInline')
+confuse(x) => x;
+
+main() {
+  confuse(new MyClass(3));
+  var m = confuse(null);
+  m. /*0:main*/ getterName;
+}
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/setter_inlining.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/setter_inlining.dart
new file mode 100644
index 0000000..9b5ab60
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/setter_inlining.dart
@@ -0,0 +1,16 @@
+class MyClass {
+  int fieldName;
+
+  MyClass(this.fieldName);
+
+  set setterName(int v) => /*1:setterName(inlined)*/ fieldName = v;
+}
+
+@pragma('dart2js:noInline')
+confuse(x) => x;
+
+main() {
+  confuse(new MyClass(3));
+  var m = confuse(null);
+  m. /*0:main*/ setterName = 2;
+}
diff --git a/tests/compiler/dart2js/static_type/static_type_test.dart b/tests/compiler/dart2js/static_type/static_type_test.dart
index 070d0f6..1f935d8 100644
--- a/tests/compiler/dart2js/static_type/static_type_test.dart
+++ b/tests/compiler/dart2js/static_type/static_type_test.dart
@@ -8,6 +8,7 @@
 import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/ir/cached_static_type.dart';
+import 'package:compiler/src/ir/static_type_base.dart';
 import 'package:compiler/src/kernel/element_map_impl.dart';
 import 'package:compiler/src/kernel/kernel_strategy.dart';
 import 'package:kernel/ast.dart' as ir;
@@ -55,7 +56,9 @@
             compiler.reporter,
             actualMap,
             new CachedStaticType(
-                getTypeEnvironment(elementMap), staticTypeCache))
+                getTypeEnvironment(elementMap),
+                staticTypeCache,
+                new ThisInterfaceType.from(node.enclosingClass?.thisType)))
         .run(node);
   }
 
diff --git a/tests/compiler/dart2js/static_type/type_promotion_data/bottom.dart b/tests/compiler/dart2js/static_type/type_promotion_data/bottom.dart
new file mode 100644
index 0000000..1c94829
--- /dev/null
+++ b/tests/compiler/dart2js/static_type/type_promotion_data/bottom.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {}
+
+main() {
+  conditionNullElse(null);
+  conditionNullThen(null);
+}
+
+conditionNullElse(dynamic o) {
+  /*{}*/ o;
+  /*{}*/ o is A ? /*{o:[{true:A}|A]}*/ o : null;
+  /*{}*/ o;
+}
+
+conditionNullThen(dynamic o) {
+  /*{}*/ o;
+  /*{}*/ o is! A ? null : /*{o:[{true:A}|A]}*/ o;
+  /*{}*/ o;
+}
diff --git a/tests/compiler/dart2js_extra/35341_test.dart b/tests/compiler/dart2js_extra/35341_test.dart
index 027182f..80310f0 100644
--- a/tests/compiler/dart2js_extra/35341_test.dart
+++ b/tests/compiler/dart2js_extra/35341_test.dart
@@ -8,7 +8,6 @@
 
 @pragma('dart2js:disableFinal')
 void main() {
-  FutureOr<int> i = 0;
-  i = new Future<int>.value(0);
+  FutureOr<int> i = new Future<int>.value(0);
   print(i.runtimeType);
 }
diff --git a/tests/corelib_2/date_time_parse_test.dart b/tests/corelib_2/date_time_parse_test.dart
index 74cc78f..6b3d58d 100644
--- a/tests/corelib_2/date_time_parse_test.dart
+++ b/tests/corelib_2/date_time_parse_test.dart
@@ -18,9 +18,13 @@
   if (supportsMicroseconds) {
     check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
         "2012-02-27 13:27:00.123456z");
+    check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
+        "2012-02-27 13:27:00,123456z");
   } else {
     check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
         "2012-02-27 13:27:00.123z");
+    check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
+        "2012-02-27 13:27:00,123z");
   }
   check(new DateTime(2012, 02, 27, 13, 27), "20120227 13:27:00");
   check(new DateTime(2012, 02, 27, 13, 27), "20120227T132700");
diff --git a/tests/language_2/checked_method_error_order_test.dart b/tests/language_2/checked_method_error_order_test.dart
index c5370cf..04279f8 100644
--- a/tests/language_2/checked_method_error_order_test.dart
+++ b/tests/language_2/checked_method_error_order_test.dart
@@ -22,7 +22,8 @@
       if (e is TypeError) {
         var m = e.message.toString();
         return m.contains("is not a subtype of type 'int'") ||
-            m.contains("is not a subtype of expected type 'int'");
+            m.contains(
+                "Expected a value of type 'int', but got one of type 'String'");
       }
       return false;
     });
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index fb08b21..fa02ab6 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -93,7 +93,6 @@
 regress_29784_test/02: MissingCompileTimeError # Issue 29784
 regress_30339_test: CompileTimeError
 regress_33479_test/01: Crash # Issue #33479
-set_literals/*: Skip
 setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
 setter3_test/02: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
 super_bound_closure_test/none: CompileTimeError
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index c38a4b3..afc42ff 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -60,7 +60,6 @@
 partial_tearoff_instantiation_test/07: Pass # for the wrong reason.
 partial_tearoff_instantiation_test/08: Pass # for the wrong reason.
 private_method_tearoff_test: RuntimeError
-set_literals/*: Skip
 type_constants_test/none: RuntimeError # Issue 35052
 vm/*: SkipByDesign # Tests for the VM.
 
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 8047938..03b555e 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -193,15 +193,6 @@
 implicit_creation/implicit_const_not_default_values_test/e7: MissingCompileTimeError
 implicit_creation/implicit_const_not_default_values_test/e8: MissingCompileTimeError
 mixin_method_override_test/G4: Crash # Assertion error: mixin_full_resolution.dart': 'src.typeParameters.length == dst.typeParameters.length': is not true.
-set_literals/invalid_set_literal_test/08: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/09: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/10: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/29: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/30: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/31: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/32: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/33: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/34: MissingCompileTimeError # Requires constant evaluation
 vm/regress_33469_test/01: MissingCompileTimeError
 vm/regress_33469_test/02: MissingCompileTimeError
 vm/regress_33469_test/03: MissingCompileTimeError
@@ -236,6 +227,16 @@
 mixin_declaration/mixin_declaration_superinvocation_application_test/08: MissingCompileTimeError
 mixin_method_override_test/G5: Crash # Issue 34354
 regress_22976_test/*: CompileTimeError # Issue 31935
+set_literals/invalid_set_literal_test/08: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/09: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/10: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/23: MissingCompileTimeError # Exact types
+set_literals/invalid_set_literal_test/29: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/30: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/31: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/32: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/33: MissingCompileTimeError # Requires constant evaluation
+set_literals/invalid_set_literal_test/34: MissingCompileTimeError # Requires constant evaluation
 syntax_test/28: MissingCompileTimeError # Issue 29763 - low priority
 syntax_test/29: MissingCompileTimeError # Issue 29763 - low priority
 syntax_test/30: MissingCompileTimeError # Issue 29763 - low priority
diff --git a/tests/language_2/vm/bitnot_int_test.dart b/tests/language_2/vm/bitnot_int_test.dart
new file mode 100644
index 0000000..f52d66b
--- /dev/null
+++ b/tests/language_2/vm/bitnot_int_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+// Tests for long bit-not under 64-bit arithmetic wrap-around semantics.
+
+final int maxInt32 = 2147483647;
+final int minInt32 = -2147483648;
+final int maxInt64 = 0x7fffffffffffffff;
+final int minInt64 = 0x8000000000000000;
+
+int bitnot(int x) {
+  return ~x;
+}
+
+doConstant() {
+  Expect.equals(0, bitnot(-1));
+  Expect.equals(-1, bitnot(0));
+  Expect.equals(-2, bitnot(1));
+
+  Expect.equals(minInt32, bitnot(maxInt32));
+  Expect.equals(maxInt32, bitnot(minInt32));
+  Expect.equals(minInt64, bitnot(maxInt64));
+  Expect.equals(maxInt64, bitnot(minInt64)); // sic!
+}
+
+doVar() {
+  int d = 0;
+  for (int i = -88; i < 10; i++) {
+    d += bitnot(i);
+  }
+  Expect.equals(3773, d);
+}
+
+main() {
+  // Repeat tests to enter JIT (when applicable).
+  for (int i = 0; i < 20; i++) {
+    doConstant();
+    doVar();
+  }
+}
diff --git a/tests/language_2/vm/modtruncdiv_int_test.dart b/tests/language_2/vm/modtruncdiv_int_test.dart
index 7a84d1a..8314628 100644
--- a/tests/language_2/vm/modtruncdiv_int_test.dart
+++ b/tests/language_2/vm/modtruncdiv_int_test.dart
@@ -79,6 +79,17 @@
   Expect.equals(1, mod(maxInt32 + 1, maxInt32));
   Expect.equals(maxInt32 - 2, mod(minInt32 - 1, maxInt32));
   Expect.equals(0, mod(minInt32 + 1, maxInt32));
+
+  Expect.equals(15, mod(-1, 16));
+  Expect.equals(15, mod(-17, 16));
+  Expect.equals(15, mod(-1, -16));
+  Expect.equals(15, mod(-17, -16));
+  Expect.equals(100, mod(100, 1 << 32));
+  Expect.equals(100, mod(100, -(1 << 32)));
+  Expect.equals((1 << 32) - 1, mod((1 << 35) - 1, 1 << 32));
+  Expect.equals((1 << 32) - 1, mod((1 << 35) - 1, -(1 << 32)));
+  Expect.equals(maxInt64, mod(-1, 1 << 63));
+  Expect.equals(0, mod(minInt64, 1 << 63));
 }
 
 doTruncDivConstants() {
diff --git a/tests/lib_2/isolate/kill_regexp_test.dart b/tests/lib_2/isolate/kill_regexp_test.dart
deleted file mode 100644
index 33cb8eb..0000000
--- a/tests/lib_2/isolate/kill_regexp_test.dart
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--intrinsify
-// VMOptions=--no_intrinsify
-
-import "dart:isolate";
-import "dart:async";
-import "package:expect/expect.dart";
-
-isomain1(replyPort) {
-  final regexp = new RegExp('[ab]c');
-  while (true) {
-    Expect.equals(4, regexp.allMatches("acbcacbc").length);
-  }
-}
-
-void main() {
-  for (int i = 0; i < 20; ++i) {
-    ReceivePort reply = new ReceivePort();
-    Isolate.spawn(isomain1, reply.sendPort).then((Isolate isolate) {
-      new Timer(new Duration(milliseconds: 50), () {
-        print('killing isolate $i');
-        isolate.kill(priority: Isolate.immediate);
-      });
-    });
-    reply.close();
-  }
-}
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index f6628fa..dc0745a 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -131,6 +131,9 @@
 [ $compiler != dartdevc && $checked && !$strong ]
 async/future_or_only_in_async_test/00: MissingCompileTimeError
 
+[ $compiler == dartk && $system == macos && $hot_reload && ($arch == simdbc || $arch == simdbc64) ]
+isolate/unresolved_ports_test: Pass, RuntimeError #  Issue 35410
+
 [ $compiler == none && $mode == product ]
 mirrors/library_enumeration_deferred_loading_test: RuntimeError, OK # Deferred loaded eagerly
 mirrors/library_import_deferred_loading_test: RuntimeError, OK # Deferred loaded eagerly
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index b5f6efc..ca19533 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -81,7 +81,6 @@
 [ $compiler == dartkb && $strong ]
 convert/streamed_conversion_json_utf8_decode_test: Pass, Timeout # Please triage.
 isolate/isolate_complex_messages_test: Pass, Crash # runtime/vm/object.cc: 17395: error: expected: type_arguments.IsNull() || type_arguments.IsCanonical()
-isolate/kill_regexp_test: Pass, Crash # Issue 35590 - isolate.cc: 2863: error: expected: sticky_error_ == Error::null()
 isolate/mandel_isolate_test: Pass, Timeout # Please triage.
 isolate/spawn_uri_exported_main_test: Pass, RuntimeError # Please triage: Expect.fail('Isolate was not spawned successfully.')
 mirrors/invocation_fuzz_test/emptyarray: Skip # Times out, issue 32232
diff --git a/tests/standalone_2/standalone_2_vm.status b/tests/standalone_2/standalone_2_vm.status
index cd92c8e..fcd29ba 100644
--- a/tests/standalone_2/standalone_2_vm.status
+++ b/tests/standalone_2/standalone_2_vm.status
@@ -73,16 +73,26 @@
 [ $arch == simdbc64 && $mode == debug && $checked ]
 io/web_socket_test: Pass, RuntimeError # Issue 26814.
 
+[ $arch == x64 && $compiler == dartkb && $runtime == vm && $system == linux ]
+io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
+
 [ $compiler != dart2analyzer && $system == windows ]
 io/platform_resolved_executable_test/06: RuntimeError # Issue 23641
 
+[ $mode == release && $runtime == vm && $system == linux && ($arch == simdbc64 || $arch == x64) ]
+io/http_bind_test: Pass, Timeout # Issue 35192
+
 [ $mode == release && $runtime == vm && $system == macos ]
+io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
 io/named_pipe_script_test: Pass, RuntimeError # Issue 28737
 
 [ $mode == release && $runtime == vm && $system == windows ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
 io/regress_7191_test: Pass, Timeout # Issue 28374: timeout.
 
+[ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64) ]
+io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
+
 [ $runtime == vm && !$checked && !$strong ]
 io/file_constructor_test: RuntimeError
 
diff --git a/tools/FAKE_COMMITS b/tools/FAKE_COMMITS
index 14748a9..c11b0c2 100644
--- a/tools/FAKE_COMMITS
+++ b/tools/FAKE_COMMITS
@@ -26,4 +26,5 @@
 Force build while trybots are broken, to check builders for brokenness.
 
 Analyzer branch commits:
-Force build on new analyzer-branch linux build with new workflow
\ No newline at end of file
+Force build on new analyzer-branch linux build with new workflow
+Trigger bots
diff --git a/tools/VERSION b/tools/VERSION
index 604b271..9e72048 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 1
 PATCH 1
-PRERELEASE 1
+PRERELEASE 2
 PRERELEASE_PATCH 0
diff --git a/tools/apps/update_homebrew/bin/generate.dart b/tools/apps/update_homebrew/bin/generate.dart
index e91933f..ea29e06 100644
--- a/tools/apps/update_homebrew/bin/generate.dart
+++ b/tools/apps/update_homebrew/bin/generate.dart
@@ -9,14 +9,14 @@
 import 'package:stack_trace/stack_trace.dart';
 import 'package:update_homebrew/update_homebrew.dart';
 
-main(List<String> args) async {
-  final parser = new ArgParser()
+void main(List<String> args) async {
+  final parser = ArgParser()
     ..addOption('revision', abbr: 'r')
-    ..addOption('channel', abbr: 'c', allowed: ['dev', 'stable']);
+    ..addOption('channel', abbr: 'c', allowed: supportedChannels);
 
   final options = parser.parse(args);
-  final revision = options['revision'];
-  final channel = options['channel'];
+  final revision = options['revision'] as String;
+  final channel = options['channel'] as String;
   if ([revision, channel].contains(null)) {
     print(
         "Usage: generate.dart -r revision -c channel <path_to_existing_dart.rb>");
@@ -31,7 +31,7 @@
   }
   final existingDartRb = options.rest.single;
 
-  var file = new File(existingDartRb);
+  var file = File(existingDartRb);
 
   if (!file.existsSync()) {
     print("Expected '$existingDartRb' to exist.");
diff --git a/tools/apps/update_homebrew/bin/update_homebrew.dart b/tools/apps/update_homebrew/bin/update_homebrew.dart
index e61bbdd..691f0a5 100644
--- a/tools/apps/update_homebrew/bin/update_homebrew.dart
+++ b/tools/apps/update_homebrew/bin/update_homebrew.dart
@@ -8,24 +8,24 @@
 import 'package:stack_trace/stack_trace.dart';
 import 'package:update_homebrew/update_homebrew.dart';
 
-main(List<String> args) async {
-  final parser = new ArgParser()
+void main(List<String> args) async {
+  final parser = ArgParser()
     ..addOption('revision', abbr: 'r')
-    ..addOption('channel', abbr: 'c', allowed: ['dev', 'stable'])
+    ..addOption('channel', abbr: 'c', allowed: supportedChannels)
     ..addOption('key', abbr: 'k');
   final options = parser.parse(args);
-  final revision = options['revision'];
-  final channel = options['channel'];
+  final revision = options['revision'] as String;
+  final channel = options['channel'] as String;
   if ([revision, channel].contains(null)) {
     print("Usage: update_homebrew.dart -r revision -c channel [-k ssh_key]\n"
-        "  ssh_key should allow pushes to ${GITHUB_REPO} on github");
+        "  ssh_key should allow pushes to $githubRepo on github");
     exitCode = 1;
     return;
   }
 
   Map<String, String> gitEnvironment;
 
-  final key = options['key'];
+  final key = options['key'] as String;
   if (key != null) {
     final sshWrapper = Platform.script.resolve('ssh_with_key').toFilePath();
     gitEnvironment = {'GIT_SSH': sshWrapper, 'SSH_KEY_PATH': key};
@@ -37,8 +37,8 @@
     try {
       var repository = tempDir.path;
 
-      await runGit(['clone', 'git@github.com:${GITHUB_REPO}.git', '.'],
-          repository, gitEnvironment);
+      await runGit(['clone', 'git@github.com:$githubRepo.git', '.'], repository,
+          gitEnvironment);
       await writeHomebrewInfo(channel, revision, repository);
       await runGit([
         'commit',
diff --git a/tools/apps/update_homebrew/lib/src/impl.dart b/tools/apps/update_homebrew/lib/src/impl.dart
new file mode 100644
index 0000000..2c17713
--- /dev/null
+++ b/tools/apps/update_homebrew/lib/src/impl.dart
@@ -0,0 +1,133 @@
+part of '../update_homebrew.dart';
+
+const _files = {
+  'dev': [_x64File, _ia32File],
+  'stable': [_x64File, _ia32File]
+};
+
+const _urlBase = 'https://storage.googleapis.com/dart-archive/channels';
+const _x64File = 'sdk/dartsdk-macos-x64-release.zip';
+const _ia32File = 'sdk/dartsdk-macos-ia32-release.zip';
+
+Future<String> _getHash256(
+    String channel, String revision, String download) async {
+  var client = http.Client();
+  try {
+    var api = storage.StorageApi(client);
+    var media = await api.objects.get('dart-archive',
+        'channels/$channel/release/$revision/$download.sha256sum',
+        downloadOptions: DownloadOptions.FullMedia) as Media;
+
+    var hashLine = await ascii.decodeStream(media.stream);
+    return RegExp('[0-9a-fA-F]*').stringMatch(hashLine);
+  } finally {
+    client.close();
+  }
+}
+
+Future<String> _getVersion(String channel, String revision) async {
+  var client = http.Client();
+  try {
+    var api = storage.StorageApi(client);
+
+    var media = await api.objects.get(
+        'dart-archive', 'channels/$channel/release/$revision/VERSION',
+        downloadOptions: DownloadOptions.FullMedia) as Media;
+
+    var versionObject =
+        await json.fuse(ascii).decoder.bind(media.stream).first as Map;
+    return versionObject['version'] as String;
+  } finally {
+    client.close();
+  }
+}
+
+Future<Map<String, String>> _getCurrentRevisions(String repository) async {
+  var revisions = <String, String>{};
+  var lines = await (File(p.join(repository, dartRbFileName))).readAsLines();
+
+  for (var channel in supportedChannels) {
+    /// This RegExp between release/ and /sdk matches
+    /// * 1 digit followed by
+    /// * Any number of letters, numbers, dashes and dots
+    /// This covers both numeric- and version-formatted revisions
+    ///
+    /// Note: all of the regexp escape slashes `\` are double-escaped within the
+    /// Dart string
+    final regExp = RegExp('channels/$channel/release/(\\d[\\w\\d\\-\\.]*)/sdk');
+
+    revisions[channel] =
+        regExp.firstMatch(lines.firstWhere(regExp.hasMatch)).group(1);
+  }
+  return revisions;
+}
+
+Future<Map<String, Map>> _getHashes(Map<String, String> revisions) async {
+  var hashes = <String, Map>{};
+  for (var channel in supportedChannels) {
+    hashes[channel] = {};
+    for (var file in _files[channel]) {
+      var hash = await _getHash256(channel, revisions[channel], file);
+      hashes[channel][file] = hash;
+    }
+  }
+  return hashes;
+}
+
+String _createDartFormula(
+        Map revisions, Map hashes, String devVersion, String stableVersion) =>
+    '''
+class Dart < Formula
+  desc "The Dart SDK"
+  homepage "https://www.dartlang.org/"
+
+  version "$stableVersion"
+  if Hardware::CPU.is_64_bit?
+    url "$_urlBase/stable/release/${revisions['stable']}/$_x64File"
+    sha256 "${hashes['stable'][_x64File]}"
+  else
+    url "$_urlBase/stable/release/${revisions['stable']}/$_ia32File"
+    sha256 "${hashes['stable'][_ia32File]}"
+  end
+
+  devel do
+    version "$devVersion"
+    if Hardware::CPU.is_64_bit?
+      url "$_urlBase/dev/release/${revisions['dev']}/$_x64File"
+      sha256 "${hashes['dev'][_x64File]}"
+    else
+      url "$_urlBase/dev/release/${revisions['dev']}/$_ia32File"
+      sha256 "${hashes['dev'][_ia32File]}"
+    end
+  end
+
+  def install
+    libexec.install Dir["*"]
+    bin.install_symlink "#{libexec}/bin/dart"
+    bin.write_exec_script Dir["#{libexec}/bin/{pub,dart?*}"]
+  end
+
+  def shim_script(target)
+    <<~EOS
+      #!/usr/bin/env bash
+      exec "#{prefix}/#{target}" "\$@"
+    EOS
+  end
+
+  def caveats; <<~EOS
+    Please note the path to the Dart SDK:
+      #{opt_libexec}
+    EOS
+  end
+
+  test do
+    (testpath/"sample.dart").write <<~EOS
+      void main() {
+        print(r"test message");
+      }
+    EOS
+
+    assert_equal "test message\\n", shell_output("#{bin}/dart sample.dart")
+  end
+end
+''';
diff --git a/tools/apps/update_homebrew/lib/update_homebrew.dart b/tools/apps/update_homebrew/lib/update_homebrew.dart
index 890a127..c2018d7 100644
--- a/tools/apps/update_homebrew/lib/update_homebrew.dart
+++ b/tools/apps/update_homebrew/lib/update_homebrew.dart
@@ -7,166 +7,34 @@
 import 'package:http/http.dart' as http;
 import 'package:path/path.dart' as p;
 
-const GITHUB_REPO = 'dart-lang/homebrew-dart';
+part 'src/impl.dart';
 
-const CHANNELS = const ['dev', 'stable'];
-
-const FILES = const {
-  'dev': const [x64File, ia32File],
-  'stable': const [x64File, ia32File]
-};
-
-const urlBase = 'https://storage.googleapis.com/dart-archive/channels';
-const x64File = 'sdk/dartsdk-macos-x64-release.zip';
-const ia32File = 'sdk/dartsdk-macos-ia32-release.zip';
+const githubRepo = 'dart-lang/homebrew-dart';
 
 const dartRbFileName = 'dart.rb';
 
-Future<String> getHash256(
-    String channel, String revision, String download) async {
-  var client = new http.Client();
-  try {
-    var api = new storage.StorageApi(client);
-    var media = await api.objects.get('dart-archive',
-        'channels/$channel/release/$revision/$download.sha256sum',
-        downloadOptions: DownloadOptions.FullMedia);
+Iterable<String> get supportedChannels => _files.keys;
 
-    var hashLine = await ascii.decodeStream(media.stream);
-    return new RegExp('[0-9a-fA-F]*').stringMatch(hashLine);
-  } finally {
-    client.close();
-  }
-}
-
-Future<String> getVersion(String channel, String revision) async {
-  var client = new http.Client();
-  try {
-    var api = new storage.StorageApi(client);
-
-    var media = await api.objects.get(
-        'dart-archive', 'channels/$channel/release/$revision/VERSION',
-        downloadOptions: DownloadOptions.FullMedia);
-
-    var versionObject =
-        await json.fuse(ascii).decoder.bind(media.stream).first as Map;
-    return versionObject['version'];
-  } finally {
-    client.close();
-  }
-}
-
-Future<Map> getCurrentRevisions(String repository) async {
-  var revisions = <String, String>{};
-  var lines =
-      await (new File(p.join(repository, dartRbFileName))).readAsLines();
-
-  for (var channel in CHANNELS) {
-    /// This RegExp between release/ and /sdk matches
-    /// * 1 digit followed by
-    /// * Any number of letters, numbers, dashes and dots
-    /// This covers both numeric- and version-formatted revisions
-    ///
-    /// Note: all of the regexp escape slashes `\` are double-escaped within the
-    /// Dart string
-    final regExp =
-        new RegExp('channels/$channel/release/(\\d[\\w\\d\\-\\.]*)/sdk');
-
-    revisions[channel] =
-        regExp.firstMatch(lines.firstWhere(regExp.hasMatch)).group(1);
-  }
-  return revisions;
-}
-
-Future<Map> getHashes(Map revisions) async {
-  var hashes = <String, Map>{};
-  for (var channel in CHANNELS) {
-    hashes[channel] = {};
-    for (var file in FILES[channel]) {
-      var hash = await getHash256(channel, revisions[channel], file);
-      hashes[channel][file] = hash;
-    }
-  }
-  return hashes;
-}
-
-Future writeHomebrewInfo(
+Future<void> writeHomebrewInfo(
     String channel, String revision, String repository) async {
-  var revisions = await getCurrentRevisions(repository);
+  var revisions = await _getCurrentRevisions(repository);
 
   if (revisions[channel] == revision) {
     print("Channel $channel is already at revision $revision in homebrew.");
     exit(0);
   }
   revisions[channel] = revision;
-  var hashes = await getHashes(revisions);
-  var devVersion = await getVersion('dev', revisions['dev']);
+  var hashes = await _getHashes(revisions);
+  var devVersion = await _getVersion('dev', revisions['dev']);
 
-  var stableVersion = await getVersion('stable', revisions['stable']);
+  var stableVersion = await _getVersion('stable', revisions['stable']);
 
-  await new File(p.join(repository, dartRbFileName)).writeAsString(
-      createDartFormula(revisions, hashes, devVersion, stableVersion),
+  await File(p.join(repository, dartRbFileName)).writeAsString(
+      _createDartFormula(revisions, hashes, devVersion, stableVersion),
       flush: true);
 }
 
-String createDartFormula(
-        Map revisions, Map hashes, String devVersion, String stableVersion) =>
-    '''
-class Dart < Formula
-  desc "The Dart SDK"
-  homepage "https://www.dartlang.org/"
-
-  version "$stableVersion"
-  if MacOS.prefer_64_bit?
-    url "$urlBase/stable/release/${revisions['stable']}/$x64File"
-    sha256 "${hashes['stable'][x64File]}"
-  else
-    url "$urlBase/stable/release/${revisions['stable']}/$ia32File"
-    sha256 "${hashes['stable'][ia32File]}"
-  end
-
-  devel do
-    version "$devVersion"
-    if MacOS.prefer_64_bit?
-      url "$urlBase/dev/release/${revisions['dev']}/$x64File"
-      sha256 "${hashes['dev'][x64File]}"
-    else
-      url "$urlBase/dev/release/${revisions['dev']}/$ia32File"
-      sha256 "${hashes['dev'][ia32File]}"
-    end
-  end
-
-  def install
-    libexec.install Dir["*"]
-    bin.install_symlink "#{libexec}/bin/dart"
-    bin.write_exec_script Dir["#{libexec}/bin/{pub,dart?*}"]
-  end
-
-  def shim_script(target)
-    <<~EOS
-      #!/usr/bin/env bash
-      exec "#{prefix}/#{target}" "\$@"
-    EOS
-  end
-
-  def caveats; <<~EOS
-    Please note the path to the Dart SDK:
-      #{opt_libexec}
-    EOS
-  end
-
-  test do
-    (testpath/"sample.dart").write <<~EOS
-      void main() {
-        print(r"test message");
-      }
-    EOS
-
-    assert_equal "test message\\n", shell_output("#{bin}/dart sample.dart")
-  end
-end
-''';
-
-Future runGit(List<String> args, String repository,
+Future<void> runGit(List<String> args, String repository,
     Map<String, String> gitEnvironment) async {
   print("git ${args.join(' ')}");
 
diff --git a/tools/apps/update_homebrew/pubspec.yaml b/tools/apps/update_homebrew/pubspec.yaml
index 7e342b6..9089614 100644
--- a/tools/apps/update_homebrew/pubspec.yaml
+++ b/tools/apps/update_homebrew/pubspec.yaml
@@ -1,5 +1,9 @@
 name: update_homebrew
-version: 0.1.0
+
+publish_to: none
+environment:
+  sdk: '>=2.0.0 <3.0.0'
+
 dependencies:
   _discoveryapis_commons: ^0.1.3+1
   args: ^1.5.0
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 8a731d5..a617489 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -117,6 +117,7 @@
       "out/DebugSIMDBC64/",
       "out/DebugX64/",
       "out/ProductX64/",
+      "out/ReleaseAndroidARM/",
       "out/ReleaseIA32/",
       "out/ReleaseSIMARM/",
       "out/ReleaseSIMARM64/",
@@ -134,6 +135,7 @@
       "samples/",
       "samples-dev/",
       "tools/",
+      "third_party/android_tools/sdk/platform-tools/adb",
       "third_party/gsutil/",
       "third_party/pkg/",
       "third_party/pkg_tested/",
@@ -176,7 +178,7 @@
         "runtime": "vm",
         "timeout": 240,
         "use-sdk": true
-      }},
+    }},
     "unittest-asserts-(release|debug)-(linux|mac|win)": {
       "options": {
         "compiler": "dartk",
@@ -184,15 +186,15 @@
         "runtime": "vm",
         "timeout": 240,
         "use-sdk": true
-      }},
+    }},
     "unittest-asserts-no-sdk-(linux|mac|win)": {
-        "options": {
-          "compiler": "dartk",
-          "enable-asserts": true,
-          "mode": "release",
-          "runtime": "vm",
-          "timeout": 240
-        }},
+      "options": {
+        "compiler": "dartk",
+        "enable-asserts": true,
+        "mode": "release",
+        "runtime": "vm",
+        "timeout": 240
+    }},
     "unittest-analyzer_use_fasta-linux": {
       "options": {
         "compiler": "none",
@@ -201,76 +203,47 @@
         "use-sdk": true,
         "vm-options": ["-DuseFastaParser=true"],
         "builder-tag": "analyzer_use_fasta"
-      }},
+    }},
     "dartk-asan-linux-release-(ia32|x64)": {
       "options": {
         "builder-tag": "asan",
         "timeout": 240
-      }},
+    }},
     "dart2js-(linux|mac|win)-chrome": {
       "options": {
         "use-sdk": true
-      }},
+    }},
     "dart2js-(linux|win)-firefox": {
       "options": {
         "use-sdk": true
-      }},
+    }},
     "dart2js-win-(ie11|edge)": {
       "options": {
         "use-sdk": true
-      }},
+    }},
     "dart2js-mac-safari": {
       "options": {
         "use-sdk": true
-      }},
-    "dart2js-faststartup-(linux|mac|win)-chrome": {
-      "options": {
-        "fast-startup": true,
-        "use-sdk": true
-      }},
-    "dart2js-faststartup-(linux|win)-firefox": {
-      "options": {
-        "fast-startup": true,
-        "use-sdk": true
-      }},
-    "dart2js-faststartup-win-(ie11|edge)": {
-      "options": {
-        "fast-startup": true,
-        "use-sdk": true
-      }},
-    "dart2js-faststartup-mac-safari": {
-      "options": {
-        "fast-startup": true,
-        "use-sdk": true
-      }},
+    }},
     "dart2js-minified-csp-linux-chrome": {
       "options": {
         "minified": true,
         "csp": true,
         "use-sdk": true
-      }},
-    "dart2js-minified-faststartup-csp-linux-chrome": {
-      "options": {
-        "minified": true,
-        "csp": true,
-        "fast-startup": true,
-        "use-sdk": true
-      }},
+    }},
     "dart2js-minified-linux-d8": {
       "options": {
         "minified": true,
         "use-sdk": true
-      }},
-    "dart2js-minified-faststartup-linux-d8": {
-      "options": {
-        "minified": true,
-        "fast-startup": true,
-        "use-sdk": true
-      }},
+    }},
     "dart2js-hostasserts-linux-ia32-d8": {
       "options": {
         "host-checked": true
-      }},
+    }},
+    "dartkp-android-release-arm": {
+      "options": {
+        "use-blobs": true
+    }},
     "dartkp-linux-release-(simarm|simarm64)": {
       "options": {
         "use-blobs": true
@@ -293,10 +266,15 @@
       "options": {
         "vm-options": ["--no-enable-malloc-hooks"]
     }},
-    "dartkp-bare-linux-release-x64": {
+    "dartkp-bare-linux-(debug|release)-x64": {
       "options": {
         "vm-options": ["--no-enable-malloc-hooks", "--use-bare-instructions"]
     }},
+    "dartkp-bare-linux-(debug|release)-(simarm|simarm64)": {
+      "options": {
+        "vm-options": ["--no-enable-malloc-hooks", "--use-bare-instructions"],
+        "use-blobs": true
+    }},
     "dartk-(linux|mac)-(debug|release)-(ia32|x64)": { },
     "dartk-checked-linux-release-x64": {
       "options": {
@@ -310,49 +288,49 @@
       "options": {
         "builder-tag": "optimization_counter_threshold",
         "vm-options": ["--optimization-counter-threshold=5"]
-      }},
+    }},
     "dartk-reload-linux-(debug|release)-x64": {
       "options": {
         "hot-reload": true
-      }},
+    }},
     "dartk-reload-mac-(debug|release)-simdbc64": {
       "options": {
         "hot-reload": true
-      }},
+    }},
     "dartk-reload-rollback-linux-(debug|release)-x64": {
       "options": {
         "hot-reload-rollback": true
-      }},
+    }},
     "app_jitk-linux-(debug|product|release)-x64": { },
     "dartkb-interpret-linux-(debug|release)-x64": {
       "options": {
         "vm-options": ["--enable_interpreter", "--compilation-counter-threshold=-1"]
-      }},
+    }},
     "dartkb-mixed-linux-(debug|release)-x64": {
       "options": {
         "vm-options": ["--enable_interpreter"]
-      }},
+    }},
     "dartkb-compile-linux-(debug|release)-x64": {
       "options": {
         "vm-options": ["--use_bytecode_compiler"]
-      }},
+    }},
     "(dartdevc|dartdevk)-checked-(linux|mac|win)-release-chrome": {
       "options": {
         "checked": true,
         "use-sdk": true
-      }},
+    }},
     "fasta-(linux|mac|win)": { },
     "analyzer-(linux|mac|win)": {
       "options": {
         "compiler": "dart2analyzer",
         "use-sdk": true
-      }},
+    }},
     "analyzer-asserts-(linux|mac|win)": {
       "options": {
         "compiler": "dart2analyzer",
         "enable-asserts": true,
         "use-sdk": true
-      }}
+    }}
   },
   "builder_configurations": [
     {
@@ -487,6 +465,33 @@
     },
     {
       "builders": [
+        "vm-kernel-precomp-android-release-arm"
+      ],
+      "meta": {
+        "description": "This configuration is used by the vm precomp builders on Android."
+      },
+      "steps": [
+        {
+          "name": "build dart",
+          "script": "tools/build.py",
+          "arguments": [
+            "runtime_kernel",
+            "dart_precompiled_runtime",
+            "--os=android"
+          ]
+        },
+        {
+          "name": "vm tests",
+          "arguments": [
+            "-ndartkp-android-${mode}-${arch}"
+          ],
+          "fileset": "vm-kernel",
+          "shards": 15
+        }
+      ]
+    },
+    {
+      "builders": [
         "vm-kernel-precomp-linux-debug-x64",
         "vm-kernel-precomp-linux-product-x64",
         "vm-kernel-precomp-linux-release-simarm",
@@ -520,7 +525,9 @@
     },
     {
       "builders": [
-        "vm-kernel-precomp-bare-linux-release-x64"
+        "vm-kernel-precomp-bare-linux-release-x64",
+        "vm-kernel-precomp-bare-linux-release-simarm",
+        "vm-kernel-precomp-bare-linux-release-simarm64"
       ],
       "meta": {
         "description": "This configuration is used by the vm kernel precomp builders using bare instructions."
@@ -1093,78 +1100,6 @@
       ]
     },
     {
-      "builders": [
-        "dart2js-strong-faststartup-linux-x64-chrome",
-        "dart2js-strong-faststartup-linux-x64-firefox",
-        "dart2js-strong-faststartup-mac-x64-chrome",
-        "dart2js-strong-faststartup-mac-x64-safari",
-        "dart2js-strong-faststartup-win-x64-chrome",
-        "dart2js-strong-faststartup-win-x64-edge",
-        "dart2js-strong-faststartup-win-x64-firefox",
-        "dart2js-strong-faststartup-win-x64-ie11"
-      ],
-      "meta": {
-        "description": "dart2js browser tests using the fast-startup emitter for Dart 2.0."
-      },
-      "steps": [
-        {
-          "name": "build dart",
-          "script": "tools/build.py",
-          "arguments": ["create_sdk"]
-        },
-        {
-          "name": "dart2js fast-startup tests",
-          "arguments": [
-            "-ndart2js-faststartup-${system}-${runtime}",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "--exclude_suite=observatory_ui"
-          ],
-          "shards": 6,
-          "fileset": "dart2js"
-        },
-        {
-          "name": "dart2js fast-startup co19_2 tests",
-          "arguments": [
-            "-ndart2js-faststartup-${system}-${runtime}",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "co19_2"
-          ],
-          "shards": 6,
-          "fileset": "dart2js"
-        },
-        {
-          "name": "dart2js fast-startup package tests",
-          "arguments": [
-            "-ndart2js-faststartup-${system}-${runtime}",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "pkg"
-          ]
-        },
-        {
-          "name": "dart2js fast-startup observatory-ui tests",
-          "arguments": [
-            "-ndart2js-faststartup-${system}-${runtime}",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "observatory_ui"
-          ]
-        },
-        {
-          "name": "dart2js fast-startup extra tests",
-          "arguments": [
-            "-ndart2js-faststartup-${system}-${runtime}",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "dart2js_extra",
-            "dart2js_native"
-          ]
-        }
-      ]
-    },
-    {
       "builders": ["dart2js-minified-strong-linux-x64-d8"],
       "meta": {
         "description": "dart2js tests for Dart 2.0."
@@ -1186,16 +1121,6 @@
           "fileset": "dart2js"
         },
         {
-          "name": "dart2js fast-startup tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-linux-d8",
-            "--dart2js-batch",
-            "--exclude_suite=observatory_ui"
-          ],
-          "shards": 6,
-          "fileset": "dart2js"
-        },
-        {
           "name": "dart2js package tests",
           "arguments": [
             "-ndart2js-minified-linux-d8",
@@ -1219,31 +1144,6 @@
             "dart2js_extra",
             "dart2js_native"
           ]
-        },
-        {
-          "name": "dart2js fast-startup package tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-linux-d8",
-            "--dart2js-batch",
-            "pkg"
-          ]
-        },
-        {
-          "name": "dart2js fast-startup observatory-ui tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-linux-d8",
-            "--dart2js-batch",
-            "observatory_ui"
-          ]
-        },
-        {
-          "name": "dart2js fast-startup extra tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-linux-d8",
-            "--dart2js-batch",
-            "dart2js_extra",
-            "dart2js_native"
-          ]
         }
       ]
     },
@@ -1270,17 +1170,6 @@
           "fileset": "dart2js"
         },
         {
-          "name": "dart2js fast-startup tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-csp-linux-chrome",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "--exclude_suite=observatory_ui"
-          ],
-          "shards": 4,
-          "fileset": "dart2js"
-        },
-        {
           "name": "dart2js package tests",
           "arguments": [
             "-ndart2js-minified-csp-linux-chrome",
@@ -1306,34 +1195,6 @@
             "dart2js_extra",
             "dart2js_native"
           ]
-        },
-        {
-          "name": "dart2js fast-startup package tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-csp-linux-chrome",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "pkg"
-          ]
-        },
-        {
-          "name": "dart2js fast-startup observatory-ui tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-csp-linux-chrome",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "observatory_ui"
-          ]
-        },
-        {
-          "name": "dart2js fast-startup extra tests",
-          "arguments": [
-            "-ndart2js-minified-faststartup-csp-linux-chrome",
-            "--dart2js-batch",
-            "--reset-browser-configuration",
-            "dart2js_extra",
-            "dart2js_native"
-          ]
         }
       ]
     },
diff --git a/tools/bots/update_flakiness.dart b/tools/bots/update_flakiness.dart
index c791b94..514592b 100755
--- a/tools/bots/update_flakiness.dart
+++ b/tools/bots/update_flakiness.dart
@@ -57,14 +57,7 @@
         testData["current"] = result["result"];
         testData["current_counter"] = 1;
       }
-      // Remove this code once all files are updated
-      const occurrencesMisspelled = "occurences";
-      var occurrences = testData[occurrencesMisspelled];
-      if (occurrences != null) {
-        testData["occurrences"] = occurrences;
-        testData.remove(occurrencesMisspelled);
-      }
-      occurrences = testData.putIfAbsent("occurrences", () => <String, dynamic>{});
+      var occurrences = testData.putIfAbsent("occurrences", () => <String, dynamic>{});
       occurrences.putIfAbsent(result["result"], () => 0);
       occurrences[result["result"]]++;
     }
@@ -79,6 +72,9 @@
   for (final key in keys) {
     final testData = data[key];
     if (testData["outcomes"].length < 2) continue;
+    // Remove this code once all files are updated
+    const occurrencesMisspelled = "occurences";
+    if (testData.containsKey(occurrencesMisspelled)) continue;
     // Forgive tests that have become deterministic again. If they flake less
     // than once in a 100 (p<1%), then if they flake again, the probability of
     // them getting past 5 runs of deflaking is 1%^5 = 0.00000001%.
diff --git a/tools/build.py b/tools/build.py
index a4ccf5e..237c486 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -16,6 +16,10 @@
 HOST_CPUS = utils.GuessCpus()
 SCRIPT_DIR = os.path.dirname(sys.argv[0])
 DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
+AVAILABLE_ARCHS = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6',
+    'simarmv5te', 'armv5te', 'simarm64', 'arm64',
+    'simdbc', 'simdbc64', 'armsimdbc', 'armsimdbc64']
+
 
 usage = """\
 usage: %%prog [options] [targets]
@@ -28,8 +32,7 @@
   result = optparse.OptionParser(usage=usage)
   result.add_option("-a", "--arch",
       help='Target architectures (comma-separated).',
-      metavar='[all,ia32,x64,simarm,arm,simarmv6,armv6,simarmv5te,armv5te,'
-              'simarm64,arm64,simdbc,armsimdbc]',
+      metavar='[all,' + ','.join(AVAILABLE_ARCHS) + ']',
       default=utils.GuessArchitecture())
   result.add_option("-b", "--bytecode",
       help='Build with the kernel bytecode interpreter. DEPRECATED.',
@@ -82,10 +85,7 @@
       print "Unknown mode %s" % mode
       return False
   for arch in options.arch:
-    archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6',
-             'simarmv5te', 'armv5te', 'simarm64', 'arm64',
-             'simdbc', 'simdbc64', 'armsimdbc', 'armsimdbc64']
-    if not arch in archs:
+    if not arch in AVAILABLE_ARCHS:
       print "Unknown arch %s" % arch
       return False
   options.os = [ProcessOsOption(os_name) for os_name in options.os]
@@ -301,10 +301,9 @@
   if not ProcessOptions(options, args):
     parser.print_help()
     return 1
-  # Determine which targets to build. The default is the "create_sdk" target,
-  # as the "all" target is unsupported and not built on any of the bots.
+  # Determine which targets to build. By default we build the "all" target.
   if len(args) == 0:
-    targets = ['create_sdk']
+    targets = ['all']
   else:
     targets = args
 
diff --git a/tools/generate_idefiles.py b/tools/generate_idefiles.py
index 51b41e6..900c25c 100755
--- a/tools/generate_idefiles.py
+++ b/tools/generate_idefiles.py
@@ -50,7 +50,7 @@
   if gn_result != 0:
     return gn_result
 
-  out_folder = utils.GetBuildRoot(HOST_OS, mode="debug", arch="x64")
+  out_folder = utils.GetBuildRoot(HOST_OS, mode="debug", arch=options.arch)
 
   if not os.path.isdir(out_folder):
     return 1
@@ -136,6 +136,10 @@
                       help="Target directory.",
                       default=utils.DART_DIR)
 
+  parser.add_argument("-a", "--arch",
+                      help="Target architecture for runtime sources.",
+                      default="x64")
+
   options = parser.parse_args(argv[1:])
 
   return GenerateIdeFiles(options)
diff --git a/tools/testing/dart/android.dart b/tools/testing/dart/android.dart
index 5cb232a..20e5fca 100644
--- a/tools/testing/dart/android.dart
+++ b/tools/testing/dart/android.dart
@@ -393,9 +393,6 @@
  * Helper to list all adb devices available.
  */
 class AdbHelper {
-  // This particular device seems to be flakily going offline / having problems.
-  static const blackListedDeviceIds = const <String>['06ada00c003b6f92'];
-
   static RegExp _deviceLineRegexp =
       new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
 
@@ -408,7 +405,6 @@
       return _deviceLineRegexp
           .allMatches(result.stdout as String)
           .map((Match m) => m.group(1))
-          .where((String deviceId) => !blackListedDeviceIds.contains(deviceId))
           .toList();
     });
   }
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 4cecd58..3afc50e 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -566,8 +566,6 @@
   Set<String> _testListPossibleFilenames;
   RegExp _selectorFilenameRegExp;
 
-  static final Uri co19SuiteLocation = Repository.uri.resolve("tests/co19_2/");
-
   StandardTestSuite(TestConfiguration configuration, String suiteName,
       Path suiteDirectory, List<String> statusFilePaths,
       {bool recursive: false})
@@ -1249,8 +1247,6 @@
   Map<String, dynamic> readOptionsFromFile(Uri uri) {
     if (uri.path.endsWith('.dill')) {
       return optionsFromKernelFile();
-    } else if ("$uri".startsWith("$co19SuiteLocation")) {
-      return readOptionsFromCo19File(uri);
     }
     RegExp testOptionsRegExp = new RegExp(r"// VMOptions=(.*)");
     RegExp environmentRegExp = new RegExp(r"// Environment=(.*)");
@@ -1394,9 +1390,11 @@
     //
     // Redo this code once we have a more precise test framework for detecting
     // and locating these errors.
-    var hasSyntaxError = contents.contains("/*@syntax-error=");
-    var hasCompileError =
-        hasSyntaxError || contents.contains("/*@compile-error=");
+    final hasSyntaxError = contents.contains("@syntax-error");
+    final hasCompileError =
+        hasSyntaxError || contents.contains("@compile-error");
+    final hasRuntimeError = contents.contains("@runtime-error");
+    final hasStaticWarning = contents.contains("@static-warning");
 
     return {
       "vmOptions": result,
@@ -1409,8 +1407,8 @@
       "packages": packages,
       "hasSyntaxError": hasSyntaxError,
       "hasCompileError": hasCompileError,
-      "hasRuntimeError": false,
-      "hasStaticWarning": false,
+      "hasRuntimeError": hasRuntimeError,
+      "hasStaticWarning": hasStaticWarning,
       "otherScripts": otherScripts,
       "otherResources": otherResources,
       "isMultitest": isMultitest,
@@ -1460,50 +1458,6 @@
     if (!needsVmOptions) return [[]];
     return optionsFromFile['vmOptions'] as List<List<String>>;
   }
-
-  /**
-   * Read options from a co19 test file.
-   *
-   * The reason this is different from [readOptionsFromFile] is that
-   * co19 is developed based on a contract which defines certain test
-   * tags. These tags may appear unused, but should not be removed
-   * without consulting with the co19 team.
-   *
-   * Also, [readOptionsFromFile] recognizes a number of additional
-   * tags that are not appropriate for use in general tests of
-   * conformance to the Dart language. Any Dart implementation must
-   * pass the co19 test suite as is, and not require extra flags,
-   * environment variables, configuration files, etc.
-   */
-  Map<String, dynamic> readOptionsFromCo19File(Uri uri) {
-    String contents = decodeUtf8(new File.fromUri(uri).readAsBytesSync());
-
-    bool hasSyntaxError = contents.contains("@syntax-error");
-    bool hasCompileError =
-        hasSyntaxError || contents.contains("@compile-error");
-    bool hasRuntimeError = contents.contains("@runtime-error");
-    bool hasStaticWarning = contents.contains("@static-warning");
-    bool isMultitest = multiTestRegExp.hasMatch(contents);
-
-    return {
-      "vmOptions": <List<String>>[[]],
-      "sharedOptions": <String>[],
-      "dart2jsOptions": <String>[],
-      "dartOptions": null,
-      "packageRoot": null,
-      "hasSyntaxError": hasSyntaxError,
-      "hasCompileError": hasCompileError,
-      "hasRuntimeError": hasRuntimeError,
-      "hasStaticWarning": hasStaticWarning,
-      "otherScripts": <String>[],
-      "otherResources": <String>[],
-      "isMultitest": isMultitest,
-      "isMultiHtmlTest": false,
-      "subtestNames": <String>[],
-      "isolateStubs": '',
-      "containsDomImport": false,
-    };
-  }
 }
 
 /// Used for testing packages in one-off settings, i.e., we pass in the actual