Version 2.0.0-dev.58.0

Merge commit '88d847ea3e62e4cadc326357a09e5a02a8ad0caf' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e02675e..4d101527 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+## 2.0.0-dev.58.0
+
 ## 2.0.0-dev.57.0
 
 * Support Javascript Promise APIs as a Dart Future.  In Javascript a Promise has two
diff --git a/DEPS b/DEPS
index 204088f..9f020fb 100644
--- a/DEPS
+++ b/DEPS
@@ -110,7 +110,7 @@
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_tag": "1.3.4",
   "protobuf_tag": "0.7.1",
-  "pub_rev": "0c172864be2d2043a9d630e07f6b4eae7472653f",
+  "pub_rev": "7bdcf4e4de85a7a8c7a322511b8198f1b6cb0a73",
   "pub_semver_tag": "1.4.1",
   "quiver_tag": "5aaa3f58c48608af5b027444d561270b53f15dbf",
   "resource_rev":"af5a5bf65511943398146cf146e466e5f0b95cb9",
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 7be888a..e967809 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -23,6 +23,7 @@
 import 'package:analyzer/src/generated/bazel.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/gn.dart';
+import 'package:analyzer/src/generated/package_build.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/workspace.dart';
@@ -281,11 +282,13 @@
   Workspace createWorkspace(String rootPath) {
     if (_hasPackageFileInPath(rootPath)) {
       // Bazel workspaces that include package files are treated like normal
-      // (non-Bazel) directories.
-      return _BasicWorkspace.find(resourceProvider, rootPath, this);
+      // (non-Bazel) directories. But may still use package:build.
+      return PackageBuildWorkspace.find(resourceProvider, rootPath, this) ??
+          _BasicWorkspace.find(resourceProvider, rootPath, this);
     }
     Workspace workspace = BazelWorkspace.find(resourceProvider, rootPath);
     workspace ??= GnWorkspace.find(resourceProvider, rootPath);
+    workspace ??= PackageBuildWorkspace.find(resourceProvider, rootPath, this);
     return workspace ?? _BasicWorkspace.find(resourceProvider, rootPath, this);
   }
 
diff --git a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
index 1f3035f..28b8ae0 100644
--- a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
@@ -141,6 +141,45 @@
       astFactory.expressionStatement(expression, semicolon);
 
   @override
+  Statement forStatement(
+          Token forKeyword,
+          Token leftParenthesis,
+          covariant variableList,
+          covariant initialization,
+          Token leftSeparator,
+          Expression condition,
+          Token rightSeparator,
+          List<Expression> updaters,
+          Token rightParenthesis,
+          Statement body) =>
+      astFactory.forStatement(
+          forKeyword,
+          leftParenthesis,
+          variableList,
+          initialization,
+          leftSeparator,
+          condition,
+          rightSeparator,
+          updaters,
+          rightParenthesis,
+          body);
+
+  @override
+  Expression getExpressionFromExpressionStatement(Statement statement) =>
+      (statement as ExpressionStatement).expression;
+
+  @override
+  Token getSemicolon(Statement statement) {
+    if (statement is ExpressionStatement) {
+      return statement.semicolon;
+    }
+    if (statement is EmptyStatement) {
+      return statement.semicolon;
+    }
+    return null;
+  }
+
+  @override
   kernel.DartType getTypeAt(TypeArgumentList typeArguments, int index) {
     return null; // typeArguments.arguments[index].type.kernelType;
   }
@@ -166,9 +205,24 @@
           elseStatement);
 
   @override
+  Generator<Expression, Statement, _Arguments> indexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression receiver,
+      Expression index,
+      kernel.Procedure getter,
+      kernel.Procedure setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   bool isBlock(Object node) => node is Block;
 
   @override
+  bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
+
+  @override
   bool isErroneousNode(Object node) => false /* ??? */;
 
   @override
@@ -177,6 +231,10 @@
       astFactory.isExpression(expression, isOperator, notOperator, type);
 
   @override
+  bool isExpressionStatement(Statement statement) =>
+      statement is ExpressionStatement;
+
+  @override
   bool isThisExpression(Object node) => node is ThisExpression;
 
   @override
@@ -280,12 +338,37 @@
         ..staticType = _typeProvider?.boolType;
 
   @override
+  Generator<Expression, Statement, _Arguments> nullAwarePropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression receiverExpression,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter,
+      kernel.DartType type) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   Object parenthesizedCondition(Token leftParenthesis, Expression expression,
           Token rightParenthesis) =>
       astFactory.parenthesizedExpression(
           leftParenthesis, expression, rightParenthesis);
 
   @override
+  Generator<Expression, Statement, _Arguments> propertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression receiver,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   int readOffset(AstNode node) => node.offset;
 
   @override
@@ -319,6 +402,17 @@
       astFactory.adjacentStrings(strings.cast<StringLiteral>());
 
   @override
+  Generator<Expression, Statement, _Arguments> superPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   Statement syntheticLabeledStatement(Statement statement) => statement;
 
   @override
@@ -326,6 +420,28 @@
       astFactory.thisExpression(thisKeyword);
 
   @override
+  Generator<Expression, Statement, _Arguments> thisIndexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression index,
+      kernel.Procedure getter,
+      kernel.Procedure setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
+  Generator<Expression, Statement, _Arguments> thisPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token location,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   Expression throwExpression(Token throwKeyword, Expression expression) =>
       astFactory.throwExpression(throwKeyword, expression);
 
@@ -352,6 +468,15 @@
       variablesDeclaration.variables.variables;
 
   @override
