Version 2.0.0-dev.34.0

Merge commit 'd059e979741ec1d3671a860509d65a51df4fab59' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29e2bfd..4d1f835 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -82,6 +82,7 @@
   * `BigInt` class added to support integers greater than 64-bits.
   * Deprecated the `proxy` annotation.
   * Added `Provisional` class and `provisional` field.
+  * Added `pragma` annotation.
   * `RegExp` added static `escape` function.
   * The `Uri` class now correctly handles paths while running on Node.js on
     Windows.
@@ -123,6 +124,10 @@
     `SECONDS_PER_DAY` to `secondsPerDay`,
     `MINUTES_PER_DAY` to `minutesPerDay`, and
     `ZERO` to `zero`.
+  * Added `typeArguments` to `Invocation` class.
+  * Added constructors to invocation class that allows creation of
+    `Invocation` objects directly, without going through `noSuchMethod`.
+  * Added `unaryMinus` and `empty` constant symbols on the `Symbol` class.
 
 * `dart:developer`
 
diff --git a/DEPS b/DEPS
index c546b2a..f05a29f 100644
--- a/DEPS
+++ b/DEPS
@@ -35,8 +35,8 @@
   "chromium_git": "https://chromium.googlesource.com",
   "fuchsia_git": "https://fuchsia.googlesource.com",
 
-  "co19_rev": "@dec2b67aaab3bb7339b9764049707e71e601da3d",
-  "co19_2_rev": "@d8cdc47f759b0e89a517403ffa13eccd874bbbc0",
+  "co19_rev": "@d4b3fc9af414c990b4d22f313e533b275d2f27c5",
+  "co19_2_rev": "@74562e984a81673b581e148b5802684d6df840d2",
 
   # As Flutter does, we pull buildtools, including the clang toolchain, from
   # Fuchsia. This revision should be kept up to date with the revision pulled
@@ -57,13 +57,13 @@
   "barback-0.14.1_rev": "@38525",
   "barback_tag" : "@0.15.2+14",
   "bazel_worker_tag": "@v0.1.9",
-  "boolean_selector_tag" : "@1.0.2",
+  "boolean_selector_tag" : "@1.0.3",
   "boringssl_gen_rev": "@39762c7f9ee4d828ff212838fae79528b94d5443",
   "boringssl_rev" : "@a62dbf88d8a3c04446db833a1eb80a620cb1514d",
   "charcode_tag": "@v1.1.1",
   "chrome_rev" : "@19997",
   "cli_util_tag" : "@0.1.2+1",
-  "collection_tag": "@5943e1681204250f33a833eb5550f270357ad6c8",
+  "collection_tag": "@6ff408a512df30559c1a18b37cfac9fc51a4ceef",
   "convert_tag": "@2.0.1",
   "crypto_tag" : "@2.0.2+1",
   "csslib_tag" : "@0.14.1",
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart b/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart
index f526036..a468fd4 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_notifications.dart
@@ -15,7 +15,8 @@
         new FlutterOutlineComputer(file, content, lineInfo, dartUnit);
     protocol.FlutterOutline outline = computer.compute();
     // send notification
-    var params = new protocol.FlutterOutlineParams(file, outline);
+    var params = new protocol.FlutterOutlineParams(file, outline,
+        instrumentedCode: computer.instrumentedCode);
     server.sendNotification(params.toNotification());
   });
 }
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 89561f7..5e66826 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/computer/computer_outline.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/utilities/flutter.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -14,6 +15,19 @@
 
 /// Computer for Flutter specific outlines.
 class FlutterOutlineComputer {
+  static const CONSTRUCTOR_NAME = 'forDesignTime';
+
+  /// Code to append to the instrumented library code.
+  static const RENDER_APPEND = r'''
+
+final flutterDesignerWidgets = <int, Widget>{};
+
+T _registerWidgetInstance<T extends Widget>(int id, T widget) {
+  flutterDesignerWidgets[id] = widget;
+  return widget;
+}
+''';
+
   final String file;
   final String content;
   final LineInfo lineInfo;
@@ -22,6 +36,15 @@
 
   final List<protocol.FlutterOutline> _depthFirstOrder = [];
 
+  int nextWidgetId = 0;
+
+  /// This map is filled with information about widget classes that can be
+  /// rendered. Its keys are class name offsets.
+  final Map<int, _WidgetClass> widgets = {};
+
+  final List<protocol.SourceEdit> instrumentationEdits = [];
+  String instrumentedCode;
+
   FlutterOutlineComputer(this.file, this.content, this.lineInfo, this.unit)
       : typeProvider = unit.element.context.typeProvider;
 
@@ -30,8 +53,27 @@
             file, lineInfo, unit,
             withBasicFlutter: false)
         .compute();
+
+    // Find widget classes.
+    // IDEA plugin only supports rendering widgets in libraries.
+    if (unit.element.source == unit.element.librarySource) {
+      _findWidgets();
+    }
+
+    // Convert Dart outlines into Flutter outlines.
     var flutterDartOutline = _convert(dartOutline);
+
+    // Create outlines for widgets.
     unit.accept(new _FlutterOutlineBuilder(this));
+
+    // Compute instrumented code.
+    if (widgets.isNotEmpty) {
+      instrumentationEdits.sort((a, b) => b.offset - a.offset);
+      instrumentedCode =
+          SourceEdit.applySequence(content, instrumentationEdits);
+      instrumentedCode += RENDER_APPEND;
+    }
+
     return flutterDartOutline;
   }
 
@@ -80,6 +122,14 @@
     }
   }
 
+  int _addInstrumentationEdits(Expression expression) {
+    int id = nextWidgetId++;
+    instrumentationEdits.add(new protocol.SourceEdit(
+        expression.offset, 0, '_registerWidgetInstance($id, '));
+    instrumentationEdits.add(new protocol.SourceEdit(expression.end, 0, ')'));
+    return id;
+  }
+
   protocol.FlutterOutline _convert(protocol.Outline dartOutline) {
     protocol.FlutterOutline flutterOutline = new protocol.FlutterOutline(
         protocol.FlutterOutlineKind.DART_ELEMENT,
@@ -89,6 +139,17 @@
     if (dartOutline.children != null) {
       flutterOutline.children = dartOutline.children.map(_convert).toList();
     }
+
+    // Fill rendering information for widget classes.
+    if (dartOutline.element.kind == protocol.ElementKind.CLASS) {
+      var widget = widgets[dartOutline.element.location.offset];
+      if (widget != null) {
+        flutterOutline.renderConstructor = CONSTRUCTOR_NAME;
+        flutterOutline.stateOffset = widget.state?.offset;
+        flutterOutline.stateLength = widget.state?.length;
+      }
+    }
+
     _depthFirstOrder.add(flutterOutline);
     return flutterOutline;
   }
@@ -105,6 +166,8 @@
     String className = type.element.displayName;
 
     if (node is InstanceCreationExpression) {
+      int id = _addInstrumentationEdits(node);
+
       var attributes = <protocol.FlutterOutlineAttribute>[];
       var children = <protocol.FlutterOutline>[];
       for (var argument in node.argumentList.arguments) {
@@ -144,7 +207,10 @@
 
       return new protocol.FlutterOutline(
           protocol.FlutterOutlineKind.NEW_INSTANCE, node.offset, node.length,
-          className: className, attributes: attributes, children: children);
+          className: className,
+          attributes: attributes,
+          children: children,
+          id: id);
     }
 
     // A generic Widget typed expression.
@@ -162,13 +228,89 @@
         label = _getShortLabel(node);
       }
 
+      int id = _addInstrumentationEdits(node);
       return new protocol.FlutterOutline(kind, node.offset, node.length,
-          className: className, variableName: variableName, label: label);
+          className: className,
+          variableName: variableName,
+          label: label,
+          id: id);
     }
 
     return null;
   }
 
+  /// Return the `State` declaration for the given `StatefulWidget` declaration.
+  /// Return `null` if cannot be found.
+  ClassDeclaration _findState(ClassDeclaration widget) {
+    MethodDeclaration createStateMethod = widget.members.firstWhere(
+        (method) =>
+            method is MethodDeclaration &&
+            method.name.name == 'createState' &&
+            method.body != null,
+        orElse: () => null);
+    if (createStateMethod == null) {
+      return null;
+    }
+
+    DartType stateType;
+    {
+      FunctionBody buildBody = createStateMethod.body;
+      if (buildBody is ExpressionFunctionBody) {
+        stateType = buildBody.expression.staticType;
+      } else if (buildBody is BlockFunctionBody) {
+        List<Statement> statements = buildBody.block.statements;
+        if (statements.isNotEmpty) {
+          Statement lastStatement = statements.last;
+          if (lastStatement is ReturnStatement) {
+            stateType = lastStatement.expression?.staticType;
+          }
+        }
+      }
+    }
+    if (stateType == null) {
+      return null;
+    }
+
+    ClassElement stateElement;
+    if (stateType is InterfaceType && isState(stateType.element)) {
+      stateElement = stateType.element;
+    } else {
+      return null;
+    }
+
+    for (var stateNode in unit.declarations) {
+      if (stateNode is ClassDeclaration && stateNode.element == stateElement) {
+        return stateNode;
+      }
+    }
+
+    return null;
+  }
+
+  /// Fill [widgets] with information about classes that can be rendered.
+  void _findWidgets() {
+    for (var widget in unit.declarations) {
+      if (widget is ClassDeclaration) {
+        int nameOffset = widget.name.offset;
+
+        var designTimeConstructor = widget.getConstructor(CONSTRUCTOR_NAME);
+        if (designTimeConstructor == null) {
+          continue;
+        }
+
+        InterfaceType superType = widget.element.supertype;
+        if (isExactlyStatelessWidgetType(superType)) {
+          widgets[nameOffset] = new _WidgetClass(nameOffset);
+        } else if (isExactlyStatefulWidgetType(superType)) {
+          ClassDeclaration state = _findState(widget);
+          if (state != null) {
+            widgets[nameOffset] = new _WidgetClass(nameOffset, state);
+          }
+        }
+      }
+    }
+  }
+
   String _getShortLabel(AstNode node) {
     if (node is MethodInvocation) {
       var buffer = new StringBuffer();
@@ -214,3 +356,13 @@
     }
   }
 }
+
+/// Information about a Widget class that can be rendered.
+class _WidgetClass {
+  final int nameOffset;
+
+  /// If a `StatefulWidget` with the `State` in the same file.
+  final ClassDeclaration state;
+
+  _WidgetClass(this.nameOffset, [this.state]);
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 57cf81d..f0d5a9e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -38,6 +38,7 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/task/model.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
 import 'package:analyzer_plugin/src/utilities/completion/optype.dart';
 
@@ -77,8 +78,8 @@
       ..replacementLength = range.length;
 
     // Request Dart specific completions from each contributor
-    Map<String, CompletionSuggestion> suggestionMap =
-        <String, CompletionSuggestion>{};
+    var suggestionMap = <String, CompletionSuggestion>{};
+    var constructorMap = <String, List<String>>{};
     List<DartCompletionContributor> contributors = <DartCompletionContributor>[
       new ArgListContributor(),
       new CombinatorContributor(),
@@ -109,11 +110,25 @@
       request.checkAborted();
 
       for (CompletionSuggestion newSuggestion in contributorSuggestions) {
-        var oldSuggestion = suggestionMap.putIfAbsent(
-            newSuggestion.completion, () => newSuggestion);
-        if (newSuggestion != oldSuggestion &&
-            newSuggestion.relevance > oldSuggestion.relevance) {
-          suggestionMap[newSuggestion.completion] = newSuggestion;
+        String key = newSuggestion.completion;
+
+        // Append parenthesis for constructors to disambiguate from classes.
+        if (_isConstructor(newSuggestion)) {
+          key += '()';
+          String className = _getConstructorClassName(newSuggestion);
+          _ensureList(constructorMap, className).add(key);
+        }
+
+        // Local declarations hide both the class and its constructors.
+        if (!_isClass(newSuggestion)) {
+          List<String> constructorKeys = constructorMap[key];
+          constructorKeys?.forEach(suggestionMap.remove);
+        }
+
+        CompletionSuggestion oldSuggestion = suggestionMap[key];
+        if (oldSuggestion == null ||
+            oldSuggestion.relevance < newSuggestion.relevance) {
+          suggestionMap[key] = newSuggestion;
         }
       }
     }
@@ -127,6 +142,33 @@
     request.checkAborted();
     return suggestions;
   }
+
+  static List<String> _ensureList(Map<String, List<String>> map, String key) {
+    List<String> list = map[key];
+    if (list == null) {
+      list = <String>[];
+      map[key] = list;
+    }
+    return list;
+  }
+
+  static String _getConstructorClassName(CompletionSuggestion suggestion) {
+    String completion = suggestion.completion;
+    int dotIndex = completion.indexOf('.');
+    if (dotIndex != -1) {
+      return completion.substring(0, dotIndex);
+    } else {
+      return completion;
+    }
+  }
+
+  static bool _isClass(CompletionSuggestion suggestion) {
+    return suggestion.element?.kind == protocol.ElementKind.CLASS;
+  }
+
+  static bool _isConstructor(CompletionSuggestion suggestion) {
+    return suggestion.element?.kind == protocol.ElementKind.CONSTRUCTOR;
+  }
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/utilities/flutter.dart b/pkg/analysis_server/lib/src/utilities/flutter.dart
index c03cdff..b5c82f1 100644
--- a/pkg/analysis_server/lib/src/utilities/flutter.dart
+++ b/pkg/analysis_server/lib/src/utilities/flutter.dart
@@ -14,9 +14,12 @@
 const _BASIC_URI = "package:flutter/src/widgets/basic.dart";
 const _CENTER_NAME = "Center";
 const _PADDING_NAME = "Padding";
+const _STATE_NAME = "State";
+const _STATEFUL_WIDGET_NAME = "StatefulWidget";
 const _STATELESS_WIDGET_NAME = "StatelessWidget";
 const _WIDGET_NAME = "Widget";
 const _WIDGET_URI = "package:flutter/src/widgets/framework.dart";
+final _frameworkUri = Uri.parse('package:flutter/src/widgets/framework.dart');
 
 void convertChildToChildren(
     InstanceCreationExpression childArg,
@@ -241,6 +244,14 @@
 }
 
 /**
+ * Return `true` if the given [type] is the Flutter class `StatefulWidget`.
+ */
+bool isExactlyStatefulWidgetType(DartType type) {
+  return type is InterfaceType &&
+      _isExactWidget(type.element, _STATEFUL_WIDGET_NAME, _WIDGET_URI);
+}
+
+/**
  * Return `true` if the given [type] is the Flutter class `StatelessWidget`.
  */
 bool isExactlyStatelessWidgetType(DartType type) {
@@ -276,6 +287,12 @@
       isWidgetType(type.typeArguments[0]);
 }
 
+/// Return `true` if the given [element] has the Flutter class `State` as
+/// a superclass.
+bool isState(ClassElement element) {
+  return _hasSupertype(element, _frameworkUri, _STATE_NAME);
+}
+
 /**
  * Return `true` if the given [element] is the Flutter class `Widget`, or its
  * subtype.
@@ -329,6 +346,23 @@
   return type is InterfaceType && isWidget(type.element);
 }
 
+/// Return `true` if the given [element] has a supertype with the [requiredName]
+/// defined in the file with the [requiredUri].
+bool _hasSupertype(ClassElement element, Uri requiredUri, String requiredName) {
+  if (element == null) {
+    return false;
+  }
+  for (InterfaceType type in element.allSupertypes) {
+    if (type.name == requiredName) {
+      Uri uri = type.element.source.uri;
+      if (uri == requiredUri) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 /**
  * Return `true` if the given [element] is the exact [type] defined in the
  * file with the given [uri].
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
index 75833ab..06829ed 100644
--- a/pkg/analysis_server/test/completion_test_support.dart
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -37,6 +37,13 @@
         if (matchingSuggestion == null) {
           matchingSuggestion = suggestion;
         } else {
+          // It is OK to have a class and its default constructor suggestions.
+          if (matchingSuggestion.element?.kind == ElementKind.CLASS &&
+                  suggestion.element?.kind == ElementKind.CONSTRUCTOR ||
+              matchingSuggestion.element?.kind == ElementKind.CONSTRUCTOR &&
+                  suggestion.element?.kind == ElementKind.CLASS) {
+            return;
+          }
           fail(
               "Expected exactly one '$completion' but found multiple:\n  $suggestedCompletions");
         }
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 57cd8ee..07c23fa 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -274,8 +274,10 @@
     return getSuggestions().then((_) {
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object',
+          elementKind: ElementKind.CLASS);
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement',
+          elementKind: ElementKind.CLASS);
       assertNoResult('test');
     });
   }
@@ -430,7 +432,8 @@
     return getSuggestions().then((_) {
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object',
+          elementKind: ElementKind.CLASS);
       assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
       assertNoResult('HtmlElement');
       assertNoResult('test');
@@ -597,6 +600,32 @@
     });
   }
 
+  test_local_implicitCreation() async {
+    addTestFile('''
+class A {
+  A();
+  A.named();
+}
+main() {
+  ^
+}
+''');
+    await getSuggestions();
+
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+
+    // The class is suggested.
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'A',
+        elementKind: ElementKind.CLASS);
+
+    // Both constructors - default and named, are suggested.
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'A',
+        elementKind: ElementKind.CONSTRUCTOR);
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'A.named',
+        elementKind: ElementKind.CONSTRUCTOR);
+  }
+
   test_local_named_constructor() {
     addTestFile('class A {A.c(); x() {new A.^}}');
     return getSuggestions().then((_) {
@@ -624,19 +653,47 @@
     });
   }
 
+  test_local_shadowClass() async {
+    addTestFile('''
+class A {
+  A();
+  A.named();
+}
+main() {
+  int A = 0;
+  ^
+}
+''');
+    await getSuggestions();
+
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+
+    // The class is suggested.
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'A',
+        relevance: DART_RELEVANCE_LOCAL_VARIABLE);
+
+    // Class and all its constructors are shadowed by the local variable.
+    assertNoResult('A', elementKind: ElementKind.CLASS);
+    assertNoResult('A', elementKind: ElementKind.CONSTRUCTOR);
+    assertNoResult('A.named', elementKind: ElementKind.CONSTRUCTOR);
+  }
+
   test_locals() {
     addTestFile('class A {var a; x() {var b;^}} class DateTime { }');
     return getSuggestions().then((_) {
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A',
+          elementKind: ElementKind.CLASS);
       assertHasResult(CompletionSuggestionKind.INVOCATION, 'a',
           relevance: DART_RELEVANCE_LOCAL_FIELD);
       assertHasResult(CompletionSuggestionKind.INVOCATION, 'b',
           relevance: DART_RELEVANCE_LOCAL_VARIABLE);
       assertHasResult(CompletionSuggestionKind.INVOCATION, 'x',
           relevance: DART_RELEVANCE_LOCAL_METHOD);
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'DateTime');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'DateTime',
+          elementKind: ElementKind.CLASS);
     });
   }
 
@@ -677,9 +734,12 @@
     return getSuggestions().then((_) {
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object',
+          elementKind: ElementKind.CLASS);
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement',
+          elementKind: ElementKind.CLASS);
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A',
+          elementKind: ElementKind.CLASS);
       assertNoResult('test');
     });
   }
@@ -697,9 +757,12 @@
     return getSuggestions().then((_) {
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object',
+          elementKind: ElementKind.CLASS);
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement',
+          elementKind: ElementKind.CLASS);
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A',
+          elementKind: ElementKind.CLASS);
       assertNoResult('test');
     });
   }
@@ -734,7 +797,8 @@
     return getSuggestions().then((_) {
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object',
+          elementKind: ElementKind.CLASS);
       assertNoResult('HtmlElement');
       assertNoResult('test');
     });
diff --git a/pkg/analysis_server/test/domain_completion_util.dart b/pkg/analysis_server/test/domain_completion_util.dart
index 6f1da48..0a6a543 100644
--- a/pkg/analysis_server/test/domain_completion_util.dart
+++ b/pkg/analysis_server/test/domain_completion_util.dart
@@ -43,9 +43,13 @@
       {int relevance: DART_RELEVANCE_DEFAULT,
       bool isDeprecated: false,
       bool isPotential: false,
-      int selectionOffset}) {
+      int selectionOffset,
+      ElementKind elementKind}) {
     var cs;
     suggestions.forEach((s) {
+      if (elementKind != null && s.element?.kind != elementKind) {
+        return;
+      }
       if (s.completion == completion) {
         if (cs == null) {
           cs = s;
@@ -56,7 +60,13 @@
     });
     if (cs == null) {
       var completions = suggestions.map((s) => s.completion).toList();
-      fail('expected "$completion" but found\n $completions');
+
+      String expectationText = '"$completion"';
+      if (elementKind != null) {
+        expectationText += ' ($elementKind)';
+      }
+
+      fail('expected $expectationText, but found\n $completions');
     }
     expect(cs.kind, equals(kind));
     expect(cs.relevance, equals(relevance));
@@ -66,8 +76,10 @@
     expect(cs.isPotential, equals(isPotential));
   }
 
-  void assertNoResult(String completion) {
-    if (suggestions.any((cs) => cs.completion == completion)) {
+  void assertNoResult(String completion, {ElementKind elementKind}) {
+    if (suggestions.any((cs) =>
+        cs.completion == completion &&
+        (elementKind == null || cs.element?.kind == elementKind))) {
       fail('did not expect completion: $completion');
     }
   }
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 6850ece..1dc9fe8 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
@@ -25,6 +25,8 @@
 class FlutterOutlineComputerTest extends AbstractContextTest {
   String testPath;
   String testCode;
+  AnalysisResult analysisResult;
+  FlutterOutlineComputer computer;
 
   @override
   void setUp() {
@@ -289,6 +291,167 @@
 ''');
   }
 
+  test_render_BAD_noDesignTimeConstructor() async {
+    FlutterOutline unitOutline = await _computeOutline('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return new Row();
+  }
+}
+''');
+    var myWidget = unitOutline.children[0];
+    expect(myWidget.renderConstructor, isNull);
+    expect(myWidget.stateOffset, isNull);
+    expect(myWidget.stateLength, isNull);
+
+    expect(computer.instrumentedCode, isNull);
+  }
+
+  test_render_BAD_part() async {
+    // Use test.dart as a part of a library.
+    // Add the library to the driver so that it is analyzed before the part.
+    var libPath = newFile('/test_lib.dart', content: r'''
+part 'test.dart';
+import 'package:flutter/widgets.dart';
+''').path;
+    driver.addFile(libPath);
+
+    FlutterOutline unitOutline = await _computeOutline('''
+part of 'test_lib.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.forDesignTime();
+
+  @override
+  Widget build(BuildContext context) {
+    return new Row();
+  }
+}
+''');
+
+    // Analysis is successful, no errors.
+    expect(analysisResult.errors, isEmpty);
+
+    // No instrumentation, because not a library.
+    expect(computer.instrumentedCode, isNull);
+
+    // There is forDesignTime() constructor, but we don't handle parts.
+    var myWidget = unitOutline.children[0];
+    expect(myWidget.renderConstructor, isNull);
+  }
+
+  test_render_stateful_createState_blockBody() async {
+    FlutterOutline unitOutline = await _computeOutline('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatefulWidget {
+  MyWidget.forDesignTime();
+
+  @override
+  MyWidgetState createState() {
+    return new MyWidgetState();
+  }
+}
+
+class MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return new Container(),
+  }
+}
+''');
+    var myWidget = unitOutline.children[0];
+    expect(myWidget.renderConstructor, 'forDesignTime');
+    expect(myWidget.stateOffset, 192);
+    expect(myWidget.stateLength, 130);
+  }
+
+  test_render_stateful_createState_expressionBody() async {
+    FlutterOutline unitOutline = await _computeOutline('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatefulWidget {
+  MyWidget.forDesignTime();
+
+  @override
+  MyWidgetState createState() => new MyWidgetState();
+}
+
+class MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return new Container(),
+  }
+}
+''');
+    var myWidget = unitOutline.children[0];
+    expect(myWidget.renderConstructor, 'forDesignTime');
+    expect(myWidget.stateOffset, 178);
+    expect(myWidget.stateLength, 130);
+  }
+
+  test_render_stateless() async {
+    FlutterOutline unitOutline = await _computeOutline('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.forDesignTime();
+
+  @override
+  Widget build(BuildContext context) {
+    return new Row(
+      children: <Widget>[
+        new Text('aaa'),
+        new Text('bbb'),
+      ],
+    );
+  }
+}
+''');
+    var myWidget = unitOutline.children[0];
+    expect(myWidget.renderConstructor, 'forDesignTime');
+    expect(myWidget.stateOffset, isNull);
+    expect(myWidget.stateLength, isNull);
+
+    expect(
+        computer.instrumentedCode,
+        r'''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.forDesignTime();
+
+  @override
+  Widget build(BuildContext context) {
+    return _registerWidgetInstance(0, new Row(
+      children: <Widget>[
+        _registerWidgetInstance(1, new Text('aaa')),
+        _registerWidgetInstance(2, new Text('bbb')),
+      ],
+    ));
+  }
+}
+''' +
+            FlutterOutlineComputer.RENDER_APPEND);
+
+    var build = myWidget.children[1];
+
+    var row = build.children[0];
+    expect(row.className, 'Row');
+    expect(row.id, 0);
+
+    var textA = row.children[0];
+    expect(textA.className, 'Text');
+    expect(textA.id, 1);
+
+    var textB = row.children[1];
+    expect(textB.className, 'Text');
+    expect(textB.id, 2);
+  }
+
   test_variableName() async {
     FlutterOutline unitOutline = await _computeOutline('''
 import 'package:flutter/widgets.dart';
@@ -323,10 +486,10 @@
   Future<FlutterOutline> _computeOutline(String code) async {
     testCode = code;
     newFile(testPath, content: code);
-    AnalysisResult analysisResult = await driver.getResult(testPath);
-    return new FlutterOutlineComputer(
-            testPath, testCode, analysisResult.lineInfo, analysisResult.unit)
-        .compute();
+    analysisResult = await driver.getResult(testPath);
+    computer = new FlutterOutlineComputer(
+        testPath, testCode, analysisResult.lineInfo, analysisResult.unit);
+    return computer.compute();
   }
 
   void _expect(FlutterOutline outline,
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index b3490e1..b8c90da 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -294,11 +294,20 @@
 
   final _UninstantiatedBoundChecker _uninstantiatedBoundChecker;
 
+  /// Setting this flag to `true` disables the check for conflicting generics.
+  /// This is used when running with the old task model to work around
+  /// dartbug.com/32421.
+  ///
+  /// TODO(paulberry): remove this flag once dartbug.com/32421 is properly
+  /// fixed.
+  final bool disableConflictingGenericsCheck;
+
   /**
    * Initialize a newly created error verifier.
    */
   ErrorVerifier(ErrorReporter errorReporter, this._currentLibrary,
-      this._typeProvider, this._inheritanceManager, this.enableSuperMixins)
+      this._typeProvider, this._inheritanceManager, this.enableSuperMixins,
+      {this.disableConflictingGenericsCheck: false})
       : _errorReporter = errorReporter,
         _uninstantiatedBoundChecker =
             new _UninstantiatedBoundChecker(errorReporter) {
@@ -1328,7 +1337,9 @@
 
       if (_options.strongMode) {
         _checkForMixinWithConflictingPrivateMember(withClause, superclass);
-        _checkForConflictingGenerics(node);
+        if (!disableConflictingGenericsCheck) {
+          _checkForConflictingGenerics(node);
+        }
       }
     }
   }
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 01ac085..fe9f7fe 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -846,12 +846,52 @@
    *       | identifier
    */
   Expression parseAssignableExpression(bool primaryAllowed) {
-    if (_matchesKeyword(Keyword.SUPER)) {
-      return parseAssignableSelector(
-          astFactory.superExpression(getAndAdvance()), false,
-          allowConditional: false);
+    //
+    // A primary expression can start with an identifier. We resolve the
+    // ambiguity by determining whether the primary consists of anything other
+    // than an identifier and/or is followed by an assignableSelector.
+    //
+    Expression expression = parsePrimaryExpression();
+    bool isOptional =
+        primaryAllowed || _isValidAssignableExpression(expression);
+    while (true) {
+      while (_isLikelyArgumentList()) {
+        TypeArgumentList typeArguments = _parseOptionalTypeArguments();
+        ArgumentList argumentList = parseArgumentList();
+        Expression currentExpression = expression;
+        if (currentExpression is SimpleIdentifier) {
+          expression = astFactory.methodInvocation(
+              null, null, currentExpression, typeArguments, argumentList);
+        } else if (currentExpression is PrefixedIdentifier) {
+          expression = astFactory.methodInvocation(
+              currentExpression.prefix,
+              currentExpression.period,
+              currentExpression.identifier,
+              typeArguments,
+              argumentList);
+        } else if (currentExpression is PropertyAccess) {
+          expression = astFactory.methodInvocation(
+              currentExpression.target,
+              currentExpression.operator,
+              currentExpression.propertyName,
+              typeArguments,
+              argumentList);
+        } else {
+          expression = astFactory.functionExpressionInvocation(
+              expression, typeArguments, argumentList);
+        }
+        if (!primaryAllowed) {
+          isOptional = false;
+        }
+      }
+      Expression selectorExpression = parseAssignableSelector(
+          expression, isOptional || (expression is PrefixedIdentifier));
+      if (identical(selectorExpression, expression)) {
+        return expression;
+      }
+      expression = selectorExpression;
+      isOptional = true;
     }
-    return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed);
   }
 
   /**
@@ -4457,7 +4497,7 @@
    *
    *     selector ::=
    *         assignableSelector
-   *       | argumentList
+   *       | argumentPart
    */
   Expression parsePostfixExpression() {
     Expression operand = parseAssignableExpression(true);
@@ -4583,8 +4623,6 @@
     } else if (keyword == Keyword.THIS) {
       return astFactory.thisExpression(getAndAdvance());
     } else if (keyword == Keyword.SUPER) {
-      // TODO(paulberry): verify with Gilad that "super" must be followed by
-      // unconditionalAssignableSelector in this case.
       return parseAssignableSelector(
           astFactory.superExpression(getAndAdvance()), false,
           allowConditional: false);
@@ -5416,7 +5454,7 @@
             operator, astFactory.superExpression(getAndAdvance()));
       }
       return astFactory.prefixExpression(
-          operator, _parseAssignableExpressionNotStartingWithSuper(false));
+          operator, parseAssignableExpression(false));
     } else if (type == TokenType.PLUS) {
       _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
       return createSyntheticIdentifier();
@@ -6382,6 +6420,21 @@
   }
 
   /**
+   * Return `true` if the given [expression] is a primary expression that is
+   * allowed to be an assignable expression without any assignable selector.
+   */
+  bool _isValidAssignableExpression(Expression expression) {
+    if (expression is SimpleIdentifier) {
+      return true;
+    } else if (expression is PropertyAccess) {
+      return expression.target is SuperExpression;
+    } else if (expression is IndexExpression) {
+      return expression.target is SuperExpression;
+    }
+    return false;
+  }
+
+  /**
    * Increments the error reporting lock level. If level is more than `0`, then
    * [reportError] wont report any error.
    */
@@ -6520,61 +6573,6 @@
   }
 
   /**
-   * Parse an assignable expression given that the current token is not 'super'.
-   * The [primaryAllowed] is `true` if the expression is allowed to be a primary
-   * without any assignable selector. Return the assignable expression that was
-   * parsed.
-   */
-  Expression _parseAssignableExpressionNotStartingWithSuper(
-      bool primaryAllowed) {
-    //
-    // A primary expression can start with an identifier. We resolve the
-    // ambiguity by determining whether the primary consists of anything other
-    // than an identifier and/or is followed by an assignableSelector.
-    //
-    Expression expression = parsePrimaryExpression();
-    bool isOptional = primaryAllowed || expression is SimpleIdentifier;
-    while (true) {
-      while (_isLikelyArgumentList()) {
-        TypeArgumentList typeArguments = _parseOptionalTypeArguments();
-        ArgumentList argumentList = parseArgumentList();
-        Expression currentExpression = expression;
-        if (currentExpression is SimpleIdentifier) {
-          expression = astFactory.methodInvocation(
-              null, null, currentExpression, typeArguments, argumentList);
-        } else if (currentExpression is PrefixedIdentifier) {
-          expression = astFactory.methodInvocation(
-              currentExpression.prefix,
-              currentExpression.period,
-              currentExpression.identifier,
-              typeArguments,
-              argumentList);
-        } else if (currentExpression is PropertyAccess) {
-          expression = astFactory.methodInvocation(
-              currentExpression.target,
-              currentExpression.operator,
-              currentExpression.propertyName,
-              typeArguments,
-              argumentList);
-        } else {
-          expression = astFactory.functionExpressionInvocation(
-              expression, typeArguments, argumentList);
-        }
-        if (!primaryAllowed) {
-          isOptional = false;
-        }
-      }
-      Expression selectorExpression = parseAssignableSelector(
-          expression, isOptional || (expression is PrefixedIdentifier));
-      if (identical(selectorExpression, expression)) {
-        return expression;
-      }
-      expression = selectorExpression;
-      isOptional = true;
-    }
-  }
-
-  /**
    * Parse a block when we need to check for an open curly brace and recover
    * when there isn't one. Return the block that was parsed.
    *
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 95424ed..ca300a9 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -5591,7 +5591,8 @@
         libraryElement,
         typeProvider,
         new InheritanceManager(libraryElement),
-        context.analysisOptions.enableSuperMixins);
+        context.analysisOptions.enableSuperMixins,
+        disableConflictingGenericsCheck: true);
     unit.accept(errorVerifier);
     //
     // Convert the pending errors into actual errors.
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart
index 117ae28..fdda0cd 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_driver_test.dart
@@ -18,16 +18,29 @@
   bool get enableNewAnalysisDriver => true;
 
   @override // Passes with driver
+  test_conflictingGenericInterfaces_simple() =>
+      super.test_conflictingGenericInterfaces_simple();
+
+  @override // Passes with driver
+  test_conflictingGenericInterfaces_viaMixin() =>
+      super.test_conflictingGenericInterfaces_viaMixin();
+
+  @override // Passes with driver
+  test_mixinInference_conflictingSubstitution() =>
+      super.test_mixinInference_conflictingSubstitution();
+
+  @override // Passes with driver
   test_mixinInference_doNotIgnorePreviousExplicitMixins() =>
       super.test_mixinInference_doNotIgnorePreviousExplicitMixins();
 
   @override // Passes with driver
-  test_mixinInference_matchingClass() =>
-      super.test_mixinInference_matchingClass();
+  test_mixinInference_impossibleSubstitution() =>
+      super.test_mixinInference_impossibleSubstitution();
 
   @override // Passes with driver
-  test_mixinInference_matchingClass_inPreviousMixin() =>
-      super.test_mixinInference_matchingClass_inPreviousMixin();
+  test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() =>
+      super
+          .test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause();
 
   @override // Passes with driver
   test_mixinInference_recursiveSubtypeCheck() =>
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index d69b4f2..cd32e7e 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -740,6 +740,7 @@
     assertNoErrors(source);
   }
 
+  @failingTest // Does not work with old task model
   test_conflictingGenericInterfaces_simple() async {
     Source source = addSource('''
 class I<T> {}
@@ -751,6 +752,7 @@
     assertErrors(source, [CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
   }
 
+  @failingTest // Does not work with old task model
   test_conflictingGenericInterfaces_viaMixin() async {
     Source source = addSource('''
 class I<T> {}
@@ -4018,6 +4020,7 @@
     verify([source]);
   }
 
+  @failingTest // Does not work with old task model
   test_mixinInference_conflictingSubstitution() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
@@ -4052,6 +4055,7 @@
     expect(mixins[1].toString(), 'C<String>');
   }
 
+  @failingTest // Does not work with old task model
   test_mixinInference_impossibleSubstitution() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
@@ -4069,7 +4073,6 @@
     ]);
   }
 
-  @failingTest // Does not work with old task model
   test_mixinInference_matchingClass() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
@@ -4085,7 +4088,6 @@
     assertNoErrors(source);
   }
 
-  @failingTest // Does not work with old task model
   test_mixinInference_matchingClass_inPreviousMixin() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
@@ -4118,6 +4120,7 @@
         source, [CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS]);
   }
 
+  @failingTest // Does not work with old task model
   test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() async {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableSuperMixins = true;
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 99ef619..5d3baf4 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -595,38 +595,6 @@
 
   @override
   @failingTest
-  void test_localFunctionDeclarationModifier_abstract() {
-    // TODO(brianwilkerson) Wrong errors:
-    // Expected 1 errors of type ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, found 0
-    super.test_localFunctionDeclarationModifier_abstract();
-  }
-
-  @override
-  @failingTest
-  void test_localFunctionDeclarationModifier_external() {
-    // TODO(brianwilkerson) Wrong errors:
-    // Expected 1 errors of type ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, found 0
-    super.test_localFunctionDeclarationModifier_external();
-  }
-
-  @override
-  @failingTest
-  void test_localFunctionDeclarationModifier_factory() {
-    // TODO(brianwilkerson) Wrong errors:
-    // Expected 1 errors of type ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, found 0
-    super.test_localFunctionDeclarationModifier_factory();
-  }
-
-  @override
-  @failingTest
-  void test_localFunctionDeclarationModifier_static() {
-    // TODO(brianwilkerson) Wrong errors:
-    // Expected 1 errors of type ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, found 0
-    super.test_localFunctionDeclarationModifier_static();
-  }
-
-  @override
-  @failingTest
   void test_method_invalidTypeParameterComments() {
     // TODO(brianwilkerson) Does not recover.
     //   type 'DeclaredSimpleIdentifier' is not a subtype of type 'TypeAnnotation' of 'returnType' where
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index bbf84c6..dfab7a0 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -3717,6 +3717,20 @@
 //        [expectedError(ParserErrorCode.GETTER_WITH_PARAMETERS, 9, 2)]);
   }
 
+  void test_illegalAssignmentToNonAssignable_assign_int() {
+    parseStatement("0 = 1;");
+    listener.assertErrors([
+      expectedError(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 0, 1)
+    ]);
+  }
+
+  void test_illegalAssignmentToNonAssignable_assign_this() {
+    parseStatement("this = 1;");
+    listener.assertErrors([
+      expectedError(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 0, 4)
+    ]);
+  }
+
   void test_illegalAssignmentToNonAssignable_postfix_minusMinus_literal() {
     parseExpression("0--", errors: [
       expectedError(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 1, 2)
@@ -3742,8 +3756,6 @@
   }
 
   void test_illegalAssignmentToNonAssignable_superAssigned() {
-    // TODO(brianwilkerson) When this test starts to pass, remove the test
-    // test_illegalAssignmentToNonAssignable_superAssigned.
     parseStatement("super = x;");
     listener.assertErrors(usingFastaParser
         ? [
@@ -4046,31 +4058,61 @@
   }
 
   void test_localFunctionDeclarationModifier_abstract() {
-    parseStatement("abstract f() {}");
-    listener.assertErrors([
-      expectedError(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 0, 8)
-    ]);
+    parseCompilationUnit("class C { m() { abstract f() {} } }",
+        errors: usingFastaParser
+            ? [
+                expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 8),
+                expectedError(
+                    ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 25, 1),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 26, 1),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 32, 1),
+              ]
+            : [
+                expectedError(
+                    ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 8)
+              ]);
   }
 
   void test_localFunctionDeclarationModifier_external() {
-    parseStatement("external f() {}");
-    listener.assertErrors([
-      expectedError(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 0, 8)
-    ]);
+    parseCompilationUnit("class C { m() { external f() {} } }",
+        errors: usingFastaParser
+            ? [
+                expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 8),
+                expectedError(
+                    ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 25, 1),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 26, 1),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 32, 1),
+              ]
+            : [
+                expectedError(
+                    ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 8)
+              ]);
   }
 
   void test_localFunctionDeclarationModifier_factory() {
-    parseStatement("factory f() {}");
-    listener.assertErrors([
-      expectedError(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 0, 7)
-    ]);
+    parseCompilationUnit("class C { m() { factory f() {} } }",
+        errors: usingFastaParser
+            ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 24, 1)]
+            : [
+                expectedError(
+                    ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 7)
+              ]);
   }
 
   void test_localFunctionDeclarationModifier_static() {
-    parseStatement("static f() {}");
-    listener.assertErrors([
-      expectedError(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 0, 6)
-    ]);
+    parseCompilationUnit("class C { m() { static f() {} } }",
+        errors: usingFastaParser
+            ? [
+                expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 6),
+                expectedError(
+                    ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 23, 1),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 24, 1),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 30, 1),
+              ]
+            : [
+                expectedError(
+                    ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 6)
+              ]);
   }
 
   void test_method_invalidTypeParameterComments() {
@@ -6587,6 +6629,17 @@
     expect(invocation.argumentList, isNotNull);
   }
 
+  void test_parseExpression_superMethodInvocation_typeArguments_chained() {
+    Expression expression = parseExpression('super.b.c<D>()');
+    MethodInvocation invocation = expression as MethodInvocation;
+    Expression target = invocation.target;
+    expect(target, new isInstanceOf<PropertyAccess>());
+    expect(invocation.methodName, isNotNull);
+    expect(invocation.methodName.name, 'c');
+    expect(invocation.typeArguments, isNotNull);
+    expect(invocation.argumentList, isNotNull);
+  }
+
   void test_parseExpressionList_multiple() {
     List<Expression> result = parseExpressionList('1, 2, 3');
     expect(result, isNotNull);
diff --git a/pkg/analyzer/test/generated/strong_mode_driver_test.dart b/pkg/analyzer/test/generated/strong_mode_driver_test.dart
index 40d3685..28609bb 100644
--- a/pkg/analyzer/test/generated/strong_mode_driver_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_driver_test.dart
@@ -34,32 +34,36 @@
 
   @failingTest
   @override
-  test_genericMethod_functionExpressionInvocation_explicit() {
-    return super.test_genericMethod_functionExpressionInvocation_explicit();
+  test_genericMethod_functionExpressionInvocation_functionTypedParameter_explicit() {
+    return super
+        .test_genericMethod_functionExpressionInvocation_functionTypedParameter_explicit();
   }
 
   @failingTest
   @override
-  test_genericMethod_functionExpressionInvocation_inferred() {
-    return super.test_genericMethod_functionExpressionInvocation_inferred();
+  test_genericMethod_functionExpressionInvocation_functionTypedParameter_inferred() {
+    return super
+        .test_genericMethod_functionExpressionInvocation_functionTypedParameter_inferred();
   }
 
   @failingTest
   @override
-  test_genericMethod_functionInvocation_explicit() {
-    return super.test_genericMethod_functionInvocation_explicit();
+  test_genericMethod_functionInvocation_functionTypedParameter_explicit() {
+    return super
+        .test_genericMethod_functionInvocation_functionTypedParameter_explicit();
   }
 
   @failingTest
   @override
-  test_genericMethod_functionInvocation_inferred() {
-    return super.test_genericMethod_functionInvocation_inferred();
+  test_genericMethod_functionInvocation_functionTypedParameter_inferred() {
+    return super
+        .test_genericMethod_functionInvocation_functionTypedParameter_inferred();
   }
 
   @failingTest
   @override
-  test_genericMethod_tearoff() {
-    return super.test_genericMethod_tearoff();
+  test_genericMethod_functionTypedParameter_tearoff() {
+    return super.test_genericMethod_functionTypedParameter_tearoff();
   }
 }
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 8feaf44..fa04b08 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -2816,6 +2816,17 @@
     await resolveTestUnit(code);
   }
 
+  test_generalizedVoid_assignToVoidOk() async {
+    Source source = addSource(r'''
+void main() {
+  void x;
+  x = 42;
+}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+  }
+
   test_genericFunction() async {
     await resolveTestUnit(r'T f<T>(T x) => null;');
     expectFunctionType('f', '<T>(T) → T',
@@ -2976,12 +2987,12 @@
 class C<E> {
   T f<T>(T e) => null;
   static T g<T>(T e) => null;
-  static final h = g;
+  static T Function<T>(T) h = null;
 }
 
 T topF<T>(T e) => null;
 var topG = topF;
-void test<S>(T pf<T>(T e)) {
+void test<S>(T Function<T>(T) pf) {
   var c = new C<int>();
   T lf<T>(T e) => null;
 
@@ -2994,8 +3005,7 @@
   var localCall = (lf)<int>(3);
   var paramCall = (pf)<int>(3);
 }
-''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
-        );
+''');
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -3006,17 +3016,37 @@
     expectIdentifierType('lambdaCall', "int");
   }
 
+  test_genericMethod_functionExpressionInvocation_functionTypedParameter_explicit() async {
+    await resolveTestUnit(r'''
+void test<S>(T pf<T>(T e)) {
+  var paramCall = (pf)<int>(3);
+}
+''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
+    expectIdentifierType('paramCall', "int");
+  }
+
+  test_genericMethod_functionExpressionInvocation_functionTypedParameter_inferred() async {
+    await resolveTestUnit(r'''
+void test<S>(T pf<T>(T e)) {
+  var paramCall = (pf)(3);
+}
+''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
+    expectIdentifierType('paramCall', "int");
+  }
+
   test_genericMethod_functionExpressionInvocation_inferred() async {
     await resolveTestUnit(r'''
 class C<E> {
   T f<T>(T e) => null;
   static T g<T>(T e) => null;
-  static final h = g;
+  static T Function<T>(T) h = null;
 }
 
 T topF<T>(T e) => null;
 var topG = topF;
-void test<S>(T pf<T>(T e)) {
+void test<S>(T Function<T>(T) pf) {
   var c = new C<int>();
   T lf<T>(T e) => null;
 
@@ -3046,12 +3076,12 @@
 class C<E> {
   T f<T>(T e) => null;
   static T g<T>(T e) => null;
-  static final h = g;
+  static T Function<T>(T) h = null;
 }
 
 T topF<T>(T e) => null;
 var topG = topF;
-void test<S>(T pf<T>(T e)) {
+void test<S>(T Function<T>(T) pf) {
   var c = new C<int>();
   T lf<T>(T e) => null;
   var methodCall = c.f<int>(3);
@@ -3062,8 +3092,7 @@
   var localCall = lf<int>(3);
   var paramCall = pf<int>(3);
 }
-''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
-        );
+''');
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -3073,17 +3102,37 @@
     expectIdentifierType('paramCall', "int");
   }
 
+  test_genericMethod_functionInvocation_functionTypedParameter_explicit() async {
+    await resolveTestUnit(r'''
+void test<S>(T pf<T>(T e)) {
+  var paramCall = pf<int>(3);
+}
+''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
+    expectIdentifierType('paramCall', "int");
+  }
+
+  test_genericMethod_functionInvocation_functionTypedParameter_inferred() async {
+    await resolveTestUnit(r'''
+void test<S>(T pf<T>(T e)) {
+  var paramCall = pf(3);
+}
+''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
+    expectIdentifierType('paramCall', "int");
+  }
+
   test_genericMethod_functionInvocation_inferred() async {
     await resolveTestUnit(r'''
 class C<E> {
   T f<T>(T e) => null;
   static T g<T>(T e) => null;
-  static final h = g;
+  static T Function<T>(T) h = null;
 }
 
 T topF<T>(T e) => null;
 var topG = topF;
-void test<S>(T pf<T>(T e)) {
+void test<S>(T Function<T>(T) pf) {
   var c = new C<int>();
   T lf<T>(T e) => null;
   var methodCall = c.f(3);
@@ -3094,8 +3143,7 @@
   var localCall = lf(3);
   var paramCall = pf(3);
 }
-''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
-        );
+''');
     expectIdentifierType('methodCall', "int");
     expectIdentifierType('staticCall', "int");
     expectIdentifierType('staticFieldCall', "int");
@@ -3127,6 +3175,16 @@
     expect(ft.toString(), '((String) → int) → List<int>');
   }
 
+  test_genericMethod_functionTypedParameter_tearoff() async {
+    await resolveTestUnit(r'''
+void test<S>(T pf<T>(T e)) {
+  var paramTearOff = pf;
+}
+''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
+        );
+    expectIdentifierType('paramTearOff', "<T>(T) → T");
+  }
+
   test_genericMethod_implicitDynamic() async {
     // Regression test for:
     // https://github.com/dart-lang/sdk/issues/25100#issuecomment-162047588
@@ -3395,12 +3453,12 @@
 class C<E> {
   T f<T>(E e) => null;
   static T g<T>(T e) => null;
-  static final h = g;
+  static T Function<T>(T) h = null;
 }
 
 T topF<T>(T e) => null;
 var topG = topF;
-void test<S>(T pf<T>(T e)) {
+void test<S>(T Function<T>(T) pf) {
   var c = new C<int>();
   T lf<T>(T e) => null;
   var methodTearOff = c.f;
@@ -3411,8 +3469,7 @@
   var localTearOff = lf;
   var paramTearOff = pf;
 }
-''', noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
-        );
+''');
     expectIdentifierType('methodTearOff', "<T>(int) → T");
     expectIdentifierType('staticTearOff', "<T>(T) → T");
     expectIdentifierType('staticFieldTearOff', "<T>(T) → T");
@@ -3428,7 +3485,7 @@
 class C<E> {
   T f<T>(E e) => null;
   static T g<T>(T e) => null;
-  static final h = g;
+  static T Function<T>(T) h = null;
 }
 
 T topF<T>(T e) => null;
@@ -3498,6 +3555,20 @@
     expectInitializerType('foo', 'Future<String>', isNull);
   }
 
+  test_genericMethod_toplevel_field_staticTearoff() async {
+    await resolveTestUnit(r'''
+class C<E> {
+  static T g<T>(T e) => null;
+  static T Function<T>(T) h = null;
+}
+
+void test() {
+  var fieldRead = C.h;
+}
+''');
+    expectIdentifierType('fieldRead', "<T>(T) → T");
+  }
+
   test_implicitBounds() async {
     String code = r'''
 class A<T> {}
@@ -3942,6 +4013,12 @@
     await _objectMethodOnFunctions_helper2(code);
   }
 
+  test_returnOfInvalidType_object_void() async {
+    await assertErrorsInCode(
+        "Object f() { void voidFn() => null; return voidFn(); }",
+        [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]);
+  }
+
   test_setterWithDynamicTypeIsError() async {
     Source source = addSource(r'''
 class A {
@@ -4034,23 +4111,6 @@
     expectInitializerType('foo', 'int', isNull);
   }
 
-  test_generalizedVoid_assignToVoidOk() async {
-    Source source = addSource(r'''
-void main() {
-  void x;
-  x = 42;
-}
-''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-  }
-
-  test_returnOfInvalidType_object_void() async {
-    await assertErrorsInCode(
-        "Object f() { void voidFn() => null; return voidFn(); }",
-        [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]);
-  }
-
   Future<Null> _objectMethodOnFunctions_helper2(String code) async {
     await resolveTestUnit(code);
     expectIdentifierType('t0', "String");
@@ -4139,6 +4199,28 @@
     assertTypeOfMarkedExpression(code, unit, typeProvider.intType, null);
   }
 
+  test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef() async {
+    Source source = addSource(r'''
+typedef bool F<E>(E argument);
+
+abstract class Base {
+  f<E extends int>(F<int> x);
+}
+
+abstract class BaseCopy extends Base {
+}
+
+abstract class Override implements Base, BaseCopy {
+  f<E>(x) => null;
+}
+
+class C extends Override implements Base {}
+''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   test_localVariableInference_bottom_disabled() async {
     String code = r'''
 main() {
@@ -4327,26 +4409,4 @@
     assertPropagatedAssignedType(code, unit, typeProvider.intType, null);
     assertTypeOfMarkedExpression(code, unit, typeProvider.intType, null);
   }
-
-  test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef() async {
-    Source source = addSource(r'''
-typedef bool F<E>(E argument);
-
-abstract class Base {
-  f<E extends int>(F<int> x);
-}
-
-abstract class BaseCopy extends Base {
-}
-
-abstract class Override implements Base, BaseCopy {
-  f<E>(x) => null;
-}
-
-class C extends Override implements Base {}
-''');
-    await computeAnalysisResult(source);
-    assertNoErrors(source);
-    verify([source]);
-  }
 }
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 869f387..37f17da 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2794,6 +2794,7 @@
     ''');
   }
 
+  @failingTest // Does not work with old task model
   test_interfacesFromMixinsUsedTwiceAreChecked() {
     // Regression test for https://github.com/dart-lang/sdk/issues/29782
     return checkFile(r'''
@@ -4609,4 +4610,8 @@
   test_fuzzyArrowLegacyAssignability_GlobalInference() async {
     await super.test_fuzzyArrowLegacyAssignability_GlobalInference();
   }
+
+  @override // Passes with driver
+  test_interfacesFromMixinsUsedTwiceAreChecked() =>
+      super.test_interfacesFromMixinsUsedTwiceAreChecked();
 }
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 015d4e3..1256caf 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -1258,15 +1258,37 @@
             ImportDirective next,
             String uri,
             bool trailingNewLine: false}) {
+          LineInfo lineInfo = unit.lineInfo;
           if (prev != null) {
-            addInsertion(prev.end, (EditBuilder builder) {
+            int offset = prev.end;
+            int line = lineInfo.getLocation(offset).lineNumber;
+            Token comment = prev.endToken.next.precedingComments;
+            while (comment != null) {
+              if (lineInfo.getLocation(comment.offset).lineNumber == line) {
+                offset = comment.end;
+              }
+              comment = comment.next;
+            }
+            addInsertion(offset, (EditBuilder builder) {
               builder.writeln();
               builder.write("import '");
               builder.write(uri);
               builder.write("';");
             });
           } else {
-            addInsertion(next.offset, (EditBuilder builder) {
+            int offset = next.offset;
+            Token comment = next.beginToken.precedingComments;
+            while (comment != null) {
+              int commentOffset = comment.offset;
+              if (commentOffset ==
+                  lineInfo.getOffsetOfLine(
+                      lineInfo.getLocation(commentOffset).lineNumber - 1)) {
+                offset = commentOffset;
+                break;
+              }
+              comment = comment.next;
+            }
+            addInsertion(offset, (EditBuilder builder) {
               builder.write("import '");
               builder.write(uri);
               builder.writeln("';");
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 8bc6e51..f4c063b 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -177,6 +177,34 @@
 ''');
   }
 
+  test_importLibrary_package_afterPackage_leadingComment() async {
+    await _assertImportLibraries('''
+// comment
+import 'package:aaa/a1.dart';
+
+import 'foo.dart';
+''', ['package:aaa/a2.dart'], '''
+// comment
+import 'package:aaa/a1.dart';
+import 'package:aaa/a2.dart';
+
+import 'foo.dart';
+''');
+  }
+
+  test_importLibrary_package_afterPackage_trailingComment() async {
+    await _assertImportLibraries('''
+import 'package:aaa/a1.dart'; // comment
+
+import 'foo.dart';
+''', ['package:aaa/a2.dart'], '''
+import 'package:aaa/a1.dart'; // comment
+import 'package:aaa/a2.dart';
+
+import 'foo.dart';
+''');
+  }
+
   test_importLibrary_package_beforePackage() async {
     await _assertImportLibraries('''
 import 'package:aaa/a1.dart';
@@ -205,6 +233,34 @@
 ''');
   }
 
+  test_importLibrary_package_beforePackage_leadingComments() async {
+    await _assertImportLibraries('''
+// comment a2
+import 'package:aaa/a2.dart';
+
+import 'foo.dart';
+''', ['package:aaa/a1.dart'], '''
+import 'package:aaa/a1.dart';
+// comment a2
+import 'package:aaa/a2.dart';
+
+import 'foo.dart';
+''');
+  }
+
+  test_importLibrary_package_beforePackage_trailingComments() async {
+    await _assertImportLibraries('''
+import 'package:aaa/a2.dart'; // comment a2
+
+import 'foo.dart';
+''', ['package:aaa/a1.dart'], '''
+import 'package:aaa/a1.dart';
+import 'package:aaa/a2.dart'; // comment a2
+
+import 'foo.dart';
+''');
+  }
+
   test_importLibrary_package_beforeRelative() async {
     await _assertImportLibraries('''
 import 'foo.dart';
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 2b63cc3..327c9e5 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -42,7 +42,7 @@
   static const String length = 'length';
 
   /// The name of the signature function in closure classes.
-  static const String signature = 'signature';
+  static const String signature = ':signature';
 }
 
 /// [Name]s commonly used.
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index a34a070..c399c75 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -367,6 +367,8 @@
           typedef = type;
         } else if (type is FunctionType) {
           typedef = type.typedefType;
+        } else if (type is TypeVariableType) {
+          _worldBuilder.registerTypeVariableTypeLiteral(type);
         }
         if (typedef != null) worldBuilder.registerTypedef(typedef.element);
         break;
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 5cb274c..82dd51a 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -192,6 +192,9 @@
         }
         break;
       case TypeUseKind.TYPE_LITERAL:
+        if (type is TypeVariableType) {
+          _worldBuilder.registerTypeVariableTypeLiteral(type);
+        }
         break;
     }
   }
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 9963c4c..66f8e79 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -94,10 +94,9 @@
   ///
   /// See [methodNeedsSignature] for more information on what a signature is
   /// and when it is needed.
-  // TODO(redemption): Remove this when the old frontend is deleted.
   bool localFunctionNeedsSignature(Local localFunction);
 
-  bool classUsesTypeVariableLiteral(ClassEntity cls);
+  bool selectorNeedsTypeArguments(Selector selector);
 }
 
 class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
@@ -107,9 +106,6 @@
   bool classNeedsTypeArguments(ClassEntity cls) => true;
 
   @override
-  bool classUsesTypeVariableLiteral(ClassEntity cls) => true;
-
-  @override
   bool localFunctionNeedsSignature(Local localFunction) => true;
 
   @override
@@ -120,6 +116,9 @@
       // TODO(johnniwinther): Align handling of type arguments passed to factory
       // constructors with type arguments passed the regular generic methods.
       !(method is ConstructorEntity && method.isFactoryConstructor);
+
+  @override
+  bool selectorNeedsTypeArguments(Selector selector) => true;
 }
 
 /// Interface for computing classes and methods that need runtime types.
@@ -185,12 +184,6 @@
   // but _not_ `Function()` to the [checkedFunctionTypes] set. An is-test
   // against a typedef will add its alias to the [checkedFunctionTypes] set.
   Iterable<FunctionType> get checkedFunctionTypes;
-
-  /// Classes whose type variables are explicitly or implicitly used in
-  /// is-tests.
-  ///
-  /// See [TypeVariableTests.classTests].
-  Iterable<ClassEntity> get classesUsingTypeVariableTests;
 }
 
 class TrivialTypesChecks implements RuntimeTypesChecks {
@@ -214,9 +207,6 @@
 
   @override
   Iterable<FunctionType> get checkedFunctionTypes => const <FunctionType>[];
-
-  @override
-  Iterable<ClassEntity> get classesUsingTypeVariableTests => _allClasses;
 }
 
 /// Interface for computing the needed runtime type checks.
@@ -694,9 +684,7 @@
   final Set<FunctionEntity> methodsNeedingTypeArguments;
   final Set<Local> localFunctionsNeedingSignature;
   final Set<Local> localFunctionsNeedingTypeArguments;
-
-  /// The set of classes that use one of their type variables as literals.
-  final Set<ClassEntity> classesUsingTypeVariableLiterals;
+  final Set<Selector> selectorsNeedingTypeArguments;
 
   RuntimeTypesNeedImpl(
       this._elementEnvironment,
@@ -706,7 +694,7 @@
       this.methodsNeedingTypeArguments,
       this.localFunctionsNeedingSignature,
       this.localFunctionsNeedingTypeArguments,
-      this.classesUsingTypeVariableLiterals);
+      this.selectorsNeedingTypeArguments);
 
   bool checkClass(covariant ClassEntity cls) => true;
 
@@ -741,8 +729,10 @@
   }
 
   @override
-  bool classUsesTypeVariableLiteral(ClassEntity cls) {
-    return classesUsingTypeVariableLiterals.contains(cls);
+  bool selectorNeedsTypeArguments(Selector selector) {
+    if (selector.callStructure.typeArgumentCount == 0) return false;
+    if (_backendUsage.isRuntimeTypeUsed) return true;
+    return selectorsNeedingTypeArguments.contains(selector);
   }
 }
 
@@ -755,7 +745,7 @@
       Set<FunctionEntity> methodsNeedingTypeArguments,
       Set<Local> localFunctionsNeedingSignature,
       Set<Local> localFunctionsNeedingTypeArguments,
-      Set<ClassEntity> classesUsingTypeVariableExpression)
+      Set<Selector> selectorsNeedingTypeArguments)
       : super(
             elementEnvironment,
             backendUsage,
@@ -764,7 +754,7 @@
             methodsNeedingTypeArguments,
             localFunctionsNeedingSignature,
             localFunctionsNeedingTypeArguments,
-            classesUsingTypeVariableExpression);
+            selectorsNeedingTypeArguments);
 
   bool checkClass(ClassElement cls) => cls.isDeclaration;
 }
@@ -773,6 +763,7 @@
   List<RtiNode> _nodes = <RtiNode>[];
   Map<ClassEntity, ClassNode> _classes = <ClassEntity, ClassNode>{};
   Map<Entity, MethodNode> _methods = <Entity, MethodNode>{};
+  Map<Selector, Set<Entity>> _appliedSelectorMap;
 
   /// All explicit is-tests.
   final Set<DartType> explicitIsChecks;
@@ -780,6 +771,19 @@
   /// All implicit is-tests.
   final Set<DartType> implicitIsChecks = new Set<DartType>();
 
+  TypeVariableTests(ElementEnvironment elementEnvironment,
+      CommonElements commonElements, DartTypes types, WorldBuilder worldBuilder,
+      {bool forRtiNeeds: true})
+      : explicitIsChecks = new Set<DartType>.from(worldBuilder.isChecks) {
+    _setupDependencies(elementEnvironment, commonElements, worldBuilder);
+    _propagateTests(elementEnvironment, worldBuilder);
+    if (forRtiNeeds) {
+      _propagateLiterals(elementEnvironment, worldBuilder);
+    }
+    _collectResults(elementEnvironment, types, worldBuilder,
+        forRtiNeeds: forRtiNeeds);
+  }
+
   /// Classes whose type variables are explicitly or implicitly used in
   /// is-tests.
   ///
@@ -843,7 +847,7 @@
   ///     class B<T> {}
   ///     main() => new A<String>().m() is B<int>;
   ///
-  /// Here `A` need type arguments at runtime because the key entity `B` needs
+  /// Here `A` needs type arguments at runtime because the key entity `B` needs
   /// it in order to generate the check against `B<int>`.
   ///
   /// This can also involve generic methods:
@@ -866,50 +870,54 @@
     return dependencies.map((n) => n.entity).toSet();
   }
 
-  TypeVariableTests(ElementEnvironment elementEnvironment,
-      CommonElements commonElements, DartTypes types, WorldBuilder worldBuilder)
-      : explicitIsChecks = new Set<DartType>.from(worldBuilder.isChecks) {
-    ClassNode getClassNode(ClassEntity cls) {
-      return _classes.putIfAbsent(cls, () {
-        ClassNode node = new ClassNode(cls);
-        _nodes.add(node);
-        return node;
-      });
-    }
+  /// Calls [f] for each selector that applies to generic [targets].
+  void forEachAppliedSelector(void f(Selector selector, Set<Entity> targets)) {
+    _appliedSelectorMap.forEach(f);
+  }
 
-    MethodNode getMethodNode(Entity function) {
-      return _methods.putIfAbsent(function, () {
-        MethodNode node;
-        if (function is FunctionEntity) {
-          Name instanceName;
-          bool isCallTarget;
-          if (function.isInstanceMember) {
-            isCallTarget = worldBuilder.closurizedMembers.contains(function);
-            instanceName = function.memberName;
-          } else {
-            isCallTarget = worldBuilder.closurizedStatics.contains(function);
-          }
-          node = new MethodNode(function, function.parameterStructure,
-              isCallTarget: isCallTarget, instanceName: instanceName);
+  ClassNode _getClassNode(ClassEntity cls) {
+    return _classes.putIfAbsent(cls, () {
+      ClassNode node = new ClassNode(cls);
+      _nodes.add(node);
+      return node;
+    });
+  }
+
+  MethodNode _getMethodNode(ElementEnvironment elementEnvironment,
+      WorldBuilder worldBuilder, Entity function) {
+    return _methods.putIfAbsent(function, () {
+      MethodNode node;
+      if (function is FunctionEntity) {
+        Name instanceName;
+        bool isCallTarget;
+        if (function.isInstanceMember) {
+          isCallTarget = worldBuilder.closurizedMembers.contains(function);
+          instanceName = function.memberName;
         } else {
-          ParameterStructure parameterStructure =
-              new ParameterStructure.fromType(
-                  elementEnvironment.getLocalFunctionType(function));
-          node =
-              new MethodNode(function, parameterStructure, isCallTarget: true);
+          isCallTarget = worldBuilder.closurizedStatics.contains(function);
         }
-        _nodes.add(node);
-        return node;
-      });
-    }
+        node = new MethodNode(function, function.parameterStructure,
+            isCallTarget: isCallTarget, instanceName: instanceName);
+      } else {
+        ParameterStructure parameterStructure = new ParameterStructure.fromType(
+            elementEnvironment.getLocalFunctionType(function));
+        node = new MethodNode(function, parameterStructure, isCallTarget: true);
+      }
+      _nodes.add(node);
+      return node;
+    });
+  }
 
+  void _setupDependencies(ElementEnvironment elementEnvironment,
+      CommonElements commonElements, WorldBuilder worldBuilder) {
     void registerDependencies(RtiNode node, DartType type) {
       type.forEachTypeVariable((TypeVariableType typeVariable) {
         Entity typeDeclaration = typeVariable.element.typeDeclaration;
         if (typeDeclaration is ClassEntity) {
-          node.addDependency(getClassNode(typeDeclaration));
+          node.addDependency(_getClassNode(typeDeclaration));
         } else {
-          node.addDependency(getMethodNode(typeDeclaration));
+          node.addDependency(_getMethodNode(
+              elementEnvironment, worldBuilder, typeDeclaration));
         }
       });
     }
@@ -935,55 +943,88 @@
     // TODO(johnniwinther): Make this dependency visible from code, possibly
     // using generic methods.
     if (commonElements.jsArrayClass != null) {
-      getClassNode(commonElements.jsArrayClass)
-          .addDependency(getClassNode(commonElements.listClass));
+      _getClassNode(commonElements.jsArrayClass)
+          .addDependency(_getClassNode(commonElements.listClass));
     }
     if (commonElements.mapLiteralClass != null) {
-      getClassNode(commonElements.mapLiteralClass)
-          .addDependency(getClassNode(commonElements.mapClass));
+      _getClassNode(commonElements.mapLiteralClass)
+          .addDependency(_getClassNode(commonElements.mapClass));
     }
 
     worldBuilder.isChecks.forEach((DartType type) {
       if (type is InterfaceType) {
-        registerDependencies(getClassNode(type.element), type);
+        registerDependencies(_getClassNode(type.element), type);
       }
     });
     worldBuilder.instantiatedTypes.forEach((InterfaceType type) {
-      registerDependencies(getClassNode(type.element), type);
+      registerDependencies(_getClassNode(type.element), type);
     });
 
     worldBuilder.forEachStaticTypeArgument(
         (Entity entity, Iterable<DartType> typeArguments) {
       for (DartType type in typeArguments) {
-        registerDependencies(getMethodNode(entity), type);
+        registerDependencies(
+            _getMethodNode(elementEnvironment, worldBuilder, entity), type);
       }
     });
 
+    // TODO(johnniwinther): Cached here because the world builders computes
+    // this lazily. Track this set directly in the world builders .
+    Iterable<FunctionEntity> genericInstanceMethods =
+        worldBuilder.genericInstanceMethods;
     worldBuilder.forEachDynamicTypeArgument(
         (Selector selector, Iterable<DartType> typeArguments) {
-      for (DartType type in typeArguments) {
-        // TODO(johnniwinther): Ensure that methods added here will be
-        // processed for matching selectors.
-        for (MethodNode method in _methods.values.toList()) {
-          if (method.selectorApplies(selector)) {
-            registerDependencies(method, type);
+      void processEntity(Entity entity) {
+        MethodNode node =
+            _getMethodNode(elementEnvironment, worldBuilder, entity);
+        if (node.selectorApplies(selector)) {
+          for (DartType type in typeArguments) {
+            registerDependencies(node, type);
           }
         }
       }
-    });
 
+      genericInstanceMethods.forEach(processEntity);
+      worldBuilder.genericLocalFunctions.forEach(processEntity);
+      worldBuilder.closurizedStatics.forEach(processEntity);
+    });
+  }
+
+  void _propagateTests(
+      ElementEnvironment elementEnvironment, WorldBuilder worldBuilder) {
     worldBuilder.isChecks.forEach((DartType type) {
       if (type.isTypeVariable) {
         TypeVariableType typeVariableType = type;
         TypeVariableEntity variable = typeVariableType.element;
         if (variable.typeDeclaration is ClassEntity) {
-          getClassNode(variable.typeDeclaration).markDirectTest();
+          _getClassNode(variable.typeDeclaration).markDirectTest();
         } else {
-          getMethodNode(variable.typeDeclaration).markDirectTest();
+          _getMethodNode(
+                  elementEnvironment, worldBuilder, variable.typeDeclaration)
+              .markDirectTest();
         }
       }
     });
+  }
 
+  void _propagateLiterals(
+      ElementEnvironment elementEnvironment, WorldBuilder worldBuilder) {
+    worldBuilder.typeVariableTypeLiterals
+        .forEach((TypeVariableType typeVariableType) {
+      TypeVariableEntity variable = typeVariableType.element;
+      if (variable.typeDeclaration is ClassEntity) {
+        _getClassNode(variable.typeDeclaration).markDirectLiteral();
+      } else {
+        _getMethodNode(
+                elementEnvironment, worldBuilder, variable.typeDeclaration)
+            .markDirectLiteral();
+      }
+    });
+  }
+
+  void _collectResults(ElementEnvironment elementEnvironment, DartTypes types,
+      WorldBuilder worldBuilder,
+      {bool forRtiNeeds: true}) {
     // Compute type arguments of classes that use one of their type variables in
     // is-checks and add the is-checks that they imply.
     _classes.forEach((ClassEntity cls, ClassNode node) {
@@ -1006,15 +1047,28 @@
 
     worldBuilder.forEachStaticTypeArgument(
         (Entity function, Iterable<DartType> typeArguments) {
-      if (!getMethodNode(function).hasTest) return;
+      if (!_getMethodNode(elementEnvironment, worldBuilder, function).hasTest) {
+        return;
+      }
       implicitIsChecks.addAll(typeArguments);
     });
+
+    if (forRtiNeeds) {
+      _appliedSelectorMap = <Selector, Set<Entity>>{};
+    }
+
     worldBuilder.forEachDynamicTypeArgument(
         (Selector selector, Iterable<DartType> typeArguments) {
       for (MethodNode node in _methods.values) {
-        if (!node.hasTest) continue;
         if (node.selectorApplies(selector)) {
-          implicitIsChecks.addAll(typeArguments);
+          if (forRtiNeeds) {
+            _appliedSelectorMap
+                .putIfAbsent(selector, () => new Set<Entity>())
+                .add(node.entity);
+          }
+          if (node.hasTest) {
+            implicitIsChecks.addAll(typeArguments);
+          }
         }
       }
     });
@@ -1024,13 +1078,24 @@
     StringBuffer sb = new StringBuffer();
 
     void addNode(RtiNode node) {
-      if (node._testState != 0 || node.dependencies.isNotEmpty || verbose) {
+      if (node.hasUse || node.dependencies.isNotEmpty || verbose) {
         sb.write(' $node');
+        String comma = '';
         if (node._testState & 1 != 0) {
-          sb.write(' direct');
+          sb.write(' direct test');
+          comma = ',';
         }
         if (node._testState & 2 != 0) {
-          sb.write(' indirect');
+          sb.write('$comma indirect test');
+          comma = ',';
+        }
+        if (node._literalState & 1 != 0) {
+          sb.write('$comma direct literal');
+          comma = ',';
+        }
+        if (node._literalState & 2 != 0) {
+          sb.write('$comma indirect literal');
+          comma = ',';
         }
         if (node.dependencies.isNotEmpty || verbose) {
           sb.writeln(':');
@@ -1062,6 +1127,7 @@
   Entity get entity;
   Set<RtiNode> _dependencies;
   int _testState = 0;
+  int _literalState = 0;
 
   Iterable<RtiNode> get dependencies => _dependencies ?? const <RtiNode>[];
 
@@ -1070,6 +1136,13 @@
 
   bool get hasTest => _testState != 0;
 
+  bool get hasDirectLiteral => _literalState & 1 != 0;
+  bool get hasIndirectLiteral => _literalState & 2 != 0;
+
+  bool get hasLiteral => _literalState != 0;
+
+  bool get hasUse => hasTest || hasLiteral;
+
   bool addDependency(RtiNode node) {
     if (entity == node.entity) {
       // Skip trivial dependencies; if [entity] needs type arguments so does
@@ -1103,6 +1176,29 @@
     }
   }
 
+  void markDirectLiteral() {
+    setLiteralState(1);
+  }
+
+  void markIndirectLiteral() {
+    setLiteralState(2);
+  }
+
+  void setLiteralState(int value) {
+    if (_literalState != value) {
+      if (_literalState == 0) {
+        _literalState |= value;
+        if (_dependencies != null) {
+          for (RtiNode node in _dependencies) {
+            node.markIndirectLiteral();
+          }
+        }
+      } else {
+        _literalState = value;
+      }
+    }
+  }
+
   String get kind;
 
   String toString() {
@@ -1142,6 +1238,17 @@
   }
 
   String get kind => 'method';
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('MethodNode(');
+    sb.write('function=$function');
+    sb.write(',parameterStructure=$parameterStructure');
+    sb.write(',isCallTarget=$isCallTarget');
+    sb.write(',instanceName=$instanceName');
+    sb.write(')');
+    return sb.toString();
+  }
 }
 
 class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
@@ -1156,7 +1263,9 @@
 
   final Set<Local> localFunctionsUsingTypeVariableLiterals = new Set<Local>();
 
-  TypeVariableTests typeVariableTests;
+  Map<Selector, Set<Entity>> selectorsNeedingTypeArgumentsForTesting;
+
+  TypeVariableTests typeVariableTestsForTesting;
 
   RuntimeTypesNeedBuilderImpl(this._elementEnvironment, DartTypes types)
       : super(types);
@@ -1182,7 +1291,7 @@
   RuntimeTypesNeed computeRuntimeTypesNeed(
       ResolutionWorldBuilder resolutionWorldBuilder, ClosedWorld closedWorld,
       {bool enableTypeAssertions}) {
-    typeVariableTests = new TypeVariableTests(
+    TypeVariableTests typeVariableTests = new TypeVariableTests(
         closedWorld.elementEnvironment,
         closedWorld.commonElements,
         closedWorld.dartTypes,
@@ -1192,6 +1301,7 @@
     Set<FunctionEntity> methodsNeedingTypeArguments = new Set<FunctionEntity>();
     Set<Local> localFunctionsNeedingSignature = new Set<Local>();
     Set<Local> localFunctionsNeedingTypeArguments = new Set<Local>();
+    Set<Entity> processedEntities = new Set<Entity>();
 
     // Find the classes that need type arguments at runtime. Such
     // classes are:
@@ -1199,6 +1309,12 @@
     // (2) dependencies of classes in (1),
     // (3) subclasses of (2) and (3).
     void potentiallyNeedTypeArguments(Entity entity) {
+      // Functions with type arguments can have dependencies of each other (if
+      // the functions call each other) so we keep a set to prevent infinitely
+      // recursing over the same entities.
+      if (processedEntities.contains(entity)) return;
+
+      processedEntities.add(entity);
       if (entity is ClassEntity) {
         ClassEntity cls = entity;
         assert(checkClass(cls));
@@ -1290,6 +1406,30 @@
     localFunctionsUsingTypeVariableLiterals
         .forEach(potentiallyNeedTypeArguments);
 
+    Set<Selector> selectorsNeedingTypeArguments = new Set<Selector>();
+    typeVariableTests
+        .forEachAppliedSelector((Selector selector, Set<Entity> targets) {
+      for (Entity target in targets) {
+        if (methodsNeedingTypeArguments.contains(target) ||
+            localFunctionsNeedingTypeArguments.contains(target)) {
+          selectorsNeedingTypeArguments.add(selector);
+          if (cacheRtiDataForTesting) {
+            selectorsNeedingTypeArgumentsForTesting ??=
+                <Selector, Set<Entity>>{};
+            selectorsNeedingTypeArgumentsForTesting
+                .putIfAbsent(selector, () => new Set<Entity>())
+                .add(target);
+          } else {
+            return;
+          }
+        }
+      }
+    });
+
+    if (cacheRtiDataForTesting) {
+      typeVariableTestsForTesting = typeVariableTests;
+    }
+
     return _createRuntimeTypesNeed(
         _elementEnvironment,
         closedWorld.backendUsage,
@@ -1298,7 +1438,7 @@
         methodsNeedingTypeArguments,
         localFunctionsNeedingSignature,
         localFunctionsNeedingTypeArguments,
-        classesUsingTypeVariableLiterals);
+        selectorsNeedingTypeArguments);
   }
 
   RuntimeTypesNeed _createRuntimeTypesNeed(
@@ -1309,7 +1449,7 @@
       Set<FunctionEntity> methodsNeedingTypeArguments,
       Set<Local> localFunctionsNeedingSignature,
       Set<Local> localFunctionsNeedingTypeArguments,
-      Set<ClassEntity> classesUsingTypeVariableExpression) {
+      Set<Selector> selectorsNeedingTypeArguments) {
     return new RuntimeTypesNeedImpl(
         _elementEnvironment,
         backendUsage,
@@ -1318,7 +1458,7 @@
         methodsNeedingTypeArguments,
         localFunctionsNeedingSignature,
         localFunctionsNeedingTypeArguments,
-        classesUsingTypeVariableExpression);
+        selectorsNeedingTypeArguments);
   }
 }
 
@@ -1338,7 +1478,7 @@
       Set<FunctionEntity> methodsNeedingTypeArguments,
       Set<Local> localFunctionsNeedingSignature,
       Set<Local> localFunctionsNeedingTypeArguments,
-      Set<ClassEntity> classesUsingTypeVariableExpression) {
+      Set<Selector> selectorsNeedingTypeArguments) {
     return new _ResolutionRuntimeTypesNeed(
         _elementEnvironment,
         backendUsage,
@@ -1347,7 +1487,7 @@
         methodsNeedingTypeArguments,
         localFunctionsNeedingSignature,
         localFunctionsNeedingTypeArguments,
-        classesUsingTypeVariableExpression);
+        selectorsNeedingTypeArguments);
   }
 }
 
@@ -1356,10 +1496,9 @@
   final TypeChecks requiredChecks;
   final Iterable<ClassEntity> checkedClasses;
   final Iterable<FunctionType> checkedFunctionTypes;
-  final TypeVariableTests _typeVariableTests;
 
   _RuntimeTypesChecks(this._substitutions, this.requiredChecks,
-      this.checkedClasses, this.checkedFunctionTypes, this._typeVariableTests);
+      this.checkedClasses, this.checkedFunctionTypes);
 
   @override
   Iterable<ClassEntity> get requiredClasses {
@@ -1372,10 +1511,6 @@
     collector.collect(type);
     return collector.classes;
   }
-
-  @override
-  Iterable<ClassEntity> get classesUsingTypeVariableTests =>
-      _typeVariableTests.classTests;
 }
 
 class RuntimeTypesImpl extends _RuntimeTypesBase
@@ -1413,7 +1548,8 @@
   RuntimeTypesChecks computeRequiredChecks(
       CodegenWorldBuilder codegenWorldBuilder) {
     TypeVariableTests typeVariableTests = new TypeVariableTests(
-        _elementEnvironment, _commonElements, _types, codegenWorldBuilder);
+        _elementEnvironment, _commonElements, _types, codegenWorldBuilder,
+        forRtiNeeds: false);
     Set<DartType> explicitIsChecks = typeVariableTests.explicitIsChecks;
     Set<DartType> implicitIsChecks = typeVariableTests.implicitIsChecks;
 
@@ -1479,8 +1615,8 @@
 
     cachedRequiredChecks = _computeChecks(classUseMap);
     rtiChecksBuilderClosed = true;
-    return new _RuntimeTypesChecks(this, cachedRequiredChecks, checkedClasses,
-        checkedFunctionTypes, typeVariableTests);
+    return new _RuntimeTypesChecks(
+        this, cachedRequiredChecks, checkedClasses, checkedFunctionTypes);
   }
 
   Set<FunctionType> computeInstantiatedClosureTypes(
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 7a88ac1..4c57841 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -110,7 +110,11 @@
   final RuntimeTypesEncoder _rtiEncoder;
   final JsInteropAnalysis _jsInteropAnalysis;
   final bool _useKernel;
+
+  /// ignore: UNUSED_FIELD
   final bool _strongMode;
+
+  /// ignore: UNUSED_FIELD
   final bool _disableRtiOptimization;
 
   RuntimeTypeGenerator(
@@ -132,9 +136,6 @@
   Iterable<ClassEntity> get checkedClasses =>
       _typeTestRegistry.rtiChecks.checkedClasses;
 
-  Iterable<ClassEntity> get classesUsingTypeVariableTests =>
-      _typeTestRegistry.rtiChecks.classesUsingTypeVariableTests;
-
   Iterable<FunctionType> get checkedFunctionTypes =>
       _typeTestRegistry.rtiChecks.checkedFunctionTypes;
 
@@ -186,27 +187,13 @@
         if (_useKernel &&
             signature != null &&
             generatedCode[signature] != null) {
+          // Use precomputed signature function.
           encoding = generatedCode[signature];
         } else {
-          // With Dart 2, if disableRtiOptimization is true, then we might
-          // generate some code for classes that are not actually called,
-          // so following this path is "okay." Also, classes that have call
-          // methods are no longer a subtype of Function (and therefore we don't
-          // create a closure class), so this path is also acceptable.
-
-          // TODO(efortuna, johnniwinther): Verify that closures that use this
-          // path are in fact dead code. If this *not* actually dead code, we
-          // get to this point because TrivialRuntimeTypesChecksBuilder
-          // specifies that every subtype of Object and its types is "used"
-          // (ClassUse = true). However, on the codegen side, we only codegen
-          // entities that are actually reachable via treeshaking. To solve this
-          // issue, if disableRtiOptimization is turned on, we could literally
-          // in world_impact.dart loop through every subclass of Object and say
-          // that all types related to JClosureClasses are "used" so the go
-          // through the codegen queue and therefore we generate code for it.
-          // This seems not ideal though.
-          assert(!(_useKernel && _strongMode && !_disableRtiOptimization) ||
-              (_useKernel && _strongMode && !method.enclosingClass.isClosure));
+          // TODO(efortuna): Reinsert assertion.
+          // TODO(johnniwinther): Avoid unneeded signatures from closure
+          // classes.
+          // Use shared signature function.
           encoding = _rtiEncoder.getSignatureEncoding(
               emitterTask.emitter, type, thisAccess);
         }
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 0a09460..e48188e 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -15,6 +15,7 @@
 import '../constants/values.dart';
 import '../deferred_load.dart';
 import '../elements/entities.dart';
+import '../elements/names.dart';
 import '../elements/types.dart';
 import '../enqueue.dart';
 import '../io/kernel_source_information.dart'
@@ -40,6 +41,7 @@
 import '../ssa/ssa.dart';
 import '../types/types.dart';
 import '../universe/class_set.dart';
+import '../universe/selector.dart';
 import '../universe/world_builder.dart';
 import '../util/emptyset.dart';
 import '../world.dart';
@@ -502,8 +504,18 @@
         map.toBackendFunctionSet(rtiNeed.methodsNeedingTypeArguments);
     Set<FunctionEntity> methodsNeedingSignature =
         map.toBackendFunctionSet(rtiNeed.methodsNeedingSignature);
-    Set<ClassEntity> classesUsingTypeVariableExpression =
-        map.toBackendClassSet(rtiNeed.classesUsingTypeVariableLiterals);
+    Set<Selector> selectorsNeedingTypeArguments =
+        rtiNeed.selectorsNeedingTypeArguments.map((Selector selector) {
+      if (selector.memberName.isPrivate) {
+        return new Selector(
+            selector.kind,
+            new PrivateName(selector.memberName.text,
+                map.toBackendLibrary(selector.memberName.library),
+                isSetter: selector.memberName.isSetter),
+            selector.callStructure);
+      }
+      return selector;
+    }).toSet();
     return new RuntimeTypesNeedImpl(
         _elementEnvironment,
         backendUsage,
@@ -512,7 +524,7 @@
         methodsNeedingTypeArguments,
         null,
         null,
-        classesUsingTypeVariableExpression);
+        selectorsNeedingTypeArguments);
   }
 
   /// Construct a closure class and set up the necessary class inference
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index 21cb15e..bfb8531 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -358,17 +358,17 @@
   TypeMask getReturnTypeOf(FunctionEntity function);
 
   /// Returns the inferred receiver type of the dynamic [invocation].
-  TypeMask typeOfInvocation(
+  TypeMask receiverTypeOfInvocation(
       ir.MethodInvocation invocation, ClosedWorld closedWorld);
 
   /// Returns the inferred receiver type of the dynamic [read].
-  TypeMask typeOfGet(ir.PropertyGet read);
+  TypeMask receiverTypeOfGet(ir.PropertyGet read);
 
   /// Returns the inferred receiver type of the direct [read].
-  TypeMask typeOfDirectGet(ir.DirectPropertyGet read);
+  TypeMask receiverTypeOfDirectGet(ir.DirectPropertyGet read);
 
   /// Returns the inferred receiver type of the dynamic [write].
-  TypeMask typeOfSet(ir.PropertySet write, ClosedWorld closedWorld);
+  TypeMask receiverTypeOfSet(ir.PropertySet write, ClosedWorld closedWorld);
 
   /// Returns the inferred type of [listLiteral].
   TypeMask typeOfListLiteral(covariant MemberEntity owner,
diff --git a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
index ac1f34c..d0de459 100644
--- a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
@@ -129,20 +129,21 @@
         function, _globalInferenceResults);
   }
 
-  TypeMask typeOfInvocation(ir.MethodInvocation node, ClosedWorld closedWorld) {
+  TypeMask receiverTypeOfInvocation(
+      ir.MethodInvocation node, ClosedWorld closedWorld) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask typeOfGet(ir.PropertyGet node) {
+  TypeMask receiverTypeOfGet(ir.PropertyGet node) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask typeOfDirectGet(ir.DirectPropertyGet node) {
+  TypeMask receiverTypeOfDirectGet(ir.DirectPropertyGet node) {
     return _targetResults.typeOfSend(node);
   }
 
-  TypeMask typeOfSet(ir.PropertySet node, ClosedWorld closedWorld) {
-    return closedWorld.commonMasks.dynamicType;
+  TypeMask receiverTypeOfSet(ir.PropertySet node, ClosedWorld closedWorld) {
+    return _targetResults.typeOfSend(node);
   }
 
   TypeMask typeOfListLiteral(
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 6233855..9ba287b 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -13,7 +13,6 @@
     show
         BaseClassElementX,
         ErroneousElementX,
-        LibraryElementX,
         MixinApplicationElementX,
         SynthesizedConstructorElementX,
         TypeVariableElementX,
@@ -32,10 +31,6 @@
 import 'scope.dart' show Scope, TypeDeclarationScope;
 import 'type_resolver.dart' show FunctionTypeParameterScope;
 
-/// If `true` compatible mixin applications are shared within a library. This
-/// matches the mixins generated by fasta.
-bool useOptimizedMixins = false;
-
 class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> {
   Scope scope;
   final TypeDeclarationElement enclosingElement;
@@ -152,11 +147,7 @@
     if (element.supertype == null && node.superclass != null) {
       MixinApplication superMixin = node.superclass.asMixinApplication();
       if (superMixin != null) {
-        if (useOptimizedMixins) {
-          element.supertype = createMixinsOptimized(element, superMixin);
-        } else {
-          element.supertype = createMixins(element, superMixin);
-        }
+        element.supertype = createMixins(element, superMixin);
       } else {
         element.supertype = resolveSupertype(element, node.superclass);
       }
@@ -288,223 +279,10 @@
 
     // Generate anonymous mixin application elements for the
     // intermediate mixin applications (excluding the last).
-    if (useOptimizedMixins) {
-      createMixinsOptimized(element, node, isNamed: true);
-    } else {
-      createMixins(element, node, isNamed: true);
-    }
+    createMixins(element, node, isNamed: true);
     return element.computeType(resolution);
   }
 
-  /// Create the mixin applications for [superMixin].
-  ///
-  /// This algorithm is ported from
-  /// `package:front_end/src/fasta/kernel/kernel_library_builder.dart` and
-  /// added create allow for equivalence testing between the AST and kernel
-  /// based compilations in face of shared mixins. It will be removed when we
-  /// no longer need equivalence testing.
-  ResolutionDartType createMixinsOptimized(
-      BaseClassElementX element, MixinApplication superMixin,
-      {bool isNamed: false}) {
-    List<ResolutionDartType> typeVariables = element.typeVariables;
-    LibraryElementX library = element.library;
-    Map<String, MixinApplicationElementX> mixinApplicationClasses =
-        library.mixinApplicationCache;
-
-    String name = element.isNamedMixinApplication ? element.name : null;
-    ResolutionDartType supertype =
-        resolveSupertype(element, superMixin.superclass);
-    Link<Node> link = superMixin.mixins.nodes;
-    List<ResolutionDartType> mixins = <ResolutionDartType>[];
-    List<Node> mixinNodes = <Node>[];
-    while (!link.isEmpty) {
-      mixins.add(checkMixinType(link.head));
-      mixinNodes.add(link.head);
-      link = link.tail;
-    }
-
-    List<List<String>> signatureParts = <List<String>>[];
-    Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{};
-
-    {
-      Map<String, String> unresolved = <String, String>{};
-      int unresolvedCount = 0;
-
-      /// Compute a signature of the type arguments used by the supertype and
-      /// mixins. These types are free variables. At this point we can't
-      /// trust that the number of type arguments match the type parameters,
-      /// so we also need to be able to detect missing type arguments.  To do
-      /// so, we separate each list of type arguments by `^` and type
-      /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
-      /// look like this:
-      ///
-      ///     ^#U0^#U1&#U2
-      ///
-      /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
-      /// `S`, `T`, and `U` respectively.
-      ///
-      /// As we can resolve any type parameters used at this point, those are
-      /// named `#T0` and so forth. This reduces the number of free variables
-      /// which is crucial for memory usage and the Dart VM's bootstrap
-      /// sequence.
-      ///
-      /// For example, consider this use of mixin applications:
-      ///
-      ///     class _InternalLinkedHashMap<K, V> extends _HashVMBase
-      ///         with
-      ///             MapMixin<K, V>,
-      ///             _LinkedHashMapMixin<K, V>,
-      ///             _HashBase,
-      ///             _OperatorEqualsAndHashCode {}
-      ///
-      /// In this case, only two variables are free, and we produce this
-      /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
-      /// sames mixins but with missing type arguments for `MapMixin`, its
-      /// signature would be: `^^^#T0&#T1^^`.
-      ///
-      /// Note that we do not need to compute a signature for a named mixin
-      /// application with only one mixin as we don't have to invent a name
-      /// for any classes in this situation.
-      void analyzeArguments(ResolutionDartType type, {bool isLast}) {
-        if (isNamed && isLast) {
-          // The last mixin of a named mixin application doesn't contribute
-          // to free variables.
-          return;
-        }
-        if (type is GenericType) {
-          List<String> part = <String>[];
-          for (int i = 0; i < type.typeArguments.length; i++) {
-            var argument = type.typeArguments[i];
-            String name;
-            if (argument is ResolutionTypeVariableType) {
-              int index = typeVariables.indexOf(argument) ?? -1;
-              if (index != -1) {
-                name = "#T${index}";
-              }
-            } else if (argument is GenericType && argument.isRaw) {
-              name = unresolved[argument.name] ??= "#U${unresolvedCount++}";
-            }
-            name ??= "#U${unresolvedCount++}";
-            freeTypes[name] = argument;
-            part.add(name);
-          }
-          signatureParts.add(part);
-        }
-      }
-
-      analyzeArguments(supertype, isLast: false);
-      for (int i = 0; i < mixins.length; i++) {
-        analyzeArguments(mixins[i], isLast: i == mixins.length - 1);
-      }
-    }
-
-    List<List<String>> currentSignatureParts = <List<String>>[];
-    String computeSignature(int index) {
-      if (freeTypes.isEmpty) return "";
-      currentSignatureParts.add(signatureParts[index]);
-      if (currentSignatureParts.any((l) => l.isNotEmpty)) {
-        return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
-      } else {
-        return "";
-      }
-    }
-
-    Map<String, ResolutionTypeVariableType> computeTypeVariables(
-        ClassElement cls, Node node) {
-      Map<String, ResolutionTypeVariableType> variables =
-          <String, ResolutionTypeVariableType>{};
-      int index = 0;
-      for (List<String> strings in currentSignatureParts) {
-        for (String name in strings) {
-          variables.putIfAbsent(name, () {
-            ResolutionTypeVariableType typeVariable =
-                new ResolutionTypeVariableType(
-                    new TypeVariableElementX(name, cls, index++, node));
-            TypeVariableElementX typeVariableElement = typeVariable.element;
-            typeVariableElement.typeCache = typeVariable;
-            typeVariableElement.boundCache = const ResolutionDynamicType();
-            return typeVariable;
-          });
-        }
-      }
-      return variables;
-    }
-
-    computeSignature(0); // This combines the supertype with the first mixin.
-
-    for (int i = 0; i < mixins.length; i++) {
-      int signatureIndex = i + 1;
-      Set<String> supertypeArguments = new Set<String>();
-      for (List<String> part in currentSignatureParts) {
-        supertypeArguments.addAll(part);
-      }
-      Node node = mixinNodes[i];
-      ResolutionDartType mixin = mixins[i];
-
-      bool lastAndNamed = i == mixins.length - 1 && isNamed;
-
-      ResolutionInterfaceType createMixinApplication() {
-        Map<String, ResolutionDartType> variables;
-        MixinApplicationElementX mixinElement;
-        ResolutionDartType mixinType;
-        if (lastAndNamed) {
-          mixinElement = element;
-          variables = freeTypes;
-        } else {
-          String signature = computeSignature(signatureIndex);
-          name = supertype.name;
-          int index = name.indexOf("^");
-          if (index != -1) {
-            name = name.substring(0, index);
-          }
-          name = "_$name&${mixin.name}$signature";
-          mixinElement = mixinApplicationClasses[name];
-          if (mixinElement != null) return mixinElement.thisType;
-
-          mixinElement = new UnnamedMixinApplicationElementX(
-              name, element, resolution.idGenerator.getNextFreeId(), node);
-          variables = computeTypeVariables(mixinElement, node);
-          mixinElement.setThisAndRawTypes(variables.values.toList());
-          mixinApplicationClasses[name] = mixinElement;
-        }
-
-        if (supertypeArguments.isNotEmpty) {
-          List<ResolutionDartType> supertypeTypeArguments =
-              <ResolutionDartType>[];
-          for (String part in supertypeArguments) {
-            supertypeTypeArguments.add(variables[part]);
-          }
-          supertype = new ResolutionInterfaceType(
-              supertype.element, supertypeTypeArguments);
-        }
-
-        if (lastAndNamed) {
-          mixinType = mixin;
-        } else {
-          List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[];
-          for (String part in signatureParts[signatureIndex]) {
-            mixinTypeArguments.add(variables[part]);
-          }
-          mixinType =
-              new ResolutionInterfaceType(mixin.element, mixinTypeArguments);
-        }
-
-        doApplyMixinTo(mixinElement, supertype, mixinType);
-        mixinElement.resolutionState = STATE_DONE;
-        mixinElement.supertypeLoadState = STATE_DONE;
-        return mixinElement.thisType;
-      }
-
-      supertype = createMixinApplication();
-    }
-
-    if (!isNamed) {
-      typeVariables = freeTypes.values.toList();
-    }
-
-    return new ResolutionInterfaceType(supertype.element, typeVariables);
-  }
-
   ResolutionDartType createMixins(ClassElement element, MixinApplication node,
       {bool isNamed: false}) {
     ResolutionDartType supertype = resolveSupertype(element, node.superclass);
diff --git a/pkg/compiler/lib/src/resolution/resolution_strategy.dart b/pkg/compiler/lib/src/resolution/resolution_strategy.dart
index a3d9504..f425600 100644
--- a/pkg/compiler/lib/src/resolution/resolution_strategy.dart
+++ b/pkg/compiler/lib/src/resolution/resolution_strategy.dart
@@ -737,8 +737,7 @@
 
   @override
   List<TypeVariableType> getFunctionTypeVariables(FunctionEntity function) {
-    throw new UnsupportedError(
-        "_CompilerElementEnvironment.getFunctionTypeVariables");
+    return const <TypeVariableType>[];
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index ba6cb77..cc9ea4b 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -2706,7 +2706,7 @@
 
     _pushDynamicInvocation(
         node,
-        _typeInferenceMap.typeOfGet(node),
+        _typeInferenceMap.receiverTypeOfGet(node),
         new Selector.getter(_elementMap.getName(node.name)),
         <HInstruction>[receiver],
         const <DartType>[],
@@ -2736,7 +2736,7 @@
 
     _pushDynamicInvocation(
         node,
-        _typeInferenceMap.typeOfSet(node, closedWorld),
+        _typeInferenceMap.receiverTypeOfSet(node, closedWorld),
         new Selector.setter(_elementMap.getName(node.name)),
         <HInstruction>[receiver, value],
         const <DartType>[],
@@ -2755,7 +2755,7 @@
     // TODO(sra): Implement direct invocations properly.
     _pushDynamicInvocation(
         node,
-        _typeInferenceMap.typeOfDirectGet(node),
+        _typeInferenceMap.receiverTypeOfDirectGet(node),
         new Selector.getter(_elementMap.getMember(node.target).memberName),
         <HInstruction>[receiver],
         const <DartType>[],
@@ -2934,14 +2934,18 @@
     return values;
   }
 
-  List<DartType> _getDynamicTypeArguments(
-      Selector selector, ir.Arguments arguments) {
-    if (options.strongMode && arguments.types.isNotEmpty) {
-      // TODO(johnniwinther): Only pass type arguments to dynamic call where at
-      // least one potential target need them.
-      return arguments.types.map(_elementMap.getDartType).toList();
+  /// Fills [typeArguments] with the type arguments needed for [selector] and
+  /// returns the selector corresponding to the passed type arguments.
+  Selector _fillDynamicTypeArguments(
+      Selector selector, ir.Arguments arguments, List<DartType> typeArguments) {
+    if (options.strongMode && selector.typeArgumentCount > 0) {
+      if (rtiNeed.selectorNeedsTypeArguments(selector)) {
+        typeArguments.addAll(arguments.types.map(_elementMap.getDartType));
+      } else {
+        return selector.toNonGeneric();
+      }
     }
-    return const <DartType>[];
+    return selector;
   }
 
   List<DartType> _getConstructorTypeArguments(
@@ -4024,11 +4028,12 @@
     node.receiver.accept(this);
     HInstruction receiver = pop();
     Selector selector = _elementMap.getSelector(node);
-    List<DartType> typeArguments =
-        _getDynamicTypeArguments(selector, node.arguments);
+    List<DartType> typeArguments = <DartType>[];
+    selector =
+        _fillDynamicTypeArguments(selector, node.arguments, typeArguments);
     _pushDynamicInvocation(
         node,
-        _typeInferenceMap.typeOfInvocation(node, closedWorld),
+        _typeInferenceMap.receiverTypeOfInvocation(node, closedWorld),
         selector,
         <HInstruction>[receiver]..addAll(_visitArgumentsForDynamicTarget(
             selector, node.arguments, typeArguments)),
@@ -4167,8 +4172,9 @@
         _sourceInformationBuilder.buildCall(node, node);
     if (node.interfaceTarget == null) {
       Selector selector = _elementMap.getSelector(node);
-      List<DartType> typeArguments =
-          _getDynamicTypeArguments(selector, node.arguments);
+      List<DartType> typeArguments = <DartType>[];
+      selector =
+          _fillDynamicTypeArguments(selector, node.arguments, typeArguments);
       List<HInstruction> arguments = _visitArgumentsForDynamicTarget(
           selector, node.arguments, typeArguments);
       _generateSuperNoSuchMethod(
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 3492172..8654584 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1846,8 +1846,8 @@
       // for this to work.
       assert(selector.applies(target),
           failedAt(node, '$selector does not apply to $target'));
-      _registry.registerStaticUse(
-          new StaticUse.directInvoke(target, selector.callStructure));
+      _registry.registerStaticUse(new StaticUse.directInvoke(
+          target, selector.callStructure, node.typeArguments));
     } else {
       TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
       _registry.registerDynamicUse(
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index 1953d7b..38476a9 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -57,6 +57,10 @@
   /// The names of the named arguments in canonicalized order.
   List<String> getOrderedNamedArguments() => const <String>[];
 
+  CallStructure get nonGeneric => typeArgumentCount == 0
+      ? this
+      : new CallStructure(argumentCount, namedArguments);
+
   /// A description of the argument structure.
   String structureToString() {
     StringBuffer sb = new StringBuffer();
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index bc4937e..fa33d69 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -266,7 +266,8 @@
 
     switch (dynamicUse.kind) {
       case DynamicUseKind.INVOKE:
-        registerDynamicInvocation(dynamicUse);
+        registerDynamicInvocation(
+            dynamicUse.selector, dynamicUse.typeArguments);
         if (_registerNewSelector(dynamicUse, _invokedNames)) {
           _process(_instanceMembersByName, (m) => m.invoke());
           return true;
@@ -422,12 +423,17 @@
         useSet.addAll(usage.normalUse());
         break;
       case StaticUseKind.DIRECT_INVOKE:
-        _MemberUsage instanceUsage =
-            _getMemberUsage(staticUse.element, memberUsed);
+        MemberEntity member = staticUse.element;
+        _MemberUsage instanceUsage = _getMemberUsage(member, memberUsed);
         memberUsed(instanceUsage.entity, instanceUsage.invoke());
         _instanceMembersByName[instanceUsage.entity.name]
             ?.remove(instanceUsage);
         useSet.addAll(usage.normalUse());
+        if (staticUse.typeArguments?.isNotEmpty ?? false) {
+          registerDynamicInvocation(
+              new Selector.call(member.memberName, staticUse.callStructure),
+              staticUse.typeArguments);
+        }
         break;
       case StaticUseKind.INLINING:
         break;
@@ -571,6 +577,26 @@
     }
     return _constantValues.add(use.value);
   }
+
+  @override
+  Iterable<Local> get genericLocalFunctions => const <Local>[];
+
+  @override
+  Iterable<FunctionEntity> get genericInstanceMethods {
+    List<FunctionEntity> functions = <FunctionEntity>[];
+
+    void processMemberUse(MemberEntity member, _MemberUsage memberUsage) {
+      if (member.isInstanceMember &&
+          member is FunctionEntity &&
+          memberUsage.hasUse &&
+          _elementEnvironment.getFunctionTypeVariables(member).isNotEmpty) {
+        functions.add(member);
+      }
+    }
+
+    _instanceMemberUsage.forEach(processMemberUse);
+    return functions;
+  }
 }
 
 class ElementCodegenWorldBuilderImpl extends CodegenWorldBuilderImpl {
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index 0d599e7..95a24e8 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -98,6 +98,8 @@
   /// Registers that [type] is checked in this world builder. The unaliased type
   /// is returned.
   void registerIsCheck(DartType type);
+
+  void registerTypeVariableTypeLiteral(TypeVariableType typeVariable);
 }
 
 /// The type and kind of an instantiation registered through
@@ -382,6 +384,8 @@
 
   final Set<ConstantValue> _constantValues = new Set<ConstantValue>();
 
+  final Set<Local> genericLocalFunctions = new Set<Local>();
+
   Set<MemberEntity> _processedMembers = new Set<MemberEntity>();
 
   bool get isClosed => _closed;
@@ -408,10 +412,23 @@
 
   bool isMemberProcessed(MemberEntity member) =>
       _processedMembers.contains(member);
+
   void registerProcessedMember(MemberEntity member) {
     _processedMembers.add(member);
   }
 
+  Iterable<FunctionEntity> get genericInstanceMethods {
+    List<FunctionEntity> functions = <FunctionEntity>[];
+    for (MemberEntity member in processedMembers) {
+      if (member.isInstanceMember &&
+          member.isFunction &&
+          _elementEnvironment.getFunctionTypeVariables(member).isNotEmpty) {
+        functions.add(member);
+      }
+    }
+    return functions;
+  }
+
   Iterable<MemberEntity> get processedMembers => _processedMembers;
 
   ClosedWorld get closedWorldForTesting {
@@ -571,7 +588,8 @@
 
     switch (dynamicUse.kind) {
       case DynamicUseKind.INVOKE:
-        registerDynamicInvocation(dynamicUse);
+        registerDynamicInvocation(
+            dynamicUse.selector, dynamicUse.typeArguments);
         if (_registerNewSelector(dynamicUse, _invokedNames)) {
           _process(_instanceMembersByName, (m) => m.invoke());
         }
@@ -620,10 +638,17 @@
       if (type.containsTypeVariables) {
         localFunctionsWithFreeTypeVariables.add(localFunction);
       }
+      if (type.typeVariables.isNotEmpty) {
+        genericLocalFunctions.add(localFunction);
+      }
       localFunctions.add(staticUse.element);
       return;
     } else if (staticUse.kind == StaticUseKind.CLOSURE_CALL) {
-      registerStaticInvocation(staticUse);
+      if (staticUse.typeArguments?.isNotEmpty ?? false) {
+        registerDynamicInvocation(
+            new Selector.call(Names.call, staticUse.callStructure),
+            staticUse.typeArguments);
+      }
       return;
     }
 
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 5e1d07d..263d4ac 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -270,4 +270,11 @@
   }
 
   Selector toCallSelector() => new Selector.callClosureFrom(this);
+
+  /// Returns the non-generic [Selector] corresponding to this selector.
+  Selector toNonGeneric() {
+    return callStructure.typeArgumentCount > 0
+        ? new Selector(kind, memberName, callStructure.nonGeneric)
+        : this;
+  }
 }
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 1ed7da7..43958f0 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -306,16 +306,16 @@
   }
 
   /// Direct invocation of a method [element] with the given [callStructure].
-  factory StaticUse.directInvoke(
-      FunctionEntity element, CallStructure callStructure) {
+  factory StaticUse.directInvoke(FunctionEntity element,
+      CallStructure callStructure, List<DartType> typeArguments) {
     assert(
         element.isInstanceMember,
         failedAt(element,
             "Direct invoke element $element must be an instance member."));
     assert(element.isFunction,
         failedAt(element, "Direct invoke element $element must be a method."));
-    return new StaticUse.internal(element, StaticUseKind.DIRECT_INVOKE,
-        callStructure: callStructure);
+    return new GenericStaticUse(
+        element, StaticUseKind.DIRECT_INVOKE, callStructure, typeArguments);
   }
 
   /// Direct read access of a field or getter [element].
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 92e4220..4feb2a8 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -7,7 +7,7 @@
 import 'dart:collection';
 
 import '../common.dart';
-import '../common/names.dart' show Identifiers;
+import '../common/names.dart' show Identifiers, Names;
 import '../common/resolution.dart' show Resolution;
 import '../common_elements.dart';
 import '../constants/constant_system.dart';
@@ -188,12 +188,22 @@
   // TODO(johnniwinther): Improve semantic precision.
   Iterable<InterfaceType> get instantiatedTypes;
 
-  /// Set of methods in instantiated classes that are potentially closurized.
+  // TODO(johnniwinther): Clean up these getters.
+  /// Methods in instantiated classes that are potentially closurized.
   Iterable<FunctionEntity> get closurizedMembers;
 
-  /// Set of static or top level methods that are closurized.
+  /// Static or top level methods that are closurized.
   Iterable<FunctionEntity> get closurizedStatics;
 
+  /// Live generic instance methods.
+  Iterable<FunctionEntity> get genericInstanceMethods;
+
+  /// Live generic local functions.
+  Iterable<Local> get genericLocalFunctions;
+
+  /// Type variables used as type literals.
+  Iterable<TypeVariableType> get typeVariableTypeLiterals;
+
   /// Call [f] for each generic [function] with the type arguments passed
   /// through static calls to [function].
   void forEachStaticTypeArgument(
@@ -218,6 +228,9 @@
   /// Set of static or top level methods that are closurized.
   final Set<FunctionEntity> closurizedStatics = new Set<FunctionEntity>();
 
+  final Set<TypeVariableType> typeVariableTypeLiterals =
+      new Set<TypeVariableType>();
+
   void _registerStaticTypeArgumentDependency(
       Entity element, List<DartType> typeArguments) {
     _staticTypeArgumentDependencies.putIfAbsent(
@@ -240,10 +253,10 @@
         staticUse.element, staticUse.typeArguments);
   }
 
-  void registerDynamicInvocation(DynamicUse dynamicUse) {
-    if (dynamicUse.typeArguments.isEmpty) return;
-    _registerDynamicTypeArgumentDependency(
-        dynamicUse.selector, dynamicUse.typeArguments);
+  void registerDynamicInvocation(
+      Selector selector, List<DartType> typeArguments) {
+    if (typeArguments.isEmpty) return;
+    _registerDynamicTypeArgumentDependency(selector, typeArguments);
   }
 
   void forEachStaticTypeArgument(
@@ -255,4 +268,8 @@
       void f(Selector selector, Set<DartType> typeArguments)) {
     _dynamicTypeArgumentDependencies.forEach(f);
   }
+
+  void registerTypeVariableTypeLiteral(TypeVariableType typeVariable) {
+    typeVariableTypeLiterals.add(typeVariable);
+  }
 }
diff --git a/pkg/compiler/testing_dart.json b/pkg/compiler/testing_dart.json
index 428cfd2..b0fb40c3a 100644
--- a/pkg/compiler/testing_dart.json
+++ b/pkg/compiler/testing_dart.json
@@ -16,8 +16,6 @@
     "exclude": [
       "^tests/compiler/dart2js/codegen_helper\\.dart",
       "^tests/compiler/dart2js/codegen/type_inference8_test\\.dart",
-      "^tests/compiler/dart2js/constant_expression_evaluate_test\\.dart",
-      "^tests/compiler/dart2js/constant_expression_test\\.dart",
       "^tests/compiler/dart2js/data/one_line_dart_program\\.dart",
       "^tests/compiler/dart2js/deferred/inline_restrictions_test\\.dart",
       "^tests/compiler/dart2js/deferred/load_graph_segmentation2_test\\.dart",
@@ -40,6 +38,8 @@
       "^tests/compiler/dart2js/mirrors/deferred_mirrors_test\\.dart",
       "^tests/compiler/dart2js/mirrors/mirrors_used_test\\.dart",
       "^tests/compiler/dart2js/mixin_typevariable_test\\.dart",
+      "^tests/compiler/dart2js/model/constant_expression_evaluate_test\\.dart",
+      "^tests/compiler/dart2js/model/constant_expression_test\\.dart",
       "^tests/compiler/dart2js/needs_no_such_method_test\\.dart",
       "^tests/compiler/dart2js/no_such_method_enabled_test\\.dart",
       "^tests/compiler/dart2js/output_collector\\.dart",
@@ -68,14 +68,10 @@
       "^tests/compiler/dart2js/sourcemaps/helpers/sourcemap_helper\\.dart",
       "^tests/compiler/dart2js/sourcemaps/helpers/sourcemap_html_helper\\.dart",
       "^tests/compiler/dart2js/sourcemaps/stacktrace_test\\.dart",
-      "^tests/compiler/dart2js/subtype_test\\.dart",
-      "^tests/compiler/dart2js/subtypeset_test\\.dart",
       "^tests/compiler/dart2js/token_naming_test\\.dart",
       "^tests/compiler/dart2js/type_representation_test\\.dart",
-      "^tests/compiler/dart2js/type_substitution_test\\.dart",
       "^tests/compiler/dart2js/type_variable_occurrence_test\\.dart",
       "^tests/compiler/dart2js/unused_empty_map_test\\.dart",
-      "^tests/compiler/dart2js/world_test\\.dart",
 
       "^tests/compiler/dart2js/path with spaces/.*"
     ]
diff --git a/pkg/dev_compiler/bin/dartdevk.dart b/pkg/dev_compiler/bin/dartdevk.dart
index b0d6aec..36f4535 100755
--- a/pkg/dev_compiler/bin/dartdevk.dart
+++ b/pkg/dev_compiler/bin/dartdevk.dart
@@ -104,7 +104,7 @@
     return new _ParsedArgs(true, false, args.sublist(0, args.length - 1));
   }
 
-  var newArgs = [];
+  var newArgs = <String>[];
   bool isWorker = false;
   var len = args.length;
   for (int i = 0; i < len; i++) {
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 489c467..db33ffb 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -218,8 +218,9 @@
         types = c.typeProvider,
         _asyncStreamIterator =
             _getLibrary(c, 'dart:async').getType('StreamIterator').type,
-        _coreIdentical =
-            _getLibrary(c, 'dart:core').publicNamespace.get('identical'),
+        _coreIdentical = _getLibrary(c, 'dart:core')
+            .publicNamespace
+            .get('identical') as FunctionElement,
         _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'),
         _jsBool = _getLibrary(c, 'dart:_interceptors').getType('JSBool'),
         _jsString = _getLibrary(c, 'dart:_interceptors').getType('JSString'),
@@ -254,9 +255,9 @@
   LibraryElement get currentLibrary => _currentElement.library;
 
   CompilationUnitElement get _currentCompilationUnit {
-    var e = _currentElement;
-    while (e is! CompilationUnitElement) e = e.enclosingElement;
-    return e;
+    for (var e = _currentElement;; e = e.enclosingElement) {
+      if (e is CompilationUnitElement) return e;
+    }
   }
 
   /// The main entry point to JavaScript code generation.
@@ -291,13 +292,12 @@
 
     var assembler = new PackageBundleAssembler();
 
-    var uriToUnit = new Map<String, UnlinkedUnit>.fromIterable(units,
-        key: (u) => u.element.source.uri.toString(),
-        value: (unit) {
-          var unlinked = serializeAstUnlinked(unit);
-          assembler.addUnlinkedUnit(unit.element.source, unlinked);
-          return unlinked;
-        });
+    var uriToUnit = new Map<String, UnlinkedUnit>.fromIterables(
+        units.map((u) => u.element.source.uri.toString()), units.map((unit) {
+      var unlinked = serializeAstUnlinked(unit);
+      assembler.addUnlinkedUnit(unit.element.source, unlinked);
+      return unlinked;
+    }));
 
     summary_link
         .link(
@@ -329,8 +329,9 @@
     var root = new JS.Identifier('_root');
     items.add(js.statement('const # = Object.create(null)', [root]));
 
-    if (compilationUnits.any((u) => isSdkInternalRuntime(
-        resolutionMap.elementDeclaredByCompilationUnit(u).library))) {
+    var isBuildingSdk =
+        compilationUnits.any((u) => isSdkInternalRuntime(u.element.library));
+    if (isBuildingSdk) {
       // Don't allow these to be renamed when we're building the SDK.
       // There is JS code in dart:* that depends on their names.
       _runtimeModule = new JS.Identifier('dart');
@@ -343,28 +344,29 @@
     _typeTable = new TypeTable(_runtimeModule);
 
     // Initialize our library variables.
-    var isBuildingSdk = false;
+    var exports = <JS.NameSpecifier>[];
+    void emitLibrary(JS.Identifier id) {
+      items.add(js.statement('const # = Object.create(#)', [id, root]));
+      exports.add(new JS.NameSpecifier(id));
+    }
+
     for (var unit in compilationUnits) {
-      var library =
-          resolutionMap.elementDeclaredByCompilationUnit(unit).library;
+      var library = unit.element.library;
       if (unit.element != library.definingCompilationUnit) continue;
 
       var libraryTemp = isSdkInternalRuntime(library)
           ? _runtimeModule
           : new JS.TemporaryId(jsLibraryName(_libraryRoot, library));
       _libraries[library] = libraryTemp;
-      items.add(new JS.ExportDeclaration(
-          js.call('const # = Object.create(#)', [libraryTemp, root])));
-
-      // dart:_runtime has a magic module that holds extension method symbols.
-      // TODO(jmesserly): find a cleaner design for this.
-      if (isSdkInternalRuntime(library)) {
-        isBuildingSdk = true;
-        items.add(new JS.ExportDeclaration(js.call(
-            'const # = Object.create(#)', [_extensionSymbolsModule, root])));
-      }
+      emitLibrary(libraryTemp);
     }
 
+    // dart:_runtime has a magic module that holds extension method symbols.
+    // TODO(jmesserly): find a cleaner design for this.
+    if (isBuildingSdk) emitLibrary(_extensionSymbolsModule);
+
+    items.add(new JS.ExportDeclaration(new JS.ExportClause(exports)));
+
     // Collect all class/type Element -> Node mappings
     // in case we need to forward declare any classes.
     _declarationNodes = new HashMap<TypeDefiningElement, AstNode>.identity();
@@ -401,7 +403,7 @@
     _finishImports(items);
     // Initialize extension symbols
     _extensionSymbols.forEach((name, id) {
-      var value =
+      JS.Expression value =
           new JS.PropertyAccess(_extensionSymbolsModule, _propertyName(name));
       if (isBuildingSdk) {
         value = js.call('# = Symbol(#)', [value, js.string("dartx.$name")]);
@@ -472,16 +474,19 @@
     return libraryJSName != null ? '$libraryJSName.$jsName' : jsName;
   }
 
-  JS.Expression _emitJSInterop(Element e) {
+  JS.PropertyAccess _emitJSInterop(Element e) {
     var jsName = _getJSNameWithoutGlobal(e);
     if (jsName == null) return null;
     return _emitJSInteropForGlobal(jsName);
   }
 
-  JS.Expression _emitJSInteropForGlobal(String name) {
-    var access = _callHelper('global');
-    for (var part in name.split('.')) {
-      access = new JS.PropertyAccess(access, js.escapedString(part, "'"));
+  JS.PropertyAccess _emitJSInteropForGlobal(String name) {
+    var parts = name.split('.');
+    if (parts.isEmpty) parts = [''];
+    JS.PropertyAccess access;
+    for (var part in parts) {
+      access = new JS.PropertyAccess(
+          access ?? _callHelper('global'), js.escapedString(part, "'"));
     }
     return access;
   }
@@ -584,7 +589,7 @@
     // only run this on the outermost function, and not any closures.
     inferNullableTypes(node);
 
-    _moduleItems.add(node.accept<JS.Node>(this));
+    _moduleItems.add(node.accept(this) as JS.ModuleItem);
 
     _currentElement = savedElement;
   }
@@ -622,10 +627,9 @@
     for (var declaration in unit.declarations) {
       if (declaration is TopLevelVariableDeclaration) {
         inferNullableTypes(declaration);
-        var lazyFields = declaration.variables.variables;
-        if (isInternalSdk) {
-          lazyFields = _emitInternalSdkFields(lazyFields);
-        }
+        var variables = declaration.variables.variables;
+        var lazyFields =
+            isInternalSdk ? _emitInternalSdkFields(variables) : variables;
         if (lazyFields.isNotEmpty) {
           (fields ??= []).addAll(lazyFields);
         }
@@ -644,7 +648,7 @@
       }
 
       inferNullableTypes(declaration);
-      var item = declaration.accept(this);
+      var item = declaration.accept(this) as JS.ModuleItem;
       if (isInternalSdk && element is FunctionElement) {
         _internalSdkFunctions.add(item);
       } else {
@@ -847,7 +851,7 @@
 
   @override
   JS.Statement visitClassTypeAlias(ClassTypeAlias node) {
-    return _emitClassDeclaration(node, node.element, []);
+    return _emitClassDeclaration(node, node.element as ClassElement, []);
   }
 
   JS.Statement _emitJSType(Element e) {
@@ -1260,7 +1264,7 @@
       return;
     }
 
-    emitDeferredType(DartType t) {
+    JS.Expression emitDeferredType(DartType t) {
       if (t is InterfaceType && t.typeArguments.isNotEmpty) {
         _declareBeforeUse(t.element);
         return _emitGenericClassType(
@@ -1438,7 +1442,7 @@
         var field = decl.element as FieldElement;
         var name = getAnnotationName(field, isJSName) ?? field.name;
         // Generate getter
-        var fn = new JS.Fun([], js.statement('{ return this.#; }', [name]));
+        var fn = new JS.Fun([], js.block('{ return this.#; }', [name]));
         var method =
             new JS.Method(_declareMemberName(field.getter), fn, isGetter: true);
         jsMethods.add(method);
@@ -1446,8 +1450,7 @@
         // Generate setter
         if (!decl.isFinal) {
           var value = new JS.TemporaryId('value');
-          fn = new JS.Fun(
-              [value], js.statement('{ this.# = #; }', [name, value]));
+          fn = new JS.Fun([value], js.block('{ this.# = #; }', [name, value]));
           method = new JS.Method(_declareMemberName(field.setter), fn,
               isSetter: true);
           jsMethods.add(method);
@@ -1470,7 +1473,7 @@
       // Dart does not use ES6 constructors.
       // Add an error to catch any invalid usage.
       jsMethods.add(
-          new JS.Method(_propertyName('constructor'), js.call(r'''function() {
+          new JS.Method(_propertyName('constructor'), js.fun(r'''function() {
                   throw Error("use `new " + #.typeName(#.getReifiedType(this)) +
                       ".new(...)` to create a Dart object");
               }''', [_runtimeModule, _runtimeModule])));
@@ -1484,7 +1487,7 @@
       }
       jsMethods.add(new JS.Method(
           _declareMemberName(types.objectType.getMethod('toString')),
-          js.call('function() { return #[this.index]; }',
+          js.fun('function() { return #[this.index]; }',
               new JS.ObjectInitializer(mapMap, multiline: true))));
     }
 
@@ -1546,18 +1549,20 @@
     var covariantParams = getSuperclassCovariantParameters(node);
     if (covariantParams == null) return;
 
-    for (var member in covariantParams.map((p) => p.enclosingElement).toSet()) {
+    for (var member in covariantParams
+        .map((p) => p.enclosingElement as ExecutableElement)
+        .toSet()) {
       var name = _declareMemberName(member);
       if (member is PropertyAccessorElement) {
         var param =
             covariantParams.lookup(member.parameters[0]) as ParameterElement;
         methods.add(new JS.Method(
             name,
-            js.call('function(x) { return super.# = #._check(x); }',
+            js.fun('function(x) { return super.# = #._check(x); }',
                 [name, _emitType(param.type)]),
             isSetter: true));
         methods.add(new JS.Method(
-            name, js.call('function() { return super.#; }', [name]),
+            name, js.fun('function() { return super.#; }', [name]),
             isGetter: true));
       } else if (member is MethodElement) {
         var type = member.type;
@@ -1733,7 +1738,7 @@
       fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]);
     }
 
-    var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
+    var fn = new JS.Fun(fnArgs, js.block('{ return #; }', [fnBody]),
         typeParams: typeParams);
 
     return new JS.Method(
@@ -1760,7 +1765,7 @@
 
     var mocks = _classProperties.mockMembers;
     if (!mocks.containsKey(element.name)) {
-      var getter = js.call('function() { return this[#]; }', [virtualField]);
+      var getter = js.fun('function() { return this[#]; }', [virtualField]);
       result.add(new JS.Method(name, getter, isGetter: true)
         ..sourceInformation = _functionSpan(field.name));
     }
@@ -1782,7 +1787,7 @@
         jsCode = 'function(value) { #[#] = value; }';
       }
 
-      result.add(new JS.Method(name, js.call(jsCode, args), isSetter: true)
+      result.add(new JS.Method(name, js.fun(jsCode, args), isSetter: true)
         ..sourceInformation = _functionSpan(field.name));
     }
 
@@ -1806,7 +1811,7 @@
       if ((setter == null || setter.isAbstract) &&
           _classProperties.inheritedSetters.contains(field.name)) {
         // Generate a setter that forwards to super.
-        var fn = js.call('function(value) { super[#] = value; }', [name]);
+        var fn = js.fun('function(value) { super[#] = value; }', [name]);
         return new JS.Method(name, fn, isSetter: true);
       }
     } else {
@@ -1814,7 +1819,7 @@
       if ((getter == null || getter.isAbstract) &&
           _classProperties.inheritedGetters.contains(field.name)) {
         // Generate a getter that forwards to super.
-        var fn = js.call('function() { return super[#]; }', [name]);
+        var fn = js.fun('function() { return super[#]; }', [name]);
         return new JS.Method(name, fn, isGetter: true);
       }
     }
@@ -1857,8 +1862,12 @@
   JS.Expression _instantiateAnnotation(Annotation node) {
     var element = node.element;
     if (element is ConstructorElement) {
-      return _emitInstanceCreationExpression(element, element.returnType,
-          node.constructorName, node.arguments, true);
+      return _emitInstanceCreationExpression(
+          element,
+          element.returnType as InterfaceType,
+          node.constructorName,
+          node.arguments,
+          true);
     } else {
       return _visitExpression(node.name);
     }
@@ -2040,7 +2049,7 @@
         .map((f) => members[f] as VariableDeclaration)
         .toList();
     if (lazyStatics.isNotEmpty) {
-      body.add(_emitLazyFields(classElem, lazyStatics));
+      body.add(_emitLazyFields(_emitTopLevelName(classElem), lazyStatics));
     }
   }
 
@@ -2294,8 +2303,8 @@
       ..sourceInformation = _functionEnd(node);
   }
 
-  JS.Fun _finishConstructorFunction(
-      List<JS.Parameter> params, JS.Block body, isCallable) {
+  JS.Expression _finishConstructorFunction(
+      List<JS.Parameter> params, JS.Block body, bool isCallable) {
     // We consider a class callable if it inherits from anything with a `call`
     // method. As a result, we can know the callable JS function was created
     // at the first constructor that was hit.
@@ -2356,13 +2365,11 @@
 
     // Redirecting constructors: these are not allowed to have initializers,
     // and the redirecting ctor invocation runs before field initializers.
-    var redirectCall = node.initializers.firstWhere(
-        (i) => i is RedirectingConstructorInvocation,
-        orElse: () => null);
-
-    if (redirectCall != null) {
-      body.add(_emitRedirectingConstructor(redirectCall, className));
-      return new JS.Block(body);
+    for (var init in node.initializers) {
+      if (init is RedirectingConstructorInvocation) {
+        body.add(_emitRedirectingConstructor(init, className));
+        return new JS.Block(body);
+      }
     }
 
     // Generate field initializers.
@@ -2483,7 +2490,8 @@
       for (var init in ctor.initializers) {
         if (init is ConstructorFieldInitializer) {
           var field = init.fieldName;
-          body.add(emitFieldInit(field.staticElement, init.expression, field));
+          var element = field.staticElement as FieldElement;
+          body.add(emitFieldInit(element, init.expression, field));
         } else if (init is AssertInitializer) {
           body.add(_emitAssert(init.condition, init.message));
         }
@@ -2498,7 +2506,7 @@
     // like `field = value`, or via a `this.field` parameter).
     var fieldInit = <JS.Statement>[];
     for (var field in fieldDecls) {
-      var f = field.element;
+      var f = field.element as FieldElement;
       if (f.isStatic) continue;
       if (ctorFields != null &&
           ctorFields.contains(f) &&
@@ -2523,7 +2531,8 @@
     _emitCovarianceBoundsCheck(
         element.typeParameters, _classProperties?.covariantParameters, body);
     for (var param in parameters.parameters) {
-      var jsParam = _emitParameter(param.identifier.staticElement)
+      var element = param.identifier.staticElement as ParameterElement;
+      var jsParam = _emitParameter(element)
         ..sourceInformation = _nodeStart(param.identifier);
 
       if (param.kind != ParameterKind.REQUIRED) {
@@ -2602,13 +2611,13 @@
     String name =
         getAnnotationName(node.element, isJSAnnotation) ?? node.name.name;
     if (node.isGetter) {
-      return new JS.Fun([], js.statement('{ return this.#; }', [name]));
+      return new JS.Fun([], js.block('{ return this.#; }', [name]));
     } else if (node.isSetter) {
       var params = _emitFormalParameters(node.parameters?.parameters);
       return new JS.Fun(
-          params, js.statement('{ this.# = #; }', [name, params.last]));
+          params, js.block('{ this.# = #; }', [name, params.last]));
     } else {
-      return js.call(
+      return js.fun(
           'function (...args) { return this.#.apply(this, args); }', name);
     }
   }
@@ -2744,8 +2753,8 @@
     return !_declarationNodes.containsKey(type.element);
   }
 
-  JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type,
-      {topLevel: false}) {
+  JS.Expression _emitFunctionTagged(JS.Expression fn, FunctionType type,
+      {bool topLevel: false}) {
     var lazy = topLevel && !_typeIsLoaded(type);
     var typeRep = _emitFunctionType(type);
     return _callHelper(lazy ? 'lazyFn(#, () => #)' : 'fn(#, #)', [fn, typeRep]);
@@ -2764,7 +2773,7 @@
         node.parent is! MethodDeclaration);
     var fn = _emitArrowFunction(node);
     if (!_reifyFunctionType(node.element)) return fn;
-    return _emitFunctionTagged(fn, getStaticType(node),
+    return _emitFunctionTagged(fn, getStaticType(node) as FunctionType,
         topLevel: _executesAtTopLevel(node));
   }
 
@@ -2895,8 +2904,7 @@
 
     var returnType = _getExpectedReturnType(element);
 
-    emitGeneratorFn(Iterable<JS.Expression> jsParams,
-        [JS.TemporaryId asyncStar]) {
+    emitGeneratorFn(List<JS.Parameter> jsParams, [JS.TemporaryId asyncStar]) {
       var savedSuperAllowed = _superAllowed;
       var savedController = _asyncStarController;
       _superAllowed = false;
@@ -2907,17 +2915,16 @@
       // TODO(jmesserly): this will emit argument initializers (for default
       // values) inside the generator function body. Is that the best place?
       var jsBody = _emitFunctionBody(element, parameters, body);
-      JS.Expression gen = new JS.Fun(jsParams, jsBody,
+      var genFn = new JS.Fun(jsParams, jsBody,
           isGenerator: true, returnType: emitTypeRef(returnType));
 
+      // Name the function if possible, to get better stack traces.
       var name = element.name;
-      name = JS.friendlyNameForDartOperator[name] ?? name;
+      JS.Expression gen = genFn;
       if (name.isNotEmpty) {
-        // Name the function if possible, to get better stack traces.
-        //
-        // Also use a temporary ID so we don't conflict with the function
-        // itself, for recursive calls.
-        gen = new JS.NamedFunction(new JS.TemporaryId(name), gen);
+        gen = new JS.NamedFunction(
+            new JS.TemporaryId(JS.friendlyNameForDartOperator[name] ?? name),
+            genFn);
       }
       gen.sourceInformation = _functionEnd(body);
       if (JS.This.foundIn(gen)) gen = js.call('#.bind(this)', gen);
@@ -3048,7 +3055,7 @@
 
     // Directly emit constants.
     if (element is VariableElement && element.isStatic && element.isConst) {
-      var val = element.computeConstantValue();
+      var val = element.computeConstantValue() as DartObjectImpl;
       var result = _emitDartObject(val);
       if (result != null) {
         return result;
@@ -3364,7 +3371,7 @@
 
     if (type is ParameterizedType) {
       var args = type.typeArguments;
-      Iterable jsArgs = null;
+      List<JS.Expression> jsArgs;
       if (args.any((a) => !a.isDynamic)) {
         jsArgs = args.map((x) => _emitType(x, nameType: nameType)).toList();
       }
@@ -3378,7 +3385,7 @@
   }
 
   JS.Expression _emitGenericClassType(
-      InterfaceType t, List<JS.Expression> typeArgs) {
+      ParameterizedType t, List<JS.Expression> typeArgs) {
     var genericName = _emitTopLevelNameNoInterop(t.element, suffix: '\$');
     return js.call('#(#)', [genericName, typeArgs]);
   }
@@ -3529,7 +3536,8 @@
       return _emitSetLocal(element, right, node);
     }
 
-    if (element.enclosingElement is CompilationUnitElement) {
+    if (accessor is PropertyAccessorElement &&
+        element.enclosingElement is CompilationUnitElement) {
       // Top level library member.
       return _emitSetTopLevel(accessor, right);
     }
@@ -3701,7 +3709,10 @@
       // Use the full span for a cascade property so we can hover over `bar` in
       // `..bar()` and see the `bar` method.
       var cascade = _cascadeTarget;
-      var isCascade = cascade != null && _getTarget(node.parent) == cascade;
+      var parent = node.parent;
+      var isCascade = cascade != null &&
+          parent is Expression &&
+          _getTarget(parent) == cascade;
       result.sourceInformation = isCascade ? _nodeSpan(node) : _nodeEnd(node);
     }
     return result;
@@ -3711,7 +3722,7 @@
     var jsMethod = _superHelpers.putIfAbsent(member.name, () {
       if (member is PropertyAccessorElement) {
         var isSetter = member.isSetter;
-        var fn = js.call(
+        var fn = js.fun(
             isSetter
                 ? 'function(x) { super[#] = x; }'
                 : 'function() { return super[#]; }',
@@ -3730,7 +3741,7 @@
           params.add(new JS.Identifier(param.name));
         }
 
-        var fn = js.call(
+        var fn = js.fun(
             'function(#) { return super[#](#); }', [params, jsName, params]);
         var name = method.name;
         name = JS.friendlyNameForDartOperator[name] ?? name;
@@ -4019,8 +4030,8 @@
       if (arg is NamedExpression) {
         named.add(visitNamedExpression(arg));
       } else if (arg is MethodInvocation && isJsSpreadInvocation(arg)) {
-        args.add(new JS.RestParameter(
-            _visitExpression(arg.argumentList.arguments[0])));
+        args.add(
+            new JS.Spread(_visitExpression(arg.argumentList.arguments[0])));
       } else {
         args.add(_visitExpression(arg));
       }
@@ -4181,7 +4192,8 @@
           value = _emitArrowFunction(initializer);
           return new JS.Block([
             value.toVariableDeclaration(name),
-            _emitFunctionTagged(name, getStaticType(initializer),
+            _emitFunctionTagged(
+                    name, getStaticType(initializer) as FunctionType,
                     topLevel: _executesAtTopLevel(node))
                 .toStatement()
           ]);
@@ -4218,7 +4230,7 @@
 
   /// Emits a list of top-level field.
   void _emitTopLevelFields(List<VariableDeclaration> fields) {
-    _moduleItems.add(_emitLazyFields(currentLibrary, fields));
+    _moduleItems.add(_emitLazyFields(emitLibraryName(currentLibrary), fields));
   }
 
   /// Treat dart:_runtime fields as safe to eagerly evaluate.
@@ -4261,21 +4273,13 @@
   }
 
   JS.Statement _emitLazyFields(
-      Element target, List<VariableDeclaration> fields) {
+      JS.Expression objExpr, List<VariableDeclaration> fields) {
     var accessors = <JS.Method>[];
 
-    var objExpr = target is ClassElement
-        ? _emitTopLevelName(target)
-        : emitLibraryName(target);
-
     for (var node in fields) {
       var name = node.name.name;
       var element = node.element;
-      assert(element.getAncestor((e) => identical(e, target)) != null,
-          "target is $target but enclosing element is ${element.enclosingElement}");
-      var access = target is ClassElement
-          ? _emitStaticMemberName(name)
-          : (_emitJSInteropStaticMemberName(element) ?? _propertyName(name));
+      var access = _emitStaticMemberName(name, element);
       accessors.add(closureAnnotate(
           new JS.Method(
               access,
@@ -4325,7 +4329,7 @@
 
   JS.Expression _emitInstanceCreationExpression(
       ConstructorElement element,
-      DartType type,
+      InterfaceType type,
       SimpleIdentifier name,
       ArgumentList argumentList,
       bool isConst,
@@ -4467,8 +4471,13 @@
       return typeNode.type;
     }
 
-    return _emitInstanceCreationExpression(element, getType(constructor.type),
-        name, node.argumentList, node.isConst, constructor);
+    return _emitInstanceCreationExpression(
+        element,
+        getType(constructor.type) as InterfaceType,
+        name,
+        node.argumentList,
+        node.isConst,
+        constructor);
   }
 
   bool isPrimitiveType(DartType t) => _typeRep.isPrimitive(t);
@@ -4848,10 +4857,11 @@
 
     variable ??= new JS.TemporaryId(name);
 
-    id.staticElement = new TemporaryVariableElement.forNode(id, variable);
+    var idElement = new TemporaryVariableElement.forNode(id, variable);
+    id.staticElement = idElement;
     id.staticType = type;
     setIsDynamicInvoke(id, dynamicInvoke ?? type.isDynamic);
-    addTemporaryVariable(id.staticElement, nullable: nullable);
+    addTemporaryVariable(idElement, nullable: nullable);
     return id;
   }
 
@@ -5380,9 +5390,10 @@
     //
     // TODO(jmesserly): we may want a helper if these become common. For now the
     // full desugaring seems okay.
-    var streamIterator = rules.instantiateToBounds(_asyncStreamIterator);
+    var streamIterator =
+        rules.instantiateToBounds(_asyncStreamIterator) as InterfaceType;
     var createStreamIter = _emitInstanceCreationExpression(
-        (streamIterator.element as ClassElement).unnamedConstructor,
+        streamIterator.element.unnamedConstructor,
         streamIterator,
         null,
         ast.argumentList([node.iterable]),
@@ -5430,9 +5441,9 @@
   visitTryStatement(TryStatement node) {
     var savedSuperAllowed = _superAllowed;
     _superAllowed = false;
-    var finallyBlock = _visitStatement(node.finallyBlock);
+    var finallyBlock = _visitStatement(node.finallyBlock)?.toBlock();
     _superAllowed = savedSuperAllowed;
-    return new JS.Try(_visitStatement(node.body),
+    return new JS.Try(_visitStatement(node.body).toBlock(),
         _visitCatch(node.catchClauses), finallyBlock);
   }
 
@@ -5458,7 +5469,7 @@
       catchBody = _catchClauseGuard(clause, catchBody);
     }
 
-    var catchVarDecl = _emitSimpleIdentifier(_catchParameter);
+    var catchVarDecl = _emitSimpleIdentifier(_catchParameter) as JS.Identifier;
     if (isSingleCatch) {
       catchVarDecl..sourceInformation = _nodeStart(_catchParameter);
     }
@@ -5518,27 +5529,27 @@
   }
 
   @override
-  JS.Case visitSwitchCase(SwitchCase node) {
+  JS.SwitchCase visitSwitchCase(SwitchCase node) {
     var expr = _visitExpression(node.expression);
     var body = _visitStatementList(node.statements);
     if (node.labels.isNotEmpty) {
       body.insert(0, js.comment('Unimplemented case labels: ${node.labels}'));
     }
     // TODO(jmesserly): make sure we are statically checking fall through
-    return new JS.Case(expr, new JS.Block(body));
+    return new JS.SwitchCase(expr, new JS.Block(body));
   }
 
   @override
-  JS.Default visitSwitchDefault(SwitchDefault node) {
+  JS.SwitchCase visitSwitchDefault(SwitchDefault node) {
     var body = _visitStatementList(node.statements);
     if (node.labels.isNotEmpty) {
       body.insert(0, js.comment('Unimplemented case labels: ${node.labels}'));
     }
     // TODO(jmesserly): make sure we are statically checking fall through
-    return new JS.Default(new JS.Block(body));
+    return new JS.SwitchCase.defaultCase(new JS.Block(body));
   }
 
-  JS.SwitchClause _emitSwitchMember(SwitchMember node) {
+  JS.SwitchCase _emitSwitchMember(SwitchMember node) {
     if (node is SwitchCase) {
       return visitSwitchCase(node);
     } else {
@@ -5643,14 +5654,15 @@
       return new JS.ArrayInitializer(entries);
     }
 
+    var type = node.staticType as InterfaceType;
     if (!node.isConst) {
-      var mapType = _emitMapImplType(node.staticType);
+      var mapType = _emitMapImplType(type);
       if (node.entries.isEmpty) {
         return js.call('new #.new()', [mapType]);
       }
       return js.call('new #.from(#)', [mapType, emitEntries()]);
     }
-    var typeArgs = (node.staticType as InterfaceType).typeArguments;
+    var typeArgs = type.typeArguments;
     return _cacheConst(() => _callHelper('constMap(#, #, #)',
         [_emitType(typeArgs[0]), _emitType(typeArgs[1]), emitEntries()]));
   }
@@ -5676,7 +5688,7 @@
       js.escapedString(node.value, node.isSingleQuoted ? "'" : '"');
 
   @override
-  JS.Binary visitAdjacentStrings(AdjacentStrings node) {
+  JS.Expression visitAdjacentStrings(AdjacentStrings node) {
     var nodes = node.strings;
     if (nodes == null || nodes.isEmpty) return null;
     return new JS.Expression.binary(_visitExpressionList(nodes), '+');
@@ -6002,7 +6014,7 @@
             '\$${JS.friendlyNameForDartOperator[name] ?? name}'));
   }
 
-  var _forwardingCache = new HashMap<Element, Map<String, ExecutableElement>>();
+  var _forwardingCache = new HashMap<Element, Map<String, Element>>();
 
   Element _lookupForwardedMember(ClassElement element, String name) {
     // We only care about public methods.
@@ -6016,13 +6028,13 @@
     var member = element.lookUpMethod(name, library) ??
         element.lookUpGetter(name, library) ??
         element.lookUpSetter(name, library);
-    member = (member != null &&
+    var classMember = (member != null &&
             member.isSynthetic &&
             member is PropertyAccessorElement)
         ? member.variable
         : member;
-    map[name] = member;
-    return member;
+    map[name] = classMember;
+    return classMember;
   }
 
   /// Don't symbolize native members that just forward to the underlying
@@ -6039,8 +6051,8 @@
     if (type == null || type.isDynamic || type.isObject) {
       return isObjectMember(name);
     } else if (type is InterfaceType) {
-      type = getImplementationType(type) ?? type;
-      var element = type.element;
+      var interfaceType = getImplementationType(type) ?? type;
+      var element = interfaceType.element;
       if (_extensionTypes.isNativeClass(element)) {
         var member = _lookupForwardedMember(element, name);
 
@@ -6178,7 +6190,7 @@
   JS.Expression _throwUnsafe(String message) => _callHelper(
       'throw(Error(#))', js.escapedString("compile error: $message"));
 
-  _unreachable(AstNode node) {
+  JS.Node _unreachable(AstNode node) {
     throw new UnsupportedError(
         'tried to generate an unreachable node: `$node`');
   }
diff --git a/pkg/dev_compiler/lib/src/analyzer/command.dart b/pkg/dev_compiler/lib/src/analyzer/command.dart
index b12e5f8..dd028f0 100644
--- a/pkg/dev_compiler/lib/src/analyzer/command.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/command.dart
@@ -42,13 +42,13 @@
     return 64;
   }
 
-  _verbose = argResults['verbose'];
-  if (argResults['help'] || args.isEmpty) {
+  _verbose = argResults['verbose'] as bool;
+  if (argResults['help'] as bool || args.isEmpty) {
     printFn(_usageMessage);
     return 0;
   }
 
-  if (argResults['version']) {
+  if (argResults['version'] as bool) {
     printFn('$_binaryName version ${_getVersion()}');
     return 0;
   }
diff --git a/pkg/dev_compiler/lib/src/analyzer/context.dart b/pkg/dev_compiler/lib/src/analyzer/context.dart
index b3b855c..5ce463c 100644
--- a/pkg/dev_compiler/lib/src/analyzer/context.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/context.dart
@@ -81,7 +81,7 @@
     (contextBuilderOptions.defaultOptions as AnalysisOptionsImpl).previewDart2 =
         true;
 
-    var dartSdkPath = args['dart-sdk'] ?? getSdkDir().path;
+    var dartSdkPath = args['dart-sdk'] as String ?? getSdkDir().path;
 
     dartSdkSummaryPath ??= contextBuilderOptions.dartSdkSummaryPath;
     dartSdkSummaryPath ??=
@@ -94,7 +94,8 @@
         contextBuilderOptions: contextBuilderOptions,
         summaryPaths: summaryPaths ?? args['summary'] as List<String>,
         dartSdkPath: dartSdkPath,
-        customUrlMappings: _parseUrlMappings(args['url-mapping']));
+        customUrlMappings:
+            _parseUrlMappings(args['url-mapping'] as List<String>));
   }
 
   static void addArguments(ArgParser parser, {bool hide: true}) {
@@ -109,7 +110,7 @@
           hide: hide);
   }
 
-  static Map<String, String> _parseUrlMappings(Iterable argument) {
+  static Map<String, String> _parseUrlMappings(List<String> argument) {
     var mappings = <String, String>{};
     for (var mapping in argument) {
       var splitMapping = mapping.split(',');
diff --git a/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart b/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
index b40e3ff..23b9d8f 100644
--- a/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
@@ -64,7 +64,7 @@
 DartObject findAnnotation(Element element, bool test(DartObjectImpl value)) {
   for (var metadata in element.metadata) {
     var value = metadata.computeConstantValue();
-    if (value != null && test(value)) return value;
+    if (value is DartObjectImpl && test(value)) return value;
   }
   return null;
 }
diff --git a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
index d0286ab..6c7f005 100644
--- a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
@@ -290,17 +290,18 @@
       this.summaryOutPath});
 
   CompilerOptions.fromArguments(ArgResults args)
-      : sourceMap = args['source-map'],
-        sourceMapComment = args['source-map-comment'],
-        inlineSourceMap = args['inline-source-map'],
-        summarizeApi = args['summarize'],
-        summaryExtension = args['summary-extension'],
-        unsafeForceCompile = args['unsafe-force-compile'],
-        replCompile = args['repl-compile'],
-        emitMetadata = args['emit-metadata'],
-        closure = args['closure-experimental'],
-        bazelMapping = _parseBazelMappings(args['bazel-mapping']),
-        summaryOutPath = args['summary-out'];
+      : sourceMap = args['source-map'] as bool,
+        sourceMapComment = args['source-map-comment'] as bool,
+        inlineSourceMap = args['inline-source-map'] as bool,
+        summarizeApi = args['summarize'] as bool,
+        summaryExtension = args['summary-extension'] as String,
+        unsafeForceCompile = args['unsafe-force-compile'] as bool,
+        replCompile = args['repl-compile'] as bool,
+        emitMetadata = args['emit-metadata'] as bool,
+        closure = args['closure-experimental'] as bool,
+        bazelMapping =
+            _parseBazelMappings(args['bazel-mapping'] as List<String>),
+        summaryOutPath = args['summary-out'] as String;
 
   static void addArguments(ArgParser parser, {bool hide: true}) {
     parser
@@ -348,7 +349,7 @@
           help: 'location to write the summary file', hide: hide);
   }
 
-  static Map<String, String> _parseBazelMappings(Iterable argument) {
+  static Map<String, String> _parseBazelMappings(List<String> argument) {
     var mappings = <String, String>{};
     for (var mapping in argument) {
       var splitMapping = mapping.split(',');
@@ -543,7 +544,7 @@
   // Convert to a local file path if it's not.
   sourceMapPath = path.fromUri(_sourceToUri(sourceMapPath));
   var sourceMapDir = path.dirname(path.absolute(sourceMapPath));
-  var list = new List.from(map['sources']);
+  var list = (map['sources'] as List).toList();
   map['sources'] = list;
 
   String makeRelative(String sourcePath) {
@@ -565,9 +566,9 @@
   }
 
   for (int i = 0; i < list.length; i++) {
-    list[i] = makeRelative(list[i]);
+    list[i] = makeRelative(list[i] as String);
   }
-  map['file'] = makeRelative(map['file']);
+  map['file'] = makeRelative(map['file'] as String);
   return map;
 }
 
diff --git a/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart b/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
index c2afbbd..5006b76 100644
--- a/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
@@ -356,14 +356,14 @@
   @override
   visitCatchClause(CatchClause node) {
     var e = node.exceptionParameter?.staticElement;
-    if (e != null) {
+    if (e is LocalVariableElement) {
       _locals.add(e);
       // TODO(jmesserly): we allow throwing of `null`, for better or worse.
       _nullableLocals.add(e);
     }
 
     e = node.stackTraceParameter?.staticElement;
-    if (e != null) _locals.add(e);
+    if (e is LocalVariableElement) _locals.add(e);
 
     super.visitCatchClause(node);
   }
diff --git a/pkg/dev_compiler/lib/src/analyzer/property_model.dart b/pkg/dev_compiler/lib/src/analyzer/property_model.dart
index 34b2330..636ca24 100644
--- a/pkg/dev_compiler/lib/src/analyzer/property_model.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/property_model.dart
@@ -82,12 +82,14 @@
     // ClassElement can only look up inherited members with an O(N) scan through
     // the class, so we build up a mapping of all fields in the library ahead of
     // time.
+    Map<String, FieldElement> getInstanceFieldMap(ClassElement c) {
+      var instanceFields = c.fields.where((f) => !f.isStatic);
+      return new HashMap.fromIterables(
+          instanceFields.map((f) => f.name), instanceFields);
+    }
+
     var allFields =
-        new HashMap<ClassElement, HashMap<String, FieldElement>>.fromIterable(
-            allTypes,
-            value: (t) => new HashMap.fromIterable(
-                t.fields.where((f) => !f.isStatic),
-                key: (f) => f.name));
+        new HashMap.fromIterables(allTypes, allTypes.map(getInstanceFieldMap));
 
     for (var type in allTypes) {
       Set<ClassElement> supertypes = null;
diff --git a/pkg/dev_compiler/lib/src/analyzer/reify_coercions.dart b/pkg/dev_compiler/lib/src/analyzer/reify_coercions.dart
index 4192eb5..d2604bc 100644
--- a/pkg/dev_compiler/lib/src/analyzer/reify_coercions.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/reify_coercions.dart
@@ -126,7 +126,7 @@
 
 class _TreeCloner extends analyzer.AstCloner {
   void _cloneProperties(AstNode clone, AstNode node) {
-    if (clone is Expression) {
+    if (clone is Expression && node is Expression) {
       ast_properties.setImplicitCast(
           clone, ast_properties.getImplicitCast(node));
       ast_properties.setImplicitOperationCast(
@@ -134,7 +134,7 @@
       ast_properties.setIsDynamicInvoke(
           clone, ast_properties.isDynamicInvoke(node));
     }
-    if (clone is ClassDeclaration || clone is ClassTypeAlias) {
+    if (clone is Declaration && node is Declaration) {
       ast_properties.setClassCovariantParameters(
           clone, ast_properties.getClassCovariantParameters(node));
       ast_properties.setSuperclassCovariantParameters(
diff --git a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
index 7ec0f6e..8675657 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
@@ -82,9 +82,11 @@
     return new MetaLet(variables, exprs);
   }
 
-  Statement toVariableDeclaration(Identifier name) {
-    var simple = _simplifyAssignment(name, isDeclaration: true);
-    if (simple != null) return simple.toStatement();
+  Statement toVariableDeclaration(VariableBinding name) {
+    if (name is Identifier) {
+      var simple = _simplifyAssignment(name, isDeclaration: true);
+      if (simple != null) return simple.toStatement();
+    }
 
     // We can still optimize something like:
     //
@@ -138,13 +140,14 @@
     return _finishStatement(statements);
   }
 
-  accept(NodeVisitor visitor) {
+  T accept<T>(NodeVisitor<T> visitor) {
     // TODO(jmesserly): we special case vistors from js_ast.Template, because it
     // doesn't know about MetaLet. Should we integrate directly?
-    if (visitor is InstantiatorGeneratorVisitor) {
-      return _templateVisitMetaLet(visitor);
-    } else if (visitor is InterpolatedNodeAnalysis) {
-      return visitor.visitNode(this);
+    NodeVisitor v = visitor;
+    if (v is InstantiatorGeneratorVisitor) {
+      return _templateVisitMetaLet(v) as T;
+    } else if (v is InterpolatedNodeAnalysis) {
+      return v.visitNode(this) as T;
     } else {
       return toExpression().accept(visitor);
     }
@@ -171,13 +174,13 @@
     var bodyInstantiators = body.map(visitor.visit);
 
     return (args) => new MetaLet(
-        new Map.fromIterables(
-            variables.keys, valueInstantiators.map((i) => i(args))),
+        new Map.fromIterables(variables.keys,
+            valueInstantiators.map((i) => i(args) as Expression)),
         bodyInstantiators.map((i) => i(args) as Expression).toList(),
         statelessResult: statelessResult);
   }
 
-  Expression _toInvokedFunction(Statement block) {
+  Expression _toInvokedFunction(Block block) {
     var finder = new _YieldFinder();
     block.accept(finder);
     if (!finder.hasYield) {
@@ -276,7 +279,8 @@
 }
 
 /// Similar to [Template.instantiate] but works with free variables.
-Node _substitute(Node tree, Map<MetaLetVariable, Expression> substitutions) {
+T _substitute<T extends Node>(
+    T tree, Map<MetaLetVariable, Expression> substitutions) {
   var generator = new InstantiatorGeneratorVisitor(/*forceCopy:*/ false);
   var instantiator = generator.compile(tree);
   var nodes = new List<MetaLetVariable>.from(generator
@@ -286,7 +290,7 @@
 
   return instantiator(new Map.fromIterable(nodes,
       key: (v) => (v as MetaLetVariable).nameOrPosition,
-      value: (v) => substitutions[v] ?? v));
+      value: (v) => substitutions[v] ?? v)) as T;
 }
 
 /// A temporary variable used in a [MetaLet].
diff --git a/pkg/dev_compiler/lib/src/compiler/js_names.dart b/pkg/dev_compiler/lib/src/compiler/js_names.dart
index 8db3036..0310d63 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_names.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_names.dart
@@ -33,10 +33,11 @@
   }
 
   /// Helper to create an [Identifier] from something that starts as a property.
-  static identifier(LiteralString propertyName) =>
+  static Identifier identifier(LiteralString propertyName) =>
       new Identifier(propertyName.valueWithoutQuotes);
 
   void setQualified(bool qualified) {
+    var name = this.name;
     if (!qualified && name is LiteralString) {
       _expr = identifier(name);
     }
@@ -44,7 +45,7 @@
 
   int get precedenceLevel => _expr.precedenceLevel;
 
-  accept(NodeVisitor visitor) => _expr.accept(visitor);
+  T accept<T>(NodeVisitor<T> visitor) => _expr.accept(visitor);
 
   void visitChildren(NodeVisitor visitor) => _expr.visitChildren(visitor);
 }
@@ -194,7 +195,7 @@
       name = id.name;
       valid = !invalidVariableName(name);
     } else {
-      name = id;
+      name = id as String;
       valid = false;
     }
 
diff --git a/pkg/dev_compiler/lib/src/compiler/js_utils.dart b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
index d557f79..1710810 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_utils.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
@@ -11,10 +11,13 @@
     var stat = fn.body.statements.single;
     if (stat is Return && stat.value is Call) {
       Call call = stat.value;
-      if (call.target is ArrowFun && call.arguments.isEmpty) {
-        ArrowFun innerFun = call.target;
-        if (innerFun.params.isEmpty) {
-          return new Fun(fn.params, innerFun.body,
+      var innerFun = call.target;
+      if (innerFun is ArrowFun &&
+          call.arguments.isEmpty &&
+          innerFun.params.isEmpty) {
+        var body = innerFun.body;
+        if (body is Block) {
+          return new Fun(fn.params, body,
               typeParams: fn.typeParams, returnType: fn.returnType);
         }
       }
diff --git a/pkg/dev_compiler/lib/src/compiler/module_builder.dart b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
index 6546995..53f6735 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_builder.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
@@ -134,7 +134,10 @@
 
   visitExportDeclaration(ExportDeclaration node) {
     exports.add(node);
-    statements.add(node.exported.toStatement());
+    var exported = node.exported;
+    if (exported is! ExportClause) {
+      statements.add(exported.toStatement());
+    }
   }
 
   visitStatement(Statement node) {
@@ -193,12 +196,12 @@
       }
     }
 
-    var resultModule =
-        js.call("function(#) { 'use strict'; #; }", [parameters, statements]);
     var functionName =
         'load__' + pathToJSIdentifier(module.name.replaceAll('.', '_'));
-    resultModule =
-        new NamedFunction(new Identifier(functionName), resultModule, true);
+    var resultModule = new NamedFunction(
+        new Identifier(functionName),
+        js.fun("function(#) { 'use strict'; #; }", [parameters, statements]),
+        true);
 
     var moduleDef = js.statement("dart_library.library(#, #, #, #)", [
       js.string(module.name, "'"),
diff --git a/pkg/dev_compiler/lib/src/compiler/type_utilities.dart b/pkg/dev_compiler/lib/src/compiler/type_utilities.dart
index f497fc4..a5dfc6f 100644
--- a/pkg/dev_compiler/lib/src/compiler/type_utilities.dart
+++ b/pkg/dev_compiler/lib/src/compiler/type_utilities.dart
@@ -116,7 +116,7 @@
 
   /// Heuristically choose a good name for the cache and generator
   /// variables.
-  JS.Identifier chooseTypeName(DartType type) {
+  JS.TemporaryId chooseTypeName(DartType type) {
     return new JS.TemporaryId(_typeString(type));
   }
 }
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index 1101b7d..16fea13 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -202,25 +202,29 @@
    * a list of [Node]s, which will be interpolated into the source at the '#'
    * signs.
    */
-  Expression call(String source, [var arguments]) {
+  Expression call(String source, [arguments]) {
     Template template = _findExpressionTemplate(source);
-    if (arguments == null) return template.instantiate([]);
+    if (arguments == null) return template.instantiate([]) as Expression;
     // We allow a single argument to be given directly.
     if (arguments is! List && arguments is! Map) arguments = [arguments];
-    return template.instantiate(arguments);
+    return template.instantiate(arguments) as Expression;
   }
 
   /**
    * Parses a JavaScript Statement, otherwise just like [call].
    */
-  Statement statement(String source, [var arguments]) {
+  Statement statement(String source, [arguments]) {
     Template template = _findStatementTemplate(source);
-    if (arguments == null) return template.instantiate([]);
+    if (arguments == null) return template.instantiate([]) as Statement;
     // We allow a single argument to be given directly.
     if (arguments is! List && arguments is! Map) arguments = [arguments];
-    return template.instantiate(arguments);
+    return template.instantiate(arguments) as Statement;
   }
 
+  Block block(String source, [arguments]) =>
+      statement(source, arguments) as Block;
+  Fun fun(String source, [arguments]) => call(source, arguments) as Fun;
+
   /**
    * Parses JavaScript written in the `JS` foreign instruction.
    *
@@ -789,7 +793,7 @@
     return false;
   }
 
-  void error(message) {
+  void error(String message) {
     throw new MiniJsParserError(this, message);
   }
 
@@ -970,7 +974,7 @@
     return parseFun();
   }
 
-  Expression parseFun() {
+  Fun parseFun() {
     List<Parameter> params = <Parameter>[];
 
     expectCategory(LPAREN);
@@ -1222,7 +1226,7 @@
     var initialization = <VariableInitialization>[];
 
     do {
-      var declarator;
+      VariableBinding declarator;
       if (firstIdentifier != null) {
         declarator = new Identifier(firstIdentifier);
         firstIdentifier = null;
@@ -1269,17 +1273,18 @@
   ArrayBindingPattern parseArrayBindingPattern() {
     var variables = <DestructuredVariable>[];
     do {
-      var name;
-      var structure;
-      var defaultValue;
+      Identifier name;
+      BindingPattern structure;
+      Expression defaultValue;
 
       var declarator = parseVariableBinding();
-      if (declarator is Identifier)
+      if (declarator is Identifier) {
         name = declarator;
-      else if (declarator is BindingPattern)
+      } else if (declarator is BindingPattern) {
         structure = declarator;
-      else
+      } else {
         error("Unexpected LHS: $declarator");
+      }
 
       if (acceptString("=")) {
         defaultValue = parseExpression();
@@ -1296,8 +1301,8 @@
     var variables = <DestructuredVariable>[];
     do {
       var name = parseIdentifier();
-      var structure;
-      var defaultValue;
+      BindingPattern structure;
+      Expression defaultValue;
 
       if (acceptCategory(COLON)) {
         structure = parseBindingPattern();
@@ -1454,7 +1459,7 @@
     return new Throw(expression);
   }
 
-  Statement parseBreakOrContinue(constructor) {
+  Statement parseBreakOrContinue(Statement Function(String) constructor) {
     var identifier = lastToken;
     if (!skippedNewline && acceptCategory(ALPHA)) {
       expectSemicolon();
@@ -1546,7 +1551,7 @@
   Statement parseFunctionDeclaration() {
     String name = lastToken;
     expectCategory(ALPHA);
-    Expression fun = parseFun();
+    var fun = parseFun();
     return new FunctionDeclaration(new Identifier(name), fun);
   }
 
@@ -1565,7 +1570,7 @@
     return new Try(body, catchPart, finallyPart);
   }
 
-  SwitchClause parseSwitchClause() {
+  SwitchCase parseSwitchClause() {
     Expression expression = null;
     if (acceptString('case')) {
       expression = parseExpression();
@@ -1582,9 +1587,7 @@
         lastToken != 'default') {
       statements.add(parseStatement());
     }
-    return expression == null
-        ? new Default(new Block(statements))
-        : new Case(expression, new Block(statements));
+    return new SwitchCase(expression, new Block(statements));
   }
 
   Statement parseWhile() {
@@ -1611,7 +1614,7 @@
     Expression key = parseExpression();
     expectCategory(RPAREN);
     expectCategory(LBRACE);
-    List<SwitchClause> clauses = new List<SwitchClause>();
+    var clauses = new List<SwitchCase>();
     while (lastCategory != RBRACE) {
       clauses.add(parseSwitchClause());
     }
@@ -1638,7 +1641,7 @@
     expectCategory(LBRACE);
     var methods = new List<Method>();
     while (lastCategory != RBRACE) {
-      methods.add(parseMethodOrProperty(onlyMethods: true));
+      methods.add(parseMethodOrProperty(onlyMethods: true) as Method);
     }
     expectCategory(RBRACE);
     return new ClassExpression(name, heritage, methods);
diff --git a/pkg/dev_compiler/lib/src/js_ast/js_types.dart b/pkg/dev_compiler/lib/src/js_ast/js_types.dart
index a3d1971..6217798 100644
--- a/pkg/dev_compiler/lib/src/js_ast/js_types.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/js_types.dart
@@ -84,7 +84,7 @@
   AnyTypeRef._() : super();
 
   factory AnyTypeRef() => _any;
-  accept(NodeVisitor visitor) => visitor.visitAnyTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitAnyTypeRef(this);
   void visitChildren(NodeVisitor visitor) {}
   _clone() => new AnyTypeRef();
 }
@@ -98,7 +98,7 @@
   UnknownTypeRef._() : super();
 
   factory UnknownTypeRef() => _unknown;
-  accept(NodeVisitor visitor) => visitor.visitUnknownTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitUnknownTypeRef(this);
   void visitChildren(NodeVisitor visitor) {}
   _clone() => new UnknownTypeRef();
 }
@@ -107,7 +107,7 @@
   final List<Identifier> path;
   QualifiedTypeRef(this.path);
 
-  accept(NodeVisitor visitor) => visitor.visitQualifiedTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitQualifiedTypeRef(this);
   void visitChildren(NodeVisitor visitor) =>
       path.forEach((p) => p.accept(visitor));
   _clone() => new QualifiedTypeRef(path);
@@ -116,7 +116,7 @@
 class ArrayTypeRef extends TypeRef {
   final TypeRef elementType;
   ArrayTypeRef(this.elementType);
-  accept(NodeVisitor visitor) => visitor.visitArrayTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayTypeRef(this);
   void visitChildren(NodeVisitor visitor) {
     elementType.accept(visitor);
   }
@@ -129,7 +129,7 @@
   final List<TypeRef> typeArgs;
   GenericTypeRef(this.rawType, this.typeArgs);
 
-  accept(NodeVisitor visitor) => visitor.visitGenericTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitGenericTypeRef(this);
   void visitChildren(NodeVisitor visitor) {
     rawType.accept(visitor);
     typeArgs.forEach((p) => p.accept(visitor));
@@ -142,7 +142,7 @@
   final List<TypeRef> types;
   UnionTypeRef(this.types);
 
-  accept(NodeVisitor visitor) => visitor.visitUnionTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitUnionTypeRef(this);
   void visitChildren(NodeVisitor visitor) {
     types.forEach((p) => p.accept(visitor));
   }
@@ -162,7 +162,7 @@
   final TypeRef type;
   OptionalTypeRef(this.type);
 
-  accept(NodeVisitor visitor) => visitor.visitOptionalTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitOptionalTypeRef(this);
   void visitChildren(NodeVisitor visitor) {
     type.accept(visitor);
   }
@@ -177,7 +177,7 @@
   final Map<Identifier, TypeRef> types;
   RecordTypeRef(this.types);
 
-  accept(NodeVisitor visitor) => visitor.visitRecordTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitRecordTypeRef(this);
   void visitChildren(NodeVisitor visitor) {
     types.values.forEach((p) => p.accept(visitor));
   }
@@ -190,7 +190,7 @@
   final Map<Identifier, TypeRef> paramTypes;
   FunctionTypeRef(this.returnType, this.paramTypes);
 
-  accept(NodeVisitor visitor) => visitor.visitFunctionTypeRef(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitFunctionTypeRef(this);
   void visitChildren(NodeVisitor visitor) {
     returnType.accept(visitor);
     paramTypes.forEach((n, t) {
diff --git a/pkg/dev_compiler/lib/src/js_ast/nodes.dart b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
index 01649b7..cbbfa9b 100644
--- a/pkg/dev_compiler/lib/src/js_ast/nodes.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
@@ -23,8 +23,7 @@
   T visitTry(Try node);
   T visitCatch(Catch node);
   T visitSwitch(Switch node);
-  T visitCase(Case node);
-  T visitDefault(Default node);
+  T visitSwitchCase(SwitchCase node);
   T visitFunctionDeclaration(FunctionDeclaration node);
   T visitLabeledStatement(LabeledStatement node);
   T visitLiteralStatement(LiteralStatement node);
@@ -139,8 +138,7 @@
   T visitLiteralStatement(LiteralStatement node) => visitStatement(node);
 
   T visitCatch(Catch node) => visitNode(node);
-  T visitCase(Case node) => visitNode(node);
-  T visitDefault(Default node) => visitNode(node);
+  T visitSwitchCase(SwitchCase node) => visitNode(node);
 
   T visitExpression(Expression node) => visitNode(node);
 
@@ -148,13 +146,8 @@
   T visitVariableDeclarationList(VariableDeclarationList node) =>
       visitExpression(node);
   T visitAssignment(Assignment node) => visitExpression(node);
-  T visitVariableInitialization(VariableInitialization node) {
-    if (node.value != null) {
-      return visitAssignment(node);
-    } else {
-      return visitExpression(node);
-    }
-  }
+  T visitVariableInitialization(VariableInitialization node) =>
+      visitExpression(node);
 
   T visitConditional(Conditional node) => visitExpression(node);
   T visitNew(New node) => visitExpression(node);
@@ -255,7 +248,7 @@
   /// Closure annotation of this node.
   ClosureAnnotation closureAnnotation;
 
-  accept(NodeVisitor visitor);
+  T accept<T>(NodeVisitor<T> visitor);
   void visitChildren(NodeVisitor visitor);
 
   // Shallow clone of node.  Does not clone positions since the only use of this
@@ -311,7 +304,7 @@
 
   Program(this.body, {this.scriptTag, this.name});
 
-  accept(NodeVisitor visitor) => visitor.visitProgram(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitProgram(this);
   void visitChildren(NodeVisitor visitor) {
     for (ModuleItem statement in body) statement.accept(visitor);
   }
@@ -369,14 +362,14 @@
       !isScope && statements.any((s) => s.shadows(names));
 
   @override
-  Statement toScopedBlock(Set<String> names) {
+  Block toScopedBlock(Set<String> names) {
     var scoped = statements.any((s) => s.shadows(names));
     if (scoped == isScope) return this;
     return new Block(statements, isScope: scoped)
       ..sourceInformation = sourceInformation;
   }
 
-  accept(NodeVisitor visitor) => visitor.visitBlock(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitBlock(this);
   void visitChildren(NodeVisitor visitor) {
     for (Statement statement in statements) statement.accept(visitor);
   }
@@ -394,7 +387,7 @@
     return expression is VariableDeclarationList && expression.shadows(names);
   }
 
-  accept(NodeVisitor visitor) => visitor.visitExpressionStatement(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitExpressionStatement(this);
   void visitChildren(NodeVisitor visitor) {
     expression.accept(visitor);
   }
@@ -405,22 +398,22 @@
 class EmptyStatement extends Statement {
   EmptyStatement();
 
-  accept(NodeVisitor visitor) => visitor.visitEmptyStatement(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitEmptyStatement(this);
   void visitChildren(NodeVisitor visitor) {}
   EmptyStatement _clone() => new EmptyStatement();
 }
 
 class If extends Statement {
   final Expression condition;
-  final Node then;
-  final Node otherwise;
+  final Statement then;
+  final Statement otherwise;
 
   If(this.condition, this.then, this.otherwise);
   If.noElse(this.condition, this.then) : this.otherwise = null;
 
   bool get hasElse => otherwise != null;
 
-  accept(NodeVisitor visitor) => visitor.visitIf(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitIf(this);
 
   void visitChildren(NodeVisitor visitor) {
     condition.accept(visitor);
@@ -443,7 +436,7 @@
 
   For(this.init, this.condition, this.update, Statement body) : super(body);
 
-  accept(NodeVisitor visitor) => visitor.visitFor(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitFor(this);
 
   void visitChildren(NodeVisitor visitor) {
     if (init != null) init.accept(visitor);
@@ -463,7 +456,7 @@
 
   ForIn(this.leftHandSide, this.object, Statement body) : super(body);
 
-  accept(NodeVisitor visitor) => visitor.visitForIn(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitForIn(this);
 
   void visitChildren(NodeVisitor visitor) {
     leftHandSide.accept(visitor);
@@ -482,7 +475,7 @@
 
   ForOf(this.leftHandSide, this.iterable, Statement body) : super(body);
 
-  accept(NodeVisitor visitor) => visitor.visitForOf(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitForOf(this);
 
   void visitChildren(NodeVisitor visitor) {
     leftHandSide.accept(visitor);
@@ -494,11 +487,11 @@
 }
 
 class While extends Loop {
-  final Node condition;
+  final Expression condition;
 
   While(this.condition, Statement body) : super(body);
 
-  accept(NodeVisitor visitor) => visitor.visitWhile(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitWhile(this);
 
   void visitChildren(NodeVisitor visitor) {
     condition.accept(visitor);
@@ -513,7 +506,7 @@
 
   Do(Statement body, this.condition) : super(body);
 
-  accept(NodeVisitor visitor) => visitor.visitDo(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitDo(this);
 
   void visitChildren(NodeVisitor visitor) {
     body.accept(visitor);
@@ -528,7 +521,7 @@
 
   Continue(this.targetLabel);
 
-  accept(NodeVisitor visitor) => visitor.visitContinue(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitContinue(this);
   void visitChildren(NodeVisitor visitor) {}
 
   Continue _clone() => new Continue(targetLabel);
@@ -539,7 +532,7 @@
 
   Break(this.targetLabel);
 
-  accept(NodeVisitor visitor) => visitor.visitBreak(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitBreak(this);
   void visitChildren(NodeVisitor visitor) {}
 
   Break _clone() => new Break(targetLabel);
@@ -552,7 +545,7 @@
 
   Statement toReturn() => this;
 
-  accept(NodeVisitor visitor) => visitor.visitReturn(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitReturn(this);
 
   void visitChildren(NodeVisitor visitor) {
     if (value != null) value.accept(visitor);
@@ -585,7 +578,7 @@
 
   Throw(this.expression);
 
-  accept(NodeVisitor visitor) => visitor.visitThrow(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitThrow(this);
 
   void visitChildren(NodeVisitor visitor) {
     expression.accept(visitor);
@@ -603,7 +596,7 @@
     assert(catchPart != null || finallyPart != null);
   }
 
-  accept(NodeVisitor visitor) => visitor.visitTry(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitTry(this);
 
   void visitChildren(NodeVisitor visitor) {
     body.accept(visitor);
@@ -620,7 +613,7 @@
 
   Catch(this.declaration, this.body);
 
-  accept(NodeVisitor visitor) => visitor.visitCatch(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitCatch(this);
 
   void visitChildren(NodeVisitor visitor) {
     declaration.accept(visitor);
@@ -632,51 +625,37 @@
 
 class Switch extends Statement {
   final Expression key;
-  final List<SwitchClause> cases;
+  final List<SwitchCase> cases;
 
   Switch(this.key, this.cases);
 
-  accept(NodeVisitor visitor) => visitor.visitSwitch(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitSwitch(this);
 
   void visitChildren(NodeVisitor visitor) {
     key.accept(visitor);
-    for (SwitchClause clause in cases) clause.accept(visitor);
+    for (var clause in cases) clause.accept(visitor);
   }
 
   Switch _clone() => new Switch(key, cases);
 }
 
-abstract class SwitchClause extends Node {
+class SwitchCase extends Node {
+  final Expression expression;
   final Block body;
 
-  SwitchClause(this.body);
-}
+  SwitchCase(this.expression, this.body);
+  SwitchCase.defaultCase(this.body) : expression = null;
 
-class Case extends SwitchClause {
-  final Expression expression;
+  bool get isDefault => expression == null;
 
-  Case(this.expression, Block body) : super(body);
-
-  accept(NodeVisitor visitor) => visitor.visitCase(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitSwitchCase(this);
 
   void visitChildren(NodeVisitor visitor) {
-    expression.accept(visitor);
+    expression?.accept(visitor);
     body.accept(visitor);
   }
 
-  Case _clone() => new Case(expression, body);
-}
-
-class Default extends SwitchClause {
-  Default(Block body) : super(body);
-
-  accept(NodeVisitor visitor) => visitor.visitDefault(this);
-
-  void visitChildren(NodeVisitor visitor) {
-    body.accept(visitor);
-  }
-
-  Default _clone() => new Default(body);
+  SwitchCase _clone() => new SwitchCase(expression, body);
 }
 
 class FunctionDeclaration extends Statement {
@@ -685,7 +664,7 @@
 
   FunctionDeclaration(this.name, this.function);
 
-  accept(NodeVisitor visitor) => visitor.visitFunctionDeclaration(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitFunctionDeclaration(this);
 
   void visitChildren(NodeVisitor visitor) {
     name.accept(visitor);
@@ -701,7 +680,7 @@
 
   LabeledStatement(this.label, this.body);
 
-  accept(NodeVisitor visitor) => visitor.visitLabeledStatement(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLabeledStatement(this);
 
   void visitChildren(NodeVisitor visitor) {
     body.accept(visitor);
@@ -715,7 +694,7 @@
 
   LiteralStatement(this.code);
 
-  accept(NodeVisitor visitor) => visitor.visitLiteralStatement(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralStatement(this);
   void visitChildren(NodeVisitor visitor) {}
 
   LiteralStatement _clone() => new LiteralStatement(code);
@@ -730,7 +709,7 @@
 
   DartYield(this.expression, this.hasStar);
 
-  accept(NodeVisitor visitor) => visitor.visitDartYield(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitDartYield(this);
 
   void visitChildren(NodeVisitor visitor) {
     expression.accept(visitor);
@@ -764,7 +743,7 @@
       new Assignment.compound(left, op, this);
 
   // TODO(jmesserly): make this work for more cases?
-  Statement toVariableDeclaration(Identifier name) =>
+  Statement toVariableDeclaration(VariableBinding name) =>
       new VariableDeclarationList(
           'let', [new VariableInitialization(name, this)]).toStatement();
 }
@@ -776,7 +755,7 @@
   LiteralExpression(this.template) : inputs = const [];
   LiteralExpression.withData(this.template, this.inputs);
 
-  accept(NodeVisitor visitor) => visitor.visitLiteralExpression(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralExpression(this);
 
   void visitChildren(NodeVisitor visitor) {
     if (inputs != null) {
@@ -815,7 +794,8 @@
     return false;
   }
 
-  accept(NodeVisitor visitor) => visitor.visitVariableDeclarationList(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitVariableDeclarationList(this);
 
   void visitChildren(NodeVisitor visitor) {
     for (VariableInitialization declaration in declarations) {
@@ -832,16 +812,16 @@
 class Assignment extends Expression {
   final Expression leftHandSide;
   final String op; // Null, if the assignment is not compound.
-  final Expression value; // May be null, for [VariableInitialization]s.
+  final Expression value;
 
-  Assignment(leftHandSide, value) : this.compound(leftHandSide, null, value);
+  Assignment(this.leftHandSide, this.value) : op = null;
   Assignment.compound(this.leftHandSide, this.op, this.value);
 
   int get precedenceLevel => ASSIGNMENT;
 
   bool get isCompound => op != null;
 
-  accept(NodeVisitor visitor) => visitor.visitAssignment(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitAssignment(this);
 
   void visitChildren(NodeVisitor visitor) {
     leftHandSide.accept(visitor);
@@ -851,17 +831,25 @@
   Assignment _clone() => new Assignment.compound(leftHandSide, op, value);
 }
 
-class VariableInitialization extends Assignment {
-  /** [value] may be null. */
-  VariableInitialization(VariableBinding declaration, Expression value)
-      : super(declaration, value);
+class VariableInitialization extends Expression {
+  final VariableBinding declaration;
+  final Expression value; // May be null.
 
-  VariableBinding get declaration => leftHandSide;
+  /// [value] may be null.
+  VariableInitialization(this.declaration, this.value);
 
-  accept(NodeVisitor visitor) => visitor.visitVariableInitialization(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitVariableInitialization(this);
 
   VariableInitialization _clone() =>
       new VariableInitialization(declaration, value);
+
+  int get precedenceLevel => ASSIGNMENT;
+
+  void visitChildren(NodeVisitor visitor) {
+    declaration.accept(visitor);
+    if (value != null) value.accept(visitor);
+  }
 }
 
 abstract class VariableBinding extends Expression {
@@ -871,24 +859,39 @@
   bool shadows(Set<String> names);
 }
 
+// TODO(jmesserly): destructuring was originally implemented in the context of
+// Closure Compiler work. Rethink how this is represented.
 class DestructuredVariable extends Expression implements Parameter {
-  /// [LiteralString] or [Identifier].
-  final Expression name;
+  final Identifier name;
+
+  /// The proprety in an object binding pattern, for example:
+  ///
+  ///     let key = 'z';
+  ///     let {[key]: foo} = {z: 'bar'};
+  ///     console.log(foo); // "bar"
+  ///
+  // TODO(jmesserly): parser does not support this feature.
+  final Expression property;
+
   final BindingPattern structure;
   final Expression defaultValue;
   final TypeRef type;
   DestructuredVariable(
-      {this.name, this.structure, this.defaultValue, this.type}) {
+      {this.name,
+      this.property,
+      this.structure,
+      this.defaultValue,
+      this.type}) {
     assert(name != null || structure != null);
   }
 
   bool shadows(Set<String> names) {
-    Expression name = this.name;
-    return names.contains(
-        name is LiteralString ? name.value : (name as Identifier).name);
+    return (name?.shadows(names) ?? false) ||
+        (structure?.shadows(names) ?? false);
   }
 
-  accept(NodeVisitor visitor) => visitor.visitDestructuredVariable(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitDestructuredVariable(this);
   void visitChildren(NodeVisitor visitor) {
     name?.accept(visitor);
     structure?.accept(visitor);
@@ -900,7 +903,10 @@
   int get precedenceLevel => PRIMARY;
   @override
   Node _clone() => new DestructuredVariable(
-      name: name, structure: structure, defaultValue: defaultValue);
+      name: name,
+      property: property,
+      structure: structure,
+      defaultValue: defaultValue);
 }
 
 abstract class BindingPattern extends Expression implements VariableBinding {
@@ -923,7 +929,8 @@
       : name = name,
         super([new DestructuredVariable(name: name)]);
 
-  accept(NodeVisitor visitor) => visitor.visitSimpleBindingPattern(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitSimpleBindingPattern(this);
 
   @override
   bool shadows(Set<String> names) => names.contains(name.name);
@@ -937,7 +944,8 @@
 
 class ObjectBindingPattern extends BindingPattern {
   ObjectBindingPattern(List<DestructuredVariable> variables) : super(variables);
-  accept(NodeVisitor visitor) => visitor.visitObjectBindingPattern(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitObjectBindingPattern(this);
 
   /// Avoid parenthesis when pretty-printing.
   @override
@@ -948,13 +956,13 @@
 
 class ArrayBindingPattern extends BindingPattern {
   ArrayBindingPattern(List<DestructuredVariable> variables) : super(variables);
-  accept(NodeVisitor visitor) => visitor.visitArrayBindingPattern(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayBindingPattern(this);
 
   /// Avoid parenthesis when pretty-printing.
   @override
   int get precedenceLevel => PRIMARY;
   @override
-  Node _clone() => new ObjectBindingPattern(variables);
+  Node _clone() => new ArrayBindingPattern(variables);
 }
 
 class Conditional extends Expression {
@@ -964,7 +972,7 @@
 
   Conditional(this.condition, this.then, this.otherwise);
 
-  accept(NodeVisitor visitor) => visitor.visitConditional(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitConditional(this);
 
   void visitChildren(NodeVisitor visitor) {
     condition.accept(visitor);
@@ -983,7 +991,7 @@
 
   Call(this.target, this.arguments);
 
-  accept(NodeVisitor visitor) => visitor.visitCall(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitCall(this);
 
   void visitChildren(NodeVisitor visitor) {
     target.accept(visitor);
@@ -998,7 +1006,7 @@
 class New extends Call {
   New(Expression cls, List<Expression> arguments) : super(cls, arguments);
 
-  accept(NodeVisitor visitor) => visitor.visitNew(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitNew(this);
 
   New _clone() => new New(target, arguments);
 
@@ -1012,7 +1020,7 @@
 
   Binary(this.op, this.left, this.right);
 
-  accept(NodeVisitor visitor) => visitor.visitBinary(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitBinary(this);
 
   Binary _clone() => new Binary(op, left, right);
 
@@ -1113,7 +1121,7 @@
 
   Prefix(this.op, this.argument);
 
-  accept(NodeVisitor visitor) => visitor.visitPrefix(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitPrefix(this);
 
   Prefix _clone() => new Prefix(op, argument);
 
@@ -1131,7 +1139,7 @@
   Spread(Expression operand) : super('...', operand);
   int get precedenceLevel => SPREAD;
 
-  accept(NodeVisitor visitor) => visitor.visitSpread(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitSpread(this);
   Spread _clone() => new Spread(argument);
 }
 
@@ -1141,7 +1149,7 @@
 
   Postfix(this.op, this.argument);
 
-  accept(NodeVisitor visitor) => visitor.visitPostfix(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitPostfix(this);
 
   Postfix _clone() => new Postfix(op, argument);
 
@@ -1156,7 +1164,7 @@
   TypeRef get type;
 }
 
-class Identifier extends Expression implements Parameter, VariableBinding {
+class Identifier extends Expression implements Parameter {
   final String name;
   final bool allowRename;
   final TypeRef type;
@@ -1171,7 +1179,7 @@
   bool shadows(Set<String> names) => names.contains(name);
 
   Identifier _clone() => new Identifier(name, allowRename: allowRename);
-  accept(NodeVisitor visitor) => visitor.visitIdentifier(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitIdentifier(this);
   int get precedenceLevel => PRIMARY;
   void visitChildren(NodeVisitor visitor) {}
 }
@@ -1186,7 +1194,7 @@
   bool shadows(Set<String> names) => names.contains(parameter.name);
 
   RestParameter _clone() => new RestParameter(parameter);
-  accept(NodeVisitor visitor) => visitor.visitRestParameter(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitRestParameter(this);
   void visitChildren(NodeVisitor visitor) {
     parameter.accept(visitor);
   }
@@ -1195,7 +1203,7 @@
 }
 
 class This extends Expression {
-  accept(NodeVisitor visitor) => visitor.visitThis(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitThis(this);
   This _clone() => new This();
   int get precedenceLevel => PRIMARY;
   void visitChildren(NodeVisitor visitor) {}
@@ -1223,7 +1231,7 @@
 // `super` is more restricted in the ES6 spec, but for simplicity we accept
 // it anywhere that `this` is accepted.
 class Super extends Expression {
-  accept(NodeVisitor visitor) => visitor.visitSuper(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitSuper(this);
   Super _clone() => new Super();
   int get precedenceLevel => PRIMARY;
   void visitChildren(NodeVisitor visitor) {}
@@ -1239,7 +1247,7 @@
 
   NamedFunction(this.name, this.function, [this.immediatelyInvoked = false]);
 
-  accept(NodeVisitor visitor) => visitor.visitNamedFunction(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitNamedFunction(this);
 
   void visitChildren(NodeVisitor visitor) {
     name.accept(visitor);
@@ -1284,7 +1292,7 @@
       this.typeParams,
       this.returnType});
 
-  accept(NodeVisitor visitor) => visitor.visitFun(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitFun(this);
 
   void visitChildren(NodeVisitor visitor) {
     for (Parameter param in params) param.accept(visitor);
@@ -1307,7 +1315,7 @@
 
   ArrowFun(this.params, this.body, {this.typeParams, this.returnType});
 
-  accept(NodeVisitor visitor) => visitor.visitArrowFun(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrowFun(this);
 
   void visitChildren(NodeVisitor visitor) {
     for (Parameter param in params) param.accept(visitor);
@@ -1359,7 +1367,7 @@
   PropertyAccess.indexed(this.receiver, int index)
       : selector = new LiteralNumber('$index');
 
-  accept(NodeVisitor visitor) => visitor.visitAccess(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitAccess(this);
 
   void visitChildren(NodeVisitor visitor) {
     receiver.accept(visitor);
@@ -1382,7 +1390,7 @@
 
   LiteralBool(this.value);
 
-  accept(NodeVisitor visitor) => visitor.visitLiteralBool(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralBool(this);
   // [visitChildren] inherited from [Literal].
   LiteralBool _clone() => new LiteralBool(value);
 }
@@ -1390,7 +1398,7 @@
 class LiteralNull extends Literal {
   LiteralNull();
 
-  accept(NodeVisitor visitor) => visitor.visitLiteralNull(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralNull(this);
   LiteralNull _clone() => new LiteralNull();
 }
 
@@ -1412,7 +1420,7 @@
   /// Gets the value inside the string without the beginning and end quotes.
   String get valueWithoutQuotes => value.substring(1, value.length - 1);
 
-  accept(NodeVisitor visitor) => visitor.visitLiteralString(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralString(this);
   LiteralString _clone() => new LiteralString(value);
 }
 
@@ -1421,7 +1429,7 @@
 
   LiteralNumber(this.value);
 
-  accept(NodeVisitor visitor) => visitor.visitLiteralNumber(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralNumber(this);
   LiteralNumber _clone() => new LiteralNumber(value);
 
   /**
@@ -1437,7 +1445,7 @@
 
   ArrayInitializer(this.elements, {this.multiline: false});
 
-  accept(NodeVisitor visitor) => visitor.visitArrayInitializer(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayInitializer(this);
 
   void visitChildren(NodeVisitor visitor) {
     for (Expression element in elements) element.accept(visitor);
@@ -1453,7 +1461,7 @@
  * For example the list [1, , , 2] would contain two holes.
  */
 class ArrayHole extends Expression {
-  accept(NodeVisitor visitor) => visitor.visitArrayHole(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayHole(this);
 
   void visitChildren(NodeVisitor visitor) {}
 
@@ -1469,10 +1477,10 @@
   /**
    * Constructs a new object-initializer containing the given [properties].
    */
-  ObjectInitializer(this.properties, {multiline: false})
+  ObjectInitializer(this.properties, {bool multiline: false})
       : _multiline = multiline;
 
-  accept(NodeVisitor visitor) => visitor.visitObjectInitializer(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitObjectInitializer(this);
 
   void visitChildren(NodeVisitor visitor) {
     for (Property init in properties) init.accept(visitor);
@@ -1497,7 +1505,7 @@
 
   Property(this.name, this.value);
 
-  accept(NodeVisitor visitor) => visitor.visitProperty(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitProperty(this);
 
   void visitChildren(NodeVisitor visitor) {
     name.accept(visitor);
@@ -1533,7 +1541,7 @@
     assert(strings.length == interpolations.length + 1);
   }
 
-  accept(NodeVisitor visitor) => visitor.visitTemplateString(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitTemplateString(this);
 
   void visitChildren(NodeVisitor visitor) {
     for (var element in interpolations) {
@@ -1553,7 +1561,7 @@
 
   TaggedTemplate(this.tag, this.template);
 
-  accept(NodeVisitor visitor) => visitor.visitTaggedTemplate(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitTaggedTemplate(this);
 
   void visitChildren(NodeVisitor visitor) {
     tag.accept(visitor);
@@ -1577,7 +1585,7 @@
 
   Yield(this.value, {this.star: false});
 
-  accept(NodeVisitor visitor) => visitor.visitYield(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitYield(this);
 
   void visitChildren(NodeVisitor visitor) {
     if (value != null) value.accept(visitor);
@@ -1593,7 +1601,7 @@
 
   ClassDeclaration(this.classExpr);
 
-  accept(NodeVisitor visitor) => visitor.visitClassDeclaration(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitClassDeclaration(this);
   visitChildren(NodeVisitor visitor) => classExpr.accept(visitor);
   ClassDeclaration _clone() => new ClassDeclaration(classExpr);
 }
@@ -1613,7 +1621,7 @@
   ClassExpression(this.name, this.heritage, this.methods,
       {this.typeParams, this.fields});
 
-  accept(NodeVisitor visitor) => visitor.visitClassExpression(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitClassExpression(this);
 
   void visitChildren(NodeVisitor visitor) {
     name.accept(visitor);
@@ -1640,22 +1648,23 @@
   int get precedenceLevel => PRIMARY_LOW_PRECEDENCE;
 }
 
-class Method extends Property {
+class Method extends Node implements Property {
+  final Expression name;
+  final Fun function;
   final bool isGetter;
   final bool isSetter;
   final bool isStatic;
 
-  Method(Expression name, Fun function,
-      {this.isGetter: false, this.isSetter: false, this.isStatic: false})
-      : super(name, function) {
+  Method(this.name, this.function,
+      {this.isGetter: false, this.isSetter: false, this.isStatic: false}) {
     assert(!isGetter || function.params.length == 0);
     assert(!isSetter || function.params.length == 1);
     assert(!isGetter && !isSetter || !function.isGenerator);
   }
 
-  Fun get function => super.value;
+  Fun get value => function;
 
-  accept(NodeVisitor visitor) => visitor.visitMethod(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitMethod(this);
 
   void visitChildren(NodeVisitor visitor) {
     name.accept(visitor);
@@ -1679,7 +1688,8 @@
 
   InterpolatedExpression(this.nameOrPosition);
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedExpression(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitInterpolatedExpression(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedExpression _clone() => new InterpolatedExpression(nameOrPosition);
 
@@ -1691,7 +1701,7 @@
 
   InterpolatedLiteral(this.nameOrPosition);
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedLiteral(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitInterpolatedLiteral(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedLiteral _clone() => new InterpolatedLiteral(nameOrPosition);
 }
@@ -1712,7 +1722,8 @@
 
   InterpolatedParameter(this.nameOrPosition);
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedParameter(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitInterpolatedParameter(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedParameter _clone() => new InterpolatedParameter(nameOrPosition);
 
@@ -1724,7 +1735,8 @@
 
   InterpolatedSelector(this.nameOrPosition);
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedSelector(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitInterpolatedSelector(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedSelector _clone() => new InterpolatedSelector(nameOrPosition);
 
@@ -1736,7 +1748,8 @@
 
   InterpolatedStatement(this.nameOrPosition);
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedStatement(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitInterpolatedStatement(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedStatement _clone() => new InterpolatedStatement(nameOrPosition);
 }
@@ -1749,18 +1762,19 @@
 
   InterpolatedMethod(this.nameOrPosition);
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedMethod(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitInterpolatedMethod(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedMethod _clone() => new InterpolatedMethod(nameOrPosition);
 
   int get precedenceLevel => PRIMARY;
-  Expression get name => _unsupported;
-  Expression get value => _unsupported;
-  bool get isGetter => _unsupported;
-  bool get isSetter => _unsupported;
-  bool get isStatic => _unsupported;
-  Fun get function => _unsupported;
-  get _unsupported => throw '$runtimeType does not support this member.';
+  Expression get name => throw _unsupported;
+  Fun get value => throw _unsupported;
+  bool get isGetter => throw _unsupported;
+  bool get isSetter => throw _unsupported;
+  bool get isStatic => throw _unsupported;
+  Fun get function => throw _unsupported;
+  Error get _unsupported =>
+      new UnsupportedError('$runtimeType does not support this member.');
 }
 
 class InterpolatedIdentifier extends Expression
@@ -1773,7 +1787,8 @@
 
   bool shadows(Set<String> names) => false;
 
-  accept(NodeVisitor visitor) => visitor.visitInterpolatedIdentifier(this);
+  T accept<T>(NodeVisitor<T> visitor) =>
+      visitor.visitInterpolatedIdentifier(this);
   void visitChildren(NodeVisitor visitor) {}
   InterpolatedIdentifier _clone() => new InterpolatedIdentifier(nameOrPosition);
 
@@ -1793,7 +1808,7 @@
 
   RegExpLiteral(this.pattern);
 
-  accept(NodeVisitor visitor) => visitor.visitRegExpLiteral(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitRegExpLiteral(this);
   void visitChildren(NodeVisitor visitor) {}
   RegExpLiteral _clone() => new RegExpLiteral(pattern);
 
@@ -1813,7 +1828,7 @@
   Await(this.expression);
 
   int get precedenceLevel => UNARY;
-  accept(NodeVisitor visitor) => visitor.visitAwait(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitAwait(this);
   void visitChildren(NodeVisitor visitor) => expression.accept(visitor);
   Await _clone() => new Await(expression);
 }
@@ -1829,7 +1844,7 @@
 
   Comment(this.comment);
 
-  accept(NodeVisitor visitor) => visitor.visitComment(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitComment(this);
   Comment _clone() => new Comment(comment);
 
   void visitChildren(NodeVisitor visitor) {}
@@ -1848,7 +1863,7 @@
   CommentExpression(this.comment, this.expression);
 
   int get precedenceLevel => PRIMARY;
-  accept(NodeVisitor visitor) => visitor.visitCommentExpression(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitCommentExpression(this);
   CommentExpression _clone() => new CommentExpression(comment, expression);
 
   void visitChildren(NodeVisitor visitor) => expression.accept(visitor);
@@ -1885,7 +1900,7 @@
     return null;
   }
 
-  accept(NodeVisitor visitor) => visitor.visitImportDeclaration(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitImportDeclaration(this);
   void visitChildren(NodeVisitor visitor) {
     if (namedImports != null) {
       for (NameSpecifier name in namedImports) name.accept(visitor);
@@ -1929,7 +1944,9 @@
     if (exported is ClassDeclaration) return [exported.classExpr.name];
     if (exported is FunctionDeclaration) return [exported.name];
     if (exported is VariableDeclarationList) {
-      return exported.declarations.map((i) => i.declaration).toList();
+      return exported.declarations
+          .map((i) => i.declaration as Identifier)
+          .toList();
     }
     if (exported is ExportClause) {
       if (exported.exportStar) return null;
@@ -1938,7 +1955,7 @@
     throw new StateError('invalid export declaration');
   }
 
-  accept(NodeVisitor visitor) => visitor.visitExportDeclaration(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitExportDeclaration(this);
   visitChildren(NodeVisitor visitor) => exported.accept(visitor);
   ExportDeclaration _clone() =>
       new ExportDeclaration(exported, isDefault: isDefault);
@@ -1957,7 +1974,7 @@
   /** True if this is an `export *`. */
   bool get exportStar => exports.length == 1 && exports[0].isStar;
 
-  accept(NodeVisitor visitor) => visitor.visitExportClause(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitExportClause(this);
   void visitChildren(NodeVisitor visitor) {
     for (NameSpecifier name in exports) name.accept(visitor);
     if (from != null) from.accept(visitor);
@@ -1977,7 +1994,7 @@
   /** True if this is a `* as someName` specifier. */
   bool get isStar => name == null;
 
-  accept(NodeVisitor visitor) => visitor.visitNameSpecifier(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitNameSpecifier(this);
   void visitChildren(NodeVisitor visitor) {}
   NameSpecifier _clone() => new NameSpecifier(name, asName: asName);
 }
@@ -1992,7 +2009,7 @@
   final List<ModuleItem> body;
   Module(this.body, {this.name});
 
-  accept(NodeVisitor visitor) => visitor.visitModule(this);
+  T accept<T>(NodeVisitor<T> visitor) => visitor.visitModule(this);
   void visitChildren(NodeVisitor visitor) {
     for (ModuleItem item in body) item.accept(visitor);
   }
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index d787256..7688fc7 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -218,7 +218,7 @@
     context.exitNode(node);
   }
 
-  visitCommaSeparated(List<Node> nodes, int hasRequiredType,
+  visitCommaSeparated(List<Expression> nodes, int hasRequiredType,
       {bool newInForInit, bool newAtStatementBegin}) {
     for (int i = 0; i < nodes.length; i++) {
       if (i != 0) {
@@ -303,8 +303,8 @@
   }
 
   void ifOut(If node, bool shouldIndent) {
-    Node then = node.then;
-    Node elsePart = node.otherwise;
+    var then = node.then;
+    var elsePart = node.otherwise;
     bool hasElse = node.hasElse;
 
     // Handle dangling elses and a work-around for Android 4.0 stock browser.
@@ -524,19 +524,16 @@
     outIndentLn("}");
   }
 
-  visitCase(Case node) {
-    outIndent("case");
-    pendingSpace = true;
-    visitNestedExpression(node.expression, EXPRESSION,
-        newInForInit: false, newAtStatementBegin: false);
-    outLn(":");
-    if (!node.body.statements.isEmpty) {
-      blockOut(node.body, true, true);
+  visitSwitchCase(SwitchCase node) {
+    if (node.isDefault) {
+      outIndentLn("default:");
+    } else {
+      outIndent("case");
+      pendingSpace = true;
+      visitNestedExpression(node.expression, EXPRESSION,
+          newInForInit: false, newAtStatementBegin: false);
+      outLn(":");
     }
-  }
-
-  visitDefault(Default node) {
-    outIndentLn("default:");
     if (!node.body.statements.isEmpty) {
       blockOut(node.body, true, true);
     }
@@ -547,7 +544,7 @@
     blockBody(node.body, needsSeparation: false, needsNewline: true);
   }
 
-  void functionOut(Fun fun, Node name) {
+  void functionOut(Fun fun, Identifier name) {
     out("function");
     if (fun.isGenerator) out("*");
     if (name != null) {
@@ -648,29 +645,29 @@
 
   visitDestructuredVariable(DestructuredVariable node) {
     var name = node.name;
-    var hasName = name != null;
-    if (hasName) {
-      if (name is LiteralString) {
-        out("[");
-        out(name.value);
-        out("]");
-      } else {
-        visit(name);
-      }
+    var property = node.property;
+    if (name != null) {
+      visit(node.name);
+    } else if (property != null) {
+      out("[");
+      visit(node.property);
+      out("]");
     }
-    if (node.structure != null) {
-      if (hasName) {
+    var structure = node.structure;
+    if (structure != null) {
+      if (name != null || property != null) {
         out(":");
         spaceOut();
       }
-      visit(node.structure);
+      visit(structure);
     }
     outTypeAnnotation(node.type);
-    if (node.defaultValue != null) {
+    var defaultValue = node.defaultValue;
+    if (defaultValue != null) {
       spaceOut();
       out("=");
       spaceOut();
-      visitNestedExpression(node.defaultValue, EXPRESSION,
+      visitNestedExpression(defaultValue, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
   }
@@ -693,9 +690,17 @@
     }
   }
 
-  visitVariableInitialization(VariableInitialization initialization) {
-    outClosureAnnotation(initialization);
-    visitAssignment(initialization);
+  visitVariableInitialization(VariableInitialization init) {
+    outClosureAnnotation(init);
+    visitNestedExpression(init.declaration, LEFT_HAND_SIDE,
+        newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
+    if (init.value != null) {
+      spaceOut();
+      out("=");
+      spaceOut();
+      visitNestedExpression(init.value, ASSIGNMENT,
+          newInForInit: inForInit, newAtStatementBegin: false);
+    }
   }
 
   visitConditional(Conditional cond) {
@@ -971,18 +976,19 @@
     outTypeAnnotation(fun.returnType);
     spaceOut();
     out("=>");
-    if (fun.body is Expression) {
+    var body = fun.body;
+    if (body is Expression) {
       spaceOut();
       // Object initializers require parenthesis to disambiguate
       // AssignmentExpression from FunctionBody. See:
       // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions
       var needsParen = fun.body is ObjectInitializer;
       if (needsParen) out("(");
-      visitNestedExpression(fun.body, ASSIGNMENT,
+      visitNestedExpression(body, ASSIGNMENT,
           newInForInit: false, newAtStatementBegin: false);
       if (needsParen) out(")");
     } else {
-      blockBody(fun.body, needsSeparation: false, needsNewline: false);
+      blockBody(body as Block, needsSeparation: false, needsNewline: false);
     }
     localNamer.leaveScope();
   }
@@ -1233,7 +1239,7 @@
         spaceOut();
       }
     }
-    nameSpecifierListOut(node.namedImports);
+    nameSpecifierListOut(node.namedImports, false);
     fromClauseOut(node.from);
     outSemicolonLn();
   }
@@ -1248,15 +1254,15 @@
   }
 
   visitExportClause(ExportClause node) {
-    nameSpecifierListOut(node.exports);
+    nameSpecifierListOut(node.exports, true);
     fromClauseOut(node.from);
   }
 
-  nameSpecifierListOut(List<NameSpecifier> names) {
+  nameSpecifierListOut(List<NameSpecifier> names, bool export) {
     if (names == null) return;
 
     if (names.length == 1 && names[0].name == '*') {
-      visit(names[0]);
+      nameSpecifierOut(names[0], export);
       return;
     }
 
@@ -1267,7 +1273,7 @@
         out(',');
         spaceOut();
       }
-      visit(names[i]);
+      nameSpecifierOut(names[i], export);
     }
     spaceOut();
     out('}');
@@ -1281,22 +1287,28 @@
     }
   }
 
+  /// This is unused, see [nameSpecifierOut].
   visitNameSpecifier(NameSpecifier node) {
+    throw new UnsupportedError('visitNameSpecifier');
+  }
+
+  nameSpecifierOut(NameSpecifier node, bool export) {
     if (node.isStar) {
       out('*');
     } else {
-      var importName = node.name.name;
-      out(importName);
-
+      var name = node.name.name;
       if (node.asName == null) {
         // If our local was renamed, generate an implicit "as".
-        // This is a convenience feature so imports can be renamed.
+        // This is a convenience feature so imports and exports can be renamed.
         var localName = localNamer.getName(node.name);
-        if (localName != importName) {
+        if (localName != name) {
+          out(export ? localName : name);
           out(' as ');
-          out(localName);
+          out(export ? name : localName);
+          return;
         }
       }
+      out(name);
     }
     if (node.asName != null) {
       out(' as ');
@@ -1463,8 +1475,10 @@
   }
 
   void visitVariableInitialization(VariableInitialization node) {
-    declareVariable(node.declaration);
-    if (node.value != null) node.value.accept(this);
+    // TODO(jmesserly): add ES6 support. Currently not needed because
+    // dart2js does not emit ES6 rest param or destructuring.
+    declareVariable(node.declaration as Identifier);
+    node.value?.accept(this);
   }
 
   void declareVariable(Identifier decl) {
@@ -1515,8 +1529,7 @@
 
   bool visitCatch(Catch node) => node.body.accept(this);
   bool visitSwitch(Switch node) => false;
-  bool visitCase(Case node) => false;
-  bool visitDefault(Default node) => false;
+  bool visitSwitchCase(SwitchCase node) => false;
   bool visitFunctionDeclaration(FunctionDeclaration node) => false;
   bool visitLabeledStatement(LabeledStatement node) => node.body.accept(this);
   bool visitLiteralStatement(LiteralStatement node) => true;
@@ -1590,7 +1603,7 @@
   // moving on to a0, a1, etc.
   String declareVariable(String oldName) {
     if (avoidRenaming(oldName)) return oldName;
-    var newName;
+    String newName;
     if (variableNumber + parameterNumber < LOWER_CASE_LETTERS) {
       // Variables start from z and go backwards, for better gzipability.
       newName = getNameNumber(oldName, LOWER_CASE_LETTERS - 1 - variableNumber);
@@ -1604,7 +1617,7 @@
 
   String declareParameter(String oldName) {
     if (avoidRenaming(oldName)) return oldName;
-    var newName;
+    String newName;
     if (variableNumber + parameterNumber < LOWER_CASE_LETTERS) {
       newName = getNameNumber(oldName, parameterNumber);
     } else {
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index 4a822f3..6b4bc6c 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -79,15 +79,13 @@
   }
 
   bool _checkNoPlaceholders() {
-    InstantiatorGeneratorVisitor generator =
-        new InstantiatorGeneratorVisitor(false);
+    var generator = new InstantiatorGeneratorVisitor(false);
     generator.compile(ast);
     return generator.analysis.count == 0;
   }
 
   void _compile() {
-    InstantiatorGeneratorVisitor generator =
-        new InstantiatorGeneratorVisitor(forceCopy);
+    var generator = new InstantiatorGeneratorVisitor(forceCopy);
     instantiator = generator.compile(ast);
     positionalArgumentCount = generator.analysis.count;
     Set<String> names = generator.analysis.holeNames;
@@ -104,22 +102,25 @@
         throw 'Wrong number of template arguments, given ${arguments.length}, '
             'expected $positionalArgumentCount:\n$source';
       }
-      return instantiator(arguments);
+      return instantiator(arguments) as Node;
     }
-    assert(arguments is Map);
-    if (holeNames.length < arguments.length) {
-      // This search is in O(n), but we only do it in case of an error, and the
-      // number of holes should be quite limited.
-      String unusedNames =
-          arguments.keys.where((name) => !holeNames.contains(name)).join(", ");
-      throw "Template arguments has unused mappings: $unusedNames";
+    if (arguments is Map) {
+      if (holeNames.length < arguments.length) {
+        // This search is in O(n), but we only do it in case of an new StateError, and the
+        // number of holes should be quite limited.
+        String unusedNames = arguments.keys
+            .where((name) => !holeNames.contains(name))
+            .join(", ");
+        throw "Template arguments has unused mappings: $unusedNames";
+      }
+      if (!holeNames.every((String name) => arguments.containsKey(name))) {
+        String notFound =
+            holeNames.where((name) => !arguments.containsKey(name)).join(", ");
+        throw "Template arguments is missing mappings for: $notFound";
+      }
+      return instantiator(arguments) as Node;
     }
-    if (!holeNames.every((String name) => arguments.containsKey(name))) {
-      String notFound =
-          holeNames.where((name) => !arguments.containsKey(name)).join(", ");
-      throw "Template arguments is missing mappings for: $notFound";
-    }
-    return instantiator(arguments);
+    throw new ArgumentError.value(arguments, 'must be a List or Map');
   }
 }
 
@@ -128,7 +129,7 @@
  * trees. [arguments] is a List for positional templates, or Map for
  * named templates.
  */
-typedef Instantiator(var arguments);
+typedef T Instantiator<T>(arguments);
 
 /**
  * InstantiatorGeneratorVisitor compiles a template.  This class compiles a tree
@@ -138,7 +139,7 @@
 class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
   final bool forceCopy;
 
-  InterpolatedNodeAnalysis analysis = new InterpolatedNodeAnalysis();
+  final analysis = new InterpolatedNodeAnalysis();
 
   /**
    * The entire tree is cloned if [forceCopy] is true.
@@ -147,16 +148,11 @@
 
   Instantiator compile(Node node) {
     analysis.visit(node);
-    Instantiator result = visit(node);
-    return result;
+    return visit(node);
   }
 
-  static error(String message) {
-    throw message;
-  }
-
-  static Instantiator same(Node node) => (arguments) => node;
-  static Node makeNull(arguments) => null;
+  static Instantiator<T> same<T extends Node>(T node) => (arguments) => node;
+  static Null makeNull(arguments) => null;
 
   Instantiator visit(Node node) {
     if (forceCopy || analysis.containsInterpolatedNodes(node)) {
@@ -166,26 +162,29 @@
   }
 
   Instantiator visitNullable(Node node) {
-    if (node == null) return makeNull;
-    return visit(node);
+    return node == null ? makeNull : visit(node);
   }
 
   Instantiator visitSplayable(Node node) {
-    // TODO(sra): Process immediate [InterpolatedNode]s, permitting splaying.
-    return visit(node);
+    // TODO(jmesserly): parameters and methods always support splaying because
+    // they appear in lists. So this method is equivalent to
+    // `visitSplayableExpression`.
+    return visitSplayableExpression(node);
   }
 
   Instantiator visitNode(Node node) {
-    throw 'Unimplemented InstantiatorGeneratorVisitor for $node';
+    throw new UnimplementedError('visit${node.runtimeType}');
   }
 
-  Instantiator visitInterpolatedExpression(InterpolatedExpression node) {
+  Instantiator<Expression> visitInterpolatedExpression(
+      InterpolatedExpression node) {
     var nameOrPosition = node.nameOrPosition;
     return (arguments) {
       var value = arguments[nameOrPosition];
       if (value is Expression) return value;
       if (value is String) return new Identifier(value);
-      error('Interpolated value #$nameOrPosition is not an Expression: $value');
+      throw new StateError(
+          'Interpolated value #$nameOrPosition is not an Expression: $value');
     };
   }
 
@@ -197,7 +196,7 @@
         Expression toExpression(item) {
           if (item is Expression) return item;
           if (item is String) return new Identifier(item);
-          return error('Interpolated value #$nameOrPosition is not '
+          throw new StateError('Interpolated value #$nameOrPosition is not '
               'an Expression or List of Expressions: $value');
         }
 
@@ -208,12 +207,26 @@
     return visit(node);
   }
 
-  Instantiator visitInterpolatedLiteral(InterpolatedLiteral node) {
+  List<T> splayNodes<T extends Node>(List<Instantiator> makers, args) {
+    var exprs = <T>[];
+    for (var instantiator in makers) {
+      var result = instantiator(args);
+      if (result is Iterable) {
+        for (var e in result) exprs.add(e as T);
+      } else {
+        exprs.add(result as T);
+      }
+    }
+    return exprs;
+  }
+
+  Instantiator<Literal> visitInterpolatedLiteral(InterpolatedLiteral node) {
     var nameOrPosition = node.nameOrPosition;
     return (arguments) {
       var value = arguments[nameOrPosition];
       if (value is Literal) return value;
-      error('Interpolated value #$nameOrPosition is not a Literal: $value');
+      throw new StateError(
+          'Interpolated value #$nameOrPosition is not a Literal: $value');
     };
   }
 
@@ -225,7 +238,8 @@
       Parameter toIdentifier(item) {
         if (item is Parameter) return item;
         if (item is String) return new Identifier(item);
-        return error('Interpolated value #$nameOrPosition is not an Identifier'
+        throw new StateError(
+            'Interpolated value #$nameOrPosition is not an Identifier'
             ' or List of Identifiers: $value');
       }
 
@@ -234,7 +248,8 @@
     };
   }
 
-  Instantiator visitInterpolatedSelector(InterpolatedSelector node) {
+  Instantiator<Expression> visitInterpolatedSelector(
+      InterpolatedSelector node) {
     // A selector is an expression, as in `a[selector]`.
     // A String argument converted into a LiteralString, so `a.#` with argument
     // 'foo' generates `a["foo"]` which prints as `a.foo`.
@@ -243,16 +258,19 @@
       var value = arguments[nameOrPosition];
       if (value is Expression) return value;
       if (value is String) return new LiteralString('"$value"');
-      error('Interpolated value #$nameOrPosition is not a selector: $value');
+      throw new StateError(
+          'Interpolated value #$nameOrPosition is not a selector: $value');
     };
   }
 
-  Instantiator visitInterpolatedStatement(InterpolatedStatement node) {
+  Instantiator<Statement> visitInterpolatedStatement(
+      InterpolatedStatement node) {
     var nameOrPosition = node.nameOrPosition;
     return (arguments) {
       var value = arguments[nameOrPosition];
       if (value is Node) return value.toStatement();
-      error('Interpolated value #$nameOrPosition is not a Statement: $value');
+      throw new StateError(
+          'Interpolated value #$nameOrPosition is not a Statement: $value');
     };
   }
 
@@ -262,7 +280,8 @@
       var value = arguments[nameOrPosition];
       Method toMethod(item) {
         if (item is Method) return item;
-        return error('Interpolated value #$nameOrPosition is not a Method '
+        throw new StateError(
+            'Interpolated value #$nameOrPosition is not a Method '
             'or List of Methods: $value');
       }
 
@@ -271,13 +290,14 @@
     };
   }
 
-  Instantiator visitInterpolatedIdentifier(InterpolatedIdentifier node) {
+  Instantiator<Identifier> visitInterpolatedIdentifier(
+      InterpolatedIdentifier node) {
     var nameOrPosition = node.nameOrPosition;
     return (arguments) {
       var item = arguments[nameOrPosition];
       if (item is Identifier) return item;
       if (item is String) return new Identifier(item);
-      return error('Interpolated value #$nameOrPosition is not a '
+      throw new StateError('Interpolated value #$nameOrPosition is not a '
           'Identifier or String: $item');
     };
   }
@@ -290,8 +310,7 @@
         Statement toStatement(item) {
           if (item is Statement) return item;
           if (item is Expression) return item.toStatement();
-          ;
-          return error('Interpolated value #$nameOrPosition is not '
+          throw new StateError('Interpolated value #$nameOrPosition is not '
               'a Statement or List of Statements: $value');
         }
 
@@ -302,250 +321,178 @@
     return visit(node);
   }
 
-  Instantiator visitProgram(Program node) {
-    List instantiators = node.body.map(visitSplayableStatement).toList();
-    return (arguments) {
-      List<Statement> statements = <Statement>[];
-      void add(node) {
-        if (node is EmptyStatement) return;
-        if (node is Iterable) {
-          for (var n in node) statements.add(n);
-        } else {
-          statements.add(node.toStatement());
-        }
-      }
-
-      for (Instantiator instantiator in instantiators) {
-        add(instantiator(arguments));
-      }
-      return new Program(statements);
-    };
+  Instantiator<Program> visitProgram(Program node) {
+    var instantiators = node.body.map(visitSplayableStatement).toList();
+    return (a) => new Program(splayStatements(instantiators, a));
   }
 
-  Instantiator visitBlock(Block node) {
-    List instantiators = node.statements.map(visitSplayableStatement).toList();
-    return (arguments) {
-      List<Statement> statements = <Statement>[];
-      void add(node) {
-        if (node is EmptyStatement) return;
-        if (node is Iterable) {
-          for (var n in node) statements.add(n);
-        } else if (node is Block) {
-          statements.addAll(node.statements);
-        } else {
-          statements.add(node.toStatement());
-        }
+  List<Statement> splayStatements(List<Instantiator> instantiators, arguments) {
+    var statements = <Statement>[];
+    for (var instantiator in instantiators) {
+      var node = instantiator(arguments);
+      if (node is EmptyStatement) continue;
+      if (node is Iterable) {
+        for (var n in node) statements.add(n as Statement);
+      } else if (node is Block && !node.isScope) {
+        statements.addAll(node.statements);
+      } else {
+        statements.add((node as Node).toStatement());
       }
-
-      for (Instantiator instantiator in instantiators) {
-        add(instantiator(arguments));
-      }
-      return new Block(statements);
-    };
+    }
+    return statements;
   }
 
-  Instantiator visitExpressionStatement(ExpressionStatement node) {
-    Instantiator buildExpression = visit(node.expression);
-    return (arguments) {
-      return buildExpression(arguments).toStatement();
-    };
+  Instantiator<Block> visitBlock(Block node) {
+    var instantiators = node.statements.map(visitSplayableStatement).toList();
+    return (a) => new Block(splayStatements(instantiators, a));
   }
 
-  Instantiator visitEmptyStatement(EmptyStatement node) =>
-      (arguments) => new EmptyStatement();
+  Instantiator<Statement> visitExpressionStatement(ExpressionStatement node) {
+    Instantiator<Expression> makeExpression = visit(node.expression);
+    return (a) => makeExpression(a).toStatement();
+  }
 
-  Instantiator visitIf(If node) {
-    if (node.condition is InterpolatedExpression) {
-      return visitIfConditionalCompilation(node);
+  Instantiator<EmptyStatement> visitEmptyStatement(EmptyStatement node) =>
+      (a) => new EmptyStatement();
+
+  Instantiator<Statement> visitIf(If node) {
+    var condition = node.condition;
+    if (condition is InterpolatedExpression) {
+      return visitIfConditionalCompilation(node, condition);
     } else {
       return visitIfNormal(node);
     }
   }
 
-  Instantiator visitIfConditionalCompilation(If node) {
-    // Special version of visitInterpolatedExpression that permits bools.
-    compileCondition(InterpolatedExpression node) {
-      var nameOrPosition = node.nameOrPosition;
-      return (arguments) {
-        var value = arguments[nameOrPosition];
-        if (value is bool) return value;
-        if (value is Expression) return value;
-        if (value is String) return new Identifier(value);
-        error('Interpolated value #$nameOrPosition '
-            'is not an Expression: $value');
-      };
-    }
-
-    var makeCondition = compileCondition(node.condition);
-    Instantiator makeThen = visit(node.then);
-    Instantiator makeOtherwise = visit(node.otherwise);
+  Instantiator<Statement> visitIfConditionalCompilation(
+      If node, InterpolatedExpression condition) {
+    Instantiator<Statement> makeThen = visit(node.then);
+    Instantiator<Statement> makeOtherwise = visit(node.otherwise);
     return (arguments) {
-      var condition = makeCondition(arguments);
-      if (condition is bool) {
-        if (condition == true) {
-          return makeThen(arguments);
-        } else {
-          return makeOtherwise(arguments);
-        }
+      // Allow bools to be used for conditional compliation.
+      var nameOrPosition = condition.nameOrPosition;
+      var value = arguments[nameOrPosition];
+      if (value is bool) {
+        return value ? makeThen(arguments) : makeOtherwise(arguments);
       }
-      return new If(condition, makeThen(arguments), makeOtherwise(arguments));
+      var cond = value is String ? new Identifier(value) : value as Expression;
+      return new If(cond, makeThen(arguments), makeOtherwise(arguments));
     };
   }
 
-  Instantiator visitIfNormal(If node) {
-    Instantiator makeCondition = visit(node.condition);
-    Instantiator makeThen = visit(node.then);
-    Instantiator makeOtherwise = visit(node.otherwise);
-    return (arguments) {
-      return new If(makeCondition(arguments), makeThen(arguments),
-          makeOtherwise(arguments));
-    };
+  Instantiator<Statement> visitIfNormal(If node) {
+    Instantiator<Expression> makeCondition = visit(node.condition);
+    Instantiator<Statement> makeThen = visit(node.then);
+    Instantiator<Statement> makeOtherwise = visit(node.otherwise);
+    return (a) => new If(makeCondition(a), makeThen(a), makeOtherwise(a));
   }
 
-  Instantiator visitFor(For node) {
-    Instantiator makeInit = visitNullable(node.init);
-    Instantiator makeCondition = visitNullable(node.condition);
-    Instantiator makeUpdate = visitNullable(node.update);
-    Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return new For(makeInit(arguments), makeCondition(arguments),
-          makeUpdate(arguments)?.toVoidExpression(), makeBody(arguments));
-    };
+  Instantiator<Statement> visitFor(For node) {
+    Instantiator<Expression> makeInit = visitNullable(node.init);
+    Instantiator<Expression> makeCondition = visitNullable(node.condition);
+    Instantiator<Expression> makeUpdate = visitNullable(node.update);
+    Instantiator<Statement> makeBody = visit(node.body);
+    return (a) => new For(makeInit(a), makeCondition(a),
+        makeUpdate(a)?.toVoidExpression(), makeBody(a));
   }
 
-  Instantiator visitForIn(ForIn node) {
-    Instantiator makeLeftHandSide = visit(node.leftHandSide);
-    Instantiator makeObject = visit(node.object);
-    Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return new ForIn(makeLeftHandSide(arguments), makeObject(arguments),
-          makeBody(arguments));
-    };
+  Instantiator<ForIn> visitForIn(ForIn node) {
+    Instantiator<Expression> makeLeftHandSide = visit(node.leftHandSide);
+    Instantiator<Expression> makeObject = visit(node.object);
+    Instantiator<Statement> makeBody = visit(node.body);
+    return (a) => new ForIn(makeLeftHandSide(a), makeObject(a), makeBody(a));
   }
 
-  Instantiator visitForOf(ForOf node) {
-    Instantiator makeLeftHandSide = visit(node.leftHandSide);
-    Instantiator makeObject = visit(node.iterable);
-    Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return new ForOf(makeLeftHandSide(arguments), makeObject(arguments),
-          makeBody(arguments));
-    };
+  Instantiator<ForOf> visitForOf(ForOf node) {
+    Instantiator<Expression> makeLeftHandSide = visit(node.leftHandSide);
+    Instantiator<Expression> makeObject = visit(node.iterable);
+    Instantiator<Statement> makeBody = visit(node.body);
+    return (a) => new ForOf(makeLeftHandSide(a), makeObject(a), makeBody(a));
   }
 
-  TODO(String name) {
-    throw new UnimplementedError('$this.$name');
+  Instantiator<While> visitWhile(While node) {
+    Instantiator<Expression> makeCondition = visit(node.condition);
+    Instantiator<Statement> makeBody = visit(node.body);
+    return (a) => new While(makeCondition(a), makeBody(a));
   }
 
-  Instantiator visitWhile(While node) {
-    Instantiator makeCondition = visit(node.condition);
-    Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return new While(makeCondition(arguments), makeBody(arguments));
-    };
+  Instantiator<Do> visitDo(Do node) {
+    Instantiator<Statement> makeBody = visit(node.body);
+    Instantiator<Expression> makeCondition = visit(node.condition);
+    return (a) => new Do(makeBody(a), makeCondition(a));
   }
 
-  Instantiator visitDo(Do node) {
-    Instantiator makeBody = visit(node.body);
-    Instantiator makeCondition = visit(node.condition);
-    return (arguments) {
-      return new Do(makeBody(arguments), makeCondition(arguments));
-    };
-  }
+  Instantiator<Continue> visitContinue(Continue node) =>
+      (a) => new Continue(node.targetLabel);
 
-  Instantiator visitContinue(Continue node) =>
-      (arguments) => new Continue(node.targetLabel);
+  Instantiator<Break> visitBreak(Break node) =>
+      (a) => new Break(node.targetLabel);
 
-  Instantiator visitBreak(Break node) =>
-      (arguments) => new Break(node.targetLabel);
-
-  Instantiator visitReturn(Return node) {
+  Instantiator<Statement> visitReturn(Return node) {
     if (node.value == null) return (args) => new Return();
-    Instantiator makeExpression = visit(node.value);
-    return (args) => makeExpression(args).toReturn();
+    Instantiator<Expression> makeExpression = visit(node.value);
+    return (a) => makeExpression(a).toReturn();
   }
 
-  Instantiator visitDartYield(DartYield node) {
-    Instantiator makeExpression = visit(node.expression);
-    return (arguments) =>
-        new DartYield(makeExpression(arguments), node.hasStar);
+  Instantiator<DartYield> visitDartYield(DartYield node) {
+    Instantiator<Expression> makeExpression = visit(node.expression);
+    return (a) => new DartYield(makeExpression(a), node.hasStar);
   }
 
-  Instantiator visitThrow(Throw node) {
-    Instantiator makeExpression = visit(node.expression);
-    return (arguments) => new Throw(makeExpression(arguments));
+  Instantiator<Throw> visitThrow(Throw node) {
+    Instantiator<Expression> makeExpression = visit(node.expression);
+    return (a) => new Throw(makeExpression(a));
   }
 
-  Instantiator visitTry(Try node) {
-    Instantiator makeBody = visit(node.body);
-    Instantiator makeCatch = visitNullable(node.catchPart);
-    Instantiator makeFinally = visitNullable(node.finallyPart);
-    return (arguments) => new Try(
-        makeBody(arguments), makeCatch(arguments), makeFinally(arguments));
+  Instantiator<Try> visitTry(Try node) {
+    Instantiator<Block> makeBody = visit(node.body);
+    Instantiator<Catch> makeCatch = visitNullable(node.catchPart);
+    Instantiator<Block> makeFinally = visitNullable(node.finallyPart);
+    return (a) => new Try(makeBody(a), makeCatch(a), makeFinally(a));
   }
 
-  Instantiator visitCatch(Catch node) {
-    Instantiator makeDeclaration = visit(node.declaration);
-    Instantiator makeBody = visit(node.body);
-    return (arguments) =>
-        new Catch(makeDeclaration(arguments), makeBody(arguments));
+  Instantiator<Catch> visitCatch(Catch node) {
+    Instantiator<Identifier> makeDeclaration = visit(node.declaration);
+    Instantiator<Block> makeBody = visit(node.body);
+    return (a) => new Catch(makeDeclaration(a), makeBody(a));
   }
 
-  Instantiator visitSwitch(Switch node) {
-    Instantiator makeKey = visit(node.key);
-    Iterable<Instantiator> makeCases = node.cases.map(visit);
+  Instantiator<Switch> visitSwitch(Switch node) {
+    Instantiator<Expression> makeKey = visit(node.key);
+    var makeCases = node.cases.map(visitSwitchCase).toList();
+    return (a) => new Switch(makeKey(a), makeCases.map((m) => m(a)).toList());
+  }
+
+  Instantiator<SwitchCase> visitSwitchCase(SwitchCase node) {
+    Instantiator<Expression> makeExpression = visitNullable(node.expression);
+    Instantiator<Block> makeBody = visit(node.body);
     return (arguments) {
-      return new Switch(
-          makeKey(arguments),
-          makeCases
-              .map((makeCase) => makeCase(arguments) as SwitchClause)
-              .toList());
+      return new SwitchCase(makeExpression(arguments), makeBody(arguments));
     };
   }
 
-  Instantiator visitCase(Case node) {
-    Instantiator makeExpression = visit(node.expression);
-    Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return new Case(makeExpression(arguments), makeBody(arguments));
-    };
+  Instantiator<FunctionDeclaration> visitFunctionDeclaration(
+      FunctionDeclaration node) {
+    Instantiator<Identifier> makeName = visit(node.name);
+    Instantiator<Fun> makeFunction = visit(node.function);
+    return (a) => new FunctionDeclaration(makeName(a), makeFunction(a));
   }
 
-  Instantiator visitDefault(Default node) {
-    Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return new Default(makeBody(arguments));
-    };
+  Instantiator<LabeledStatement> visitLabeledStatement(LabeledStatement node) {
+    Instantiator<Statement> makeBody = visit(node.body);
+    return (a) => new LabeledStatement(node.label, makeBody(a));
   }
 
-  Instantiator visitFunctionDeclaration(FunctionDeclaration node) {
-    Instantiator makeName = visit(node.name);
-    Instantiator makeFunction = visit(node.function);
-    return (arguments) =>
-        new FunctionDeclaration(makeName(arguments), makeFunction(arguments));
-  }
-
-  Instantiator visitLabeledStatement(LabeledStatement node) {
-    Instantiator makeBody = visit(node.body);
-    return (arguments) => new LabeledStatement(node.label, makeBody(arguments));
-  }
-
-  Instantiator visitLiteralStatement(LiteralStatement node) =>
-      TODO('visitLiteralStatement');
+  Instantiator visitLiteralStatement(LiteralStatement node) => visitNode(node);
   Instantiator visitLiteralExpression(LiteralExpression node) =>
-      TODO('visitLiteralExpression');
+      visitNode(node);
 
-  Instantiator visitVariableDeclarationList(VariableDeclarationList node) {
-    List<Instantiator> declarationMakers =
-        node.declarations.map(visit).toList();
-    return (arguments) {
-      List<VariableInitialization> declarations = <VariableInitialization>[];
-      for (Instantiator instantiator in declarationMakers) {
-        var result = instantiator(arguments);
-        declarations.add(result);
-      }
-      return new VariableDeclarationList(node.keyword, declarations);
-    };
+  Instantiator<VariableDeclarationList> visitVariableDeclarationList(
+      VariableDeclarationList node) {
+    var declarationMakers =
+        node.declarations.map(visitVariableInitialization).toList();
+    return (a) => new VariableDeclarationList(
+        node.keyword, declarationMakers.map((m) => m(a)).toList());
   }
 
   Instantiator visitAssignment(Assignment node) {
@@ -558,260 +505,185 @@
     };
   }
 
-  Instantiator visitVariableInitialization(VariableInitialization node) {
-    Instantiator makeDeclaration = visit(node.declaration);
-    Instantiator makeValue = visitNullable(node.value);
-    return (arguments) {
-      return new VariableInitialization(
-          makeDeclaration(arguments), makeValue(arguments));
-    };
+  Instantiator<VariableInitialization> visitVariableInitialization(
+      VariableInitialization node) {
+    Instantiator<VariableBinding> makeDeclaration = visit(node.declaration);
+    Instantiator<Expression> makeValue = visitNullable(node.value);
+    return (a) => new VariableInitialization(makeDeclaration(a), makeValue(a));
   }
 
-  Instantiator visitConditional(Conditional cond) {
-    Instantiator makeCondition = visit(cond.condition);
-    Instantiator makeThen = visit(cond.then);
-    Instantiator makeOtherwise = visit(cond.otherwise);
-    return (arguments) => new Conditional(makeCondition(arguments),
-        makeThen(arguments), makeOtherwise(arguments));
+  Instantiator<Conditional> visitConditional(Conditional cond) {
+    Instantiator<Expression> makeCondition = visit(cond.condition);
+    Instantiator<Expression> makeThen = visit(cond.then);
+    Instantiator<Expression> makeOtherwise = visit(cond.otherwise);
+    return (a) =>
+        new Conditional(makeCondition(a), makeThen(a), makeOtherwise(a));
   }
 
-  Instantiator visitNew(New node) => handleCallOrNew(node,
-      (target, arguments) => new New(target, arguments as List<Expression>));
+  Instantiator<Call> visitNew(New node) => handleCallOrNew(node, true);
 
-  Instantiator visitCall(Call node) => handleCallOrNew(node,
-      (target, arguments) => new Call(target, arguments as List<Expression>));
+  Instantiator<Call> visitCall(Call node) => handleCallOrNew(node, false);
 
-  Instantiator handleCallOrNew(Call node, finish(target, arguments)) {
-    Instantiator makeTarget = visit(node.target);
-    Iterable<Instantiator> argumentMakers =
-        node.arguments.map(visitSplayableExpression).toList();
+  Instantiator<Call> handleCallOrNew(Call node, bool isNew) {
+    Instantiator<Expression> makeTarget = visit(node.target);
+    var argumentMakers = node.arguments.map(visitSplayableExpression).toList();
 
     // TODO(sra): Avoid copying call arguments if no interpolation or forced
     // copying.
-    return (arguments) {
-      Node target = makeTarget(arguments);
-      List<Expression> callArguments = <Expression>[];
-      for (Instantiator instantiator in argumentMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          for (var r in result) callArguments.add(r);
-        } else {
-          callArguments.add(result);
-        }
-      }
-      return finish(target, callArguments.toList(growable: false));
+    return (a) {
+      var target = makeTarget(a);
+      var callArgs = splayNodes<Expression>(argumentMakers, a);
+      return isNew ? new New(target, callArgs) : new Call(target, callArgs);
     };
   }
 
-  Instantiator visitBinary(Binary node) {
-    Instantiator makeLeft = visit(node.left);
-    Instantiator makeRight = visit(node.right);
+  Instantiator<Binary> visitBinary(Binary node) {
+    Instantiator<Expression> makeLeft = visit(node.left);
+    Instantiator<Expression> makeRight = visit(node.right);
     String op = node.op;
-    return (arguments) =>
-        new Binary(op, makeLeft(arguments), makeRight(arguments));
+    return (a) => new Binary(op, makeLeft(a), makeRight(a));
   }
 
-  Instantiator visitPrefix(Prefix node) {
-    Instantiator makeOperand = visit(node.argument);
+  Instantiator<Prefix> visitPrefix(Prefix node) {
+    Instantiator<Expression> makeOperand = visit(node.argument);
     String op = node.op;
-    return (arguments) => new Prefix(op, makeOperand(arguments));
+    return (a) => new Prefix(op, makeOperand(a));
   }
 
-  Instantiator visitPostfix(Postfix node) {
-    Instantiator makeOperand = visit(node.argument);
+  Instantiator<Postfix> visitPostfix(Postfix node) {
+    Instantiator<Expression> makeOperand = visit(node.argument);
     String op = node.op;
-    return (arguments) => new Postfix(op, makeOperand(arguments));
+    return (a) => new Postfix(op, makeOperand(a));
   }
 
-  Instantiator visitThis(This node) => (arguments) => new This();
-  Instantiator visitSuper(Super node) => (arguments) => new Super();
+  Instantiator<This> visitThis(This node) => (a) => new This();
+  Instantiator<Super> visitSuper(Super node) => (a) => new Super();
 
-  Instantiator visitIdentifier(Identifier node) =>
-      (arguments) => new Identifier(node.name);
+  Instantiator<Identifier> visitIdentifier(Identifier node) =>
+      (a) => new Identifier(node.name);
 
-  Instantiator visitSpread(Spread node) =>
-      (args) => new Spread(visit(node.argument)(args));
-
-  Instantiator visitYield(Yield node) =>
-      (args) => new Yield(node.value != null ? visit(node.value)(args) : null,
-          star: node.star);
-
-  Instantiator visitRestParameter(RestParameter node) =>
-      (args) => new RestParameter(visit(node.parameter)(args));
-
-  Instantiator visitAccess(PropertyAccess node) {
-    Instantiator makeReceiver = visit(node.receiver);
-    Instantiator makeSelector = visit(node.selector);
-    return (arguments) =>
-        new PropertyAccess(makeReceiver(arguments), makeSelector(arguments));
+  Instantiator<Spread> visitSpread(Spread node) {
+    var maker = visit(node.argument);
+    return (a) => new Spread(maker(a) as Expression);
   }
 
-  Instantiator visitNamedFunction(NamedFunction node) {
-    Instantiator makeDeclaration = visit(node.name);
-    Instantiator makeFunction = visit(node.function);
-    return (arguments) =>
-        new NamedFunction(makeDeclaration(arguments), makeFunction(arguments));
+  Instantiator<Yield> visitYield(Yield node) {
+    var maker = visitNullable(node.value);
+    return (a) => new Yield(maker(a) as Expression, star: node.star);
   }
 
-  Instantiator visitFunctionExpression(FunctionExpression node) {
-    List<Instantiator> paramMakers = node.params.map(visitSplayable).toList();
-    Instantiator makeBody = visit(node.body);
-    // TODO(sra): Avoid copying params if no interpolation or forced copying.
-    return (arguments) {
-      List<Parameter> params = <Parameter>[];
-      for (Instantiator instantiator in paramMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          for (var r in result) params.add(r);
-        } else {
-          params.add(result);
-        }
-      }
-      var body = makeBody(arguments);
-      if (node is ArrowFun) {
-        return new ArrowFun(params, body);
-      } else if (node is Fun) {
-        return new Fun(params, body,
-            isGenerator: node.isGenerator, asyncModifier: node.asyncModifier);
-      } else {
-        throw "Unknown FunctionExpression type ${node.runtimeType}: $node";
-      }
-    };
+  Instantiator<RestParameter> visitRestParameter(RestParameter node) {
+    var maker = visit(node.parameter);
+    return (a) => new RestParameter(maker(a) as Identifier);
   }
 
-  Instantiator visitFun(Fun node) => visitFunctionExpression(node);
+  Instantiator<PropertyAccess> visitAccess(PropertyAccess node) {
+    Instantiator<Expression> makeReceiver = visit(node.receiver);
+    Instantiator<Expression> makeSelector = visit(node.selector);
+    return (a) => new PropertyAccess(makeReceiver(a), makeSelector(a));
+  }
 
-  Instantiator visitArrowFun(ArrowFun node) => visitFunctionExpression(node);
+  Instantiator<NamedFunction> visitNamedFunction(NamedFunction node) {
+    Instantiator<Identifier> makeDeclaration = visit(node.name);
+    Instantiator<Fun> makeFunction = visit(node.function);
+    return (a) => new NamedFunction(makeDeclaration(a), makeFunction(a));
+  }
 
-  Instantiator visitLiteralBool(LiteralBool node) =>
-      (arguments) => new LiteralBool(node.value);
+  Instantiator<Fun> visitFun(Fun node) {
+    var paramMakers = node.params.map(visitSplayable).toList();
+    Instantiator<Block> makeBody = visit(node.body);
+    return (a) => new Fun(splayNodes(paramMakers, a), makeBody(a),
+        isGenerator: node.isGenerator, asyncModifier: node.asyncModifier);
+  }
 
-  Instantiator visitLiteralString(LiteralString node) =>
-      (arguments) => new LiteralString(node.value);
+  Instantiator<ArrowFun> visitArrowFun(ArrowFun node) {
+    var paramMakers = node.params.map(visitSplayable).toList();
+    Instantiator makeBody = visit(node.body as Node);
+    return (a) => new ArrowFun(splayNodes(paramMakers, a), makeBody(a));
+  }
 
-  Instantiator visitLiteralNumber(LiteralNumber node) =>
-      (arguments) => new LiteralNumber(node.value);
+  Instantiator<LiteralBool> visitLiteralBool(LiteralBool node) =>
+      (a) => new LiteralBool(node.value);
 
-  Instantiator visitLiteralNull(LiteralNull node) =>
-      (arguments) => new LiteralNull();
+  Instantiator<LiteralString> visitLiteralString(LiteralString node) =>
+      (a) => new LiteralString(node.value);
 
-  Instantiator visitArrayInitializer(ArrayInitializer node) {
-    List<Instantiator> elementMakers =
-        node.elements.map(visitSplayableExpression).toList(growable: false);
-    return (arguments) {
-      var elements = <Expression>[];
-      for (var instantiator in elementMakers) {
-        var element = instantiator(arguments);
-        if (element is Iterable) {
-          elements.addAll(element);
-        } else {
-          elements.add(element);
-        }
-      }
-      return new ArrayInitializer(elements);
-    };
+  Instantiator<LiteralNumber> visitLiteralNumber(LiteralNumber node) =>
+      (a) => new LiteralNumber(node.value);
+
+  Instantiator<LiteralNull> visitLiteralNull(LiteralNull node) =>
+      (a) => new LiteralNull();
+
+  Instantiator<ArrayInitializer> visitArrayInitializer(ArrayInitializer node) {
+    var makers = node.elements.map(visitSplayableExpression).toList();
+    return (a) => new ArrayInitializer(splayNodes(makers, a));
   }
 
   Instantiator visitArrayHole(ArrayHole node) {
     return (arguments) => new ArrayHole();
   }
 
-  Instantiator visitObjectInitializer(ObjectInitializer node) {
-    List<Instantiator> propertyMakers =
-        node.properties.map(visitSplayable).toList();
-    return (arguments) {
-      List<Property> properties = <Property>[];
-      for (Instantiator instantiator in propertyMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          for (var r in result) properties.add(r);
-        } else {
-          properties.add(result);
-        }
-      }
-      return new ObjectInitializer(properties);
-    };
+  Instantiator<ObjectInitializer> visitObjectInitializer(
+      ObjectInitializer node) {
+    var propertyMakers = node.properties.map(visitSplayable).toList();
+    return (a) => new ObjectInitializer(splayNodes(propertyMakers, a));
   }
 
-  Instantiator visitProperty(Property node) {
-    Instantiator makeName = visit(node.name);
-    Instantiator makeValue = visit(node.value);
-    return (arguments) {
-      return new Property(makeName(arguments), makeValue(arguments));
-    };
+  Instantiator<Property> visitProperty(Property node) {
+    Instantiator<Expression> makeName = visit(node.name);
+    Instantiator<Expression> makeValue = visit(node.value);
+    return (a) => new Property(makeName(a), makeValue(a));
   }
 
-  Instantiator visitRegExpLiteral(RegExpLiteral node) =>
-      (arguments) => new RegExpLiteral(node.pattern);
+  Instantiator<RegExpLiteral> visitRegExpLiteral(RegExpLiteral node) =>
+      (a) => new RegExpLiteral(node.pattern);
 
-  Instantiator visitTemplateString(TemplateString node) {
-    Iterable<Instantiator> makeElements = node.interpolations.map(visit);
-    return (arguments) => new TemplateString(node.strings,
-        makeElements.map((m) => m(arguments)).toList(growable: false));
+  Instantiator<TemplateString> visitTemplateString(TemplateString node) {
+    var makeElements = node.interpolations.map(visit).toList();
+    return (a) => new TemplateString(node.strings, splayNodes(makeElements, a));
   }
 
-  Instantiator visitTaggedTemplate(TaggedTemplate node) {
-    Instantiator makeTag = visit(node.tag);
-    Instantiator makeTemplate = visit(node.template);
-    return (arguments) {
-      return new TaggedTemplate(makeTag(arguments), makeTemplate(arguments));
-    };
+  Instantiator<TaggedTemplate> visitTaggedTemplate(TaggedTemplate node) {
+    Instantiator<Expression> makeTag = visit(node.tag);
+    var makeTemplate = visitTemplateString(node.template);
+    return (a) => new TaggedTemplate(makeTag(a), makeTemplate(a));
   }
 
   Instantiator visitClassDeclaration(ClassDeclaration node) {
-    Instantiator makeClass = visit(node.classExpr);
-    return (arguments) {
-      return new ClassDeclaration(makeClass(arguments));
-    };
+    var makeClass = visitClassExpression(node.classExpr);
+    return (a) => new ClassDeclaration(makeClass(a));
   }
 
-  Instantiator visitClassExpression(ClassExpression node) {
-    List<Instantiator> makeMethods =
-        node.methods.map(visitSplayableExpression).toList(growable: true);
-    Instantiator makeName = visit(node.name);
-    Instantiator makeHeritage = visit(node.heritage);
+  Instantiator<ClassExpression> visitClassExpression(ClassExpression node) {
+    var makeMethods = node.methods.map(visitSplayableExpression).toList();
+    Instantiator<Identifier> makeName = visit(node.name);
+    Instantiator<Expression> makeHeritage = visit(node.heritage);
 
-    return (arguments) {
-      var methods = <Method>[];
-      for (Instantiator instantiator in makeMethods) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          for (var r in result) methods.add(r);
-        } else {
-          methods.add(result);
-        }
-      }
-      return new ClassExpression(
-          makeName(arguments), makeHeritage(arguments), methods);
-    };
+    return (a) => new ClassExpression(
+        makeName(a), makeHeritage(a), splayNodes(makeMethods, a));
   }
 
-  Instantiator visitMethod(Method node) {
-    Instantiator makeName = visit(node.name);
-    Instantiator makeFunction = visit(node.function);
-    return (arguments) {
-      return new Method(makeName(arguments), makeFunction(arguments),
-          isGetter: node.isGetter,
-          isSetter: node.isSetter,
-          isStatic: node.isStatic);
-    };
+  Instantiator<Method> visitMethod(Method node) {
+    Instantiator<Expression> makeName = visit(node.name);
+    Instantiator<Fun> makeFunction = visit(node.function);
+    return (a) => new Method(makeName(a), makeFunction(a),
+        isGetter: node.isGetter,
+        isSetter: node.isSetter,
+        isStatic: node.isStatic);
   }
 
-  Instantiator visitComment(Comment node) =>
-      (arguments) => new Comment(node.comment);
+  Instantiator<Comment> visitComment(Comment node) =>
+      (a) => new Comment(node.comment);
 
-  Instantiator visitCommentExpression(CommentExpression node) {
-    Instantiator makeExpr = visit(node.expression);
-    return (arguments) {
-      return new CommentExpression(node.comment, makeExpr(arguments));
-    };
+  Instantiator<CommentExpression> visitCommentExpression(
+      CommentExpression node) {
+    Instantiator<Expression> makeExpr = visit(node.expression);
+    return (a) => new CommentExpression(node.comment, makeExpr(a));
   }
 
-  Instantiator visitAwait(Await node) {
-    Instantiator makeExpression = visit(node.expression);
-    return (arguments) {
-      return new Await(makeExpression(arguments));
-    };
+  Instantiator<Await> visitAwait(Await node) {
+    Instantiator<Expression> makeExpr = visit(node.expression);
+    return (a) => new Await(makeExpr(a));
   }
 
   // Note: these are not supported yet in the interpolation grammar.
@@ -856,39 +728,36 @@
       throw new UnimplementedError();
 
   @override
-  Instantiator visitDestructuredVariable(DestructuredVariable node) {
-    Instantiator makeName = visit(node.name);
-    Instantiator makeStructure = visit(node.structure);
-    Instantiator makeDefaultValue = visit(node.defaultValue);
-    return (arguments) {
-      return new DestructuredVariable(
-          name: makeName(arguments),
-          structure: makeStructure(arguments),
-          defaultValue: makeDefaultValue(arguments));
-    };
+  Instantiator<DestructuredVariable> visitDestructuredVariable(
+      DestructuredVariable node) {
+    Instantiator<Identifier> makeName = visitNullable(node.name);
+    Instantiator<Expression> makeProperty = visitNullable(node.property);
+    Instantiator<BindingPattern> makeStructure = visitNullable(node.structure);
+    Instantiator<Expression> makeDefaultValue =
+        visitNullable(node.defaultValue);
+    return (a) => new DestructuredVariable(
+        name: makeName(a),
+        property: makeProperty(a),
+        structure: makeStructure(a),
+        defaultValue: makeDefaultValue(a));
   }
 
   @override
-  Instantiator visitArrayBindingPattern(ArrayBindingPattern node) {
+  Instantiator<ArrayBindingPattern> visitArrayBindingPattern(
+      ArrayBindingPattern node) {
     List<Instantiator> makeVars = node.variables.map(this.visit).toList();
-    return (arguments) {
-      return new ArrayBindingPattern(
-          makeVars.map((m) => m(arguments) as DestructuredVariable).toList());
-    };
+    return (a) => new ArrayBindingPattern(splayNodes(makeVars, a));
   }
 
   @override
   Instantiator visitObjectBindingPattern(ObjectBindingPattern node) {
     List<Instantiator> makeVars = node.variables.map(this.visit).toList();
-    return (arguments) {
-      return new ObjectBindingPattern(
-          makeVars.map((m) => m(arguments) as DestructuredVariable).toList());
-    };
+    return (a) => new ObjectBindingPattern(splayNodes(makeVars, a));
   }
 
   @override
   Instantiator visitSimpleBindingPattern(SimpleBindingPattern node) =>
-      (arguments) => new SimpleBindingPattern(new Identifier(node.name.name));
+      (a) => new SimpleBindingPattern(new Identifier(node.name.name));
 }
 
 /**
@@ -918,7 +787,7 @@
 
   visitInterpolatedNode(InterpolatedNode node) {
     containsInterpolatedNode.add(node);
-    if (node.isNamed) holeNames.add(node.nameOrPosition);
+    if (node.isNamed) holeNames.add(node.nameOrPosition as String);
     ++count;
   }
 }
diff --git a/pkg/dev_compiler/lib/src/js_ast/type_printer.dart b/pkg/dev_compiler/lib/src/js_ast/type_printer.dart
index ff859aa..f0252c7 100644
--- a/pkg/dev_compiler/lib/src/js_ast/type_printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/type_printer.dart
@@ -100,7 +100,7 @@
       if (node.paramTypes == null) {
         out('...any');
       } else {
-        outSeparated(", ", node.paramTypes.keys, (name) {
+        outSeparated(", ", node.paramTypes.keys, (Identifier name) {
           var paramType = node.paramTypes[name];
           visit(name);
           _outTypeAnnotation(paramType);
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index bdc4519..f3f1108 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -132,7 +132,7 @@
   var declaredVariables = parseAndRemoveDeclaredVariables(args);
   var argResults = argParser.parse(args);
 
-  if (argResults['help'] || args.isEmpty) {
+  if (argResults['help'] as bool || args.isEmpty) {
     print(_usageMessage(argParser));
     return new CompilerResult.noState(true);
   }
@@ -140,8 +140,8 @@
   var moduleFormat = parseModuleFormatOption(argResults).first;
   var ddcPath = path.dirname(path.dirname(path.fromUri(Platform.script)));
 
-  var multiRoots = [];
-  for (var s in argResults['summary-input-dir']) {
+  var multiRoots = <Uri>[];
+  for (var s in argResults['summary-input-dir'] as List<String>) {
     var uri = stringToUri(s);
     if (!uri.path.endsWith('/')) {
       uri = uri.replace(path: '${uri.path}/');
@@ -150,15 +150,16 @@
   }
   multiRoots.add(Uri.base);
 
-  var customScheme = argResults['custom-app-scheme'];
-  var summaryUris = argResults['summary']
+  var customScheme = argResults['custom-app-scheme'] as String;
+  var summaryUris = (argResults['summary'] as List<String>)
       .map((s) => stringToCustomUri(s, multiRoots, customScheme))
       .toList();
 
-  var sdkSummaryPath = argResults['dart-sdk-summary'] ?? defaultSdkSummaryPath;
+  var sdkSummaryPath =
+      argResults['dart-sdk-summary'] as String ?? defaultSdkSummaryPath;
 
-  var packageFile =
-      argResults['packages'] ?? path.absolute(ddcPath, '..', '..', '.packages');
+  var packageFile = argResults['packages'] as String ??
+      path.absolute(ddcPath, '..', '..', '.packages');
 
   var inputs = argResults.rest
       .map((s) => stringToCustomUri(s, [Uri.base], customScheme))
@@ -203,7 +204,7 @@
   var jsModule = compileToJSModule(
       result.program, result.inputSummaries, summaryUris, declaredVariables);
   var jsCode = jsProgramToCode(jsModule, moduleFormat,
-      buildSourceMap: argResults['source-map'],
+      buildSourceMap: argResults['source-map'] as bool,
       jsUrl: path.toUri(output).toString(),
       mapUrl: path.toUri(output + '.map').toString(),
       customScheme: customScheme);
@@ -249,7 +250,7 @@
     String customScheme}) {
   var opts = new JS.JavaScriptPrintingOptions(
       allowKeywordsInProperties: true, allowSingleLineIfStatements: true);
-  var printer;
+  JS.SimpleJavaScriptPrintingContext printer;
   SourceMapBuilder sourceMap;
   if (buildSourceMap) {
     var sourceMapContext = new SourceMapPrintingContext();
@@ -293,7 +294,7 @@
   // Convert to a local file path if it's not.
   sourceMapPath = path.fromUri(_sourceToUri(sourceMapPath, customScheme));
   var sourceMapDir = path.dirname(path.absolute(sourceMapPath));
-  var list = new List.from(map['sources']);
+  var list = (map['sources'] as List).toList();
   map['sources'] = list;
 
   String makeRelative(String sourcePath) {
@@ -319,9 +320,9 @@
   }
 
   for (int i = 0; i < list.length; i++) {
-    list[i] = makeRelative(list[i]);
+    list[i] = makeRelative(list[i] as String);
   }
-  map['file'] = makeRelative(map['file']);
+  map['file'] = makeRelative(map['file'] as String);
   return map;
 }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index c8047fa..62ac08d 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -280,22 +280,29 @@
 
     // Initialize our library variables.
     var items = <JS.ModuleItem>[];
+    var exports = <JS.NameSpecifier>[];
+    var root = new JS.Identifier('_root');
+    items.add(js.statement('const # = Object.create(null)', [root]));
+
+    void emitLibrary(JS.Identifier id) {
+      items.add(js.statement('const # = Object.create(#)', [id, root]));
+      exports.add(new JS.NameSpecifier(id));
+    }
+
     for (var library in libraries) {
       var libraryTemp = library == ddcRuntime
           ? _runtimeModule
           : new JS.TemporaryId(jsLibraryName(library));
       _libraries[library] = libraryTemp;
-      items.add(new JS.ExportDeclaration(
-          js.call('const # = Object.create(null)', [libraryTemp])));
-
-      // dart:_runtime has a magic module that holds extension method symbols.
-      // TODO(jmesserly): find a cleaner design for this.
-      if (library == ddcRuntime) {
-        items.add(new JS.ExportDeclaration(js
-            .call('const # = Object.create(null)', [_extensionSymbolsModule])));
-      }
+      emitLibrary(libraryTemp);
     }
 
+    // dart:_runtime has a magic module that holds extension method symbols.
+    // TODO(jmesserly): find a cleaner design for this.
+    if (ddcRuntime != null) emitLibrary(_extensionSymbolsModule);
+
+    items.add(new JS.ExportDeclaration(new JS.ExportClause(exports)));
+
     // Collect all class/type Element -> Node mappings
     // in case we need to forward declare any classes.
     _pendingClasses = new HashSet.identity();
@@ -320,7 +327,7 @@
     _finishImports(items);
     // Initialize extension symbols
     _extensionSymbols.forEach((name, id) {
-      var value =
+      JS.Expression value =
           new JS.PropertyAccess(_extensionSymbolsModule, _propertyName(name));
       if (ddcRuntime != null) {
         value = js.call('# = Symbol(#)', [value, js.string("dartx.$name")]);
@@ -435,7 +442,8 @@
     } else {
       _emitLibraryProcedures(library);
       var fields = library.fields;
-      if (fields.isNotEmpty) _moduleItems.add(_emitLazyFields(library, fields));
+      if (fields.isNotEmpty)
+        _moduleItems.add(_emitLazyFields(emitLibraryName(library), fields));
     }
 
     _currentLibrary = null;
@@ -671,7 +679,7 @@
       return base;
     }
 
-    var mixins = [];
+    var mixins = <InterfaceType>[];
     var mixedInType = c.mixedInType;
     var superclass = c.superclass;
     var supertype = c.supertype.asInterfaceType;
@@ -1094,7 +1102,7 @@
             .toStatement());
       }
     } else if (fields.isNotEmpty) {
-      body.add(_emitLazyFields(c, fields));
+      body.add(_emitLazyFields(_emitTopLevelName(c), fields));
     }
   }
 
@@ -1443,7 +1451,7 @@
   }
 
   JS.Expression _finishConstructorFunction(
-      List<JS.Parameter> params, JS.Block body, isCallable) {
+      List<JS.Parameter> params, JS.Block body, bool isCallable) {
     // We consider a class callable if it inherits from anything with a `call`
     // method. As a result, we can know the callable JS function was created
     // at the first constructor that was hit.
@@ -1566,7 +1574,7 @@
       // Dart does not use ES6 constructors.
       // Add an error to catch any invalid usage.
       jsMethods.add(
-          new JS.Method(_propertyName('constructor'), js.call(r'''function() {
+          new JS.Method(_propertyName('constructor'), js.fun(r'''function() {
                   throw Error("use `new " + #.typeName(#.getReifiedType(this)) +
                       ".new(...)` to create a Dart object");
               }''', [_runtimeModule, _runtimeModule])));
@@ -1661,13 +1669,13 @@
   JS.Fun _emitNativeFunctionBody(Procedure node) {
     String name = getAnnotationName(node, isJSAnnotation) ?? node.name.name;
     if (node.isGetter) {
-      return new JS.Fun([], js.statement('{ return this.#; }', [name]));
+      return new JS.Fun([], js.block('{ return this.#; }', [name]));
     } else if (node.isSetter) {
       var params = _emitFormalParameters(node.function);
       return new JS.Fun(
-          params, js.statement('{ this.# = #; }', [name, params.last]));
+          params, js.block('{ this.# = #; }', [name, params.last]));
     } else {
-      return js.call(
+      return js.fun(
           'function (...args) { return this.#.apply(this, args); }', name);
     }
   }
@@ -1700,12 +1708,12 @@
       return [
         new JS.Method(
             name,
-            js.call('function(x) { return super.# = #._check(x); }', [
+            js.fun('function(x) { return super.# = #._check(x); }', [
               name,
               _emitType(superSubstition.substituteType(superMember.setterType))
             ]),
             isSetter: true),
-        new JS.Method(name, js.call('function() { return super.#; }', [name]),
+        new JS.Method(name, js.fun('function() { return super.#; }', [name]),
             isGetter: true)
       ];
     }
@@ -1866,7 +1874,7 @@
         fnBody = js.call('#._check(#)', [_emitType(returnType), fnBody]);
       }
 
-      var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
+      var fn = new JS.Fun(fnArgs, js.block('{ return #; }', [fnBody]),
           typeParams: typeParams);
 
       return new JS.Method(
@@ -1922,7 +1930,7 @@
 
     var mocks = _classProperties.mockMembers;
     if (!mocks.containsKey(field.name.name)) {
-      var getter = js.call('function() { return this[#]; }', [virtualField]);
+      var getter = js.fun('function() { return this[#]; }', [virtualField]);
       result.add(new JS.Method(name, getter, isGetter: true)
         ..sourceInformation = _nodeStart(field));
     }
@@ -1940,7 +1948,7 @@
         jsCode = 'function(value) { #[#] = value; }';
       }
 
-      result.add(new JS.Method(name, js.call(jsCode, args), isSetter: true)
+      result.add(new JS.Method(name, js.fun(jsCode, args), isSetter: true)
         ..sourceInformation = _nodeStart(field));
     }
 
@@ -1961,14 +1969,14 @@
 
     var name = getAnnotationName(field, isJSName) ?? field.name.name;
     // Generate getter
-    var fn = new JS.Fun([], js.statement('{ return this.#; }', [name]));
+    var fn = new JS.Fun([], js.block('{ return this.#; }', [name]));
     var method = new JS.Method(_declareMemberName(field), fn, isGetter: true);
     jsMethods.add(method);
 
     // Generate setter
     if (!field.isFinal) {
       var value = new JS.TemporaryId('value');
-      fn = new JS.Fun([value], js.statement('{ this.# = #; }', [name, value]));
+      fn = new JS.Fun([value], js.block('{ this.# = #; }', [name, value]));
       method = new JS.Method(_declareMemberName(field), fn, isSetter: true);
       jsMethods.add(method);
     }
@@ -1990,7 +1998,7 @@
       if (!setters.containsKey(name) &&
           _classProperties.inheritedSetters.contains(name)) {
         // Generate a setter that forwards to super.
-        var fn = js.call('function(value) { super[#] = value; }', [memberName]);
+        var fn = js.fun('function(value) { super[#] = value; }', [memberName]);
         return new JS.Method(memberName, fn, isSetter: true);
       }
     } else {
@@ -1998,7 +2006,7 @@
       if (!getters.containsKey(name) &&
           _classProperties.inheritedGetters.contains(name)) {
         // Generate a getter that forwards to super.
-        var fn = js.call('function() { return super[#]; }', [memberName]);
+        var fn = js.fun('function() { return super[#]; }', [memberName]);
         return new JS.Method(memberName, fn, isGetter: true);
       }
     }
@@ -2118,7 +2126,7 @@
       var init = field.initializer;
       if (init == null ||
           init is BasicLiteral ||
-          _isInlineJSCall(init) ||
+          init is StaticInvocation && isInlineJS(init.target) ||
           init is ConstructorInvocation &&
               isSdkInternalRuntime(init.target.enclosingLibrary)) {
         _currentUri = field.fileUri;
@@ -2132,16 +2140,13 @@
     }
 
     _currentUri = savedUri;
-    return _emitLazyFields(_currentLibrary, lazyFields);
+    return _emitLazyFields(emitLibraryName(_currentLibrary), lazyFields);
   }
 
-  JS.Statement _emitLazyFields(NamedNode target, Iterable<Field> fields) {
+  JS.Statement _emitLazyFields(JS.Expression objExpr, Iterable<Field> fields) {
     var accessors = <JS.Method>[];
     var savedUri = _currentUri;
 
-    var objExpr =
-        target is Class ? _emitTopLevelName(target) : emitLibraryName(target);
-
     for (var field in fields) {
       _currentUri = field.fileUri;
       var name = field.name.name;
@@ -2437,16 +2442,19 @@
     return libraryJSName != null ? '$libraryJSName.$jsName' : jsName;
   }
 
-  JS.Expression _emitJSInterop(NamedNode n) {
+  JS.PropertyAccess _emitJSInterop(NamedNode n) {
     var jsName = _getJSNameWithoutGlobal(n);
     if (jsName == null) return null;
     return _emitJSInteropForGlobal(jsName);
   }
 
-  JS.Expression _emitJSInteropForGlobal(String name) {
-    var access = _callHelper('global');
-    for (var part in name.split('.')) {
-      access = new JS.PropertyAccess(access, js.escapedString(part, "'"));
+  JS.PropertyAccess _emitJSInteropForGlobal(String name) {
+    var parts = name.split('.');
+    if (parts.isEmpty) parts = [''];
+    JS.PropertyAccess access;
+    for (var part in parts) {
+      access = new JS.PropertyAccess(
+          access ?? _callHelper('global'), js.escapedString(part, "'"));
     }
     return access;
   }
@@ -2510,7 +2518,7 @@
   }
 
   JS.Expression _emitFunctionTagged(JS.Expression fn, FunctionType type,
-      {topLevel: false}) {
+      {bool topLevel: false}) {
     var lazy = topLevel && !_typeIsLoaded(type);
     var typeRep = visitFunctionType(type);
     return _callHelper(lazy ? 'lazyFn(#, () => #)' : 'fn(#, #)', [fn, typeRep]);
@@ -2533,7 +2541,7 @@
   }
 
   /// Emits a Dart [type] into code.
-  JS.Expression _emitType(DartType type) => type.accept(this);
+  JS.Expression _emitType(DartType type) => type.accept(this) as JS.Expression;
 
   JS.Expression _emitInvalidNode(Node node, [String message = '']) {
     if (message.isNotEmpty) message += ' ';
@@ -2588,7 +2596,7 @@
     }
 
     var args = type.typeArguments;
-    Iterable jsArgs = null;
+    Iterable<JS.Expression> jsArgs = null;
     if (args.any((a) => a != const DynamicType())) {
       jsArgs = args.map(_emitType);
     } else if (lowerGeneric) {
@@ -2729,9 +2737,9 @@
   @override
   visitTypedefType(type, {bool lowerGeneric: false}) {
     var args = type.typeArguments;
-    Iterable jsArgs = null;
+    List<JS.Expression> jsArgs = null;
     if (args.any((a) => a != const DynamicType())) {
-      jsArgs = args.map(_emitType);
+      jsArgs = args.map(_emitType).toList();
     } else if (lowerGeneric) {
       jsArgs = [];
     }
@@ -2797,7 +2805,7 @@
     });
   }
 
-  List<JS.Parameter> _emitTypeFormals(List<TypeParameter> typeFormals) {
+  List<JS.Identifier> _emitTypeFormals(List<TypeParameter> typeFormals) {
     return typeFormals
         .map((t) => new JS.Identifier(getTypeParameterName(t)))
         .toList();
@@ -2807,7 +2815,7 @@
     // Transforms `sync*` `async` and `async*` function bodies
     // using ES6 generators.
 
-    emitGeneratorFn(Iterable<JS.Expression> getParameters(JS.Block jsBody)) {
+    emitGeneratorFn(List<JS.Parameter> getParameters(JS.Block jsBody)) {
       var savedController = _asyncStarController;
       _asyncStarController = function.asyncMarker == AsyncMarker.AsyncStar
           ? new JS.TemporaryId('stream')
@@ -2820,12 +2828,15 @@
         // TODO(jmesserly): this will emit argument initializers (for default
         // values) inside the generator function body. Is that the best place?
         var jsBody = _emitFunctionBody(function);
-        gen = new JS.Fun(getParameters(jsBody), jsBody, isGenerator: true);
+        var genFn =
+            new JS.Fun(getParameters(jsBody), jsBody, isGenerator: true);
 
         // Name the function if possible, to get better stack traces.
+        gen = genFn;
         if (name != null) {
-          name = JS.friendlyNameForDartOperator[name] ?? name;
-          gen = new JS.NamedFunction(new JS.TemporaryId(name), gen);
+          gen = new JS.NamedFunction(
+              new JS.TemporaryId(JS.friendlyNameForDartOperator[name] ?? name),
+              genFn);
         }
 
         gen.sourceInformation = _nodeEnd(function.fileEndOffset);
@@ -3065,7 +3076,7 @@
 
   JS.Statement _visitStatement(Statement s) {
     if (s == null) return null;
-    var result = s.accept(this);
+    var result = s.accept(this) as JS.Statement;
     // TODO(jmesserly): is the `is! Block` still necessary?
     if (s is! Block) result.sourceInformation = _nodeStart(s);
 
@@ -3122,10 +3133,12 @@
       if (op == '||') return shortCircuit('# || #');
     }
 
-    var result = _visitExpression(node);
-    if (node.getStaticType(types) != coreTypes.boolClass.rawType) {
-      return _callHelper('dtest(#)', result);
+    if (node is AsExpression && node.isTypeError) {
+      assert(node.getStaticType(types) == types.boolType);
+      return _callHelper('dtest(#)', _visitExpression(node.operand));
     }
+
+    var result = _visitExpression(node);
     if (isNullable(node)) result = _callHelper('test(#)', result);
     return result;
   }
@@ -3196,9 +3209,9 @@
   @override
   visitExpressionStatement(ExpressionStatement node) {
     var expr = node.expression;
-    if (_isInlineJSCall(expr)) {
+    if (expr is StaticInvocation && isInlineJS(expr.target)) {
       var inlineJS = _emitInlineJSCode(expr);
-      return inlineJS is JS.Expression ? inlineJS.toStatement() : inlineJS;
+      return inlineJS is JS.Statement ? inlineJS : inlineJS.toStatement();
     }
     return _visitExpression(expr).toStatement();
   }
@@ -3235,7 +3248,7 @@
     ]);
   }
 
-  static isBreakable(Statement stmt) {
+  static bool isBreakable(Statement stmt) {
     // These are conservatively the things that compile to things that can be
     // the target of a break without a label.
     return stmt is ForStatement ||
@@ -3247,7 +3260,7 @@
 
   @override
   visitLabeledStatement(LabeledStatement node) {
-    var saved;
+    List<LabeledStatement> saved;
     var target = _effectiveTargets[node];
     // If the effective target is known then this statement is either contained
     // in a labeled statement or a loop.  It has already been processed when
@@ -3258,8 +3271,9 @@
       var statements = [node];
       target = node.body;
       while (target is LabeledStatement) {
-        statements.add(target);
-        target = (target as LabeledStatement).body;
+        var labeled = target as LabeledStatement;
+        statements.add(labeled);
+        target = labeled.body;
       }
       for (var statement in statements) _effectiveTargets[statement] = target;
 
@@ -3301,9 +3315,9 @@
 
     // It is a break if the target labeled statement encloses the effective
     // target.
-    var current = node.target;
+    Statement current = node.target;
     while (current is LabeledStatement) {
-      current = current.body;
+      current = (current as LabeledStatement).body;
     }
     if (identical(current, target)) {
       return new JS.Break(name);
@@ -3321,15 +3335,16 @@
     // it is not possible to continue to an outer loop without a label.
     _currentContinueTargets = <LabeledStatement>[];
     while (body is LabeledStatement) {
-      _currentContinueTargets.add(body);
-      _effectiveTargets[body] = loop;
-      body = (body as LabeledStatement).body;
+      var labeled = body as LabeledStatement;
+      _currentContinueTargets.add(labeled);
+      _effectiveTargets[labeled] = loop;
+      body = labeled.body;
     }
     return body;
   }
 
-  JS.Statement translateLoop(Statement node, JS.Statement action()) {
-    var savedBreakTargets;
+  T translateLoop<T extends JS.Statement>(Statement node, T action()) {
+    List<LabeledStatement> savedBreakTargets;
     if (_currentBreakTargets.isNotEmpty &&
         _effectiveTargets[_currentBreakTargets.first] != node) {
       // If breaking without a label targets some other (outer) loop, then
@@ -3458,19 +3473,19 @@
 
   @override
   visitSwitchStatement(SwitchStatement node) {
-    var cases = <JS.SwitchClause>[];
+    var cases = <JS.SwitchCase>[];
     var emptyBlock = new JS.Block.empty();
     for (var c in node.cases) {
       // TODO(jmesserly): make sure we are statically checking fall through
-      var body = _visitStatement(c.body);
+      var body = _visitStatement(c.body).toBlock();
       var expressions = c.expressions;
       var last =
           expressions.isNotEmpty && !c.isDefault ? expressions.last : null;
       for (var e in expressions) {
         var jsExpr = _visitExpression(e);
-        cases.add(new JS.Case(jsExpr, e == last ? body : emptyBlock));
+        cases.add(new JS.SwitchCase(jsExpr, e == last ? body : emptyBlock));
       }
-      if (c.isDefault) cases.add(new JS.Default(body));
+      if (c.isDefault) cases.add(new JS.SwitchCase.defaultCase(body));
     }
 
     return new JS.Switch(_visitExpression(node.expression), cases);
@@ -3930,7 +3945,9 @@
       Expression node, JS.Expression uncoerced) {
     // Don't coerce if the parent will coerce.
     var parent = node.parent;
-    if (_nodeIsBitwiseOperation(parent)) return uncoerced;
+    if (parent is InvocationExpression && _nodeIsBitwiseOperation(parent)) {
+      return uncoerced;
+    }
 
     // Don't do a no-op coerce if the most significant bit is zero.
     if (_is31BitUnsigned(node)) return uncoerced;
@@ -3958,15 +3975,13 @@
     return js.call('# >>> 0', uncoerced);
   }
 
-  bool _nodeIsBitwiseOperation(Node node) {
-    if (node is InvocationExpression) {
-      switch (node.name.name) {
-        case '&':
-        case '|':
-        case '^':
-        case '~':
-          return true;
-      }
+  bool _nodeIsBitwiseOperation(InvocationExpression node) {
+    switch (node.name.name) {
+      case '&':
+      case '|':
+      case '^':
+      case '~':
+        return true;
     }
     return false;
   }
@@ -3984,17 +3999,15 @@
     if (expr is IntLiteral) return expr.value >= 0;
 
     // TODO(sra): Lengths of known list types etc.
-    return _nodeIsBitwiseOperation(expr);
+    return expr is InvocationExpression && _nodeIsBitwiseOperation(expr);
   }
 
   /// Does the parent of [node] mask the result to [width] bits or fewer?
   bool _parentMasksToWidth(Expression node, int width) {
     var parent = node.parent;
     if (parent == null) return false;
-    if (_nodeIsBitwiseOperation(parent)) {
-      if (parent is InvocationExpression &&
-          parent.name.name == '&' &&
-          parent.arguments.positional.length == 1) {
+    if (parent is InvocationExpression && _nodeIsBitwiseOperation(parent)) {
+      if (parent.name.name == '&' && parent.arguments.positional.length == 1) {
         var left = getInvocationReceiver(parent);
         var right = parent.arguments.positional[0];
         final int MAX = (1 << width) - 1;
@@ -4253,7 +4266,7 @@
         assert(member is Procedure
             ? member.isSetter == setter
             : !setter || !(member as Field).isFinal);
-        var fn = js.call(
+        var fn = js.fun(
             setter
                 ? 'function(x) { super[#] = x; }'
                 : 'function() { return super[#]; }',
@@ -4271,7 +4284,7 @@
           params.add(namedArgumentTemp);
         }
 
-        var fn = js.call(
+        var fn = js.fun(
             'function(#) { return super[#](#); }', [params, jsName, params]);
         name = JS.friendlyNameForDartOperator[name] ?? name;
         return new JS.Method(new JS.TemporaryId(name), fn);
@@ -4283,7 +4296,7 @@
   @override
   visitStaticInvocation(StaticInvocation node) {
     var target = node.target;
-    if (isInlineJS(target)) return _emitInlineJSCode(node);
+    if (isInlineJS(target)) return _emitInlineJSCode(node) as JS.Expression;
     if (target.isFactory) return _emitFactoryInvocation(node);
 
     if (target.name.name == 'extensionSymbol' &&
@@ -4324,8 +4337,7 @@
       if (arg is StaticInvocation &&
           isJSSpreadInvocation(arg.target) &&
           arg.arguments.positional.length == 1) {
-        args.add(new JS.RestParameter(
-            _visitExpression(arg.arguments.positional[0])));
+        args.add(new JS.Spread(_visitExpression(arg.arguments.positional[0])));
       } else {
         args.add(_visitExpression(arg));
       }
@@ -4640,7 +4652,8 @@
       _visitTest(node.condition),
       _visitExpression(node.then),
       _visitExpression(node.otherwise)
-    ]);
+    ])
+      ..sourceInformation = _nodeStart(node.condition);
   }
 
   @override
@@ -4864,7 +4877,8 @@
     }
 
     if (!node.isConst) {
-      var mapType = _emitMapImplType(node.getStaticType(types));
+      var mapType =
+          _emitMapImplType(node.getStaticType(types) as InterfaceType);
       if (node.entries.isEmpty) {
         return js.call('new #.new()', [mapType]);
       }
@@ -4882,7 +4896,7 @@
   visitFunctionExpression(FunctionExpression node) {
     var fn = _emitArrowFunction(node);
     if (!_reifyFunctionType(_currentFunction)) return fn;
-    return _emitFunctionTagged(fn, node.getStaticType(types));
+    return _emitFunctionTagged(fn, node.getStaticType(types) as FunctionType);
   }
 
   JS.ArrowFun _emitArrowFunction(FunctionExpression node) {
@@ -5064,12 +5078,13 @@
     if (statements.length != 1) return false;
     body = statements[0];
   }
-  return body is ReturnStatement && _isInlineJSCall(body.expression);
+  if (body is ReturnStatement) {
+    var expr = body.expression;
+    return expr is StaticInvocation && isInlineJS(expr.target);
+  }
+  return false;
 }
 
-bool _isInlineJSCall(Expression expr) =>
-    expr is StaticInvocation && isInlineJS(expr.target);
-
 /// Return true if this is one of the methods/properties on all Dart Objects
 /// (toString, hashCode, noSuchMethod, runtimeType).
 ///
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 2571702..c16ad0d 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -9,12 +9,12 @@
 Constructor unnamedConstructor(Class c) =>
     c.constructors.firstWhere((c) => c.name.name == '', orElse: () => null);
 
-/// Returns the enclosing library for reference [r].
-Library getLibrary(NamedNode n) {
-  while (n != null && n is! Library) {
-    n = n.parent;
+/// Returns the enclosing library for reference [node].
+Library getLibrary(NamedNode node) {
+  for (TreeNode n = node; n != null; n = n.parent) {
+    if (n is Library) return n;
   }
-  return n;
+  return null;
 }
 
 final Pattern _syntheticTypeCharacters = new RegExp('[&^#.]');
@@ -132,7 +132,7 @@
   final CoreTypes coreTypes;
   ConstantVisitor(this.coreTypes);
 
-  bool isConstant(Expression e) => e.accept(this);
+  bool isConstant(Expression e) => e.accept(this) as bool;
 
   defaultExpression(node) => false;
   defaultBasicLiteral(node) => true;
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index bdfd687..0dd31c6 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -53,7 +53,8 @@
   void exitFunction(FunctionNode fn) => _variableInference.exitFunction(fn);
 
   /// Returns true if [expr] can be null.
-  bool isNullable(Expression expr) => expr != null ? expr.accept(this) : false;
+  bool isNullable(Expression expr) =>
+      expr != null ? expr.accept(this) as bool : false;
 
   @override
   defaultExpression(Expression node) => true;
diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart
index 76e9761..84fc2e4 100644
--- a/pkg/dev_compiler/lib/src/kernel/property_model.dart
+++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart
@@ -82,11 +82,14 @@
     // Class can only look up inherited members with an O(N) scan through
     // the class, so we build up a mapping of all fields in the library ahead of
     // time.
-    var allFields = new HashMap<Class, HashMap<String, Field>>.fromIterable(
-        allClasses,
-        value: (t) => new HashMap.fromIterable(
-            t.fields.where((f) => !f.isStatic),
-            key: (f) => f.name));
+    Map<String, Field> getInstanceFieldMap(Class c) {
+      var instanceFields = c.fields.where((f) => !f.isStatic);
+      return new HashMap.fromIterables(
+          instanceFields.map((f) => f.name.name), instanceFields);
+    }
+
+    var allFields = new HashMap.fromIterables(
+        allClasses, allClasses.map(getInstanceFieldMap));
 
     for (var class_ in allClasses) {
       Set<Class> superclasses = null;
diff --git a/pkg/dev_compiler/lib/src/kernel/type_table.dart b/pkg/dev_compiler/lib/src/kernel/type_table.dart
index 3eede2c..bfb5e9c 100644
--- a/pkg/dev_compiler/lib/src/kernel/type_table.dart
+++ b/pkg/dev_compiler/lib/src/kernel/type_table.dart
@@ -113,7 +113,7 @@
 
   /// Heuristically choose a good name for the cache and generator
   /// variables.
-  JS.Identifier chooseTypeName(DartType type) {
+  JS.TemporaryId chooseTypeName(DartType type) {
     return new JS.TemporaryId(_typeString(type));
   }
 }
diff --git a/pkg/dev_compiler/test/codegen_test.dart b/pkg/dev_compiler/test/codegen_test.dart
index 6e270c9..d8327f4 100644
--- a/pkg/dev_compiler/test/codegen_test.dart
+++ b/pkg/dev_compiler/test/codegen_test.dart
@@ -14,13 +14,7 @@
 
 import 'dart:convert';
 import 'dart:io' show Directory, File, Platform;
-import 'package:analyzer/analyzer.dart'
-    show
-        ExportDirective,
-        ImportDirective,
-        StringLiteral,
-        UriBasedDirective,
-        parseDirectives;
+import 'package:analyzer/analyzer.dart' show StringLiteral, parseDirectives;
 import 'package:analyzer/src/command_line/arguments.dart'
     show defineAnalysisArguments;
 import 'package:analyzer/src/dart/ast/ast.dart';
@@ -431,7 +425,7 @@
 
   var unit = parseDirectives(contents, name: from, suppressErrors: true);
   for (var d in unit.directives) {
-    if (d is ImportDirective || d is ExportDirective) {
+    if (d is NamespaceDirectiveImpl) {
       String uri = _resolveDirective(d);
       if (uri == null ||
           uri.startsWith('dart:') ||
@@ -449,14 +443,12 @@
 }
 
 /// Simplified from ParseDartTask.resolveDirective.
-String _resolveDirective(UriBasedDirective directive) {
+String _resolveDirective(NamespaceDirectiveImpl directive) {
   StringLiteral uriLiteral = directive.uri;
   String uriContent = uriLiteral.stringValue;
   if (uriContent != null) {
     uriContent = uriContent.trim();
     directive.uriContent = uriContent;
   }
-  return (directive as UriBasedDirectiveImpl).validate() == null
-      ? uriContent
-      : null;
+  return directive.validate() == null ? uriContent : null;
 }
diff --git a/pkg/dev_compiler/test/js/builder_test.dart b/pkg/dev_compiler/test/js/builder_test.dart
index c02909c..6604d4a 100644
--- a/pkg/dev_compiler/test/js/builder_test.dart
+++ b/pkg/dev_compiler/test/js/builder_test.dart
@@ -3,7 +3,7 @@
 
 final _prenumberedPlaceholders = new RegExp(r'#\d+');
 
-_parser(String src) =>
+MiniJsParser _parser(String src) =>
     new MiniJsParser(src.replaceAll(_prenumberedPlaceholders, '#'));
 
 _check(Node node, String expected) =>
diff --git a/pkg/dev_compiler/test/sourcemap/common.dart b/pkg/dev_compiler/test/sourcemap/common.dart
index 4945d20..3170c17 100644
--- a/pkg/dev_compiler/test/sourcemap/common.dart
+++ b/pkg/dev_compiler/test/sourcemap/common.dart
@@ -67,7 +67,7 @@
     var outWrapperPath = path.join(data.outDir.path, "wrapper.js");
     ProcessResult runResult =
         runD8AndStep(data.outDir.path, data.code, ['--module', outWrapperPath]);
-    data.d8Output = runResult.stdout.split("\n");
+    data.d8Output = (runResult.stdout as String).split("\n");
     return pass(data);
   }
 }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart
index 7e78059..f44926d 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart
@@ -19,6 +19,6 @@
   /*bc:12*/ print(g);
 }
 
-foo() {
+int foo() {
   return 42;
 }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/step_through_conditional_expression.dart b/pkg/dev_compiler/test/sourcemap/testfiles/step_through_conditional_expression.dart
index 8d68e54..8ea00cf 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/step_through_conditional_expression.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/step_through_conditional_expression.dart
@@ -9,7 +9,7 @@
   print(/*bc:4*/ ! /*bc:3*/ foo() ? /*bc:5*/ bar() : baz());
 }
 
-foo() {
+bool foo() {
   return false;
 }
 
diff --git a/pkg/dev_compiler/test/testing.dart b/pkg/dev_compiler/test/testing.dart
index f5b8034..d350f57 100644
--- a/pkg/dev_compiler/test/testing.dart
+++ b/pkg/dev_compiler/test/testing.dart
@@ -21,9 +21,7 @@
 
 class TestUriResolver extends ResourceUriResolver {
   final MemoryResourceProvider provider;
-  TestUriResolver(provider)
-      : provider = provider,
-        super(provider);
+  TestUriResolver(this.provider) : super(provider);
 
   @override
   Source resolveAbsolute(Uri uri, [Uri actualUri]) {
diff --git a/pkg/dev_compiler/tool/build_pkgs.dart b/pkg/dev_compiler/tool/build_pkgs.dart
index 7662b36..904aad3 100755
--- a/pkg/dev_compiler/tool/build_pkgs.dart
+++ b/pkg/dev_compiler/tool/build_pkgs.dart
@@ -65,10 +65,10 @@
         argParser, 'Unexpected arguments "${argResults.rest.join(' ')}".');
   }
 
-  var isTravis = argResults["travis"];
-  analyzerSummary = argResults["analyzer-sdk"];
-  kernelSummary = argResults["kernel-sdk"];
-  outputDirectory = argResults["output"];
+  var isTravis = argResults["travis"] as bool;
+  analyzerSummary = argResults["analyzer-sdk"] as String;
+  kernelSummary = argResults["kernel-sdk"] as String;
+  outputDirectory = argResults["output"] as String;
 
   new Directory(pkgDirectory).createSync(recursive: true);
 
diff --git a/pkg/dev_compiler/tool/global_compile.dart b/pkg/dev_compiler/tool/global_compile.dart
index c480116..1f344c5 100644
--- a/pkg/dev_compiler/tool/global_compile.dart
+++ b/pkg/dev_compiler/tool/global_compile.dart
@@ -6,14 +6,7 @@
 import 'dart:async';
 import 'dart:io';
 
-import 'package:analyzer/analyzer.dart'
-    show
-        ExportDirective,
-        ImportDirective,
-        PartDirective,
-        StringLiteral,
-        UriBasedDirective,
-        parseDirectives;
+import 'package:analyzer/analyzer.dart' show StringLiteral, parseDirectives;
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:args/args.dart' show ArgParser;
 import 'package:path/path.dart' as path;
@@ -252,16 +245,14 @@
 }
 
 /// Simplified from ParseDartTask.resolveDirective.
-String _resolveDirective(UriBasedDirective directive) {
+String _resolveDirective(UriBasedDirectiveImpl directive) {
   StringLiteral uriLiteral = directive.uri;
   String uriContent = uriLiteral.stringValue;
   if (uriContent != null) {
     uriContent = uriContent.trim();
     directive.uriContent = uriContent;
   }
-  return (directive as UriBasedDirectiveImpl).validate() == null
-      ? uriContent
-      : null;
+  return directive.validate() == null ? uriContent : null;
 }
 
 String _loadFile(String uri, String packageRoot) {
@@ -280,11 +271,11 @@
     var entryDir = path.dirname(entryPoint);
     var unit = parseDirectives(source, name: entryPoint, suppressErrors: true);
     for (var d in unit.directives) {
-      if (d is ImportDirective || d is ExportDirective) {
+      if (d is NamespaceDirectiveImpl) {
         var uri = _resolveDirective(d);
         processDependence(entryPoint, canonicalize(uri, entryDir));
         transitiveFiles(uri, entryDir, packageRoot);
-      } else if (d is PartDirective) {
+      } else if (d is PartDirectiveImpl) {
         var uri = _resolveDirective(d);
         processFile(canonicalize(uri, entryDir));
       }
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index b78c49f..9f59400 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -15,7 +15,7 @@
   final bool isGetter;
   final bool isSetter;
 
-  InvocationImpl(memberName, this.positionalArguments,
+  InvocationImpl(memberName, List<Object> positionalArguments,
       {namedArguments,
       List typeArguments,
       this.isMethod: false,
@@ -23,6 +23,7 @@
       this.isSetter: false})
       : memberName =
             isSetter ? _setterSymbol(memberName) : _dartSymbol(memberName),
+        positionalArguments = new List.unmodifiable(positionalArguments),
         namedArguments = _namedArgsToSymbols(namedArguments),
         typeArguments = typeArguments == null
             ? const []
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
index f1d4f56..44f9f8b 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
@@ -37,7 +37,7 @@
 final Function(Object, Object) getOwnPropertyDescriptor =
     JS('', 'Object.getOwnPropertyDescriptor');
 
-final Function(Object) getOwnPropertyNames =
+final Iterable Function(Object) getOwnPropertyNames =
     JS('', 'Object.getOwnPropertyNames');
 
 final Function(Object) getOwnPropertySymbols =
diff --git a/pkg/dev_compiler/tool/patch_sdk.dart b/pkg/dev_compiler/tool/patch_sdk.dart
index b1a4bcc4..6032c60 100755
--- a/pkg/dev_compiler/tool/patch_sdk.dart
+++ b/pkg/dev_compiler/tool/patch_sdk.dart
@@ -10,6 +10,7 @@
 import 'dart:math' as math;
 
 import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:path/path.dart' as path;
 
@@ -66,7 +67,7 @@
 
     var libraryOut = path.join(sdkLibIn, library.path);
     var libraryOverride = path.join(patchDir, 'lib', library.path);
-    var libraryIn;
+    String libraryIn;
     if (library.path.contains(INTERNAL_PATH)) {
       libraryIn =
           path.join(privateIn, library.path.replaceAll(INTERNAL_PATH, ''));
@@ -265,10 +266,10 @@
     }
   }
 
-  void _maybePatch(AstNode node) {
+  void _maybePatch(Declaration node) {
     if (node is FieldDeclaration) return;
 
-    var externalKeyword = (node as dynamic).externalKeyword;
+    Token externalKeyword = (node as dynamic).externalKeyword;
     if (externalKeyword == null) return;
 
     var name = _qualifiedName(node);
@@ -303,9 +304,9 @@
   final String contents;
   final CompilationUnit unit;
 
-  final Map patches = <String, Declaration>{};
-  final Map mergeMembers = <String, List<ClassMember>>{};
-  final List mergeDeclarations = <CompilationUnitMember>[];
+  final patches = <String, Declaration>{};
+  final mergeMembers = <String, List<ClassMember>>{};
+  final mergeDeclarations = <CompilationUnitMember>[];
 
   PatchFinder.parseAndVisit(String contents)
       : contents = contents,
@@ -358,12 +359,12 @@
     result = "${parent.name.name}.";
   }
 
-  var name = (node as dynamic).name;
+  SimpleIdentifier name = (node as dynamic).name;
   if (name != null) result += name.name;
 
   // Make sure setters and getters don't collide.
-  if ((node is FunctionDeclaration || node is MethodDeclaration) &&
-      (node as dynamic).isSetter) {
+  if (node is FunctionDeclaration && node.isSetter ||
+      node is MethodDeclaration && node.isSetter) {
     result += "=";
   }
 
diff --git a/pkg/dev_compiler/web/stack_trace_mapper.dart b/pkg/dev_compiler/web/stack_trace_mapper.dart
index 89b2389..a5cdd4d 100644
--- a/pkg/dev_compiler/web/stack_trace_mapper.dart
+++ b/pkg/dev_compiler/web/stack_trace_mapper.dart
@@ -75,11 +75,8 @@
     if (!_bundle.containsMapping(uri)) {
       var rawMap = _provider(uri);
       if (rawMap != null) {
-        if (rawMap is! String) {
-          // The sourcemap was passed as regular JavaScript JSON.
-          rawMap = _stringify(rawMap);
-        }
-        SingleMapping mapping = parse(rawMap);
+        var strMap = rawMap is String ? rawMap : _stringify(rawMap);
+        var mapping = parse(strMap) as SingleMapping;
         mapping
           ..targetUrl = uri
           ..sourceRoot = '${path.dirname(uri)}/';
diff --git a/pkg/front_end/lib/src/api_prototype/kernel_generator.dart b/pkg/front_end/lib/src/api_prototype/kernel_generator.dart
index 753cb83..ddf30e1 100644
--- a/pkg/front_end/lib/src/api_prototype/kernel_generator.dart
+++ b/pkg/front_end/lib/src/api_prototype/kernel_generator.dart
@@ -13,9 +13,7 @@
 
 import '../fasta/compiler_context.dart' show CompilerContext;
 
-import '../fasta/fasta_codes.dart' show messageMissingMain;
-
-import '../fasta/parser.dart' show noLength;
+import '../fasta/fasta_codes.dart' show messageMissingMain, noLength;
 
 import '../fasta/severity.dart' show Severity;
 
diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart
index 57f3e25..bad1ff9 100644
--- a/pkg/front_end/lib/src/api_unstable/dart2js.dart
+++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart
@@ -17,9 +17,7 @@
 
 import '../fasta/compiler_context.dart' show CompilerContext;
 
-import '../fasta/fasta_codes.dart' show messageMissingMain;
-
-import '../fasta/parser.dart' show noLength;
+import '../fasta/fasta_codes.dart' show messageMissingMain, noLength;
 
 import '../fasta/severity.dart' show Severity;
 
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index 78da339..6739a47 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -44,6 +44,7 @@
         messageCantInferPackagesFromPackageUri,
         messageInternalProblemProvidedBothCompileSdkAndSdkSummary,
         messageMissingInput,
+        noLength,
         templateCannotReadPackagesFile,
         templateCannotReadSdkSpecification,
         templateInputFileNotFound,
@@ -54,8 +55,6 @@
 
 import '../fasta/messages.dart' show getLocation;
 
-import '../fasta/parser.dart' show noLength;
-
 import '../fasta/problems.dart' show unimplemented;
 
 import '../fasta/severity.dart' show Severity;
@@ -233,32 +232,9 @@
     if (_reportMessages) command_line_reporting.report(message, severity);
   }
 
+  // TODO(askesc): Remove this and direct callers directly to report.
   void reportWithoutLocation(Message message, Severity severity) {
-    if (_raw.onProblem != null) {
-      _raw.onProblem(
-          message.withLocation(null, -1, noLength),
-          severity,
-          command_line_reporting.formatWithoutLocation(message, severity),
-          -1,
-          -1);
-      if (command_line_reporting.shouldThrowOn(severity)) {
-        if (verbose) print(StackTrace.current);
-        throw new deprecated_InputError(
-            null,
-            -1,
-            "Compilation aborted due to fatal "
-            "${command_line_reporting.severityName(severity)}.");
-      }
-      return;
-    }
-    if (_raw.onError != null) {
-      _raw.onError(new _CompilationMessage(
-          message.withLocation(null, -1, noLength), severity));
-    }
-
-    if (_reportMessages) {
-      command_line_reporting.reportWithoutLocation(message, severity);
-    }
+    report(message.withoutLocation(), severity);
   }
 
   /// Runs various validations checks on the input options. For instance,
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
index 65cd053..d059f88 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
@@ -4,9 +4,7 @@
 
 library fasta.constructor_reference_builder;
 
-import '../messages.dart' show templateConstructorNotFound;
-
-import '../parser.dart' show noLength;
+import '../messages.dart' show noLength, templateConstructorNotFound;
 
 import 'builder.dart'
     show
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 7782a3b..054a552 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -27,5 +27,5 @@
 
   bool get isField => true;
 
-  bool get hasImplicitType;
+  bool get hasTypeInferredFromInitializer;
 }
diff --git a/pkg/front_end/lib/src/fasta/command_line_reporting.dart b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
index 02802e0..fe28e9c 100644
--- a/pkg/front_end/lib/src/fasta/command_line_reporting.dart
+++ b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
@@ -19,12 +19,10 @@
 import 'deprecated_problems.dart'
     show Crash, deprecated_InputError, safeToString;
 
-import 'fasta_codes.dart' show LocatedMessage, Message;
+import 'fasta_codes.dart' show LocatedMessage;
 
 import 'messages.dart' show getLocation, getSourceLine, isVerbose;
 
-import 'parser.dart' show noLength;
-
 import 'problems.dart' show unexpected;
 
 import 'severity.dart' show Severity;
@@ -36,13 +34,9 @@
 /// Formats [message] as a string that is suitable for output from a
 /// command-line tool. This includes source snippets and different colors based
 /// on [severity].
-///
-/// This is shared implementation used by methods below, and isn't intended to
-/// be called directly.
-String formatInternal(
-    Message message, Severity severity, Uri uri, int offset, int length,
-    {Location location}) {
+String format(LocatedMessage message, Severity severity, {Location location}) {
   try {
+    int length = message.length;
     if (length < 1) {
       // TODO(ahe): Throw in this situation. It is normally an error caused by
       // empty names.
@@ -73,13 +67,14 @@
           break;
 
         default:
-          return unexpected("$severity", "formatInternal", -1, null);
+          return unexpected("$severity", "format", -1, null);
       }
     }
 
-    if (uri != null) {
-      String path = relativizeUri(uri);
-      location ??= (offset == -1 ? null : getLocation(uri, offset));
+    if (message.uri != null) {
+      String path = relativizeUri(message.uri);
+      int offset = message.charOffset;
+      location ??= (offset == -1 ? null : getLocation(message.uri, offset));
       String sourceLine = getSourceLine(location);
       if (sourceLine == null) {
         sourceLine = "";
@@ -110,7 +105,7 @@
         "[${message.code.name}] ${safeToString(message.message)}\n"
         "${safeToString(error)}\n"
         "$trace");
-    throw new Crash(uri, offset, error, trace);
+    throw new Crash(message.uri, message.charOffset, error, trace);
   }
 }
 
@@ -234,34 +229,3 @@
   _printAndThrowIfDebugging(
       format(message, severity), severity, message.uri, message.charOffset);
 }
-
-/// Similar to [report].
-///
-/// This method isn't intended to be called directly. Use
-/// [CompilerContext.reportWithoutLocation] instead.
-void reportWithoutLocation(Message message, Severity severity) {
-  if (isHidden(severity)) return;
-  if (isCompileTimeError(severity)) {
-    CompilerContext.current.logError(message, severity);
-  }
-  _printAndThrowIfDebugging(
-      formatWithoutLocation(message, severity), severity, null, -1);
-}
-
-/// Formats [message] as described in [formatInternal].
-///
-/// This method isn't intended to be called directly. Use
-/// [CompilerContext.format] instead.
-String format(LocatedMessage message, Severity severity, {Location location}) {
-  return formatInternal(message.messageObject, severity, message.uri,
-      message.charOffset, message.length,
-      location: location);
-}
-
-/// Formats [message] as described in [formatInternal].
-///
-/// This method isn't intended to be called directly. Use
-/// [CompilerContext.formatWithoutLocation] instead.
-String formatWithoutLocation(Message message, Severity severity) {
-  return formatInternal(message, severity, null, -1, noLength);
-}
diff --git a/pkg/front_end/lib/src/fasta/compiler_context.dart b/pkg/front_end/lib/src/fasta/compiler_context.dart
index c34c57f..77ab869 100644
--- a/pkg/front_end/lib/src/fasta/compiler_context.dart
+++ b/pkg/front_end/lib/src/fasta/compiler_context.dart
@@ -65,6 +65,7 @@
   }
 
   /// Report [message], for example, by printing it.
+  // TODO(askesc): Remove this and direct callers directly to report.
   void reportWithoutLocation(Message message, Severity severity) {
     options.reportWithoutLocation(message, severity);
   }
@@ -75,8 +76,9 @@
   }
 
   /// Format [message] as a text string that can be included in generated code.
+  // TODO(askesc): Remove this and direct callers directly to format.
   String formatWithoutLocation(Message message, Severity severity) {
-    return command_line_reporting.formatWithoutLocation(message, severity);
+    return command_line_reporting.format(message.withoutLocation(), severity);
   }
 
   void logError(Object message, Severity severity) {
diff --git a/pkg/front_end/lib/src/fasta/deprecated_problems.dart b/pkg/front_end/lib/src/fasta/deprecated_problems.dart
index b69bb9d..935e73f 100644
--- a/pkg/front_end/lib/src/fasta/deprecated_problems.dart
+++ b/pkg/front_end/lib/src/fasta/deprecated_problems.dart
@@ -13,9 +13,8 @@
 
 import 'command_line_reporting.dart' show shouldThrowOn;
 
-import 'messages.dart' show LocatedMessage, isVerbose, templateUnspecified;
-
-import 'parser.dart' show noLength;
+import 'messages.dart'
+    show LocatedMessage, noLength, isVerbose, templateUnspecified;
 
 import 'severity.dart' show Severity;
 
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes.dart b/pkg/front_end/lib/src/fasta/fasta_codes.dart
index 4d2a4d3..d3b42b9 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes.dart
@@ -16,6 +16,8 @@
 
 part 'fasta_codes_generated.dart';
 
+const int noLength = 1;
+
 class Code<T> {
   final String name;
 
@@ -47,6 +49,10 @@
   LocatedMessage withLocation(Uri uri, int charOffset, int length) {
     return new LocatedMessage(uri, charOffset, length, this);
   }
+
+  LocatedMessage withoutLocation() {
+    return new LocatedMessage(null, -1, noLength, this);
+  }
 }
 
 class MessageCode extends Code<Null> implements Message {
@@ -73,6 +79,10 @@
   LocatedMessage withLocation(Uri uri, int charOffset, int length) {
     return new LocatedMessage(uri, charOffset, length, this);
   }
+
+  LocatedMessage withoutLocation() {
+    return new LocatedMessage(null, -1, noLength, this);
+  }
 }
 
 class Template<T> {
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 8389e2d..00f7201 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -8,7 +8,7 @@
 
 import '../fasta_codes.dart' as fasta;
 
-import '../fasta_codes.dart' show LocatedMessage, Message, Template;
+import '../fasta_codes.dart' show LocatedMessage, Message, noLength, Template;
 
 import '../messages.dart' as messages show getLocationFromUri;
 
@@ -23,7 +23,6 @@
         closeBraceTokenFor,
         lengthForToken,
         lengthOfSpan,
-        noLength,
         offsetForToken,
         optional;
 
@@ -463,7 +462,9 @@
         }
         field.initializer = initializer;
         _typeInferrer.inferFieldInitializer(
-            this, field.hasImplicitType ? null : field.builtType, initializer);
+            this,
+            field.hasTypeInferredFromInitializer ? null : field.builtType,
+            initializer);
       }
     }
     pop(); // Type.
@@ -604,7 +605,7 @@
       return member.procedure.function.returnType;
     } else {
       assert(member is KernelConstructorBuilder);
-      return null;
+      return const DynamicType();
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
index 2a3d2d5..1fb2094 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
@@ -18,12 +18,11 @@
         templateNotAType,
         templateUnresolvedPrefixInTypeAnnotation;
 
-import '../messages.dart' show Message;
+import '../messages.dart' show Message, noLength;
 
 import '../names.dart' show callName, lengthName;
 
-import '../parser.dart'
-    show lengthForToken, lengthOfSpan, noLength, offsetForToken;
+import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
 
 import '../problems.dart' show unhandled, unimplemented, unsupported;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
index d542d10..b4e425e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
@@ -40,6 +40,7 @@
         messagePatchClassTypeVariablesMismatch,
         messagePatchDeclarationMismatch,
         messagePatchDeclarationOrigin,
+        noLength,
         templateOverriddenMethodCause,
         templateOverrideFewerNamedArguments,
         templateOverrideFewerPositionalArguments,
@@ -50,8 +51,6 @@
         templateOverrideTypeVariablesMismatch,
         templateRedirectionTargetNotFound;
 
-import '../parser.dart' show noLength;
-
 import '../problems.dart' show unexpected, unhandled, unimplemented;
 
 import '../type_inference/type_schema.dart' show UnknownType;
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 b915987..18cca9e 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
@@ -32,13 +32,12 @@
 import '../fasta_codes.dart'
     show
         messageNoUnnamedConstructorInObject,
+        noLength,
         templateDuplicatedName,
         templateEnumConstantSameNameAsEnclosing;
 
 import '../modifier.dart' show constMask, finalMask, staticMask;
 
-import '../parser.dart' show noLength;
-
 import '../source/source_class_builder.dart' show SourceClassBuilder;
 
 import 'kernel_builder.dart'
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 9a1756a..0e60a3e 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
@@ -130,5 +130,6 @@
   DartType get builtType => field.type;
 
   @override
-  bool get hasImplicitType => type == null;
+  bool get hasTypeInferredFromInitializer =>
+      ShadowField.hasTypeInferredFromInitializer(field);
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart
index 044e692..6bf1aa2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_alias_builder.dart
@@ -15,9 +15,7 @@
 
 import 'package:kernel/type_algebra.dart' show substitute;
 
-import '../parser.dart' show noLength;
-
-import '../fasta_codes.dart' show templateCyclicTypedef;
+import '../fasta_codes.dart' show noLength, templateCyclicTypedef;
 
 import 'kernel_builder.dart'
     show
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart
index 63a43ad..7e6aeb3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart
@@ -13,9 +13,7 @@
         Supertype,
         TypeParameter;
 
-import '../fasta_codes.dart' show messageSupertypeIsFunction;
-
-import '../parser.dart' show noLength;
+import '../fasta_codes.dart' show messageSupertypeIsFunction, noLength;
 
 import '../problems.dart' show unsupported;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart
index dffdd01..5d8004a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_invalid_type_builder.dart
@@ -6,9 +6,8 @@
 
 import 'package:kernel/ast.dart' show DartType, InvalidType;
 
-import '../fasta_codes.dart' show LocatedMessage, Message, templateTypeNotFound;
-
-import '../parser.dart' show noLength;
+import '../fasta_codes.dart'
+    show LocatedMessage, Message, noLength, templateTypeNotFound;
 
 import 'kernel_builder.dart'
     show InvalidTypeBuilder, KernelTypeBuilder, LibraryBuilder;
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 78bc875..25054fe 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
@@ -18,6 +18,7 @@
         messageConflictsWithTypeVariableCause,
         messageTypeVariableDuplicatedName,
         messageTypeVariableSameNameAsEnclosing,
+        noLength,
         templateConflictsWithTypeVariable,
         templateDuplicatedExport,
         templateDuplicatedExportInType,
@@ -38,8 +39,6 @@
 import '../modifier.dart'
     show abstractMask, namedMixinApplicationMask, staticMask;
 
-import '../parser.dart' show noLength;
-
 import '../problems.dart' show unhandled;
 
 import '../source/source_class_builder.dart' show SourceClassBuilder;
@@ -75,9 +74,9 @@
         LoadLibraryBuilder,
         MemberBuilder,
         MetadataBuilder,
-        NamedTypeBuilder,
         PrefixBuilder,
         ProcedureBuilder,
+        QualifiedName,
         Scope,
         TypeBuilder,
         TypeVariableBuilder,
@@ -96,9 +95,6 @@
 
   final KernelLibraryBuilder actualOrigin;
 
-  final Map<String, SourceClassBuilder> mixinApplicationClasses =
-      <String, SourceClassBuilder>{};
-
   final List<KernelFunctionBuilder> nativeMethods = <KernelFunctionBuilder>[];
 
   final List<KernelTypeVariableBuilder> boundlessTypeVariables =
@@ -175,9 +171,7 @@
         modifiers,
         className,
         typeVariables,
-        applyMixins(supertype, supertypeOffset,
-            isSyntheticMixinImplementation: true,
-            subclassName: className,
+        applyMixins(supertype, supertypeOffset, className,
             typeVariables: typeVariables),
         interfaces,
         classScope,
@@ -251,269 +245,199 @@
     return typeVariablesByName;
   }
 
-  KernelTypeBuilder applyMixin(
-      KernelTypeBuilder supertype, KernelTypeBuilder mixin, String signature,
+  KernelTypeBuilder applyMixins(
+      KernelTypeBuilder type, int charOffset, String subclassName,
       {String documentationComment,
       List<MetadataBuilder> metadata,
-      bool isSyntheticMixinImplementation: false,
       String name,
       List<TypeVariableBuilder> typeVariables,
-      int modifiers: abstractMask,
-      List<KernelTypeBuilder> interfaces,
-      int charOffset: -1}) {
-    var constructors = <String, MemberBuilder>{};
-    bool isNamed = name != null;
-    SourceClassBuilder builder;
-    if (isNamed) {
-      modifiers |= namedMixinApplicationMask;
-    } else {
-      name = "${supertype.name}";
-      int index = name.indexOf("^");
-      if (index != -1) {
-        name = name.substring(0, index);
-      }
-      name = "_$name&${mixin.name}$signature";
-      builder = mixinApplicationClasses[name];
-    }
-    if (builder == null) {
-      builder = new SourceClassBuilder(
-          metadata,
-          modifiers,
-          name,
-          typeVariables,
-          supertype,
-          interfaces,
-          new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
-              scope.withTypeVariables(typeVariables),
-              "mixin $name", isModifiable: false),
-          new Scope(constructors, null, null, "constructors",
-              isModifiable: false),
-          this,
-          <ConstructorReferenceBuilder>[],
-          charOffset,
-          TreeNode.noOffset,
-          null,
-          mixin);
-      loader.target.metadataCollector
-          ?.setDocumentationComment(builder.target, documentationComment);
-      builder.cls.isSyntheticMixinImplementation =
-          isSyntheticMixinImplementation;
-      addBuilder(name, builder, charOffset);
-      if (!isNamed) {
-        mixinApplicationClasses[name] = builder;
-      }
-    }
-    return addNamedType(name, <KernelTypeBuilder>[], charOffset)
-      ..bind(isNamed ? builder : null);
-  }
-
-  KernelTypeBuilder applyMixins(KernelTypeBuilder type, int charOffset,
-      {String documentationComment,
-      List<MetadataBuilder> metadata,
-      bool isSyntheticMixinImplementation: false,
-      String name,
-      String subclassName,
-      List<TypeVariableBuilder> typeVariables,
-      int modifiers: abstractMask,
+      int modifiers,
       List<KernelTypeBuilder> interfaces}) {
+    if (name == null) {
+      // The following parameters should only be used when building a named
+      // mixin application.
+      if (documentationComment != null) {
+        unhandled("documentationComment", "unnamed mixin application",
+            charOffset, fileUri);
+      } else if (metadata != null) {
+        unhandled("metadata", "unnamed mixin application", charOffset, fileUri);
+      } else if (interfaces != null) {
+        unhandled(
+            "interfaces", "unnamed mixin application", charOffset, fileUri);
+      }
+    }
     if (type is KernelMixinApplicationBuilder) {
-      subclassName ??= name;
-      List<List<String>> signatureParts = <List<String>>[];
-      Map<String, String> unresolved = <String, String>{};
-      Map<String, String> unresolvedReversed = <String, String>{};
-      int unresolvedCount = 0;
-      Map<String, TypeBuilder> freeTypes = <String, TypeBuilder>{};
-
-      if (name == null || type.mixins.length != 1) {
-        TypeBuilder last = type.mixins.last;
-
-        /// Compute a signature of the type arguments used by the supertype and
-        /// mixins. These types are free variables. At this point we can't
-        /// trust that the number of type arguments match the type parameters,
-        /// so we also need to be able to detect missing type arguments.  To do
-        /// so, we separate each list of type arguments by `^` and type
-        /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
-        /// look like this:
-        ///
-        ///     ^#U0^#U1&#U2
-        ///
-        /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
-        /// `S`, `T`, and `U` respectively.
-        ///
-        /// As we can resolve any type parameters used at this point, those are
-        /// named `#T0` and so forth. This reduces the number of free variables
-        /// which is crucial for memory usage and the Dart VM's bootstrap
-        /// sequence.
-        ///
-        /// For example, consider this use of mixin applications:
-        ///
-        ///     class _InternalLinkedHashMap<K, V> extends _HashVMBase
-        ///         with
-        ///             MapMixin<K, V>,
-        ///             _LinkedHashMapMixin<K, V>,
-        ///             _HashBase,
-        ///             _OperatorEqualsAndHashCode {}
-        ///
-        /// In this case, only two variables are free, and we produce this
-        /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
-        /// sames mixins but with missing type arguments for `MapMixin`, its
-        /// signature would be: `^^^#T0&#T1^^`.
-        ///
-        /// Note that we do not need to compute a signature for a named mixin
-        /// application with only one mixin as we don't have to invent a name
-        /// for any classes in this situation.
-        void analyzeArguments(TypeBuilder type) {
-          if (name != null && type == last) {
-            // The last mixin of a named mixin application doesn't contribute
-            // to free variables.
-            return;
-          }
-          if (type is NamedTypeBuilder) {
-            List<String> part = <String>[];
-            for (int i = 0; i < (type.arguments?.length ?? 0); i++) {
-              var argument = type.arguments[i];
-              String name;
-              if (argument is NamedTypeBuilder) {
-                if (argument.builder != null) {
-                  int index = typeVariables?.indexOf(argument.builder) ?? -1;
-                  if (index != -1) {
-                    name = "#T${index}";
-                  }
-                } else if (argument.arguments == null) {
-                  name = unresolved["${argument.name}"] ??=
-                      "#U${unresolvedCount++}";
-                }
-              }
-              name ??= "#U${unresolvedCount++}";
-              unresolvedReversed[name] = "${argument.name}";
-              freeTypes[name] = argument;
-              part.add(name);
-              type.arguments[i] = new KernelNamedTypeBuilder(name, null);
-            }
-            signatureParts.add(part);
-          }
-        }
-
-        analyzeArguments(type.supertype);
-        type.mixins.forEach(analyzeArguments);
-      }
-      KernelTypeBuilder supertype = type.supertype;
-      List<List<String>> currentSignatureParts = <List<String>>[];
-      int currentSignatureCount = 0;
-      String computeSignature() {
-        if (freeTypes.isEmpty) return "";
-        currentSignatureParts.add(signatureParts[currentSignatureCount++]);
-        if (currentSignatureParts.any((l) => l.isNotEmpty)) {
-          return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
+      String extractName(name) {
+        if (name is QualifiedName) {
+          return name.suffix;
         } else {
-          return "";
+          return name;
         }
       }
 
-      Map<String, TypeVariableBuilder> computeTypeVariables() {
-        Map<String, TypeVariableBuilder> variables =
-            <String, TypeVariableBuilder>{};
-        for (List<String> strings in currentSignatureParts) {
-          for (String name in strings) {
-            variables[name] ??= addTypeVariable(name, null, -1);
-          }
+      // Documentation below assumes the given mixin application is in one of
+      // these forms:
+      //
+      //     class C extends S with M1, M2, M3;
+      //     class Named = S with M1, M2, M3;
+      //
+      // When we refer to the subclass, we mean `C` or `Named`.
+
+      /// The current supertype.
+      ///
+      /// Starts out having the value `S` and on each iteration of the loop
+      /// below, it will take on the value corresponding to:
+      ///
+      /// 1. `S with M1`.
+      /// 2. `(S with M1) with M2`.
+      /// 3. `((S with M1) with M2) with M3`.
+      KernelTypeBuilder supertype = type.supertype;
+
+      /// The variable part of the mixin application's synthetic name. It
+      /// starts out as the name of the superclass, but is only used after it
+      /// has been combined with the name of the current mixin. In the examples
+      /// from above, it will take these values:
+      ///
+      /// 1. `S&M1`
+      /// 2. `S&M1&M2`
+      /// 3. `S&M1&M2&M3`.
+      ///
+      /// The full name of the mixin application is obtained by prepending the
+      /// name of the subclass (`C` or `Named` in the above examples) to the
+      /// running name. For the example `C`, that leads to these full names:
+      ///
+      /// 1. `_C&S&M1`
+      /// 2. `_C&S&M1&M2`
+      /// 3. `_C&S&M1&M2&M3`.
+      ///
+      /// For a named mixin application, the last name has been given by the
+      /// programmer, so for the example `Named` we see these full names:
+      ///
+      /// 1. `_Named&S&M1`
+      /// 2. `_Named&S&M1&M2`
+      /// 3. `Named`.
+      String runningName = extractName(supertype.name);
+
+      /// True when we're building a named mixin application. Notice that for
+      /// the `Named` example above, this is only true on the last
+      /// iteration because only the full mixin application is named.
+      bool isNamedMixinApplication;
+
+      /// The names of the type variables of the subclass.
+      Set<String> typeVariableNames;
+      if (typeVariables != null) {
+        typeVariableNames = new Set<String>();
+        for (TypeVariableBuilder typeVariable in typeVariables) {
+          typeVariableNames.add(typeVariable.name);
         }
-        return variables;
       }
 
-      checkArguments(t) {
-        for (var argument in t.arguments ?? const []) {
-          if (argument.builder == null && argument.name.startsWith("#")) {
-            throw "No builder on ${argument.name}";
+      /// The type variables used in [supertype] and the current mixin.
+      Map<String, TypeVariableBuilder> usedTypeVariables;
+
+      /// Helper function that updates [usedTypeVariables]. It needs to be
+      /// called twice per iteration: once on supertype and once on the current
+      /// mixin.
+      void computeUsedTypeVariables(KernelNamedTypeBuilder type) {
+        List<KernelTypeBuilder> typeArguments = type.arguments;
+        if (typeArguments != null && typeVariables != null) {
+          for (KernelTypeBuilder argument in typeArguments) {
+            if (typeVariableNames.contains(argument.name)) {
+              usedTypeVariables ??= <String, TypeVariableBuilder>{};
+              KernelTypeVariableBuilder freshTypeVariable =
+                  (usedTypeVariables[argument.name] ??=
+                      addTypeVariable(argument.name, null, charOffset));
+              // Notice that [argument] may have been created below as part of
+              // [applicationTypeArguments] and have to be rebound now
+              // (otherwise it would refer to a type variable in the subclass).
+              argument.bind(freshTypeVariable);
+            } else {
+              if (argument is KernelNamedTypeBuilder) {
+                computeUsedTypeVariables(argument);
+              }
+            }
           }
         }
       }
 
-      computeSignature(); // This combines the supertype with the first mixin.
-      for (int i = 0; i < type.mixins.length - 1; i++) {
-        Set<String> supertypeArguments = new Set<String>();
-        for (var part in currentSignatureParts) {
-          supertypeArguments.addAll(part);
+      /// Iterate over the mixins from left to right. At the end of each
+      /// iteration, a new [supertype] is computed that is the mixin
+      /// application of [supertype] with the current mixin.
+      for (int i = 0; i < type.mixins.length; i++) {
+        KernelTypeBuilder mixin = type.mixins[i];
+        isNamedMixinApplication = name != null && mixin == type.mixins.last;
+        usedTypeVariables = null;
+        if (!isNamedMixinApplication) {
+          if (supertype is KernelNamedTypeBuilder) {
+            computeUsedTypeVariables(supertype);
+          }
+          if (mixin is KernelNamedTypeBuilder) {
+            runningName += "&${extractName(mixin.name)}";
+            computeUsedTypeVariables(mixin);
+          }
         }
-        String signature = computeSignature();
-        var variables = computeTypeVariables();
-        if (supertypeArguments.isNotEmpty) {
-          supertype = addNamedType(
-              supertype.name,
-              supertypeArguments
-                  .map((n) => addNamedType(n, null, -1)..bind(variables[n]))
-                  .toList(),
-              -1);
+        String fullname =
+            isNamedMixinApplication ? name : "_$subclassName&$runningName";
+        List<TypeVariableBuilder> applicationTypeVariables;
+        List<KernelTypeBuilder> applicationTypeArguments;
+        if (isNamedMixinApplication) {
+          // If this is a named mixin application, it must be given all the
+          // declarated type variables.
+          applicationTypeVariables = typeVariables;
+        } else {
+          // Otherwise, we pass the fresh type variables to the mixin
+          // application in the same order as they're declared on the subclass.
+          if (usedTypeVariables != null) {
+            applicationTypeVariables = <TypeVariableBuilder>[];
+            applicationTypeArguments = <KernelTypeBuilder>[];
+            for (TypeVariableBuilder typeVariable in typeVariables) {
+              TypeVariableBuilder freshTypeVariable =
+                  usedTypeVariables[typeVariable.name];
+              if (freshTypeVariable != null) {
+                applicationTypeVariables.add(freshTypeVariable);
+                applicationTypeArguments.add(
+                    addNamedType(typeVariable.name, null, charOffset)..bind(
+                        // This may be rebound in the next iteration when
+                        // calling [computeUsedTypeVariables].
+                        typeVariable));
+              }
+            }
+          }
         }
-        KernelNamedTypeBuilder mixin = type.mixins[i];
-        for (var type in mixin.arguments ?? const []) {
-          type.bind(variables[type.name]);
+        SourceClassBuilder application = new SourceClassBuilder(
+            isNamedMixinApplication ? metadata : null,
+            isNamedMixinApplication
+                ? modifiers | namedMixinApplicationMask
+                : abstractMask,
+            fullname,
+            applicationTypeVariables,
+            supertype,
+            isNamedMixinApplication ? interfaces : null,
+            new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
+                scope.withTypeVariables(typeVariables),
+                "mixin $fullname ", isModifiable: false),
+            new Scope(<String, MemberBuilder>{}, null, null, "constructors",
+                isModifiable: false),
+            this,
+            <ConstructorReferenceBuilder>[],
+            charOffset,
+            TreeNode.noOffset,
+            null,
+            mixin);
+        if (isNamedMixinApplication) {
+          loader.target.metadataCollector?.setDocumentationComment(
+              application.target, documentationComment);
         }
-        checkArguments(supertype);
-        checkArguments(mixin);
-        supertype = applyMixin(supertype, mixin, signature,
-            isSyntheticMixinImplementation: true,
-            typeVariables: new List<TypeVariableBuilder>.from(variables.values),
-            // TODO(ahe): Eventually, the charOffset should be -1 as these
-            // classes are canonicalized and synthetic. For now, for the
-            // benefit of dart2js, we add offsets to help the compiler during
-            // the migration process. We add i because dart2js uses these
-            // numbers to sort the classes by. Adding i isn't precisely what
-            // dart2js does, but it should be good enough.
-            charOffset: charOffset + i);
+        // TODO(ahe, kmillikin): Should always be true?
+        // pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
+        // handle that :(
+        application.cls.isSyntheticMixinImplementation =
+            !isNamedMixinApplication;
+        addBuilder(fullname, application, charOffset);
+        supertype =
+            addNamedType(fullname, applicationTypeArguments, charOffset);
       }
-      KernelNamedTypeBuilder mixin = type.mixins.last;
-
-      Set<String> supertypeArguments = new Set<String>();
-      for (var part in currentSignatureParts) {
-        supertypeArguments.addAll(part);
-      }
-      String signature = name == null ? computeSignature() : "";
-      var variables;
-      if (name == null) {
-        variables = computeTypeVariables();
-        typeVariables = new List<TypeVariableBuilder>.from(variables.values);
-        if (supertypeArguments.isNotEmpty) {
-          supertype = addNamedType(
-              supertype.name,
-              supertypeArguments
-                  .map((n) => addNamedType(n, null, -1)..bind(variables[n]))
-                  .toList(),
-              -1);
-        }
-      } else {
-        if (supertypeArguments.isNotEmpty) {
-          supertype = addNamedType(supertype.name,
-              supertypeArguments.map((n) => freeTypes[n]).toList(), -1);
-        }
-      }
-
-      if (name == null) {
-        for (var type in mixin.arguments ?? const []) {
-          type.bind(variables[type.name]);
-        }
-      }
-      checkArguments(supertype);
-      checkArguments(mixin);
-
-      KernelNamedTypeBuilder t = applyMixin(supertype, mixin, signature,
-          documentationComment: documentationComment,
-          metadata: metadata,
-          name: name,
-          isSyntheticMixinImplementation: isSyntheticMixinImplementation,
-          typeVariables: typeVariables,
-          modifiers: modifiers,
-          interfaces: interfaces,
-          charOffset: charOffset);
-      if (name == null) {
-        var builder = t.builder;
-        t = addNamedType(
-            t.name, freeTypes.keys.map((k) => freeTypes[k]).toList(), -1);
-        if (builder != null) {
-          t.bind(builder);
-        }
-      }
-      return t;
+      return supertype;
     } else {
       return type;
     }
@@ -530,7 +454,8 @@
       int charOffset) {
     // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
     endNestedDeclaration(name).resolveTypes(typeVariables, this);
-    KernelNamedTypeBuilder supertype = applyMixins(mixinApplication, charOffset,
+    KernelNamedTypeBuilder supertype = applyMixins(
+        mixinApplication, charOffset, name,
         documentationComment: documentationComment,
         metadata: metadata,
         name: name,
@@ -1072,14 +997,6 @@
 
   @override
   void includePart(covariant KernelLibraryBuilder part) {
-    part.mixinApplicationClasses
-        .forEach((String name, SourceClassBuilder builder) {
-      SourceClassBuilder existing =
-          mixinApplicationClasses.putIfAbsent(name, () => builder);
-      if (existing != builder) {
-        part.scope.local.remove(name);
-      }
-    });
     super.includePart(part);
     nativeMethods.addAll(part.nativeMethods);
     boundlessTypeVariables.addAll(part.boundlessTypeVariables);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart
index 299756e..3428329 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_named_type_builder.dart
@@ -7,9 +7,7 @@
 import 'package:kernel/ast.dart' show DartType, Supertype;
 
 import '../messages.dart'
-    show templateSupertypeIsIllegal, templateSupertypeIsTypeVariable;
-
-import '../parser.dart' show noLength;
+    show noLength, templateSupertypeIsIllegal, templateSupertypeIsTypeVariable;
 
 import 'kernel_builder.dart'
     show
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
index 9f9701d..e239fa77 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
@@ -49,9 +49,8 @@
         messageNonInstanceTypeVariableUse,
         messagePatchDeclarationMismatch,
         messagePatchDeclarationOrigin,
-        messagePatchNonExternal;
-
-import '../parser.dart' show noLength;
+        messagePatchNonExternal,
+        noLength;
 
 import '../problems.dart' show unexpected;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index a7447ef..4e9fc11 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -390,6 +390,7 @@
 
   _ComplexAssignmentInferenceResult _inferRhs(
       ShadowTypeInferrer inferrer, DartType readType, DartType writeContext) {
+    assert(writeContext != null);
     var writeOffset = write == null ? -1 : write.fileOffset;
     Procedure combinerMember;
     DartType combinedType;
@@ -448,7 +449,8 @@
       _storeLetType(inferrer, replacedRhs ?? rhs, rhsType);
       if (nullAwareCombiner != null) {
         MethodInvocation equalsInvocation = nullAwareCombiner.condition;
-        inferrer.findMethodInvocationMember(writeContext, equalsInvocation,
+        inferrer.findMethodInvocationMember(
+            greatestClosure(inferrer.coreTypes, writeContext), equalsInvocation,
             silent: true);
         // Note: the case of readType=null only happens for erroneous code.
         combinedType = readType == null
@@ -782,6 +784,9 @@
     type = inferredType;
   }
 
+  static bool hasTypeInferredFromInitializer(ShadowField field) =>
+      field._inferenceNode is FieldInitializerInferenceNode;
+
   static bool isImplicitlyTyped(ShadowField field) => field._isImplicitlyTyped;
 
   static void setInferenceNode(ShadowField field, InferenceNode node) {
@@ -1079,7 +1084,7 @@
         inferrer.getCalleeFunctionType(writeMember, receiverType, false);
     DartType expectedIndexTypeForWrite;
     DartType indexContext = const UnknownType();
-    DartType writeContext;
+    DartType writeContext = const UnknownType();
     if (calleeType.positionalParameters.length >= 2) {
       // TODO(paulberry): we ought to get a context for the index expression
       // from the index formal parameter, but analyzer doesn't so for now we
@@ -1089,7 +1094,7 @@
     }
     var indexType = inferrer.inferExpression(index, indexContext, true);
     _storeLetType(inferrer, index, indexType);
-    if (writeContext != null) {
+    if (writeContext is! UnknownType) {
       inferrer.ensureAssignable(
           expectedIndexTypeForWrite,
           indexType,
@@ -1660,10 +1665,9 @@
     var closureContext = inferrer.closureContext;
     var typeContext = !closureContext.isGenerator
         ? closureContext.returnOrYieldContext
-        : null;
+        : const UnknownType();
     var inferredType = expression != null
-        ? inferrer.inferExpression(
-            expression, typeContext ?? const UnknownType(), true)
+        ? inferrer.inferExpression(expression, typeContext, true)
         : const VoidType();
     // Analyzer treats bare `return` statements as having no effect on the
     // inferred type of the closure.  TODO(paulberry): is this what we want
@@ -1695,14 +1699,14 @@
 
   @override
   DartType _inferExpression(ShadowTypeInferrer inferrer, DartType typeContext) {
-    DartType readType;
+    DartType readType = const DynamicType(); // Only used in error recovery
     var read = this.read;
     if (read is StaticGet) {
       readType = read.target.getterType;
       _storeLetType(inferrer, read, readType);
     }
     Member writeMember;
-    DartType writeContext;
+    DartType writeContext = const UnknownType();
     var write = this.write;
     if (write is StaticSet) {
       writeContext = write.target.setterType;
@@ -2193,7 +2197,7 @@
     if (read is VariableGet) {
       readType = read.promotedType ?? read.variable.type;
     }
-    DartType writeContext;
+    DartType writeContext = const UnknownType();
     var write = this.write;
     if (write is VariableSet) {
       writeContext = write.variable.type;
@@ -2347,17 +2351,21 @@
   @override
   void _inferStatement(ShadowTypeInferrer inferrer) {
     var closureContext = inferrer.closureContext;
-    var typeContext =
-        closureContext.isGenerator ? closureContext.returnOrYieldContext : null;
-    if (isYieldStar && typeContext != null) {
-      typeContext = inferrer.wrapType(
-          typeContext,
-          closureContext.isAsync
-              ? inferrer.coreTypes.streamClass
-              : inferrer.coreTypes.iterableClass);
+    DartType inferredType;
+    if (closureContext.isGenerator) {
+      var typeContext = closureContext.returnOrYieldContext;
+      if (isYieldStar && typeContext != null) {
+        typeContext = inferrer.wrapType(
+            typeContext,
+            closureContext.isAsync
+                ? inferrer.coreTypes.streamClass
+                : inferrer.coreTypes.iterableClass);
+      }
+      inferredType = inferrer.inferExpression(expression, typeContext, true);
+    } else {
+      inferredType =
+          inferrer.inferExpression(expression, const UnknownType(), true);
     }
-    var inferredType = inferrer.inferExpression(
-        expression, typeContext ?? const UnknownType(), true);
     closureContext.handleYield(
         inferrer, isYieldStar, inferredType, expression, fileOffset);
   }
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 282980e..c0b4ad3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -59,10 +59,9 @@
         LocatedMessage,
         messageConstConstructorNonFinalField,
         messageConstConstructorNonFinalFieldCause,
+        noLength,
         templateSuperclassHasNoDefaultConstructor;
 
-import '../parser.dart' show noLength;
-
 import '../problems.dart' show unhandled;
 
 import '../severity.dart' show Severity;
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index 045c9f3..6cfa12c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -28,9 +28,7 @@
 import '../compiler_context.dart' show CompilerContext;
 
 import '../fasta_codes.dart'
-    show LocatedMessage, templateInternalVerificationError;
-
-import '../parser.dart' show noLength;
+    show LocatedMessage, noLength, templateInternalVerificationError;
 
 import '../severity.dart' show Severity;
 
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index ad04feb..d14ac1e 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -16,14 +16,13 @@
     show
         LocatedMessage,
         Message,
+        noLength,
         SummaryTemplate,
         Template,
         messagePlatformPrivateLibraryAccess,
         templateInternalProblemMissingSeverity,
         templateSourceBodySummary;
 
-import 'parser.dart' show noLength;
-
 import 'problems.dart' show internalProblem;
 
 import 'severity.dart' show Severity;
diff --git a/pkg/front_end/lib/src/fasta/parser.dart b/pkg/front_end/lib/src/fasta/parser.dart
index 8419609..17c0d5c 100644
--- a/pkg/front_end/lib/src/fasta/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser.dart
@@ -35,7 +35,6 @@
         closeBraceTokenFor,
         lengthForToken,
         lengthOfSpan,
-        noLength,
         offsetForToken,
         optional;
 
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 5a847d1..896f9f0 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -2468,7 +2468,8 @@
         if (!token.isIdentifier) {
           if (memberKind == MemberKind.TopLevelField ||
               memberKind == MemberKind.NonStaticField ||
-              memberKind == MemberKind.StaticField) {
+              memberKind == MemberKind.StaticField ||
+              memberKind == MemberKind.Local) {
             reportRecoverableError(
                 begin, fasta.messageMissingConstFinalVarOrType);
             listener.handleNoType(beforeBegin);
diff --git a/pkg/front_end/lib/src/fasta/parser/util.dart b/pkg/front_end/lib/src/fasta/parser/util.dart
index 3a503aa..f16353d 100644
--- a/pkg/front_end/lib/src/fasta/parser/util.dart
+++ b/pkg/front_end/lib/src/fasta/parser/util.dart
@@ -6,12 +6,12 @@
 
 import 'package:kernel/ast.dart' show TreeNode;
 
+import '../fasta_codes.dart' show noLength;
+
 import '../scanner.dart' show Token;
 
 import '../../scanner/token.dart' show BeginToken;
 
-const int noLength = 1;
-
 /// Returns true if [token] is the symbol or keyword [value].
 bool optional(String value, Token token) {
   return identical(value, token.stringValue);
@@ -48,7 +48,7 @@
 /// A null-aware alternative to `token.length`.  If [token] is `null`, returns
 /// [noLength].
 int lengthForToken(Token token) {
-  return token == null ? 1 : token.length;
+  return token == null ? noLength : token.length;
 }
 
 /// Returns the length of the span from [begin] to [end] (inclusive). If both
diff --git a/pkg/front_end/lib/src/fasta/problems.dart b/pkg/front_end/lib/src/fasta/problems.dart
index d9b0777..d16e520 100644
--- a/pkg/front_end/lib/src/fasta/problems.dart
+++ b/pkg/front_end/lib/src/fasta/problems.dart
@@ -9,13 +9,12 @@
 import 'messages.dart'
     show
         Message,
+        noLength,
         templateInternalProblemUnexpected,
         templateInternalProblemUnhandled,
         templateInternalProblemUnimplemented,
         templateInternalProblemUnsupported;
 
-import 'parser.dart' show noLength;
-
 import 'severity.dart' show Severity;
 
 /// Used to report an internal error.
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index a09cdd2..eb8e9c5 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -13,6 +13,7 @@
 
 import '../fasta_codes.dart'
     show
+        noLength,
         templateConflictsWithConstructor,
         templateConflictsWithFactory,
         templateConflictsWithMember,
@@ -39,8 +40,6 @@
 
 import '../kernel/kernel_shadow_ast.dart' show ShadowClass;
 
-import '../parser.dart' show noLength;
-
 import '../problems.dart' show unexpected, unhandled;
 
 import 'source_library_builder.dart' show SourceLibraryBuilder;
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 01d6e4b..2980d2f 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
@@ -42,6 +42,7 @@
         messageExpectedUri,
         messageMemberWithSameNameAsClass,
         messagePartOfSelf,
+        noLength,
         templateConflictsWithMember,
         templateConflictsWithSetter,
         templateCouldNotParseUri,
@@ -59,8 +60,6 @@
 
 import '../configuration.dart' show Configuration;
 
-import '../parser.dart' show noLength;
-
 import '../problems.dart' show unhandled;
 
 import 'source_loader.dart' show SourceLoader;
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 534367c..fcac936 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -46,6 +46,7 @@
     show
         LocatedMessage,
         Message,
+        noLength,
         SummaryTemplate,
         Template,
         templateAmbiguousSupertypes,
@@ -69,7 +70,7 @@
 
 import '../parser/class_member_parser.dart' show ClassMemberParser;
 
-import '../parser.dart' show lengthForToken, noLength, offsetForToken;
+import '../parser.dart' show lengthForToken, offsetForToken;
 
 import '../problems.dart' show internalProblem;
 
diff --git a/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart b/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
index dae1dc7..f16d6af 100644
--- a/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
+++ b/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
@@ -14,9 +14,7 @@
 
 import '../compiler_context.dart' show CompilerContext;
 
-import '../messages.dart' show templateUnspecified;
-
-import '../parser.dart' show noLength;
+import '../messages.dart' show noLength, templateUnspecified;
 
 import '../scanner.dart' show ScannerResult, Token, scan;
 
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 be842cf..ced42ae 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
@@ -18,8 +18,6 @@
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
-import '../parser.dart' show noLength;
-
 /// Set this flag to `true` to cause debugging information about covariance
 /// checks to be printed to standard output.
 const bool debugCovariance = false;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 9e4d468..0f78fba 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -26,9 +26,7 @@
 
 import '../deprecated_problems.dart' show Crash;
 
-import '../messages.dart' show getLocationFromNode;
-
-import '../parser.dart' show noLength;
+import '../messages.dart' show getLocationFromNode, noLength;
 
 /// Concrete class derived from [InferenceNode] to represent type inference of a
 /// field based on its initializer.
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 9cbbcb7..8dccab2 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
@@ -81,8 +81,6 @@
 
 import '../names.dart' show callName;
 
-import '../parser.dart' show noLength;
-
 import '../problems.dart' show unexpected, unhandled;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
@@ -195,7 +193,9 @@
   }
 
   ClosureContext._(this.isAsync, this.isGenerator, this.returnOrYieldContext,
-      this._needToInferReturnType, this._needImplicitDowncasts);
+      this._needToInferReturnType, this._needImplicitDowncasts) {
+    assert(returnOrYieldContext != null);
+  }
 
   /// Updates the inferred return type based on the presence of a return
   /// statement returning the given [type].
@@ -446,12 +446,13 @@
         typeSchemaEnvironment.isSubtypeOf(actualType, expectedType);
   }
 
-  /// Checks whether [actualType] can be assigned to [expectedType], and inserts
-  /// an implicit downcast if appropriate.
+  /// Checks whether [actualType] can be assigned to the greatest closure of
+  /// [expectedType], and inserts an implicit downcast if appropriate.
   Expression ensureAssignable(DartType expectedType, DartType actualType,
       Expression expression, int fileOffset,
       {bool isReturnFromAsync = false}) {
-    assert(expectedType == null || isKnown(expectedType));
+    assert(expectedType != null);
+    expectedType = greatestClosure(coreTypes, expectedType);
 
     DartType initialExpectedType = expectedType;
     if (isReturnFromAsync && !isAssignable(expectedType, actualType)) {
@@ -498,7 +499,7 @@
               new NullLiteral()..fileOffset = fileOffset, tearOff, actualType);
           var let = new Let(t, conditional);
           parent?.replaceChild(expression, let);
-          expression = conditional;
+          expression = let;
         }
       }
     }
@@ -549,6 +550,8 @@
       Expression receiver,
       bool setter: false,
       bool silent: false}) {
+    assert(receiverType != null && isKnown(receiverType));
+
     // Our non-strong golden files currently don't include interface
     // targets, so we can't store the interface target without causing tests
     // to fail.  TODO(paulberry): fix this.
@@ -793,7 +796,7 @@
     if (type is InterfaceType && identical(type.classNode, class_)) {
       return type.typeArguments[0];
     } else {
-      return null;
+      return const UnknownType();
     }
   }
 
@@ -1135,7 +1138,11 @@
 
   DartType inferLocalFunction(FunctionNode function, DartType typeContext,
       int fileOffset, DartType returnContext) {
-    bool hasImplicitReturnType = returnContext == null;
+    bool hasImplicitReturnType = false;
+    if (returnContext == null) {
+      hasImplicitReturnType = true;
+      returnContext = const DynamicType();
+    }
     if (!isTopLevel) {
       var positionalParameters = function.positionalParameters;
       for (var i = 0; i < positionalParameters.length; i++) {
@@ -1234,9 +1241,7 @@
     // Let `N'` be `N[T/S]`.  The [ClosureContext] constructor will adjust
     // accordingly if the closure is declared with `async`, `async*`, or
     // `sync*`.
-    if (returnContext != null) {
-      returnContext = substitution.substituteType(returnContext);
-    }
+    returnContext = substitution.substituteType(returnContext);
 
     // Apply type inference to `B` in return context `N’`, with any references
     // to `xi` in `B` having type `Pi`.  This produces `B’`.
diff --git a/pkg/front_end/testcases/bug32426.dart b/pkg/front_end/testcases/bug32426.dart
new file mode 100644
index 0000000..cb70b9b
--- /dev/null
+++ b/pkg/front_end/testcases/bug32426.dart
@@ -0,0 +1,16 @@
+// 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.
+
+abstract class I {
+  void call();
+}
+
+class C implements I {
+  void call([int x]) {}
+}
+
+main() {
+  I i = new C();
+  void Function([int]) f = i;
+}
diff --git a/pkg/front_end/testcases/bug32426.dart.direct.expect b/pkg/front_end/testcases/bug32426.dart.direct.expect
new file mode 100644
index 0000000..1e86267
--- /dev/null
+++ b/pkg/front_end/testcases/bug32426.dart.direct.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class I extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  abstract method call() → void;
+}
+class C extends core::Object implements self::I {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method call([core::int x = null]) → void {}
+}
+static method main() → dynamic {
+  self::I i = new self::C::•();
+  ([core::int]) → void f = i;
+}
diff --git a/pkg/front_end/testcases/bug32426.dart.outline.expect b/pkg/front_end/testcases/bug32426.dart.outline.expect
new file mode 100644
index 0000000..f4a907d
--- /dev/null
+++ b/pkg/front_end/testcases/bug32426.dart.outline.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class I extends core::Object {
+  synthetic constructor •() → void
+    ;
+  abstract method call() → void;
+}
+class C extends core::Object implements self::I {
+  synthetic constructor •() → void
+    ;
+  method call([core::int x]) → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/bug32426.dart.strong.expect b/pkg/front_end/testcases/bug32426.dart.strong.expect
new file mode 100644
index 0000000..4c681bf
--- /dev/null
+++ b/pkg/front_end/testcases/bug32426.dart.strong.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class I extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  abstract method call() → void;
+}
+class C extends core::Object implements self::I {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method call([core::int x = null]) → void {}
+}
+static method main() → dynamic {
+  self::I i = new self::C::•();
+  ([core::int]) → void f = (let final self::I #t1 = i in #t1.==(null) ?{() → void} null : #t1.{self::I::call}) as{TypeError} ([core::int]) → void;
+}
diff --git a/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart
new file mode 100644
index 0000000..3d735e5
--- /dev/null
+++ b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart
@@ -0,0 +1,16 @@
+// 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.
+
+/*@testedFeatures=inference*/
+library test;
+
+abstract class A {
+  Iterable<String> get foo;
+}
+
+class B implements A {
+  final /*@topType=Iterable<String>*/ foo = /*@typeArgs=String*/ const [];
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.direct.expect b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.direct.expect
new file mode 100644
index 0000000..95f7601
--- /dev/null
+++ b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.direct.expect
@@ -0,0 +1,17 @@
+library test;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  abstract get foo() → core::Iterable<core::String>;
+}
+class B extends core::Object implements self::A {
+  final field dynamic foo = const <dynamic>[];
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → void {}
diff --git a/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.outline.expect b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.outline.expect
new file mode 100644
index 0000000..872d11c
--- /dev/null
+++ b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.outline.expect
@@ -0,0 +1,16 @@
+library test;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → void
+    ;
+  abstract get foo() → core::Iterable<core::String>;
+}
+class B extends core::Object implements self::A {
+  final field dynamic foo;
+  synthetic constructor •() → void
+    ;
+}
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.strong.expect b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.strong.expect
new file mode 100644
index 0000000..f7a8373
--- /dev/null
+++ b/pkg/front_end/testcases/inference/downwards_context_from_inferred_field_type.dart.strong.expect
@@ -0,0 +1,17 @@
+library test;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  abstract get foo() → core::Iterable<core::String>;
+}
+class B extends core::Object implements self::A {
+  final field core::Iterable<core::String> foo = const <core::String>[];
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → void {}
diff --git a/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.direct.expect b/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.direct.expect
index 082497c..e32aaba 100644
--- a/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.direct.expect
@@ -39,9 +39,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&B = core::Object with self::B {
+abstract class _G&Object&B = core::Object with self::B {
 }
-class G extends self::_Object&B {
+class G extends self::_G&Object&B {
   field dynamic x = null;
   synthetic constructor •() → void
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.outline.expect b/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.outline.expect
index 6e8f7c6..1228829 100644
--- a/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.outline.expect
@@ -33,9 +33,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&B = core::Object with self::B {
+abstract class _G&Object&B = core::Object with self::B {
 }
-class G extends self::_Object&B {
+class G extends self::_G&Object&B {
   field dynamic x;
   synthetic constructor •() → void
     ;
diff --git a/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.strong.expect b/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.strong.expect
index 6666c4d..bc12de8 100644
--- a/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/infer_field_overrides_getter.dart.strong.expect
@@ -39,9 +39,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&B = core::Object with self::B {
+abstract class _G&Object&B = core::Object with self::B {
 }
-class G extends self::_Object&B {
+class G extends self::_G&Object&B {
   field core::int x = null;
   synthetic constructor •() → void
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.direct.expect b/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.direct.expect
index 1dd6525..47d371a 100644
--- a/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.direct.expect
@@ -38,9 +38,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&B = core::Object with self::B {
+abstract class _G&Object&B = core::Object with self::B {
 }
-class G extends self::_Object&B {
+class G extends self::_G&Object&B {
   field dynamic x = null;
   synthetic constructor •() → void
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.outline.expect b/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.outline.expect
index 762f38c..bf71555 100644
--- a/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.outline.expect
@@ -33,9 +33,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&B = core::Object with self::B {
+abstract class _G&Object&B = core::Object with self::B {
 }
-class G extends self::_Object&B {
+class G extends self::_G&Object&B {
   field dynamic x;
   synthetic constructor •() → void
     ;
diff --git a/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.strong.expect b/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.strong.expect
index 30834b6..13ed540 100644
--- a/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/infer_field_overrides_setter.dart.strong.expect
@@ -38,9 +38,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&B = core::Object with self::B {
+abstract class _G&Object&B = core::Object with self::B {
 }
-class G extends self::_Object&B {
+class G extends self::_G&Object&B {
   field core::int x = null;
   synthetic constructor •() → void
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.direct.expect
index 58666dc..5bb0107b 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.direct.expect
@@ -17,9 +17,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
+abstract class _A&M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     : super self::M1::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.outline.expect
index 43cd31c..d2d243e 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.outline.expect
@@ -14,9 +14,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
+abstract class _A&M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.strong.expect
index c6be946..c88b202 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.strong.expect
@@ -17,9 +17,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<core::int, core::String> {
+abstract class _A&M1&M0 = self::M1 with self::M0<core::int, core::String> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     : super self::M1::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.direct.expect
index 91adf7b..99c0ac1 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.direct.expect
@@ -17,9 +17,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
+abstract class _A&M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     : super self::M1::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.outline.expect
index bd994a1..b32af06 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.outline.expect
@@ -14,9 +14,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
+abstract class _A&M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.strong.expect
index c455b6c..fc43a81 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.strong.expect
@@ -17,9 +17,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<core::int, core::int> {
+abstract class _A&M1&M0 = self::M1 with self::M0<core::int, core::int> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     : super self::M1::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.direct.expect
index 55f52e1..1bf2b7f 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.direct.expect
@@ -17,9 +17,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
+abstract class _A&M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     : super self::M1::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
index 2271436..5a8614d 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
@@ -14,9 +14,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
+abstract class _A&M1&M0 = self::M1 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
index 7256dd1..261aee6 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
@@ -17,9 +17,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _M1&M0 = self::M1 with self::M0<core::int, core::Comparable<dynamic>> {
+abstract class _A&M1&M0 = self::M1 with self::M0<core::int, core::Comparable<dynamic>> {
 }
-class A extends self::_M1&M0 {
+class A extends self::_A&M1&M0 {
   synthetic constructor •() → void
     : super self::M1::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.direct.expect
index 3ac06e1..732cded 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.direct.expect
@@ -12,9 +12,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _I&J^#T0^#T1<#T0 extends core::Object, #T1 extends core::Object> = self::I<self::_I&J^#T0^#T1::#T0> with self::J<self::_I&J^#T0^#T1::#T1> {
+abstract class _M0&I&J<X extends core::Object, Y extends core::Object> = self::I<self::_M0&I&J::X> with self::J<self::_M0&I&J::Y> {
 }
-class M0<X extends core::Object, Y extends core::Object> extends self::_I&J^#T0^#T1<self::M0::X, self::M0::Y> {
+class M0<X extends core::Object, Y extends core::Object> extends self::_M0&I&J<self::M0::X, self::M0::Y> {
   synthetic constructor •() → void
     : super self::I::•()
     ;
@@ -29,9 +29,9 @@
     : super self::M1::•()
     ;
 }
-abstract class _M2&M0 = self::M2 with self::M0<dynamic, dynamic> {
+abstract class _A&M2&M0 = self::M2 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M2&M0 {
+class A extends self::_A&M2&M0 {
   synthetic constructor •() → void
     : super self::M2::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.outline.expect
index 57ed82e..5d417f7 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.outline.expect
@@ -10,9 +10,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _I&J^#T0^#T1<#T0 extends core::Object, #T1 extends core::Object> = self::I<self::_I&J^#T0^#T1::#T0> with self::J<self::_I&J^#T0^#T1::#T1> {
+abstract class _M0&I&J<X extends core::Object, Y extends core::Object> = self::I<self::_M0&I&J::X> with self::J<self::_M0&I&J::Y> {
 }
-class M0<X extends core::Object, Y extends core::Object> extends self::_I&J^#T0^#T1<self::M0::X, self::M0::Y> {
+class M0<X extends core::Object, Y extends core::Object> extends self::_M0&I&J<self::M0::X, self::M0::Y> {
   synthetic constructor •() → void
     ;
 }
@@ -24,9 +24,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M2&M0 = self::M2 with self::M0<dynamic, dynamic> {
+abstract class _A&M2&M0 = self::M2 with self::M0<dynamic, dynamic> {
 }
-class A extends self::_M2&M0 {
+class A extends self::_A&M2&M0 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.strong.expect
index 420f505..92d614a 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_multiple_constraints.dart.strong.expect
@@ -12,9 +12,9 @@
     : super core::Object::•()
     ;
 }
-abstract class _I&J^#T0^#T1<#T0 extends core::Object, #T1 extends core::Object> = self::I<self::_I&J^#T0^#T1::#T0> with self::J<self::_I&J^#T0^#T1::#T1> {
+abstract class _M0&I&J<X extends core::Object, Y extends core::Object> = self::I<self::_M0&I&J::X> with self::J<self::_M0&I&J::Y> {
 }
-class M0<X extends core::Object, Y extends core::Object> extends self::_I&J^#T0^#T1<self::M0::X, self::M0::Y> {
+class M0<X extends core::Object, Y extends core::Object> extends self::_M0&I&J<self::M0::X, self::M0::Y> {
   synthetic constructor •() → void
     : super self::I::•()
     ;
@@ -29,9 +29,9 @@
     : super self::M1::•()
     ;
 }
-abstract class _M2&M0 = self::M2 with self::M0<core::int, core::double> {
+abstract class _A&M2&M0 = self::M2 with self::M0<core::int, core::double> {
 }
-class A extends self::_M2&M0 {
+class A extends self::_A&M2&M0 {
   synthetic constructor •() → void
     : super self::M2::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.direct.expect
index e1b1656..ce175b8 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.direct.expect
@@ -22,9 +22,9 @@
     : super self::M1::•()
     ;
 }
-abstract class _M2&M0^#U0^<#U0 extends core::Object> = self::M2<self::_M2&M0^#U0^::#U0> with self::M0<dynamic> {
+abstract class _A&M2&M0 = self::M2<core::int> with self::M0<dynamic> {
 }
-class A extends self::_M2&M0^#U0^<core::int> {
+class A extends self::_A&M2&M0 {
   synthetic constructor •() → void
     : super self::M2::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.outline.expect
index 130fe8c8..a626b7e 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.outline.expect
@@ -18,9 +18,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M2&M0^#U0^<#U0 extends core::Object> = self::M2<self::_M2&M0^#U0^::#U0> with self::M0<dynamic> {
+abstract class _A&M2&M0 = self::M2<core::int> with self::M0<dynamic> {
 }
-class A extends self::_M2&M0^#U0^<core::int> {
+class A extends self::_A&M2&M0 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.strong.expect
index 07bb906..bc3f07d 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_non_trivial_constraints.dart.strong.expect
@@ -22,9 +22,9 @@
     : super self::M1::•()
     ;
 }
-abstract class _M2&M0^#U0^<#U0 extends core::Object> = self::M2<self::_M2&M0^#U0^::#U0> with self::M0<core::Map<self::_M2&M0^#U0^::#U0, self::_M2&M0^#U0^::#U0>> {
+abstract class _A&M2&M0 = self::M2<core::int> with self::M0<core::Map<core::int, core::int>> {
 }
-class A extends self::_M2&M0^#U0^<core::int> {
+class A extends self::_A&M2&M0 {
   synthetic constructor •() → void
     : super self::M2::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.direct.expect
index a445dca..58630ac 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.direct.expect
@@ -17,9 +17,9 @@
     : super self::I::•()
     ;
 }
-abstract class _M0&M1^#U0^<#U0 extends core::Object> = self::M0<self::_M0&M1^#U0^::#U0> with self::M1<dynamic> {
+abstract class _A&M0&M1 = self::M0<core::int> with self::M1<dynamic> {
 }
-class A extends self::_M0&M1^#U0^<core::int> {
+class A extends self::_A&M0&M1 {
   synthetic constructor •() → void
     : super self::M0::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.outline.expect
index 185c73d..e7482bf 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.outline.expect
@@ -14,9 +14,9 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M0&M1^#U0^<#U0 extends core::Object> = self::M0<self::_M0&M1^#U0^::#U0> with self::M1<dynamic> {
+abstract class _A&M0&M1 = self::M0<core::int> with self::M1<dynamic> {
 }
-class A extends self::_M0&M1^#U0^<core::int> {
+class A extends self::_A&M0&M1 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.strong.expect
index 046015f..a21a809 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_1.dart.strong.expect
@@ -17,9 +17,9 @@
     : super self::I::•()
     ;
 }
-abstract class _M0&M1^#U0^<#U0 extends core::Object> = self::M0<self::_M0&M1^#U0^::#U0> with self::M1<self::_M0&M1^#U0^::#U0> {
+abstract class _A&M0&M1 = self::M0<core::int> with self::M1<core::int> {
 }
-class A extends self::_M0&M1^#U0^<core::int> {
+class A extends self::_A&M0&M1 {
   synthetic constructor •() → void
     : super self::M0::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.direct.expect
index 51ca970..848a79e 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.direct.expect
@@ -22,11 +22,11 @@
     : super self::I::•()
     ;
 }
-abstract class _M0&M1^#U0^<#U0 extends core::Object> = self::M0<self::_M0&M1^#U0^::#U0> with self::M1<dynamic> {
+abstract class _A&M0&M1 = self::M0<core::int> with self::M1<dynamic> {
 }
-abstract class __M0&M1&M2^#U0^^<#U0 extends core::Object> = self::_M0&M1^#U0^<self::__M0&M1&M2^#U0^^::#U0> with self::M2<dynamic> {
+abstract class _A&M0&M1&M2 = self::_A&M0&M1 with self::M2<dynamic> {
 }
-class A extends self::__M0&M1&M2^#U0^^<core::int> {
+class A extends self::_A&M0&M1&M2 {
   synthetic constructor •() → void
     : super self::M0::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.outline.expect
index 453336f..acc4658 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.outline.expect
@@ -18,11 +18,11 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _M0&M1^#U0^<#U0 extends core::Object> = self::M0<self::_M0&M1^#U0^::#U0> with self::M1<dynamic> {
+abstract class _A&M0&M1 = self::M0<core::int> with self::M1<dynamic> {
 }
-abstract class __M0&M1&M2^#U0^^<#U0 extends core::Object> = self::_M0&M1^#U0^<self::__M0&M1&M2^#U0^^::#U0> with self::M2<dynamic> {
+abstract class _A&M0&M1&M2 = self::_A&M0&M1 with self::M2<dynamic> {
 }
-class A extends self::__M0&M1&M2^#U0^^<core::int> {
+class A extends self::_A&M0&M1&M2 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.strong.expect
index 6cc9bf5..036d56c 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_2.dart.strong.expect
@@ -22,11 +22,11 @@
     : super self::I::•()
     ;
 }
-abstract class _M0&M1^#U0^<#U0 extends core::Object> = self::M0<self::_M0&M1^#U0^::#U0> with self::M1<self::_M0&M1^#U0^::#U0> {
+abstract class _A&M0&M1 = self::M0<core::int> with self::M1<core::int> {
 }
-abstract class __M0&M1&M2^#U0^^<#U0 extends core::Object> = self::_M0&M1^#U0^<self::__M0&M1&M2^#U0^^::#U0> with self::M2<self::__M0&M1&M2^#U0^^::#U0> {
+abstract class _A&M0&M1&M2 = self::_A&M0&M1 with self::M2<core::int> {
 }
-class A extends self::__M0&M1&M2^#U0^^<core::int> {
+class A extends self::_A&M0&M1&M2 {
   synthetic constructor •() → void
     : super self::M0::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.direct.expect
index 2613be2..a9749fe 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.direct.expect
@@ -17,11 +17,11 @@
     : super self::I::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1^^^#U0<#U0 extends core::Object> = self::_Object&M0 with self::M1<self::__Object&M0&M1^^^#U0::#U0> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<core::int> {
 }
-class A extends self::__Object&M0&M1^^^#U0<core::int> {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.outline.expect
index 299bf73..f83992c 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.outline.expect
@@ -14,11 +14,11 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1^^^#U0<#U0 extends core::Object> = self::_Object&M0 with self::M1<self::__Object&M0&M1^^^#U0::#U0> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<core::int> {
 }
-class A extends self::__Object&M0&M1^^^#U0<core::int> {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.strong.expect
index 2613be2..a9749fe 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_3.dart.strong.expect
@@ -17,11 +17,11 @@
     : super self::I::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1^^^#U0<#U0 extends core::Object> = self::_Object&M0 with self::M1<self::__Object&M0&M1^^^#U0::#U0> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<core::int> {
 }
-class A extends self::__Object&M0&M1^^^#U0<core::int> {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.direct.expect
index 7928f75..b341add 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.direct.expect
@@ -17,11 +17,11 @@
     : super self::I::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 implements self::I<core::int> {
+class A extends self::_A&Object&M0&M1 implements self::I<core::int> {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.outline.expect
index 75c5146..46f1868 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.outline.expect
@@ -14,11 +14,11 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 implements self::I<core::int> {
+class A extends self::_A&Object&M0&M1 implements self::I<core::int> {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.strong.expect
index 7928f75..b341add 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_outwards_4.dart.strong.expect
@@ -17,11 +17,11 @@
     : super self::I::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 implements self::I<core::int> {
+class A extends self::_A&Object&M0&M1 implements self::I<core::int> {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.direct.expect
index f3fb9a5..f15969d 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.direct.expect
@@ -17,11 +17,11 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.outline.expect
index 43277d0..4e5c65c 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.outline.expect
@@ -14,11 +14,11 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.strong.expect
index f3fb9a5..f15969d 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_unification_1.dart.strong.expect
@@ -17,11 +17,11 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.direct.expect b/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.direct.expect
index ba12e18..1cf79e6 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.direct.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.direct.expect
@@ -17,11 +17,11 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.outline.expect
index 7a9af6b..82b7624 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.outline.expect
@@ -14,11 +14,11 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.strong.expect
index ba12e18..1cf79e6 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_unification_2.dart.strong.expect
@@ -17,11 +17,11 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&M0 = core::Object with self::M0<dynamic> {
+abstract class _A&Object&M0 = core::Object with self::M0<dynamic> {
 }
-abstract class __Object&M0&M1 = self::_Object&M0 with self::M1<dynamic> {
+abstract class _A&Object&M0&M1 = self::_A&Object&M0 with self::M1<dynamic> {
 }
-class A extends self::__Object&M0&M1 {
+class A extends self::_A&Object&M0&M1 {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin.dart.direct.expect b/pkg/front_end/testcases/mixin.dart.direct.expect
index 82cbfbd..7ebdddc 100644
--- a/pkg/front_end/testcases/mixin.dart.direct.expect
+++ b/pkg/front_end/testcases/mixin.dart.direct.expect
@@ -2,11 +2,11 @@
 import self as self;
 import "dart:core" as core;
 
-abstract class _Object&M1 = core::Object with self::M1 {
+abstract class _B&Object&M1 = core::Object with self::M1 {
 }
-abstract class __Object&M1&M2 = self::_Object&M1 with self::M2 {
+abstract class _B&Object&M1&M2 = self::_B&Object&M1 with self::M2 {
 }
-class B extends self::__Object&M1&M2 {
+class B extends self::_B&Object&M1&M2 {
   constructor •(dynamic value) → void
     : super core::Object::•()
     ;
@@ -25,7 +25,11 @@
   method m() → dynamic
     return core::print("M2");
 }
-class C extends self::__Object&M1&M2 {
+abstract class _C&Object&M1 = core::Object with self::M1 {
+}
+abstract class _C&Object&M1&M2 = self::_C&Object&M1 with self::M2 {
+}
+class C extends self::_C&Object&M1&M2 {
   constructor •(dynamic value) → void
     : super core::Object::•()
     ;
@@ -37,9 +41,9 @@
   method m() → dynamic
     return core::print(self::G1::T);
 }
-abstract class _Object&G1^^#T0<#T0 extends core::Object> = core::Object with self::G1<self::_Object&G1^^#T0::#T0> {
+abstract class _D&Object&G1<S extends core::Object> = core::Object with self::G1<self::_D&Object&G1::S> {
 }
-class D<S extends core::Object> extends self::_Object&G1^^#T0<self::D::S> {
+class D<S extends core::Object> extends self::_D&Object&G1<self::D::S> {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin.dart.outline.expect b/pkg/front_end/testcases/mixin.dart.outline.expect
index f2e9d27..ec5b2f3 100644
--- a/pkg/front_end/testcases/mixin.dart.outline.expect
+++ b/pkg/front_end/testcases/mixin.dart.outline.expect
@@ -2,11 +2,11 @@
 import self as self;
 import "dart:core" as core;
 
-abstract class _Object&M1 = core::Object with self::M1 {
+abstract class _B&Object&M1 = core::Object with self::M1 {
 }
-abstract class __Object&M1&M2 = self::_Object&M1 with self::M2 {
+abstract class _B&Object&M1&M2 = self::_B&Object&M1 with self::M2 {
 }
-class B extends self::__Object&M1&M2 {
+class B extends self::_B&Object&M1&M2 {
   constructor •(dynamic value) → void
     ;
 }
@@ -22,7 +22,11 @@
   method m() → dynamic
     ;
 }
-class C extends self::__Object&M1&M2 {
+abstract class _C&Object&M1 = core::Object with self::M1 {
+}
+abstract class _C&Object&M1&M2 = self::_C&Object&M1 with self::M2 {
+}
+class C extends self::_C&Object&M1&M2 {
   constructor •(dynamic value) → void
     ;
 }
@@ -32,9 +36,9 @@
   method m() → dynamic
     ;
 }
-abstract class _Object&G1^^#T0<#T0 extends core::Object> = core::Object with self::G1<self::_Object&G1^^#T0::#T0> {
+abstract class _D&Object&G1<S extends core::Object> = core::Object with self::G1<self::_D&Object&G1::S> {
 }
-class D<S extends core::Object> extends self::_Object&G1^^#T0<self::D::S> {
+class D<S extends core::Object> extends self::_D&Object&G1<self::D::S> {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/mixin.dart.strong.expect b/pkg/front_end/testcases/mixin.dart.strong.expect
index bdaa070..b60be6e 100644
--- a/pkg/front_end/testcases/mixin.dart.strong.expect
+++ b/pkg/front_end/testcases/mixin.dart.strong.expect
@@ -2,11 +2,11 @@
 import self as self;
 import "dart:core" as core;
 
-abstract class _Object&M1 = core::Object with self::M1 {
+abstract class _B&Object&M1 = core::Object with self::M1 {
 }
-abstract class __Object&M1&M2 = self::_Object&M1 with self::M2 {
+abstract class _B&Object&M1&M2 = self::_B&Object&M1 with self::M2 {
 }
-class B extends self::__Object&M1&M2 {
+class B extends self::_B&Object&M1&M2 {
   constructor •(dynamic value) → void
     : super core::Object::•()
     ;
@@ -25,7 +25,11 @@
   method m() → dynamic
     return core::print("M2");
 }
-class C extends self::__Object&M1&M2 {
+abstract class _C&Object&M1 = core::Object with self::M1 {
+}
+abstract class _C&Object&M1&M2 = self::_C&Object&M1 with self::M2 {
+}
+class C extends self::_C&Object&M1&M2 {
   constructor •(dynamic value) → void
     : super core::Object::•()
     ;
@@ -37,9 +41,9 @@
   method m() → dynamic
     return core::print(self::G1::T);
 }
-abstract class _Object&G1^^#T0<#T0 extends core::Object> = core::Object with self::G1<self::_Object&G1^^#T0::#T0> {
+abstract class _D&Object&G1<S extends core::Object> = core::Object with self::G1<self::_D&Object&G1::S> {
 }
-class D<S extends core::Object> extends self::_Object&G1^^#T0<self::D::S> {
+class D<S extends core::Object> extends self::_D&Object&G1<self::D::S> {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin_super_repeated.dart b/pkg/front_end/testcases/mixin_super_repeated.dart
new file mode 100644
index 0000000..e9453fd
--- /dev/null
+++ b/pkg/front_end/testcases/mixin_super_repeated.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.
+
+abstract class M {
+  var m;
+}
+
+abstract class N extends M {
+  void set superM(value) {
+    super.m = value;
+  }
+
+  get superM => super.m;
+}
+
+class S {}
+
+class Named = S with M, N, M;
+
+main() {
+  Named named = new Named();
+  named.m = 42;
+  named.superM = 87;
+  if (named.m != 42) {
+    throw "Bad mixin translation of set:superM";
+  }
+  if (named.superM != 87) {
+    throw "Bad mixin translation of get:superM";
+  }
+}
diff --git a/pkg/front_end/testcases/mixin_super_repeated.dart.direct.expect b/pkg/front_end/testcases/mixin_super_repeated.dart.direct.expect
new file mode 100644
index 0000000..84f870b
--- /dev/null
+++ b/pkg/front_end/testcases/mixin_super_repeated.dart.direct.expect
@@ -0,0 +1,45 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class M extends core::Object {
+  field dynamic m = null;
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+abstract class N extends self::M {
+  synthetic constructor •() → void
+    : super self::M::•()
+    ;
+  set superM(dynamic value) → void {
+    super.{self::M::m} = value;
+  }
+  get superM() → dynamic
+    return super.{self::M::m};
+}
+class S extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+abstract class _Named&S&M = self::S with self::M {
+}
+abstract class _Named&S&M&N = self::_Named&S&M with self::N {
+}
+class Named = self::_Named&S&M&N with self::M {
+  synthetic constructor •() → void
+    : super self::S::•()
+    ;
+}
+static method main() → dynamic {
+  self::Named named = new self::Named::•();
+  named.m = 42;
+  named.superM = 87;
+  if(!named.m.==(42)) {
+    throw "Bad mixin translation of set:superM";
+  }
+  if(!named.superM.==(87)) {
+    throw "Bad mixin translation of get:superM";
+  }
+}
diff --git a/pkg/front_end/testcases/mixin_super_repeated.dart.outline.expect b/pkg/front_end/testcases/mixin_super_repeated.dart.outline.expect
new file mode 100644
index 0000000..a267b35
--- /dev/null
+++ b/pkg/front_end/testcases/mixin_super_repeated.dart.outline.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class M extends core::Object {
+  field dynamic m;
+  synthetic constructor •() → void
+    ;
+}
+abstract class N extends self::M {
+  synthetic constructor •() → void
+    ;
+  set superM(dynamic value) → void
+    ;
+  get superM() → dynamic
+    ;
+}
+class S extends core::Object {
+  synthetic constructor •() → void
+    ;
+}
+abstract class _Named&S&M = self::S with self::M {
+}
+abstract class _Named&S&M&N = self::_Named&S&M with self::N {
+}
+class Named = self::_Named&S&M&N with self::M {
+  synthetic constructor •() → void
+    : super self::S::•()
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/mixin_super_repeated.dart.strong.expect b/pkg/front_end/testcases/mixin_super_repeated.dart.strong.expect
new file mode 100644
index 0000000..4ece1f0
--- /dev/null
+++ b/pkg/front_end/testcases/mixin_super_repeated.dart.strong.expect
@@ -0,0 +1,45 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class M extends core::Object {
+  field dynamic m = null;
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+abstract class N extends self::M {
+  synthetic constructor •() → void
+    : super self::M::•()
+    ;
+  set superM(dynamic value) → void {
+    super.{self::M::m} = value;
+  }
+  get superM() → dynamic
+    return super.{self::M::m};
+}
+class S extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+abstract class _Named&S&M = self::S with self::M {
+}
+abstract class _Named&S&M&N = self::_Named&S&M with self::N {
+}
+class Named = self::_Named&S&M&N with self::M {
+  synthetic constructor •() → void
+    : super self::S::•()
+    ;
+}
+static method main() → dynamic {
+  self::Named named = new self::Named::•();
+  named.{self::M::m} = 42;
+  named.{self::N::superM} = 87;
+  if(!named.{self::M::m}.==(42)) {
+    throw "Bad mixin translation of set:superM";
+  }
+  if(!named.{self::N::superM}.==(87)) {
+    throw "Bad mixin translation of get:superM";
+  }
+}
diff --git a/pkg/front_end/testcases/qualified.dart.direct.expect b/pkg/front_end/testcases/qualified.dart.direct.expect
index 07abef7..85f2bbf 100644
--- a/pkg/front_end/testcases/qualified.dart.direct.expect
+++ b/pkg/front_end/testcases/qualified.dart.direct.expect
@@ -7,9 +7,9 @@
   method method() → invalid-type {}
   static factory WrongName() → self::Bad {}
 }
-abstract class _lib.Supertype&lib.Mixin = lib::Supertype with lib::Mixin {
+abstract class _WithMixin&Supertype&Mixin = lib::Supertype with lib::Mixin {
 }
-class WithMixin extends self::_lib.Supertype&lib.Mixin {
+class WithMixin extends self::_WithMixin&Supertype&Mixin {
   synthetic constructor •() → void
     : super lib::Supertype::•()
     ;
diff --git a/pkg/front_end/testcases/qualified.dart.outline.expect b/pkg/front_end/testcases/qualified.dart.outline.expect
index 16d0055..1214470 100644
--- a/pkg/front_end/testcases/qualified.dart.outline.expect
+++ b/pkg/front_end/testcases/qualified.dart.outline.expect
@@ -9,9 +9,9 @@
   static factory WrongName() → self::Bad
     ;
 }
-abstract class _lib.Supertype&lib.Mixin = lib::Supertype with lib::Mixin {
+abstract class _WithMixin&Supertype&Mixin = lib::Supertype with lib::Mixin {
 }
-class WithMixin extends self::_lib.Supertype&lib.Mixin {
+class WithMixin extends self::_WithMixin&Supertype&Mixin {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/qualified.dart.strong.expect b/pkg/front_end/testcases/qualified.dart.strong.expect
index 79b0cfb..4522e74 100644
--- a/pkg/front_end/testcases/qualified.dart.strong.expect
+++ b/pkg/front_end/testcases/qualified.dart.strong.expect
@@ -7,9 +7,9 @@
   method method() → invalid-type {}
   static factory WrongName() → self::Bad {}
 }
-abstract class _lib.Supertype&lib.Mixin = lib::Supertype with lib::Mixin {
+abstract class _WithMixin&Supertype&Mixin = lib::Supertype with lib::Mixin {
 }
-class WithMixin extends self::_lib.Supertype&lib.Mixin {
+class WithMixin extends self::_WithMixin&Supertype&Mixin {
   synthetic constructor •() → void
     : super lib::Supertype::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/duplicated_mixin.dart.direct.expect b/pkg/front_end/testcases/rasta/duplicated_mixin.dart.direct.expect
index af20a91..8d36ce1 100644
--- a/pkg/front_end/testcases/rasta/duplicated_mixin.dart.direct.expect
+++ b/pkg/front_end/testcases/rasta/duplicated_mixin.dart.direct.expect
@@ -8,11 +8,11 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&Mixin = core::Object with self::Mixin {
+abstract class _A&Object&Mixin = core::Object with self::Mixin {
 }
-abstract class __Object&Mixin&Mixin = self::_Object&Mixin with self::Mixin {
+abstract class _A&Object&Mixin&Mixin = self::_A&Object&Mixin with self::Mixin {
 }
-class A extends self::__Object&Mixin&Mixin {
+class A extends self::_A&Object&Mixin&Mixin {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/duplicated_mixin.dart.outline.expect b/pkg/front_end/testcases/rasta/duplicated_mixin.dart.outline.expect
index 68a7de9..494e9e1 100644
--- a/pkg/front_end/testcases/rasta/duplicated_mixin.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/duplicated_mixin.dart.outline.expect
@@ -7,11 +7,11 @@
   synthetic constructor •() → void
     ;
 }
-abstract class _Object&Mixin = core::Object with self::Mixin {
+abstract class _A&Object&Mixin = core::Object with self::Mixin {
 }
-abstract class __Object&Mixin&Mixin = self::_Object&Mixin with self::Mixin {
+abstract class _A&Object&Mixin&Mixin = self::_A&Object&Mixin with self::Mixin {
 }
-class A extends self::__Object&Mixin&Mixin {
+class A extends self::_A&Object&Mixin&Mixin {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/rasta/duplicated_mixin.dart.strong.expect b/pkg/front_end/testcases/rasta/duplicated_mixin.dart.strong.expect
index af20a91..8d36ce1 100644
--- a/pkg/front_end/testcases/rasta/duplicated_mixin.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/duplicated_mixin.dart.strong.expect
@@ -8,11 +8,11 @@
     : super core::Object::•()
     ;
 }
-abstract class _Object&Mixin = core::Object with self::Mixin {
+abstract class _A&Object&Mixin = core::Object with self::Mixin {
 }
-abstract class __Object&Mixin&Mixin = self::_Object&Mixin with self::Mixin {
+abstract class _A&Object&Mixin&Mixin = self::_A&Object&Mixin with self::Mixin {
 }
-class A extends self::__Object&Mixin&Mixin {
+class A extends self::_A&Object&Mixin&Mixin {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/issue_000007.dart.direct.expect b/pkg/front_end/testcases/rasta/issue_000007.dart.direct.expect
index 0d5738c..524ca4d 100644
--- a/pkg/front_end/testcases/rasta/issue_000007.dart.direct.expect
+++ b/pkg/front_end/testcases/rasta/issue_000007.dart.direct.expect
@@ -14,9 +14,9 @@
   method foo() → dynamic
     return core::print("foo");
 }
-abstract class _Base&Mixin = self::Base with self::Mixin {
+abstract class _Sub&Base&Mixin = self::Base with self::Mixin {
 }
-class Sub extends self::_Base&Mixin {
+class Sub extends self::_Sub&Base&Mixin {
   synthetic constructor •() → void
     : super self::Base::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/issue_000007.dart.outline.expect b/pkg/front_end/testcases/rasta/issue_000007.dart.outline.expect
index 7694753..f322f88 100644
--- a/pkg/front_end/testcases/rasta/issue_000007.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/issue_000007.dart.outline.expect
@@ -12,9 +12,9 @@
   method foo() → dynamic
     ;
 }
-abstract class _Base&Mixin = self::Base with self::Mixin {
+abstract class _Sub&Base&Mixin = self::Base with self::Mixin {
 }
-class Sub extends self::_Base&Mixin {
+class Sub extends self::_Sub&Base&Mixin {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/rasta/issue_000007.dart.strong.expect b/pkg/front_end/testcases/rasta/issue_000007.dart.strong.expect
index a970df5..55136c8 100644
--- a/pkg/front_end/testcases/rasta/issue_000007.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/issue_000007.dart.strong.expect
@@ -14,9 +14,9 @@
   method foo() → dynamic
     return core::print("foo");
 }
-abstract class _Base&Mixin = self::Base with self::Mixin {
+abstract class _Sub&Base&Mixin = self::Base with self::Mixin {
 }
-class Sub extends self::_Base&Mixin {
+class Sub extends self::_Sub&Base&Mixin {
   synthetic constructor •() → void
     : super self::Base::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/issue_000080.dart.direct.expect b/pkg/front_end/testcases/rasta/issue_000080.dart.direct.expect
index 35cf1612..1e8a13f 100644
--- a/pkg/front_end/testcases/rasta/issue_000080.dart.direct.expect
+++ b/pkg/front_end/testcases/rasta/issue_000080.dart.direct.expect
@@ -10,9 +10,9 @@
   method foo() → dynamic
     return 87;
 }
-abstract class _Object&Mixin = core::Object with self::Mixin {
+abstract class _Foo&Object&Mixin = core::Object with self::Mixin {
 }
-class Foo extends self::_Object&Mixin {
+class Foo extends self::_Foo&Object&Mixin {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/issue_000080.dart.outline.expect b/pkg/front_end/testcases/rasta/issue_000080.dart.outline.expect
index f5c3d07..c254729 100644
--- a/pkg/front_end/testcases/rasta/issue_000080.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/issue_000080.dart.outline.expect
@@ -9,9 +9,9 @@
   method foo() → dynamic
     ;
 }
-abstract class _Object&Mixin = core::Object with self::Mixin {
+abstract class _Foo&Object&Mixin = core::Object with self::Mixin {
 }
-class Foo extends self::_Object&Mixin {
+class Foo extends self::_Foo&Object&Mixin {
   synthetic constructor •() → void
     ;
   method foo() → dynamic
diff --git a/pkg/front_end/testcases/rasta/issue_000080.dart.strong.expect b/pkg/front_end/testcases/rasta/issue_000080.dart.strong.expect
index d0251cd..a336a75 100644
--- a/pkg/front_end/testcases/rasta/issue_000080.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/issue_000080.dart.strong.expect
@@ -10,9 +10,9 @@
   method foo() → dynamic
     return 87;
 }
-abstract class _Object&Mixin = core::Object with self::Mixin {
+abstract class _Foo&Object&Mixin = core::Object with self::Mixin {
 }
-class Foo extends self::_Object&Mixin {
+class Foo extends self::_Foo&Object&Mixin {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/super_mixin.dart.direct.expect b/pkg/front_end/testcases/rasta/super_mixin.dart.direct.expect
index 0dfe536..25388a4 100644
--- a/pkg/front_end/testcases/rasta/super_mixin.dart.direct.expect
+++ b/pkg/front_end/testcases/rasta/super_mixin.dart.direct.expect
@@ -12,16 +12,16 @@
   method f() → dynamic
     return 3;
 }
-abstract class _Super&Mixin^#T0^#T0<#T0 extends core::Object> = self::Super<self::_Super&Mixin^#T0^#T0::#T0> with mix::Mixin<self::_Super&Mixin^#T0^#T0::#T0> {
+abstract class _C&Super&Mixin<V extends core::Object> = self::Super<self::_C&Super&Mixin::V> with mix::Mixin<self::_C&Super&Mixin::V> {
 }
-class C<V extends core::Object> extends self::_Super&Mixin^#T0^#T0<self::C::V> {
+class C<V extends core::Object> extends self::_C&Super&Mixin<self::C::V> {
   synthetic constructor •() → void
     : super self::Super::•()
     ;
 }
-abstract class _Super&Mixin = self::Super<dynamic> with mix::Mixin<dynamic> {
+abstract class _D&Super&Mixin = self::Super<dynamic> with mix::Mixin<dynamic> {
 }
-class D extends self::_Super&Mixin {
+class D extends self::_D&Super&Mixin {
   synthetic constructor •() → void
     : super self::Super::•()
     ;
diff --git a/pkg/front_end/testcases/rasta/super_mixin.dart.outline.expect b/pkg/front_end/testcases/rasta/super_mixin.dart.outline.expect
index 5c8d386..e1bc111 100644
--- a/pkg/front_end/testcases/rasta/super_mixin.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/super_mixin.dart.outline.expect
@@ -11,15 +11,15 @@
   method f() → dynamic
     ;
 }
-abstract class _Super&Mixin^#T0^#T0<#T0 extends core::Object> = self::Super<self::_Super&Mixin^#T0^#T0::#T0> with mix::Mixin<self::_Super&Mixin^#T0^#T0::#T0> {
+abstract class _C&Super&Mixin<V extends core::Object> = self::Super<self::_C&Super&Mixin::V> with mix::Mixin<self::_C&Super&Mixin::V> {
 }
-class C<V extends core::Object> extends self::_Super&Mixin^#T0^#T0<self::C::V> {
+class C<V extends core::Object> extends self::_C&Super&Mixin<self::C::V> {
   synthetic constructor •() → void
     ;
 }
-abstract class _Super&Mixin = self::Super<dynamic> with mix::Mixin<dynamic> {
+abstract class _D&Super&Mixin = self::Super<dynamic> with mix::Mixin<dynamic> {
 }
-class D extends self::_Super&Mixin {
+class D extends self::_D&Super&Mixin {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/rasta/super_mixin.dart.strong.expect b/pkg/front_end/testcases/rasta/super_mixin.dart.strong.expect
index fb1ba40..6a403fb 100644
--- a/pkg/front_end/testcases/rasta/super_mixin.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/super_mixin.dart.strong.expect
@@ -12,18 +12,18 @@
   method f() → dynamic
     return 3;
 }
-abstract class _Super&Mixin^#T0^#T0<#T0 extends core::Object> = self::Super<self::_Super&Mixin^#T0^#T0::#T0> with mix::Mixin<self::_Super&Mixin^#T0^#T0::#T0> {
+abstract class _C&Super&Mixin<V extends core::Object> = self::Super<self::_C&Super&Mixin::V> with mix::Mixin<self::_C&Super&Mixin::V> {
 }
-class C<V extends core::Object> extends self::_Super&Mixin^#T0^#T0<self::C::V> {
+class C<V extends core::Object> extends self::_C&Super&Mixin<self::C::V> {
   synthetic constructor •() → void
     : super self::Super::•()
     ;
 }
-abstract class _Super&Mixin = self::Super<dynamic> with mix::Mixin<dynamic> {
+abstract class _D&Super&Mixin = self::Super<dynamic> with mix::Mixin<dynamic> {
   abstract forwarding-stub method g(generic-covariant-impl dynamic a) → dynamic;
   abstract forwarding-stub set t(generic-covariant-impl dynamic _) → void;
 }
-class D extends self::_Super&Mixin {
+class D extends self::_D&Super&Mixin {
   synthetic constructor •() → void
     : super self::Super::•()
     ;
diff --git a/pkg/front_end/testcases/regress/issue_32182.dart.direct.expect b/pkg/front_end/testcases/regress/issue_32182.dart.direct.expect
index 4a0cedc..634143d 100644
--- a/pkg/front_end/testcases/regress/issue_32182.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_32182.dart.direct.expect
@@ -14,9 +14,9 @@
   method m() → dynamic
     return 42;
 }
-abstract class _A&M^#U0^<#U0 extends core::Object> = self::A<self::_A&M^#U0^::#U0> with self::M {
+abstract class _C&A&M = self::A<self::A<dynamic>> with self::M {
 }
-class C extends self::_A&M^#U0^<self::A<dynamic>> {
+class C extends self::_C&A&M {
   synthetic constructor •() → void
     : super self::A::•()
     ;
diff --git a/pkg/front_end/testcases/regress/issue_32182.dart.outline.expect b/pkg/front_end/testcases/regress/issue_32182.dart.outline.expect
index b04b47b..92da155 100644
--- a/pkg/front_end/testcases/regress/issue_32182.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_32182.dart.outline.expect
@@ -12,9 +12,9 @@
   method m() → dynamic
     ;
 }
-abstract class _A&M^#U0^<#U0 extends core::Object> = self::A<self::_A&M^#U0^::#U0> with self::M {
+abstract class _C&A&M = self::A<self::A<dynamic>> with self::M {
 }
-class C extends self::_A&M^#U0^<self::A<dynamic>> {
+class C extends self::_C&A&M {
   synthetic constructor •() → void
     ;
 }
diff --git a/pkg/front_end/testcases/regress/issue_32182.dart.strong.expect b/pkg/front_end/testcases/regress/issue_32182.dart.strong.expect
index 9bf3c1c..e9a1802 100644
--- a/pkg/front_end/testcases/regress/issue_32182.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_32182.dart.strong.expect
@@ -14,9 +14,9 @@
   method m() → dynamic
     return 42;
 }
-abstract class _A&M^#U0^<#U0 extends core::Object> = self::A<self::_A&M^#U0^::#U0> with self::M {
+abstract class _C&A&M = self::A<self::A<dynamic>> with self::M {
 }
-class C extends self::_A&M^#U0^<self::A<dynamic>> {
+class C extends self::_C&A&M {
   synthetic constructor •() → void
     : super self::A::•()
     ;
diff --git a/pkg/front_end/testcases/shaker/empty_program.dart.outline.expect b/pkg/front_end/testcases/shaker/empty_program.dart.outline.expect
index 8e30b21..636512b 100644
--- a/pkg/front_end/testcases/shaker/empty_program.dart.outline.expect
+++ b/pkg/front_end/testcases/shaker/empty_program.dart.outline.expect
@@ -321,6 +321,7 @@
 }
 abstract class Invocation extends self::Object {
   abstract get memberName() → self::Symbol;
+  get typeArguments() → self::List<self::Type>;
   abstract get positionalArguments() → self::List<dynamic>;
   abstract get namedArguments() → self::Map<self::Symbol, dynamic>;
   abstract get isMethod() → self::bool;
diff --git a/pkg/front_end/testcases/shaker/empty_program.dart.shaker.expect b/pkg/front_end/testcases/shaker/empty_program.dart.shaker.expect
index 56ce3ff..3844c72 100644
--- a/pkg/front_end/testcases/shaker/empty_program.dart.shaker.expect
+++ b/pkg/front_end/testcases/shaker/empty_program.dart.shaker.expect
@@ -263,6 +263,7 @@
     - toRadixString
   - class Invocation
     - memberName
+    - typeArguments
     - positionalArguments
     - namedArguments
     - isMethod
diff --git a/pkg/front_end/testcases/shaker/source_top.dart.outline.expect b/pkg/front_end/testcases/shaker/source_top.dart.outline.expect
index 781008f..019bb8a 100644
--- a/pkg/front_end/testcases/shaker/source_top.dart.outline.expect
+++ b/pkg/front_end/testcases/shaker/source_top.dart.outline.expect
@@ -17,9 +17,9 @@
   synthetic constructor •() → void
     : super core::Object::•();
 }
-abstract class _Object&A3 extends core::Object implements sou::A3 {
+abstract class _C3&Object&A3 extends core::Object implements sou::A3 {
 }
-class C3 extends self::_Object&A3 {
+class C3 extends self::_C3&Object&A3 {
   synthetic constructor •() → void
     : super core::Object::•();
 }
diff --git a/pkg/front_end/testcases/shaker/transitive_mixins.dart.outline.expect b/pkg/front_end/testcases/shaker/transitive_mixins.dart.outline.expect
index d56843d..b823ddf 100644
--- a/pkg/front_end/testcases/shaker/transitive_mixins.dart.outline.expect
+++ b/pkg/front_end/testcases/shaker/transitive_mixins.dart.outline.expect
@@ -17,8 +17,8 @@
 }
 class B extends core::Object {
 }
-abstract class _Object&A extends core::Object implements self::A {
+abstract class _C&Object&A extends core::Object implements self::A {
 }
-class C extends self::_Object&A implements self::B {
+class C extends self::_C&Object&A implements self::B {
 }
 
diff --git a/pkg/front_end/testcases/shaker/transitive_mixins.dart.shaker.expect b/pkg/front_end/testcases/shaker/transitive_mixins.dart.shaker.expect
index 749fe7e..b083426 100644
--- a/pkg/front_end/testcases/shaker/transitive_mixins.dart.shaker.expect
+++ b/pkg/front_end/testcases/shaker/transitive_mixins.dart.shaker.expect
@@ -5,5 +5,5 @@
 library pkg/front_end/testcases/shaker/transitive_mixins_lib.dart:
   - class A
   - class B
-  - class _Object&A
+  - class _C&Object&A
   - class C
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 7c5d041..647c7e5 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -48,6 +48,7 @@
 front_end/tool/incremental_perf_test: Slow, Pass
 kernel/test/closures_test: Slow, Pass
 kernel/testcases/*: Skip # These are not tests but input for tests.
+vm/test/transformations/type_flow/transformer_test: Slow, Pass
 vm/testcases/*: SkipByDesign # These are not tests but input for tests.
 
 [ $compiler == dart2analyzer ]
@@ -68,18 +69,13 @@
 collection/test/equality_test/05: Fail # Issue 1533
 collection/test/equality_test/none: Pass, Fail # Issue 14348
 compiler/tool/*: SkipByDesign # Only meant to run on vm
-front_end/test/dependency_grapher_test: SkipByDesign # Uses dart:io
-front_end/test/incremental_kernel_generator_test: SkipByDesign # Uses dart:io
-front_end/test/incremental_load_from_dill_test: SkipByDesign # Uses dart:io
-front_end/test/incremental_resolved_ast_generator_test: SkipByDesign # Uses dart:io
-front_end/test/memory_file_system_test: CompileTimeError # Issue 23773
-front_end/test/src/base/file_repository_test: SkipByDesign # Uses dart:io
-front_end/test/src/base/libraries_reader_test: SkipByDesign # Uses dart:io
-front_end/test/src/base/processed_options_test: SkipByDesign # Uses dart:io
-front_end/test/standard_file_system_test: SkipByDesign # Uses dart:io
-front_end/test/subpackage_relationships_test: SkipByDesign # Uses dart:io
+front_end/test/*: SkipByDesign # Only meant to run on vm, most use dart:mirrors and dart:io
 front_end/tool/*: SkipByDesign # Only meant to run on vm
+status_file/test/normalize_test: SkipByDesign # Uses dart:io
+status_file/test/parse_and_normalize_test: SkipByDesign # Uses dart:io
+status_file/test/repo_status_files_test: SkipByDesign # Uses dart:io
 telemetry/test/*: SkipByDesign # Only meant to run on vm
+testing/*: SkipByDesign # Only meant to run on vm
 typed_data/test/typed_buffers_test/01: Fail # Not supporting Int64List, Uint64List.
 
 [ $compiler == none ]
@@ -183,8 +179,10 @@
 [ $compiler == dart2js && $csp ]
 mutation_observer: Skip # This test cannot run under CSP because it is injecting a JavaScript polyfill
 
-[ $compiler == dart2js && $fast_startup ]
-front_end/test/*: SkipByDesign # Tests written with dart:mirrors.
+[ $compiler == dart2js && $fasta && $host_checked ]
+analysis_server_client/test/analysis_server_client_test: Crash
+js_ast/test/printer_callback_test: Crash
+js_ast/test/string_escape_test: Crash
 
 [ $compiler == dart2js && ($runtime == chrome || $runtime == ff) ]
 async/test/stream_zip_test: SkipSlow # Times out. Issue 22050
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 92f7ec2..0b6bd2e 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -34,7 +34,6 @@
 // * Support function types, better handle closures.
 // * Support generic types: substitution, passing type arguments. Figure out
 //   when generic type should be approximated.
-// * Support named parameters (remove their approximation with static types).
 //
 // === Efficiency of the analysis ===
 // * Add benchmark to measure analysis time continuously.
@@ -182,7 +181,7 @@
   Type _processFunction(TypeFlowAnalysis typeFlowAnalysis) {
     final Member member = selector.member;
     if (selector.memberAgreesToCallKind(member)) {
-      if (_isLegalNumberOfArguments()) {
+      if (_argumentsValid()) {
         return typeFlowAnalysis
             .getSummary(member)
             .apply(args, typeFlowAnalysis.hierarchyCache, typeFlowAnalysis);
@@ -210,7 +209,7 @@
     }
   }
 
-  bool _isLegalNumberOfArguments() {
+  bool _argumentsValid() {
     final function = selector.member.function;
     assertx(function != null);
 
@@ -229,6 +228,16 @@
       return false;
     }
 
+    if (args.names.isNotEmpty) {
+      // TODO(dartbug.com/32292): make sure parameters are sorted in kernel AST
+      // and iterate parameters in parallel, without lookup.
+      for (var name in args.names) {
+        if (findNamedParameter(function, name) == null) {
+          return false;
+        }
+      }
+    }
+
     return true;
   }
 }
@@ -668,7 +677,7 @@
   final int _id;
   final Class class_;
   final Set<_ClassData> supertypes; // List of super-types including this.
-  final Set<_ClassData> allocatedSubtypes = new Set<_ClassData>();
+  final Set<_ClassData> _allocatedSubtypes = new Set<_ClassData>();
 
   /// Flag indicating if this class has a noSuchMethod() method not inherited
   /// from Object.
@@ -683,6 +692,33 @@
   ConcreteType get concreteType =>
       _concreteType ??= new ConcreteType(this, class_.rawType);
 
+  Type _specializedConeType;
+  Type get specializedConeType =>
+      _specializedConeType ??= _calculateConeTypeSpecialization();
+
+  Type _calculateConeTypeSpecialization() {
+    final int numSubTypes = _allocatedSubtypes.length;
+    if (numSubTypes == 0) {
+      return new Type.empty();
+    } else if (numSubTypes == 1) {
+      return _allocatedSubtypes.single.concreteType;
+    } else {
+      List<ConcreteType> types = new List<ConcreteType>();
+      for (var sub in _allocatedSubtypes) {
+        types.add(sub.concreteType);
+      }
+      // SetType constructor expects a list of ConcreteTypes sorted by classId
+      // (for faster intersections and unions).
+      types.sort();
+      return new SetType(types);
+    }
+  }
+
+  void addAllocatedSubtype(_ClassData subType) {
+    _allocatedSubtypes.add(subType);
+    _specializedConeType = null; // Reset cached specialization.
+  }
+
   @override
   int get hashCode => _id;
 
@@ -746,11 +782,11 @@
     final _ClassData classData = getClassData(cl);
 
     if (allocatedClasses.add(cl)) {
-      classData.allocatedSubtypes.add(classData);
+      classData.addAllocatedSubtype(classData);
       classData.invalidateDependentInvocations(_typeFlowAnalysis.workList);
 
       for (var supertype in classData.supertypes) {
-        supertype.allocatedSubtypes.add(classData);
+        supertype.addAllocatedSubtype(classData);
         supertype.invalidateDependentInvocations(_typeFlowAnalysis.workList);
       }
 
@@ -842,26 +878,11 @@
 
     _ClassData classData = getClassData(baseClass);
 
-    final allocatedSubtypes = classData.allocatedSubtypes;
     if (!_sealed) {
       classData.addDependentInvocation(_typeFlowAnalysis.currentInvocation);
     }
 
-    final int numSubTypes = allocatedSubtypes.length;
-
-    if (numSubTypes == 0) {
-      return new Type.empty();
-    } else if (numSubTypes == 1) {
-      return allocatedSubtypes.single.concreteType;
-    } else {
-      List<ConcreteType> types = new List<ConcreteType>();
-      for (var sub in allocatedSubtypes) {
-        types.add(sub.concreteType);
-      }
-      // TODO(alexmarkov): cache result of specialization or keep allocatedSubtypes sorted
-      types.sort();
-      return new SetType(types);
-    }
+    return classData.specializedConeType;
   }
 
   bool hasNonTrivialNoSuchMethod(Class c) {
diff --git a/pkg/vm/lib/transformations/type_flow/calls.dart b/pkg/vm/lib/transformations/type_flow/calls.dart
index cb4d30d..02166f9 100644
--- a/pkg/vm/lib/transformations/type_flow/calls.dart
+++ b/pkg/vm/lib/transformations/type_flow/calls.dart
@@ -155,15 +155,15 @@
 }
 
 /// Arguments passed to a call, including implicit receiver argument.
-// TODO(alexmarkov): use this class instead of List<Type> / List<TypeExpr>.
 // TODO(alexmarkov): take type arguments into account
-// TODO(alexmarkov): keep names sorted
 class Args<T extends TypeExpr> {
   final List<T> values;
   final List<String> names;
   int _hashCode;
 
-  Args(this.values, {this.names = const <String>[]});
+  Args(this.values, {this.names = const <String>[]}) {
+    assertx(isSorted(names));
+  }
 
   Args.withReceiver(Args<T> args, T receiver)
       : values = new List.from(args.values),
@@ -172,9 +172,7 @@
   }
 
   int get positionalCount => values.length - names.length;
-
-  // TODO(alexmarkov): get rid of this method
-  List<T> get positional => values.sublist(0, positionalCount);
+  int get namedCount => names.length;
 
   T get receiver => values[0];
 
diff --git a/pkg/vm/lib/transformations/type_flow/summary.dart b/pkg/vm/lib/transformations/type_flow/summary.dart
index 58a259c..f4e9f38 100644
--- a/pkg/vm/lib/transformations/type_flow/summary.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary.dart
@@ -30,10 +30,10 @@
     return type;
   }
 
-  String get name => "t$index";
+  String get label => "t$index";
 
   @override
-  String toString() => name;
+  String toString() => label;
 
   /// Prints body of this statement.
   String dump();
@@ -58,20 +58,21 @@
 
 /// Input parameter of the summary.
 class Parameter extends Statement {
-  final String _name;
+  final String name;
   final Type staticType;
   Type defaultValue;
   Type _argumentType = const EmptyType();
 
-  Parameter(this._name, this.staticType);
+  Parameter(this.name, this.staticType);
 
-  String get name => _name != null ? "%$_name" : super.name;
+  @override
+  String get label => "%$name";
 
   @override
   void accept(StatementVisitor visitor) => visitor.visitParameter(this);
 
   @override
-  String dump() => "$name = _Parameter #$index [$staticType]";
+  String dump() => "$label = _Parameter #$index [$staticType]";
 
   @override
   Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
@@ -96,7 +97,7 @@
   void accept(StatementVisitor visitor) => visitor.visitNarrow(this);
 
   @override
-  String dump() => "$name = _Narrow ($arg to $type)";
+  String dump() => "$label = _Narrow ($arg to $type)";
 
   @override
   Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
@@ -112,13 +113,14 @@
 
   Join(this._name, this.staticType);
 
-  String get name => _name ?? super.name;
+  @override
+  String get label => _name ?? super.label;
 
   @override
   void accept(StatementVisitor visitor) => visitor.visitJoin(this);
 
   @override
-  String dump() => "$name = _Join [$staticType] (${values.join(", ")})";
+  String dump() => "$label = _Join [$staticType] (${values.join(", ")})";
 
   @override
   Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
@@ -144,7 +146,7 @@
   void accept(StatementVisitor visitor) => visitor.visitCall(this);
 
   @override
-  String dump() => "$name${isResultUsed ? '*' : ''} = _Call $selector $args";
+  String dump() => "$label${isResultUsed ? '*' : ''} = _Call $selector $args";
 
   @override
   Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
@@ -238,12 +240,16 @@
 /// one member, function or initializer.
 class Summary {
   final int parameterCount;
+  final int positionalParameterCount;
   final int requiredParameterCount;
 
   List<Statement> _statements = <Statement>[];
   TypeExpr result = null;
 
-  Summary({this.parameterCount: 0, this.requiredParameterCount: 0});
+  Summary(
+      {this.parameterCount: 0,
+      this.positionalParameterCount: 0,
+      this.requiredParameterCount: 0});
 
   List<Statement> get statements => _statements;
 
@@ -267,11 +273,12 @@
   /// Apply this summary to the given arguments and return the resulting type.
   Type apply(Args<Type> arguments, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
-    // TODO(alexmarkov): take named parameters into account
-    final args = arguments.positional;
-
-    assertx(args.length >= requiredParameterCount);
-    assertx(args.length <= parameterCount);
+    final args = arguments.values;
+    final positionalArgCount = arguments.positionalCount;
+    final namedArgCount = arguments.namedCount;
+    assertx(requiredParameterCount <= positionalArgCount);
+    assertx(positionalArgCount <= positionalParameterCount);
+    assertx(namedArgCount <= parameterCount - positionalParameterCount);
 
     // Interpret statements sequentially, calculating the result type
     // of each statement and putting it into the 'types' list parallel
@@ -284,21 +291,40 @@
 
     List<Type> types = new List<Type>(_statements.length);
 
-    types.setAll(0, args);
+    types.setRange(0, positionalArgCount, args);
 
-    for (int i = 0; i < args.length; i++) {
+    for (int i = 0; i < positionalArgCount; i++) {
       Parameter param = _statements[i] as Parameter;
       param._observeArgumentType(args[i], typeHierarchy);
       types[i] = args[i].intersection(param.staticType, typeHierarchy);
     }
 
-    for (int i = args.length; i < parameterCount; i++) {
+    for (int i = positionalArgCount; i < positionalParameterCount; i++) {
       Parameter param = _statements[i] as Parameter;
+      assertx(param.defaultValue != null);
       param._observeArgumentType(param.defaultValue, typeHierarchy);
       types[i] = param.defaultValue;
-      assertx(types[i] != null);
     }
 
+    final argNames = arguments.names;
+    int argIndex = 0;
+    for (int i = positionalParameterCount; i < parameterCount; i++) {
+      Parameter param = _statements[i] as Parameter;
+      assertx(param.defaultValue != null);
+      if ((argIndex < namedArgCount) && (argNames[argIndex] == param.name)) {
+        Type argType = args[positionalArgCount + argIndex];
+        argIndex++;
+        param._observeArgumentType(argType, typeHierarchy);
+        types[i] = argType.intersection(param.staticType, typeHierarchy);
+      } else {
+        assertx((argIndex == namedArgCount) ||
+            (param.name.compareTo(argNames[argIndex]) < 0));
+        param._observeArgumentType(param.defaultValue, typeHierarchy);
+        types[i] = param.defaultValue;
+      }
+    }
+    assertx(argIndex == namedArgCount);
+
     for (int i = parameterCount; i < _statements.length; i++) {
       // Test if tracing is enabled to avoid expensive message formatting.
       if (kPrintTrace) {
@@ -316,12 +342,16 @@
   }
 
   Args<Type> get argumentTypes {
-    final positional = new List<Type>(parameterCount);
+    final argTypes = new List<Type>(parameterCount);
+    final argNames =
+        new List<String>(parameterCount - positionalParameterCount);
     for (int i = 0; i < parameterCount; i++) {
       Parameter param = _statements[i] as Parameter;
-      positional[i] = param.argumentType;
+      argTypes[i] = param.argumentType;
+      if (i >= positionalParameterCount) {
+        argNames[i - positionalParameterCount] = param.name;
+      }
     }
-    // TODO(alexmarkov): support named parameters
-    return new Args<Type>(positional);
+    return new Args<Type>(argTypes, names: argNames);
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index cb96d73..94a6d37 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -36,14 +36,28 @@
   _SummaryNormalizer(this._summary);
 
   void normalize() {
-    var statements = _summary.statements;
+    final List<Statement> statements = _summary.statements;
     _summary.reset();
 
-    for (int i = 0; i < _summary.parameterCount; i++) {
+    for (int i = 0; i < _summary.positionalParameterCount; i++) {
       _processed.add(statements[i]);
       _summary.add(statements[i]);
     }
 
+    // Sort named parameters.
+    // TODO(dartbug.com/32292): make sure parameters are sorted in kernel AST
+    // and remove this sorting.
+    if (_summary.positionalParameterCount < _summary.parameterCount) {
+      List<Statement> namedParams = statements.sublist(
+          _summary.positionalParameterCount, _summary.parameterCount);
+      namedParams.sort((Statement s1, Statement s2) =>
+          (s1 as Parameter).name.compareTo((s2 as Parameter).name));
+      namedParams.forEach((Statement st) {
+        _processed.add(st);
+        _summary.add(st);
+      });
+    }
+
     for (Statement st in statements) {
       if (st is Call) {
         _normalizeExpr(st, false);
@@ -255,7 +269,10 @@
       final firstParamIndex = hasReceiver ? 1 : 0;
 
       _summary = new Summary(
-          parameterCount:
+          parameterCount: firstParamIndex +
+              function.positionalParameters.length +
+              function.namedParameters.length,
+          positionalParameterCount:
               firstParamIndex + function.positionalParameters.length,
           requiredParameterCount:
               firstParamIndex + function.requiredParameterCount);
@@ -271,16 +288,20 @@
       for (VariableDeclaration param in function.positionalParameters) {
         _declareParameter(param.name, param.type, param.initializer);
       }
-
-      int count = 0;
-      for (VariableDeclaration param in function.positionalParameters) {
-        Join v = _declareVariable(param);
-        v.values.add(_summary.statements[firstParamIndex + count]);
-        ++count;
+      for (VariableDeclaration param in function.namedParameters) {
+        _declareParameter(param.name, param.type, param.initializer);
       }
 
-      // TODO(alexmarkov): take named parameters into account
-      function.namedParameters.forEach(_declareVariableWithStaticType);
+      int count = firstParamIndex;
+      for (VariableDeclaration param in function.positionalParameters) {
+        Join v = _declareVariable(param);
+        v.values.add(_summary.statements[count++]);
+      }
+      for (VariableDeclaration param in function.namedParameters) {
+        Join v = _declareVariable(param);
+        v.values.add(_summary.statements[count++]);
+      }
+      assertx(count == _summary.parameterCount);
 
       _returnValue = new Join("%result", function.returnType);
       _summary.add(_returnValue);
@@ -331,7 +352,8 @@
     final member = selector.member;
     assertx(member != null);
 
-    List<Type> args = <Type>[];
+    final List<Type> args = <Type>[];
+    final List<String> names = <String>[];
 
     if (hasReceiverArg(member) &&
         (selector.callKind != CallKind.FieldInitializer)) {
@@ -346,11 +368,20 @@
           final function = member.function;
           assertx(function != null);
 
-          for (int i = 0; i < function.positionalParameters.length; i++) {
+          final int paramCount = function.positionalParameters.length +
+              function.namedParameters.length;
+          for (int i = 0; i < paramCount; i++) {
             args.add(new Type.nullableAny());
           }
 
-          // TODO(alexmarkov): take named parameters into account
+          if (function.namedParameters.isNotEmpty) {
+            for (var param in function.namedParameters) {
+              names.add(param.name);
+            }
+            // TODO(dartbug.com/32292): make sure parameters are sorted in
+            // kernel AST and remove this sorting.
+            names.sort();
+          }
         }
         break;
 
@@ -365,24 +396,35 @@
         break;
     }
 
-    return new Args<Type>(args);
+    return new Args<Type>(args, names: names);
   }
 
   TypeExpr _visit(TreeNode node) => node.accept(this);
 
   Args<TypeExpr> _visitArguments(TypeExpr receiver, Arguments arguments) {
-    var args = <TypeExpr>[];
+    final args = <TypeExpr>[];
     if (receiver != null) {
       args.add(receiver);
     }
     for (Expression arg in arguments.positional) {
       args.add(_visit(arg));
     }
-    // TODO(alexmarkov): take named arguments into account
-    for (NamedExpression arg in arguments.named) {
-      _visit(arg.value);
+    if (arguments.named.isNotEmpty) {
+      final names = <String>[];
+      final map = <String, TypeExpr>{};
+      for (NamedExpression arg in arguments.named) {
+        final name = arg.name;
+        names.add(name);
+        map[name] = _visit(arg.value);
+      }
+      names.sort();
+      for (var name in names) {
+        args.add(map[name]);
+      }
+      return new Args<TypeExpr>(args, names: names);
+    } else {
+      return new Args<TypeExpr>(args);
     }
-    return new Args<TypeExpr>(args);
   }
 
   Parameter _declareParameter(
@@ -404,12 +446,15 @@
     return param;
   }
 
-  Join _declareVariable(VariableDeclaration decl) {
+  Join _declareVariable(VariableDeclaration decl, {bool addInitType: false}) {
     Join v = new Join(decl.name, decl.type);
     _summary.add(v);
     _variables[decl] = v;
     if (decl.initializer != null) {
-      v.values.add(_visit(decl.initializer));
+      TypeExpr initType = _visit(decl.initializer);
+      if (addInitType) {
+        v.values.add(initType);
+      }
     }
     return v;
   }
@@ -594,7 +639,7 @@
 
   @override
   TypeExpr visitLet(Let node) {
-    _declareVariable(node.variable);
+    _declareVariable(node.variable, addInitType: true);
     return _visit(node.body);
   }
 
@@ -1037,7 +1082,7 @@
 
   @override
   visitVariableDeclaration(VariableDeclaration node) {
-    final v = _declareVariable(node);
+    final v = _declareVariable(node, addInitType: true);
     if (node.initializer == null) {
       v.values.add(_nullType);
     }
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 9bb6c65..7d5480c 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -214,8 +214,17 @@
               positionalParams[i], argTypes.values[firstParamIndex + i]);
         }
 
+        // TODO(dartbug.com/32292): make sure parameters are sorted in kernel
+        // AST and iterate parameters in parallel, without lookup.
+        final names = argTypes.names;
+        for (int i = 0; i < names.length; i++) {
+          final param = findNamedParameter(member.function, names[i]);
+          assertx(param != null);
+          _setInferredType(param,
+              argTypes.values[firstParamIndex + positionalParams.length + i]);
+        }
+
         // TODO(alexmarkov): figure out how to pass receiver type.
-        // TODO(alexmarkov): support named parameters
       }
     } else if (!member.isAbstract) {
       _setUnreachable(member);
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 7b0b6f8..a964682 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -234,16 +234,7 @@
   /// Creates a new SetType using list of concrete types sorted by classId.
   SetType(this.types) {
     assertx(types.length >= 2);
-    assertx(_isSorted(types));
-  }
-
-  static bool _isSorted(List<ConcreteType> types) {
-    for (int i = 0; i < types.length - 1; i++) {
-      if (types[i].classId.compareTo(types[i + 1].classId) >= 0) {
-        return false;
-      }
-    }
-    return true;
+    assertx(isSorted(types));
   }
 
   @override
diff --git a/pkg/vm/lib/transformations/type_flow/utils.dart b/pkg/vm/lib/transformations/type_flow/utils.dart
index 865907e..75dd3dc 100644
--- a/pkg/vm/lib/transformations/type_flow/utils.dart
+++ b/pkg/vm/lib/transformations/type_flow/utils.dart
@@ -6,7 +6,8 @@
 /// analysis.
 library vm.transformations.type_flow.utils;
 
-import 'package:kernel/ast.dart' show Member, Constructor;
+import 'package:kernel/ast.dart'
+    show Constructor, FunctionNode, Member, VariableDeclaration;
 
 const bool kPrintTrace =
     const bool.fromEnvironment('global.type.flow.print.trace');
@@ -47,6 +48,22 @@
 bool hasReceiverArg(Member member) =>
     member.isInstanceMember || (member is Constructor);
 
+/// Returns true if elements in [list] are in strictly increasing order.
+/// List with duplicates is considered not sorted.
+bool isSorted(List list) {
+  for (int i = 0; i < list.length - 1; i++) {
+    if (list[i].compareTo(list[i + 1]) >= 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+VariableDeclaration findNamedParameter(FunctionNode function, String name) {
+  return function.namedParameters
+      .firstWhere((p) => p.name == name, orElse: () => null);
+}
+
 /// Holds various statistic counters for type flow analysis.
 class Statistics {
   static int summariesCreated = 0;
diff --git a/pkg/vm/test/frontend_server_test.dart b/pkg/vm/test/frontend_server_test.dart
index 481eb0c..1e4f4c1 100644
--- a/pkg/vm/test/frontend_server_test.dart
+++ b/pkg/vm/test/frontend_server_test.dart
@@ -45,8 +45,7 @@
         argThat(equals('server.dart')),
         captureAny,
         generator: any,
-      ))
-          .captured;
+      )).captured;
       expect(capturedArgs.single['sdk-root'], equals('sdkroot'));
       expect(capturedArgs.single['strong'], equals(false));
     });
@@ -64,8 +63,7 @@
         argThat(equals('server.dart')),
         captureAny,
         generator: any,
-      ))
-          .captured;
+      )).captured;
       expect(capturedArgs.single['sdk-root'], equals('sdkroot'));
       expect(capturedArgs.single['strong'], equals(true));
     });
@@ -83,8 +81,7 @@
         argThat(equals('server.dart')),
         captureAny,
         generator: any,
-      ))
-          .captured;
+      )).captured;
       expect(capturedArgs.single['sdk-root'], equals('sdkroot'));
       expect(capturedArgs.single['link-platform'], equals(true));
       expect(capturedArgs.single['strong'], equals(false));
@@ -425,8 +422,7 @@
           argThat(equals('server.dart')),
           captureAny,
           generator: any,
-        ))
-            .captured;
+        )).captured;
         expect(capturedArgs.single['sdk-root'], equals('sdkroot'));
         expect(capturedArgs.single['strong'], equals(false));
       });
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/params.dart b/pkg/vm/testcases/transformations/type_flow/summary_collector/params.dart
new file mode 100644
index 0000000..e09015d
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/params.dart
@@ -0,0 +1,39 @@
+// 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.
+
+t1(a1, a2, a3) => a1.foo1() + a2.foo2() + a3.foo3();
+
+t2(a3, a2, a1) => a1.foo1() + a2.foo2() + a3.foo3();
+
+t3(a1, a2, a3, [a4, a5, a6]) =>
+    a1.foo1() + a2.foo2() + a3.foo3() + a4.foo4() + a5.foo5() + a6.foo6();
+
+t4(a1, a2, a3, [a6, a5, a4]) =>
+    a1.foo1() + a2.foo2() + a3.foo3() + a4.foo4() + a5.foo5() + a6.foo6();
+
+t5(a1, a2, a3, {a4, a5, a6}) =>
+    a1.foo1() + a2.foo2() + a3.foo3() + a4.foo4() + a5.foo5() + a6.foo6();
+
+t6(a1, a2, a3, {a6, a5, a4}) =>
+    a1.foo1() + a2.foo2() + a3.foo3() + a4.foo4() + a5.foo5() + a6.foo6();
+
+t7(a1, a2, a3, {a5, a4, a6}) =>
+    a1.foo1() + a2.foo2() + a3.foo3() + a4.foo4() + a5.foo5() + a6.foo6();
+
+calls(x1, x2, x3, x4, x5, x6, x7, x8, x9) {
+  t1(x1, x2, x3);
+  t2(x1, x2, x3);
+  t3(x1, x2, x3);
+  t3(x1, x2, x3, x4);
+  t4(x1, x2, x3, x4, x5);
+  t5(x1, x2, x3);
+  t5(x1, x2, x3, a4: x4);
+  t5(x1, x2, x3, a5: x4);
+  t5(x1, x2, x3, a6: x4, a5: x5);
+  t6(x1, x2, x3, a4: x4, a6: x5);
+  t6(x1, x2, x3, a4: x4, a5: x5, a6: x6);
+  t7(x1, x2, x3, a4: x4, a6: x5, a5: x6);
+}
+
+main() {}
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/params.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/params.dart.expect
new file mode 100644
index 0000000..02d140f
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/params.dart.expect
@@ -0,0 +1,141 @@
+------------ #lib::t1 ------------
+%a1 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a3 = _Parameter #2 [_T ANY?]
+t3* = _Call dynamic [foo1] (%a1)
+t4* = _Call dynamic [foo2] (%a2)
+t5* = _Call dynamic [+] (t3, t4)
+t6* = _Call dynamic [foo3] (%a3)
+t7* = _Call dynamic [+] (t5, t6)
+RESULT: t7
+------------ #lib::t2 ------------
+%a3 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a1 = _Parameter #2 [_T ANY?]
+t3* = _Call dynamic [foo1] (%a1)
+t4* = _Call dynamic [foo2] (%a2)
+t5* = _Call dynamic [+] (t3, t4)
+t6* = _Call dynamic [foo3] (%a3)
+t7* = _Call dynamic [+] (t5, t6)
+RESULT: t7
+------------ #lib::t3 ------------
+%a1 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a3 = _Parameter #2 [_T ANY?]
+%a4 = _Parameter #3 [_T ANY?]
+%a5 = _Parameter #4 [_T ANY?]
+%a6 = _Parameter #5 [_T ANY?]
+t6* = _Call dynamic [foo1] (%a1)
+t7* = _Call dynamic [foo2] (%a2)
+t8* = _Call dynamic [+] (t6, t7)
+t9* = _Call dynamic [foo3] (%a3)
+t10* = _Call dynamic [+] (t8, t9)
+t11* = _Call dynamic [foo4] (%a4)
+t12* = _Call dynamic [+] (t10, t11)
+t13* = _Call dynamic [foo5] (%a5)
+t14* = _Call dynamic [+] (t12, t13)
+t15* = _Call dynamic [foo6] (%a6)
+t16* = _Call dynamic [+] (t14, t15)
+RESULT: t16
+------------ #lib::t4 ------------
+%a1 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a3 = _Parameter #2 [_T ANY?]
+%a6 = _Parameter #3 [_T ANY?]
+%a5 = _Parameter #4 [_T ANY?]
+%a4 = _Parameter #5 [_T ANY?]
+t6* = _Call dynamic [foo1] (%a1)
+t7* = _Call dynamic [foo2] (%a2)
+t8* = _Call dynamic [+] (t6, t7)
+t9* = _Call dynamic [foo3] (%a3)
+t10* = _Call dynamic [+] (t8, t9)
+t11* = _Call dynamic [foo4] (%a4)
+t12* = _Call dynamic [+] (t10, t11)
+t13* = _Call dynamic [foo5] (%a5)
+t14* = _Call dynamic [+] (t12, t13)
+t15* = _Call dynamic [foo6] (%a6)
+t16* = _Call dynamic [+] (t14, t15)
+RESULT: t16
+------------ #lib::t5 ------------
+%a1 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a3 = _Parameter #2 [_T ANY?]
+%a4 = _Parameter #3 [_T ANY?]
+%a5 = _Parameter #4 [_T ANY?]
+%a6 = _Parameter #5 [_T ANY?]
+t6* = _Call dynamic [foo1] (%a1)
+t7* = _Call dynamic [foo2] (%a2)
+t8* = _Call dynamic [+] (t6, t7)
+t9* = _Call dynamic [foo3] (%a3)
+t10* = _Call dynamic [+] (t8, t9)
+t11* = _Call dynamic [foo4] (%a4)
+t12* = _Call dynamic [+] (t10, t11)
+t13* = _Call dynamic [foo5] (%a5)
+t14* = _Call dynamic [+] (t12, t13)
+t15* = _Call dynamic [foo6] (%a6)
+t16* = _Call dynamic [+] (t14, t15)
+RESULT: t16
+------------ #lib::t6 ------------
+%a1 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a3 = _Parameter #2 [_T ANY?]
+%a4 = _Parameter #3 [_T ANY?]
+%a5 = _Parameter #4 [_T ANY?]
+%a6 = _Parameter #5 [_T ANY?]
+t6* = _Call dynamic [foo1] (%a1)
+t7* = _Call dynamic [foo2] (%a2)
+t8* = _Call dynamic [+] (t6, t7)
+t9* = _Call dynamic [foo3] (%a3)
+t10* = _Call dynamic [+] (t8, t9)
+t11* = _Call dynamic [foo4] (%a4)
+t12* = _Call dynamic [+] (t10, t11)
+t13* = _Call dynamic [foo5] (%a5)
+t14* = _Call dynamic [+] (t12, t13)
+t15* = _Call dynamic [foo6] (%a6)
+t16* = _Call dynamic [+] (t14, t15)
+RESULT: t16
+------------ #lib::t7 ------------
+%a1 = _Parameter #0 [_T ANY?]
+%a2 = _Parameter #1 [_T ANY?]
+%a3 = _Parameter #2 [_T ANY?]
+%a4 = _Parameter #3 [_T ANY?]
+%a5 = _Parameter #4 [_T ANY?]
+%a6 = _Parameter #5 [_T ANY?]
+t6* = _Call dynamic [foo1] (%a1)
+t7* = _Call dynamic [foo2] (%a2)
+t8* = _Call dynamic [+] (t6, t7)
+t9* = _Call dynamic [foo3] (%a3)
+t10* = _Call dynamic [+] (t8, t9)
+t11* = _Call dynamic [foo4] (%a4)
+t12* = _Call dynamic [+] (t10, t11)
+t13* = _Call dynamic [foo5] (%a5)
+t14* = _Call dynamic [+] (t12, t13)
+t15* = _Call dynamic [foo6] (%a6)
+t16* = _Call dynamic [+] (t14, t15)
+RESULT: t16
+------------ #lib::calls ------------
+%x1 = _Parameter #0 [_T ANY?]
+%x2 = _Parameter #1 [_T ANY?]
+%x3 = _Parameter #2 [_T ANY?]
+%x4 = _Parameter #3 [_T ANY?]
+%x5 = _Parameter #4 [_T ANY?]
+%x6 = _Parameter #5 [_T ANY?]
+%x7 = _Parameter #6 [_T ANY?]
+%x8 = _Parameter #7 [_T ANY?]
+%x9 = _Parameter #8 [_T ANY?]
+t9 = _Call direct [#lib::t1] (%x1, %x2, %x3)
+t10 = _Call direct [#lib::t2] (%x1, %x2, %x3)
+t11 = _Call direct [#lib::t3] (%x1, %x2, %x3)
+t12 = _Call direct [#lib::t3] (%x1, %x2, %x3, %x4)
+t13 = _Call direct [#lib::t4] (%x1, %x2, %x3, %x4, %x5)
+t14 = _Call direct [#lib::t5] (%x1, %x2, %x3)
+t15 = _Call direct [#lib::t5] (%x1, %x2, %x3, a4: %x4)
+t16 = _Call direct [#lib::t5] (%x1, %x2, %x3, a5: %x4)
+t17 = _Call direct [#lib::t5] (%x1, %x2, %x3, a5: %x5, a6: %x4)
+t18 = _Call direct [#lib::t6] (%x1, %x2, %x3, a4: %x4, a6: %x5)
+t19 = _Call direct [#lib::t6] (%x1, %x2, %x3, a4: %x4, a5: %x5, a6: %x6)
+t20 = _Call direct [#lib::t7] (%x1, %x2, %x3, a4: %x4, a5: %x6, a6: %x5)
+RESULT: _T {}?
+------------ #lib::main ------------
+
+RESULT: _T {}?
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
index c400675..44d8318 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
@@ -14,11 +14,10 @@
 a1 = _Join [dart.core::Object] (%a1, _T (#lib::A), _T (#lib::B))
 t5 = _Call direct [#lib::bar] (a1, _T (dart.core::int)+)
 t6 = _Call direct [#lib::B::] (_T (#lib::B))
-a2 = _Join [dart.core::Object] (_T {}?, %a2)
-t8 = _Call [dart.core::Object::==] (a1, a2)
-t9 = _Join [dart.core::Object] (a1, a2)
-t10 = _Narrow (t9 to _T (dart.core::Object)+?)
-RESULT: t10
+t7 = _Call [dart.core::Object::==] (a1, %a2)
+t8 = _Join [dart.core::Object] (a1, %a2)
+t9 = _Narrow (t8 to _T (dart.core::Object)+?)
+RESULT: t9
 ------------ #lib::bar ------------
 %a1 = _Parameter #0 [_T (dart.core::Object)+?]
 %a2 = _Parameter #1 [_T (dart.core::int)+?]
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart b/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart
index 9fa7451..515824c 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart
@@ -28,7 +28,7 @@
   aa.foo();
 }
 
-void callerA3(A aa) {
+void callerA3({A aa}) {
   aa.foo();
 }
 
@@ -51,7 +51,7 @@
   callerA1(new B());
   callerA1(new C());
   callerA2(new B());
-  callerA3(new C());
+  callerA3(aa: new C());
   callerA4(dd);
   dd = new D();
 
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect
index 9fd98bb..8843409 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect
@@ -42,7 +42,7 @@
 static method callerA2([@vm.inferred-type.metadata=#lib::B] self::A aa) → void {
   [@vm.direct-call.metadata=#lib::B::foo] aa.{self::A::foo}();
 }
-static method callerA3([@vm.inferred-type.metadata=#lib::C] self::A aa) → void {
+static method callerA3({[@vm.inferred-type.metadata=#lib::C] self::A aa = null}) → void {
   [@vm.direct-call.metadata=#lib::C::foo] aa.{self::A::foo}();
 }
 static method callerA4([@vm.inferred-type.metadata=#lib::D?] self::A aa) → void {
@@ -58,7 +58,7 @@
   self::callerA1(new self::B::•());
   self::callerA1(new self::C::•());
   self::callerA2(new self::B::•());
-  self::callerA3(new self::C::•());
+  self::callerA3(aa: new self::C::•());
   self::callerA4([@vm.inferred-type.metadata=#lib::D?] self::dd);
   self::dd = new self::D::•();
   self::callerE1("abc");
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect
index a3755e4..977c750 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect
@@ -35,12 +35,12 @@
     : super core::Object::•()
     ;
 }
-abstract class _D&C extends self::D implements self::C {
+abstract class _E&D&C extends self::D implements self::C {
   synthetic constructor •() → void
     : super self::D::•()
     ;
 }
-class E extends self::_D&C {
+class E extends self::_E&D&C {
   synthetic constructor •() → void
     : super self::D::•()
     ;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart
index ab479a7..a85118e 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart
@@ -12,6 +12,10 @@
 
 class T5 {}
 
+class T6 {}
+
+class T7 {}
+
 abstract class A {
   foo();
   get bar;
@@ -54,6 +58,14 @@
   }
 }
 
+class H {
+  foo({left, right}) => new T6();
+
+  noSuchMethod(Invocation invocation) {
+    return new T7();
+  }
+}
+
 A bb = new B();
 A dd = new D();
 
@@ -83,4 +95,9 @@
   dynamic gg = new G();
 
   print(gg.noSuchMethod(null, null));
+
+  dynamic hh = new H();
+
+  print(hh.foo(right: 2, left: 1));
+  print(hh.foo(left: 1, top: 2));
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
index 9b51a47..61fb50e 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
@@ -27,6 +27,16 @@
     : super core::Object::•()
     ;
 }
+class T6 extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class T7 extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
 abstract class A extends core::Object {
   synthetic constructor •() → void
     : super core::Object::•()
@@ -84,6 +94,16 @@
     return new self::T5::•();
   }
 }
+class H extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo({[@vm.inferred-type.metadata=!] dynamic left = null, [@vm.inferred-type.metadata=!] dynamic right = null}) → dynamic
+    return new self::T6::•();
+  method noSuchMethod(core::Invocation invocation) → dynamic {
+    return new self::T7::•();
+  }
+}
 [@vm.inferred-type.metadata=#lib::B]static field self::A bb = new self::B::•();
 [@vm.inferred-type.metadata=#lib::D]static field self::A dd = new self::D::•();
 [@vm.inferred-type.metadata=dart.core::Null?]static field core::Function unknown;
@@ -104,4 +124,7 @@
   new self::F::•();
   dynamic gg = new self::G::•();
   core::print([@vm.inferred-type.metadata=#lib::T5] gg.noSuchMethod(null, null));
+  dynamic hh = new self::H::•();
+  core::print([@vm.inferred-type.metadata=#lib::T6] hh.foo(right: 2, left: 1));
+  core::print([@vm.inferred-type.metadata=#lib::T7] hh.foo(left: 1, top: 2));
 }
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 709e13e..05cf6e1 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -9,7 +9,7 @@
 
 import "dart:_internal" as internal;
 
-import "dart:_internal" show patch;
+import "dart:_internal" show patch, IterableElementError;
 
 import "dart:typed_data" show Uint32List;
 
@@ -599,6 +599,29 @@
     return null;
   }
 
+  E get first {
+    for (int i = 0; i < _buckets.length; i++) {
+      var entry = _buckets[i];
+      if (entry != null) {
+        return entry.key;
+      }
+    }
+    throw IterableElementError.noElement();
+  }
+
+  E get last {
+    for (int i = _buckets.length - 1; i >= 0; i--) {
+      var entry = _buckets[i];
+      if (entry != null) {
+        while (entry.next != null) {
+          entry = entry.next;
+        }
+        return entry.key;
+      }
+    }
+    throw IterableElementError.noElement();
+  }
+
   // Set.
 
   bool add(E element) {
diff --git a/runtime/lib/compact_hash.dart b/runtime/lib/compact_hash.dart
index 7961370..82bc532 100644
--- a/runtime/lib/compact_hash.dart
+++ b/runtime/lib/compact_hash.dart
@@ -469,6 +469,26 @@
 
   int get length => _usedData - _deletedKeys;
 
+  E get first {
+    for (int offset = 0; offset < _usedData; offset++) {
+      Object current = _data[offset];
+      if (!_HashBase._isDeleted(_data, current)) {
+        return current;
+      }
+    }
+    throw IterableElementError.noElement();
+  }
+
+  E get last {
+    for (int offset = _usedData - 1; offset >= 0; offset--) {
+      Object current = _data[offset];
+      if (!_HashBase._isDeleted(_data, current)) {
+        return current;
+      }
+    }
+    throw IterableElementError.noElement();
+  }
+
   void _rehash() {
     if ((_deletedKeys << 1) > _usedData) {
       _init(_index.length, _hashMask, _data, _usedData);
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 26d8f3d..6ee28f1 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -294,7 +294,7 @@
   bool get isPrivate => _n(simpleName).startsWith('_');
 
   Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
-  Symbol get constructorName => const Symbol('');
+  Symbol get constructorName => Symbol.empty;
 
   TypeMirror get returnType => _target.type;
   List<ParameterMirror> get parameters {
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index a64c3c6..a7c256b 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -112,11 +112,19 @@
     return Bool::True().raw();
   }
 
+  if (left.GetTypeArguments() == right.GetTypeArguments()) {
+    return Bool::True().raw();
+  }
   const TypeArguments& left_type_arguments =
       TypeArguments::Handle(left.GetTypeArguments());
   const TypeArguments& right_type_arguments =
       TypeArguments::Handle(right.GetTypeArguments());
-  return Bool::Get(left_type_arguments.Equals(right_type_arguments)).raw();
+  const intptr_t num_type_args = cls.NumTypeArguments();
+  const intptr_t num_type_params = cls.NumTypeParameters();
+  return Bool::Get(left_type_arguments.IsSubvectorEquivalent(
+                       right_type_arguments, num_type_args - num_type_params,
+                       num_type_params))
+      .raw();
 }
 
 DEFINE_NATIVE_ENTRY(Object_instanceOf, 4) {
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 040f075..65d32b9 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -35,7 +35,6 @@
 # Tests with known analyzer issues
 [ $compiler == dart2analyzer ]
 developer_extension_test: SkipByDesign
-evaluate_activation_in_method_class_test: RuntimeError # Issue 24478, also, test is excluded in .analysis_options
 get_isolate_after_language_error_test: SkipByDesign
 
 # Kernel version of tests
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index baff3ed..0c37c31 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -123,3 +123,7 @@
 rewind_test: Pass, RuntimeError
 set_name_rpc_test: RuntimeError # Please triage.
 unused_changes_in_last_reload_test: Skip # Times out on sim architectures.
+
+[ $compiler == fasta && $strong ]
+add_breakpoint_rpc_test: CompileTimeError
+
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 16e041d..bf9dfa1 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -194,10 +194,6 @@
 cc/Debugger_SetBreakpointInPartOfLibrary: Crash
 cc/FunctionSourceFingerprint: Fail
 cc/GenerateSource: Skip # Cannot generate source from a kernel binary. 
-cc/IsolateReload_EnumDelete: Fail
-cc/IsolateReload_EnumReorderIdentical: Fail
-cc/IsolateReload_EnumToNotEnum: Skip
-cc/IsolateReload_NotEnumToEnum: Skip
 cc/IsolateReload_NotTypedefToTypedef: Fail
 cc/IsolateReload_TypedefToNotTypedef: Fail
 cc/Parser_AllocateVariables_CaptureLoopVar: Fail
@@ -246,7 +242,6 @@
 dart/spawn_shutdown_test: SkipSlow
 
 [ $compiler == dartk && $runtime == vm && $system == macos ]
-cc/IsolateReload_EnumDelete: Crash
 cc/IsolateReload_LibraryLookup: Fail, Crash
 cc/IsolateReload_TearOff_AddArguments: Fail
 cc/IsolateReload_TearOff_Instance_Equality: Fail
diff --git a/runtime/vm/atomic.h b/runtime/vm/atomic.h
index e4dd4ab..1d18a2c 100644
--- a/runtime/vm/atomic.h
+++ b/runtime/vm/atomic.h
@@ -43,6 +43,13 @@
   static T LoadRelaxed(T* ptr) {
     return *static_cast<volatile T*>(ptr);
   }
+
+  template <typename T>
+  static T* CompareAndSwapPointer(T** slot, T* old_value, T* new_value) {
+    return reinterpret_cast<T*>(AtomicOperations::CompareAndSwapWord(
+        reinterpret_cast<uword*>(slot), reinterpret_cast<uword>(old_value),
+        reinterpret_cast<uword>(new_value)));
+  }
 };
 
 }  // namespace dart
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 3c8a853..e8dde2e 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -4,6 +4,7 @@
 
 #include "vm/class_finalizer.h"
 
+#include "vm/compiler/jit/compiler.h"
 #include "vm/flags.h"
 #include "vm/hash_table.h"
 #include "vm/heap.h"
@@ -2719,27 +2720,21 @@
 void ClassFinalizer::AllocateEnumValues(const Class& enum_cls) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
+
   const Field& index_field =
       Field::Handle(zone, enum_cls.LookupInstanceField(Symbols::Index()));
   ASSERT(!index_field.IsNull());
+
   const Field& name_field = Field::Handle(
       zone, enum_cls.LookupInstanceFieldAllowPrivate(Symbols::_name()));
   ASSERT(!name_field.IsNull());
-  const Field& values_field =
-      Field::Handle(zone, enum_cls.LookupStaticField(Symbols::Values()));
-  ASSERT(!values_field.IsNull());
-  ASSERT(Instance::Handle(zone, values_field.StaticValue()).IsArray());
-  Array& values_list =
-      Array::Handle(zone, Array::RawCast(values_field.StaticValue()));
-  const String& enum_name = String::Handle(enum_cls.ScrubbedName());
-  const String& name_prefix =
-      String::Handle(String::Concat(enum_name, Symbols::Dot()));
 
+  const String& enum_name = String::Handle(zone, enum_cls.ScrubbedName());
+
+  const Array& fields = Array::Handle(zone, enum_cls.fields());
   Field& field = Field::Handle(zone);
-  Instance& ordinal_value = Instance::Handle(zone);
   Instance& enum_value = Instance::Handle(zone);
-
-  String& enum_ident = String::Handle();
+  String& enum_ident = String::Handle(zone);
 
   enum_ident =
       Symbols::FromConcat(thread, Symbols::_DeletedEnumPrefix(), enum_name);
@@ -2750,44 +2745,70 @@
   enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
   ASSERT(!enum_value.IsNull());
   ASSERT(enum_value.IsCanonical());
-  field = enum_cls.LookupStaticField(Symbols::_DeletedEnumSentinel());
-  ASSERT(!field.IsNull());
-  field.SetStaticValue(enum_value, true);
-  field.RecordStore(enum_value);
+  const Field& sentinel = Field::Handle(
+      zone, enum_cls.LookupStaticField(Symbols::_DeletedEnumSentinel()));
+  ASSERT(!sentinel.IsNull());
+  sentinel.SetStaticValue(enum_value, true);
+  sentinel.RecordStore(enum_value);
 
-  const Array& fields = Array::Handle(zone, enum_cls.fields());
-  for (intptr_t i = 0; i < fields.Length(); i++) {
-    field = Field::RawCast(fields.At(i));
-    if (!field.is_static()) continue;
-    ordinal_value = field.StaticValue();
-    // The static fields that need to be initialized with enum instances
-    // contain the smi value of the ordinal number, which was stored in
-    // the field by the parser. Other fields contain non-smi values.
-    if (!ordinal_value.IsSmi()) continue;
-    enum_ident = field.name();
-    // Construct the string returned by toString.
-    ASSERT(!enum_ident.IsNull());
-    // For the user-visible name of the enumeration value, we need to
-    // unmangle private names.
-    if (enum_ident.CharAt(0) == '_') {
-      enum_ident = String::ScrubName(enum_ident);
+  if (thread->isolate()->use_dart_frontend()) {
+    Object& result = Object::Handle(zone);
+    for (intptr_t i = 0; i < fields.Length(); i++) {
+      field = Field::RawCast(fields.At(i));
+      if (!field.is_static() || !field.is_const() ||
+          (sentinel.raw() == field.raw())) {
+        continue;
+      }
+      field.SetStaticValue(Object::transition_sentinel());
+      result = Compiler::EvaluateStaticInitializer(field);
+      ASSERT(!result.IsError());
+      field.SetStaticValue(Instance::Cast(result), true);
+      field.RecordStore(Instance::Cast(result));
     }
-    enum_ident = Symbols::FromConcat(thread, name_prefix, enum_ident);
-    enum_value = Instance::New(enum_cls, Heap::kOld);
-    enum_value.SetField(index_field, ordinal_value);
-    enum_value.SetField(name_field, enum_ident);
-    enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
-    ASSERT(!enum_value.IsNull());
-    ASSERT(enum_value.IsCanonical());
-    field.SetStaticValue(enum_value, true);
-    field.RecordStore(enum_value);
-    intptr_t ord = Smi::Cast(ordinal_value).Value();
-    ASSERT(ord < values_list.Length());
-    values_list.SetAt(ord, enum_value);
+  } else {
+    const String& name_prefix =
+        String::Handle(String::Concat(enum_name, Symbols::Dot()));
+    Instance& ordinal_value = Instance::Handle(zone);
+    Array& values_list = Array::Handle(zone);
+    const Field& values_field =
+        Field::Handle(zone, enum_cls.LookupStaticField(Symbols::Values()));
+    ASSERT(!values_field.IsNull());
+    ASSERT(Instance::Handle(zone, values_field.StaticValue()).IsArray());
+    values_list = Array::RawCast(values_field.StaticValue());
+    const Array& fields = Array::Handle(zone, enum_cls.fields());
+    for (intptr_t i = 0; i < fields.Length(); i++) {
+      field = Field::RawCast(fields.At(i));
+      if (!field.is_static()) continue;
+      ordinal_value = field.StaticValue();
+      // The static fields that need to be initialized with enum instances
+      // contain the smi value of the ordinal number, which was stored in
+      // the field by the parser. Other fields contain non-smi values.
+      if (!ordinal_value.IsSmi()) continue;
+      enum_ident = field.name();
+      // Construct the string returned by toString.
+      ASSERT(!enum_ident.IsNull());
+      // For the user-visible name of the enumeration value, we need to
+      // unmangle private names.
+      if (enum_ident.CharAt(0) == '_') {
+        enum_ident = String::ScrubName(enum_ident);
+      }
+      enum_ident = Symbols::FromConcat(thread, name_prefix, enum_ident);
+      enum_value = Instance::New(enum_cls, Heap::kOld);
+      enum_value.SetField(index_field, ordinal_value);
+      enum_value.SetField(name_field, enum_ident);
+      enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
+      ASSERT(!enum_value.IsNull());
+      ASSERT(enum_value.IsCanonical());
+      field.SetStaticValue(enum_value, true);
+      field.RecordStore(enum_value);
+      intptr_t ord = Smi::Cast(ordinal_value).Value();
+      ASSERT(ord < values_list.Length());
+      values_list.SetAt(ord, enum_value);
+    }
+    values_list.MakeImmutable();
+    values_list ^= values_list.CheckAndCanonicalize(thread, &error_msg);
+    ASSERT(!values_list.IsNull());
   }
-  values_list.MakeImmutable();
-  values_list ^= values_list.CheckAndCanonicalize(thread, &error_msg);
-  ASSERT(!values_list.IsNull());
 }
 
 bool ClassFinalizer::IsSuperCycleFree(const Class& cls) {
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index f1ec175..2b8015a 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -322,8 +322,8 @@
     case kEndPosition:
       end_position_ = builder_->ReadPosition();  // read end position.
       if (++next_read_ == field) return;
-    case kIsAbstract:
-      is_abstract_ = builder_->ReadBool();  // read is_abstract.
+    case kFlags:
+      flags_ = builder_->ReadFlags();  // read flags.
       if (++next_read_ == field) return;
     case kNameIndex:
       name_index_ = builder_->ReadStringReference();  // read name index.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index aac0ad34..dda7bbd 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -388,7 +388,7 @@
     kCanonicalName,
     kPosition,
     kEndPosition,
-    kIsAbstract,
+    kFlags,
     kNameIndex,
     kSourceUriIndex,
     kAnnotations,
@@ -403,6 +403,11 @@
     kEnd,
   };
 
+  enum Flag {
+    kIsAbstract = 1,
+    kIsEnumClass = 2,
+  };
+
   explicit ClassHelper(StreamingFlowGraphBuilder* builder) {
     builder_ = builder;
     next_read_ = kStart;
@@ -417,14 +422,18 @@
   void SetNext(Field field) { next_read_ = field; }
   void SetJustRead(Field field) { next_read_ = field + 1; }
 
+  bool is_abstract() { return flags_ & Flag::kIsAbstract; }
+
+  bool is_enum_class() { return flags_ & Flag::kIsEnumClass; }
+
   NameIndex canonical_name_;
   TokenPosition position_;
   TokenPosition end_position_;
-  bool is_abstract_;
   StringIndex name_index_;
   intptr_t source_uri_index_;
   intptr_t annotation_count_;
   intptr_t procedure_count_;
+  uint8_t flags_;
 
  private:
   StreamingFlowGraphBuilder* builder_;
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 6b2e819..831115a 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -17,6 +17,7 @@
 #include "vm/reusable_handles.h"
 #include "vm/service_isolate.h"
 #include "vm/symbols.h"
+#include "vm/thread.h"
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 namespace dart {
@@ -966,7 +967,7 @@
   class_helper->SetJustRead(ClassHelper::kImplementedClasses);
   klass->set_interfaces(interfaces);
 
-  if (class_helper->is_abstract_) klass->set_is_abstract();
+  if (class_helper->is_abstract()) klass->set_is_abstract();
 }
 
 // Workaround for http://dartbug.com/32087: currently Kernel front-end
@@ -1016,6 +1017,9 @@
   Class& klass = LookupClass(class_helper.canonical_name_);
   klass.set_kernel_offset(class_offset - correction_offset_);
 
+  class_helper.ReadUntilIncluding(ClassHelper::kFlags);
+  if (class_helper.is_enum_class()) klass.set_is_enum_class();
+
   // The class needs to have a script because all the functions in the class
   // will inherit it.  The predicate Function::IsOptimizable uses the absence of
   // a script to detect test functions that should not be optimized.
@@ -1070,7 +1074,6 @@
                                       ClassHelper* class_helper) {
   fields_.Clear();
   functions_.Clear();
-
   ActiveClassScope active_class_scope(&active_class_, &klass);
   if (library.raw() == Library::InternalLibrary() &&
       klass.Name() == Symbols::ClassID().raw()) {
@@ -1122,8 +1125,22 @@
       }
       fields_.Add(&field);
     }
-    klass.AddFields(fields_);
     class_helper->SetJustRead(ClassHelper::kFields);
+
+    if (I->use_dart_frontend() && klass.is_enum_class()) {
+      // Add static field 'const _deleted_enum_sentinel'.
+      // This field does not need to be of type E.
+      Field& deleted_enum_sentinel = Field::ZoneHandle(Z);
+      deleted_enum_sentinel = Field::New(
+          Symbols::_DeletedEnumSentinel(),
+          /* is_static = */ true,
+          /* is_final = */ true,
+          /* is_const = */ true,
+          /* is_reflectable = */ false, klass, Object::dynamic_type(),
+          TokenPosition::kNoSource, TokenPosition::kNoSource);
+      fields_.Add(&deleted_enum_sentinel);
+    }
+    klass.AddFields(fields_);
   }
 
   class_helper->ReadUntilExcluding(ClassHelper::kConstructors);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e03dcb1..f7113a6 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -17613,9 +17613,24 @@
     // Canonicalize the type arguments.
     TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
     // In case the type is first canonicalized at runtime, its type argument
-    // vector may be longer than necessary. This is not an issue.
-    ASSERT(type_args.IsNull() ||
-           (type_args.Length() >= cls.NumTypeArguments()));
+    // vector may be longer than necessary. If so, reallocate a vector of the
+    // exact size to prevent multiple "canonical" types.
+    if (!type_args.IsNull()) {
+      const intptr_t num_type_args = cls.NumTypeArguments();
+      ASSERT(type_args.Length() >= num_type_args);
+      if (type_args.Length() > num_type_args) {
+        TypeArguments& new_type_args =
+            TypeArguments::Handle(zone, TypeArguments::New(num_type_args));
+        AbstractType& type_arg = AbstractType::Handle(zone);
+        for (intptr_t i = 0; i < num_type_args; i++) {
+          type_arg = type_args.TypeAt(i);
+          new_type_args.SetTypeAt(i, type_arg);
+        }
+        type_args = new_type_args.raw();
+        set_arguments(type_args);
+        SetHash(0);  // Flush cached hash value.
+      }
+    }
     type_args = type_args.Canonicalize(trail);
     if (IsCanonical()) {
       // Canonicalizing type_args canonicalized this type as a side effect.
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index f0264a6..ca885ea 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -747,11 +747,27 @@
   static Redirection* Get(uword external_function,
                           Simulator::CallKind call_kind,
                           int argument_count) {
-    Redirection* current;
-    for (current = list_; current != NULL; current = current->next_) {
+    MutexLocker ml(mutex_);
+
+    for (Redirection* current = list_; current != NULL;
+         current = current->next_) {
       if (current->external_function_ == external_function) return current;
     }
-    return new Redirection(external_function, call_kind, argument_count);
+
+    Redirection* redirection =
+        new Redirection(external_function, call_kind, argument_count);
+    redirection->next_ = list_;
+
+    // Use a memory fence to ensure all pending writes are written at the time
+    // of updating the list head, so the profiling thread always has a valid
+    // list to look at.
+    Redirection* old_head = list_;
+    Redirection* replaced_list_head =
+        AtomicOperations::CompareAndSwapPointer<Redirection>(&list_, old_head,
+                                                             redirection);
+    ASSERT(old_head == replaced_list_head);
+
+    return redirection;
   }
 
   static Redirection* FromSvcInstruction(Instr* svc_instruction) {
@@ -761,6 +777,10 @@
     return reinterpret_cast<Redirection*>(addr_of_redirection);
   }
 
+  // Please note that this function is called by the signal handler of the
+  // profiling thread.  It can therefore run at any point in time and is not
+  // allowed to hold any locks - which is precisely the reason why the list is
+  // prepend-only and a memory fence is used when writing the list head [list_]!
   static uword FunctionForRedirect(uword address_of_svc) {
     Redirection* current;
     for (current = list_; current != NULL; current = current->next_) {
@@ -778,18 +798,8 @@
       : external_function_(external_function),
         call_kind_(call_kind),
         argument_count_(argument_count),
-        svc_instruction_(Instr::kSimulatorRedirectInstruction) {
-    // Atomically prepend this element to the front of the global list.
-    // Note: Since elements are never removed, there is no ABA issue.
-    Redirection* list_head = list_;
-    do {
-      next_ = list_head;
-      list_head =
-          reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord(
-              reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_),
-              reinterpret_cast<uword>(this)));
-    } while (list_head != next_);
-  }
+        svc_instruction_(Instr::kSimulatorRedirectInstruction),
+        next_(NULL) {}
 
   uword external_function_;
   Simulator::CallKind call_kind_;
@@ -797,9 +807,11 @@
   uint32_t svc_instruction_;
   Redirection* next_;
   static Redirection* list_;
+  static Mutex* mutex_;
 };
 
 Redirection* Redirection::list_ = NULL;
+Mutex* Redirection::mutex_ = new Mutex();
 
 uword Simulator::RedirectExternalReference(uword function,
                                            CallKind call_kind,
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 4c9495a..eece8ad 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -784,11 +784,27 @@
   static Redirection* Get(uword external_function,
                           Simulator::CallKind call_kind,
                           int argument_count) {
-    Redirection* current;
-    for (current = list_; current != NULL; current = current->next_) {
+    MutexLocker ml(mutex_);
+
+    for (Redirection* current = list_; current != NULL;
+         current = current->next_) {
       if (current->external_function_ == external_function) return current;
     }
-    return new Redirection(external_function, call_kind, argument_count);
+
+    Redirection* redirection =
+        new Redirection(external_function, call_kind, argument_count);
+    redirection->next_ = list_;
+
+    // Use a memory fence to ensure all pending writes are written at the time
+    // of updating the list head, so the profiling thread always has a valid
+    // list to look at.
+    Redirection* old_head = list_;
+    Redirection* replaced_list_head =
+        AtomicOperations::CompareAndSwapPointer<Redirection>(&list_, old_head,
+                                                             redirection);
+    ASSERT(old_head == replaced_list_head);
+
+    return redirection;
   }
 
   static Redirection* FromHltInstruction(Instr* hlt_instruction) {
@@ -798,6 +814,10 @@
     return reinterpret_cast<Redirection*>(addr_of_redirection);
   }
 
+  // Please note that this function is called by the signal handler of the
+  // profiling thread.  It can therefore run at any point in time and is not
+  // allowed to hold any locks - which is precisely the reason why the list is
+  // prepend-only and a memory fence is used when writing the list head [list_]!
   static uword FunctionForRedirect(uword address_of_hlt) {
     Redirection* current;
     for (current = list_; current != NULL; current = current->next_) {
@@ -816,18 +836,7 @@
         call_kind_(call_kind),
         argument_count_(argument_count),
         hlt_instruction_(Instr::kSimulatorRedirectInstruction),
-        next_(list_) {
-    // Atomically prepend this element to the front of the global list.
-    // Note: Since elements are never removed, there is no ABA issue.
-    Redirection* list_head = list_;
-    do {
-      next_ = list_head;
-      list_head =
-          reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord(
-              reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_),
-              reinterpret_cast<uword>(this)));
-    } while (list_head != next_);
-  }
+        next_(NULL) {}
 
   uword external_function_;
   Simulator::CallKind call_kind_;
@@ -835,9 +844,11 @@
   uint32_t hlt_instruction_;
   Redirection* next_;
   static Redirection* list_;
+  static Mutex* mutex_;
 };
 
 Redirection* Redirection::list_ = NULL;
+Mutex* Redirection::mutex_ = new Mutex();
 
 uword Simulator::RedirectExternalReference(uword function,
                                            CallKind call_kind,
diff --git a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
index db3605e..7aebc9e 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
@@ -1602,7 +1602,7 @@
   bool get isPrivate => n(simpleName).startsWith('_');
 
   Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
-  Symbol get constructorName => const Symbol('');
+  Symbol get constructorName => Symbol.empty;
 
   TypeMirror get returnType => _target.type;
   List<ParameterMirror> get parameters {
@@ -2462,10 +2462,10 @@
   Symbol get constructorName {
     // TODO(ahe): I believe it is more appropriate to throw an exception or
     // return null.
-    if (!isConstructor) return const Symbol('');
+    if (!isConstructor) return Symbol.empty;
     String name = n(simpleName);
     int index = name.indexOf('.');
-    if (index == -1) return const Symbol('');
+    if (index == -1) return Symbol.empty;
     return s(name.substring(index + 1));
   }
 
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 4dac8c6..fa49808 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -284,7 +284,7 @@
    * desired behavior.
    */
   static const Zone root = _rootZone;
-  /** Deprecated, use [root] instead. */
+  @Deprecated("Use root instead")
   static const Zone ROOT = root;
 
   /** The currently running zone. */
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
index 2639ca8..cd54517 100644
--- a/sdk/lib/convert/ascii.dart
+++ b/sdk/lib/convert/ascii.dart
@@ -17,7 +17,7 @@
  *                                 0x20, 0x41, 0x53, 0x43, 0x49, 0x49, 0x21]);
  */
 const AsciiCodec ascii = const AsciiCodec();
-/** Deprecated, use [ascii] instead. */
+@Deprecated("Use ascii instead")
 const AsciiCodec ASCII = ascii;
 
 const int _asciiMask = 0x7F;
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index b538aae..bbccf95 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.dart
@@ -18,7 +18,7 @@
  *     var decoded = base64.decode("YmzDpWLDpnJncsO4ZAo=");
  */
 const Base64Codec base64 = const Base64Codec();
-/** Deprecated, use [base64] instead. */
+@Deprecated("Use base64 instead")
 const Base64Codec BASE64 = base64;
 
 /**
@@ -35,7 +35,7 @@
  *     var decoded = base64Url.decode("YmzDpWLDpnJncsO4ZAo=");
  */
 const Base64Codec base64Url = const Base64Codec.urlSafe();
-/** Deprecated, use [base64Url] instead. */
+@Deprecated("Use base64Url instead")
 const Base64Codec BASE64URL = base64Url;
 
 // Constants used in more than one class.
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index e7cb4ab..befde38 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -25,7 +25,7 @@
  * tag, but not inside a quoted attribute value, is still dangerous.
  */
 const HtmlEscape htmlEscape = const HtmlEscape();
-/** Deprecated, use [htmlEscape] instead. */
+@Deprecated("Use htmlEscape instead")
 const HtmlEscape HTML_ESCAPE = htmlEscape;
 
 /**
@@ -72,7 +72,7 @@
    */
   static const HtmlEscapeMode unknown =
       const HtmlEscapeMode._('unknown', true, true, true, true);
-  /** Deprecated, use [unknown] instead. */
+  @Deprecated("Use unknown instead")
   static const HtmlEscapeMode UNKNOWN = unknown;
 
   /**
@@ -87,7 +87,7 @@
    */
   static const HtmlEscapeMode attribute =
       const HtmlEscapeMode._('attribute', true, true, false, false);
-  /** Deprecated, use [attribute] instead. */
+  @Deprecated("Use attribute instead")
   static const HtmlEscapeMode ATTRIBUTE = attribute;
 
   /**
@@ -102,7 +102,7 @@
    */
   static const HtmlEscapeMode sqAttribute =
       const HtmlEscapeMode._('attribute', true, false, true, false);
-  /** Deprecated, use [sqAttribute] instead. */
+  @Deprecated("Use sqAttribute instead")
   static const HtmlEscapeMode SQ_ATTRIBUTE = sqAttribute;
 
   /**
@@ -116,7 +116,7 @@
    */
   static const HtmlEscapeMode element =
       const HtmlEscapeMode._('element', true, false, false, false);
-  /** Deprecated, use [element] instead. */
+  @Deprecated("Use element instead")
   static const HtmlEscapeMode ELEMENT = element;
 
   const HtmlEscapeMode._(this._name, this.escapeLtGt, this.escapeQuot,
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index bc50a00..b9095d1 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -66,7 +66,7 @@
  *     var decoded = json.decode('["foo", { "bar": 499 }]');
  */
 const JsonCodec json = const JsonCodec();
-/** Deprecated, use [json] instead. */
+@Deprecated("Use json instead")
 const JsonCodec JSON = json;
 
 typedef _Reviver(Object key, Object value);
diff --git a/sdk/lib/convert/latin1.dart b/sdk/lib/convert/latin1.dart
index af386ce..a2f8e8a 100644
--- a/sdk/lib/convert/latin1.dart
+++ b/sdk/lib/convert/latin1.dart
@@ -17,7 +17,7 @@
  *                                  0x72, 0x67, 0x72, 0xf8, 0x64]);
  */
 const Latin1Codec latin1 = const Latin1Codec();
-/** Deprecated, use [latin1] instead. */
+@Deprecated("Use latin1 instead")
 const Latin1Codec LATIN1 = latin1;
 
 const int _latin1Mask = 0xFF;
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index b5850a6..17bde46 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -6,12 +6,12 @@
 
 /** The Unicode Replacement character `U+FFFD` (�). */
 const int unicodeReplacementCharacterRune = 0xFFFD;
-/** Deprecated, use [unicodeReplacementCharacterRune] instead. */
+@Deprecated("Use unicodeReplacementCharacterRune instead")
 const int UNICODE_REPLACEMENT_CHARACTER_RUNE = unicodeReplacementCharacterRune;
 
 /** The Unicode Byte Order Marker (BOM) character `U+FEFF`. */
 const int unicodeBomCharacterRune = 0xFEFF;
-/** Deprecated, use [unicodeBomCharacterRune] instead. */
+@Deprecated("Use unicodeBomCharacterRune instead")
 const int UNICODE_BOM_CHARACTER_RUNE = unicodeBomCharacterRune;
 
 /**
@@ -27,7 +27,7 @@
  *                                0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
  */
 const Utf8Codec utf8 = const Utf8Codec();
-/** Deprecated, use [Utf8Codec] instead. */
+@Deprecated("Use Utf8Codec instead")
 const Utf8Codec UTF8 = utf8;
 
 /**
diff --git a/sdk/lib/core/annotations.dart b/sdk/lib/core/annotations.dart
index 3071723..c0234f5 100644
--- a/sdk/lib/core/annotations.dart
+++ b/sdk/lib/core/annotations.dart
@@ -214,3 +214,55 @@
  */
 @deprecated
 const Object proxy = const _Proxy();
+
+/**
+ * A hint to tools.
+ *
+ * Tools that work with Dart programs may accept hints to guide their behavior
+ * as `pragma` annotations on declarations.
+ * Each tool decides which hints it accepts, what they mean, and whether and
+ * how they apply to sub-parts of the annotated entity.
+ *
+ * Tools that recognize pragma hints should pick a pragma prefix to identify
+ * the tool. They should recognize any hint with a [name] starting with their
+ * prefix followed by `:` as if it was intended for that tool. A hint with a
+ * prefix for another tool should be ignored (unless compatibility with that
+ * other tool is a goal).
+ *
+ * A tool may recognize unprefixed names as well, if they would recognize that
+ * name with their own prefix in front.
+ *
+ * If the hint can be parameterized, an extra [options] object can be added as well.
+ *
+ * For example:
+ *
+ * ```dart
+ * @pragma('Tool:pragma-name', [param1, param2, ...])
+ * class Foo { }
+ *
+ * @pragma('OtherTool:other-pragma')
+ * void foo() { }
+ * ```
+ *
+ * Here class Foo is annotated with a Tool specific pragma 'pragma-name' and
+ * function foo is annotated with a pragma 'other-pragma' specific to OtherTool.
+ *
+ */
+class pragma {
+  /**
+   * The name of the hint.
+   *
+   * A string that is recognized by one or more tools, or such a string prefixed
+   * by a tool identifier and a colon, which is only recognized by that
+   * particular tool.
+   */
+  final String name;
+
+  /** Optional extra data parameterizing the hint. */
+  final Object options;
+
+  /** Creates a hint named [name] with optional [options]. */
+  const factory pragma(String name, [Object options]) = pragma._;
+
+  const pragma._(this.name, [this.options]);
+}
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 33913b4..ccc850b 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -131,21 +131,21 @@
   static const int sunday = 7;
   static const int daysPerWeek = 7;
 
-  /** Deprecated, use [monday] instead. */
+  @Deprecated("Use monday instead")
   static const int MONDAY = monday;
-  /** Deprecated, use [tuesday] instead. */
+  @Deprecated("Use tuesday instead")
   static const int TUESDAY = tuesday;
-  /** Deprecated, use [wednesday] instead. */
+  @Deprecated("Use wednesday instead")
   static const int WEDNESDAY = wednesday;
-  /** Deprecated, use [thursday] instead. */
+  @Deprecated("Use thursday instead")
   static const int THURSDAY = thursday;
-  /** Deprecated, use [friday] instead. */
+  @Deprecated("Use friday instead")
   static const int FRIDAY = friday;
-  /** Deprecated, use [saturday] instead. */
+  @Deprecated("Use saturday instead")
   static const int SATURDAY = saturday;
-  /** Deprecated, use [sunday] instead. */
+  @Deprecated("Use sunday instead")
   static const int SUNDAY = sunday;
-  /** Deprecated, use [daysPerWeek] instead. */
+  @Deprecated("Use daysPerWeek instead")
   static const int DAYS_PER_WEEK = daysPerWeek;
 
   // Month constants that are returned by the [month] getter.
@@ -163,31 +163,31 @@
   static const int december = 12;
   static const int monthsPerYear = 12;
 
-  /** Deprecated, use [january] instead. */
+  @Deprecated("Use january instead")
   static const int JANUARY = january;
-  /** Deprecated, use [february] instead. */
+  @Deprecated("Use february instead")
   static const int FEBRUARY = february;
-  /** Deprecated, use [march] instead. */
+  @Deprecated("Use march instead")
   static const int MARCH = march;
-  /** Deprecated, use [april] instead. */
+  @Deprecated("Use april instead")
   static const int APRIL = april;
-  /** Deprecated, use [may] instead. */
+  @Deprecated("Use may instead")
   static const int MAY = may;
-  /** Deprecated, use [june] instead. */
+  @Deprecated("Use june instead")
   static const int JUNE = june;
-  /** Deprecated, use [july] instead. */
+  @Deprecated("Use july instead")
   static const int JULY = july;
-  /** Deprecated, use [august] instead. */
+  @Deprecated("Use august instead")
   static const int AUGUST = august;
-  /** Deprecated, use [september] instead. */
+  @Deprecated("Use september instead")
   static const int SEPTEMBER = september;
-  /** Deprecated, use [october] instead. */
+  @Deprecated("Use october instead")
   static const int OCTOBER = october;
-  /** Deprecated, use [november] instead. */
+  @Deprecated("Use november instead")
   static const int NOVEMBER = november;
-  /** Deprecated, use [december] instead. */
+  @Deprecated("Use december instead")
   static const int DECEMBER = december;
-  /** Deprecated, use [monthsPerYear] instead. */
+  @Deprecated("Use monthsPerYear instead")
   static const int MONTHS_PER_YEAR = monthsPerYear;
 
   /**
diff --git a/sdk/lib/core/double.dart b/sdk/lib/core/double.dart
index 2d62636..e10a99b 100644
--- a/sdk/lib/core/double.dart
+++ b/sdk/lib/core/double.dart
@@ -23,19 +23,19 @@
  * double.
  */
 abstract class double extends num {
-  /** Deprecated, use [nan] instead. */
+  @Deprecated("Use nan instead")
   static const double NAN = nan;
   static const double nan = 0.0 / 0.0;
-  /** Deprecated, use [infinity] instead. */
+  @Deprecated("Use infinity instead")
   static const double INFINITY = infinity;
   static const double infinity = 1.0 / 0.0;
-  /** Deprecated, use [negativeInfinity] instead. */
+  @Deprecated("Use negativeInfinity instead")
   static const double NEGATIVE_INFINITY = negativeInfinity;
   static const double negativeInfinity = -infinity;
-  /** Deprecated, use [minPositive] instead. */
+  @Deprecated("Use minPositive instead")
   static const double MIN_POSITIVE = minPositive;
   static const double minPositive = 5e-324;
-  /** Deprecated, use [maxFinite] instead. */
+  @Deprecated("Use maxFinite instead")
   static const double MAX_FINITE = maxFinite;
   static const double maxFinite = 1.7976931348623157e+308;
 
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index 92f7ede..393fa9d 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -76,37 +76,37 @@
 
   static const Duration zero = const Duration(seconds: 0);
 
-  /** Deprecated, use [microsecondsPerMillisecond] instead. */
+  @Deprecated("Use microsecondsPerMillisecond instead")
   static const int MICROSECONDS_PER_MILLISECOND = microsecondsPerMillisecond;
-  /** Deprecated, use [millisecondsPerSecond] instead. */
+  @Deprecated("Use millisecondsPerSecond instead")
   static const int MILLISECONDS_PER_SECOND = millisecondsPerSecond;
-  /** Deprecated, use [secondsPerMinute] instead. */
+  @Deprecated("Use secondsPerMinute instead")
   static const int SECONDS_PER_MINUTE = secondsPerMinute;
-  /** Deprecated, use [minutesPerHour] instead. */
+  @Deprecated("Use minutesPerHour instead")
   static const int MINUTES_PER_HOUR = minutesPerHour;
-  /** Deprecated, use [hoursPerDay] instead. */
+  @Deprecated("Use hoursPerDay instead")
   static const int HOURS_PER_DAY = hoursPerDay;
-  /** Deprecated, use [microsecondsPerSecond] instead. */
+  @Deprecated("Use microsecondsPerSecond instead")
   static const int MICROSECONDS_PER_SECOND = microsecondsPerSecond;
-  /** Deprecated, use [microsecondsPerMinute] instead. */
+  @Deprecated("Use microsecondsPerMinute instead")
   static const int MICROSECONDS_PER_MINUTE = microsecondsPerMinute;
-  /** Deprecated, use [microsecondsPerHour] instead. */
+  @Deprecated("Use microsecondsPerHour instead")
   static const int MICROSECONDS_PER_HOUR = microsecondsPerHour;
-  /** Deprecated, use [microsecondsPerDay] instead. */
+  @Deprecated("Use microsecondsPerDay instead")
   static const int MICROSECONDS_PER_DAY = microsecondsPerDay;
-  /** Deprecated, use [millisecondsPerMinute] instead. */
+  @Deprecated("Use millisecondsPerMinute instead")
   static const int MILLISECONDS_PER_MINUTE = millisecondsPerMinute;
-  /** Deprecated, use [millisecondsPerHour] instead. */
+  @Deprecated("Use millisecondsPerHour instead")
   static const int MILLISECONDS_PER_HOUR = millisecondsPerHour;
-  /** Deprecated, use [millisecondsPerDay] instead. */
+  @Deprecated("Use millisecondsPerDay instead")
   static const int MILLISECONDS_PER_DAY = millisecondsPerDay;
-  /** Deprecated, use [secondsPerHour] instead. */
+  @Deprecated("Use secondsPerHour instead")
   static const int SECONDS_PER_HOUR = secondsPerHour;
-  /** Deprecated, use [secondsPerDay] instead. */
+  @Deprecated("Use secondsPerDay instead")
   static const int SECONDS_PER_DAY = secondsPerDay;
-  /** Deprecated, use [minutesPerDay] instead. */
+  @Deprecated("Use minutesPerDay instead")
   static const int MINUTES_PER_DAY = minutesPerDay;
-  /** Deprecated, use [zero] instead. */
+  @Deprecated("Use zero instead")
   static const Duration ZERO = zero;
 
   /*
diff --git a/sdk/lib/core/invocation.dart b/sdk/lib/core/invocation.dart
index 9e32581..3cae040 100644
--- a/sdk/lib/core/invocation.dart
+++ b/sdk/lib/core/invocation.dart
@@ -12,22 +12,77 @@
  * on it.
  */
 abstract class Invocation {
+  Invocation();
+
+  /**
+   * Creates an invocation corresponding to a method invocation.
+   *
+   * The method invocation has no type arguments.
+   * If the named arguments are omitted, they default to no named arguments.
+   */
+  factory Invocation.method(
+          Symbol memberName, Iterable<Object> positionalArguments,
+          [Map<Symbol, Object> namedArguments]) =>
+      new _Invocation.method(
+          memberName, null, positionalArguments, namedArguments);
+
+  /**
+   * Creates an invocation corresponding to a generic method invocation.
+   *
+   * If [typeArguments] is `null` or empty, the constructor is equivalent to
+   * calling [Invocation.method] with the remaining arguments.
+   * All the individual type arguments must be non-null.
+   *
+   * If the named arguments are omitted, they default to no named arguments.
+   */
+  factory Invocation.genericMethod(Symbol memberName,
+          Iterable<Type> typeArguments, Iterable<Object> positionalArguments,
+          [Map<Symbol, Object> namedArguments]) =>
+      new _Invocation.method(
+          memberName, typeArguments, positionalArguments, namedArguments);
+
+  /**
+   * Creates an invocation corresponding to a getter invocation.
+   */
+  factory Invocation.getter(Symbol name) = _Invocation.getter;
+
+  /**
+   * Creates an invocation corresponding to a setter invocation.
+   *
+   * This constructor accepts any [Symbol] as [memberName], but remember that
+   * *actual setter names* end in `=`, so the invocation corresponding
+   * to `object.member = value` is
+   * ```dart
+   * Invocation.setter(const Symbol("member="), value)
+   * ```
+   */
+  factory Invocation.setter(Symbol memberName, Object argument) =
+      _Invocation.setter;
+
   /** The name of the invoked member. */
   Symbol get memberName;
 
   /**
+   * An unmodifiable view of the type arguments of the call.
+   *
+   * If the member is a getter, setter or operator,
+   * the type argument list is always empty.
+   */
+  List<Type> get typeArguments => const <Type>[];
+
+  /**
    * An unmodifiable view of the positional arguments of the call.
    *
    * If the member is a getter, the positional arguments list is
-   * empty.
+   * always empty.
    */
-  List get positionalArguments;
+  List<dynamic> get positionalArguments;
 
   /**
    * An unmodifiable view of the named arguments of the call.
    *
-   * If the member is a getter, setter or operator, the named
-   * arguments map is empty.
+   * If the member is a getter, setter or operator,
+   * the named arguments map is always empty.
    */
   Map<Symbol, dynamic> get namedArguments;
 
@@ -52,3 +107,57 @@
   /** Whether the invocation was a getter or a setter call. */
   bool get isAccessor => isGetter || isSetter;
 }
+
+/** Implementation of [Invocation] used by its factory constructors. */
+class _Invocation implements Invocation {
+  final Symbol memberName;
+  final List<Type> typeArguments;
+  // Positional arguments is `null` for getters only.
+  final List<Object> _positional;
+  // Named arguments is `null` for accessors only.
+  final Map<Symbol, Object> _named;
+
+  _Invocation.method(this.memberName, Iterable<Type> types,
+      Iterable<Object> positional, Map<Symbol, Object> named)
+      : typeArguments = _ensureNonNullTypes(_makeUnmodifiable<Type>(types)),
+        _positional = _makeUnmodifiable<Object>(positional) ?? const <Object>[],
+        _named = (named == null || named.isEmpty)
+            ? const <Symbol, Object>{}
+            : new Map<Symbol, Object>.unmodifiable(named);
+
+  _Invocation.getter(this.memberName)
+      : typeArguments = const <Type>[],
+        _positional = null,
+        _named = null;
+
+  _Invocation.setter(this.memberName, Object argument)
+      : typeArguments = const <Type>[],
+        _positional = new List<Object>.unmodifiable([argument]),
+        _named = null;
+
+  List<dynamic> get positionalArguments => _positional ?? const <Object>[];
+
+  Map<Symbol, dynamic> get namedArguments => _named ?? const <Symbol, Object>{};
+
+  bool get isMethod => _named != null;
+  bool get isGetter => _positional == null;
+  bool get isSetter => _positional != null && _named == null;
+  bool get isAccessor => _named == null;
+
+  /// Checks that the elements of [types] are not null.
+  static List<Type> _ensureNonNullTypes(List<Type> types) {
+    if (types == null) return const <Type>[];
+    for (int i = 0; i < types.length; i++) {
+      if (types[i] == null) {
+        throw new ArgumentError(
+            "Type arguments must be non-null, was null at index $i.");
+      }
+    }
+    return types;
+  }
+
+  static List<T> _makeUnmodifiable<T>(Iterable<T> elements) {
+    if (elements == null) return null;
+    return new List<T>.unmodifiable(elements);
+  }
+}
diff --git a/sdk/lib/core/symbol.dart b/sdk/lib/core/symbol.dart
index e399d9c..ac0fc65 100644
--- a/sdk/lib/core/symbol.dart
+++ b/sdk/lib/core/symbol.dart
@@ -6,6 +6,17 @@
 
 /// Opaque name used by mirrors, invocations and [Function.apply].
 abstract class Symbol {
+  /** The symbol corresponding to the name of the unary minus operator. */
+  static const Symbol unaryMinus = const Symbol("unary-");
+
+  /**
+   * The empty symbol.
+   *
+   * The empty symbol is the name of libraries with no library declaration,
+   * and the base-name of the unnamed constructor.
+   */
+  static const Symbol empty = const Symbol("");
+
   /**
    * Constructs a new Symbol.
    *
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index bcc4df5..5fec1c0 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -68,11 +68,11 @@
 class Isolate {
   /** Argument to `ping` and `kill`: Ask for immediate action. */
   static const int immediate = 0;
-  /** Deprecated. Use [immediate] instead. */
+  @Deprecated("Use immediate instead")
   static const int IMMEDIATE = immediate;
   /** Argument to `ping` and `kill`: Ask for action before the next event. */
   static const int beforeNextEvent = 1;
-  /** Deprecated. Use [beforeNextEvent] instead. */
+  @Deprecated("Use beforeNextEvent instead")
   static const int BEFORE_NEXT_EVENT = beforeNextEvent;
 
   /**
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 68cad30..8e0a30f 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -66,21 +66,21 @@
  */
 const double sqrt2 = 1.4142135623730951;
 
-/** Deprecated, use [e] instead. */
+@Deprecated("Use e instead")
 const double E = e;
-/** Deprecated, use [ln10] instead. */
+@Deprecated("Use ln10 instead")
 const double LN10 = ln10;
-/** Deprecated, use [ln2] instead. */
+@Deprecated("Use ln2 instead")
 const double LN2 = ln2;
-/** Deprecated, use [log2e] instead. */
+@Deprecated("Use log2e instead")
 const double LOG2E = log2e;
-/** Deprecated, use [log10e] instead. */
+@Deprecated("Use log10e instead")
 const double LOG10E = log10e;
-/** Deprecated, use [pi] instead. */
+@Deprecated("Use pi instead")
 const double PI = pi;
-/** Deprecated, use [sqrt1_2] instead. */
+@Deprecated("Use sqrt1_2 instead")
 const double SQRT1_2 = sqrt1_2;
-/** Deprecated, use [sqrt2] instead. */
+@Deprecated("Use sqrt2 instead")
 const double SQRT2 = sqrt2;
 
 /**
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 9c20289..d4a1e0e 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -412,7 +412,7 @@
 }
 
 // TODO(lrn): Remove class for Dart 2.0.
-/** Deprecated, use [Endian] instead. */
+@Deprecated("Use Endian instead")
 abstract class Endianness {
   Endianness._(); // prevent construction.
   /** Deprecated, use [Endian.big] instead. */
@@ -781,7 +781,7 @@
     return buffer.asInt8List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 1;
 }
@@ -840,7 +840,7 @@
    */
   List<int> operator +(List<int> other);
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 1;
 }
@@ -891,7 +891,7 @@
     return buffer.asUint8ClampedList(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 1;
 }
@@ -945,7 +945,7 @@
     return buffer.asInt16List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 2;
 }
@@ -1000,7 +1000,7 @@
     return buffer.asUint16List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 2;
 }
@@ -1054,7 +1054,7 @@
     return buffer.asInt32List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 4;
 }
@@ -1109,7 +1109,7 @@
     return buffer.asUint32List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 4;
 }
@@ -1163,7 +1163,7 @@
     return buffer.asInt64List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 8;
 }
@@ -1218,7 +1218,7 @@
     return buffer.asUint64List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 8;
 }
@@ -1273,7 +1273,7 @@
     return buffer.asFloat32List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 4;
 }
@@ -1321,7 +1321,7 @@
     return buffer.asFloat64List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 8;
 }
@@ -1376,7 +1376,7 @@
    */
   List<Float32x4> operator +(List<Float32x4> other);
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 16;
 }
@@ -1431,7 +1431,7 @@
    */
   List<Int32x4> operator +(List<Int32x4> other);
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 16;
 }
@@ -1486,7 +1486,7 @@
     return buffer.asFloat64x2List(offsetInBytes, length);
   }
 
-  /** Deprecated, use [bytesPerElement] instead. */
+  @Deprecated("Use bytesPerElement instead")
   static const int BYTES_PER_ELEMENT = bytesPerElement;
   static const int bytesPerElement = 16;
 }
@@ -1826,517 +1826,517 @@
   static const int wwwy = 0x7F;
   static const int wwwz = 0xBF;
   static const int wwww = 0xFF;
-  /** Deprecated, use [xxxx] instead. */
+  @Deprecated("Use xxxx instead")
   static const int XXXX = xxxx;
-  /** Deprecated, use [xxxy] instead. */
+  @Deprecated("Use xxxy instead")
   static const int XXXY = xxxy;
-  /** Deprecated, use [xxxz] instead. */
+  @Deprecated("Use xxxz instead")
   static const int XXXZ = xxxz;
-  /** Deprecated, use [xxxw] instead. */
+  @Deprecated("Use xxxw instead")
   static const int