+  Generator<Expression, Statement, _Arguments> variableUseGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      VariableDeclarationStatement variable,
+      kernel.DartType promotedType) {
+    // TODO(brianwilkerson) Implement this.
+    throw new UnimplementedError();
+  }
+
   Statement whileStatement(Token whileKeyword,
           ParenthesizedExpression condition, Statement body) =>
       astFactory.whileStatement(whileKeyword, condition.leftParenthesis,
diff --git a/pkg/analyzer/lib/src/generated/package_build.dart b/pkg/analyzer/lib/src/generated/package_build.dart
new file mode 100644
index 0000000..96e2dcf
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/package_build.dart
@@ -0,0 +1,300 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:core';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/file_system/file_system.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/workspace.dart';
+import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:package_config/packages.dart';
+import 'package:path/path.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * Instances of the class `PackageBuildFileUriResolver` resolve `file` URI's by
+ * first resolving file uri's in the expected way, and then by looking in the
+ * corresponding generated directories.
+ */
+class PackageBuildFileUriResolver extends ResourceUriResolver {
+  final PackageBuildWorkspace workspace;
+
+  PackageBuildFileUriResolver(PackageBuildWorkspace workspace)
+      : workspace = workspace,
+        super(workspace.provider);
+
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+    if (!ResourceUriResolver.isFileUri(uri)) {
+      return null;
+    }
+    String path = provider.pathContext.fromUri(uri);
+    File file = workspace.findFile(path);
+    if (file != null) {
+      return file.createSource(actualUri ?? uri);
+    }
+    return null;
+  }
+}
+
+/**
+ * The [UriResolver] that can resolve `package` URIs in [PackageBuildWorkspace].
+ */
+class PackageBuildPackageUriResolver extends UriResolver {
+  final PackageBuildWorkspace _workspace;
+  final UriResolver _normalUriResolver;
+  final Context _context;
+
+  /**
+   * The cache of absolute [Uri]s to [Source]s mappings.
+   */
+  final Map<Uri, Source> _sourceCache = new HashMap<Uri, Source>();
+
+  PackageBuildPackageUriResolver(
+      PackageBuildWorkspace workspace, this._normalUriResolver)
+      : _workspace = workspace,
+        _context = workspace.provider.pathContext;
+
+  @override
+  Source resolveAbsolute(Uri _ignore, [Uri uri]) {
+    uri ??= _ignore;
+    return _sourceCache.putIfAbsent(uri, () {
+      if (uri.scheme != 'package') {
+        return null;
+      }
+
+      Source basicResolverSource = _normalUriResolver.resolveAbsolute(uri);
+      if (basicResolverSource != null && basicResolverSource.exists()) {
+        return basicResolverSource;
+      }
+
+      String uriPath = uri.path;
+      int slash = uriPath.indexOf('/');
+
+      // If the path either starts with a slash or has no slash, it is invalid.
+      if (slash < 1) {
+        return null;
+      }
+
+      String packageName = uriPath.substring(0, slash);
+      String fileUriPart = uriPath.substring(slash + 1);
+      String filePath = fileUriPart.replaceAll('/', _context.separator);
+
+      File file = _workspace.builtFile(
+          _workspace.builtPackageSourcePath(filePath), packageName);
+      if (file != null && file.exists) {
+        return file.createSource(uri);
+      }
+      return basicResolverSource;
+    });
+  }
+
+  @override
+  Uri restoreAbsolute(Source source) {
+    Context context = _workspace.provider.pathContext;
+    String path = source.fullName;
+
+    if (context.isWithin(_workspace.root, path)) {
+      String relative = context.relative(path, from: _workspace.root);
+      List<String> components = context.split(relative);
+      if (components.length > 4 &&
+          components[0] == 'build' &&
+          components[1] == 'generated' &&
+          components[3] == 'lib') {
+        String packageName = components[2];
+        String pathInLib = components.skip(4).join('/');
+        return Uri.parse('package:$packageName/$pathInLib');
+      }
+    }
+    return source.uri;
+  }
+}
+
+/**
+ * Information about a package:build workspace.
+ */
+class PackageBuildWorkspace extends Workspace {
+  /**
+   * The name of the directory that identifies the root of the workspace. Note,
+   * the presence of this file does not show package:build is used. For that,
+   * the subdirectory [_dartToolBuildName] must exist. A `pub` subdirectory
+   * will usually exist in non-package:build projects too.
+   */
+  static const String _dartToolRootName = '.dart_tool';
+
+  /**
+   * The name of the subdirectory in [_dartToolName] that distinguishes projects
+   * built with package:build.
+   */
+  static const String _dartToolBuildName = 'build';
+
+  /**
+   * We use pubspec.yaml to get the package name to be consistent with how
+   * package:build does it.
+   */
+  static const String _pubspecName = 'pubspec.yaml';
+
+  /**
+   * The resource provider used to access the file system.
+   */
+  final ResourceProvider provider;
+
+  /**
+   * The absolute workspace root path (the directory containing the `.dart_tool`
+   * directory).
+   */
+  final String root;
+
+  /**
+   * The name of the package under development as defined in pubspec.yaml. This
+   * matches the behavior of package:build.
+   */
+  final String projectPackageName;
+
+  final ContextBuilder _builder;
+
+  /**
+   * The map of package locations indexed by package name.
+   *
+   * This is a cached field.
+   */
+  Map<String, List<Folder>> _packageMap;
+
+  /**
+   * The package location strategy.
+   *
+   * This is a cached field.
+   */
+  Packages _packages;
+
+  PackageBuildWorkspace._(
+      this.provider, this.root, this.projectPackageName, this._builder);
+
+  @override
+  Map<String, List<Folder>> get packageMap {
+    _packageMap ??= _builder.convertPackagesToMap(packages);
+    return _packageMap;
+  }
+
+  Packages get packages {
+    _packages ??= _builder.createPackageMap(root);
+    return _packages;
+  }
+
+  @override
+  UriResolver get packageUriResolver => new PackageBuildPackageUriResolver(
+      this, new PackageMapUriResolver(provider, packageMap));
+
+  /**
+   * For some package file, which may or may not be a package source (it could
+   * be in `bin/`, `web/`, etc), find where its built counterpart will exist if
+   * its a generated source.
+   *
+   * To get a [builtPath] for a package source file to use in this method,
+   * use [builtPackageSourcePath]. For `bin/`, `web/`, etc, it must be relative
+   * to the project root.
+   */
+  File builtFile(String builtPath, String packageName) {
+    if (!packageMap.containsKey(packageName)) {
+      return null;
+    }
+    String path = context.join(
+        root, _dartToolRootName, 'build', 'generated', packageName, builtPath);
+    return provider.getFile(path);
+  }
+
+  /**
+   * Unlike the way that sources are resolved against `.packages` (if foo points
+   * to folder bar, then `foo:baz.dart` is found at `bar/baz.dart`), the built
+   * sources for a package require the `lib/` prefix first. This is because
+   * `bin/`, `web/`, and `test/` etc can all be built as well. This method
+   * exists to give a name to that prefix processing step.
+   */
+  String builtPackageSourcePath(String path) {
+    assert(context.isRelative(path));
+    return context.join('lib', path);
+  }
+
+  @override
+  SourceFactory createSourceFactory(DartSdk sdk) {
+    List<UriResolver> resolvers = <UriResolver>[];
+    if (sdk != null) {
+      resolvers.add(new DartUriResolver(sdk));
+    }
+    resolvers.add(packageUriResolver);
+    resolvers.add(new PackageBuildFileUriResolver(this));
+    return new SourceFactory(resolvers, packages, provider);
+  }
+
+  /**
+   * Return the file with the given [path], looking first into directories for
+   * source files, and then in the generated directory
+   * `.dart_tool/build/generated/$projectPackageName/$FILE`. The file in the
+   * workspace root is returned even if it does not exist. Return `null` if the
+   * given [path] is not in the workspace [root].
+   */
+  File findFile(String path) {
+    assert(context.isAbsolute(path));
+    try {
+      final String builtPath = context.relative(path, from: root);
+      final File file = builtFile(builtPath, projectPackageName);
+
+      if (file.exists) {
+        return file;
+      }
+
+      return provider.getFile(path);
+    } catch (_) {
+      return null;
+    }
+  }
+
+  /**
+   * Find the package:build workspace that contains the given [path].
+   *
+   * Return `null` if the path is not in a package:build workspace.
+   */
+  static PackageBuildWorkspace find(
+      ResourceProvider provider, String path, ContextBuilder builder) {
+    Context context = provider.pathContext;
+
+    // Ensure that the path is absolute and normalized.
+    if (!context.isAbsolute(path)) {
+      throw new ArgumentError('Not an absolute path: $path');
+    }
+    path = context.normalize(path);
+
+    Folder folder = provider.getFolder(path);
+    while (true) {
+      Folder parent = folder.parent;
+      if (parent == null) {
+        return null;
+      }
+
+      final File pubspec = folder.getChildAssumingFile(_pubspecName);
+      final Folder dartToolDir =
+          folder.getChildAssumingFolder(_dartToolRootName);
+      final Folder dartToolBuildDir =
+          dartToolDir.getChildAssumingFolder(_dartToolBuildName);
+
+      // Found the .dart_tool file, that's our project root. We also require a
+      // pubspec, to know the package name that package:build will assume.
+      if (dartToolBuildDir.exists && pubspec.exists) {
+        try {
+          final yaml = loadYaml(pubspec.readAsStringSync());
+          return new PackageBuildWorkspace._(
+              provider, folder.path, yaml['name'], builder);
+        } on Exception {}
+      }
+
+      // Go up the folder.
+      folder = parent;
+    }
+  }
+}
diff --git a/pkg/analyzer/test/generated/package_build_test.dart b/pkg/analyzer/test/generated/package_build_test.dart
new file mode 100644
index 0000000..1b2dedd
--- /dev/null
+++ b/pkg/analyzer/test/generated/package_build_test.dart
@@ -0,0 +1,479 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/generated/package_build.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:mockito/mockito.dart';
+import 'package:package_config/packages.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(PackageBuildFileUriResolverTest);
+    defineReflectiveTests(PackageBuildPackageUriResolverTest);
+    defineReflectiveTests(PackageBuildWorkspaceTest);
+  });
+}
+
+class MockContextBuilder extends Mock implements ContextBuilder {}
+
+class MockPackages extends Mock implements Packages {}
+
+class MockUriResolver extends Mock implements UriResolver {}
+
+@reflectiveTest
+class PackageBuildFileUriResolverTest extends _BaseTest {
+  PackageBuildWorkspace workspace;
+  PackageBuildFileUriResolver resolver;
+
+  void setUp() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    final ContextBuilder contextBuilder = new MockContextBuilder();
+    final Packages packages = new MockPackages();
+    when(contextBuilder.createPackageMap(_p('/workspace')))
+        .thenReturn(packages);
+    when(contextBuilder.convertPackagesToMap(packages))
+        .thenReturn({'project': []});
+    workspace =
+        PackageBuildWorkspace.find(provider, _p('/workspace'), contextBuilder);
+    resolver = new PackageBuildFileUriResolver(workspace);
+    provider.newFile(_p('/workspace/test.dart'), '');
+    provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/project/gen.dart'), '');
+  }
+
+  void test_resolveAbsolute_doesNotExist() {
+    Source source = _resolvePath('/workspace/foo.dart');
+    expect(source, isNotNull);
+    expect(source.exists(), isFalse);
+    expect(source.fullName, _p('/workspace/foo.dart'));
+  }
+
+  void test_resolveAbsolute_file() {
+    Source source = _resolvePath('/workspace/test.dart');
+    expect(source, isNotNull);
+    expect(source.exists(), isTrue);
+    expect(source.fullName, _p('/workspace/test.dart'));
+  }
+
+  void test_resolveAbsolute_folder() {
+    Source source = _resolvePath('/workspace');
+    expect(source, isNotNull);
+    expect(source.exists(), isFalse);
+    expect(source.fullName, _p('/workspace'));
+  }
+
+  void test_resolveAbsolute_generated_file_exists_one() {
+    Source source = _resolvePath('/workspace/gen.dart');
+    expect(source, isNotNull);
+    expect(source.exists(), isTrue);
+    expect(source.fullName,
+        _p('/workspace/.dart_tool/build/generated/project/gen.dart'));
+  }
+
+  void test_resolveAbsolute_notFile_dartUri() {
+    Uri uri = new Uri(scheme: 'dart', path: 'core');
+    Source source = resolver.resolveAbsolute(uri);
+    expect(source, isNull);
+  }
+
+  void test_resolveAbsolute_notFile_httpsUri() {
+    Uri uri = new Uri(scheme: 'https', path: '127.0.0.1/test.dart');
+    Source source = resolver.resolveAbsolute(uri);
+    expect(source, isNull);
+  }
+
+  void test_restoreAbsolute() {
+    Uri uri = provider.pathContext.toUri(_p('/workspace/test.dart'));
+    Source source = resolver.resolveAbsolute(uri);
+    expect(source, isNotNull);
+    expect(resolver.restoreAbsolute(source), uri);
+    expect(
+        resolver.restoreAbsolute(
+            new NonExistingSource(source.fullName, null, null)),
+        uri);
+  }
+
+  Source _resolvePath(String absolutePosixPath) {
+    String absolutePath = provider.convertPath(absolutePosixPath);
+    Uri uri = provider.pathContext.toUri(absolutePath);
+    return resolver.resolveAbsolute(uri);
+  }
+}
+
+@reflectiveTest
+class PackageBuildPackageUriResolverTest extends _BaseTest {
+  PackageBuildWorkspace workspace;
+  PackageBuildPackageUriResolver resolver;
+  UriResolver packageUriResolver;
+
+  Uri addPackageSource(String path, String uriStr, {bool create: true}) {
+    Uri uri = Uri.parse(uriStr);
+    final File file =
+        create ? provider.newFile(_p(path), '') : provider.getResource(path);
+    final Source source = file.createSource(uri);
+    when(packageUriResolver.resolveAbsolute(uri)).thenReturn(source);
+    return uri;
+  }
+
+  void setUp() {
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+  }
+
+  void test_resolveAbsolute_generated() {
+    _addResources([
+      '/workspace/.dart_tool/build/generated/project/lib/generated_file.dart',
+    ]);
+    final Uri sourceUri = addPackageSource('/workspace/lib/generated_file.dart',
+        'package:project/generated_file.dart',
+        create: false);
+    _assertResolveUri(sourceUri,
+        '/workspace/.dart_tool/build/generated/project/lib/generated_file.dart',
+        exists: true);
+  }
+
+  void test_resolveAbsolute_null_notPackage() {
+    _addResources([
+      '/workspace/.dart_tool/build/generated',
+    ]);
+    Source source = resolver.resolveAbsolute(Uri.parse('dart:async'));
+    expect(source, isNull);
+  }
+
+  void test_resolveAbsolute_null_startsWithSlash() {
+    _addResources([
+      '/workspace/.dart_tool/build/generated',
+    ]);
+    Source source =
+        resolver.resolveAbsolute(Uri.parse('package:/foo/bar.dart'));
+    expect(source, isNull);
+  }
+
+  void test_resolveAbsolute_source() {
+    _addResources([
+      '/workspace/.dart_tool/build/generated/project/lib/source_file.dart',
+    ]);
+    final Uri sourceUri = addPackageSource(
+        '/workspace/lib/source_file.dart', 'package:project/source_file.dart');
+    _assertResolveUri(sourceUri, '/workspace/lib/source_file.dart',
+        exists: true);
+  }
+
+  void test_resolveAbsolute_workspace_doesNotExist() {
+    _addResources([
+      '/workspace/.dart_tool/build/generated',
+    ]);
+    final Uri sourceUri = addPackageSource(
+        '/workspace/lib/doesNotExist.dart', 'package:project/doesNotExist.dart',
+        create: false);
+    _assertResolveUri(sourceUri, '/workspace/lib/doesNotExist.dart',
+        exists: false);
+  }
+
+  void _addResources(List<String> paths, {String workspacePath: '/workspace'}) {
+    for (String path in paths) {
+      if (path.endsWith('/')) {
+        provider.newFolder(_p(path.substring(0, path.length - 1)));
+      } else {
+        provider.newFile(_p(path), '');
+      }
+    }
+    final contextBuilder = new MockContextBuilder();
+    final packages = new MockPackages();
+    when(contextBuilder.createPackageMap(_p(workspacePath)))
+        .thenReturn(packages);
+    when(contextBuilder.convertPackagesToMap(packages))
+        .thenReturn({'project': []});
+    workspace =
+        PackageBuildWorkspace.find(provider, _p(workspacePath), contextBuilder);
+    packageUriResolver = new MockUriResolver();
+    resolver =
+        new PackageBuildPackageUriResolver(workspace, packageUriResolver);
+  }
+
+  Source _assertResolveUri(Uri uri, String posixPath,
+      {bool exists: true, bool restore: true}) {
+    Source source = resolver.resolveAbsolute(uri);
+    expect(source, isNotNull);
+    expect(source.fullName, _p(posixPath));
+    expect(source.uri, uri);
+    expect(source.exists(), exists);
+    // If enabled, test also "restoreAbsolute".
+    if (restore) {
+      Uri restoredUri = resolver.restoreAbsolute(source);
+      expect(restoredUri.toString(), uri.toString());
+    }
+    return source;
+  }
+}
+
+@reflectiveTest
+class PackageBuildWorkspaceTest extends _BaseTest {
+  void test_builtFile_currentProject() {
+    provider.newFolder(_p('/workspace/.dart_tool/build'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final libFile = provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/project/lib/file.dart'), '');
+    expect(workspace.builtFile('lib/file.dart', 'project'), libFile);
+  }
+
+  void test_builtFile_importedPackage() {
+    provider.newFolder(_p('/workspace/.dart_tool/build'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project', 'foo']);
+
+    final libFile = provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/foo/lib/file.dart'), '');
+    expect(workspace.builtFile('lib/file.dart', 'foo'), libFile);
+  }
+
+  void test_builtFile_notInPackagesGetsHidden() {
+    provider.newFolder(_p('/workspace/.dart_tool/build'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+
+    // Ensure package:bar is not configured.
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project', 'foo']);
+
+    // Create a generated file in package:bar.
+    provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/bar/lib/file.dart'), '');
+
+    // Bar not in packages, file should not be returned.
+    expect(workspace.builtFile('lib/file.dart', 'bar'), isNull);
+  }
+
+  void test_find_fail_notAbsolute() {
+    expect(
+        () => PackageBuildWorkspace.find(
+            provider, _p('not_absolute'), new MockContextBuilder()),
+        throwsArgumentError);
+  }
+
+  void test_find_hasDartToolAndPubspec() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+        provider, _p('/workspace'), new MockContextBuilder());
+    expect(workspace.root, _p('/workspace'));
+    expect(workspace.projectPackageName, 'project');
+  }
+
+  void test_find_hasDartToolAndPubspec_inParentDirectory() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+    provider.newFileWithBytes(
+        _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+        'name: subproject'.codeUnits);
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+        _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+    expect(workspace.root, _p('/workspace/opened/up/a/child/dir'));
+    expect(workspace.projectPackageName, 'subproject');
+  }
+
+  void
+      test_find_hasDartToolAndPubspec_inParentDirectory_ignoresMalformedPubspec() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+    provider.newFileWithBytes(
+        _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+        'not: yaml: here!!! 111'.codeUnits);
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+        _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+    expect(workspace.root, _p('/workspace'));
+    expect(workspace.projectPackageName, 'project');
+  }
+
+  void test_find_hasDartToolAndPubspec_inParentDirectory_ignoresSoloDartTool() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFolder(_p('/workspace/opened/up/a/child/dir'));
+    provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+        _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+    expect(workspace.root, _p('/workspace'));
+    expect(workspace.projectPackageName, 'project');
+  }
+
+  void test_find_hasDartToolAndPubspec_inParentDirectory_ignoresSoloPubspec() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFolder(_p('/workspace/opened/up/a/child/dir'));
+    provider.newFileWithBytes(
+        _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+        'name: subproject'.codeUnits);
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+        _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+    expect(workspace.root, _p('/workspace'));
+    expect(workspace.projectPackageName, 'project');
+  }
+
+  void test_find_hasDartToolNoBuild() {
+    // Edge case: an empty .dart_tool directory. Don't assume package:build.
+    provider.newFolder(_p('/workspace/.dart_tool'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+        provider, _p('/workspace'), new MockContextBuilder());
+    expect(workspace, isNull);
+  }
+
+  void test_find_hasDartToolNoPubspec() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+        provider, _p('/workspace'), new MockContextBuilder());
+    expect(workspace, isNull);
+  }
+
+  void test_find_hasDartToolPubButNotBuild() {
+    // Dart projects will have this directory, that don't use package:build.
+    provider.newFolder(_p('/workspace/.dart_tool/pub'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+        provider, _p('/workspace'), new MockContextBuilder());
+    expect(workspace, isNull);
+  }
+
+  void test_find_hasMalformedPubspec() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'not: yaml: here! 1111'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+        provider, _p('/workspace'), new MockContextBuilder());
+    expect(workspace, isNull);
+  }
+
+  void test_find_hasPubspecNoDartTool() {
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+        provider, _p('/workspace'), new MockContextBuilder());
+    expect(workspace, isNull);
+  }
+
+  void test_findFile_bin() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/bin'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final binFile = provider.newFile(_p('/workspace/bin/file.dart'), '');
+    expect(workspace.findFile('/workspace/bin/file.dart'), binFile);
+  }
+
+  void test_findFile_binGenerated() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/bin'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final binFile = provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/project/bin/file.dart'), '');
+    expect(workspace.findFile('/workspace/bin/file.dart'), binFile);
+  }
+
+  void test_findFile_libGenerated() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final libFile = provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/project/lib/file.dart'), '');
+    expect(workspace.findFile('/workspace/lib/file.dart'), libFile);
+  }
+
+  void test_findFile_test() {
+    provider
+        .newFolder(_p('/workspace/.dart_tool/build/generated/project/test'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final testFile = provider.newFile(_p('/workspace/test/file.dart'), '');
+    expect(workspace.findFile('/workspace/test/file.dart'), testFile);
+  }
+
+  void test_findFile_testGenerated() {
+    provider
+        .newFolder(_p('/workspace/.dart_tool/build/generated/project/test'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final testFile = provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/project/test/file.dart'), '');
+    expect(workspace.findFile('/workspace/test/file.dart'), testFile);
+  }
+
+  void test_findFile_web() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/web'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final webFile = provider.newFile(_p('/workspace/web/file.dart'), '');
+    expect(workspace.findFile('/workspace/web/file.dart'), webFile);
+  }
+
+  void test_findFile_webGenerated() {
+    provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/web'));
+    provider.newFileWithBytes(
+        _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+    PackageBuildWorkspace workspace =
+        _createWorkspace('/workspace', ['project']);
+
+    final webFile = provider.newFile(
+        _p('/workspace/.dart_tool/build/generated/project/web/file.dart'), '');
+    expect(workspace.findFile('/workspace/web/file.dart'), webFile);
+  }
+
+  PackageBuildWorkspace _createWorkspace(
+      String root, List<String> packageNames) {
+    final contextBuilder = new MockContextBuilder();
+    final packages = new MockPackages();
+    final packageMap = new Map.fromIterable(packageNames, value: ((_) => []));
+    when(contextBuilder.createPackageMap(_p(root))).thenReturn(packages);
+    when(contextBuilder.convertPackagesToMap(packages)).thenReturn(packageMap);
+    when(packages.asMap()).thenReturn(packageMap);
+    return PackageBuildWorkspace.find(provider, _p(root), contextBuilder);
+  }
+}
+
+class _BaseTest {
+  final MemoryResourceProvider provider = new MemoryResourceProvider();
+
+  /**
+   * Return the [provider] specific path for the given Posix [path].
+   */
+  String _p(String path) => provider.convertPath(path);
+}
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 56f90ba..7b529d3 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4495,12 +4495,12 @@
     // being reported in code that cannot actually be reached), but that hasn't
     // been proven yet.
     createParser('(int a, int b ;',
-        expectedEndOffset: 0 /* ErrorToken at end of token stream */);
+        expectedEndOffset: 14 /* ErrorToken at end of token stream */);
     FormalParameterList list = parser.parseFormalParameterList();
     expectNotNullIfNoErrors(list);
     if (usingFastaParser) {
-      listener
-          .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 1)]);
+      // Fasta scanner reports missing `)` error
+      listener.assertNoErrors();
     } else if (fe.Scanner.useFasta) {
       listener.errors
           .contains(expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 1));
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart
index a2c8624..aacff92 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart
@@ -12,6 +12,15 @@
 
 class MethodTest extends PartialCodeTest {
   buildAll() {
+    const allExceptEof = const [
+      'field',
+      'fieldConst',
+      'fieldFinal',
+      'methodNonVoid',
+      'methodVoid',
+      'getter',
+      'setter'
+    ];
     buildTests(
       'method_declaration',
       [
@@ -21,44 +30,52 @@
         new TestDescriptor(
           'noType_leftParen',
           'm(',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'm();',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'm() {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'noType_paramName',
           'm(B',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'm(B);',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'm(B) {}',
+          failing: ['methodNonVoid', 'getter', 'setter'],
         ),
         new TestDescriptor(
-          'noType_paramTypeAndName',
-          'm(B b',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'm(B b);',
-          allFailing: true,
-        ),
+            'noType_paramTypeAndName',
+            'm(B b',
+            [
+              ScannerErrorCode.EXPECTED_TOKEN,
+              ParserErrorCode.MISSING_FUNCTION_BODY
+            ],
+            'm(B b) {}'),
         new TestDescriptor(
           'noType_paramAndComma',
           'm(B b,',
-          [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
-          'm(B b, _s_);',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'm(B b) {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'noType_noParams',
           'm()',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'm();',
-          allFailing: true,
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'm() {}',
         ),
         new TestDescriptor(
           'noType_params',
           'm(b, c)',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'm(b, c);',
-          allFailing: true,
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'm(b, c) {}',
         ),
         new TestDescriptor(
           'noType_emptyOptional',
@@ -84,44 +101,53 @@
         new TestDescriptor(
           'type_leftParen',
           'A m(',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'A m();',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'A m() {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'type_paramName',
           'A m(B',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'A m(B);',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'A m(B) {}',
+          failing: ['methodNonVoid', 'getter', 'setter'],
         ),
         new TestDescriptor(
           'type_paramTypeAndName',
           'A m(B b',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'A m(B b);',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'A m(B b) {}',
         ),
         new TestDescriptor(
           'type_paramAndComma',
           'A m(B b,',
-          [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
-          'A m(B b, _s_);',
-          allFailing: true,
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'A m(B b) {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'type_noParams',
           'A m()',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'A m();',
-          allFailing: true,
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'A m() {}',
         ),
         new TestDescriptor(
           'type_params',
           'A m(b, c)',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'A m(b, c);',
-          allFailing: true,
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'A m(b, c) {}',
         ),
         new TestDescriptor(
           'type_emptyOptional',
@@ -147,50 +173,53 @@
         new TestDescriptor(
           'static_noType_leftParen',
           'static m(',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static m();',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static m() {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'static_noType_paramName',
           'static m(B',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static m(B);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static m(B) {}',
+          failing: ['methodNonVoid', 'getter', 'setter'],
         ),
         new TestDescriptor(
           'static_noType_paramTypeAndName',
           'static m(B b',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static m(B b);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static m(B b) {}',
         ),
         new TestDescriptor(
           'static_noType_paramAndComma',
           'static m(B b,',
-          [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
-          'static m(B b, _s_);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static m(B b) {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'static_noType_noParams',
           'static m()',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static m();',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'static m() {}',
         ),
         new TestDescriptor(
           'static_noType_params',
           'static m(b, c)',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static m(b, c);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'static m(b, c) {}',
         ),
         new TestDescriptor(
           'static_noType_emptyOptional',
@@ -216,50 +245,53 @@
         new TestDescriptor(
           'static_type_leftParen',
           'static A m(',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static A m();',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static A m() {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'static_type_paramName',
           'static A m(B',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static A m(B);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static A m(B) {}',
+          failing: ['methodNonVoid', 'getter', 'setter'],
         ),
         new TestDescriptor(
           'static_type_paramTypeAndName',
           'static A m(B b',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static A m(B b);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static A m(B b) {}',
         ),
         new TestDescriptor(
           'static_type_paramAndComma',
           'static A m(B b,',
-          [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
-          'static A m(B b, _s_);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [
+            ScannerErrorCode.EXPECTED_TOKEN,
+            ParserErrorCode.MISSING_FUNCTION_BODY
+          ],
+          'static A m(B b) {}',
+          failing: allExceptEof,
         ),
         new TestDescriptor(
           'static_type_noParams',
           'static A m()',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static A m();',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'static A m() {}',
         ),
         new TestDescriptor(
           'static_type_params',
           'static A m(b, c)',
-          [ParserErrorCode.EXPECTED_TOKEN],
-          'static A m(b, c);',
-          allFailing: true,
-          expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+          [ParserErrorCode.MISSING_FUNCTION_BODY],
+          'static A m(b, c) {}',
         ),
         new TestDescriptor(
           'static_type_emptyOptional',
diff --git a/pkg/front_end/lib/src/api_prototype/dependency_grapher.dart b/pkg/front_end/lib/src/api_prototype/dependency_grapher.dart
deleted file mode 100644
index fed5df9..0000000
--- a/pkg/front_end/lib/src/api_prototype/dependency_grapher.dart
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/base/processed_options.dart';
-import 'package:front_end/src/dependency_grapher_impl.dart' as impl;
-
-/// Generates a representation of the dependency graph of a program.
-///
-/// Given the Uri of one or more files, this function follows `import`,
-/// `export`, and `part` declarations to discover a graph of all files involved
-/// in the program.
-Future<Graph> graphForProgram(List<Uri> sources, CompilerOptions options) {
-  var processedOptions = new ProcessedOptions(options);
-  return impl.graphForProgram(sources, processedOptions);
-}
-
-/// A representation of the dependency graph of a program.
-///
-/// Not intended to be extended, implemented, or mixed in by clients.
-class Graph {
-  /// A list of all library cycles in the program, in topologically sorted order
-  /// (each cycle only depends on libraries in the cycles that precede it).
-  final topologicallySortedCycles = <LibraryCycleNode>[];
-}
-
-/// A representation of a single library cycle in the dependency graph of a
-/// program.
-///
-/// Not intended to be extended, implemented, or mixed in by clients.
-class LibraryCycleNode {
-  /// A map of all the libraries in the cycle, keyed by the URI of their
-  /// defining compilation unit.
-  final libraries = <Uri, LibraryNode>{};
-}
-
-/// A representation of a single library in the dependency graph of a program.
-///
-/// Not intended to be extended, implemented, or mixed in by clients.
-class LibraryNode {
-  /// The URI of this library's defining compilation unit.
-  final Uri uri;
-
-  /// A list of the URIs of all of this library's "part" files.
-  final parts = <Uri>[];
-
-  /// A list of all the other libraries this library directly depends on.
-  final dependencies = <LibraryNode>[];
-
-  LibraryNode(this.uri);
-}
diff --git a/pkg/front_end/lib/src/async_dependency_walker.dart b/pkg/front_end/lib/src/async_dependency_walker.dart
deleted file mode 100644
index b0c6535..0000000
--- a/pkg/front_end/lib/src/async_dependency_walker.dart
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-/**
- * An instance of [AsyncDependencyWalker] contains the core algorithms for
- * walking a dependency graph and evaluating nodes in a safe order.
- *
- * Computation of dependencies and evaluation of nodes may be asynchronous.
- */
-abstract class AsyncDependencyWalker<NodeType extends Node<NodeType>> {
-  /**
-   * Called by [walk] to evaluate a single non-cyclical node, after
-   * all that node's dependencies have been evaluated.
-   */
-  Future<Null> evaluate(NodeType v);
-
-  /**
-   * Called by [walk] to evaluate a strongly connected component
-   * containing one or more nodes.  All dependencies of the strongly
-   * connected component have been evaluated.
-   */
-  Future<Null> evaluateScc(List<NodeType> scc);
-
-  /**
-   * Walk the dependency graph starting at [startingPoint], finding
-   * strongly connected components and evaluating them in a safe order
-   * by calling [evaluate] and [evaluateScc].
-   *
-   * This is an implementation of Tarjan's strongly connected
-   * components algorithm
-   * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm).
-   *
-   * TODO(paulberry): Consider switching to an algorithm that allows
-   * dependencies to be computed in parallel, and nodes to be evaluated in
-   * parallel.
-   */
-  Future<Null> walk(NodeType startingPoint) async {
-    // TODO(paulberry): consider rewriting in a non-recursive way so
-    // that long dependency chains don't cause stack overflow.
-
-    // TODO(paulberry): in the event that an exception occurs during
-    // the walk, restore the state of the [Node] data structures so
-    // that further evaluation will be safe.
-
-    // The index which will be assigned to the next node that is
-    // freshly visited.
-    int index = 1;
-
-    // Stack of nodes which have been seen so far and whose strongly
-    // connected component is still being determined.  Nodes are only
-    // popped off the stack when they are evaluated, so sometimes the
-    // stack contains nodes that were visited after the current node.
-    List<NodeType> stack = <NodeType>[];
-
-    Future strongConnect(NodeType node) async {
-      bool hasTrivialCycle = false;
-
-      // Assign the current node an index and add it to the stack.  We
-      // haven't seen any of its dependencies yet, so set its lowLink
-      // to its index, indicating that so far it is the only node in
-      // its strongly connected component.
-      node._index = node._lowLink = index++;
-      stack.add(node);
-
-      // Consider the node's dependencies one at a time.
-      var dependencies =
-          node._dependencies ??= await node.computeDependencies();
-      for (NodeType dependency in dependencies) {
-        // If the dependency has already been evaluated, it can't be
-        // part of this node's strongly connected component, so we can
-        // skip it.
-        if (dependency._isEvaluated) {
-          continue;
-        }
-        if (identical(node, dependency)) {
-          // If a node includes itself as a dependency, there is no need to
-          // explore the dependency further.
-          hasTrivialCycle = true;
-        } else if (dependency._index == 0) {
-          // The dependency hasn't been seen yet, so recurse on it.
-          await strongConnect(dependency);
-          // If the dependency's lowLink refers to a node that was
-          // visited before the current node, that means that the
-          // current node, the dependency, and the node referred to by
-          // the dependency's lowLink are all part of the same
-          // strongly connected component, so we need to update the
-          // current node's lowLink accordingly.
-          if (dependency._lowLink < node._lowLink) {
-            node._lowLink = dependency._lowLink;
-          }
-        } else {
-          // The dependency has already been seen, so it is part of
-          // the current node's strongly connected component.  If it
-          // was visited earlier than the current node's lowLink, then
-          // it is a new addition to the current node's strongly
-          // connected component, so we need to update the current
-          // node's lowLink accordingly.
-          if (dependency._index < node._lowLink) {
-            node._lowLink = dependency._index;
-          }
-        }
-      }
-
-      // If the current node's lowLink is the same as its index, then
-      // we have finished visiting a strongly connected component, so
-      // pop the stack and evaluate it before moving on.
-      if (node._lowLink == node._index) {
-        // The strongly connected component has only one node.  If there is a
-        // cycle, it's a trivial one.
-        if (identical(stack.last, node)) {
-          stack.removeLast();
-          node._isEvaluated = true;
-          if (hasTrivialCycle) {
-            await evaluateScc(<NodeType>[node]);
-          } else {
-            await evaluate(node);
-          }
-        } else {
-          // There are multiple nodes in the strongly connected
-          // component.
-          List<NodeType> scc = <NodeType>[];
-          while (true) {
-            NodeType otherNode = stack.removeLast();
-            scc.add(otherNode);
-            otherNode._isEvaluated = true;
-            if (identical(otherNode, node)) {
-              break;
-            }
-          }
-          await evaluateScc(scc);
-        }
-      }
-    }
-
-    // Kick off the algorithm starting with the starting point.
-    await strongConnect(startingPoint);
-  }
-}
-
-/**
- * Instances of [Node] represent nodes in a dependency graph.  The
- * type parameter, [NodeType], is the derived type (this affords some
- * extra type safety by making it difficult to accidentally construct
- * bridges between unrelated dependency graphs).
- */
-abstract class Node<NodeType> {
-  /**
-   * Index used by Tarjan's strongly connected components algorithm.
-   * Zero means the node has not been visited yet; a nonzero value
-   * counts the order in which the node was visited.
-   */
-  int _index = 0;
-
-  /**
-   * Low link used by Tarjan's strongly connected components
-   * algorithm.  This represents the smallest [_index] of all the nodes
-   * in the strongly connected component to which this node belongs.
-   */
-  int _lowLink = 0;
-
-  List<NodeType> _dependencies;
-
-  bool _isEvaluated = false;
-
-  /**
-   * Compute the dependencies of this node.
-   */
-  Future<List<NodeType>> computeDependencies();
-}
diff --git a/pkg/front_end/lib/src/dependency_grapher_impl.dart b/pkg/front_end/lib/src/dependency_grapher_impl.dart
deleted file mode 100644
index f22f992..0000000
--- a/pkg/front_end/lib/src/dependency_grapher_impl.dart
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:front_end/src/api_prototype/dependency_grapher.dart';
-import 'package:front_end/src/async_dependency_walker.dart';
-import 'package:front_end/src/base/processed_options.dart';
-import 'package:front_end/src/fasta/parser.dart';
-import 'package:front_end/src/fasta/scanner.dart';
-import 'package:front_end/src/fasta/source/directive_listener.dart';
-import 'package:front_end/src/fasta/uri_translator.dart';
-
-/// Generates a representation of the dependency graph of a program.
-///
-/// Given the Uri of one or more files, this function follows `import`,
-/// `export`, and `part` declarations to discover a graph of all files involved
-/// in the program.
-///
-/// If a [fileReader] is supplied, it is used to read file contents; otherwise
-/// they are read directly from `options.fileSystem`.
-///
-/// This is intended for internal use by the front end.  Clients should use
-/// package:front_end/src/api_prototype/dependency_grapher.dart.
-Future<Graph> graphForProgram(List<Uri> sources, ProcessedOptions options,
-    {FileReader fileReader}) async {
-  UriTranslator uriTranslator = await options.getUriTranslator();
-  fileReader ??= (originalUri, resolvedUri) =>
-      options.fileSystem.entityForUri(resolvedUri).readAsString();
-  var walker = new _Walker(fileReader, uriTranslator, options.compileSdk);
-  var startingPoint = new _StartingPoint(walker, sources);
-  await walker.walk(startingPoint);
-  return walker.graph;
-}
-
-/// Type of the callback function used by [graphForProgram] to read file
-/// contents.
-typedef Future<String> FileReader(Uri originalUri, Uri resolvedUri);
-
-class _StartingPoint extends _WalkerNode {
-  final List<Uri> sources;
-
-  _StartingPoint(_Walker walker, this.sources) : super(walker, null);
-
-  @override
-  Future<List<_WalkerNode>> computeDependencies() async =>
-      sources.map(walker.nodeForUri).toList();
-}
-
-class _Walker extends AsyncDependencyWalker<_WalkerNode> {
-  final FileReader fileReader;
-  final UriTranslator uriTranslator;
-  final _nodesByUri = <Uri, _WalkerNode>{};
-  final graph = new Graph();
-  final bool compileSdk;
-
-  _Walker(this.fileReader, this.uriTranslator, this.compileSdk);
-
-  @override
-  Future<Null> evaluate(_WalkerNode v) {
-    if (v is _StartingPoint) return new Future.value();
-    return evaluateScc([v]);
-  }
-
-  @override
-  Future<Null> evaluateScc(List<_WalkerNode> scc) {
-    var cycle = new LibraryCycleNode();
-    for (var walkerNode in scc) {
-      cycle.libraries[walkerNode.uri] = walkerNode.library;
-    }
-    graph.topologicallySortedCycles.add(cycle);
-    return new Future.value();
-  }
-
-  _WalkerNode nodeForUri(Uri referencedUri) {
-    var dependencyNode = _nodesByUri.putIfAbsent(
-        referencedUri, () => new _WalkerNode(this, referencedUri));
-    return dependencyNode;
-  }
-}
-
-class _WalkerNode extends Node<_WalkerNode> {
-  static final dartCoreUri = Uri.parse('dart:core');
-  final _Walker walker;
-  final Uri uri;
-  final LibraryNode library;
-
-  _WalkerNode(this.walker, Uri uri)
-      : uri = uri,
-        library = new LibraryNode(uri);
-
-  @override
-  Future<List<_WalkerNode>> computeDependencies() async {
-    var dependencies = <_WalkerNode>[];
-    // TODO(paulberry): add error recovery if the file can't be read.
-    var resolvedUri = uri.scheme == 'dart' || uri.scheme == 'package'
-        ? walker.uriTranslator.translate(uri)
-        : uri;
-    if (resolvedUri == null) {
-      // TODO(paulberry): If an error reporter was provided, report the error
-      // in the proper way and continue.
-      throw new StateError('Invalid URI: $uri');
-    }
-    var contents = await walker.fileReader(uri, resolvedUri);
-    var scannerResults = scanString(contents);
-    // TODO(paulberry): report errors.
-    var listener = new DirectiveListener();
-    new TopLevelParser(listener).parseUnit(scannerResults.tokens);
-    bool coreUriFound = false;
-    void handleDependency(Uri referencedUri) {
-      _WalkerNode dependencyNode = walker.nodeForUri(referencedUri);
-      library.dependencies.add(dependencyNode.library);
-      if (referencedUri.scheme != 'dart' || walker.compileSdk) {
-        dependencies.add(dependencyNode);
-      }
-      if (referencedUri == dartCoreUri) {
-        coreUriFound = true;
-      }
-    }
-
-    for (var part in listener.parts) {
-      // TODO(paulberry): when we support SDK libraries, we'll need more
-      // complex logic here to find SDK parts correctly.
-      library.parts.add(uri.resolve(part));
-    }
-
-    for (var dep in listener.imports) {
-      handleDependency(uri.resolve(dep.uri));
-    }
-
-    for (var dep in listener.exports) {
-      handleDependency(uri.resolve(dep.uri));
-    }
-
-    if (!coreUriFound) {
-      handleDependency(dartCoreUri);
-    }
-    return dependencies;
-  }
-}
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index 9a49fd8..65fc3cd 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -14,8 +14,6 @@
 
 export '../scope.dart' show AccessErrorBuilder, Scope, ScopeBuilder;
 
-export '../source/unhandled_listener.dart' show Unhandled;
-
 export 'builtin_type_builder.dart' show BuiltinTypeBuilder;
 
 export 'class_builder.dart' show ClassBuilder;
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 abcc818..2fc31e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -6,6 +6,8 @@
 
 import 'dart:core' hide MapEntry;
 
+import 'package:kernel/ast.dart' as kernel show Expression, Statement;
+
 import '../constant_context.dart' show ConstantContext;
 
 import '../fasta_codes.dart' as fasta;
@@ -19,22 +21,7 @@
 import '../modifier.dart' show Modifier, constMask, covariantMask, finalMask;
 
 import '../names.dart'
-    show
-        ampersandName,
-        barName,
-        callName,
-        caretName,
-        divisionName,
-        emptyName,
-        indexGetName,
-        indexSetName,
-        leftShiftName,
-        minusName,
-        multiplyName,
-        mustacheName,
-        percentName,
-        plusName,
-        rightShiftName;
+    show callName, emptyName, indexGetName, indexSetName, minusName, plusName;
 
 import '../parser.dart'
     show
@@ -85,6 +72,8 @@
 import 'expression_generator.dart'
     show
         DeferredAccessGenerator,
+        DelayedAssignment,
+        DelayedPostfixIncrement,
         ErroneousExpressionGenerator,
         Generator,
         IncompleteErrorGenerator,
@@ -118,8 +107,6 @@
 
 import 'kernel_ast_api.dart' hide Expression, Statement;
 
-import 'kernel_ast_api.dart' as kernel show Expression, Statement;
-
 import 'kernel_builder.dart';
 
 import 'type_algorithms.dart' show calculateBounds;
@@ -325,10 +312,6 @@
 
   Statement popStatement() => forest.wrapVariables(pop());
 
-  void ignore(Unhandled value) {
-    pop();
-  }
-
   void enterSwitchScope() {
     push(switchScope ?? NullValue.SwitchScope);
     switchScope = scope;
@@ -654,8 +637,11 @@
   }
 
   @override
-  void finishFunction(List annotations, FormalParameters<Arguments> formals,
-      AsyncMarker asyncModifier, kernel.Statement body) {
+  void finishFunction(
+      List annotations,
+      FormalParameters<Expression, Statement, Arguments> formals,
+      AsyncMarker asyncModifier,
+      kernel.Statement body) {
     debugEvent("finishFunction");
     typePromoter.finished();
 
@@ -753,7 +739,7 @@
 
     enterLocalScope(
         null,
-        new FormalParameters<Arguments>(
+        new FormalParameters<Expression, Statement, Arguments>(
                 parameters.positionalParameters, null, -1)
             .computeFormalParameterScope(scope, member, this));
 
@@ -925,7 +911,8 @@
       if (arguments == null) {
         push(new IncompletePropertyAccessGenerator(this, beginToken, name));
       } else {
-        push(new SendAccessGenerator(this, beginToken, name, arguments));
+        push(new SendAccessGenerator(
+            this, beginToken, name, forest.castArguments(arguments)));
       }
     } else if (arguments == null) {
       push(receiver);
@@ -1852,14 +1839,6 @@
     Statement body = popStatement();
     List<Expression> updates = popListForEffect(updateExpressionCount);
     Statement conditionStatement = popStatement();
-    kernel.Statement kernelConditionStatement =
-        toKernelStatement(conditionStatement);
-    Expression condition = null;
-    if (kernelConditionStatement is ExpressionStatement) {
-      condition = toExpression(kernelConditionStatement.expression);
-    } else {
-      assert(kernelConditionStatement is EmptyStatement);
-    }
     dynamic variableOrExpression = pop();
     List<VariableDeclaration> variables =
         buildVariableDeclarations(variableOrExpression);
@@ -1870,22 +1849,36 @@
     exitLocalScope();
     JumpTarget continueTarget = exitContinueTarget();
     JumpTarget breakTarget = exitBreakTarget();
-    kernel.Statement kernelBody = toKernelStatement(body);
     if (continueTarget.hasUsers) {
-      kernelBody = new ShadowLabeledStatement(kernelBody);
-      continueTarget.resolveContinues(forest, kernelBody);
+      body = forest.syntheticLabeledStatement(body);
+      continueTarget.resolveContinues(forest, body);
     }
-    kernel.Statement result = new ShadowForStatement(
+    Expression condition;
+    Token rightSeparator;
+    if (forest.isExpressionStatement(conditionStatement)) {
+      condition =
+          forest.getExpressionFromExpressionStatement(conditionStatement);
+      rightSeparator = forest.getSemicolon(conditionStatement);
+    } else {
+      assert(forest.isEmptyStatement(conditionStatement));
+      rightSeparator = forest.getSemicolon(conditionStatement);
+    }
+    Statement result = forest.forStatement(
+        forKeyword,
+        leftParen,
         variables,
-        toKernelExpression(condition),
-        toKernelExpressionList(updates),
-        kernelBody)
-      ..fileOffset = forKeyword.charOffset;
+        variables,
+        leftSeparator,
+        condition,
+        rightSeparator,
+        updates,
+        leftParen.endGroup,
+        body);
     if (breakTarget.hasUsers) {
-      result = new ShadowLabeledStatement(result);
+      result = forest.syntheticLabeledStatement(result);
       breakTarget.resolveBreaks(forest, result);
     }
-    exitLoopOrSwitch(toStatement(result));
+    exitLoopOrSwitch(result);
   }
 
   @override
@@ -2094,7 +2087,7 @@
   @override
   void endFunctionType(Token functionToken, Token endToken) {
     debugEvent("FunctionType");
-    FormalParameters<Arguments> formals = pop();
+    FormalParameters<Expression, Statement, Arguments> formals = pop();
     DartType returnType = pop();
     List<TypeParameter> typeVariables = typeVariableBuildersToKernel(pop());
     FunctionType type = formals.toFunctionType(returnType, typeVariables);
@@ -2268,7 +2261,7 @@
     if (inCatchClause || functionNestingLevel != 0) {
       exitLocalScope();
     }
-    FormalParameters<Arguments> formals = pop();
+    FormalParameters<Expression, Statement, Arguments> formals = pop();
     DartType returnType = pop();
     List<TypeParameter> typeVariables = typeVariableBuildersToKernel(pop());
     FunctionType type = formals.toFunctionType(returnType, typeVariables);
@@ -2323,8 +2316,8 @@
     List<VariableDeclaration> variables =
         new List<VariableDeclaration>.filled(count, null, growable: true);
     popList(count, variables);
-    FormalParameters<Arguments> formals =
-        new FormalParameters(variables, optional, beginToken.charOffset);
+    var formals = new FormalParameters<Expression, Statement, Arguments>(
+        variables, optional, beginToken.charOffset);
     constantContext = pop();
     push(formals);
     if ((inCatchClause || functionNestingLevel != 0) &&
@@ -2358,7 +2351,8 @@
     if (catchKeyword != null) {
       exitLocalScope();
     }
-    FormalParameters<Arguments> catchParameters = popIfNotNull(catchKeyword);
+    FormalParameters<Expression, Statement, Arguments> catchParameters =
+        popIfNotNull(catchKeyword);
     DartType type = popIfNotNull(onKeyword) ?? const DynamicType();
     VariableDeclaration exception;
     VariableDeclaration stackTrace;
@@ -2421,13 +2415,8 @@
           lookupInstanceMember(indexGetName, isSuper: true),
           lookupInstanceMember(indexSetName, isSuper: true)));
     } else {
-      push(IndexedAccessGenerator.make<Arguments>(
-          this,
-          openSquareBracket,
-          toKernelExpression(toValue(receiver)),
-          toKernelExpression(index),
-          null,
-          null));
+      push(IndexedAccessGenerator.make(
+          this, openSquareBracket, toValue(receiver), index, null, null));
     }
   }
 
@@ -2492,7 +2481,7 @@
     debugEvent("UnaryPostfixAssignmentExpression");
     var generator = pop();
     if (generator is Generator) {
-      push(new DelayedPostfixIncrement<Arguments>(
+      push(new DelayedPostfixIncrement(
           this, token, generator, incrementOperator(token), null));
     } else {
       push(
@@ -2794,7 +2783,7 @@
           ? wrapInDeferredCheck(expression, deferredPrefix, checkOffset)
           : expression);
     } else if (type is ErroneousExpressionGenerator) {
-      push(type.buildError(arguments));
+      push(type.buildError(forest.castArguments(arguments)));
     } else {
       push(throwNoSuchMethodError(storeOffset(forest.literalNull(null), offset),
           debugName(getNodeName(type), name), arguments, nameToken.charOffset));
@@ -3018,7 +3007,7 @@
     Statement body = popStatement();
     AsyncMarker asyncModifier = pop();
     exitLocalScope();
-    FormalParameters<Arguments> formals = pop();
+    FormalParameters<Expression, Statement, Arguments> formals = pop();
     var declaration = pop();
     var returnType = pop();
     var hasImplicitReturnType = returnType == null;
@@ -3115,7 +3104,7 @@
     Statement body = popStatement();
     AsyncMarker asyncModifier = pop();
     exitLocalScope();
-    FormalParameters<Arguments> formals = pop();
+    FormalParameters<Expression, Statement, Arguments> formals = pop();
     exitFunction();
     List<TypeParameter> typeParameters = typeVariableBuildersToKernel(pop());
     FunctionNode function = formals.addToFunction(new FunctionNode(
@@ -4209,203 +4198,6 @@
   String toString() => "label($name)";
 }
 
-abstract class ContextAwareGenerator<Arguments> extends Generator<Arguments> {
-  final Generator generator;
-
-  ContextAwareGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.generator)
-      : super(helper, token);
-
-  String get plainNameForRead {
-    return unsupported("plainNameForRead", token.charOffset, helper.uri);
-  }
-
-  kernel.Expression doInvocation(int charOffset, Arguments arguments) {
-    return unhandled("${runtimeType}", "doInvocation", charOffset, uri);
-  }
-
-  kernel.Expression buildSimpleRead();
-
-  kernel.Expression buildForEffect();
-
-  kernel.Expression buildAssignment(kernel.Expression value,
-      {bool voidContext: false}) {
-    return makeInvalidWrite(value);
-  }
-
-  kernel.Expression buildNullAwareAssignment(
-      kernel.Expression value, DartType type, int offset,
-      {bool voidContext: false}) {
-    return makeInvalidWrite(value);
-  }
-
-  kernel.Expression buildCompoundAssignment(
-      Name binaryOperator, kernel.Expression value,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget,
-      bool isPreIncDec: false}) {
-    return makeInvalidWrite(value);
-  }
-
-  kernel.Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    return makeInvalidWrite(null);
-  }
-
-  kernel.Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    return makeInvalidWrite(null);
-  }
-
-  makeInvalidRead() {
-    return unsupported("makeInvalidRead", token.charOffset, helper.uri);
-  }
-
-  kernel.Expression makeInvalidWrite(kernel.Expression value) {
-    return helper.deprecated_buildCompileTimeError(
-        "Can't be used as left-hand side of assignment.",
-        offsetForToken(token));
-  }
-}
-
-class DelayedAssignment<Arguments> extends ContextAwareGenerator<Arguments> {
-  final kernel.Expression value;
-
-  final String assignmentOperator;
-
-  DelayedAssignment(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      Generator generator,
-      this.value,
-      this.assignmentOperator)
-      : super(helper, token, generator);
-
-  String get debugName => "DelayedAssignment";
-
-  kernel.Expression buildSimpleRead() {
-    return handleAssignment(false);
-  }
-
-  kernel.Expression buildForEffect() {
-    return handleAssignment(true);
-  }
-
-  kernel.Expression handleAssignment(bool voidContext) {
-    if (helper.constantContext != ConstantContext.none) {
-      return helper.deprecated_buildCompileTimeError(
-          "Not a constant expression.", offsetForToken(token));
-    }
-    if (identical("=", assignmentOperator)) {
-      return generator.buildAssignment(value, voidContext: voidContext);
-    } else if (identical("+=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(plusName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("-=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(minusName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("*=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(multiplyName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("%=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(percentName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("&=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(ampersandName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("/=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(divisionName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("<<=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(leftShiftName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical(">>=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(rightShiftName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("??=", assignmentOperator)) {
-      return generator.buildNullAwareAssignment(
-          value, const DynamicType(), offsetForToken(token),
-          voidContext: voidContext);
-    } else if (identical("^=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(caretName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("|=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(barName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else if (identical("~/=", assignmentOperator)) {
-      return generator.buildCompoundAssignment(mustacheName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
-    } else {
-      return unhandled(
-          assignmentOperator, "handleAssignment", token.charOffset, helper.uri);
-    }
-  }
-
-  @override
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    if (!identical("=", assignmentOperator) ||
-        !generator.isThisPropertyAccess) {
-      return generator.buildFieldInitializer(initializedFields);
-    }
-    return helper.buildFieldInitializer(
-        false, generator.plainNameForRead, offsetForToken(token), value);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", value: ");
-    printNodeOn(value, sink);
-    sink.write(", assignmentOperator: ");
-    sink.write(assignmentOperator);
-  }
-}
-
-class DelayedPostfixIncrement<Arguments>
-    extends ContextAwareGenerator<Arguments> {
-  final Name binaryOperator;
-
-  final Procedure interfaceTarget;
-
-  DelayedPostfixIncrement(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      Generator generator,
-      this.binaryOperator,
-      this.interfaceTarget)
-      : super(helper, token, generator);
-
-  String get debugName => "DelayedPostfixIncrement";
-
-  kernel.Expression buildSimpleRead() {
-    return generator.buildPostfixIncrement(binaryOperator,
-        offset: offsetForToken(token),
-        voidContext: false,
-        interfaceTarget: interfaceTarget);
-  }
-
-  kernel.Expression buildForEffect() {
-    return generator.buildPostfixIncrement(binaryOperator,
-        offset: offsetForToken(token),
-        voidContext: true,
-        interfaceTarget: interfaceTarget);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", binaryOperator: ");
-    sink.write(binaryOperator.name);
-    sink.write(", interfaceTarget: ");
-    printQualifiedNameOn(interfaceTarget, sink);
-  }
-}
-
 class JumpTarget<Statement> extends Builder {
   final List<Statement> users = <Statement>[];
 
@@ -4536,7 +4328,7 @@
   OptionalFormals(this.kind, this.formals);
 }
 
-class FormalParameters<Arguments> {
+class FormalParameters<Expression, Statement, Arguments> {
   final List<VariableDeclaration> required;
   final OptionalFormals optional;
   final int charOffset;
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index b644d94..92b3ac2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -10,90 +10,113 @@
 import '../constant_context.dart' show ConstantContext;
 
 import '../fasta_codes.dart'
-    show
-        LocatedMessage,
-        messageInvalidInitializer,
-        messageLoadLibraryTakesNoArguments,
-        messageSuperAsExpression,
-        templateDeferredTypeAnnotation,
-        templateIntegerLiteralIsOutOfRange,
-        templateNotAPrefixInTypeAnnotation,
-        templateNotAType,
-        templateUnresolvedPrefixInTypeAnnotation;
+    show LocatedMessage, messageInvalidInitializer, templateNotAType;
 
-import '../messages.dart' show Message, noLength;
+import '../names.dart' show lengthName;
 
-import '../names.dart'
-    show callName, equalsName, indexGetName, indexSetName, lengthName;
+import '../parser.dart' show lengthForToken, offsetForToken;
 
-import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
-
-import '../problems.dart' show unhandled, unsupported;
-
-import '../scope.dart' show AccessErrorBuilder;
-
-import 'body_builder.dart' show Identifier, noLocation;
-
-import 'constness.dart' show Constness;
+import '../problems.dart' show unsupported;
 
 import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
 
 import 'forest.dart' show Forest;
 
-import 'kernel_builder.dart' show LoadLibraryBuilder, PrefixBuilder;
-
-import 'kernel_api.dart' show NameSystem, printNodeOn, printQualifiedNameOn;
-
 import 'kernel_ast_api.dart'
     show
-        Constructor,
         DartType,
-        Field,
         Initializer,
         InvalidType,
-        Let,
         Member,
         Name,
         Procedure,
-        PropertySet,
-        ShadowComplexAssignment,
-        ShadowIllegalAssignment,
-        ShadowIndexAssign,
-        ShadowMethodInvocation,
-        ShadowNullAwarePropertyGet,
-        ShadowPropertyAssign,
-        ShadowPropertyGet,
-        ShadowStaticAssignment,
-        ShadowSuperMethodInvocation,
-        ShadowSuperPropertyGet,
-        ShadowVariableAssignment,
-        ShadowVariableDeclaration,
-        ShadowVariableGet,
-        StaticSet,
-        SuperMethodInvocation,
-        SuperPropertySet,
-        Throw,
-        TreeNode,
-        TypeParameter,
-        TypeParameterType,
-        VariableDeclaration,
-        VariableGet,
-        VariableSet;
+        VariableDeclaration;
 
-import 'kernel_ast_api.dart' as kernel show Expression, Node, Statement;
+import 'kernel_expression_generator.dart'
+    show IncompleteSendGenerator, SendAccessGenerator;
 
-import 'kernel_builder.dart'
+export 'kernel_expression_generator.dart'
     show
-        Builder,
-        BuiltinTypeBuilder,
-        FunctionTypeAliasBuilder,
-        KernelClassBuilder,
-        KernelFunctionTypeAliasBuilder,
-        KernelInvalidTypeBuilder,
-        KernelTypeVariableBuilder,
-        LoadLibraryBuilder,
-        PrefixBuilder,
-        TypeDeclarationBuilder;
+        DeferredAccessGenerator,
+        DelayedAssignment,
+        DelayedPostfixIncrement,
+        ErroneousExpressionGenerator,
+        IncompleteErrorGenerator,
+        IncompletePropertyAccessGenerator,
+        IncompleteSendGenerator,
+        LargeIntAccessGenerator,
+        LoadLibraryGenerator,
+        ParenthesizedExpressionGenerator,
+        ReadOnlyAccessGenerator,
+        SendAccessGenerator,
+        StaticAccessGenerator,
+        SuperIndexedAccessGenerator,
+        ThisAccessGenerator,
+        TypeDeclarationAccessGenerator,
+        UnresolvedNameGenerator,
+        buildIsNull;
+
+abstract class ExpressionGenerator<Expression, Statement, Arguments> {
+  /// Builds a [Expression] representing a read from the generator.
+  Expression buildSimpleRead();
+
+  /// Builds a [Expression] representing an assignment with the generator on
+  /// the LHS and [value] on the RHS.
+  ///
+  /// The returned expression evaluates to the assigned value, unless
+  /// [voidContext] is true, in which case it may evaluate to anything.
+  Expression buildAssignment(Expression value, {bool voidContext});
+
+  /// Returns a [Expression] representing a null-aware assignment (`??=`) with
+  /// the generator on the LHS and [value] on the RHS.
+  ///
+  /// The returned expression evaluates to the assigned value, unless
+  /// [voidContext] is true, in which case it may evaluate to anything.
+  ///
+  /// [type] is the static type of the RHS.
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext});
+
+  /// Returns a [Expression] representing a compound assignment (e.g. `+=`)
+  /// with the generator on the LHS and [value] on the RHS.
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset,
+      bool voidContext,
+      Procedure interfaceTarget,
+      bool isPreIncDec});
+
+  /// Returns a [Expression] representing a pre-increment or pre-decrement of
+  /// the generator.
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset, bool voidContext, Procedure interfaceTarget});
+
+  /// Returns a [Expression] representing a post-increment or post-decrement of
+  /// the generator.
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset, bool voidContext, Procedure interfaceTarget});
+
+  /// Returns a [Expression] representing a compile-time error.
+  ///
+  /// At runtime, an exception will be thrown.
+  Expression makeInvalidRead();
+
+  /// Returns a [Expression] representing a compile-time error wrapping
+  /// [value].
+  ///
+  /// At runtime, [value] will be evaluated before throwing an exception.
+  Expression makeInvalidWrite(Expression value);
+
+  /* Expression | Generator */ buildThrowNoSuchMethodError(
+      Expression receiver, Arguments arguments,
+      {bool isSuper,
+      bool isGetter,
+      bool isSetter,
+      bool isStatic,
+      String name,
+      int offset,
+      LocatedMessage argMessage});
+}
 
 /// A generator represents a subexpression for which we can't yet build an
 /// expression because we don't yet know the context in which it's used.
@@ -106,15 +129,15 @@
 /// generate an invocation of `operator[]` or `operator[]=`, so we create a
 /// [Generator] object.  Later, after `= b` is parsed, [buildAssignment] will
 /// be called.
-abstract class Generator<Arguments> {
-  final ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper;
+abstract class Generator<Expression, Statement, Arguments>
+    implements ExpressionGenerator<Expression, Statement, Arguments> {
+  final ExpressionGeneratorHelper<Expression, Statement, Arguments> helper;
+
   final Token token;
 
   Generator(this.helper, this.token);
 
-  // TODO(ahe): Change type arguments.
-  Forest<kernel.Expression, kernel.Statement, Token, Arguments> get forest =>
-      helper.forest;
+  Forest<Expression, Statement, Token, Arguments> get forest => helper.forest;
 
   String get plainNameForRead;
 
@@ -126,168 +149,12 @@
 
   bool get isInitializer => false;
 
-  /// Builds a [kernel.Expression] representing a read from the generator.
-  kernel.Expression buildSimpleRead() {
-    return _finish(_makeSimpleRead(), null);
-  }
-
-  /// Builds a [kernel.Expression] representing an assignment with the
-  /// generator on the LHS and [value] on the RHS.
-  ///
-  /// The returned expression evaluates to the assigned value, unless
-  /// [voidContext] is true, in which case it may evaluate to anything.
-  kernel.Expression buildAssignment(kernel.Expression value,
-      {bool voidContext: false}) {
-    var complexAssignment = startComplexAssignment(value);
-    return _finish(_makeSimpleWrite(value, voidContext, complexAssignment),
-        complexAssignment);
-  }
-
-  /// Returns a [kernel.Expression] representing a null-aware assignment
-  /// (`??=`) with the generator on the LHS and [value] on the RHS.
-  ///
-  /// The returned expression evaluates to the assigned value, unless
-  /// [voidContext] is true, in which case it may evaluate to anything.
-  ///
-  /// [type] is the static type of the RHS.
-  kernel.Expression buildNullAwareAssignment(
-      kernel.Expression value, DartType type, int offset,
-      {bool voidContext: false}) {
-    var complexAssignment = startComplexAssignment(value);
-    if (voidContext) {
-      var nullAwareCombiner = helper.storeOffset(
-          forest.conditionalExpression(
-              buildIsNull(_makeRead(complexAssignment), offset, helper),
-              null,
-              _makeWrite(value, false, complexAssignment),
-              null,
-              helper.storeOffset(forest.literalNull(null), offset)),
-          offset);
-      complexAssignment?.nullAwareCombiner = nullAwareCombiner;
-      return _finish(nullAwareCombiner, complexAssignment);
-    }
-    var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment));
-    var nullAwareCombiner = helper.storeOffset(
-        forest.conditionalExpression(
-            buildIsNull(new VariableGet(tmp), offset, helper),
-            null,
-            _makeWrite(value, false, complexAssignment),
-            null,
-            new VariableGet(tmp)),
-        offset);
-    complexAssignment?.nullAwareCombiner = nullAwareCombiner;
-    return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment);
-  }
-
-  /// Returns a [kernel.Expression] representing a compound assignment
-  /// (e.g. `+=`) with the generator on the LHS and [value] on the RHS.
-  kernel.Expression buildCompoundAssignment(
-      Name binaryOperator, kernel.Expression value,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget,
-      bool isPreIncDec: false}) {
-    var complexAssignment = startComplexAssignment(value);
-    complexAssignment?.isPreIncDec = isPreIncDec;
-    var combiner = makeBinary(_makeRead(complexAssignment), binaryOperator,
-        interfaceTarget, value, helper,
-        offset: offset);
-    complexAssignment?.combiner = combiner;
-    return _finish(_makeWrite(combiner, voidContext, complexAssignment),
-        complexAssignment);
-  }
-
-  /// Returns a [kernel.Expression] representing a pre-increment or
-  /// pre-decrement of the generator.
-  kernel.Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    return buildCompoundAssignment(
-        binaryOperator, helper.storeOffset(forest.literalInt(1, null), offset),
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPreIncDec: true);
-  }
-
-  /// Returns a [kernel.Expression] representing a post-increment or
-  /// post-decrement of the generator.
-  kernel.Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    if (voidContext) {
-      return buildPrefixIncrement(binaryOperator,
-          offset: offset, voidContext: true, interfaceTarget: interfaceTarget);
-    }
-    var rhs = helper.storeOffset(forest.literalInt(1, null), offset);
-    var complexAssignment = startComplexAssignment(rhs);
-    var value = new VariableDeclaration.forValue(_makeRead(complexAssignment));
-    valueAccess() => new VariableGet(value);
-    var combiner = makeBinary(
-        valueAccess(), binaryOperator, interfaceTarget, rhs, helper,
-        offset: offset);
-    complexAssignment?.combiner = combiner;
-    complexAssignment?.isPostIncDec = true;
-    var dummy = new ShadowVariableDeclaration.forValue(
-        _makeWrite(combiner, true, complexAssignment),
-        helper.functionNestingLevel);
-    return _finish(
-        makeLet(value, makeLet(dummy, valueAccess())), complexAssignment);
-  }
-
-  kernel.Expression _makeSimpleRead() => _makeRead(null);
-
-  kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return _makeWrite(value, voidContext, complexAssignment);
-  }
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment);
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment);
-
-  kernel.Expression _finish(
-      kernel.Expression body, ShadowComplexAssignment complexAssignment) {
-    if (complexAssignment != null) {
-      complexAssignment.desugared = body;
-      return complexAssignment;
-    } else {
-      return body;
-    }
-  }
-
-  /// Returns a [kernel.Expression] representing a compile-time error.
-  ///
-  /// At runtime, an exception will be thrown.
-  kernel.Expression makeInvalidRead() {
-    return buildThrowNoSuchMethodError(
-        forest.literalNull(token), forest.argumentsEmpty(noLocation),
-        isGetter: true);
-  }
-
-  /// Returns a [kernel.Expression] representing a compile-time error wrapping
-  /// [value].
-  ///
-  /// At runtime, [value] will be evaluated before throwing an exception.
-  kernel.Expression makeInvalidWrite(kernel.Expression value) {
-    return buildThrowNoSuchMethodError(forest.literalNull(token),
-        forest.arguments(<kernel.Expression>[value], noLocation),
-        isSetter: true);
-  }
-
-  /// Creates a data structure for tracking the desugaring of a complex
-  /// assignment expression whose right hand side is [rhs].
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowIllegalAssignment(rhs);
-
+  // TODO(ahe): Remove this method.
   T storeOffset<T>(T node, int offset) {
     return helper.storeOffset(node, offset);
   }
 
-  kernel.Expression buildForEffect() => buildSimpleRead();
+  Expression buildForEffect() => buildSimpleRead();
 
   Initializer buildFieldInitializer(Map<String, int> initializedFields) {
     int offset = offsetForToken(token);
@@ -303,8 +170,11 @@
   /* kernel.Expression | Generator */ buildPropertyAccess(
       IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
     if (send is SendAccessGenerator) {
-      return helper.buildMethodInvocation(buildSimpleRead(), send.name,
-          send.arguments, offsetForToken(send.token),
+      return helper.buildMethodInvocation(
+          buildSimpleRead(),
+          send.name,
+          send.arguments as dynamic /* TODO(ahe): Remove this cast. */,
+          offsetForToken(send.token),
           isNullAware: isNullAware);
     } else {
       if (helper.constantContext != ConstantContext.none &&
@@ -312,8 +182,14 @@
         helper.deprecated_addCompileTimeError(
             offsetForToken(token), "Not a constant expression.");
       }
-      return PropertyAccessGenerator.make(helper, send.token, buildSimpleRead(),
-          send.name, null, null, isNullAware);
+      return PropertyAccessGenerator.make<Expression, Statement, Arguments>(
+          helper,
+          send.token,
+          buildSimpleRead(),
+          send.name,
+          null,
+          null,
+          isNullAware);
     }
   }
 
@@ -324,8 +200,9 @@
     return const InvalidType();
   }
 
+  @override
   /* kernel.Expression | Generator */ buildThrowNoSuchMethodError(
-      kernel.Expression receiver, Arguments arguments,
+      Expression receiver, Arguments arguments,
       {bool isSuper: false,
       bool isGetter: false,
       bool isSetter: false,
@@ -357,447 +234,143 @@
   }
 }
 
-class VariableUseGenerator<Arguments> extends Generator<Arguments> {
-  final VariableDeclaration variable;
-
-  final DartType promotedType;
-
-  VariableUseGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class VariableUseGenerator<Expression, Statement, Arguments>
+    implements Generator<Expression, Statement, Arguments> {
+  factory VariableUseGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.variable,
-      [this.promotedType])
-      : super(helper, token);
+      VariableDeclaration variable,
+      [DartType promotedType]) {
+    return helper.forest
+        .variableUseGenerator(helper, token, variable, promotedType);
+  }
 
-  String get plainNameForRead => variable.name;
-
+  @override
   String get debugName => "VariableUseGenerator";
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    var fact = helper.typePromoter
-        .getFactForAccess(variable, helper.functionNestingLevel);
-    var scope = helper.typePromoter.currentScope;
-    var read = new ShadowVariableGet(variable, fact, scope)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel);
-    var write = variable.isFinal || variable.isConst
-        ? makeInvalidWrite(value)
-        : new VariableSet(variable, value)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  @override
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
-        adjustForImplicitCall(plainNameForRead, offset),
-        isImplicitCall: true);
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowVariableAssignment(rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", variable: ");
-    printNodeOn(variable, sink, syntheticNames: syntheticNames);
-    sink.write(", promotedType: ");
-    printNodeOn(promotedType, sink, syntheticNames: syntheticNames);
-  }
 }
 
-class PropertyAccessGenerator<Arguments> extends Generator<Arguments> {
-  final kernel.Expression receiver;
-
-  final Name name;
-
-  final Member getter;
-
-  final Member setter;
-
-  VariableDeclaration _receiverVariable;
-
-  PropertyAccessGenerator.internal(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class PropertyAccessGenerator<Expression, Statement, Arguments>
+    implements Generator<Expression, Statement, Arguments> {
+  factory PropertyAccessGenerator.internal(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.receiver,
-      this.name,
-      this.getter,
-      this.setter)
-      : super(helper, token);
-
-  static Generator<Arguments> make<Arguments>(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      kernel.Expression receiver,
+      Expression receiver,
       Name name,
       Member getter,
-      Member setter,
-      bool isNullAware) {
+      Member setter) {
+    return helper.forest
+        .propertyAccessGenerator(helper, token, receiver, name, getter, setter);
+  }
+
+  static Generator<Expression, Statement, Arguments>
+      make<Expression, Statement, Arguments>(
+          ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+          Token token,
+          Expression receiver,
+          Name name,
+          Member getter,
+          Member setter,
+          bool isNullAware) {
     if (helper.forest.isThisExpression(receiver)) {
       return unsupported("ThisExpression", offsetForToken(token), helper.uri);
     } else {
       return isNullAware
           ? new NullAwarePropertyAccessGenerator(
-              helper, token, receiver, name, getter, setter, null)
+              helper,
+              token,
+              receiver as dynamic /* TODO(ahe): Remove this cast. */,
+              name,
+              getter,
+              setter,
+              null)
           : new PropertyAccessGenerator.internal(
               helper, token, receiver, name, getter, setter);
     }
   }
 
-  String get plainNameForRead => name.name;
-
+  @override
   String get debugName => "PropertyAccessGenerator";
 
-  bool get isThisPropertyAccess => forest.isThisExpression(receiver);
-
-  kernel.Expression _makeSimpleRead() =>
-      new ShadowPropertyGet(receiver, name, getter)
-        ..fileOffset = offsetForToken(token);
-
-  kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    var write = new PropertySet(receiver, name, value, setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  receiverAccess() {
-    _receiverVariable ??= new VariableDeclaration.forValue(receiver);
-    return new VariableGet(_receiverVariable)
-      ..fileOffset = offsetForToken(token);
-  }
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    var read = new ShadowPropertyGet(receiverAccess(), name, getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    var write = new PropertySet(receiverAccess(), name, value, setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  kernel.Expression _finish(
-      kernel.Expression body, ShadowComplexAssignment complexAssignment) {
-    return super._finish(makeLet(_receiverVariable, body), complexAssignment);
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildMethodInvocation(receiver, name, arguments, offset);
-  }
-
   @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowPropertyAssign(receiver, rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", _receiverVariable: ");
-    printNodeOn(_receiverVariable, sink, syntheticNames: syntheticNames);
-    sink.write(", receiver: ");
-    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
-    sink.write(", name: ");
-    sink.write(name.name);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-  }
+  bool get isThisPropertyAccess => false;
 }
 
 /// Special case of [PropertyAccessGenerator] to avoid creating an indirect
 /// access to 'this'.
-class ThisPropertyAccessGenerator<Arguments> extends Generator<Arguments> {
-  final Name name;
-
-  final Member getter;
-
-  final Member setter;
-
-  ThisPropertyAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class ThisPropertyAccessGenerator<Expression, Statement, Arguments>
+    implements Generator<Expression, Statement, Arguments> {
+  factory ThisPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.name,
-      this.getter,
-      this.setter)
-      : super(helper, token);
+      Name name,
+      Member getter,
+      Member setter) {
+    return helper.forest
+        .thisPropertyAccessGenerator(helper, token, name, getter, setter);
+  }
 
-  String get plainNameForRead => name.name;
-
+  @override
   String get debugName => "ThisPropertyAccessGenerator";
 
+  @override
   bool get isThisPropertyAccess => true;
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    if (getter == null) {
-      helper.warnUnresolvedGet(name, offsetForToken(token));
-    }
-    var read = new ShadowPropertyGet(forest.thisExpression(token), name, getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (setter == null) {
-      helper.warnUnresolvedSet(name, offsetForToken(token));
-    }
-    var write =
-        new PropertySet(forest.thisExpression(token), name, value, setter)
-          ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    Member interfaceTarget = getter;
-    if (interfaceTarget == null) {
-      helper.warnUnresolvedMethod(name, offset);
-    }
-    if (interfaceTarget is Field) {
-      // TODO(ahe): In strong mode we should probably rewrite this to
-      // `this.name.call(arguments)`.
-      interfaceTarget = null;
-    }
-    return helper.buildMethodInvocation(
-        forest.thisExpression(null), name, arguments, offset,
-        interfaceTarget: interfaceTarget);
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowPropertyAssign(null, rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", name: ");
-    sink.write(name.name);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-  }
 }
 
-class NullAwarePropertyAccessGenerator<Arguments> extends Generator<Arguments> {
-  final VariableDeclaration receiver;
-
-  final kernel.Expression receiverExpression;
-
-  final Name name;
-
-  final Member getter;
-
-  final Member setter;
-
-  final DartType type;
-
-  NullAwarePropertyAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class NullAwarePropertyAccessGenerator<Expression, Statement,
+    Arguments> implements Generator<Expression, Statement, Arguments> {
+  factory NullAwarePropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.receiverExpression,
-      this.name,
-      this.getter,
-      this.setter,
-      this.type)
-      : this.receiver = makeOrReuseVariable(receiverExpression),
-        super(helper, token);
+      Expression receiverExpression,
+      Name name,
+      Member getter,
+      Member setter,
+      DartType type) {
+    return helper.forest.nullAwarePropertyAccessGenerator(
+        helper, token, receiverExpression, name, getter, setter, type);
+  }
 
-  String get plainNameForRead => name.name;
-
+  @override
   String get debugName => "NullAwarePropertyAccessGenerator";
-
-  kernel.Expression receiverAccess() => new VariableGet(receiver);
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    var read = new ShadowPropertyGet(receiverAccess(), name, getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    var write = new PropertySet(receiverAccess(), name, value, setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  kernel.Expression _finish(
-      kernel.Expression body, ShadowComplexAssignment complexAssignment) {
-    var offset = offsetForToken(token);
-    var nullAwareGuard = helper.storeOffset(
-        forest.conditionalExpression(
-            buildIsNull(receiverAccess(), offset, helper),
-            null,
-            helper.storeOffset(forest.literalNull(null), offset),
-            null,
-            body),
-        offset);
-    if (complexAssignment != null) {
-      body = makeLet(receiver, nullAwareGuard);
-      ShadowPropertyAssign kernelPropertyAssign = complexAssignment;
-      kernelPropertyAssign.nullAwareGuard = nullAwareGuard;
-      kernelPropertyAssign.desugared = body;
-      return kernelPropertyAssign;
-    } else {
-      return new ShadowNullAwarePropertyGet(receiver, nullAwareGuard)
-        ..fileOffset = offset;
-    }
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return unsupported("doInvocation", offset, uri);
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowPropertyAssign(receiverExpression, rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", receiver: ");
-    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
-    sink.write(", receiverExpression: ");
-    printNodeOn(receiverExpression, sink, syntheticNames: syntheticNames);
-    sink.write(", name: ");
-    sink.write(name.name);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-    sink.write(", type: ");
-    printNodeOn(type, sink, syntheticNames: syntheticNames);
-  }
 }
 
-class SuperPropertyAccessGenerator<Arguments> extends Generator<Arguments> {
-  final Name name;
-
-  final Member getter;
-
-  final Member setter;
-
-  SuperPropertyAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class SuperPropertyAccessGenerator<Expression, Statement, Arguments>
+    implements Generator<Expression, Statement, Arguments> {
+  factory SuperPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.name,
-      this.getter,
-      this.setter)
-      : super(helper, token);
+      Name name,
+      Member getter,
+      Member setter) {
+    return helper.forest
+        .superPropertyAccessGenerator(helper, token, name, getter, setter);
+  }
 
-  String get plainNameForRead => name.name;
-
+  @override
   String get debugName => "SuperPropertyAccessGenerator";
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    if (getter == null) {
-      helper.warnUnresolvedGet(name, offsetForToken(token), isSuper: true);
-    }
-    // TODO(ahe): Use [DirectPropertyGet] when possible.
-    var read = new ShadowSuperPropertyGet(name, getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (setter == null) {
-      helper.warnUnresolvedSet(name, offsetForToken(token), isSuper: true);
-    }
-    // TODO(ahe): Use [DirectPropertySet] when possible.
-    var write = new SuperPropertySet(name, value, setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    if (helper.constantContext != ConstantContext.none) {
-      helper.deprecated_addCompileTimeError(
-          offset, "Not a constant expression.");
-    }
-    if (getter == null || isFieldOrGetter(getter)) {
-      return helper.buildMethodInvocation(
-          buildSimpleRead(), callName, arguments, offset,
-          // This isn't a constant expression, but we have checked if a
-          // constant expression error should be emitted already.
-          isConstantExpression: true,
-          isImplicitCall: true);
-    } else {
-      // TODO(ahe): This could be something like "super.property(...)" where
-      // property is a setter.
-      return unhandled("${getter.runtimeType}", "doInvocation", offset, uri);
-    }
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowPropertyAssign(null, rhs, isSuper: true);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", name: ");
-    sink.write(name.name);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-  }
 }
 
-class IndexedAccessGenerator<Arguments> extends Generator<Arguments> {
-  final kernel.Expression receiver;
-
-  final kernel.Expression index;
-
-  final Procedure getter;
-
-  final Procedure setter;
-
-  VariableDeclaration receiverVariable;
-
-  VariableDeclaration indexVariable;
-
-  IndexedAccessGenerator.internal(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class IndexedAccessGenerator<Expression, Statement, Arguments>
+    implements Generator<Expression, Statement, Arguments> {
+  factory IndexedAccessGenerator.internal(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.receiver,
-      this.index,
-      this.getter,
-      this.setter)
-      : super(helper, token);
-
-  static Generator<Arguments> make<Arguments>(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      kernel.Expression receiver,
-      kernel.Expression index,
+      Expression receiver,
+      Expression index,
       Procedure getter,
       Procedure setter) {
+    return helper.forest
+        .indexedAccessGenerator(helper, token, receiver, index, getter, setter);
+  }
+
+  static Generator<Expression, Statement, Arguments>
+      make<Expression, Statement, Arguments>(
+          ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+          Token token,
+          Expression receiver,
+          Expression index,
+          Procedure getter,
+          Procedure setter) {
     if (helper.forest.isThisExpression(receiver)) {
       return new ThisIndexedAccessGenerator(
           helper, token, index, getter, setter);
@@ -807,1525 +380,36 @@
     }
   }
 
+  @override
   String get plainNameForRead => "[]";
 
+  @override
   String get plainNameForWrite => "[]=";
 
+  @override
   String get debugName => "IndexedAccessGenerator";
-
-  kernel.Expression _makeSimpleRead() {
-    var read = new ShadowMethodInvocation(
-        receiver,
-        indexGetName,
-        forest
-            .castArguments(forest.arguments(<kernel.Expression>[index], token)),
-        interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
-    return read;
-  }
-
-  kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
-    var write = new ShadowMethodInvocation(
-        receiver,
-        indexSetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[index, value], token)),
-        interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  receiverAccess() {
-    // We cannot reuse the receiver if it is a variable since it might be
-    // reassigned in the index expression.
-    receiverVariable ??= new VariableDeclaration.forValue(receiver);
-    return new VariableGet(receiverVariable)
-      ..fileOffset = offsetForToken(token);
-  }
-
-  indexAccess() {
-    indexVariable ??= new VariableDeclaration.forValue(index);
-    return new VariableGet(indexVariable)..fileOffset = offsetForToken(token);
-  }
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    var read = new ShadowMethodInvocation(
-        receiverAccess(),
-        indexGetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[indexAccess()], token)),
-        interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
-    var write = new ShadowMethodInvocation(
-        receiverAccess(),
-        indexSetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[indexAccess(), value], token)),
-        interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  // TODO(dmitryas): remove this method after the "[]=" operator of the Context
-  // class is made to return a value.
-  _makeWriteAndReturn(
-      kernel.Expression value, ShadowComplexAssignment complexAssignment) {
-    // The call to []= does not return the value like direct-style assignments
-    // do.  We need to bind the value in a let.
-    var valueVariable = new VariableDeclaration.forValue(value);
-    var write = new ShadowMethodInvocation(
-        receiverAccess(),
-        indexSetName,
-        forest.castArguments(forest.arguments(
-            <kernel.Expression>[indexAccess(), new VariableGet(valueVariable)],
-            token)),
-        interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    var dummy = new ShadowVariableDeclaration.forValue(
-        write, helper.functionNestingLevel);
-    return makeLet(
-        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
-  }
-
-  kernel.Expression _finish(
-      kernel.Expression body, ShadowComplexAssignment complexAssignment) {
-    return super._finish(
-        makeLet(receiverVariable, makeLet(indexVariable, body)),
-        complexAssignment);
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildMethodInvocation(
-        buildSimpleRead(), callName, arguments, forest.readOffset(arguments),
-        isImplicitCall: true);
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowIndexAssign(receiver, index, rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", receiver: ");
-    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
-    sink.write(", index: ");
-    printNodeOn(index, sink, syntheticNames: syntheticNames);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-    sink.write(", receiverVariable: ");
-    printNodeOn(receiverVariable, sink, syntheticNames: syntheticNames);
-    sink.write(", indexVariable: ");
-    printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
-  }
 }
 
 /// Special case of [IndexedAccessGenerator] to avoid creating an indirect
 /// access to 'this'.
-class ThisIndexedAccessGenerator<Arguments> extends Generator<Arguments> {
-  final kernel.Expression index;
-
-  final Procedure getter;
-
-  final Procedure setter;
-
-  VariableDeclaration indexVariable;
-
-  ThisIndexedAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class ThisIndexedAccessGenerator<Expression, Statement, Arguments>
+    implements Generator<Expression, Statement, Arguments> {
+  factory ThisIndexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
       Token token,
-      this.index,
-      this.getter,
-      this.setter)
-      : super(helper, token);
+      Expression index,
+      Procedure getter,
+      Procedure setter) {
+    return helper.forest
+        .thisIndexedAccessGenerator(helper, token, index, getter, setter);
+  }
 
+  @override
   String get plainNameForRead => "[]";
 
+  @override
   String get plainNameForWrite => "[]=";
 
+  @override
   String get debugName => "ThisIndexedAccessGenerator";
-
-  kernel.Expression _makeSimpleRead() {
-    return new ShadowMethodInvocation(
-        forest.thisExpression(token),
-        indexGetName,
-        forest
-            .castArguments(forest.arguments(<kernel.Expression>[index], token)),
-        interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
-  }
-
-  kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
-    var write = new ShadowMethodInvocation(
-        forest.thisExpression(token),
-        indexSetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[index, value], token)),
-        interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  indexAccess() {
-    indexVariable ??= new VariableDeclaration.forValue(index);
-    return new VariableGet(indexVariable);
-  }
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    var read = new ShadowMethodInvocation(
-        forest.thisExpression(token),
-        indexGetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[indexAccess()], token)),
-        interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
-    var write = new ShadowMethodInvocation(
-        forest.thisExpression(token),
-        indexSetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[indexAccess(), value], token)),
-        interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  _makeWriteAndReturn(
-      kernel.Expression value, ShadowComplexAssignment complexAssignment) {
-    var valueVariable = new VariableDeclaration.forValue(value);
-    var write = new ShadowMethodInvocation(
-        forest.thisExpression(token),
-        indexSetName,
-        forest.castArguments(forest.arguments(
-            <kernel.Expression>[indexAccess(), new VariableGet(valueVariable)],
-            token)),
-        interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    var dummy = new VariableDeclaration.forValue(write);
-    return makeLet(
-        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
-  }
-
-  kernel.Expression _finish(
-      kernel.Expression body, ShadowComplexAssignment complexAssignment) {
-    return super._finish(makeLet(indexVariable, body), complexAssignment);
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildMethodInvocation(
-        buildSimpleRead(), callName, arguments, offset,
-        isImplicitCall: true);
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowIndexAssign(null, index, rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", index: ");
-    printNodeOn(index, sink, syntheticNames: syntheticNames);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-    sink.write(", indexVariable: ");
-    printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
-  }
-}
-
-class SuperIndexedAccessGenerator<Arguments> extends Generator<Arguments> {
-  final kernel.Expression index;
-
-  final Member getter;
-
-  final Member setter;
-
-  VariableDeclaration indexVariable;
-
-  SuperIndexedAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.index,
-      this.getter,
-      this.setter)
-      : super(helper, token);
-
-  String get plainNameForRead => "[]";
-
-  String get plainNameForWrite => "[]=";
-
-  String get debugName => "SuperIndexedAccessGenerator";
-
-  indexAccess() {
-    indexVariable ??= new VariableDeclaration.forValue(index);
-    return new VariableGet(indexVariable);
-  }
-
-  kernel.Expression _makeSimpleRead() {
-    if (getter == null) {
-      helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
-          isSuper: true);
-    }
-    // TODO(ahe): Use [DirectMethodInvocation] when possible.
-    return new ShadowSuperMethodInvocation(
-        indexGetName,
-        forest
-            .castArguments(forest.arguments(<kernel.Expression>[index], token)),
-        getter)
-      ..fileOffset = offsetForToken(token);
-  }
-
-  kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
-    if (setter == null) {
-      helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
-          isSuper: true);
-    }
-    var write = new SuperMethodInvocation(
-        indexSetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[index, value], token)),
-        setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    if (getter == null) {
-      helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
-          isSuper: true);
-    }
-    var read = new SuperMethodInvocation(
-        indexGetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[indexAccess()], token)),
-        getter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
-    if (setter == null) {
-      helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
-          isSuper: true);
-    }
-    var write = new SuperMethodInvocation(
-        indexSetName,
-        forest.castArguments(
-            forest.arguments(<kernel.Expression>[indexAccess(), value], token)),
-        setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  _makeWriteAndReturn(
-      kernel.Expression value, ShadowComplexAssignment complexAssignment) {
-    var valueVariable = new VariableDeclaration.forValue(value);
-    if (setter == null) {
-      helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
-          isSuper: true);
-    }
-    var write = new SuperMethodInvocation(
-        indexSetName,
-        forest.castArguments(forest.arguments(
-            <kernel.Expression>[indexAccess(), new VariableGet(valueVariable)],
-            token)),
-        setter)
-      ..fileOffset = offsetForToken(token);
-    complexAssignment?.write = write;
-    var dummy = new VariableDeclaration.forValue(write);
-    return makeLet(
-        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
-  }
-
-  kernel.Expression _finish(
-      kernel.Expression body, ShadowComplexAssignment complexAssignment) {
-    return super._finish(makeLet(indexVariable, body), complexAssignment);
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildMethodInvocation(
-        buildSimpleRead(), callName, arguments, offset,
-        isImplicitCall: true);
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowIndexAssign(null, index, rhs, isSuper: true);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", index: ");
-    printNodeOn(index, sink, syntheticNames: syntheticNames);
-    sink.write(", getter: ");
-    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
-    sink.write(", setter: ");
-    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
-    sink.write(", indexVariable: ");
-    printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
-  }
-}
-
-class StaticAccessGenerator<Arguments> extends Generator<Arguments> {
-  final Member readTarget;
-
-  final Member writeTarget;
-
-  StaticAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.readTarget,
-      this.writeTarget)
-      : assert(readTarget != null || writeTarget != null),
-        super(helper, token);
-
-  factory StaticAccessGenerator.fromBuilder(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Builder builder,
-      Token token,
-      Builder builderSetter) {
-    if (builder is AccessErrorBuilder) {
-      AccessErrorBuilder error = builder;
-      builder = error.builder;
-      // We should only see an access error here if we've looked up a setter
-      // when not explicitly looking for a setter.
-      assert(builder.isSetter);
-    } else if (builder.target == null) {
-      return unhandled(
-          "${builder.runtimeType}",
-          "StaticAccessGenerator.fromBuilder",
-          offsetForToken(token),
-          helper.uri);
-    }
-    Member getter = builder.target.hasGetter ? builder.target : null;
-    Member setter = builder.target.hasSetter ? builder.target : null;
-    if (setter == null) {
-      if (builderSetter?.target?.hasSetter ?? false) {
-        setter = builderSetter.target;
-      }
-    }
-    return new StaticAccessGenerator(helper, token, getter, setter);
-  }
-
-  String get plainNameForRead => (readTarget ?? writeTarget).name.name;
-
-  String get debugName => "StaticAccessGenerator";
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    if (readTarget == null) {
-      return makeInvalidRead();
-    } else {
-      var read = helper.makeStaticGet(readTarget, token);
-      complexAssignment?.read = read;
-      return read;
-    }
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    kernel.Expression write;
-    if (writeTarget == null) {
-      write = makeInvalidWrite(value);
-    } else {
-      write = new StaticSet(writeTarget, value);
-      complexAssignment?.write = write;
-    }
-    write.fileOffset = offsetForToken(token);
-    return write;
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    if (helper.constantContext != ConstantContext.none &&
-        !helper.isIdentical(readTarget)) {
-      helper.deprecated_addCompileTimeError(
-          offset, "Not a constant expression.");
-    }
-    if (readTarget == null || isFieldOrGetter(readTarget)) {
-      return helper.buildMethodInvocation(buildSimpleRead(), callName,
-          arguments, offset + (readTarget?.name?.name?.length ?? 0),
-          // This isn't a constant expression, but we have checked if a
-          // constant expression error should be emitted already.
-          isConstantExpression: true,
-          isImplicitCall: true);
-    } else {
-      return helper.buildStaticInvocation(readTarget, arguments,
-          charOffset: offset);
-    }
-  }
-
-  @override
-  ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
-      new ShadowStaticAssignment(rhs);
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", readTarget: ");
-    printQualifiedNameOn(readTarget, sink, syntheticNames: syntheticNames);
-    sink.write(", writeTarget: ");
-    printQualifiedNameOn(writeTarget, sink, syntheticNames: syntheticNames);
-  }
-}
-
-class LoadLibraryGenerator<Arguments> extends Generator<Arguments> {
-  final LoadLibraryBuilder builder;
-
-  LoadLibraryGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.builder)
-      : super(helper, token);
-
-  String get plainNameForRead => 'loadLibrary';
-
-  String get debugName => "LoadLibraryGenerator";
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    var read =
-        helper.makeStaticGet(builder.createTearoffMethod(helper.forest), token);
-    complexAssignment?.read = read;
-    return read;
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    kernel.Expression write = makeInvalidWrite(value);
-    write.fileOffset = offsetForToken(token);
-    return write;
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    if (forest.argumentsPositional(arguments).length > 0 ||
-        forest.argumentsNamed(arguments).length > 0) {
-      helper.addProblemErrorIfConst(
-          messageLoadLibraryTakesNoArguments, offset, 'loadLibrary'.length);
-    }
-    return builder.createLoadLibrary(offset, forest);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", builder: ");
-    sink.write(builder);
-  }
-}
-
-class DeferredAccessGenerator<Arguments> extends Generator<Arguments> {
-  final PrefixBuilder builder;
-
-  final Generator generator;
-
-  DeferredAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.builder,
-      this.generator)
-      : super(helper, token);
-
-  String get plainNameForRead {
-    return unsupported(
-        "deferredAccessor.plainNameForRead", offsetForToken(token), uri);
-  }
-
-  String get debugName => "DeferredAccessGenerator";
-
-  kernel.Expression _makeSimpleRead() {
-    return helper.wrapInDeferredCheck(
-        generator._makeSimpleRead(), builder, token.charOffset);
-  }
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    return helper.wrapInDeferredCheck(
-        generator._makeRead(complexAssignment), builder, token.charOffset);
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return helper.wrapInDeferredCheck(
-        generator._makeWrite(value, voidContext, complexAssignment),
-        builder,
-        token.charOffset);
-  }
-
-  buildPropertyAccess(
-      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
-    var propertyAccess =
-        generator.buildPropertyAccess(send, operatorOffset, isNullAware);
-    if (propertyAccess is Generator) {
-      return new DeferredAccessGenerator(
-          helper, token, builder, propertyAccess);
-    } else {
-      kernel.Expression expression = propertyAccess;
-      return helper.wrapInDeferredCheck(expression, builder, token.charOffset);
-    }
-  }
-
-  @override
-  DartType buildTypeWithBuiltArguments(List<DartType> arguments,
-      {bool nonInstanceAccessIsError: false}) {
-    helper.addProblem(
-        templateDeferredTypeAnnotation.withArguments(
-            generator.buildTypeWithBuiltArguments(arguments,
-                nonInstanceAccessIsError: nonInstanceAccessIsError),
-            builder.name),
-        offsetForToken(token),
-        lengthForToken(token));
-    return const InvalidType();
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.wrapInDeferredCheck(
-        generator.doInvocation(offset, arguments), builder, token.charOffset);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", builder: ");
-    sink.write(builder);
-    sink.write(", generator: ");
-    sink.write(generator);
-  }
-}
-
-class ReadOnlyAccessGenerator<Arguments> extends Generator<Arguments> {
-  final String plainNameForRead;
-
-  kernel.Expression expression;
-
-  VariableDeclaration value;
-
-  ReadOnlyAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.expression,
-      this.plainNameForRead)
-      : super(helper, token);
-
-  String get debugName => "ReadOnlyAccessGenerator";
-
-  kernel.Expression _makeSimpleRead() => expression;
-
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    value ??= new VariableDeclaration.forValue(expression);
-    return new VariableGet(value);
-  }
-
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    var write = makeInvalidWrite(value);
-    complexAssignment?.write = write;
-    return write;
-  }
-
-  kernel.Expression _finish(
-          kernel.Expression body, ShadowComplexAssignment complexAssignment) =>
-      super._finish(makeLet(value, body), complexAssignment);
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
-        adjustForImplicitCall(plainNameForRead, offset),
-        isImplicitCall: true);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    NameSystem syntheticNames = new NameSystem();
-    sink.write(", expression: ");
-    printNodeOn(expression, sink, syntheticNames: syntheticNames);
-    sink.write(", plainNameForRead: ");
-    sink.write(plainNameForRead);
-    sink.write(", value: ");
-    printNodeOn(value, sink, syntheticNames: syntheticNames);
-  }
-}
-
-class LargeIntAccessGenerator<Arguments> extends Generator<Arguments> {
-  LargeIntAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token)
-      : super(helper, token);
-
-  // TODO(ahe): This should probably be calling unhandled.
-  String get plainNameForRead => null;
-
-  String get debugName => "LargeIntAccessGenerator";
-
-  @override
-  kernel.Expression _makeSimpleRead() => buildError();
-
-  @override
-  kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return buildError();
-  }
-
-  @override
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    return buildError();
-  }
-
-  @override
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return buildError();
-  }
-
-  kernel.Expression buildError() {
-    return helper.buildCompileTimeError(
-        templateIntegerLiteralIsOutOfRange.withArguments(token),
-        offsetForToken(token),
-        lengthForToken(token));
-  }
-
-  @override
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return buildError();
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", lexeme: ");
-    sink.write(token.lexeme);
-  }
-}
-
-abstract class ErroneousExpressionGenerator<Arguments>
-    implements Generator<Arguments> {
-  /// Pass [arguments] that must be evaluated before throwing an error.  At
-  /// most one of [isGetter] and [isSetter] should be true and they're passed
-  /// to [ExpressionGeneratorHelper.buildThrowNoSuchMethodError] if it is used.
-  kernel.Expression buildError(Arguments arguments,
-      {bool isGetter: false, bool isSetter: false, int offset});
-
-  DartType buildErroneousTypeNotAPrefix(Identifier suffix);
-
-  Name get name => unsupported("name", offsetForToken(token), uri);
-
-  @override
-  String get plainNameForRead => name.name;
-
-  withReceiver(Object receiver, int operatorOffset, {bool isNullAware}) => this;
-
-  @override
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    return helper.buildInvalidInitializer(
-        buildError(forest.argumentsEmpty(noLocation), isSetter: true));
-  }
-
-  @override
-  doInvocation(int offset, Arguments arguments) {
-    return buildError(arguments, offset: offset);
-  }
-
-  @override
-  buildPropertyAccess(
-      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
-    return this;
-  }
-
-  @override
-  buildThrowNoSuchMethodError(kernel.Expression receiver, Arguments arguments,
-      {bool isSuper: false,
-      bool isGetter: false,
-      bool isSetter: false,
-      bool isStatic: false,
-      String name,
-      int offset,
-      LocatedMessage argMessage}) {
-    return this;
-  }
-
-  @override
-  kernel.Expression buildAssignment(kernel.Expression value,
-      {bool voidContext: false}) {
-    return buildError(forest.arguments(<kernel.Expression>[value], noLocation),
-        isSetter: true);
-  }
-
-  @override
-  kernel.Expression buildCompoundAssignment(
-      Name binaryOperator, kernel.Expression value,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget,
-      bool isPreIncDec: false}) {
-    return buildError(forest.arguments(<kernel.Expression>[value], token),
-        isGetter: true);
-  }
-
-  @override
-  kernel.Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    // TODO(ahe): For the Analyzer, we probably need to build a prefix
-    // increment node that wraps an error.
-    return buildError(
-        forest.arguments(<kernel.Expression>[
-          storeOffset(forest.literalInt(1, null), offset)
-        ], noLocation),
-        isGetter: true);
-  }
-
-  @override
-  kernel.Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    // TODO(ahe): For the Analyzer, we probably need to build a post increment
-    // node that wraps an error.
-    return buildError(
-        forest.arguments(<kernel.Expression>[
-          storeOffset(forest.literalInt(1, null), offset)
-        ], noLocation),
-        isGetter: true);
-  }
-
-  @override
-  kernel.Expression buildNullAwareAssignment(
-      kernel.Expression value, DartType type, int offset,
-      {bool voidContext: false}) {
-    return buildError(forest.arguments(<kernel.Expression>[value], noLocation),
-        isSetter: true);
-  }
-
-  @override
-  kernel.Expression buildSimpleRead() =>
-      buildError(forest.argumentsEmpty(noLocation), isGetter: true);
-
-  @override
-  kernel.Expression makeInvalidRead() =>
-      buildError(forest.argumentsEmpty(noLocation), isGetter: true);
-
-  @override
-  kernel.Expression makeInvalidWrite(kernel.Expression value) {
-    return buildError(forest.arguments(<kernel.Expression>[value], noLocation),
-        isSetter: true);
-  }
-}
-
-class ThisAccessGenerator<Arguments> extends Generator<Arguments> {
-  final bool isInitializer;
-
-  final bool isSuper;
-
-  ThisAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.isInitializer,
-      {this.isSuper: false})
-      : super(helper, token);
-
-  String get plainNameForRead {
-    return unsupported("${isSuper ? 'super' : 'this'}.plainNameForRead",
-        offsetForToken(token), uri);
-  }
-
-  String get debugName => "ThisAccessGenerator";
-
-  kernel.Expression buildSimpleRead() {
-    if (!isSuper) {
-      return forest.thisExpression(token);
-    } else {
-      return helper.buildCompileTimeError(messageSuperAsExpression,
-          offsetForToken(token), lengthForToken(token));
-    }
-  }
-
-  @override
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    String keyword = isSuper ? "super" : "this";
-    int offset = offsetForToken(token);
-    return helper.buildInvalidInitializer(
-        helper.deprecated_buildCompileTimeError(
-            "Can't use '$keyword' here, did you mean '$keyword()'?", offset),
-        offset);
-  }
-
-  buildPropertyAccess(
-      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
-    Name name = send.name;
-    Arguments arguments = send.arguments;
-    int offset = offsetForToken(send.token);
-    if (isInitializer && send is SendAccessGenerator) {
-      if (isNullAware) {
-        helper.deprecated_addCompileTimeError(
-            operatorOffset, "Expected '.'\nTry removing '?'.");
-      }
-      return buildConstructorInitializer(offset, name, arguments);
-    }
-    Member getter = helper.lookupInstanceMember(name, isSuper: isSuper);
-    if (send is SendAccessGenerator) {
-      // Notice that 'this' or 'super' can't be null. So we can ignore the
-      // value of [isNullAware].
-      if (getter == null) {
-        helper.warnUnresolvedMethod(name, offsetForToken(send.token),
-            isSuper: isSuper);
-      }
-      return helper.buildMethodInvocation(forest.thisExpression(null), name,
-          send.arguments, offsetForToken(send.token),
-          isSuper: isSuper, interfaceTarget: getter);
-    } else {
-      Member setter =
-          helper.lookupInstanceMember(name, isSuper: isSuper, isSetter: true);
-      if (isSuper) {
-        return new SuperPropertyAccessGenerator(
-            helper, send.token, name, getter, setter);
-      } else {
-        return new ThisPropertyAccessGenerator(
-            helper, send.token, name, getter, setter);
-      }
-    }
-  }
-
-  doInvocation(int offset, Arguments arguments) {
-    if (isInitializer) {
-      return buildConstructorInitializer(offset, new Name(""), arguments);
-    } else if (isSuper) {
-      return helper.buildCompileTimeError(
-          messageSuperAsExpression, offset, noLength);
-    } else {
-      return helper.buildMethodInvocation(
-          forest.thisExpression(null), callName, arguments, offset,
-          isImplicitCall: true);
-    }
-  }
-
-  Initializer buildConstructorInitializer(
-      int offset, Name name, Arguments arguments) {
-    Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper);
-    LocatedMessage argMessage;
-    if (constructor != null) {
-      argMessage = helper.checkArgumentsForFunction(
-          constructor.function, arguments, offset, <TypeParameter>[]);
-    }
-    if (constructor == null || argMessage != null) {
-      return helper.buildInvalidInitializer(
-          buildThrowNoSuchMethodError(
-              storeOffset(forest.literalNull(null), offset), arguments,
-              isSuper: isSuper,
-              name: name.name,
-              offset: offset,
-              argMessage: argMessage),
-          offset);
-    } else if (isSuper) {
-      return helper.buildSuperInitializer(
-          false, constructor, arguments, offset);
-    } else {
-      return helper.buildRedirectingInitializer(constructor, arguments, offset);
-    }
-  }
-
-  kernel.Expression buildAssignment(kernel.Expression value,
-      {bool voidContext: false}) {
-    return buildAssignmentError();
-  }
-
-  kernel.Expression buildNullAwareAssignment(
-      kernel.Expression value, DartType type, int offset,
-      {bool voidContext: false}) {
-    return buildAssignmentError();
-  }
-
-  kernel.Expression buildCompoundAssignment(
-      Name binaryOperator, kernel.Expression value,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget,
-      bool isPreIncDec: false}) {
-    return buildAssignmentError();
-  }
-
-  kernel.Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    return buildAssignmentError();
-  }
-
-  kernel.Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
-    return buildAssignmentError();
-  }
-
-  kernel.Expression buildAssignmentError() {
-    String message =
-        isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'.";
-    return helper.deprecated_buildCompileTimeError(
-        message, offsetForToken(token));
-  }
-
-  @override
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    return unsupported("_makeRead", offsetForToken(token), uri);
-  }
-
-  @override
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return unsupported("_makeWrite", offsetForToken(token), uri);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", isInitializer: ");
-    sink.write(isInitializer);
-    sink.write(", isSuper: ");
-    sink.write(isSuper);
-  }
-}
-
-abstract class IncompleteSendGenerator<Arguments> extends Generator<Arguments> {
-  final Name name;
-
-  IncompleteSendGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.name)
-      : super(helper, token);
-
-  withReceiver(Object receiver, int operatorOffset, {bool isNullAware});
-
-  Arguments get arguments => null;
-
-  @override
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    return unsupported("_makeRead", offsetForToken(token), uri);
-  }
-
-  @override
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return unsupported("_makeWrite", offsetForToken(token), uri);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", name: ");
-    sink.write(name.name);
-  }
-}
-
-class UnresolvedNameGenerator<Arguments> extends Generator<Arguments>
-    with ErroneousExpressionGenerator<Arguments> {
-  @override
-  final Name name;
-
-  UnresolvedNameGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.name)
-      : super(helper, token);
-
-  String get debugName => "UnresolvedNameGenerator";
-
-  kernel.Expression doInvocation(int charOffset, Arguments arguments) {
-    return buildError(arguments, offset: charOffset);
-  }
-
-  @override
-  DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
-    helper.addProblem(
-        templateUnresolvedPrefixInTypeAnnotation.withArguments(
-            name.name, suffix.name),
-        offsetForToken(token),
-        lengthOfSpan(token, suffix.token));
-    return const InvalidType();
-  }
-
-  @override
-  kernel.Expression buildError(Arguments arguments,
-      {bool isGetter: false, bool isSetter: false, int offset}) {
-    offset ??= offsetForToken(this.token);
-    return helper.throwNoSuchMethodError(
-        storeOffset(forest.literalNull(null), offset),
-        plainNameForRead,
-        arguments,
-        offset,
-        isGetter: isGetter,
-        isSetter: isSetter);
-  }
-
-  @override
-  kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
-    return unsupported("_makeRead", offsetForToken(token), uri);
-  }
-
-  @override
-  kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
-      ShadowComplexAssignment complexAssignment) {
-    return unsupported("_makeWrite", offsetForToken(token), uri);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", name: ");
-    sink.write(name.name);
-  }
-}
-
-class IncompleteErrorGenerator<Arguments>
-    extends IncompleteSendGenerator<Arguments>
-    with ErroneousExpressionGenerator<Arguments> {
-  final Message message;
-
-  IncompleteErrorGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.message)
-      : super(helper, token, null);
-
-  String get debugName => "IncompleteErrorGenerator";
-
-  @override
-  kernel.Expression buildError(Arguments arguments,
-      {bool isGetter: false, bool isSetter: false, int offset}) {
-    int length = noLength;
-    if (offset == null) {
-      offset = offsetForToken(token);
-      length = lengthForToken(token);
-    }
-    return helper.buildCompileTimeError(message, offset, length);
-  }
-
-  @override
-  DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
-    helper.addProblem(
-        templateNotAPrefixInTypeAnnotation.withArguments(
-            token.lexeme, suffix.name),
-        offsetForToken(token),
-        lengthOfSpan(token, suffix.token));
-    return const InvalidType();
-  }
-
-  @override
-  doInvocation(int offset, Arguments arguments) => this;
-
-  @override
-  void printOn(StringSink sink) {
-    sink.write(", message: ");
-    sink.write(message.code.name);
-  }
-}
-
-class SendAccessGenerator<Arguments>
-    extends IncompleteSendGenerator<Arguments> {
-  @override
-  final Arguments arguments;
-
-  SendAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      Name name,
-      this.arguments)
-      : super(helper, token, name) {
-    assert(arguments != null);
-  }
-
-  String get plainNameForRead => name.name;
-
-  String get debugName => "SendAccessGenerator";
-
-  kernel.Expression buildSimpleRead() {
-    return unsupported("buildSimpleRead", offsetForToken(token), uri);
-  }
-
-  kernel.Expression buildAssignment(kernel.Expression value,
-      {bool voidContext: false}) {
-    return unsupported("buildAssignment", offsetForToken(token), uri);
-  }
-
-  withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
-    if (receiver is Generator) {
-      return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
-    }
-    if (receiver is PrefixBuilder) {
-      PrefixBuilder prefix = receiver;
-      if (isNullAware) {
-        helper.deprecated_addCompileTimeError(
-            offsetForToken(token),
-            "Library prefix '${prefix.name}' can't be used with null-aware "
-            "operator.\nTry removing '?'.");
-      }
-      receiver = helper.scopeLookup(prefix.exportScope, name.name, token,
-          isQualified: true, prefix: prefix);
-      return helper.finishSend(receiver, arguments, offsetForToken(token));
-    }
-    return helper.buildMethodInvocation(
-        helper.toValue(receiver), name, arguments, offsetForToken(token),
-        isNullAware: isNullAware);
-  }
-
-  kernel.Expression buildNullAwareAssignment(
-      kernel.Expression value, DartType type, int offset,
-      {bool voidContext: false}) {
-    return unsupported("buildNullAwareAssignment", offset, uri);
-  }
-
-  kernel.Expression buildCompoundAssignment(
-      Name binaryOperator, kernel.Expression value,
-      {int offset,
-      bool voidContext: false,
-      Procedure interfaceTarget,
-      bool isPreIncDec: false}) {
-    return unsupported(
-        "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
-  }
-
-  kernel.Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
-  }
-
-  kernel.Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return unsupported("doInvocation", offset, uri);
-  }
-
-  @override
-  void printOn(StringSink sink) {
-    super.printOn(sink);
-    sink.write(", arguments: ");
-    var node = arguments;
-    if (node is kernel.Node) {
-      printNodeOn(node, sink);
-    } else {
-      sink.write(node);
-    }
-  }
-}
-
-class IncompletePropertyAccessGenerator<Arguments>
-    extends IncompleteSendGenerator<Arguments> {
-  IncompletePropertyAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      Name name)
-      : super(helper, token, name);
-
-  String get plainNameForRead => name.name;
-
-  String get debugName => "IncompletePropertyAccessGenerator";
-
-  kernel.Expression buildSimpleRead() {
-    return unsupported("buildSimpleRead", offsetForToken(token), uri);
-  }
-
-  kernel.Expression buildAssignment(kernel.Expression value,
-      {bool voidContext: false}) {
-    return unsupported("buildAssignment", offsetForToken(token), uri);
-  }
-
-  withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
-    if (receiver is Generator) {
-      return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
-    }
-    if (receiver is PrefixBuilder) {
-      PrefixBuilder prefix = receiver;
-      if (isNullAware) {
-        helper.deprecated_addCompileTimeError(
-            offsetForToken(token),
-            "Library prefix '${prefix.name}' can't be used with null-aware "
-            "operator.\nTry removing '?'.");
-      }
-      return helper.scopeLookup(prefix.exportScope, name.name, token,
-          isQualified: true, prefix: prefix);
-    }
-
-    return PropertyAccessGenerator.make(
-        helper, token, helper.toValue(receiver), name, null, null, isNullAware);
-  }
-
-  kernel.Expression buildNullAwareAssignment(
-      kernel.Expression value, DartType type, int offset,
-      {bool voidContext: false}) {
-    return unsupported("buildNullAwareAssignment", offset, uri);
-  }
-
-  kernel.Expression buildCompoundAssignment(
-      Name binaryOperator, kernel.Expression value,
-      {int offset,
-      bool voidContext: false,
-      Procedure interfaceTarget,
-      bool isPreIncDec: false}) {
-    return unsupported(
-        "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
-  }
-
-  kernel.Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
-  }
-
-  kernel.Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
-  }
-
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return unsupported("doInvocation", offset, uri);
-  }
-}
-
-class ParenthesizedExpressionGenerator<Arguments>
-    extends ReadOnlyAccessGenerator<Arguments> {
-  ParenthesizedExpressionGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      kernel.Expression expression)
-      : super(helper, token, expression, null);
-
-  String get debugName => "ParenthesizedExpressionGenerator";
-
-  kernel.Expression makeInvalidWrite(kernel.Expression value) {
-    return helper.deprecated_buildCompileTimeError(
-        "Can't assign to a parenthesized expression.", offsetForToken(token));
-  }
-}
-
-class TypeDeclarationAccessGenerator<Arguments>
-    extends ReadOnlyAccessGenerator<Arguments> {
-  /// The import prefix preceding the [declaration] reference, or `null` if
-  /// the reference is not prefixed.
-  final PrefixBuilder prefix;
-
-  /// The offset at which the [declaration] is referenced by this generator,
-  /// or `-1` if the reference is implicit.
-  final int declarationReferenceOffset;
-
-  final TypeDeclarationBuilder declaration;
-
-  TypeDeclarationAccessGenerator(
-      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-      Token token,
-      this.prefix,
-      this.declarationReferenceOffset,
-      this.declaration,
-      String plainNameForRead)
-      : super(helper, token, null, plainNameForRead);
-
-  String get debugName => "TypeDeclarationAccessGenerator";
-
-  kernel.Expression get expression {
-    if (super.expression == null) {
-      int offset = offsetForToken(token);
-      if (declaration is KernelInvalidTypeBuilder) {
-        KernelInvalidTypeBuilder declaration = this.declaration;
-        helper.addProblemErrorIfConst(
-            declaration.message.messageObject, offset, token.length);
-        super.expression =
-            new Throw(forest.literalString(declaration.message.message, token))
-              ..fileOffset = offset;
-      } else {
-        super.expression = forest.literalType(
-            buildTypeWithBuiltArguments(null, nonInstanceAccessIsError: true),
-            token);
-      }
-    }
-    return super.expression;
-  }
-
-  kernel.Expression makeInvalidWrite(kernel.Expression value) {
-    return buildThrowNoSuchMethodError(
-        forest.literalNull(token),
-        storeOffset(forest.arguments(<kernel.Expression>[value], null),
-            value.fileOffset),
-        isSetter: true);
-  }
-
-  @override
-  buildPropertyAccess(
-      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
-    // `SomeType?.toString` is the same as `SomeType.toString`, not
-    // `(SomeType).toString`.
-    isNullAware = false;
-
-    Name name = send.name;
-    Arguments arguments = send.arguments;
-
-    if (declaration is KernelClassBuilder) {
-      KernelClassBuilder declaration = this.declaration;
-      Builder builder = declaration.findStaticBuilder(
-          name.name, offsetForToken(token), uri, helper.library);
-
-      Generator generator;
-      if (builder == null) {
-        // If we find a setter, [builder] is an [AccessErrorBuilder], not null.
-        if (send is IncompletePropertyAccessGenerator) {
-          generator = new UnresolvedNameGenerator(helper, send.token, name);
-        } else {
-          return helper.buildConstructorInvocation(declaration, send.token,
-              arguments, name.name, null, token.charOffset, Constness.implicit);
-        }
-      } else {
-        Builder setter;
-        if (builder.isSetter) {
-          setter = builder;
-        } else if (builder.isGetter) {
-          setter = declaration.findStaticBuilder(
-              name.name, offsetForToken(token), uri, helper.library,
-              isSetter: true);
-        } else if (builder.isField && !builder.isFinal) {
-          setter = builder;
-        }
-        generator = new StaticAccessGenerator.fromBuilder(
-            helper, builder, send.token, setter);
-      }
-
-      return arguments == null
-          ? generator
-          : generator.doInvocation(offsetForToken(send.token), arguments);
-    } else {
-      return super.buildPropertyAccess(send, operatorOffset, isNullAware);
-    }
-  }
-
-  @override
-  DartType buildTypeWithBuiltArguments(List<DartType> arguments,
-      {bool nonInstanceAccessIsError: false}) {
-    if (arguments != null) {
-      int expected = 0;
-      if (declaration is KernelClassBuilder) {
-        expected = declaration.target.typeParameters.length;
-      } else if (declaration is FunctionTypeAliasBuilder) {
-        expected = declaration.target.typeParameters.length;
-      } else if (declaration is KernelTypeVariableBuilder) {
-        // Type arguments on a type variable - error reported elsewhere.
-      } else if (declaration is BuiltinTypeBuilder) {
-        // Type arguments on a built-in type, for example, dynamic or void.
-        expected = 0;
-      } else {
-        return unhandled(
-            "${declaration.runtimeType}",
-            "TypeDeclarationAccessGenerator.buildType",
-            offsetForToken(token),
-            helper.uri);
-      }
-      if (arguments.length != expected) {
-        helper.warnTypeArgumentsMismatch(
-            declaration.name, expected, offsetForToken(token));
-        // We ignore the provided arguments, which will in turn return the
-        // raw type below.
-        // TODO(sigmund): change to use an InvalidType and include the raw type
-        // as a recovery node once the IR can represent it (Issue #29840).
-        arguments = null;
-      }
-    }
-
-    DartType type;
-    if (arguments == null) {
-      TypeDeclarationBuilder typeDeclaration = declaration;
-      if (typeDeclaration is KernelClassBuilder) {
-        type = typeDeclaration.buildType(helper.library, null);
-      } else if (typeDeclaration is KernelFunctionTypeAliasBuilder) {
-        type = typeDeclaration.buildType(helper.library, null);
-      }
-    }
-    if (type == null) {
-      type =
-          declaration.buildTypesWithBuiltArguments(helper.library, arguments);
-    }
-    if (type is TypeParameterType) {
-      return helper.validatedTypeVariableUse(
-          type, offsetForToken(token), nonInstanceAccessIsError);
-    }
-    return type;
-  }
-
-  @override
-  kernel.Expression doInvocation(int offset, Arguments arguments) {
-    return helper.buildConstructorInvocation(declaration, token, arguments, "",
-        null, token.charOffset, Constness.implicit);
-  }
-}
-
-kernel.Expression makeLet(
-    VariableDeclaration variable, kernel.Expression body) {
-  if (variable == null) return body;
-  return new Let(variable, body);
-}
-
-kernel.Expression makeBinary<Arguments>(
-    kernel.Expression left,
-    Name operator,
-    Procedure interfaceTarget,
-    kernel.Expression right,
-    ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
-    {int offset: TreeNode.noOffset}) {
-  return new ShadowMethodInvocation(
-      left,
-      operator,
-      helper.storeOffset(
-          helper.forest.castArguments(
-              helper.forest.arguments(<kernel.Expression>[right], null)),
-          offset),
-      interfaceTarget: interfaceTarget)
-    ..fileOffset = offset;
-}
-
-kernel.Expression buildIsNull<Arguments>(kernel.Expression value, int offset,
-    ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper) {
-  return makeBinary(value, equalsName, null,
-      helper.storeOffset(helper.forest.literalNull(null), offset), helper,
-      offset: offset);
-}
-
-VariableDeclaration makeOrReuseVariable(kernel.Expression value) {
-  // TODO: Devise a way to remember if a variable declaration was reused
-  // or is fresh (hence needs a let binding).
-  return new VariableDeclaration.forValue(value);
-}
-
-int adjustForImplicitCall(String name, int offset) {
-  // Normally the offset is at the start of the token, but in this case,
-  // because we insert a '.call', we want it at the end instead.
-  return offset + (name?.length ?? 0);
-}
-
-bool isFieldOrGetter(Member member) {
-  return member is Field || (member is Procedure && member.isGetter);
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index 5af746c..4d3404a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -14,6 +14,8 @@
 
 import '../scope.dart' show ProblemBuilder, Scope;
 
+import '../type_inference/inference_helper.dart' show InferenceHelper;
+
 import '../type_inference/type_promotion.dart' show TypePromoter;
 
 import 'constness.dart' show Constness;
@@ -43,7 +45,8 @@
         PrefixBuilder,
         TypeDeclarationBuilder;
 
-abstract class ExpressionGeneratorHelper<Expression, Statement, Arguments> {
+abstract class ExpressionGeneratorHelper<Expression, Statement, Arguments>
+    implements InferenceHelper<Expression, Statement, Arguments> {
   LibraryBuilder get library;
 
   Uri get uri;
diff --git a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
index 49330c6..1490aff 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
@@ -10,8 +10,8 @@
     show
         Arguments,
         AssertInitializer,
-        BreakStatement,
         Block,
+        BreakStatement,
         Catch,
         ContinueSwitchStatement,
         DartType,
@@ -23,7 +23,10 @@
         Let,
         LibraryDependency,
         MapEntry,
+        Member,
+        Name,
         NamedExpression,
+        Procedure,
         Statement,
         SwitchCase,
         ThisExpression,
@@ -37,6 +40,16 @@
 
 import '../scanner.dart' show Token;
 
+import 'kernel_expression_generator.dart'
+    show
+        KernelIndexedAccessGenerator,
+        KernelNullAwarePropertyAccessGenerator,
+        KernelPropertyAccessGenerator,
+        KernelSuperPropertyAccessGenerator,
+        KernelThisIndexedAccessGenerator,
+        KernelThisPropertyAccessGenerator,
+        KernelVariableUseGenerator;
+
 import 'kernel_shadow_ast.dart'
     show
         ShadowArguments,
@@ -52,6 +65,7 @@
         ShadowDoStatement,
         ShadowDoubleLiteral,
         ShadowExpressionStatement,
+        ShadowForStatement,
         ShadowIfStatement,
         ShadowIntLiteral,
         ShadowIsExpression,
@@ -76,7 +90,7 @@
         ShadowWhileStatement,
         ShadowYieldStatement;
 
-import 'forest.dart' show Forest;
+import 'forest.dart' show ExpressionGeneratorHelper, Forest;
 
 /// A shadow tree factory.
 class Fangorn extends Forest<Expression, Statement, Token, Arguments> {
@@ -338,6 +352,22 @@
   }
 
   @override
+  Statement forStatement(
+      Token forKeyword,
+      Token leftParenthesis,
+      List<VariableDeclaration> variableList,
+      covariant initialization,
+      Token leftSeparator,
+      Expression condition,
+      Token rightSeparator,
+      List<Expression> updaters,
+      Token rightParenthesis,
+      Statement body) {
+    return new ShadowForStatement(variableList, condition, updaters, body)
+      ..fileOffset = forKeyword.charOffset;
+  }
+
+  @override
   Statement ifStatement(Token ifKeyword, Expression condition,
       Statement thenStatement, Token elseKeyword, Statement elseStatement) {
     return new ShadowIfStatement(condition, thenStatement, elseStatement)
@@ -454,9 +484,20 @@
   }
 
   @override
+  Expression getExpressionFromExpressionStatement(Statement statement) {
+    return (statement as ExpressionStatement).expression;
+  }
+
+  @override
+  Token getSemicolon(Statement statement) => null;
+
+  @override
   bool isBlock(Object node) => node is Block;
 
   @override
+  bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
+
+  @override
   bool isErroneousNode(Object node) {
     if (node is ExpressionStatement) {
       ExpressionStatement statement = node;
@@ -478,6 +519,10 @@
   }
 
   @override
+  bool isExpressionStatement(Statement statement) =>
+      statement is ExpressionStatement;
+
+  @override
   bool isThisExpression(Object node) => node is ThisExpression;
 
   @override
@@ -498,6 +543,86 @@
       SwitchCase target, ContinueSwitchStatement user) {
     user.target = target;
   }
+
+  @override
+  KernelVariableUseGenerator variableUseGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      VariableDeclaration variable,
+      DartType promotedType) {
+    return new KernelVariableUseGenerator(
+        helper, token, variable, promotedType);
+  }
+
+  @override
+  KernelPropertyAccessGenerator propertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      Expression receiver,
+      Name name,
+      Member getter,
+      Member setter) {
+    return new KernelPropertyAccessGenerator.internal(
+        helper, token, receiver, name, getter, setter);
+  }
+
+  @override
+  KernelThisPropertyAccessGenerator thisPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      Name name,
+      Member getter,
+      Member setter) {
+    return new KernelThisPropertyAccessGenerator(
+        helper, token, name, getter, setter);
+  }
+
+  @override
+  KernelNullAwarePropertyAccessGenerator nullAwarePropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      Expression receiverExpression,
+      Name name,
+      Member getter,
+      Member setter,
+      DartType type) {
+    return new KernelNullAwarePropertyAccessGenerator(
+        helper, token, receiverExpression, name, getter, setter, type);
+  }
+
+  @override
+  KernelSuperPropertyAccessGenerator superPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      Name name,
+      Member getter,
+      Member setter) {
+    return new KernelSuperPropertyAccessGenerator(
+        helper, token, name, getter, setter);
+  }
+
+  @override
+  KernelIndexedAccessGenerator indexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      Expression receiver,
+      Expression index,
+      Procedure getter,
+      Procedure setter) {
+    return new KernelIndexedAccessGenerator.internal(
+        helper, token, receiver, index, getter, setter);
+  }
+
+  @override
+  KernelThisIndexedAccessGenerator thisIndexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      Expression index,
+      Procedure getter,
+      Procedure setter) {
+    return new KernelThisIndexedAccessGenerator(
+        helper, token, index, getter, setter);
+  }
 }
 
 class _VariablesDeclaration extends Statement {
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index f7a8b61..2589526 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -4,13 +4,26 @@
 
 library fasta.forest;
 
-// TODO(ahe): Remove this import.
-import 'package:kernel/ast.dart' as kernel show Arguments, DartType;
+import 'package:kernel/ast.dart' as kernel
+    show
+        Arguments, // TODO(ahe): Remove this import.
+        DartType,
+        Member,
+        Name,
+        Procedure;
 
 import 'body_builder.dart' show Identifier;
 
+import 'expression_generator.dart' show Generator;
+
+import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+
 export 'body_builder.dart' show Identifier, Operator;
 
+export 'expression_generator.dart' show Generator;
+
+export 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+
 /// A tree factory.
 ///
 /// For now, the [Location] is always a token.
@@ -188,6 +201,19 @@
   /// [semicolon].
   Statement emptyStatement(Location semicolon);
 
+  /// Return a representation of a for statement.
+  Statement forStatement(
+      Location forKeyword,
+      Location leftParenthesis,
+      covariant variableList,
+      covariant initialization,
+      Location leftSeparator,
+      Expression condition,
+      Location rightSeparator,
+      List<Expression> updaters,
+      Location rightParenthesis,
+      Statement body);
+
   /// Return a representation of an `if` statement.
   Statement ifStatement(Location ifKeyword, covariant Expression condition,
       Statement thenStatement, Location elseKeyword, Statement elseStatement);
@@ -257,10 +283,25 @@
   Statement yieldStatement(Location yieldKeyword, Location star,
       Expression expression, Location semicolon);
 
+  /// Return the expression from the given expression [statement].
+  Expression getExpressionFromExpressionStatement(Statement statement);
+
+  /// Return the semicolon at the end of the given [statement], or `null` if the
+  /// statement is not terminated by a semicolon.
+  Location getSemicolon(Statement statement);
+
   bool isBlock(Object node);
 
+  /// Return `true` if the given [statement] is the representation of an empty
+  /// statement.
+  bool isEmptyStatement(Statement statement);
+
   bool isErroneousNode(Object node);
 
+  /// Return `true` if the given [statement] is the representation of an
+  /// expression statement.
+  bool isExpressionStatement(Statement statement);
+
   bool isThisExpression(Object node);
 
   bool isVariablesDeclaration(Object node);
@@ -278,6 +319,58 @@
   void resolveContinueInSwitch(
       covariant Object target, covariant Statement user);
 
+  Generator<Expression, Statement, Arguments> variableUseGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      covariant variable,
+      kernel.DartType promotedType);
+
+  Generator<Expression, Statement, Arguments> propertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      Expression receiver,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter);
+
+  Generator<Expression, Statement, Arguments> thisPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter);
+
+  Generator<Expression, Statement, Arguments> nullAwarePropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      Expression receiverExpression,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter,
+      kernel.DartType type);
+
+  Generator<Expression, Statement, Arguments> superPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter);
+
+  Generator<Expression, Statement, Arguments> indexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      Expression receiver,
+      Expression index,
+      kernel.Procedure getter,
+      kernel.Procedure setter);
+
+  Generator<Expression, Statement, Arguments> thisIndexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Location location,
+      Expression index,
+      kernel.Procedure getter,
+      kernel.Procedure setter);
+
   // TODO(ahe): Remove this method when all users are moved here.
   kernel.Arguments castArguments(Arguments arguments) {
     dynamic a = arguments;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
index 6817deb..33906b3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
@@ -76,7 +76,6 @@
         ShadowFactoryConstructorInvocation,
         ShadowFieldInitializer,
         ShadowForInStatement,
-        ShadowForStatement,
         ShadowFunctionDeclaration,
         ShadowFunctionExpression,
         ShadowIfNullExpression,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
new file mode 100644
index 0000000..218f9f9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
@@ -0,0 +1,991 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart' show Arguments, Expression, Node, Statement;
+
+import '../../scanner/token.dart' show Token;
+
+import '../constant_context.dart' show ConstantContext;
+
+import '../fasta_codes.dart'
+    show
+        LocatedMessage,
+        messageLoadLibraryTakesNoArguments,
+        messageSuperAsExpression,
+        templateDeferredTypeAnnotation,
+        templateIntegerLiteralIsOutOfRange,
+        templateNotAPrefixInTypeAnnotation,
+        templateUnresolvedPrefixInTypeAnnotation;
+
+import '../messages.dart' show Message, noLength;
+
+import '../names.dart'
+    show
+        ampersandName,
+        barName,
+        callName,
+        caretName,
+        divisionName,
+        equalsName,
+        indexGetName,
+        indexSetName,
+        leftShiftName,
+        minusName,
+        multiplyName,
+        mustacheName,
+        percentName,
+        plusName,
+        rightShiftName;
+
+import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
+
+import '../problems.dart' show unhandled, unsupported;
+
+import '../scope.dart' show AccessErrorBuilder;
+
+import 'body_builder.dart' show Identifier, noLocation;
+
+import 'constness.dart' show Constness;
+
+import 'expression_generator.dart'
+    show
+        ExpressionGenerator,
+        Generator,
+        IndexedAccessGenerator,
+        NullAwarePropertyAccessGenerator,
+        PropertyAccessGenerator,
+        SuperPropertyAccessGenerator,
+        ThisIndexedAccessGenerator,
+        ThisPropertyAccessGenerator,
+        VariableUseGenerator;
+
+import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+
+import 'forest.dart' show Forest;
+
+import 'kernel_builder.dart' show LoadLibraryBuilder, PrefixBuilder;
+
+import 'kernel_api.dart' show NameSystem, printNodeOn, printQualifiedNameOn;
+
+import 'kernel_ast_api.dart'
+    show
+        Constructor,
+        DartType,
+        DynamicType,
+        Field,
+        Initializer,
+        InvalidType,
+        Let,
+        Member,
+        Name,
+        Procedure,
+        PropertySet,
+        ShadowComplexAssignment,
+        ShadowIllegalAssignment,
+        ShadowIndexAssign,
+        ShadowMethodInvocation,
+        ShadowNullAwarePropertyGet,
+        ShadowPropertyAssign,
+        ShadowPropertyGet,
+        ShadowStaticAssignment,
+        ShadowSuperMethodInvocation,
+        ShadowSuperPropertyGet,
+        ShadowVariableAssignment,
+        ShadowVariableDeclaration,
+        ShadowVariableGet,
+        StaticSet,
+        SuperMethodInvocation,
+        SuperPropertySet,
+        Throw,
+        TreeNode,
+        TypeParameter,
+        TypeParameterType,
+        VariableDeclaration,
+        VariableGet,
+        VariableSet;
+
+import 'kernel_builder.dart'
+    show
+        Builder,
+        BuiltinTypeBuilder,
+        FunctionTypeAliasBuilder,
+        KernelClassBuilder,
+        KernelFunctionTypeAliasBuilder,
+        KernelInvalidTypeBuilder,
+        KernelTypeVariableBuilder,
+        LoadLibraryBuilder,
+        PrefixBuilder,
+        TypeDeclarationBuilder;
+
+part 'kernel_expression_generator_impl.dart';
+
+abstract class KernelExpressionGenerator
+    implements ExpressionGenerator<Expression, Statement, Arguments> {
+  ExpressionGeneratorHelper<Expression, Statement, Arguments> get helper;
+
+  Token get token;
+
+  Forest<Expression, Statement, Token, Arguments> get forest;
+
+  @override
+  Expression buildSimpleRead() {
+    return _finish(_makeSimpleRead(), null);
+  }
+
+  @override
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    var complexAssignment = startComplexAssignment(value);
+    return _finish(_makeSimpleWrite(value, voidContext, complexAssignment),
+        complexAssignment);
+  }
+
+  @override
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext: false}) {
+    var complexAssignment = startComplexAssignment(value);
+    if (voidContext) {
+      var nullAwareCombiner = helper.storeOffset(
+          forest.conditionalExpression(
+              buildIsNull(_makeRead(complexAssignment), offset, helper),
+              null,
+              _makeWrite(value, false, complexAssignment),
+              null,
+              helper.storeOffset(forest.literalNull(null), offset)),
+          offset);
+      complexAssignment?.nullAwareCombiner = nullAwareCombiner;
+      return _finish(nullAwareCombiner, complexAssignment);
+    }
+    var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment));
+    var nullAwareCombiner = helper.storeOffset(
+        forest.conditionalExpression(
+            buildIsNull(new VariableGet(tmp), offset, helper),
+            null,
+            _makeWrite(value, false, complexAssignment),
+            null,
+            new VariableGet(tmp)),
+        offset);
+    complexAssignment?.nullAwareCombiner = nullAwareCombiner;
+    return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment);
+  }
+
+  @override
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget,
+      bool isPreIncDec: false}) {
+    var complexAssignment = startComplexAssignment(value);
+    complexAssignment?.isPreIncDec = isPreIncDec;
+    var combiner = makeBinary(_makeRead(complexAssignment), binaryOperator,
+        interfaceTarget, value, helper,
+        offset: offset);
+    complexAssignment?.combiner = combiner;
+    return _finish(_makeWrite(combiner, voidContext, complexAssignment),
+        complexAssignment);
+  }
+
+  @override
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    return buildCompoundAssignment(
+        binaryOperator, helper.storeOffset(forest.literalInt(1, null), offset),
+        offset: offset,
+        voidContext: voidContext,
+        interfaceTarget: interfaceTarget,
+        isPreIncDec: true);
+  }
+
+  @override
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    if (voidContext) {
+      return buildPrefixIncrement(binaryOperator,
+          offset: offset, voidContext: true, interfaceTarget: interfaceTarget);
+    }
+    var rhs = helper.storeOffset(forest.literalInt(1, null), offset);
+    var complexAssignment = startComplexAssignment(rhs);
+    var value = new VariableDeclaration.forValue(_makeRead(complexAssignment));
+    valueAccess() => new VariableGet(value);
+    var combiner = makeBinary(
+        valueAccess(), binaryOperator, interfaceTarget, rhs, helper,
+        offset: offset);
+    complexAssignment?.combiner = combiner;
+    complexAssignment?.isPostIncDec = true;
+    var dummy = new ShadowVariableDeclaration.forValue(
+        _makeWrite(combiner, true, complexAssignment),
+        helper.functionNestingLevel);
+    return _finish(
+        makeLet(value, makeLet(dummy, valueAccess())), complexAssignment);
+  }
+
+  @override
+  Expression makeInvalidRead() {
+    return buildThrowNoSuchMethodError(
+        forest.literalNull(token), forest.argumentsEmpty(noLocation),
+        isGetter: true);
+  }
+
+  @override
+  Expression makeInvalidWrite(Expression value) {
+    return buildThrowNoSuchMethodError(forest.literalNull(token),
+        forest.arguments(<Expression>[value], noLocation),
+        isSetter: true);
+  }
+
+  Expression _makeSimpleRead() => _makeRead(null);
+
+  Expression _makeSimpleWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return _makeWrite(value, voidContext, complexAssignment);
+  }
+
+  Expression _makeRead(ShadowComplexAssignment complexAssignment);
+
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment);
+
+  Expression _finish(
+      Expression body, ShadowComplexAssignment complexAssignment) {
+    if (complexAssignment != null) {
+      complexAssignment.desugared = body;
+      return complexAssignment;
+    } else {
+      return body;
+    }
+  }
+
+  /// Creates a data structure for tracking the desugaring of a complex
+  /// assignment expression whose right hand side is [rhs].
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowIllegalAssignment(rhs);
+}
+
+abstract class KernelGenerator = Generator<Expression, Statement, Arguments>
+    with KernelExpressionGenerator;
+
+class KernelVariableUseGenerator extends KernelGenerator
+    with VariableUseGenerator<Expression, Statement, Arguments> {
+  final VariableDeclaration variable;
+
+  final DartType promotedType;
+
+  KernelVariableUseGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+      Token token,
+      this.variable,
+      this.promotedType)
+      : super(helper, token);
+
+  @override
+  String get plainNameForRead => variable.name;
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    var fact = helper.typePromoter
+        .getFactForAccess(variable, helper.functionNestingLevel);
+    var scope = helper.typePromoter.currentScope;
+    var read = new ShadowVariableGet(variable, fact, scope)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel);
+    var write = variable.isFinal || variable.isConst
+        ? makeInvalidWrite(value)
+        : new VariableSet(variable, value)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
+        adjustForImplicitCall(plainNameForRead, offset),
+        isImplicitCall: true);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowVariableAssignment(rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", variable: ");
+    printNodeOn(variable, sink, syntheticNames: syntheticNames);
+    sink.write(", promotedType: ");
+    printNodeOn(promotedType, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class KernelPropertyAccessGenerator extends KernelGenerator
+    with PropertyAccessGenerator<Expression, Statement, Arguments> {
+  final Expression receiver;
+
+  final Name name;
+
+  final Member getter;
+
+  final Member setter;
+
+  VariableDeclaration _receiverVariable;
+
+  KernelPropertyAccessGenerator.internal(
+      ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+      Token token,
+      this.receiver,
+      this.name,
+      this.getter,
+      this.setter)
+      : super(helper, token);
+
+  @override
+  String get plainNameForRead => name.name;
+
+  receiverAccess() {
+    _receiverVariable ??= new VariableDeclaration.forValue(receiver);
+    return new VariableGet(_receiverVariable)
+      ..fileOffset = offsetForToken(token);
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildMethodInvocation(receiver, name, arguments, offset);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowPropertyAssign(receiver, rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", _receiverVariable: ");
+    printNodeOn(_receiverVariable, sink, syntheticNames: syntheticNames);
+    sink.write(", receiver: ");
+    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
+    sink.write(", name: ");
+    sink.write(name.name);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+  }
+
+  @override
+  Expression _makeSimpleRead() => new ShadowPropertyGet(receiver, name, getter)
+    ..fileOffset = offsetForToken(token);
+
+  @override
+  Expression _makeSimpleWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    var write = new PropertySet(receiver, name, value, setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    var read = new ShadowPropertyGet(receiverAccess(), name, getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    var write = new PropertySet(receiverAccess(), name, value, setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression _finish(
+      Expression body, ShadowComplexAssignment complexAssignment) {
+    return super._finish(makeLet(_receiverVariable, body), complexAssignment);
+  }
+}
+
+class KernelThisPropertyAccessGenerator extends KernelGenerator
+    with ThisPropertyAccessGenerator<Expression, Statement, Arguments> {
+  final Name name;
+
+  final Member getter;
+
+  final Member setter;
+
+  KernelThisPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      this.name,
+      this.getter,
+      this.setter)
+      : super(helper, token);
+
+  @override
+  String get plainNameForRead => name.name;
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    if (getter == null) {
+      helper.warnUnresolvedGet(name, offsetForToken(token));
+    }
+    var read = new ShadowPropertyGet(forest.thisExpression(token), name, getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (setter == null) {
+      helper.warnUnresolvedSet(name, offsetForToken(token));
+    }
+    var write =
+        new PropertySet(forest.thisExpression(token), name, value, setter)
+          ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    Member interfaceTarget = getter;
+    if (interfaceTarget == null) {
+      helper.warnUnresolvedMethod(name, offset);
+    }
+    if (interfaceTarget is Field) {
+      // TODO(ahe): In strong mode we should probably rewrite this to
+      // `this.name.call(arguments)`.
+      interfaceTarget = null;
+    }
+    return helper.buildMethodInvocation(
+        forest.thisExpression(null), name, arguments, offset,
+        interfaceTarget: interfaceTarget);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowPropertyAssign(null, rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", name: ");
+    sink.write(name.name);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class KernelNullAwarePropertyAccessGenerator extends KernelGenerator
+    with NullAwarePropertyAccessGenerator<Expression, Statement, Arguments> {
+  final VariableDeclaration receiver;
+
+  final Expression receiverExpression;
+
+  final Name name;
+
+  final Member getter;
+
+  final Member setter;
+
+  final DartType type;
+
+  KernelNullAwarePropertyAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.receiverExpression,
+      this.name,
+      this.getter,
+      this.setter,
+      this.type)
+      : this.receiver = makeOrReuseVariable(receiverExpression),
+        super(helper, token);
+
+  Expression receiverAccess() => new VariableGet(receiver);
+
+  @override
+  String get plainNameForRead => name.name;
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    var read = new ShadowPropertyGet(receiverAccess(), name, getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    var write = new PropertySet(receiverAccess(), name, value, setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression _finish(
+      Expression body, ShadowComplexAssignment complexAssignment) {
+    var offset = offsetForToken(token);
+    var nullAwareGuard = helper.storeOffset(
+        forest.conditionalExpression(
+            buildIsNull(receiverAccess(), offset, helper),
+            null,
+            helper.storeOffset(forest.literalNull(null), offset),
+            null,
+            body),
+        offset);
+    if (complexAssignment != null) {
+      body = makeLet(receiver, nullAwareGuard);
+      ShadowPropertyAssign kernelPropertyAssign = complexAssignment;
+      kernelPropertyAssign.nullAwareGuard = nullAwareGuard;
+      kernelPropertyAssign.desugared = body;
+      return kernelPropertyAssign;
+    } else {
+      return new ShadowNullAwarePropertyGet(receiver, nullAwareGuard)
+        ..fileOffset = offset;
+    }
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return unsupported("doInvocation", offset, uri);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowPropertyAssign(receiverExpression, rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", receiver: ");
+    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
+    sink.write(", receiverExpression: ");
+    printNodeOn(receiverExpression, sink, syntheticNames: syntheticNames);
+    sink.write(", name: ");
+    sink.write(name.name);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+    sink.write(", type: ");
+    printNodeOn(type, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class KernelSuperPropertyAccessGenerator extends KernelGenerator
+    with SuperPropertyAccessGenerator<Expression, Statement, Arguments> {
+  final Name name;
+
+  final Member getter;
+
+  final Member setter;
+
+  KernelSuperPropertyAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.name,
+      this.getter,
+      this.setter)
+      : super(helper, token);
+
+  @override
+  String get plainNameForRead => name.name;
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    if (getter == null) {
+      helper.warnUnresolvedGet(name, offsetForToken(token), isSuper: true);
+    }
+    // TODO(ahe): Use [DirectPropertyGet] when possible.
+    var read = new ShadowSuperPropertyGet(name, getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (setter == null) {
+      helper.warnUnresolvedSet(name, offsetForToken(token), isSuper: true);
+    }
+    // TODO(ahe): Use [DirectPropertySet] when possible.
+    var write = new SuperPropertySet(name, value, setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    if (helper.constantContext != ConstantContext.none) {
+      helper.deprecated_addCompileTimeError(
+          offset, "Not a constant expression.");
+    }
+    if (getter == null || isFieldOrGetter(getter)) {
+      return helper.buildMethodInvocation(
+          buildSimpleRead(), callName, arguments, offset,
+          // This isn't a constant expression, but we have checked if a
+          // constant expression error should be emitted already.
+          isConstantExpression: true,
+          isImplicitCall: true);
+    } else {
+      // TODO(ahe): This could be something like "super.property(...)" where
+      // property is a setter.
+      return unhandled("${getter.runtimeType}", "doInvocation", offset, uri);
+    }
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowPropertyAssign(null, rhs, isSuper: true);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", name: ");
+    sink.write(name.name);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class KernelIndexedAccessGenerator extends KernelGenerator
+    with IndexedAccessGenerator<Expression, Statement, Arguments> {
+  final Expression receiver;
+
+  final Expression index;
+
+  final Procedure getter;
+
+  final Procedure setter;
+
+  VariableDeclaration receiverVariable;
+
+  VariableDeclaration indexVariable;
+
+  KernelIndexedAccessGenerator.internal(
+      ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+      Token token,
+      this.receiver,
+      this.index,
+      this.getter,
+      this.setter)
+      : super(helper, token);
+
+  Expression indexAccess() {
+    indexVariable ??= new VariableDeclaration.forValue(index);
+    return new VariableGet(indexVariable)..fileOffset = offsetForToken(token);
+  }
+
+  Expression receiverAccess() {
+    // We cannot reuse the receiver if it is a variable since it might be
+    // reassigned in the index expression.
+    receiverVariable ??= new VariableDeclaration.forValue(receiver);
+    return new VariableGet(receiverVariable)
+      ..fileOffset = offsetForToken(token);
+  }
+
+  @override
+  Expression _makeSimpleRead() {
+    var read = new ShadowMethodInvocation(receiver, indexGetName,
+        forest.castArguments(forest.arguments(<Expression>[index], token)),
+        interfaceTarget: getter)
+      ..fileOffset = offsetForToken(token);
+    return read;
+  }
+
+  @override
+  Expression _makeSimpleWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+    var write = new ShadowMethodInvocation(
+        receiver,
+        indexSetName,
+        forest
+            .castArguments(forest.arguments(<Expression>[index, value], token)),
+        interfaceTarget: setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    var read = new ShadowMethodInvocation(
+        receiverAccess(),
+        indexGetName,
+        forest.castArguments(
+            forest.arguments(<Expression>[indexAccess()], token)),
+        interfaceTarget: getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+    var write = new ShadowMethodInvocation(
+        receiverAccess(),
+        indexSetName,
+        forest.castArguments(
+            forest.arguments(<Expression>[indexAccess(), value], token)),
+        interfaceTarget: setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  // TODO(dmitryas): remove this method after the "[]=" operator of the Context
+  // class is made to return a value.
+  Expression _makeWriteAndReturn(
+      Expression value, ShadowComplexAssignment complexAssignment) {
+    // The call to []= does not return the value like direct-style assignments
+    // do.  We need to bind the value in a let.
+    var valueVariable = new VariableDeclaration.forValue(value);
+    var write = new ShadowMethodInvocation(
+        receiverAccess(),
+        indexSetName,
+        forest.castArguments(forest.arguments(
+            <Expression>[indexAccess(), new VariableGet(valueVariable)],
+            token)),
+        interfaceTarget: setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    var dummy = new ShadowVariableDeclaration.forValue(
+        write, helper.functionNestingLevel);
+    return makeLet(
+        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+  }
+
+  @override
+  Expression _finish(
+      Expression body, ShadowComplexAssignment complexAssignment) {
+    return super._finish(
+        makeLet(receiverVariable, makeLet(indexVariable, body)),
+        complexAssignment);
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildMethodInvocation(
+        buildSimpleRead(), callName, arguments, forest.readOffset(arguments),
+        isImplicitCall: true);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowIndexAssign(receiver, index, rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", receiver: ");
+    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
+    sink.write(", index: ");
+    printNodeOn(index, sink, syntheticNames: syntheticNames);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+    sink.write(", receiverVariable: ");
+    printNodeOn(receiverVariable, sink, syntheticNames: syntheticNames);
+    sink.write(", indexVariable: ");
+    printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class KernelThisIndexedAccessGenerator extends KernelGenerator
+    with ThisIndexedAccessGenerator<Expression, Statement, Arguments> {
+  final Expression index;
+
+  final Procedure getter;
+
+  final Procedure setter;
+
+  VariableDeclaration indexVariable;
+
+  KernelThisIndexedAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.index,
+      this.getter,
+      this.setter)
+      : super(helper, token);
+
+  Expression indexAccess() {
+    indexVariable ??= new VariableDeclaration.forValue(index);
+    return new VariableGet(indexVariable);
+  }
+
+  Expression _makeWriteAndReturn(
+      Expression value, ShadowComplexAssignment complexAssignment) {
+    var valueVariable = new VariableDeclaration.forValue(value);
+    var write = new ShadowMethodInvocation(
+        forest.thisExpression(token),
+        indexSetName,
+        forest.castArguments(forest.arguments(
+            <Expression>[indexAccess(), new VariableGet(valueVariable)],
+            token)),
+        interfaceTarget: setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    var dummy = new VariableDeclaration.forValue(write);
+    return makeLet(
+        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+  }
+
+  @override
+  Expression _makeSimpleRead() {
+    return new ShadowMethodInvocation(
+        forest.thisExpression(token),
+        indexGetName,
+        forest.castArguments(forest.arguments(<Expression>[index], token)),
+        interfaceTarget: getter)
+      ..fileOffset = offsetForToken(token);
+  }
+
+  @override
+  Expression _makeSimpleWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+    var write = new ShadowMethodInvocation(
+        forest.thisExpression(token),
+        indexSetName,
+        forest
+            .castArguments(forest.arguments(<Expression>[index, value], token)),
+        interfaceTarget: setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    var read = new ShadowMethodInvocation(
+        forest.thisExpression(token),
+        indexGetName,
+        forest.castArguments(
+            forest.arguments(<Expression>[indexAccess()], token)),
+        interfaceTarget: getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+    var write = new ShadowMethodInvocation(
+        forest.thisExpression(token),
+        indexSetName,
+        forest.castArguments(
+            forest.arguments(<Expression>[indexAccess(), value], token)),
+        interfaceTarget: setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  @override
+  Expression _finish(
+      Expression body, ShadowComplexAssignment complexAssignment) {
+    return super._finish(makeLet(indexVariable, body), complexAssignment);
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildMethodInvocation(
+        buildSimpleRead(), callName, arguments, offset,
+        isImplicitCall: true);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowIndexAssign(null, index, rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", index: ");
+    printNodeOn(index, sink, syntheticNames: syntheticNames);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+    sink.write(", indexVariable: ");
+    printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
+  }
+}
+
+Expression makeLet(VariableDeclaration variable, Expression body) {
+  if (variable == null) return body;
+  return new Let(variable, body);
+}
+
+Expression makeBinary(
+    Expression left,
+    Name operator,
+    Procedure interfaceTarget,
+    Expression right,
+    ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+    {int offset: TreeNode.noOffset}) {
+  return new ShadowMethodInvocation(
+      left,
+      operator,
+      helper.storeOffset(
+          helper.forest.castArguments(
+              helper.forest.arguments(<Expression>[right], null)),
+          offset),
+      interfaceTarget: interfaceTarget)
+    ..fileOffset = offset;
+}
+
+Expression buildIsNull(Expression value, int offset,
+    ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper) {
+  return makeBinary(value, equalsName, null,
+      helper.storeOffset(helper.forest.literalNull(null), offset), helper,
+      offset: offset);
+}
+
+VariableDeclaration makeOrReuseVariable(Expression value) {
+  // TODO: Devise a way to remember if a variable declaration was reused
+  // or is fresh (hence needs a let binding).
+  return new VariableDeclaration.forValue(value);
+}
+
+int adjustForImplicitCall(String name, int offset) {
+  // Normally the offset is at the start of the token, but in this case,
+  // because we insert a '.call', we want it at the end instead.
+  return offset + (name?.length ?? 0);
+}
+
+bool isFieldOrGetter(Member member) {
+  return member is Field || (member is Procedure && member.isGetter);
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
new file mode 100644
index 0000000..46e7b2a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
@@ -0,0 +1,1416 @@
+// 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.
+
+/// All classes in this file are temporary. Each class should be split in two:
+///
+/// 1. A common superclass.
+/// 2. A kernel-specific implementation class.
+///
+/// The common superclass should keep the name of the class and be moved to
+/// [expression_generator.dart]. The kernel-specific class should be moved to
+/// [kernel_expression_generator.dart] and we can eventually delete this file.
+///
+/// Take a look at [VariableUseGenerator] for an example of how the common
+/// superclass should use the forest API in a factory method.
+part of 'kernel_expression_generator.dart';
+
+class SuperIndexedAccessGenerator extends KernelGenerator {
+  final Expression index;
+
+  final Member getter;
+
+  final Member setter;
+
+  VariableDeclaration indexVariable;
+
+  SuperIndexedAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.index,
+      this.getter,
+      this.setter)
+      : super(helper, token);
+
+  String get plainNameForRead => "[]";
+
+  String get plainNameForWrite => "[]=";
+
+  String get debugName => "SuperIndexedAccessGenerator";
+
+  indexAccess() {
+    indexVariable ??= new VariableDeclaration.forValue(index);
+    return new VariableGet(indexVariable);
+  }
+
+  Expression _makeSimpleRead() {
+    if (getter == null) {
+      helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
+          isSuper: true);
+    }
+    // TODO(ahe): Use [DirectMethodInvocation] when possible.
+    return new ShadowSuperMethodInvocation(
+        indexGetName,
+        forest.castArguments(forest.arguments(<Expression>[index], token)),
+        getter)
+      ..fileOffset = offsetForToken(token);
+  }
+
+  Expression _makeSimpleWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+    if (setter == null) {
+      helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
+          isSuper: true);
+    }
+    var write = new SuperMethodInvocation(
+        indexSetName,
+        forest
+            .castArguments(forest.arguments(<Expression>[index, value], token)),
+        setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    if (getter == null) {
+      helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
+          isSuper: true);
+    }
+    var read = new SuperMethodInvocation(
+        indexGetName,
+        forest.castArguments(
+            forest.arguments(<Expression>[indexAccess()], token)),
+        getter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+    if (setter == null) {
+      helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
+          isSuper: true);
+    }
+    var write = new SuperMethodInvocation(
+        indexSetName,
+        forest.castArguments(
+            forest.arguments(<Expression>[indexAccess(), value], token)),
+        setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  _makeWriteAndReturn(
+      Expression value, ShadowComplexAssignment complexAssignment) {
+    var valueVariable = new VariableDeclaration.forValue(value);
+    if (setter == null) {
+      helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
+          isSuper: true);
+    }
+    var write = new SuperMethodInvocation(
+        indexSetName,
+        forest.castArguments(forest.arguments(
+            <Expression>[indexAccess(), new VariableGet(valueVariable)],
+            token)),
+        setter)
+      ..fileOffset = offsetForToken(token);
+    complexAssignment?.write = write;
+    var dummy = new VariableDeclaration.forValue(write);
+    return makeLet(
+        valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+  }
+
+  Expression _finish(
+      Expression body, ShadowComplexAssignment complexAssignment) {
+    return super._finish(makeLet(indexVariable, body), complexAssignment);
+  }
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildMethodInvocation(
+        buildSimpleRead(), callName, arguments, offset,
+        isImplicitCall: true);
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowIndexAssign(null, index, rhs, isSuper: true);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", index: ");
+    printNodeOn(index, sink, syntheticNames: syntheticNames);
+    sink.write(", getter: ");
+    printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+    sink.write(", setter: ");
+    printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+    sink.write(", indexVariable: ");
+    printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class StaticAccessGenerator extends KernelGenerator {
+  final Member readTarget;
+
+  final Member writeTarget;
+
+  StaticAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.readTarget,
+      this.writeTarget)
+      : assert(readTarget != null || writeTarget != null),
+        super(helper, token);
+
+  factory StaticAccessGenerator.fromBuilder(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Builder builder,
+      Token token,
+      Builder builderSetter) {
+    if (builder is AccessErrorBuilder) {
+      AccessErrorBuilder error = builder;
+      builder = error.builder;
+      // We should only see an access error here if we've looked up a setter
+      // when not explicitly looking for a setter.
+      assert(builder.isSetter);
+    } else if (builder.target == null) {
+      return unhandled(
+          "${builder.runtimeType}",
+          "StaticAccessGenerator.fromBuilder",
+          offsetForToken(token),
+          helper.uri);
+    }
+    Member getter = builder.target.hasGetter ? builder.target : null;
+    Member setter = builder.target.hasSetter ? builder.target : null;
+    if (setter == null) {
+      if (builderSetter?.target?.hasSetter ?? false) {
+        setter = builderSetter.target;
+      }
+    }
+    return new StaticAccessGenerator(helper, token, getter, setter);
+  }
+
+  String get plainNameForRead => (readTarget ?? writeTarget).name.name;
+
+  String get debugName => "StaticAccessGenerator";
+
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    if (readTarget == null) {
+      return makeInvalidRead();
+    } else {
+      var read = helper.makeStaticGet(readTarget, token);
+      complexAssignment?.read = read;
+      return read;
+    }
+  }
+
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    Expression write;
+    if (writeTarget == null) {
+      write = makeInvalidWrite(value);
+    } else {
+      write = new StaticSet(writeTarget, value);
+      complexAssignment?.write = write;
+    }
+    write.fileOffset = offsetForToken(token);
+    return write;
+  }
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    if (helper.constantContext != ConstantContext.none &&
+        !helper.isIdentical(readTarget)) {
+      helper.deprecated_addCompileTimeError(
+          offset, "Not a constant expression.");
+    }
+    if (readTarget == null || isFieldOrGetter(readTarget)) {
+      return helper.buildMethodInvocation(buildSimpleRead(), callName,
+          arguments, offset + (readTarget?.name?.name?.length ?? 0),
+          // This isn't a constant expression, but we have checked if a
+          // constant expression error should be emitted already.
+          isConstantExpression: true,
+          isImplicitCall: true);
+    } else {
+      return helper.buildStaticInvocation(readTarget, arguments,
+          charOffset: offset);
+    }
+  }
+
+  @override
+  ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+      new ShadowStaticAssignment(rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", readTarget: ");
+    printQualifiedNameOn(readTarget, sink, syntheticNames: syntheticNames);
+    sink.write(", writeTarget: ");
+    printQualifiedNameOn(writeTarget, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class LoadLibraryGenerator extends KernelGenerator {
+  final LoadLibraryBuilder builder;
+
+  LoadLibraryGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.builder)
+      : super(helper, token);
+
+  String get plainNameForRead => 'loadLibrary';
+
+  String get debugName => "LoadLibraryGenerator";
+
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    var read =
+        helper.makeStaticGet(builder.createTearoffMethod(helper.forest), token);
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    Expression write = makeInvalidWrite(value);
+    write.fileOffset = offsetForToken(token);
+    return write;
+  }
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    if (forest.argumentsPositional(arguments).length > 0 ||
+        forest.argumentsNamed(arguments).length > 0) {
+      helper.addProblemErrorIfConst(
+          messageLoadLibraryTakesNoArguments, offset, 'loadLibrary'.length);
+    }
+    return builder.createLoadLibrary(offset, forest);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", builder: ");
+    sink.write(builder);
+  }
+}
+
+class DeferredAccessGenerator extends KernelGenerator {
+  final PrefixBuilder builder;
+
+  final KernelGenerator generator;
+
+  DeferredAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.builder,
+      this.generator)
+      : super(helper, token);
+
+  String get plainNameForRead {
+    return unsupported(
+        "deferredAccessor.plainNameForRead", offsetForToken(token), uri);
+  }
+
+  String get debugName => "DeferredAccessGenerator";
+
+  Expression _makeSimpleRead() {
+    return helper.wrapInDeferredCheck(
+        generator._makeSimpleRead(), builder, token.charOffset);
+  }
+
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    return helper.wrapInDeferredCheck(
+        generator._makeRead(complexAssignment), builder, token.charOffset);
+  }
+
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return helper.wrapInDeferredCheck(
+        generator._makeWrite(value, voidContext, complexAssignment),
+        builder,
+        token.charOffset);
+  }
+
+  buildPropertyAccess(
+      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+    var propertyAccess =
+        generator.buildPropertyAccess(send, operatorOffset, isNullAware);
+    if (propertyAccess is Generator) {
+      return new DeferredAccessGenerator(
+          helper, token, builder, propertyAccess);
+    } else {
+      Expression expression = propertyAccess;
+      return helper.wrapInDeferredCheck(expression, builder, token.charOffset);
+    }
+  }
+
+  @override
+  DartType buildTypeWithBuiltArguments(List<DartType> arguments,
+      {bool nonInstanceAccessIsError: false}) {
+    helper.addProblem(
+        templateDeferredTypeAnnotation.withArguments(
+            generator.buildTypeWithBuiltArguments(arguments,
+                nonInstanceAccessIsError: nonInstanceAccessIsError),
+            builder.name),
+        offsetForToken(token),
+        lengthForToken(token));
+    return const InvalidType();
+  }
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.wrapInDeferredCheck(
+        generator.doInvocation(offset, arguments), builder, token.charOffset);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", builder: ");
+    sink.write(builder);
+    sink.write(", generator: ");
+    sink.write(generator);
+  }
+}
+
+class ReadOnlyAccessGenerator extends KernelGenerator {
+  final String plainNameForRead;
+
+  Expression expression;
+
+  VariableDeclaration value;
+
+  ReadOnlyAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.expression,
+      this.plainNameForRead)
+      : super(helper, token);
+
+  String get debugName => "ReadOnlyAccessGenerator";
+
+  Expression _makeSimpleRead() => expression;
+
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    value ??= new VariableDeclaration.forValue(expression);
+    return new VariableGet(value);
+  }
+
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    var write = makeInvalidWrite(value);
+    complexAssignment?.write = write;
+    return write;
+  }
+
+  Expression _finish(
+          Expression body, ShadowComplexAssignment complexAssignment) =>
+      super._finish(makeLet(value, body), complexAssignment);
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
+        adjustForImplicitCall(plainNameForRead, offset),
+        isImplicitCall: true);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", expression: ");
+    printNodeOn(expression, sink, syntheticNames: syntheticNames);
+    sink.write(", plainNameForRead: ");
+    sink.write(plainNameForRead);
+    sink.write(", value: ");
+    printNodeOn(value, sink, syntheticNames: syntheticNames);
+  }
+}
+
+class LargeIntAccessGenerator extends KernelGenerator {
+  LargeIntAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper, Token token)
+      : super(helper, token);
+
+  // TODO(ahe): This should probably be calling unhandled.
+  String get plainNameForRead => null;
+
+  String get debugName => "LargeIntAccessGenerator";
+
+  @override
+  Expression _makeSimpleRead() => buildError();
+
+  @override
+  Expression _makeSimpleWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return buildError();
+  }
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    return buildError();
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return buildError();
+  }
+
+  Expression buildError() {
+    return helper.buildCompileTimeError(
+        templateIntegerLiteralIsOutOfRange.withArguments(token),
+        offsetForToken(token),
+        lengthForToken(token));
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return buildError();
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", lexeme: ");
+    sink.write(token.lexeme);
+  }
+}
+
+abstract class ErroneousExpressionGenerator implements KernelGenerator {
+  /// Pass [arguments] that must be evaluated before throwing an error.  At
+  /// most one of [isGetter] and [isSetter] should be true and they're passed
+  /// to [ExpressionGeneratorHelper.buildThrowNoSuchMethodError] if it is used.
+  Expression buildError(Arguments arguments,
+      {bool isGetter: false, bool isSetter: false, int offset});
+
+  DartType buildErroneousTypeNotAPrefix(Identifier suffix);
+
+  Name get name => unsupported("name", offsetForToken(token), uri);
+
+  @override
+  String get plainNameForRead => name.name;
+
+  withReceiver(Object receiver, int operatorOffset, {bool isNullAware}) => this;
+
+  @override
+  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+    return helper.buildInvalidInitializer(
+        buildError(forest.argumentsEmpty(noLocation), isSetter: true));
+  }
+
+  @override
+  doInvocation(int offset, Arguments arguments) {
+    return buildError(arguments, offset: offset);
+  }
+
+  @override
+  buildPropertyAccess(
+      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+    return this;
+  }
+
+  @override
+  buildThrowNoSuchMethodError(Expression receiver, Arguments arguments,
+      {bool isSuper: false,
+      bool isGetter: false,
+      bool isSetter: false,
+      bool isStatic: false,
+      String name,
+      int offset,
+      LocatedMessage argMessage}) {
+    return this;
+  }
+
+  @override
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return buildError(forest.arguments(<Expression>[value], noLocation),
+        isSetter: true);
+  }
+
+  @override
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget,
+      bool isPreIncDec: false}) {
+    return buildError(forest.arguments(<Expression>[value], token),
+        isGetter: true);
+  }
+
+  @override
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    // TODO(ahe): For the Analyzer, we probably need to build a prefix
+    // increment node that wraps an error.
+    return buildError(
+        forest.arguments(
+            <Expression>[storeOffset(forest.literalInt(1, null), offset)],
+            noLocation),
+        isGetter: true);
+  }
+
+  @override
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    // TODO(ahe): For the Analyzer, we probably need to build a post increment
+    // node that wraps an error.
+    return buildError(
+        forest.arguments(
+            <Expression>[storeOffset(forest.literalInt(1, null), offset)],
+            noLocation),
+        isGetter: true);
+  }
+
+  @override
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext: false}) {
+    return buildError(forest.arguments(<Expression>[value], noLocation),
+        isSetter: true);
+  }
+
+  @override
+  Expression buildSimpleRead() =>
+      buildError(forest.argumentsEmpty(noLocation), isGetter: true);
+
+  @override
+  Expression makeInvalidRead() =>
+      buildError(forest.argumentsEmpty(noLocation), isGetter: true);
+
+  @override
+  Expression makeInvalidWrite(Expression value) {
+    return buildError(forest.arguments(<Expression>[value], noLocation),
+        isSetter: true);
+  }
+}
+
+class ThisAccessGenerator extends KernelGenerator {
+  final bool isInitializer;
+
+  final bool isSuper;
+
+  ThisAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.isInitializer,
+      {this.isSuper: false})
+      : super(helper, token);
+
+  String get plainNameForRead {
+    return unsupported("${isSuper ? 'super' : 'this'}.plainNameForRead",
+        offsetForToken(token), uri);
+  }
+
+  String get debugName => "ThisAccessGenerator";
+
+  Expression buildSimpleRead() {
+    if (!isSuper) {
+      return forest.thisExpression(token);
+    } else {
+      return helper.buildCompileTimeError(messageSuperAsExpression,
+          offsetForToken(token), lengthForToken(token));
+    }
+  }
+
+  @override
+  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+    String keyword = isSuper ? "super" : "this";
+    int offset = offsetForToken(token);
+    return helper.buildInvalidInitializer(
+        helper.deprecated_buildCompileTimeError(
+            "Can't use '$keyword' here, did you mean '$keyword()'?", offset),
+        offset);
+  }
+
+  buildPropertyAccess(
+      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+    Name name = send.name;
+    Arguments arguments = send.arguments;
+    int offset = offsetForToken(send.token);
+    if (isInitializer && send is SendAccessGenerator) {
+      if (isNullAware) {
+        helper.deprecated_addCompileTimeError(
+            operatorOffset, "Expected '.'\nTry removing '?'.");
+      }
+      return buildConstructorInitializer(offset, name, arguments);
+    }
+    Member getter = helper.lookupInstanceMember(name, isSuper: isSuper);
+    if (send is SendAccessGenerator) {
+      // Notice that 'this' or 'super' can't be null. So we can ignore the
+      // value of [isNullAware].
+      if (getter == null) {
+        helper.warnUnresolvedMethod(name, offsetForToken(send.token),
+            isSuper: isSuper);
+      }
+      return helper.buildMethodInvocation(forest.thisExpression(null), name,
+          send.arguments, offsetForToken(send.token),
+          isSuper: isSuper, interfaceTarget: getter);
+    } else {
+      Member setter =
+          helper.lookupInstanceMember(name, isSuper: isSuper, isSetter: true);
+      if (isSuper) {
+        return new SuperPropertyAccessGenerator(
+            helper, send.token, name, getter, setter);
+      } else {
+        return new ThisPropertyAccessGenerator(
+            helper, send.token, name, getter, setter);
+      }
+    }
+  }
+
+  doInvocation(int offset, Arguments arguments) {
+    if (isInitializer) {
+      return buildConstructorInitializer(offset, new Name(""), arguments);
+    } else if (isSuper) {
+      return helper.buildCompileTimeError(
+          messageSuperAsExpression, offset, noLength);
+    } else {
+      return helper.buildMethodInvocation(
+          forest.thisExpression(null), callName, arguments, offset,
+          isImplicitCall: true);
+    }
+  }
+
+  Initializer buildConstructorInitializer(
+      int offset, Name name, Arguments arguments) {
+    Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper);
+    LocatedMessage argMessage;
+    if (constructor != null) {
+      argMessage = helper.checkArgumentsForFunction(
+          constructor.function, arguments, offset, <TypeParameter>[]);
+    }
+    if (constructor == null || argMessage != null) {
+      return helper.buildInvalidInitializer(
+          buildThrowNoSuchMethodError(
+              storeOffset(forest.literalNull(null), offset), arguments,
+              isSuper: isSuper,
+              name: name.name,
+              offset: offset,
+              argMessage: argMessage),
+          offset);
+    } else if (isSuper) {
+      return helper.buildSuperInitializer(
+          false, constructor, arguments, offset);
+    } else {
+      return helper.buildRedirectingInitializer(constructor, arguments, offset);
+    }
+  }
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return buildAssignmentError();
+  }
+
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext: false}) {
+    return buildAssignmentError();
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget,
+      bool isPreIncDec: false}) {
+    return buildAssignmentError();
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    return buildAssignmentError();
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    return buildAssignmentError();
+  }
+
+  Expression buildAssignmentError() {
+    String message =
+        isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'.";
+    return helper.deprecated_buildCompileTimeError(
+        message, offsetForToken(token));
+  }
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    return unsupported("_makeRead", offsetForToken(token), uri);
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return unsupported("_makeWrite", offsetForToken(token), uri);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", isInitializer: ");
+    sink.write(isInitializer);
+    sink.write(", isSuper: ");
+    sink.write(isSuper);
+  }
+}
+
+abstract class IncompleteSendGenerator extends KernelGenerator {
+  final Name name;
+
+  IncompleteSendGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.name)
+      : super(helper, token);
+
+  withReceiver(Object receiver, int operatorOffset, {bool isNullAware});
+
+  Arguments get arguments => null;
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    return unsupported("_makeRead", offsetForToken(token), uri);
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return unsupported("_makeWrite", offsetForToken(token), uri);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", name: ");
+    sink.write(name.name);
+  }
+}
+
+class UnresolvedNameGenerator extends KernelGenerator
+    with ErroneousExpressionGenerator {
+  @override
+  final Name name;
+
+  UnresolvedNameGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.name)
+      : super(helper, token);
+
+  String get debugName => "UnresolvedNameGenerator";
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return buildError(arguments, offset: charOffset);
+  }
+
+  @override
+  DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
+    helper.addProblem(
+        templateUnresolvedPrefixInTypeAnnotation.withArguments(
+            name.name, suffix.name),
+        offsetForToken(token),
+        lengthOfSpan(token, suffix.token));
+    return const InvalidType();
+  }
+
+  @override
+  Expression buildError(Arguments arguments,
+      {bool isGetter: false, bool isSetter: false, int offset}) {
+    offset ??= offsetForToken(this.token);
+    return helper.throwNoSuchMethodError(
+        storeOffset(forest.literalNull(null), offset),
+        plainNameForRead,
+        arguments,
+        offset,
+        isGetter: isGetter,
+        isSetter: isSetter);
+  }
+
+  @override
+  Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+    return unsupported("_makeRead", offsetForToken(token), uri);
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ShadowComplexAssignment complexAssignment) {
+    return unsupported("_makeWrite", offsetForToken(token), uri);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", name: ");
+    sink.write(name.name);
+  }
+}
+
+class IncompleteErrorGenerator extends IncompleteSendGenerator
+    with ErroneousExpressionGenerator {
+  final Message message;
+
+  IncompleteErrorGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.message)
+      : super(helper, token, null);
+
+  String get debugName => "IncompleteErrorGenerator";
+
+  @override
+  Expression buildError(Arguments arguments,
+      {bool isGetter: false, bool isSetter: false, int offset}) {
+    int length = noLength;
+    if (offset == null) {
+      offset = offsetForToken(token);
+      length = lengthForToken(token);
+    }
+    return helper.buildCompileTimeError(message, offset, length);
+  }
+
+  @override
+  DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
+    helper.addProblem(
+        templateNotAPrefixInTypeAnnotation.withArguments(
+            token.lexeme, suffix.name),
+        offsetForToken(token),
+        lengthOfSpan(token, suffix.token));
+    return const InvalidType();
+  }
+
+  @override
+  doInvocation(int offset, Arguments arguments) => this;
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", message: ");
+    sink.write(message.code.name);
+  }
+}
+
+// TODO(ahe): Rename to SendGenerator.
+class SendAccessGenerator extends IncompleteSendGenerator {
+  @override
+  final Arguments arguments;
+
+  SendAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      Name name,
+      this.arguments)
+      : super(helper, token, name) {
+    assert(arguments != null);
+  }
+
+  String get plainNameForRead => name.name;
+
+  String get debugName => "SendAccessGenerator";
+
+  Expression buildSimpleRead() {
+    return unsupported("buildSimpleRead", offsetForToken(token), uri);
+  }
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return unsupported("buildAssignment", offsetForToken(token), uri);
+  }
+
+  withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
+    if (receiver is Generator) {
+      return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
+    }
+    if (receiver is PrefixBuilder) {
+      PrefixBuilder prefix = receiver;
+      if (isNullAware) {
+        helper.deprecated_addCompileTimeError(
+            offsetForToken(token),
+            "Library prefix '${prefix.name}' can't be used with null-aware "
+            "operator.\nTry removing '?'.");
+      }
+      receiver = helper.scopeLookup(prefix.exportScope, name.name, token,
+          isQualified: true, prefix: prefix);
+      return helper.finishSend(receiver, arguments, offsetForToken(token));
+    }
+    return helper.buildMethodInvocation(
+        helper.toValue(receiver), name, arguments, offsetForToken(token),
+        isNullAware: isNullAware);
+  }
+
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext: false}) {
+    return unsupported("buildNullAwareAssignment", offset, uri);
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset,
+      bool voidContext: false,
+      Procedure interfaceTarget,
+      bool isPreIncDec: false}) {
+    return unsupported(
+        "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+    return unsupported(
+        "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+    return unsupported(
+        "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
+  }
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    return unsupported("doInvocation", offset, uri);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    super.printOn(sink);
+    sink.write(", arguments: ");
+    var node = arguments;
+    if (node is Node) {
+      printNodeOn(node, sink);
+    } else {
+      sink.write(node);
+    }
+  }
+}
+
+class IncompletePropertyAccessGenerator extends IncompleteSendGenerator {
+  IncompletePropertyAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      Name name)
+      : super(helper, token, name);
+
+  String get plainNameForRead => name.name;
+
+  String get debugName => "IncompletePropertyAccessGenerator";
+
+  Expression buildSimpleRead() {
+    return unsupported("buildSimpleRead", offsetForToken(token), uri);
+  }
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return unsupported("buildAssignment", offsetForToken(token), uri);
+  }
+
+  withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
+    if (receiver is Generator) {
+      return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
+    }
+    if (receiver is PrefixBuilder) {
+      PrefixBuilder prefix = receiver;
+      if (isNullAware) {
+        helper.deprecated_addCompileTimeError(
+            offsetForToken(token),
+            "Library prefix '${prefix.name}' can't be used with null-aware "
+            "operator.\nTry removing '?'.");
+      }
+      return helper.scopeLookup(prefix.exportScope, name.name, token,
+          isQualified: true, prefix: prefix);
+    }
+
+    return PropertyAccessGenerator.make(
+        helper, token, helper.toValue(receiver), name, null, null, isNullAware);
+  }
+
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext: false}) {
+    return unsupported("buildNullAwareAssignment", offset, uri);
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset,
+      bool voidContext: false,
+      Procedure interfaceTarget,
+      bool isPreIncDec: false}) {
+    return unsupported(
+        "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+    return unsupported(
+        "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+    return unsupported(
+        "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
+  }
+
+  Expression doInvocation(int offset, Arguments arguments) {
+    return unsupported("doInvocation", offset, uri);
+  }
+}
+
+class ParenthesizedExpressionGenerator extends ReadOnlyAccessGenerator {
+  ParenthesizedExpressionGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      Expression expression)
+      : super(helper, token, expression, null);
+
+  String get debugName => "ParenthesizedExpressionGenerator";
+
+  Expression makeInvalidWrite(Expression value) {
+    return helper.deprecated_buildCompileTimeError(
+        "Can't assign to a parenthesized expression.", offsetForToken(token));
+  }
+}
+
+// TODO(ahe): Rename to TypeUseGenerator.
+class TypeDeclarationAccessGenerator extends ReadOnlyAccessGenerator {
+  /// The import prefix preceding the [declaration] reference, or `null` if
+  /// the reference is not prefixed.
+  final PrefixBuilder prefix;
+
+  /// The offset at which the [declaration] is referenced by this generator,
+  /// or `-1` if the reference is implicit.
+  final int declarationReferenceOffset;
+
+  final TypeDeclarationBuilder declaration;
+
+  TypeDeclarationAccessGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.prefix,
+      this.declarationReferenceOffset,
+      this.declaration,
+      String plainNameForRead)
+      : super(helper, token, null, plainNameForRead);
+
+  String get debugName => "TypeDeclarationAccessGenerator";
+
+  Expression get expression {
+    if (super.expression == null) {
+      int offset = offsetForToken(token);
+      if (declaration is KernelInvalidTypeBuilder) {
+        KernelInvalidTypeBuilder declaration = this.declaration;
+        helper.addProblemErrorIfConst(
+            declaration.message.messageObject, offset, token.length);
+        super.expression =
+            new Throw(forest.literalString(declaration.message.message, token))
+              ..fileOffset = offset;
+      } else {
+        super.expression = forest.literalType(
+            buildTypeWithBuiltArguments(null, nonInstanceAccessIsError: true),
+            token);
+      }
+    }
+    return super.expression;
+  }
+
+  Expression makeInvalidWrite(Expression value) {
+    return buildThrowNoSuchMethodError(
+        forest.literalNull(token),
+        storeOffset(
+            forest.arguments(<Expression>[value], null), value.fileOffset),
+        isSetter: true);
+  }
+
+  @override
+  buildPropertyAccess(
+      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+    // `SomeType?.toString` is the same as `SomeType.toString`, not
+    // `(SomeType).toString`.
+    isNullAware = false;
+
+    Name name = send.name;
+    Arguments arguments = send.arguments;
+
+    if (declaration is KernelClassBuilder) {
+      KernelClassBuilder declaration = this.declaration;
+      Builder builder = declaration.findStaticBuilder(
+          name.name, offsetForToken(token), uri, helper.library);
+
+      Generator generator;
+      if (builder == null) {
+        // If we find a setter, [builder] is an [AccessErrorBuilder], not null.
+        if (send is IncompletePropertyAccessGenerator) {
+          generator = new UnresolvedNameGenerator(helper, send.token, name);
+        } else {
+          return helper.buildConstructorInvocation(declaration, send.token,
+              arguments, name.name, null, token.charOffset, Constness.implicit);
+        }
+      } else {
+        Builder setter;
+        if (builder.isSetter) {
+          setter = builder;
+        } else if (builder.isGetter) {
+          setter = declaration.findStaticBuilder(
+              name.name, offsetForToken(token), uri, helper.library,
+              isSetter: true);
+        } else if (builder.isField && !builder.isFinal) {
+          setter = builder;
+        }
+        generator = new StaticAccessGenerator.fromBuilder(
+            helper, builder, send.token, setter);
+      }
+
+      return arguments == null
+          ? generator
+          : generator.doInvocation(offsetForToken(send.token), arguments);
+    } else {
+      return super.buildPropertyAccess(send, operatorOffset, isNullAware);
+    }
+  }
+
+  @override
+  DartType buildTypeWithBuiltArguments(List<DartType> arguments,
+      {bool nonInstanceAccessIsError: false}) {
+    if (arguments != null) {
+      int expected = 0;
+      if (declaration is KernelClassBuilder) {
+        expected = declaration.target.typeParameters.length;
+      } else if (declaration is FunctionTypeAliasBuilder) {
+        expected = declaration.target.typeParameters.length;
+      } else if (declaration is KernelTypeVariableBuilder) {
+        // Type arguments on a type variable - error reported elsewhere.
+      } else if (declaration is BuiltinTypeBuilder) {
+        // Type arguments on a built-in type, for example, dynamic or void.
+        expected = 0;
+      } else {
+        return unhandled(
+            "${declaration.runtimeType}",
+            "TypeDeclarationAccessGenerator.buildType",
+            offsetForToken(token),
+            helper.uri);
+      }
+      if (arguments.length != expected) {
+        helper.warnTypeArgumentsMismatch(
+            declaration.name, expected, offsetForToken(token));
+        // We ignore the provided arguments, which will in turn return the
+        // raw type below.
+        // TODO(sigmund): change to use an InvalidType and include the raw type
+        // as a recovery node once the IR can represent it (Issue #29840).
+        arguments = null;
+      }
+    }
+
+    DartType type;
+    if (arguments == null) {
+      TypeDeclarationBuilder typeDeclaration = declaration;
+      if (typeDeclaration is KernelClassBuilder) {
+        type = typeDeclaration.buildType(helper.library, null);
+      } else if (typeDeclaration is KernelFunctionTypeAliasBuilder) {
+        type = typeDeclaration.buildType(helper.library, null);
+      }
+    }
+    if (type == null) {
+      type =
+          declaration.buildTypesWithBuiltArguments(helper.library, arguments);
+    }
+    if (type is TypeParameterType) {
+      return helper.validatedTypeVariableUse(
+          type, offsetForToken(token), nonInstanceAccessIsError);
+    }
+    return type;
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    return helper.buildConstructorInvocation(declaration, token, arguments, "",
+        null, token.charOffset, Constness.implicit);
+  }
+}
+
+abstract class ContextAwareGenerator
+    extends Generator<Expression, Statement, Arguments> {
+  final Generator generator;
+
+  ContextAwareGenerator(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      this.generator)
+      : super(helper, token);
+
+  String get plainNameForRead {
+    return unsupported("plainNameForRead", token.charOffset, helper.uri);
+  }
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return unhandled("${runtimeType}", "doInvocation", charOffset, uri);
+  }
+
+  Expression buildSimpleRead();
+
+  Expression buildForEffect();
+
+  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+    return makeInvalidWrite(value);
+  }
+
+  Expression buildNullAwareAssignment(
+      Expression value, DartType type, int offset,
+      {bool voidContext: false}) {
+    return makeInvalidWrite(value);
+  }
+
+  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget,
+      bool isPreIncDec: false}) {
+    return makeInvalidWrite(value);
+  }
+
+  Expression buildPrefixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    return makeInvalidWrite(null);
+  }
+
+  Expression buildPostfixIncrement(Name binaryOperator,
+      {int offset: TreeNode.noOffset,
+      bool voidContext: false,
+      Procedure interfaceTarget}) {
+    return makeInvalidWrite(null);
+  }
+
+  makeInvalidRead() {
+    return unsupported("makeInvalidRead", token.charOffset, helper.uri);
+  }
+
+  Expression makeInvalidWrite(Expression value) {
+    return helper.deprecated_buildCompileTimeError(
+        "Can't be used as left-hand side of assignment.",
+        offsetForToken(token));
+  }
+}
+
+class DelayedAssignment extends ContextAwareGenerator {
+  final Expression value;
+
+  final String assignmentOperator;
+
+  DelayedAssignment(ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token, Generator generator, this.value, this.assignmentOperator)
+      : super(helper, token, generator);
+
+  String get debugName => "DelayedAssignment";
+
+  Expression buildSimpleRead() {
+    return handleAssignment(false);
+  }
+
+  Expression buildForEffect() {
+    return handleAssignment(true);
+  }
+
+  Expression handleAssignment(bool voidContext) {
+    if (helper.constantContext != ConstantContext.none) {
+      return helper.deprecated_buildCompileTimeError(
+          "Not a constant expression.", offsetForToken(token));
+    }
+    if (identical("=", assignmentOperator)) {
+      return generator.buildAssignment(value, voidContext: voidContext);
+    } else if (identical("+=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(plusName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("-=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(minusName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("*=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(multiplyName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("%=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(percentName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("&=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(ampersandName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("/=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(divisionName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("<<=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(leftShiftName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical(">>=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(rightShiftName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("??=", assignmentOperator)) {
+      return generator.buildNullAwareAssignment(
+          value, const DynamicType(), offsetForToken(token),
+          voidContext: voidContext);
+    } else if (identical("^=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(caretName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("|=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(barName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else if (identical("~/=", assignmentOperator)) {
+      return generator.buildCompoundAssignment(mustacheName, value,
+          offset: offsetForToken(token), voidContext: voidContext);
+    } else {
+      return unhandled(
+          assignmentOperator, "handleAssignment", token.charOffset, helper.uri);
+    }
+  }
+
+  @override
+  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+    if (!identical("=", assignmentOperator) ||
+        !generator.isThisPropertyAccess) {
+      return generator.buildFieldInitializer(initializedFields);
+    }
+    return helper.buildFieldInitializer(
+        false, generator.plainNameForRead, offsetForToken(token), value);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", value: ");
+    printNodeOn(value, sink);
+    sink.write(", assignmentOperator: ");
+    sink.write(assignmentOperator);
+  }
+}
+
+class DelayedPostfixIncrement extends ContextAwareGenerator {
+  final Name binaryOperator;
+
+  final Procedure interfaceTarget;
+
+  DelayedPostfixIncrement(
+      ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+      Token token,
+      Generator generator,
+      this.binaryOperator,
+      this.interfaceTarget)
+      : super(helper, token, generator);
+
+  String get debugName => "DelayedPostfixIncrement";
+
+  Expression buildSimpleRead() {
+    return generator.buildPostfixIncrement(binaryOperator,
+        offset: offsetForToken(token),
+        voidContext: false,
+        interfaceTarget: interfaceTarget);
+  }
+
+  Expression buildForEffect() {
+    return generator.buildPostfixIncrement(binaryOperator,
+        offset: offsetForToken(token),
+        voidContext: true,
+        interfaceTarget: interfaceTarget);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", binaryOperator: ");
+    sink.write(binaryOperator.name);
+    sink.write(", interfaceTarget: ");
+    printQualifiedNameOn(interfaceTarget, sink);
+  }
+}
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 59c4740..36b98a2 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
@@ -34,7 +34,7 @@
         InstrumentationValueForTypeArgs;
 
 import '../fasta_codes.dart'
-    show templateCantUseSuperBoundedTypeForInstanceCreation;
+    show noLength, templateCantUseSuperBoundedTypeForInstanceCreation;
 
 import '../problems.dart' show unhandled, unsupported;
 
@@ -42,6 +42,8 @@
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
+import '../type_inference/inference_helper.dart' show InferenceHelper;
+
 import '../type_inference/interface_resolver.dart' show InterfaceResolver;
 
 import '../type_inference/type_inference_engine.dart'
@@ -67,9 +69,7 @@
 
 import 'body_builder.dart' show combineStatements;
 
-import 'expression_generator.dart' show makeLet;
-
-import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+import 'kernel_expression_generator.dart' show makeLet;
 
 /// Indicates whether type inference involving conditional expressions should
 /// always use least upper bound.
@@ -618,11 +618,11 @@
     if (inferrer.strongMode &&
         !inferrer.isTopLevel &&
         inferrer.typeSchemaEnvironment.isSuperBounded(inferredType)) {
-      inferrer.helper.deprecated_addCompileTimeError(
-          fileOffset,
+      inferrer.helper.addProblem(
           templateCantUseSuperBoundedTypeForInstanceCreation
-              .withArguments(inferredType)
-              .message);
+              .withArguments(inferredType),
+          fileOffset,
+          noLength);
     }
 
     if (isRedirected(this)) {
@@ -2114,8 +2114,7 @@
   }
 
   @override
-  void inferInitializer(
-      ExpressionGeneratorHelper helper, Initializer initializer) {
+  void inferInitializer(InferenceHelper helper, Initializer initializer) {
     assert(initializer is ShadowInitializer);
     this.helper = helper;
     // Use polymorphic dispatch on [KernelInitializer] to perform whatever
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
index a4075e1..787bc90 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -60,9 +60,8 @@
 
   /// Identifier is a formal parameter being declared as part of a function,
   /// method, or typedef declaration.
-  static const formalParameterDeclaration = const IdentifierContext(
-      'formalParameterDeclaration',
-      inDeclaration: true);
+  static const formalParameterDeclaration =
+      const FormalParameterDeclarationIdentifierContext();
 
   /// Identifier is the start of a library name (e.g. `foo` in the directive
   /// 'library foo;`).
@@ -146,15 +145,6 @@
   static const operatorName =
       const MethodDeclarationIdentifierContext.continuation();
 
-  /// Identifier is the name being declared by a local function declaration that
-  /// uses a "get" or "set" keyword.
-  ///
-  /// TODO(paulberry,ahe): Does this ever occur in valid Dart, or does it only
-  /// occur as part of error recovery?  If it's only as part of error recovery,
-  /// perhaps we should just re-use localFunctionDeclaration.
-  static const localAccessorDeclaration =
-      const IdentifierContext('localAccessorDeclaration', inDeclaration: true);
-
   /// Identifier is the start of the name being declared by a local function
   /// declaration.
   static const localFunctionDeclaration =
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
index 2beb97c..18dd095 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
@@ -298,6 +298,39 @@
   }
 }
 
+/// See [IdentifierContext.formalParameterDeclaration].
+class FormalParameterDeclarationIdentifierContext extends IdentifierContext {
+  const FormalParameterDeclarationIdentifierContext()
+      : super('formalParameterDeclaration', inDeclaration: true);
+
+  @override
+  Token ensureIdentifier(Token token, Parser parser) {
+    Token identifier = token.next;
+    assert(identifier.kind != IDENTIFIER_TOKEN);
+    if (identifier.isIdentifier) {
+      return identifier;
+    }
+
+    // Recovery
+    const followingValues = const [':', '=', ',', '(', ')', '[', ']', '{', '}'];
+    if (looksLikeStartOfNextClassMember(identifier) ||
+        looksLikeStartOfNextStatement(identifier) ||
+        isOneOfOrEof(identifier, followingValues)) {
+      identifier = parser.insertSyntheticIdentifier(token, this,
+          message: fasta.templateExpectedIdentifier.withArguments(identifier));
+    } else {
+      parser.reportRecoverableErrorWithToken(
+          identifier, fasta.templateExpectedIdentifier);
+      if (!identifier.isKeywordOrIdentifier) {
+        // When in doubt, consume the token to ensure we make progress
+        // but insert a synthetic identifier to satisfy listeners.
+        identifier = parser.rewriter.insertSyntheticIdentifier(identifier);
+      }
+    }
+    return identifier;
+  }
+}
+
 /// See [IdentifierContext.importPrefixDeclaration].
 class ImportPrefixIdentifierContext extends IdentifierContext {
   const ImportPrefixIdentifierContext()
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index fc82a91..0b81640 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -21,6 +21,7 @@
         Keyword,
         POSTFIX_PRECEDENCE,
         RELATIONAL_PRECEDENCE,
+        SELECTOR_PRECEDENCE,
         SyntheticBeginToken,
         SyntheticKeywordToken,
         SyntheticStringToken,
@@ -1195,12 +1196,25 @@
       }
       token = parseFormalParameter(token, FormalParameterKind.mandatory, kind);
       next = token.next;
-      if (optional(',', next)) {
-        token = next;
-        continue;
+      if (!optional(',', next)) {
+        Token next = token.next;
+        if (optional(')', next)) {
+          token = next;
+        } else {
+          // Recovery
+          if (begin.endGroup.isSynthetic) {
+            // Scanner has already reported a missing `)` error,
+            // but placed the `)` in the wrong location, so move it.
+            token = rewriter.moveSynthetic(token, begin.endGroup);
+          } else {
+            reportRecoverableError(
+                next, fasta.templateExpectedButGot.withArguments(')'));
+            token = begin.endGroup;
+          }
+        }
+        break;
       }
-      token = ensureCloseParen(token, begin);
-      break;
+      token = next;
     }
     assert(optional(')', token));
     listener.endFormalParameters(parameterCount, begin, token, kind);
@@ -2013,15 +2027,11 @@
       followingValues = [';'];
     } else if (context == IdentifierContext.constructorReferenceContinuation) {
       followingValues = ['.', ',', '(', ')', '[', ']', '}', ';'];
-    } else if (context == IdentifierContext.formalParameterDeclaration) {
-      followingValues = [':', '=', ',', '(', ')', '[', ']', '{', '}'];
     } else if (context == IdentifierContext.labelDeclaration) {
       followingValues = [':'];
     } else if (context == IdentifierContext.literalSymbol ||
         context == IdentifierContext.literalSymbolContinuation) {
       followingValues = ['.', ';'];
-    } else if (context == IdentifierContext.localAccessorDeclaration) {
-      followingValues = ['(', '{', '=>'];
     } else {
       return false;
     }
@@ -2041,8 +2051,6 @@
       return false;
     }
 
-    List<String> classMemberKeywords() =>
-        <String>['const', 'final', 'var', 'void'];
     List<String> statementKeywords() => <String>[
           'const',
           'do',
@@ -2054,19 +2062,6 @@
           'void',
           'while'
         ];
-    List<String> topLevelKeywords() => <String>[
-          'class',
-          'const',
-          'enum',
-          'export',
-          'final',
-          'import',
-          'library',
-          'part',
-          'typedef',
-          'var',
-          'void'
-        ];
 
     // TODO(brianwilkerson): At the moment, this test is entirely based on data
     // that can be represented declaratively. If that proves to be sufficient,
@@ -2074,14 +2069,7 @@
     // could create a method to test whether a given token matches one of the
     // patterns.
     List<String> initialKeywords;
-    if (context == IdentifierContext.formalParameterDeclaration) {
-      initialKeywords = topLevelKeywords()
-        ..addAll(classMemberKeywords())
-        ..addAll(statementKeywords())
-        ..add('covariant');
-    } else if (context == IdentifierContext.labelDeclaration) {
-      initialKeywords = statementKeywords();
-    } else if (context == IdentifierContext.localAccessorDeclaration) {
+    if (context == IdentifierContext.labelDeclaration) {
       initialKeywords = statementKeywords();
     } else if (context ==
         IdentifierContext.localFunctionDeclarationContinuation) {
@@ -2301,32 +2289,6 @@
       return token;
     }
 
-    /// Returns true if [token] could be the start of a function body.
-    bool looksLikeFunctionBody(Token token) {
-      return optional('{', token) ||
-          optional('=>', token) ||
-          optional('async', token) ||
-          optional('sync', token);
-    }
-
-    /// Returns true if [token] could be the start of a function declaration
-    /// without a return type.
-    bool looksLikeFunctionDeclaration(Token token) {
-      if (!token.isIdentifier) {
-        return false;
-      }
-      token = token.next;
-      if (optional('<', token)) {
-        Token closeBrace = token.endGroup;
-        if (closeBrace == null) return false;
-        token = closeBrace.next;
-      }
-      if (optional('(', token)) {
-        return looksLikeFunctionBody(token.endGroup.next);
-      }
-      return false;
-    }
-
     switch (continuation) {
       case TypeContinuation.Required:
         // If the token after the type is not an identifier,
@@ -2364,41 +2326,6 @@
       case TypeContinuation.OptionalAfterVar:
         hasVar = true;
         continue optional;
-
-      case TypeContinuation.SendOrFunctionLiteral:
-        Token beforeName;
-        Token name;
-        bool hasReturnType;
-        if (looksLikeType && looksLikeFunctionDeclaration(token)) {
-          beforeName = beforeToken;
-          name = token;
-          hasReturnType = true;
-          // Fall-through to parseNamedFunctionRest below.
-        } else if (looksLikeFunctionDeclaration(begin)) {
-          beforeName = beforeBegin;
-          name = begin;
-          hasReturnType = false;
-          // Fall-through to parseNamedFunctionRest below.
-        } else {
-          return parseSend(beforeBegin, continuationContext);
-        }
-
-        Token formals = parseTypeVariablesOpt(name);
-        listener.beginNamedFunctionExpression(begin);
-        if (hasReturnType) {
-          if (voidToken != null) {
-            listener.handleVoidKeyword(voidToken);
-          } else {
-            commitType();
-          }
-          reportRecoverableError(
-              begin, fasta.messageReturnTypeFunctionExpression);
-        } else {
-          listener.handleNoType(formals);
-        }
-        if (beforeName.next != name)
-          throw new StateError("beforeName.next != name");
-        return parseNamedFunctionRest(beforeName, begin, formals, true);
     }
 
     throw "Internal error: Unhandled continuation '$continuation'.";
@@ -3494,6 +3421,16 @@
     return token;
   }
 
+  Token parseFunctionLiteral(
+      final Token start, TypeInfo typeInfo, IdentifierContext context) {
+    Token beforeName = typeInfo.skipType(start);
+    assert(beforeName.next.isIdentifier);
+    Token formals = parseTypeVariablesOpt(beforeName.next);
+    listener.beginNamedFunctionExpression(start.next);
+    typeInfo.parseType(start, this);
+    return parseNamedFunctionRest(beforeName, start.next, formals, true);
+  }
+
   /// Parses the rest of a named function declaration starting from its [name]
   /// but then skips any type parameters and continue parsing from [formals]
   /// (the formal parameters).
@@ -4027,7 +3964,7 @@
   Token parsePrecedenceExpression(
       Token token, int precedence, bool allowCascades) {
     assert(precedence >= 1);
-    assert(precedence <= POSTFIX_PRECEDENCE);
+    assert(precedence <= SELECTOR_PRECEDENCE);
     token = parseUnaryExpression(token, allowCascades);
     Token next = token.next;
     TokenType type = next.type;
@@ -4058,10 +3995,16 @@
           token = parsePrecedenceExpression(token.next, level, allowCascades);
           listener.handleAssignmentExpression(operator);
         } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
+          if ((identical(type, TokenType.PLUS_PLUS)) ||
+              (identical(type, TokenType.MINUS_MINUS))) {
+            listener.handleUnaryPostfixAssignmentExpression(token.next);
+            token = next;
+          }
+        } else if (identical(tokenLevel, SELECTOR_PRECEDENCE)) {
           if (identical(type, TokenType.PERIOD) ||
               identical(type, TokenType.QUESTION_PERIOD)) {
             // Left associative, so we recurse at the next higher precedence
-            // level. However, POSTFIX_PRECEDENCE is the highest level, so we
+            // level. However, SELECTOR_PRECEDENCE is the highest level, so we
             // should just call [parseUnaryExpression] directly. However, a
             // unary expression isn't legal after a period, so we call
             // [parsePrimary] instead.
@@ -4072,10 +4015,6 @@
               (identical(type, TokenType.OPEN_SQUARE_BRACKET))) {
             token = parseArgumentOrIndexStar(token, typeArguments);
             next = token.next;
-          } else if ((identical(type, TokenType.PLUS_PLUS)) ||
-              (identical(type, TokenType.MINUS_MINUS))) {
-            listener.handleUnaryPostfixAssignmentExpression(token.next);
-            token = next;
           } else if (identical(type, TokenType.INDEX)) {
             BeginToken replacement = link(
                 new BeginToken(TokenType.OPEN_SQUARE_BRACKET, next.charOffset,
@@ -4605,9 +4544,12 @@
   Token parseSendOrFunctionLiteral(Token token, IdentifierContext context) {
     if (!mayParseFunctionExpressions) {
       return parseSend(token, context);
-    } else {
-      return parseType(token, TypeContinuation.SendOrFunctionLiteral, context);
     }
+    TypeInfo typeInfo = computeType(token, false);
+    if (!looksLikeFunctionDeclaration(typeInfo.skipType(token).next)) {
+      return parseSend(token, context);
+    }
+    return parseFunctionLiteral(token, typeInfo, context);
   }
 
   Token parseRequiredArguments(Token token) {
@@ -5019,6 +4961,32 @@
     return false;
   }
 
+  /// Returns true if [token] could be the start of a function body.
+  bool looksLikeFunctionBody(Token token) {
+    return optional('{', token) ||
+        optional('=>', token) ||
+        optional('async', token) ||
+        optional('sync', token);
+  }
+
+  /// Returns true if [token] could be the start of a function declaration
+  /// without a return type.
+  bool looksLikeFunctionDeclaration(Token token) {
+    if (!token.isIdentifier) {
+      return false;
+    }
+    token = token.next;
+    if (optional('<', token)) {
+      Token closeBrace = token.endGroup;
+      if (closeBrace == null) return false;
+      token = closeBrace.next;
+    }
+    if (optional('(', token)) {
+      return looksLikeFunctionBody(token.endGroup.next);
+    }
+    return false;
+  }
+
   Token parseExpressionStatementOrConstDeclaration(final Token start) {
     Token constToken = start.next;
     assert(optional('const', constToken));
@@ -5113,7 +5081,8 @@
         listener.beginMetadataStar(start.next);
         listener.endMetadataStar(0);
       }
-      Token beforeFormals = parseTypeVariablesOpt(next);
+      Token beforeFormals =
+          computeTypeParamOrArg(next).parseVariables(next, this);
       listener.beginLocalFunctionDeclaration(start.next);
       token = typeInfo.parseType(beforeType, this);
       next = token.next;
diff --git a/pkg/front_end/lib/src/fasta/parser/type_continuation.dart b/pkg/front_end/lib/src/fasta/parser/type_continuation.dart
index 1f317ab..32effd3 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_continuation.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_continuation.dart
@@ -24,8 +24,4 @@
 
   /// Same as [Optional], but we have seen `var`.
   OptionalAfterVar,
-
-  /// Indicates that the parser is parsing an expression and has just seen an
-  /// identifier.
-  SendOrFunctionLiteral,
 }
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 71ae91c..b4639f1 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -5,8 +5,15 @@
 library fasta.diet_listener;
 
 import 'package:kernel/ast.dart'
-    show AsyncMarker, Class, InterfaceType, Typedef;
-import 'package:kernel/ast.dart';
+    show
+        AsyncMarker,
+        Class,
+        Expression,
+        InterfaceType,
+        Library,
+        LibraryDependency,
+        LibraryPart,
+        Typedef;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 1a2fa07..8244fca 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -62,7 +62,7 @@
 
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 
-import 'unhandled_listener.dart' show NullValue, UnhandledListener;
+import 'stack_listener.dart' show NullValue, StackListener;
 
 import '../configuration.dart' show Configuration;
 
@@ -72,7 +72,7 @@
   RedirectingFactoryBody,
 }
 
-class OutlineBuilder extends UnhandledListener {
+class OutlineBuilder extends StackListener {
   final SourceLibraryBuilder library;
 
   final bool enableNative;
@@ -90,7 +90,6 @@
   @override
   Uri get uri => library.fileUri;
 
-  @override
   int popCharOffset() => pop();
 
   List<String> popIdentifierList(int count) {
diff --git a/pkg/front_end/lib/src/fasta/source/scope_listener.dart b/pkg/front_end/lib/src/fasta/source/scope_listener.dart
index 5bb4fa0..e9a61e3 100644
--- a/pkg/front_end/lib/src/fasta/source/scope_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/scope_listener.dart
@@ -6,11 +6,11 @@
 
 import '../../scanner/token.dart' show Token;
 
-import 'unhandled_listener.dart' show NullValue, UnhandledListener;
-
 import '../scope.dart' show Scope;
 
-export 'unhandled_listener.dart' show NullValue, Unhandled;
+import 'stack_listener.dart' show NullValue, StackListener;
+
+export 'stack_listener.dart' show NullValue;
 
 enum JumpTargetKind {
   Break,
@@ -18,7 +18,7 @@
   Goto, // Continue label in switch.
 }
 
-abstract class ScopeListener<J> extends UnhandledListener {
+abstract class ScopeListener<J> extends StackListener {
   Scope scope;
 
   J breakTarget;
diff --git a/pkg/front_end/lib/src/fasta/source/stack_listener.dart b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
index f312680..ef9eda1 100644
--- a/pkg/front_end/lib/src/fasta/source/stack_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
@@ -111,7 +111,7 @@
     if (tokenOrNull == null) stack.push(nullValue);
   }
 
-  Object peek() => stack.last;
+  Object peek() => stack.isNotEmpty ? stack.last : null;
 
   Object pop([NullValue nullValue]) {
     return stack.pop(nullValue);
diff --git a/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart b/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart
deleted file mode 100644
index c678a477..0000000
--- a/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library fasta.unhandled_listener;
-
-import '../../scanner/token.dart' show Token;
-
-import 'stack_listener.dart' show NullValue, StackListener;
-
-export 'stack_listener.dart' show NullValue;
-
-// TODO(ahe): Get rid of this.
-enum Unhandled {
-  ConditionalUri,
-  ConditionalUris,
-  DottedName,
-  Hide,
-  Initializers,
-  Interpolation,
-  Metadata,
-  Show,
-  TypeVariables,
-}
-
-// TODO(ahe): Get rid of this class when all listeners are complete.
-abstract class UnhandledListener extends StackListener {
-  int popCharOffset() => -1;
-
-  List<String> popIdentifierList(int count) => popList(count);
-
-  @override
-  void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) {
-    debugEvent("ConditionalUri");
-    popCharOffset();
-    pop(); // URI.
-    if (equalSign != null) popCharOffset();
-    popIfNotNull(equalSign); // String.
-    pop(); // DottedName.
-    push(Unhandled.ConditionalUri);
-  }
-
-  @override
-  void endConditionalUris(int count) {
-    debugEvent("ConditionalUris");
-    popList(count);
-    push(Unhandled.ConditionalUris);
-  }
-
-  @override
-  void endHide(Token hideKeyword) {
-    debugEvent("Hide");
-    pop();
-    push(Unhandled.Hide);
-  }
-
-  @override
-  void endShow(Token showKeyword) {
-    debugEvent("Show");
-    pop();
-    push(Unhandled.Show);
-  }
-
-  @override
-  void endCombinators(int count) {
-    debugEvent("Combinators");
-    push(popList(count) ?? NullValue.Combinators);
-  }
-
-  @override
-  void handleDottedName(int count, Token firstIdentifier) {
-    debugEvent("DottedName");
-    popIdentifierList(count);
-    push(Unhandled.DottedName);
-  }
-
-  @override
-  void endFunctionType(Token functionToken, Token endToken) {
-    pop(); // Formals.
-    pop(); // Return type.
-    pop(); // Type variables.
-    push(NullValue.Type);
-  }
-}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
new file mode 100644
index 0000000..d7c29df
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart' show FunctionType;
+
+import '../fasta_codes.dart' show LocatedMessage, Message;
+
+abstract class InferenceHelper<Expression, Statement, Arguments> {
+  Expression wrapInCompileTimeError(Expression expression, Message message);
+
+  Expression buildCompileTimeError(Message message, int charOffset, int length,
+      {List<LocatedMessage> context});
+
+  LocatedMessage checkArgumentsForType(
+      FunctionType function, Arguments arguments, int offset);
+
+  void addProblem(Message message, int charOffset, int length);
+}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 9237dcd..58c6532 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
@@ -62,10 +62,7 @@
 
 import '../fasta_codes.dart';
 
-import '../kernel/expression_generator.dart' show buildIsNull;
-
-import '../kernel/expression_generator_helper.dart'
-    show ExpressionGeneratorHelper;
+import '../kernel/kernel_expression_generator.dart' show buildIsNull;
 
 import '../kernel/kernel_shadow_ast.dart'
     show
@@ -85,6 +82,8 @@
 
 import '../source/source_loader.dart' show SourceLoader;
 
+import 'inference_helper.dart' show InferenceHelper;
+
 import 'interface_resolver.dart' show ForwardingNode, SyntheticAccessor;
 
 import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
@@ -324,20 +323,18 @@
   Uri get uri;
 
   /// Performs full type inference on the given field initializer.
-  void inferFieldInitializer(ExpressionGeneratorHelper helper,
-      DartType declaredType, Expression initializer);
+  void inferFieldInitializer(
+      InferenceHelper helper, DartType declaredType, Expression initializer);
 
   /// Performs type inference on the given function body.
-  void inferFunctionBody(ExpressionGeneratorHelper helper, DartType returnType,
+  void inferFunctionBody(InferenceHelper helper, DartType returnType,
       AsyncMarker asyncMarker, Statement body);
 
   /// Performs type inference on the given constructor initializer.
-  void inferInitializer(
-      ExpressionGeneratorHelper helper, Initializer initializer);
+  void inferInitializer(InferenceHelper helper, Initializer initializer);
 
   /// Performs type inference on the given metadata annotations.
-  void inferMetadata(
-      ExpressionGeneratorHelper helper, List<Expression> annotations);
+  void inferMetadata(InferenceHelper helper, List<Expression> annotations);
 
   /// Performs type inference on the given metadata annotations keeping the
   /// existing helper if possible.
@@ -345,8 +342,8 @@
 
   /// Performs type inference on the given function parameter initializer
   /// expression.
-  void inferParameterInitializer(ExpressionGeneratorHelper helper,
-      Expression initializer, DartType declaredType);
+  void inferParameterInitializer(
+      InferenceHelper helper, Expression initializer, DartType declaredType);
 }
 
 /// Implementation of [TypeInferrer] which doesn't do any type inference.
@@ -366,27 +363,25 @@
   Uri get uri => null;
 
   @override
-  void inferFieldInitializer(ExpressionGeneratorHelper helper,
-      DartType declaredType, Expression initializer) {}
+  void inferFieldInitializer(
+      InferenceHelper helper, DartType declaredType, Expression initializer) {}
 
   @override
-  void inferFunctionBody(ExpressionGeneratorHelper helper, DartType returnType,
+  void inferFunctionBody(InferenceHelper helper, DartType returnType,
       AsyncMarker asyncMarker, Statement body) {}
 
   @override
-  void inferInitializer(
-      ExpressionGeneratorHelper helper, Initializer initializer) {}
+  void inferInitializer(InferenceHelper helper, Initializer initializer) {}
 
   @override
-  void inferMetadata(
-      ExpressionGeneratorHelper helper, List<Expression> annotations) {}
+  void inferMetadata(InferenceHelper helper, List<Expression> annotations) {}
 
   @override
   void inferMetadataKeepingHelper(List<Expression> annotations) {}
 
   @override
-  void inferParameterInitializer(ExpressionGeneratorHelper helper,
-      Expression initializer, DartType declaredType) {}
+  void inferParameterInitializer(
+      InferenceHelper helper, Expression initializer, DartType declaredType) {}
 }
 
 /// Derived class containing generic implementations of [TypeInferrer].
@@ -424,7 +419,7 @@
 
   final SourceLibraryBuilder library;
 
-  ExpressionGeneratorHelper helper;
+  InferenceHelper helper;
 
   /// Context information for the current closure, or `null` if we are not
   /// inside a closure.
@@ -930,8 +925,8 @@
       Expression expression, DartType typeContext, bool typeNeeded);
 
   @override
-  void inferFieldInitializer(ExpressionGeneratorHelper helper,
-      DartType declaredType, Expression initializer) {
+  void inferFieldInitializer(
+      InferenceHelper helper, DartType declaredType, Expression initializer) {
     assert(closureContext == null);
     this.helper = helper;
     var actualType = inferExpression(
@@ -950,7 +945,7 @@
   DartType inferFieldTopLevel(ShadowField field, bool typeNeeded);
 
   @override
-  void inferFunctionBody(ExpressionGeneratorHelper helper, DartType returnType,
+  void inferFunctionBody(InferenceHelper helper, DartType returnType,
       AsyncMarker asyncMarker, Statement body) {
     assert(closureContext == null);
     this.helper = helper;
@@ -1243,8 +1238,7 @@
   }
 
   @override
-  void inferMetadata(
-      ExpressionGeneratorHelper helper, List<Expression> annotations) {
+  void inferMetadata(InferenceHelper helper, List<Expression> annotations) {
     if (annotations != null) {
       this.helper = helper;
       inferMetadataKeepingHelper(annotations);
@@ -1326,8 +1320,8 @@
   }
 
   @override
-  void inferParameterInitializer(ExpressionGeneratorHelper helper,
-      Expression initializer, DartType declaredType) {
+  void inferParameterInitializer(
+      InferenceHelper helper, Expression initializer, DartType declaredType) {
     assert(closureContext == null);
     this.helper = helper;
     assert(declaredType != null);
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index 7842a42..3543578 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -29,6 +29,7 @@
 const int MULTIPLICATIVE_PRECEDENCE = 14;
 const int PREFIX_PRECEDENCE = 15;
 const int POSTFIX_PRECEDENCE = 16;
+const int SELECTOR_PRECEDENCE = 17;
 
 /**
  * The opening half of a grouping pair of tokens. This is used for curly
@@ -1289,7 +1290,7 @@
       const TokenType('#', 'HASH', NO_PRECEDENCE, HASH_TOKEN);
 
   static const TokenType INDEX = const TokenType(
-      '[]', 'INDEX', POSTFIX_PRECEDENCE, INDEX_TOKEN,
+      '[]', 'INDEX', SELECTOR_PRECEDENCE, INDEX_TOKEN,
       isOperator: true, isUserDefinableOperator: true);
 
   static const TokenType INDEX_EQ = const TokenType(
@@ -1328,10 +1329,10 @@
       '{', 'OPEN_CURLY_BRACKET', NO_PRECEDENCE, OPEN_CURLY_BRACKET_TOKEN);
 
   static const TokenType OPEN_PAREN =
-      const TokenType('(', 'OPEN_PAREN', POSTFIX_PRECEDENCE, OPEN_PAREN_TOKEN);
+      const TokenType('(', 'OPEN_PAREN', SELECTOR_PRECEDENCE, OPEN_PAREN_TOKEN);
 
   static const TokenType OPEN_SQUARE_BRACKET = const TokenType('[',
-      'OPEN_SQUARE_BRACKET', POSTFIX_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN);
+      'OPEN_SQUARE_BRACKET', SELECTOR_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN);
 
   static const TokenType PERCENT = const TokenType(
       '%', 'PERCENT', MULTIPLICATIVE_PRECEDENCE, PERCENT_TOKEN,
@@ -1342,7 +1343,7 @@
       isOperator: true);
 
   static const TokenType PERIOD =
-      const TokenType('.', 'PERIOD', POSTFIX_PRECEDENCE, PERIOD_TOKEN);
+      const TokenType('.', 'PERIOD', SELECTOR_PRECEDENCE, PERIOD_TOKEN);
 
   static const TokenType PERIOD_PERIOD = const TokenType(
       '..', 'PERIOD_PERIOD', CASCADE_PRECEDENCE, PERIOD_PERIOD_TOKEN,
@@ -1365,7 +1366,7 @@
       isOperator: true);
 
   static const TokenType QUESTION_PERIOD = const TokenType(
-      '?.', 'QUESTION_PERIOD', POSTFIX_PRECEDENCE, QUESTION_PERIOD_TOKEN,
+      '?.', 'QUESTION_PERIOD', SELECTOR_PRECEDENCE, QUESTION_PERIOD_TOKEN,
       isOperator: true);
 
   static const TokenType QUESTION_QUESTION = const TokenType(
@@ -1700,6 +1701,12 @@
       this == TokenType.PLUS_PLUS ||
       this == TokenType.MINUS_MINUS;
 
+  /**
+   * Return `true` if this type of token represents a selector operator
+   * (starting token of a selector).
+   */
+  bool get isSelectorOperator => precedence == SELECTOR_PRECEDENCE;
+
   @override
   String toString() => name;
 
diff --git a/pkg/front_end/test/dependency_grapher_test.dart b/pkg/front_end/test/dependency_grapher_test.dart
deleted file mode 100644
index 4d7e981..0000000
--- a/pkg/front_end/test/dependency_grapher_test.dart
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/api_prototype/dependency_grapher.dart';
-import 'package:front_end/src/api_prototype/memory_file_system.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(DependencyGrapherTest);
-  });
-}
-
-final root = Uri.parse('org-dartlang-test:///');
-
-@reflectiveTest
-class DependencyGrapherTest {
-  LibraryNode checkLibrary(LibraryCycleNode cycle, String uri,
-      {List<String> dependencies: const ['dart:core'],
-      List<String> parts: const []}) {
-    var library = cycle.libraries[Uri.parse(uri)];
-    expect('${library.uri}', uri);
-    expect(library.dependencies.map((dep) => '${dep.uri}'),
-        unorderedEquals(dependencies));
-    expect(library.parts.map((part) => '$part'), unorderedEquals(parts));
-    return library;
-  }
-
-  Future<List<LibraryCycleNode>> getCycles(Map<String, String> contents,
-      {List<String> startingPoints, String packagesFilePath}) async {
-    // If no starting points given, assume the first entry in [contents] is the
-    // single starting point.
-    startingPoints ??= [contents.keys.first];
-    var fileSystem = new MemoryFileSystem(root);
-    if (packagesFilePath == null) {
-      fileSystem.entityForUri(Uri.parse('.packages')).writeAsStringSync('');
-    }
-    contents.forEach((path, text) {
-      fileSystem.entityForUri(root.resolve(path)).writeAsStringSync(text);
-    });
-    // TODO(paulberry): implement and test other option possibilities.
-    var options = new CompilerOptions()
-      ..fileSystem = fileSystem
-      ..chaseDependencies = true
-      ..packagesFileUri = packagesFilePath == null
-          ? Uri.parse('.packages')
-          : root.resolve(packagesFilePath);
-    var graph = await graphForProgram(
-        startingPoints.map(root.resolve).toList(), options);
-    return graph.topologicallySortedCycles;
-  }
-
-  /// Sort the given library cycles into a deterministic order based on their
-  /// URIs for easier unit testing.
-  List<LibraryCycleNode> sortCycles(Iterable<LibraryCycleNode> cycles) {
-    var result = cycles.toList();
-    String sortKey(LibraryCycleNode node) => node.libraries.keys.join(',');
-    result.sort((a, b) => Comparable.compare(sortKey(a), sortKey(b)));
-    return result;
-  }
-
-  test_explicitCoreDependency() async {
-    // If "dart:core" is explicitly imported, there shouldn't be two imports of
-    // "dart:core", just one.
-    var cycles = await getCycles({'/foo.dart': 'import "dart:core";'});
-    expect(cycles, hasLength(1));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart');
-  }
-
-  test_exportDependency() async {
-    var cycles =
-        await getCycles({'/foo.dart': 'export "bar.dart";', '/bar.dart': ''});
-    expect(cycles, hasLength(2));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///bar.dart');
-    expect(cycles[1].libraries, hasLength(1));
-    checkLibrary(cycles[1], 'org-dartlang-test:///foo.dart',
-        dependencies: ['org-dartlang-test:///bar.dart', 'dart:core']);
-  }
-
-  test_importDependency() async {
-    var cycles =
-        await getCycles({'/foo.dart': 'import "bar.dart";', '/bar.dart': ''});
-    expect(cycles, hasLength(2));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///bar.dart');
-    expect(cycles[1].libraries, hasLength(1));
-    checkLibrary(cycles[1], 'org-dartlang-test:///foo.dart',
-        dependencies: ['org-dartlang-test:///bar.dart', 'dart:core']);
-  }
-
-  test_multipleStartingPoints() async {
-    var cycles = await getCycles({
-      '/a.dart': 'import "c.dart";',
-      '/b.dart': 'import "c.dart";',
-      '/c.dart': ''
-    }, startingPoints: [
-      '/a.dart',
-      '/b.dart'
-    ]);
-    expect(cycles, hasLength(3));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///c.dart');
-    // The other two cycles might be in any order, so sort them for
-    // reproducibility.
-    List<LibraryCycleNode> otherCycles = sortCycles(cycles.sublist(1));
-    checkLibrary(otherCycles[0], 'org-dartlang-test:///a.dart',
-        dependencies: ['org-dartlang-test:///c.dart', 'dart:core']);
-    checkLibrary(otherCycles[1], 'org-dartlang-test:///b.dart',
-        dependencies: ['org-dartlang-test:///c.dart', 'dart:core']);
-  }
-
-  test_packages() async {
-    var cycles = await getCycles({
-      '/foo.dart': 'import "package:foo/bar.dart";',
-      '/.packages': 'foo:pkg/foo/lib\nbar:pkg/bar/lib\n',
-      '/pkg/foo/lib/bar.dart': 'import "package:bar/baz.dart";',
-      '/pkg/bar/lib/baz.dart': ''
-    }, packagesFilePath: '/.packages');
-    expect(cycles, hasLength(3));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'package:bar/baz.dart');
-    expect(cycles[1].libraries, hasLength(1));
-    checkLibrary(cycles[1], 'package:foo/bar.dart',
-        dependencies: ['package:bar/baz.dart', 'dart:core']);
-    expect(cycles[2].libraries, hasLength(1));
-    checkLibrary(cycles[2], 'org-dartlang-test:///foo.dart',
-        dependencies: ['package:foo/bar.dart', 'dart:core']);
-  }
-
-  test_parts() async {
-    var cycles = await getCycles({
-      '/foo.dart': 'library foo; part "a.dart"; part "b.dart";',
-      '/a.dart': 'part of foo;',
-      '/b.dart': 'part of foo;'
-    });
-    expect(cycles, hasLength(1));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart',
-        parts: ['org-dartlang-test:///a.dart', 'org-dartlang-test:///b.dart']);
-  }
-
-  test_relativeUris() async {
-    var cycles = await getCycles({
-      '/a.dart': 'import "b/c.dart";',
-      '/b/c.dart': 'import "d/e.dart";',
-      '/b/d/e.dart': 'import "../f.dart";',
-      '/b/f.dart': ''
-    });
-    expect(cycles, hasLength(4));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///b/f.dart');
-    expect(cycles[1].libraries, hasLength(1));
-    checkLibrary(cycles[1], 'org-dartlang-test:///b/d/e.dart',
-        dependencies: ['org-dartlang-test:///b/f.dart', 'dart:core']);
-    expect(cycles[2].libraries, hasLength(1));
-    checkLibrary(cycles[2], 'org-dartlang-test:///b/c.dart',
-        dependencies: ['org-dartlang-test:///b/d/e.dart', 'dart:core']);
-    expect(cycles[3].libraries, hasLength(1));
-    checkLibrary(cycles[3], 'org-dartlang-test:///a.dart',
-        dependencies: ['org-dartlang-test:///b/c.dart', 'dart:core']);
-  }
-
-  test_sdkDependency() async {
-    // Dependencies on the SDK should be recorded even if SDK libraries aren't
-    // being included in the graph.
-    var cycles = await getCycles({'/foo.dart': 'import "dart:async";'});
-    expect(cycles, hasLength(1));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart',
-        dependencies: ['dart:core', 'dart:async']);
-  }
-
-  test_simpleCycle() async {
-    var cycles = await getCycles(
-        {'/foo.dart': 'import "bar.dart";', '/bar.dart': 'import "foo.dart";'});
-    expect(cycles, hasLength(1));
-    expect(cycles[0].libraries, hasLength(2));
-    var foo = checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart',
-        dependencies: ['org-dartlang-test:///bar.dart', 'dart:core']);
-    var bar = checkLibrary(cycles[0], 'org-dartlang-test:///bar.dart',
-        dependencies: ['org-dartlang-test:///foo.dart', 'dart:core']);
-    expect(foo.dependencies[0], same(bar));
-    expect(bar.dependencies[0], same(foo));
-  }
-
-  test_singleFile() async {
-    var cycles = await getCycles({'/foo.dart': ''});
-    expect(cycles, hasLength(1));
-    expect(cycles[0].libraries, hasLength(1));
-    checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart');
-  }
-}
diff --git a/pkg/front_end/test/fasta/generator_to_string_test.dart b/pkg/front_end/test/fasta/generator_to_string_test.dart
index e228c60..53b70fe 100644
--- a/pkg/front_end/test/fasta/generator_to_string_test.dart
+++ b/pkg/front_end/test/fasta/generator_to_string_test.dart
@@ -18,6 +18,7 @@
         Name,
         Procedure,
         ProcedureKind,
+        Statement,
         StringLiteral,
         TypeParameter,
         VariableDeclaration,
@@ -45,38 +46,40 @@
     show Message, templateUnspecified;
 
 import 'package:front_end/src/fasta/kernel/expression_generator.dart'
-    show
-        DeferredAccessGenerator,
-        Generator,
-        IncompleteErrorGenerator,
-        IncompletePropertyAccessGenerator,
-        IndexedAccessGenerator,
-        LargeIntAccessGenerator,
-        LoadLibraryGenerator,
-        NullAwarePropertyAccessGenerator,
-        ParenthesizedExpressionGenerator,
-        PropertyAccessGenerator,
-        ReadOnlyAccessGenerator,
-        SendAccessGenerator,
-        StaticAccessGenerator,
-        SuperIndexedAccessGenerator,
-        SuperPropertyAccessGenerator,
-        ThisAccessGenerator,
-        ThisIndexedAccessGenerator,
-        ThisPropertyAccessGenerator,
-        TypeDeclarationAccessGenerator,
-        UnresolvedNameGenerator,
-        VariableUseGenerator;
-
-import 'package:front_end/src/fasta/kernel/body_builder.dart'
-    show DelayedAssignment, DelayedPostfixIncrement;
+    show Generator;
 
 import 'package:front_end/src/fasta/kernel/kernel_body_builder.dart'
     show KernelBodyBuilder;
 
+import 'package:front_end/src/fasta/kernel/kernel_expression_generator.dart'
+    show
+        DeferredAccessGenerator,
+        DelayedAssignment,
+        DelayedPostfixIncrement,
+        IncompleteErrorGenerator,
+        IncompletePropertyAccessGenerator,
+        KernelIndexedAccessGenerator,
+        KernelNullAwarePropertyAccessGenerator,
+        KernelPropertyAccessGenerator,
+        KernelSuperPropertyAccessGenerator,
+        KernelThisIndexedAccessGenerator,
+        KernelThisPropertyAccessGenerator,
+        KernelVariableUseGenerator,
+        LargeIntAccessGenerator,
+        LoadLibraryGenerator,
+        ParenthesizedExpressionGenerator,
+        ReadOnlyAccessGenerator,
+        SendAccessGenerator,
+        StaticAccessGenerator,
+        SuperIndexedAccessGenerator,
+        ThisAccessGenerator,
+        TypeDeclarationAccessGenerator,
+        UnresolvedNameGenerator;
+
 import 'package:front_end/src/fasta/scanner.dart' show Token, scanString;
 
-void check(String expected, Generator<Arguments> generator) {
+void check(
+    String expected, Generator<Expression, Statement, Arguments> generator) {
   Expect.stringEquals(expected, "$generator");
 }
 
@@ -123,8 +126,7 @@
     KernelBodyBuilder helper = new KernelBodyBuilder(
         libraryBuilder, null, null, null, null, null, null, false, uri, null);
 
-    Generator generator =
-        new ThisAccessGenerator<Arguments>(helper, token, false);
+    Generator generator = new ThisAccessGenerator(helper, token, false);
 
     Library library = new Library(uri);
     Class cls = new Class();
@@ -136,98 +138,94 @@
     check(
         "DelayedAssignment(offset: 4, value: expression,"
         " assignmentOperator: +=)",
-        new DelayedAssignment<Arguments>(
+        new DelayedAssignment(
             helper, token, generator, expression, assignmentOperator));
     check(
         "DelayedPostfixIncrement(offset: 4, binaryOperator: +,"
         " interfaceTarget: $uri::#class1::myInterfaceTarget)",
-        new DelayedPostfixIncrement<Arguments>(
+        new DelayedPostfixIncrement(
             helper, token, generator, binaryOperator, interfaceTarget));
     check(
         "VariableUseGenerator(offset: 4, variable: dynamic #t1;\n,"
         " promotedType: void)",
-        new VariableUseGenerator<Arguments>(helper, token, variable, type));
+        new KernelVariableUseGenerator(helper, token, variable, type));
     check(
         "PropertyAccessGenerator(offset: 4, _receiverVariable: null,"
         " receiver: expression, name: bar, getter: $uri::myGetter,"
         " setter: $uri::mySetter)",
-        new PropertyAccessGenerator<Arguments>.internal(
+        new KernelPropertyAccessGenerator.internal(
             helper, token, expression, name, getter, setter));
     check(
         "ThisPropertyAccessGenerator(offset: 4, name: bar,"
         " getter: $uri::myGetter, setter: $uri::mySetter)",
-        new ThisPropertyAccessGenerator<Arguments>(
+        new KernelThisPropertyAccessGenerator(
             helper, token, name, getter, setter));
     check(
         "NullAwarePropertyAccessGenerator(offset: 4,"
         " receiver: final dynamic #t1 = expression;\n,"
         " receiverExpression: expression, name: bar, getter: $uri::myGetter,"
         " setter: $uri::mySetter, type: void)",
-        new NullAwarePropertyAccessGenerator<Arguments>(
+        new KernelNullAwarePropertyAccessGenerator(
             helper, token, expression, name, getter, setter, type));
     check(
         "SuperPropertyAccessGenerator(offset: 4, name: bar,"
         " getter: $uri::myGetter, setter: $uri::mySetter)",
-        new SuperPropertyAccessGenerator<Arguments>(
+        new KernelSuperPropertyAccessGenerator(
             helper, token, name, getter, setter));
     check(
         "IndexedAccessGenerator(offset: 4, receiver: expression, index: index,"
         " getter: $uri::myGetter, setter: $uri::mySetter,"
         " receiverVariable: null, indexVariable: null)",
-        new IndexedAccessGenerator<Arguments>.internal(
+        new KernelIndexedAccessGenerator.internal(
             helper, token, expression, index, getter, setter));
     check(
         "ThisIndexedAccessGenerator(offset: 4, index: index,"
         " getter: $uri::myGetter, setter: $uri::mySetter, indexVariable: null)",
-        new ThisIndexedAccessGenerator<Arguments>(
+        new KernelThisIndexedAccessGenerator(
             helper, token, index, getter, setter));
     check(
         "SuperIndexedAccessGenerator(offset: 4, index: index,"
         " getter: $uri::myGetter, setter: $uri::mySetter, indexVariable: null)",
-        new SuperIndexedAccessGenerator<Arguments>(
-            helper, token, index, getter, setter));
+        new SuperIndexedAccessGenerator(helper, token, index, getter, setter));
     check(
         "StaticAccessGenerator(offset: 4, readTarget: $uri::myGetter,"
         " writeTarget: $uri::mySetter)",
-        new StaticAccessGenerator<Arguments>(helper, token, getter, setter));
+        new StaticAccessGenerator(helper, token, getter, setter));
     check(
         "LoadLibraryGenerator(offset: 4,"
         " builder: Instance of 'LoadLibraryBuilder')",
-        new LoadLibraryGenerator<Arguments>(helper, token, loadLibraryBuilder));
+        new LoadLibraryGenerator(helper, token, loadLibraryBuilder));
     check(
         "ThisAccessGenerator(offset: 4, isInitializer: false, isSuper: false)",
-        new ThisAccessGenerator<Arguments>(helper, token, false));
+        new ThisAccessGenerator(helper, token, false));
     check("IncompleteErrorGenerator(offset: 4, message: Unspecified)",
-        new IncompleteErrorGenerator<Arguments>(helper, token, message));
+        new IncompleteErrorGenerator(helper, token, message));
     check("SendAccessGenerator(offset: 4, name: bar, arguments: (\"arg\"))",
-        new SendAccessGenerator<Arguments>(helper, token, name, arguments));
+        new SendAccessGenerator(helper, token, name, arguments));
     check("IncompletePropertyAccessGenerator(offset: 4, name: bar)",
-        new IncompletePropertyAccessGenerator<Arguments>(helper, token, name));
+        new IncompletePropertyAccessGenerator(helper, token, name));
     check(
         "DeferredAccessGenerator(offset: 4, "
         "builder: Instance of 'PrefixBuilder',"
         " generator: ThisAccessGenerator(offset: 4, isInitializer: false,"
         " isSuper: false))",
-        new DeferredAccessGenerator<Arguments>(
-            helper, token, prefixBuilder, generator));
+        new DeferredAccessGenerator(helper, token, prefixBuilder, generator));
     check(
         "ReadOnlyAccessGenerator(offset: 4, expression: expression,"
         " plainNameForRead: foo, value: null)",
-        new ReadOnlyAccessGenerator<Arguments>(
-            helper, token, expression, "foo"));
+        new ReadOnlyAccessGenerator(helper, token, expression, "foo"));
     check("LargeIntAccessGenerator(offset: 4, lexeme: myToken)",
-        new LargeIntAccessGenerator<Arguments>(helper, token));
+        new LargeIntAccessGenerator(helper, token));
     check(
         "ParenthesizedExpressionGenerator(offset: 4, expression: expression,"
         " plainNameForRead: null, value: null)",
-        new ParenthesizedExpressionGenerator<Arguments>(
-            helper, token, expression));
+        new ParenthesizedExpressionGenerator(helper, token, expression));
     check(
         "TypeDeclarationAccessGenerator(offset: 4, expression: T,"
         " plainNameForRead: foo, value: null)",
-        new TypeDeclarationAccessGenerator<Arguments>(
+        new TypeDeclarationAccessGenerator(
             helper, token, prefixBuilder, -1, declaration, "foo"));
     check("UnresolvedNameGenerator(offset: 4, name: bar)",
-        new UnresolvedNameGenerator<Arguments>(helper, token, name));
+        new UnresolvedNameGenerator(helper, token, name));
   });
 }
diff --git a/pkg/front_end/test/precedence_info_test.dart b/pkg/front_end/test/precedence_info_test.dart
index 60cb57a..3d6ee26 100644
--- a/pkg/front_end/test/precedence_info_test.dart
+++ b/pkg/front_end/test/precedence_info_test.dart
@@ -216,12 +216,7 @@
   void test_isUnaryPostfixOperator() {
     const unaryPostfixLexemes = const [
       '--',
-      '(',
-      '[',
-      '.',
       '++',
-      '?.',
-      '[]',
     ];
     assertInfo((String source, Token token) {
       expect(token.type.isUnaryPostfixOperator,
@@ -245,6 +240,20 @@
     });
   }
 
+  void test_isSelectorOperator() {
+    const selectorLexemes = const [
+      '(',
+      '[',
+      '.',
+      '?.',
+      '[]',
+    ];
+    assertInfo((String source, Token token) {
+      expect(token.type.isSelectorOperator, selectorLexemes.contains(source),
+          reason: source);
+    });
+  }
+
   void test_isUserDefinableOperator() {
     const userDefinableOperatorLexemes = const [
       '&',
@@ -358,7 +367,8 @@
   /// because it is interpreted as a minus token (precedence 13).
   void test_precedence() {
     const precedenceTable = const <int, List<String>>{
-      16: const <String>['.', '?.', '++', '--', '[', '('],
+      17: const <String>['.', '?.', '[', '('],
+      16: const <String>['++', '--'],
       15: const <String>['!', '~'], // excluded '-', '++', '--'
       14: const <String>['*', '/', '~/', '%'],
       13: const <String>['+', '-'],
diff --git a/pkg/front_end/test/src/async_dependency_walker_test.dart b/pkg/front_end/test/src/async_dependency_walker_test.dart
deleted file mode 100644
index 8cf0b28..0000000
--- a/pkg/front_end/test/src/async_dependency_walker_test.dart
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:front_end/src/async_dependency_walker.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(AsyncDependencyWalkerTest);
-  });
-}
-
-@reflectiveTest
-class AsyncDependencyWalkerTest {
-  final nodes = <String, TestNode>{};
-
-  Future<Null> checkGraph(
-      Map<String, List<String>> graph,
-      String startingNodeName,
-      List<List<String>> expectedEvaluations,
-      List<bool> expectedSccFlags) async {
-    makeGraph(graph);
-    var walker = await walk(startingNodeName);
-    expect(walker._evaluations, expectedEvaluations.map((x) => x.toSet()));
-    expect(walker._sccFlags, expectedSccFlags);
-  }
-
-  TestNode getNode(String name) =>
-      nodes.putIfAbsent(name, () => new TestNode(name));
-
-  void makeGraph(Map<String, List<String>> graph) {
-    graph.forEach((name, deps) {
-      var node = getNode(name);
-      for (var dep in deps) {
-        node._dependencies.add(getNode(dep));
-      }
-    });
-  }
-
-  test_complex_graph() async {
-    await checkGraph(
-        {
-          'a': ['b', 'c'],
-          'b': ['c', 'd'],
-          'c': [],
-          'd': ['c', 'e'],
-          'e': ['b', 'f'],
-          'f': ['c', 'd']
-        },
-        'a',
-        [
-          ['c'],
-          ['b', 'd', 'e', 'f'],
-          ['a']
-        ],
-        [false, true, false]);
-  }
-
-  test_diamond() async {
-    await checkGraph(
-        {
-          'a': ['b', 'c'],
-          'b': ['d'],
-          'c': ['d'],
-          'd': []
-        },
-        'a',
-        [
-          ['d'],
-          ['b'],
-          ['c'],
-          ['a']
-        ],
-        [false, false, false, false]);
-  }
-
-  test_singleNode() async {
-    await checkGraph(
-        {'a': []},
-        'a',
-        [
-          ['a']
-        ],
-        [false]);
-  }
-
-  test_singleNodeWithTrivialCycle() async {
-    await checkGraph(
-        {
-          'a': ['a']
-        },
-        'a',
-        [
-          ['a']
-        ],
-        [true]);
-  }
-
-  test_threeNodesWithCircularDependency() async {
-    await checkGraph(
-        {
-          'a': ['b'],
-          'b': ['c'],
-          'c': ['a'],
-        },
-        'a',
-        [
-          ['a', 'b', 'c']
-        ],
-        [true]);
-  }
-
-  test_twoBacklinksEarlierFirst() async {
-    // Test a graph A->B->C->D, where D points back to B and then C.
-    await checkGraph(
-        {
-          'a': ['b'],
-          'b': ['c'],
-          'c': ['d'],
-          'd': ['b', 'c']
-        },
-        'a',
-        [
-          ['b', 'c', 'd'],
-          ['a']
-        ],
-        [true, false]);
-  }
-
-  test_twoBacklinksLaterFirst() async {
-    // Test a graph A->B->C->D, where D points back to C and then B.
-    await checkGraph(
-        {
-          'a': ['b'],
-          'b': ['c'],
-          'c': ['d'],
-          'd': ['c', 'b']
-        },
-        'a',
-        [
-          ['b', 'c', 'd'],
-          ['a']
-        ],
-        [true, false]);
-  }
-
-  test_twoNodesWithCircularDependency() async {
-    await checkGraph(
-        {
-          'a': ['b'],
-          'b': ['a']
-        },
-        'a',
-        [
-          ['a', 'b']
-        ],
-        [true]);
-  }
-
-  test_twoNodesWithSimpleDependency() async {
-    await checkGraph(
-        {
-          'a': ['b'],
-          'b': []
-        },
-        'a',
-        [
-          ['b'],
-          ['a']
-        ],
-        [false, false]);
-  }
-
-  Future<TestWalker> walk(String startingNodeName) async {
-    var testWalker = new TestWalker();
-    await testWalker.walk(getNode(startingNodeName));
-    return testWalker;
-  }
-}
-
-class TestNode extends Node<TestNode> {
-  final String _name;
-
-  bool _computeDependenciesCalled = false;
-
-  final _dependencies = <TestNode>[];
-
-  TestNode(this._name);
-
-  @override
-  Future<List<TestNode>> computeDependencies() async {
-    expect(_computeDependenciesCalled, false);
-    _computeDependenciesCalled = true;
-    return _dependencies;
-  }
-}
-
-class TestWalker extends AsyncDependencyWalker<TestNode> {
-  final _evaluations = <Set<String>>[];
-  final _sccFlags = <bool>[];
-
-  @override
-  Future<Null> evaluate(TestNode v) async {
-    _evaluations.add([v._name].toSet());
-    _sccFlags.add(false);
-  }
-
-  @override
-  Future<Null> evaluateScc(List<TestNode> scc) async {
-    var sccNames = scc.map((node) => node._name).toSet();
-    // Make sure there were no duplicates
-    expect(sccNames.length, scc.length);
-    _evaluations.add(sccNames);
-    _sccFlags.add(true);
-  }
-}
diff --git a/pkg/front_end/test/subpackage_relationships_test.dart b/pkg/front_end/test/subpackage_relationships_test.dart
deleted file mode 100644
index bcf7288..0000000
--- a/pkg/front_end/test/subpackage_relationships_test.dart
+++ /dev/null
@@ -1,335 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/api_prototype/dependency_grapher.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
-import 'package:path/path.dart' as pathos;
-
-main() async {
-  exit(await new _SubpackageRelationshipsTest().run());
-}
-
-/// List of packages that front_end is allowed to directly depend on.
-///
-/// Note that this script only checks files in pkg/front_end/lib, so this list
-/// excludes dev dependencies.
-final allowedPackageDependencies = [
-  'charcode',
-  'convert',
-  'crypto',
-  'kernel',
-  'meta',
-  'package_config',
-  'path',
-  'source_span',
-  'testing',
-];
-
-/// Map from subpackage name to the rules for what the subpackage is allowed to
-/// depend directly on.
-///
-/// Each listed directory is considered a subpackage.  Each package contains all
-/// of its descendant files that are not in a more deeply nested subpackage.
-final subpackageRules = {
-  'lib/src': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src/base',
-    'lib/src/fasta',
-    "lib/src/fasta/dill",
-    "lib/src/fasta/kernel",
-    'lib/src/fasta/source',
-  ]),
-  'lib/src/api_prototype': new SubpackageRules(allowedDependencies: [
-    'lib/src',
-    'lib/src/base',
-    'lib/src/byte_store',
-    'lib/src/fasta',
-    'lib/src/fasta/scanner'
-  ]),
-  'lib/src/api_unstable': new SubpackageRules(allowedDependencies: [
-    'lib/src',
-    'lib/src/api_prototype',
-    'lib/src/base',
-    'lib/src/fasta',
-  ]),
-  'lib/src/base': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src/fasta',
-    'lib/src/fasta/util',
-  ]),
-  // Note: byte_store should never depend on other parts of front_end, since we
-  // may want to move it to its own package someday.
-  'lib/src/byte_store': new SubpackageRules(allowedDependencies: []),
-  'lib/src/codegen': new SubpackageRules(),
-  'lib/src/fasta': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src/base',
-    'lib/src/fasta/builder',
-    'lib/src/fasta/dill',
-    'lib/src/fasta/kernel',
-    'lib/src/fasta/parser',
-    'lib/src/fasta/scanner',
-    'lib/src/fasta/source',
-    'lib/src/fasta/util',
-    'lib/src/scanner',
-  ]),
-  'lib/src/fasta/builder': new SubpackageRules(allowedDependencies: [
-    'lib/src/base',
-    'lib/src/fasta',
-    'lib/src/fasta/parser',
-    'lib/src/fasta/source',
-  ]),
-  'lib/src/fasta/dill': new SubpackageRules(allowedDependencies: [
-    'lib/src/fasta',
-    'lib/src/fasta/kernel',
-  ]),
-  'lib/src/fasta/kernel': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src/fasta',
-    'lib/src/base',
-    'lib/src/fasta/builder',
-    'lib/src/fasta/dill',
-    'lib/src/fasta/parser',
-    'lib/src/fasta/scanner',
-    'lib/src/fasta/source',
-    'lib/src/fasta/type_inference',
-    'lib/src/scanner',
-  ]),
-  'lib/src/fasta/parser': new SubpackageRules(allowedDependencies: [
-    'lib/src/fasta',
-    'lib/src/fasta/scanner',
-    'lib/src/fasta/util',
-    'lib/src/scanner',
-  ]),
-  'lib/src/fasta/scanner': new SubpackageRules(allowedDependencies: [
-    'lib/src/fasta',
-    // fasta scanner produces analyzer scanner tokens
-    'lib/src/scanner',
-    'lib/src/fasta/util',
-  ]),
-  'lib/src/fasta/source': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src/fasta',
-    'lib/src/base',
-    'lib/src/fasta/builder',
-    'lib/src/fasta/dill',
-    'lib/src/fasta/kernel',
-    'lib/src/fasta/parser',
-    'lib/src/fasta/type_inference',
-    'lib/src/scanner',
-  ]),
-  'lib/src/fasta/testing': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src',
-    'lib/src/base',
-    'lib/src/fasta',
-    'lib/src/fasta/kernel',
-    'lib/src/fasta/scanner',
-    'lib/src/scanner',
-  ]),
-  'lib/src/fasta/type_inference': new SubpackageRules(allowedDependencies: [
-    'lib/src/base',
-    'lib/src/fasta/builder',
-    'lib/src/fasta',
-    'lib/src/fasta/kernel',
-    'lib/src/fasta/source',
-  ]),
-  'lib/src/fasta/util': new SubpackageRules(),
-  'lib/src/incremental': new SubpackageRules(allowedDependencies: [
-    'lib/src/api_prototype',
-    'lib/src',
-    'lib/src/base',
-    'lib/src/fasta',
-    'lib/src/fasta/dill',
-    'lib/src/fasta/kernel',
-    'lib/src/fasta/parser',
-    'lib/src/fasta/scanner',
-    'lib/src/fasta/source',
-  ]),
-  'lib/src/scanner': new SubpackageRules(allowedDependencies: [
-    'lib/src/base',
-    // For error codes.
-    'lib/src/fasta',
-    // fasta scanner produces analyzer scanner tokens
-    'lib/src/fasta/scanner',
-  ]),
-  'lib/src/testing': new SubpackageRules(allowedDependencies: [
-    'lib/src',
-    'lib/src/api_prototype',
-    'lib/src/fasta',
-  ]),
-};
-
-/// Rules for what a subpackage may depend directly on.
-class SubpackageRules {
-  /// Indicates whether dart files may exist in subdirectories of this
-  /// subpackage.
-  ///
-  /// If `false`, any subdirectory of this subpackage must be a separate
-  /// subpackage.
-  final bool allowSubdirs;
-
-  /// Indicates which other subpackages a given subpackage may directly depend
-  /// on.
-  final List<String> allowedDependencies;
-
-  var actuallyContainsFiles = false;
-
-  var actuallyHasSubdirs = false;
-
-  var actualDependencies = new Set<String>();
-
-  SubpackageRules(
-      {this.allowSubdirs: false, this.allowedDependencies: const []});
-}
-
-class _SubpackageRelationshipsTest {
-  /// File uri of the front_end package's "lib" directory.
-  final frontEndLibUri =
-      new Uri.file(package_root.packageRoot).resolve('front_end/lib/');
-
-  /// Indicates whether any problems have been reported yet.
-  bool problemsReported = false;
-
-  /// Package dependencies that were actually discovered
-  final actualPackageDependencies = <String>[];
-
-  /// Check for problems resulting from URI [src] having a direct dependency on
-  /// URI [dst].
-  void checkDependency(Uri src, Uri dst) {
-    var srcSubpackage = subpackageForUri(src);
-    if (srcSubpackage == null) return;
-    var srcSubpackageRules = subpackageRules[srcSubpackage];
-    if (srcSubpackageRules == null) {
-      problem('$src is in subpackage "$srcSubpackage", which is not found in '
-          'subpackageRules');
-      return;
-    }
-    srcSubpackageRules.actuallyContainsFiles = true;
-    if (dst.scheme == 'dart') return;
-    if (dst.scheme != 'package') {
-      problem('$src depends on $dst, which is neither a package: or dart: URI');
-      return;
-    }
-    if (src.scheme == 'package' &&
-        src.pathSegments[0] == 'front_end' &&
-        dst.scheme == 'package' &&
-        dst.pathSegments[0] != 'front_end') {
-      if (allowedPackageDependencies.contains(dst.pathSegments[0])) {
-        actualPackageDependencies.add(dst.pathSegments[0]);
-      } else {
-        problem('$src depends on package "${dst.pathSegments[0]}", which is '
-            'not found in allowedPackageDependencies');
-      }
-    }
-    var dstSubPackage = subpackageForUri(dst);
-    if (dstSubPackage == null) return;
-    if (dstSubPackage == srcSubpackage) return;
-    if (srcSubpackageRules.allowedDependencies.contains(dstSubPackage)) {
-      srcSubpackageRules.actualDependencies.add(dstSubPackage);
-    } else {
-      problem('$src depends on $dst, but subpackage "$srcSubpackage" is not '
-          'allowed to depend on subpackage "$dstSubPackage"');
-    }
-  }
-
-  /// Finds all files in the front_end's "lib" directory and returns their Uris
-  /// (as "package:" URIs).
-  List<Uri> findFrontEndUris() {
-    var frontEndUris = <Uri>[];
-    var frontEndLibPath = pathos.fromUri(frontEndLibUri);
-    for (var entity in new Directory(frontEndLibPath)
-        .listSync(recursive: true, followLinks: false)) {
-      if (entity.path.endsWith('.dart')) {
-        var posixRelativePath = pathos.url.joinAll(
-            pathos.split(pathos.relative(entity.path, from: frontEndLibPath)));
-        frontEndUris.add(Uri.parse('package:front_end/$posixRelativePath'));
-      }
-    }
-    return frontEndUris;
-  }
-
-  /// Reports a single problem.
-  void problem(String description) {
-    print(description);
-    problemsReported = true;
-  }
-
-  /// Tests all subpackage relationships in the front end, and returns an
-  /// appropriate exit code.
-  Future<int> run() async {
-    var frontEndUris = await findFrontEndUris();
-    var packagesFileUri = Platform.packageConfig != null
-        ? Uri.parse(Platform.packageConfig)
-        : frontEndLibUri.resolve('../../../.packages');
-    var graph = await graphForProgram(
-        frontEndUris,
-        new CompilerOptions()
-          ..packagesFileUri = packagesFileUri
-          ..chaseDependencies = true);
-    for (var i = 0; i < graph.topologicallySortedCycles.length; i++) {
-      for (var library in graph.topologicallySortedCycles[i].libraries.values) {
-        for (var dependency in library.dependencies) {
-          checkDependency(library.uri, dependency.uri);
-        }
-      }
-    }
-    for (var package in allowedPackageDependencies) {
-      if (!actualPackageDependencies.contains(package)) {
-        problem('$package is listed in allowedPackageDependencies, '
-            'but is not used');
-      }
-    }
-    subpackageRules.forEach((subpackage, rule) {
-      if (!rule.actuallyContainsFiles) {
-        problem("$subpackage contains no files");
-      }
-      if (rule.allowSubdirs && !rule.actuallyHasSubdirs) {
-        problem("$subpackage is allowed to have subdirectories, but doesn't");
-      }
-      for (var dep in rule.allowedDependencies
-          .toSet()
-          .difference(rule.actualDependencies)) {
-        problem("$subpackage lists $dep as a dependency, but doesn't use it");
-      }
-    });
-    return problemsReported ? 1 : 0;
-  }
-
-  /// Determines which subpackage [src] is in.
-  ///
-  /// If [src] is not part of the front end, `null` is returned.
-  String subpackageForUri(Uri src) {
-    if (src.scheme != 'package') return null;
-    if (src.pathSegments[0] != 'front_end') return null;
-    var pathWithLib = 'lib/${src.pathSegments.skip(1).join('/')}';
-    String subpackage;
-    String pathWithinSubpackage;
-    for (var subpackagePath in subpackageRules.keys) {
-      var subpackagePathWithSlash = '$subpackagePath/';
-      if (pathWithLib.startsWith(subpackagePathWithSlash) &&
-          (subpackage == null || subpackage.length < subpackagePath.length)) {
-        subpackage = subpackagePath;
-        pathWithinSubpackage =
-            pathWithLib.substring(subpackagePathWithSlash.length);
-      }
-    }
-    if (subpackage == null) {
-      problem('Uri $src is inside package:front_end but is not in any known '
-          'subpackage');
-    } else if (pathWithinSubpackage.contains('/')) {
-      if (subpackageRules[subpackage].allowSubdirs) {
-        subpackageRules[subpackage].actuallyHasSubdirs = true;
-      } else {
-        problem('Uri $src is in a subfolder of $subpackage, but that '
-            'subpackage does not allow dart files in subdirectories.');
-      }
-    }
-    return subpackage;
-  }
-}
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect
index 197f600..172bc99 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect
@@ -2,13 +2,9 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
   var x = void f<T>(T t) {};
-          ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
-  var x = void f<T>(T t) {};
-               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
-  print(void g<T>(T t) {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
   print(void g<T>(T t) {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect
index 197f600..172bc99 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect
@@ -2,13 +2,9 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
   var x = void f<T>(T t) {};
-          ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
-  var x = void f<T>(T t) {};
-               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
-  print(void g<T>(T t) {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
   print(void g<T>(T t) {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect
index 99ed439..1030838 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect
@@ -2,13 +2,9 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
   var x = void f<T>(T t) {};
-          ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
-  var x = void f<T>(T t) {};
-               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
-  print(void g<T>(T t) {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
   print(void g<T>(T t) {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect
index 99ed439..1030838 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect
@@ -2,13 +2,9 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
   var x = void f<T>(T t) {};
-          ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
-  var x = void f<T>(T t) {};
-               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
-  print(void g<T>(T t) {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+               ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
   print(void g<T>(T t) {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect
index 0bff178..d31deb1 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect
@@ -2,9 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
-  print(void f() {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
   print(void f() {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect
index 0bff178..d31deb1 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect
@@ -2,9 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
-  print(void f() {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
   print(void f() {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect
index 9c4d9bd..dcee09d 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect
@@ -2,9 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
-  print(void f() {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
   print(void f() {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect
index 9c4d9bd..dcee09d 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect
@@ -2,9 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
-  print(void f() {});
-        ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
   print(void f() {});
              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
index bf5d7a9..bece5a7 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
@@ -20,6 +20,7 @@
     return new self::Pair::•<self::Pair::U, self::Pair::T>(this.{self::Pair::u}, this.{self::Pair::t});
 }
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart:22:110: Error: Can't use a super-bounded type for instance creation. Got 'test::Pair<test::Clonable<dynamic>, test::Clonable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
       new /*error:COULD_NOT_INFER,error:COULD_NOT_INFER*/ /*@typeArgs=Clonable<dynamic>, Clonable<dynamic>*/ Pair
                                                                                                              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
index bf5d7a9..bece5a7 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
@@ -20,6 +20,7 @@
     return new self::Pair::•<self::Pair::U, self::Pair::T>(this.{self::Pair::u}, this.{self::Pair::t});
 }
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart:22:110: Error: Can't use a super-bounded type for instance creation. Got 'test::Pair<test::Clonable<dynamic>, test::Clonable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
       new /*error:COULD_NOT_INFER,error:COULD_NOT_INFER*/ /*@typeArgs=Clonable<dynamic>, Clonable<dynamic>*/ Pair
                                                                                                              ^"]/* from null */;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
index 893b908..682d590 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
@@ -9,6 +9,7 @@
 }
 static field self::B<core::Comparable<dynamic>> y = new self::B::•<core::Comparable<dynamic>>();
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart:11:13: Error: Can't use a super-bounded type for instance creation. Got '#lib1::B<dart.core::Comparable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
 var y = new B();
             ^"]/* from null */;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
index 893b908..682d590 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
@@ -9,6 +9,7 @@
 }
 static field self::B<core::Comparable<dynamic>> y = new self::B::•<core::Comparable<dynamic>>();
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart:11:13: Error: Can't use a super-bounded type for instance creation. Got '#lib1::B<dart.core::Comparable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
 var y = new B();
             ^"]/* from null */;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart b/pkg/front_end/testcases/named_function_scope.dart
index bb6e8aa..010ffc7 100644
--- a/pkg/front_end/testcases/named_function_scope.dart
+++ b/pkg/front_end/testcases/named_function_scope.dart
@@ -41,7 +41,6 @@
     // This causes a scope error as T is already used in the function-type
     // scope (the return type).
     var x =
-        /*@error=ReturnTypeFunctionExpression*/
         /*@context=DuplicatedNamePreviouslyUsedCause*/
         T
         /*@error=NamedFunctionExpression*/
diff --git a/pkg/front_end/testcases/named_function_scope.dart.direct.expect b/pkg/front_end/testcases/named_function_scope.dart.direct.expect
index b5ce346..8392f75 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.direct.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.direct.expect
@@ -14,11 +14,9 @@
 }
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
     var x = /*@error=NamedFunctionExpression*/ T() {};
-                                               ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
-        T
-        ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+                                               ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
         T() {};
-        ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+        ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
         T< /*@context=DuplicatedNameCause*/ T>() {};
         ^"]/* from null */;
 static method test() → dynamic {
@@ -47,24 +45,24 @@
                                                 ^" in let final dynamic #t2 = null in null;
   }
   {
-    dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+    dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
         T() {};
         ^" in let final () → self::T T = () → self::T {} in T;
   }
   {
-    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
     V /*@error=DuplicatedNamePreviouslyUsed*/ V;
                                               ^";
   }
   {
-    dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+    dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
         T< /*@context=DuplicatedNameCause*/ T>() {};
         ^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
   }
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -72,7 +70,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -81,7 +79,7 @@
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
@@ -89,7 +87,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect b/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect
index b5ce346..8392f75 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect
@@ -14,11 +14,9 @@
 }
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
     var x = /*@error=NamedFunctionExpression*/ T() {};
-                                               ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
-        T
-        ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+                                               ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
         T() {};
-        ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+        ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
         T< /*@context=DuplicatedNameCause*/ T>() {};
         ^"]/* from null */;
 static method test() → dynamic {
@@ -47,24 +45,24 @@
                                                 ^" in let final dynamic #t2 = null in null;
   }
   {
-    dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+    dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
         T() {};
         ^" in let final () → self::T T = () → self::T {} in T;
   }
   {
-    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
     V /*@error=DuplicatedNamePreviouslyUsed*/ V;
                                               ^";
   }
   {
-    dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+    dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
         T< /*@context=DuplicatedNameCause*/ T>() {};
         ^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
   }
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -72,7 +70,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -81,7 +79,7 @@
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
@@ -89,7 +87,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart.strong.expect b/pkg/front_end/testcases/named_function_scope.dart.strong.expect
index 3790ec0..f93c202 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.strong.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.strong.expect
@@ -14,13 +14,11 @@
 }
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
     var x = /*@error=NamedFunctionExpression*/ T() {};
-                                               ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
-        T
-        ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+                                               ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
         T() {};
-        ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+        ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
         T< /*@context=DuplicatedNameCause*/ T>() {};
-        ^", "pkg/front_end/testcases/named_function_scope.dart:84:32: Error: 'T' isn't a type.
+        ^", "pkg/front_end/testcases/named_function_scope.dart:83:32: Error: 'T' isn't a type.
     void T(/*@error=NotAType*/ T t) {}
                                ^"]/* from null */;
 static method test() → dynamic {
@@ -49,24 +47,24 @@
                                                 ^" in let final dynamic #t2 = null in null;
   }
   {
-    dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+    dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
         T() {};
         ^" in let final () → self::T T = () → self::T {} in T;
   }
   {
-    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
     V /*@error=DuplicatedNamePreviouslyUsed*/ V;
                                               ^" as{TypeError} self::V;
   }
   {
-    dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+    dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
         T< /*@context=DuplicatedNameCause*/ T>() {};
         ^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
   }
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -74,7 +72,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -83,7 +81,7 @@
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
@@ -91,7 +89,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect b/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect
index 94ed7c1..051c027 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect
@@ -14,13 +14,11 @@
 }
 static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
     var x = /*@error=NamedFunctionExpression*/ T() {};
-                                               ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
-        T
-        ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+                                               ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
         T() {};
-        ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+        ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
         T< /*@context=DuplicatedNameCause*/ T>() {};
-        ^", "pkg/front_end/testcases/named_function_scope.dart:84:32: Error: 'T' isn't a type.
+        ^", "pkg/front_end/testcases/named_function_scope.dart:83:32: Error: 'T' isn't a type.
     void T(/*@error=NotAType*/ T t) {}
                                ^"]/* from null */;
 static method test() → dynamic {
@@ -49,24 +47,24 @@
                                                 ^" in let final<BottomType> #t2 = null in null;
   }
   {
-    dynamic x = let final dynamic #t3 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+    dynamic x = let final dynamic #t3 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
         T() {};
         ^" in let final () → self::T T = () → self::T {} in T;
   }
   {
-    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+    self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
     V /*@error=DuplicatedNamePreviouslyUsed*/ V;
                                               ^" as{TypeError} self::V;
   }
   {
-    dynamic x = let final dynamic #t4 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+    dynamic x = let final dynamic #t4 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
         T< /*@context=DuplicatedNameCause*/ T>() {};
         ^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
   }
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -74,7 +72,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
                                               ^";
       function T() → self::T {}
@@ -83,7 +81,7 @@
   {
     self::T t;
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
@@ -91,7 +89,7 @@
   }
   {
     {
-      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+      invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
     T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
                                               ^";
       function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart b/pkg/front_end/testcases/regress/issue_31185.dart
new file mode 100644
index 0000000..568d2af
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart
@@ -0,0 +1,18 @@
+// 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.
+
+int i = 5;
+
+int test1() {
+  return i ++ (i);
+}
+
+int test2() {
+  return (i) ++ (i);
+}
+
+main() {
+  test1();
+  // Don't call test2, as error recovery has put a runtime error in there.
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.direct.expect b/pkg/front_end/testcases/regress/issue_31185.dart.direct.expect
new file mode 100644
index 0000000..bf6678e
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.direct.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+  return i ++ (i);
+              ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+  return (i) ++ (i);
+                ^"]/* from null */;
+static method test1() → core::int {
+  return let final dynamic #t1 = self::i in let final dynamic #t2 = self::i = #t1.+(1) in #t1;
+  self::i;
+}
+static method test2() → core::int {
+  return let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+  return (i) ++ (i);
+           ^" in #t4;
+  self::i;
+}
+static method main() → dynamic {
+  self::test1();
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_31185.dart.direct.transformed.expect
new file mode 100644
index 0000000..bf6678e
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.direct.transformed.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+  return i ++ (i);
+              ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+  return (i) ++ (i);
+                ^"]/* from null */;
+static method test1() → core::int {
+  return let final dynamic #t1 = self::i in let final dynamic #t2 = self::i = #t1.+(1) in #t1;
+  self::i;
+}
+static method test2() → core::int {
+  return let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+  return (i) ++ (i);
+           ^" in #t4;
+  self::i;
+}
+static method main() → dynamic {
+  self::test1();
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31185.dart.outline.expect
new file mode 100644
index 0000000..608d890
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.outline.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i;
+static method test1() → core::int
+  ;
+static method test2() → core::int
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31185.dart.strong.expect
new file mode 100644
index 0000000..a6e3919
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.strong.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+  return i ++ (i);
+              ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+  return (i) ++ (i);
+                ^"]/* from null */;
+static method test1() → core::int {
+  return let final core::int #t1 = self::i in let final core::int #t2 = self::i = #t1.{core::num::+}(1) in #t1;
+  self::i;
+}
+static method test2() → core::int {
+  return (let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+  return (i) ++ (i);
+           ^" in #t4) as{TypeError} core::int;
+  self::i;
+}
+static method main() → dynamic {
+  self::test1();
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31185.dart.strong.transformed.expect
new file mode 100644
index 0000000..719e1e1
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.strong.transformed.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+  return i ++ (i);
+              ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+  return (i) ++ (i);
+                ^"]/* from null */;
+static method test1() → core::int {
+  return let final core::int #t1 = self::i in let final core::int #t2 = self::i = #t1.{core::num::+}(1) in #t1;
+  self::i;
+}
+static method test2() → core::int {
+  return (let final core::int #t3 = self::i in let final core::int #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+  return (i) ++ (i);
+           ^" in #t4) as{TypeError} core::int;
+  self::i;
+}
+static method main() → dynamic {
+  self::test1();
+}
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index 7d3cec8..7e7762f 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -159,8 +159,6 @@
     final typeEnvironment =
         new TypeEnvironment(coreTypes, hierarchy, strongMode: strongMode);
 
-    // NOTE: Currently we keep fields, because there are certain constant
-    // fields which the VM accesses (e.g. `_Random._A` needs to be preserved).
     // TODO(kustermann): We should use the entrypoints manifest to find out
     // which fields need to be preserved and remove the rest.
     constants.transformComponent(component, vmConstants,
diff --git a/pkg/vm/lib/transformations/type_flow/entry_points_extra.json b/pkg/vm/lib/transformations/type_flow/entry_points_extra.json
index 0ff8ba4..e739bb9 100644
--- a/pkg/vm/lib/transformations/type_flow/entry_points_extra.json
+++ b/pkg/vm/lib/transformations/type_flow/entry_points_extra.json
@@ -173,12 +173,6 @@
       "library": "dart:async",
       "class": "_AsyncStarStreamController",
       "action": "create-instance"
-    },
-    {
-      "library": "dart:math",
-      "class": "_Random",
-      "name": "_A",
-      "action": "get"
     }
   ]
 }
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index 793b10b..8888042 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -189,6 +189,7 @@
   // The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1.
 
   // Implements:
+  //   const _A = 0xffffda61;
   //   var state =
   //       ((_A * (_state[_kSTATE_LO])) + _state[_kSTATE_HI]) & ((1 << 64) - 1);
   //   _state[_kSTATE_LO] = state & ((1 << 32) - 1);
@@ -233,8 +234,6 @@
   static const _POW2_53_D = 1.0 * (1 << 53);
   static const _POW2_27_D = 1.0 * (1 << 27);
 
-  static const _A = 0xffffda61;
-
   // Use a singleton Random object to get a new seed if no seed was passed.
   static var _prng = new _Random._withState(_initialSeed());
 
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index c7e0628..0a01b69 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -1421,7 +1421,8 @@
     // check earlier, or we're compiling precompiled code (no
     // optimistic hoisting of checks possible)
     const bool try_generalization =
-        function.allows_bounds_check_generalization() && !FLAG_precompiled_mode;
+        !function.ProhibitsBoundsCheckGeneralization() &&
+        !FLAG_precompiled_mode;
 
     BoundsCheckGeneralizer generalizer(this, flow_graph_);
 
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 449ace0..faadfa6 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -1331,7 +1331,7 @@
 }
 
 void LICM::OptimisticallySpecializeSmiPhis() {
-  if (!flow_graph()->function().allows_hoisting_check_class() ||
+  if (flow_graph()->function().ProhibitsHoistingCheckClass() ||
       FLAG_precompiled_mode) {
     // Do not hoist any: Either deoptimized on a hoisted check,
     // or compiling precompiled code where we can't do optimistic
@@ -1355,7 +1355,7 @@
 }
 
 void LICM::Optimize() {
-  if (!flow_graph()->function().allows_hoisting_check_class()) {
+  if (flow_graph()->function().ProhibitsHoistingCheckClass()) {
     // Do not hoist any.
     return;
   }
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 58bc7fa..ddea9fe 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -4146,6 +4146,13 @@
     intptr_t argument_count,
     const Instance* receiver,
     const TypeArguments* type_args) {
+  // We use a kernel2kernel constant evaluator in Dart 2.0 AOT compilation, so
+  // we should never end up evaluating constants using the VM's constant
+  // evaluator.
+  if (I->strong() && FLAG_precompiled_mode) {
+    UNREACHABLE();
+  }
+
   // We do not support generic methods yet.
   ASSERT((receiver == NULL) || (type_args == NULL));
   intptr_t extra_arguments =
@@ -7412,7 +7419,8 @@
 }
 
 ActiveClass* StreamingFlowGraphBuilder::active_class() {
-  return &flow_graph_builder_->active_class_;
+  return (flow_graph_builder_ != NULL) ? &flow_graph_builder_->active_class_
+                                       : NULL;
 }
 
 ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
@@ -11057,10 +11065,17 @@
   return param_descriptor.raw();
 }
 
-RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(intptr_t kernel_offset) {
+RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(
+    intptr_t kernel_offset,
+    const Class& owner_class) {
   SetOffset(kernel_offset);
   const Tag tag = PeekTag();
 
+  // Setup active_class in type translator for type finalization.
+  ActiveClass active_class;
+  active_class.klass = &owner_class;
+  type_translator_.set_active_class(&active_class);
+
   if (tag == kClass) {
     ClassHelper class_helper(this);
     class_helper.ReadUntilExcluding(ClassHelper::kAnnotations);
@@ -11087,6 +11102,8 @@
     metadata_values.SetAt(i, value);
   }
 
+  type_translator_.set_active_class(NULL);
+
   return metadata_values.raw();
 }
 
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 169f403..ce7dc4d 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -707,6 +707,10 @@
 
   const Type& ReceiverType(const Class& klass);
 
+  void set_active_class(ActiveClass* active_class) {
+    active_class_ = active_class;
+  }
+
  private:
   // Can build a malformed type.
   void BuildTypeInternal(bool invalid_as_dynamic = false);
@@ -1261,7 +1265,7 @@
 
   Fragment BuildStatementAt(intptr_t kernel_offset);
   RawObject* BuildParameterDescriptor(intptr_t kernel_offset);
-  RawObject* EvaluateMetadata(intptr_t kernel_offset);
+  RawObject* EvaluateMetadata(intptr_t kernel_offset, const Class& owner_class);
   void CollectTokenPositionsFor(
       intptr_t script_index,
       intptr_t initial_script_index,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index c8a1f61..34aa36e 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2776,8 +2776,9 @@
         &helper, Script::Handle(Z, metadata_field.Script()), Z,
         TypedData::Handle(Z, metadata_field.KernelData()),
         metadata_field.KernelDataProgramOffset());
+    const Class& owner_class = Class::Handle(Z, metadata_field.Owner());
     return streaming_flow_graph_builder.EvaluateMetadata(
-        metadata_field.kernel_offset());
+        metadata_field.kernel_offset(), owner_class);
   } else {
     Thread* thread = Thread::Current();
     Error& error = Error::Handle();
diff --git a/runtime/vm/compiler/intrinsifier.h b/runtime/vm/compiler/intrinsifier.h
index 2dbc111..bf2ec2a 100644
--- a/runtime/vm/compiler/intrinsifier.h
+++ b/runtime/vm/compiler/intrinsifier.h
@@ -36,6 +36,10 @@
   static void IntrinsicCallEpilogue(Assembler* assembler);
 
  private:
+  // The "_A" value used in the intrinsification of
+  // `runtime/lib/math_patch.dart:_Random._nextState()`
+  static const int64_t kRandomAValue = 0xffffda61;
+
   static bool CanIntrinsify(const Function& function);
 
 #define DECLARE_FUNCTION(class_name, function_name, enum_name, type, fp)       \
diff --git a/runtime/vm/compiler/intrinsifier_arm.cc b/runtime/vm/compiler/intrinsifier_arm.cc
index 9b0c63b..201306d 100644
--- a/runtime/vm/compiler/intrinsifier_arm.cc
+++ b/runtime/vm/compiler/intrinsifier_arm.cc
@@ -1520,17 +1520,7 @@
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
   ASSERT(!state_field.IsNull());
-  const Field& random_A_field = Field::ZoneHandle(
-      random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
-  ASSERT(!random_A_field.IsNull());
-  ASSERT(random_A_field.is_const());
-  Instance& a_value = Instance::Handle(random_A_field.StaticValue());
-  if (a_value.raw() == Object::sentinel().raw() ||
-      a_value.raw() == Object::transition_sentinel().raw()) {
-    random_A_field.EvaluateInitializer();
-    a_value = random_A_field.StaticValue();
-  }
-  const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+  const int64_t a_int_value = Intrinsifier::kRandomAValue;
   // 'a_int_value' is a mask.
   ASSERT(Utils::IsUint(32, a_int_value));
   int32_t a_int32_value = static_cast<int32_t>(a_int_value);
diff --git a/runtime/vm/compiler/intrinsifier_arm64.cc b/runtime/vm/compiler/intrinsifier_arm64.cc
index 4598536..d14b824 100644
--- a/runtime/vm/compiler/intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/intrinsifier_arm64.cc
@@ -1579,17 +1579,7 @@
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
   ASSERT(!state_field.IsNull());
-  const Field& random_A_field = Field::ZoneHandle(
-      random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
-  ASSERT(!random_A_field.IsNull());
-  ASSERT(random_A_field.is_const());
-  Instance& a_value = Instance::Handle(random_A_field.StaticValue());
-  if (a_value.raw() == Object::sentinel().raw() ||
-      a_value.raw() == Object::transition_sentinel().raw()) {
-    random_A_field.EvaluateInitializer();
-    a_value = random_A_field.StaticValue();
-  }
-  const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+  const int64_t a_int_value = Intrinsifier::kRandomAValue;
 
   // Receiver.
   __ ldr(R0, Address(SP, 0 * kWordSize));
diff --git a/runtime/vm/compiler/intrinsifier_ia32.cc b/runtime/vm/compiler/intrinsifier_ia32.cc
index 7727717..2e46b55 100644
--- a/runtime/vm/compiler/intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/intrinsifier_ia32.cc
@@ -1588,20 +1588,11 @@
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
   ASSERT(!state_field.IsNull());
-  const Field& random_A_field = Field::ZoneHandle(
-      random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
-  ASSERT(!random_A_field.IsNull());
-  ASSERT(random_A_field.is_const());
-  Instance& a_value = Instance::Handle(random_A_field.StaticValue());
-  if (a_value.raw() == Object::sentinel().raw() ||
-      a_value.raw() == Object::transition_sentinel().raw()) {
-    random_A_field.EvaluateInitializer();
-    a_value = random_A_field.StaticValue();
-  }
-  const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+  const int64_t a_int_value = Intrinsifier::kRandomAValue;
   // 'a_int_value' is a mask.
   ASSERT(Utils::IsUint(32, a_int_value));
   int32_t a_int32_value = static_cast<int32_t>(a_int_value);
+
   // Receiver.
   __ movl(EAX, Address(ESP, +1 * kWordSize));
   // Field '_state'.
diff --git a/runtime/vm/compiler/intrinsifier_x64.cc b/runtime/vm/compiler/intrinsifier_x64.cc
index 1e2574c..a3a0c9b 100644
--- a/runtime/vm/compiler/intrinsifier_x64.cc
+++ b/runtime/vm/compiler/intrinsifier_x64.cc
@@ -1496,17 +1496,8 @@
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
   ASSERT(!state_field.IsNull());
-  const Field& random_A_field = Field::ZoneHandle(
-      random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
-  ASSERT(!random_A_field.IsNull());
-  ASSERT(random_A_field.is_const());
-  Instance& a_value = Instance::Handle(random_A_field.StaticValue());
-  if (a_value.raw() == Object::sentinel().raw() ||
-      a_value.raw() == Object::transition_sentinel().raw()) {
-    random_A_field.EvaluateInitializer();
-    a_value = random_A_field.StaticValue();
-  }
-  const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+  const int64_t a_int_value = Intrinsifier::kRandomAValue;
+
   // Receiver.
   __ movq(RAX, Address(RSP, +1 * kWordSize));
   // Field '_state'.
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index a4e5920..153f2ae 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -139,11 +139,11 @@
   } else {
     if (deopt_context->HasDeoptFlag(ICData::kHoisted)) {
       // Prevent excessive deoptimization.
-      function.set_allows_hoisting_check_class(false);
+      function.SetProhibitsHoistingCheckClass(true);
     }
 
     if (deopt_context->HasDeoptFlag(ICData::kGeneralized)) {
-      function.set_allows_bounds_check_generalization(false);
+      function.SetProhibitsBoundsCheckGeneralization(true);
     }
   }
 }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c50f3ee..de61db2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7097,8 +7097,6 @@
   result.set_is_optimizable(is_native ? false : true);
   result.set_is_background_optimizable(is_native ? false : true);
   result.set_is_inlinable(true);
-  result.set_allows_hoisting_check_class(true);
-  result.set_allows_bounds_check_generalization(true);
   result.SetInstructionsSafe(
       Code::Handle(StubCode::LazyCompile_entry()->code()));
   if (kind == RawFunction::kClosureFunction ||
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c7749c5..1d8dc12 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2788,28 +2788,37 @@
 
   void set_modifier(RawFunction::AsyncModifier value) const;
 
+// 'WasCompiled' is true if the function was compiled once in this
+// VM instantiation. It is independent from presence of type feedback
+// (ic_data_array) and code, which may be loaded from a snapshot.
+// 'WasExecuted' is true if the usage counter has ever been positive.
+// 'ProhibitsHoistingCheckClass' is true if this function deoptimized before on
+// a hoisted check class instruction.
+// 'ProhibitsBoundsCheckGeneralization' is true if this function deoptimized
+// before on a generalized bounds check.
+#define STATE_BITS_LIST(V)                                                     \
+  V(WasCompiled)                                                               \
+  V(WasExecutedBit)                                                            \
+  V(ProhibitsHoistingCheckClass)                                               \
+  V(ProhibitsBoundsCheckGeneralization)
+
   enum StateBits {
-    kWasCompiledPos = 0,
-    kWasExecutedPos = 1,
+#define DECLARE_FLAG_POS(Name) k##Name##Pos,
+    STATE_BITS_LIST(DECLARE_FLAG_POS)
+#undef DECLARE_FLAG_POS
   };
-  class WasCompiledBit : public BitField<uint8_t, bool, kWasCompiledPos, 1> {};
-  class WasExecutedBit : public BitField<uint8_t, bool, kWasExecutedPos, 1> {};
+#define DEFINE_FLAG_BIT(Name)                                                  \
+  class Name##Bit : public BitField<uint8_t, bool, k##Name##Pos, 1> {};
+  STATE_BITS_LIST(DEFINE_FLAG_BIT)
+#undef DEFINE_FLAG_BIT
 
-  // 'WasCompiled' is true if the function was compiled once in this
-  // VM instantiation. It is independent from presence of type feedback
-  // (ic_data_array) and code, which may be loaded from a snapshot.
-  void SetWasCompiled(bool value) const {
-    set_state_bits(WasCompiledBit::update(value, state_bits()));
-  }
-  bool WasCompiled() const { return WasCompiledBit::decode(state_bits()); }
-
-  // 'WasExecuted' is true if the usage counter has ever been positive.
-  void SetWasExecuted(bool value) const {
-    set_state_bits(WasExecutedBit::update(value, state_bits()));
-  }
-  bool WasExecuted() const {
-    return (usage_counter() > 0) || WasExecutedBit::decode(state_bits());
-  }
+#define DEFINE_FLAG_ACCESSORS(Name)                                            \
+  void Set##Name(bool value) const {                                           \
+    set_state_bits(Name##Bit::update(value, state_bits()));                    \
+  }                                                                            \
+  bool Name() const { return Name##Bit::decode(state_bits()); }
+  STATE_BITS_LIST(DEFINE_FLAG_ACCESSORS)
+#undef DEFINE_FLAG_ACCESSORS
 
   void SetUsageCounter(intptr_t value) const {
     if (usage_counter() > 0) {
@@ -2818,6 +2827,10 @@
     set_usage_counter(value);
   }
 
+  bool WasExecuted() const { return (usage_counter() > 0) || WasExecutedBit(); }
+
+  void SetWasExecuted(bool value) const { SetWasExecutedBit(value); }
+
   // static: Considered during class-side or top-level resolution rather than
   //         instance-side resolution.
   // const: Valid target of a const constructor call.
@@ -2855,8 +2868,6 @@
   V(Native, is_native)                                                         \
   V(Redirecting, is_redirecting)                                               \
   V(External, is_external)                                                     \
-  V(AllowsHoistingCheckClass, allows_hoisting_check_class)                     \
-  V(AllowsBoundsCheckGeneralization, allows_bounds_check_generalization)       \
   V(GeneratedBody, is_generated_body)                                          \
   V(AlwaysInline, always_inline)                                               \
   V(PolymorphicTarget, is_polymorphic_target)
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 43b9a5c..2d62110 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -57,6 +57,13 @@
 }
 #endif  // !PRODUCT
 
+static RawInstance* AllocateObjectByClassName(const Library& library,
+                                              const String& class_name) {
+  const Class& cls = Class::Handle(library.LookupClassAllowPrivate(class_name));
+  ASSERT(!cls.IsNull());
+  return Instance::New(cls);
+}
+
 RawError* ObjectStore::PreallocateObjects() {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
@@ -81,17 +88,13 @@
   Object& result = Object::Handle();
   const Library& library = Library::Handle(Library::CoreLibrary());
 
-  result =
-      DartLibraryCalls::InstanceCreate(library, Symbols::StackOverflowError(),
-                                       Symbols::Dot(), Object::empty_array());
+  result = AllocateObjectByClassName(library, Symbols::StackOverflowError());
   if (result.IsError()) {
     return Error::Cast(result).raw();
   }
   set_stack_overflow(Instance::Cast(result));
 
-  result =
-      DartLibraryCalls::InstanceCreate(library, Symbols::OutOfMemoryError(),
-                                       Symbols::Dot(), Object::empty_array());
+  result = AllocateObjectByClassName(library, Symbols::OutOfMemoryError());
   if (result.IsError()) {
     return Error::Cast(result).raw();
   }
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index fdd9ee4..a68bce5 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -387,7 +387,6 @@
   V(ExternalName, "ExternalName")                                              \
   V(_Random, "_Random")                                                        \
   V(_state, "_state")                                                          \
-  V(_A, "_A")                                                                  \
   V(_stackTrace, "_stackTrace")                                                \
   V(_SpecialTypeMirror, "_SpecialTypeMirror")                                  \
   V(_LocalClassMirror, "_LocalClassMirror")                                    \
diff --git a/tests/lib_2/html/interactive_media_test.dart b/tests/lib_2/html/interactive_media_test.dart
index 25d43d4..d7060ac 100644
--- a/tests/lib_2/html/interactive_media_test.dart
+++ b/tests/lib_2/html/interactive_media_test.dart
@@ -18,71 +18,86 @@
 
   if (MediaStream.supported) {
     test('getUserMedia audio', () async {
-      var mediaStream = await window.navigator.getUserMedia(audio: true);
-      expect(mediaStream, isNotNull);
-      expect(mediaStream is MediaStream, true);
-      var devices = window.navigator.mediaDevices;
-      var enumDevices = await devices.enumerateDevices();
-      expect(enumDevices.length > 1, true);
-      for (var device in enumDevices) {
-        var goodDevLabel = device.label.endsWith('Built-in Output') ||
-            device.label.endsWith('Built-in Microphone');
-        expect(goodDevLabel, true);
+      try {
+        var mediaStream = await window.navigator.getUserMedia(audio: true);
+        expect(mediaStream, isNotNull);
+        expect(mediaStream is MediaStream, true);
+        var devices = window.navigator.mediaDevices;
+        var enumDevices = await devices.enumerateDevices();
+        expect(enumDevices.length > 1, true);
+        for (var device in enumDevices) {
+          var goodDevLabel = device.label.endsWith('Built-in Output') ||
+              device.label.endsWith('Built-in Microphone');
+          expect(goodDevLabel, true);
+        }
+      } catch (e) {
+        // Could fail if bot machine doesn't support audio or video.
+        expect(e.name, DomException.NOT_FOUND);
       }
     });
 
     test('getUserMedia', () {
-      return window.navigator.getUserMedia(video: true).then((stream) {
-        expect(stream, isNotNull);
+      try {
+        return window.navigator.getUserMedia(video: true).then((stream) {
+          expect(stream, isNotNull);
 
-        var url = Url.createObjectUrlFromStream(stream);
-        expect(url, isNotNull);
+          var url = Url.createObjectUrlFromStream(stream);
+          expect(url, isNotNull);
 
-        var video = new VideoElement()..autoplay = true;
+          var video = new VideoElement()..autoplay = true;
 
-        var completer = new Completer();
-        video.onError.listen((e) {
-          completer.completeError(e);
+          var completer = new Completer();
+          video.onError.listen((e) {
+            completer.completeError(e);
+          });
+          video.onPlaying.first.then((e) {
+            completer.complete(video);
+          });
+
+          document.body.append(video);
+          video.src = url;
+
+          return completer.future;
         });
-        video.onPlaying.first.then((e) {
-          completer.complete(video);
-        });
-
-        document.body.append(video);
-        video.src = url;
-
-        return completer.future;
-      });
+      } catch (e) {
+        // Could fail if bot machine doesn't support audio or video.
+        expect(e.name, DomException.NOT_FOUND);
+      }
     });
 
     test('getUserMediaComplexConstructor', () {
-      return window.navigator.getUserMedia(video: {
-        'mandatory': {'minAspectRatio': 1.333, 'maxAspectRatio': 1.334},
-        'optional': [
-          {'minFrameRate': 60},
-          {'maxWidth': 640}
-        ]
-      }).then((stream) {
-        expect(stream, isNotNull);
+      try {
+        return window.navigator.getUserMedia(video: {
+          'mandatory': {'minAspectRatio': 1.333, 'maxAspectRatio': 1.334},
+          'optional': [
+            {'minFrameRate': 60},
+            {'maxWidth': 640}
+          ]
+        }).then((stream) {
+          expect(stream, isNotNull);
 
-        var url = Url.createObjectUrlFromStream(stream);
-        expect(url, isNotNull);
+          var url = Url.createObjectUrlFromStream(stream);
+          expect(url, isNotNull);
 
-        var video = new VideoElement()..autoplay = true;
+          var video = new VideoElement()..autoplay = true;
 
-        var completer = new Completer();
-        video.onError.listen((e) {
-          completer.completeError(e);
+          var completer = new Completer();
+          video.onError.listen((e) {
+            completer.completeError(e);
+          });
+          video.onPlaying.first.then((e) {
+            completer.complete(video);
+          });
+
+          document.body.append(video);
+          video.src = url;
+
+          return completer.future;
         });
-        video.onPlaying.first.then((e) {
-          completer.complete(video);
-        });
-
-        document.body.append(video);
-        video.src = url;
-
-        return completer.future;
-      });
+      } catch (e) {
+        // Could fail if bot machine doesn't support audio or video.
+        expect(e.name, DomException.NOT_FOUND);
+      }
     });
   }
 }
diff --git a/tests/lib_2/lib_2_dart2js.status b/tests/lib_2/lib_2_dart2js.status
index e49ac50..72d9070 100644
--- a/tests/lib_2/lib_2_dart2js.status
+++ b/tests/lib_2/lib_2_dart2js.status
@@ -468,6 +468,9 @@
 [ $compiler == dart2js && $system == linux ]
 html/interactive_geolocation_test: Skip # Requires allowing geo location.
 
+[ $compiler == dart2js && $system != macos && ($runtime != chrome || $runtime != safari) ]
+html/interactive_media_test: RuntimeError # # See NOTE in test on how to run.
+
 [ $compiler == dart2js && $system == windows ]
 html/xhr_test: RuntimeError
 
@@ -790,9 +793,6 @@
 convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
 
-[ $compiler == dart2js && ($runtime != chrome || $system != macos) ]
-html/interactive_media_test: RuntimeError # # See NOTE in test on how to run.
-
 [ $compiler == dart2js && ($runtime == ff || $runtime == safari || $ie) ]
 html/custom/attribute_changed_callback_test/unsupported_on_polyfill: Fail # Polyfill does not support
 html/custom/entered_left_view_test/viewless_document: Fail # Polyfill does not handle this
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index f015610..14b7bf9 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -134,7 +134,6 @@
 mirrors/library_metadata_test: RuntimeError
 mirrors/load_library_test: RuntimeError
 mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes.
-mirrors/metadata_constructed_constant_test: Crash, RuntimeError
 mirrors/metadata_scope_test/none: RuntimeError
 mirrors/method_mirror_location_test: RuntimeError
 mirrors/method_mirror_source_line_ending_test: Crash
@@ -221,13 +220,11 @@
 mirrors/instance_members_with_override_test: RuntimeError
 mirrors/invoke_closurization2_test: RuntimeError
 mirrors/invoke_throws_test: RuntimeError
-mirrors/metadata_const_map_test: Crash
 mirrors/mixin_members_test: RuntimeError
 mirrors/operator_test: RuntimeError
 mirrors/redirecting_factory_different_type_test/02: MissingCompileTimeError
 mirrors/redirecting_factory_different_type_test/none: RuntimeError
 mirrors/redirecting_factory_reflection_test: RuntimeError
-mirrors/regress_16321_test/none: Crash
 mirrors/top_level_accessors_test/01: MissingCompileTimeError
 
 # Enabling of dartk for sim{arm,arm64,dbc64} revealed these test failures, which
diff --git a/tests/lib_2/mirrors/metadata_type_literal_test.dart b/tests/lib_2/mirrors/metadata_type_literal_test.dart
new file mode 100644
index 0000000..a40023a
--- /dev/null
+++ b/tests/lib_2/mirrors/metadata_type_literal_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class Foo {}
+
+class Annotation {
+  final Object bindings;
+  const Annotation(this.bindings);
+}
+
+@Annotation(Foo)
+class Annotated {}
+
+main(List<String> args) {
+  ClassMirror mirror = reflectType(Annotated);
+  Expect.equals("ClassMirror on 'Annotated'", mirror.toString());
+
+  var bindings = mirror.metadata[0].reflectee.bindings;
+  Expect.equals('Foo', bindings.toString());
+}
diff --git a/tools/VERSION b/tools/VERSION
index 717dac6..18e0327 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 0
 PATCH 0
-PRERELEASE 57
+PRERELEASE 58
 PRERELEASE_PATCH 0