Version 2.17.0-237.0.dev

Merge commit '539e14296d42a409e0ca1753f98cd1a9b5500600' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 911bfcd..33e98e9 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -2887,6 +2887,35 @@
         r"""Enum factory constructors can't redirect to generative constructors.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name, String name2)>
+    templateEnumImplementerContainsRestrictedInstanceDeclaration =
+    const Template<Message Function(String name, String name2)>(
+        problemMessageTemplate:
+            r"""'#name' has 'Enum' as a superinterface and can't contain non-static members with name '#name2'.""",
+        withArguments:
+            _withArgumentsEnumImplementerContainsRestrictedInstanceDeclaration);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name, String name2)>
+    codeEnumImplementerContainsRestrictedInstanceDeclaration =
+    const Code<Message Function(String name, String name2)>(
+  "EnumImplementerContainsRestrictedInstanceDeclaration",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsEnumImplementerContainsRestrictedInstanceDeclaration(
+    String name, String name2) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  if (name2.isEmpty) throw 'No name provided';
+  name2 = demangleMixinApplicationName(name2);
+  return new Message(codeEnumImplementerContainsRestrictedInstanceDeclaration,
+      problemMessage:
+          """'${name}' has 'Enum' as a superinterface and can't contain non-static members with name '${name2}'.""",
+      arguments: {'name': name, 'name2': name2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
     templateEnumImplementerContainsValuesDeclaration =
     const Template<Message Function(String name)>(
@@ -2921,6 +2950,38 @@
     correctionMessage: r"""Try moving the enum to the top-level.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)> templateEnumInheritsRestricted =
+    const Template<Message Function(String name)>(
+        problemMessageTemplate:
+            r"""An enum can't inherit a member named '#name'.""",
+        withArguments: _withArgumentsEnumInheritsRestricted);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeEnumInheritsRestricted =
+    const Code<Message Function(String name)>(
+  "EnumInheritsRestricted",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsEnumInheritsRestricted(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeEnumInheritsRestricted,
+      problemMessage: """An enum can't inherit a member named '${name}'.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeEnumInheritsRestrictedMember =
+    messageEnumInheritsRestrictedMember;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageEnumInheritsRestrictedMember = const MessageCode(
+    "EnumInheritsRestrictedMember",
+    severity: Severity.context,
+    problemMessage: r"""This is the inherited member""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeEnumInstantiation = messageEnumInstantiation;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index e5e361b..e8855e1 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
 name: _fe_analyzer_shared
-version: 37.0.0
+version: 38.0.0
 description: Logic that is shared between the front_end and analyzer packages.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/_fe_analyzer_shared
 
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index 93f4244..893de44 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -487,11 +487,11 @@
     await contextManager.refresh();
   }
 
-  ResolvedForCompletionResultImpl? resolveForCompletion({
+  Future<ResolvedForCompletionResultImpl?> resolveForCompletion({
     required String path,
     required int offset,
     required OperationPerformanceImpl performance,
-  }) {
+  }) async {
     if (!file_paths.isDart(resourceProvider.pathContext, path)) {
       return null;
     }
@@ -502,6 +502,7 @@
     }
 
     try {
+      await driver.applyPendingFileChanges();
       return driver.resolveForCompletion(
         path: path,
         offset: offset,
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 38d2b60..57f98ce 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -175,7 +175,7 @@
     performance.runAsync(
       'request',
       (performance) async {
-        var resolvedUnit = performance.run(
+        var resolvedUnit = await performance.runAsync(
           'resolveForCompletion',
           (performance) {
             return server.resolveForCompletion(
diff --git a/pkg/analysis_server/lib/src/lsp/client_configuration.dart b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
index c7497dd..6a97756 100644
--- a/pkg/analysis_server/lib/src/lsp/client_configuration.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
@@ -166,16 +166,20 @@
       true;
 
   /// Whether to include Snippets in code completion results.
-  bool get enableSnippets =>
-      // TODO(dantup): Change this setting to `enableSnippets`
-      //    and default to `true`
-      //    and remove `initializeWithSnippetSupportAndPreviewFlag` from tests
-      //    once all snippets are implemented and VS Code has shipped a
-      //    version that maps `enableServerSnippets` to `enableSnippets` in
-      //    middleware to avoid dupes.
-      _settings['previewEnableSnippets'] as bool? ??
-      _fallback?.enableSnippets ??
-      false;
+  bool get enableSnippets {
+    // Versions of Dart-Code earlier than v3.36 (1 Mar 2022) send
+    // enableServerSnippets=false to opt-out of snippets. Later versions map
+    // this version to the documented 'enableSnippets' setting in middleware.
+    // Once the number of users on < 3.36 is insignificant, this check can be
+    // removed. At 24 Mar 2022, approx 9% of users are on < 3.36.
+    if (_settings['enableServerSnippets'] == false /* explicit false */) {
+      return false;
+    }
+
+    return _settings['enableSnippets'] as bool? ??
+        _fallback?.enableSnippets ??
+        true;
+  }
 
   /// The line length used when formatting documents.
   ///
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index ad469f1..a0e8c5c 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -344,6 +344,23 @@
       ..suggestions.isEmpty;
   }
 
+  Future<void> test_applyPendingFileChanges() async {
+    await _configureWithWorkspaceRoot();
+
+    // Request with the empty content.
+    await _getTestCodeSuggestions('^');
+
+    // Change the file, and request again.
+    // Should apply pending file changes before resolving.
+    var response = await _getTestCodeSuggestions('Str^');
+
+    check(response).suggestions.includesAll([
+      (suggestion) => suggestion
+        ..completion.isEqualTo('String')
+        ..isClass,
+    ]);
+  }
+
   Future<void> test_isNotImportedFeature_prefixed_classInstanceMethod() async {
     newFile2('$testPackageLibPath/a.dart', '''
 class A {
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 66749c1..92744a4 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -2386,7 +2386,7 @@
 clas^
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartClassSnippetProducer.prefix,
@@ -2400,6 +2400,8 @@
 ''');
   }
 
+  /// Checks that the `enableSnippets` setting can disable snippets even if the
+  /// client supports them.
   Future<void> test_snippets_disabled() async {
     final content = '^';
 
@@ -2412,13 +2414,10 @@
         workspaceCapabilities:
             withConfigurationSupport(emptyWorkspaceClientCapabilities),
       ),
-      {'enableSnippets': true},
+      {'enableSnippets': false},
     );
 
-    await expectNoSnippet(
-      content,
-      FlutterStatelessWidgetSnippetProducer.prefix,
-    );
+    await expectNoSnippets(content);
   }
 
   Future<void> test_snippets_doWhile() async {
@@ -2428,7 +2427,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartDoWhileLoopSnippetProducer.prefix,
@@ -2454,7 +2453,7 @@
 class B {}
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     await expectNoSnippet(
       content,
       FlutterStatelessWidgetSnippetProducer.prefix,
@@ -2468,7 +2467,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartForLoopSnippetProducer.prefix,
@@ -2491,7 +2490,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartForInLoopSnippetProducer.prefix,
@@ -2514,7 +2513,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartIfSnippetProducer.prefix,
@@ -2537,7 +2536,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartIfElseSnippetProducer.prefix,
@@ -2564,7 +2563,7 @@
 class B {}
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartMainFunctionSnippetProducer.prefix,
@@ -2600,7 +2599,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartSwitchSnippetProducer.prefix,
@@ -2628,7 +2627,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartTestBlockSnippetProducer.prefix,
@@ -2653,7 +2652,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartTestGroupBlockSnippetProducer.prefix,
@@ -2676,7 +2675,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartTryCatchSnippetProducer.prefix,
@@ -2701,7 +2700,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: DartWhileLoopSnippetProducer.prefix,
@@ -2747,7 +2746,7 @@
 class B {}
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: FlutterStatefulWidgetSnippetProducer.prefix,
@@ -2788,7 +2787,7 @@
 class B {}
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix:
@@ -2845,7 +2844,7 @@
 class B {}
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: FlutterStatelessWidgetSnippetProducer.prefix,
@@ -2879,7 +2878,7 @@
 class B {}
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: FlutterStatelessWidgetSnippetProducer.prefix,
@@ -2910,7 +2909,7 @@
 stless^
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: FlutterStatelessWidgetSnippetProducer.prefix,
@@ -2937,7 +2936,7 @@
 ^
 '''; // Deliberate trailing newline to ensure imports aren't inserted at "end".
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
       prefix: FlutterStatelessWidgetSnippetProducer.prefix,
@@ -2968,7 +2967,7 @@
 }
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     await expectNoSnippet(
       content,
       FlutterStatelessWidgetSnippetProducer.prefix,
@@ -2980,7 +2979,7 @@
 stle^
 ''';
 
-    await initializeWithSnippetSupportAndPreviewFlag();
+    await initializeWithSnippetSupport();
     final otherFileUri = Uri.file(convertPath('/other/file.dart'));
     await openFile(otherFileUri, withoutMarkers(content));
     final res = await getCompletion(otherFileUri, positionFromMarker(content));
@@ -3040,6 +3039,14 @@
     expect(hasSnippet, isFalse);
   }
 
+  /// Expect that there are no snippets at the position of `^` within [content].
+  Future<void> expectNoSnippets(String content) async {
+    await openFile(mainFileUri, withoutMarkers(content));
+    final res = await getCompletion(mainFileUri, positionFromMarker(content));
+    final hasAnySnippet = res.any((c) => c.kind == CompletionItemKind.Snippet);
+    expect(hasAnySnippet, isFalse);
+  }
+
   /// Expect that there is a snippet for [prefix] with the label [label] at
   /// [position] in [content].
   Future<CompletionItem> expectSnippet(
@@ -3062,14 +3069,4 @@
         textDocumentCapabilities: withCompletionItemSnippetSupport(
             emptyTextDocumentClientCapabilities),
       );
-
-  Future<void> initializeWithSnippetSupportAndPreviewFlag() => provideConfig(
-        () => initialize(
-          textDocumentCapabilities: withCompletionItemSnippetSupport(
-              emptyTextDocumentClientCapabilities),
-          workspaceCapabilities:
-              withConfigurationSupport(emptyWorkspaceClientCapabilities),
-        ),
-        {'previewEnableSnippets': true},
-      );
 }
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index ccf6e8a..25a61e3 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -23,22 +23,23 @@
 
 ## Initialization Options
 
-- `onlyAnalyzeProjectsWithOpenFiles`: When set to `true`, workspace folders will be ignored and analysis will be performed based on the open files, as if no workspace was open at all. This allows opening large folders without causing them to be completely analyzed. Defaults to `false`.
-- `suggestFromUnimportedLibraries`: When set to `false`, completion will not include synbols that are not already imported into the current file. Defaults to `true`, though the client must additionally support `workspace/applyEdit` for these completions to be included.
-- `closingLabels`: When set to `true`, `dart/textDocument/publishClosingLabels` notifications will be sent with information to render editor closing labels.
-- `outline`: When set to `true`, `dart/textDocument/publishOutline` notifications will be sent with outline information for open files.
-- `flutterOutline`: When set to `true`, `dart/textDocument/publishFlutterOutline` notifications will be sent with Flutter outline information for open files.
+- `onlyAnalyzeProjectsWithOpenFiles` (`bool?`): When set to `true`, workspace folders will be ignored and analysis will be performed based on the open files, as if no workspace was open at all. This allows opening large folders without causing them to be completely analyzed. Defaults to `false`.
+- `suggestFromUnimportedLibraries` (`bool?`): When set to `false`, completion will not include synbols that are not already imported into the current file. Defaults to `true`, though the client must additionally support `workspace/applyEdit` for these completions to be included.
+- `closingLabels` (`bool?`): When set to `true`, `dart/textDocument/publishClosingLabels` notifications will be sent with information to render editor closing labels.
+- `outline` (`bool?`): When set to `true`, `dart/textDocument/publishOutline` notifications will be sent with outline information for open files.
+- `flutterOutline` (`bool?`): When set to `true`, `dart/textDocument/publishFlutterOutline` notifications will be sent with Flutter outline information for open files.
 
 ## Client Workspace Configuration
 
 Client workspace settings are requested with `workspace/configuration` during initialization and re-requested whenever the client notifies the server with `workspace/didChangeConfiguration`. This allows the settings to take effect without restarting the server.
 
-- `dart.analysisExcludedFolders`: An array of paths (absolute or relative to each workspace folder) that should be excluded from analysis.
-- `dart.enableSdkFormatter`: When set to `false`, prevents registration (or unregisters) the SDK formatter. When set to `true` or not supplied, will register/reregister the SDK formatter.
-- `dart.lineLength`: The number of characters the formatter should wrap code at. If unspecified, code will be wrapped at `80` characters.
-- `dart.completeFunctionCalls`: Completes functions/methods with their required parameters.
-- `dart.showTodos`: Whether to generate diagnostics for TODO comments. If unspecified, diagnostics will not be generated.
-- `dart.renameFilesWithClasses`: When set to `"always"`, will rename files when classes are renamed if the filename matches the class name (but in snake_form). When set to `"prompt"`, a prompt will be shown on each class rename asking to confirm the file rename. Otherwise, files will not be renamed. Renames are performed using LSP's ResourceOperation edits - that means the rename is simply included in the resulting `WorkspaceEdit` and must be handled by the client.
+- `dart.analysisExcludedFolders` (`List<String>?`): An array of paths (absolute or relative to each workspace folder) that should be excluded from analysis.
+- `dart.enableSdkFormatter` (`bool?`): When set to `false`, prevents registration (or unregisters) the SDK formatter. When set to `true` or not supplied, will register/reregister the SDK formatter.
+- `dart.lineLength` (`int?`): The number of characters the formatter should wrap code at. If unspecified, code will be wrapped at `80` characters.
+- `dart.completeFunctionCalls` (`bool?`): When set to true, completes functions/methods with their required parameters.
+- `dart.showTodos` (`bool?`): Whether to generate diagnostics for TODO comments. If unspecified, diagnostics will not be generated.
+- `dart.renameFilesWithClasses` (`String`): When set to `"always"`, will include edits to rename files when classes are renamed if the filename matches the class name (but in snake_form). When set to `"prompt"`, a prompt will be shown on each class rename asking to confirm the file rename. Otherwise, files will not be renamed. Renames are performed using LSP's ResourceOperation edits - that means the rename is simply included in the resulting `WorkspaceEdit` and must be handled by the client.
+- `dart.enableSnippets` (`bool?`): Whether to include code snippets (such as `class`, `stful`, `switch`) in code completion. When unspecified, snippets will be included.
 
 ## Method Status
 
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 0c4a820..af3475f 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 3.4.1
+* Remove checks for consistency after operations in `AnalysisSession`.
+
 ## 3.4.0
 * Deprecated `Resource.parent2`, use `parent` instead.
 * Deprecated `astFactory`, clients should not create AST nodes manually.
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index eccf228..eef485d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -57,33 +57,25 @@
   @override
   Future<SomeErrorsResult> getErrors(String path) async {
     _checkConsistency();
-    var result = await _driver.getErrors(path);
-    _checkConsistency();
-    return result;
+    return await _driver.getErrors(path);
   }
 
   @override
   SomeFileResult getFile(String path) {
     _checkConsistency();
-    var result = _driver.getFileSync(path);
-    _checkConsistency();
-    return result;
+    return _driver.getFileSync(path);
   }
 
   @override
   Future<SomeLibraryElementResult> getLibraryByUri(String uri) async {
     _checkConsistency();
-    var result = await _driver.getLibraryByUri(uri);
-    _checkConsistency();
-    return result;
+    return await _driver.getLibraryByUri(uri);
   }
 
   @override
   SomeParsedLibraryResult getParsedLibrary(String path) {
     _checkConsistency();
-    var result = _driver.getParsedLibrary(path);
-    _checkConsistency();
-    return result;
+    return _driver.getParsedLibrary(path);
   }
 
   @override
@@ -94,25 +86,19 @@
       return NotElementOfThisSessionResult();
     }
 
-    var result = _driver.getParsedLibraryByUri(element.source.uri);
-    _checkConsistency();
-    return result;
+    return _driver.getParsedLibraryByUri(element.source.uri);
   }
 
   @override
   SomeParsedUnitResult getParsedUnit(String path) {
     _checkConsistency();
-    var result = _driver.parseFileSync(path);
-    _checkConsistency();
-    return result;
+    return _driver.parseFileSync(path);
   }
 
   @override
   Future<SomeResolvedLibraryResult> getResolvedLibrary(String path) async {
     _checkConsistency();
-    var result = await _driver.getResolvedLibrary(path);
-    _checkConsistency();
-    return result;
+    return await _driver.getResolvedLibrary(path);
   }
 
   @override
@@ -125,25 +111,19 @@
       return NotElementOfThisSessionResult();
     }
 
-    var result = await _driver.getResolvedLibraryByUri(element.source.uri);
-    _checkConsistency();
-    return result;
+    return await _driver.getResolvedLibraryByUri(element.source.uri);
   }
 
   @override
   Future<SomeResolvedUnitResult> getResolvedUnit(String path) async {
     _checkConsistency();
-    var result = await _driver.getResult(path);
-    _checkConsistency();
-    return result;
+    return await _driver.getResult(path);
   }
 
   @override
   Future<SomeUnitElementResult> getUnitElement(String path) {
     _checkConsistency();
-    var result = _driver.getUnitElement(path);
-    _checkConsistency();
-    return result;
+    return _driver.getUnitElement(path);
   }
 
   /// Check to see that results from this session will be consistent, and throw
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index a2c3b09..a645d81 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -85,20 +85,19 @@
     var typeArgumentList = _getTypeArguments(node);
 
     List<DartType>? typeArgumentTypes;
-    FunctionType? invokeType;
     GenericInferrer? inferrer;
+    Substitution? substitution;
     if (_isGenericInferenceDisabled(resolver)) {
       if (rawType != null && rawType.typeFormals.isNotEmpty) {
         typeArgumentTypes = List.filled(
           rawType.typeFormals.length,
           DynamicTypeImpl.instance,
         );
+        substitution =
+            Substitution.fromPairs(rawType.typeFormals, typeArgumentTypes);
       } else {
         typeArgumentTypes = const <DartType>[];
-        invokeType = rawType;
       }
-
-      invokeType = rawType?.instantiate(typeArgumentTypes);
     } else if (typeArgumentList != null) {
       if (rawType != null &&
           typeArgumentList.arguments.length != rawType.typeFormals.length) {
@@ -138,10 +137,12 @@
         }
       }
 
-      invokeType = rawType?.instantiate(typeArgumentTypes);
+      if (rawType != null) {
+        substitution =
+            Substitution.fromPairs(rawType.typeFormals, typeArgumentTypes);
+      }
     } else if (rawType == null || rawType.typeFormals.isEmpty) {
       typeArgumentTypes = const <DartType>[];
-      invokeType = rawType;
     } else {
       rawType = getFreshTypeParameters(rawType.typeFormals)
           .applyToFunctionType(rawType);
@@ -156,16 +157,21 @@
         genericMetadataIsEnabled: resolver.genericMetadataIsEnabled,
       );
 
-      invokeType = rawType.instantiate(inferrer.downwardsInfer());
+      substitution = Substitution.fromPairs(
+          rawType.typeFormals, inferrer.downwardsInfer());
     }
 
-    super.resolveInvocation(
+    List<EqualityInfo<PromotableElement, DartType>?>? identicalInfo =
+        _isIdentical(node) ? [] : null;
+    _visitArguments(
         resolver: resolver,
         node: node,
         argumentList: argumentList,
-        rawType: invokeType,
+        rawType: rawType,
         contextType: contextType,
-        whyNotPromotedList: whyNotPromotedList);
+        whyNotPromotedList: whyNotPromotedList,
+        identicalInfo: identicalInfo,
+        substitution: substitution);
 
     if (inferrer != null) {
       // Get the parameters that correspond to the uninstantiated generic.
@@ -186,8 +192,10 @@
       }
       inferrer.constrainArguments(parameters: params, argumentTypes: argTypes);
       typeArgumentTypes = inferrer.upwardsInfer();
-      invokeType = rawType.instantiate(typeArgumentTypes);
     }
+    FunctionType? invokeType = typeArgumentTypes != null
+        ? rawType?.instantiate(typeArgumentTypes)
+        : rawType;
 
     var parameters = _storeResult(node, typeArgumentTypes, invokeType);
     if (parameters != null) {
@@ -198,8 +206,14 @@
         errorReporter: resolver.errorReporter,
       );
     }
-    var returnType = InvocationInferrer.computeInvokeReturnType(invokeType);
-    return _refineReturnType(resolver, node, returnType);
+    var returnType = _refineReturnType(
+        resolver, node, InvocationInferrer.computeInvokeReturnType(invokeType));
+    _recordIdenticalInfo(
+        resolver: resolver,
+        node: node,
+        argumentList: argumentList,
+        identicalInfo: identicalInfo);
+    return returnType;
   }
 
   AstNode _getErrorNode(Node node) => node;
@@ -337,6 +351,55 @@
     required DartType? contextType,
     required List<WhyNotPromotedGetter> whyNotPromotedList,
   }) {
+    _visitArguments(
+        resolver: resolver,
+        node: node,
+        argumentList: argumentList,
+        rawType: rawType,
+        contextType: contextType,
+        whyNotPromotedList: whyNotPromotedList);
+  }
+
+  /// Computes the type context that should be used when evaluating a particular
+  /// argument of the invocation.  Usually this is just the type of the
+  /// corresponding parameter, but it can be different for certain primitive
+  /// numeric operations.
+  DartType? _computeContextForArgument(ResolverVisitor resolver, Node node,
+          DartType parameterType, DartType? methodInvocationContext) =>
+      parameterType;
+
+  /// Determines whether [node] is an invocation of the core function
+  /// `identical` (which needs special flow analysis treatment).
+  bool _isIdentical(Node node) => false;
+
+  /// If the invocation being processed is a call to `identical`, informs flow
+  /// analysis about it, so that it can do appropriate promotions.
+  void _recordIdenticalInfo(
+      {required ResolverVisitor resolver,
+      required Node node,
+      required ArgumentListImpl argumentList,
+      required List<EqualityInfo<PromotableElement, DartType>?>?
+          identicalInfo}) {
+    var flow = resolver.flowAnalysis.flow;
+    if (identicalInfo != null) {
+      flow?.equalityOperation_end(argumentList.parent as Expression,
+          identicalInfo[0], identicalInfo[1]);
+    }
+  }
+
+  /// Visits [argumentList], resolving each argument.  If any arguments need to
+  /// be deferred due to the `inference-update-1` feature, a list of them is
+  /// returned.
+  void _visitArguments(
+      {required ResolverVisitor resolver,
+      required Node node,
+      required ArgumentListImpl argumentList,
+      required FunctionType? rawType,
+      required DartType? contextType,
+      required List<WhyNotPromotedGetter> whyNotPromotedList,
+      List<EqualityInfo<PromotableElement, DartType>?>? identicalInfo,
+      Substitution? substitution}) {
+    assert(whyNotPromotedList.isEmpty);
     var parameters = rawType?.parameters;
     var namedParameters = <String, ParameterElement>{};
     if (parameters != null) {
@@ -350,8 +413,6 @@
     resolver.checkUnreachableNode(argumentList);
     var flow = resolver.flowAnalysis.flow;
     var positionalParameterIndex = 0;
-    List<EqualityInfo<PromotableElement, DartType>?>? identicalInfo =
-        _isIdentical(node) ? [] : null;
     var arguments = argumentList.arguments;
     for (int i = 0; i < arguments.length; i++) {
       var argument = arguments[i];
@@ -370,6 +431,9 @@
       DartType? parameterContextType;
       if (parameter != null) {
         var parameterType = parameter.type;
+        if (substitution != null) {
+          parameterType = substitution.substituteType(parameterType);
+        }
         parameterContextType = _computeContextForArgument(
             resolver, node, parameterType, contextType);
       }
@@ -382,24 +446,8 @@
         whyNotPromotedList.add(flow.whyNotPromoted(argument));
       }
     }
-    if (identicalInfo != null) {
-      flow?.equalityOperation_end(argumentList.parent as Expression,
-          identicalInfo[0], identicalInfo[1]);
-    }
   }
 
-  /// Computes the type context that should be used when evaluating a particular
-  /// argument of the invocation.  Usually this is just the type of the
-  /// corresponding parameter, but it can be different for certain primitive
-  /// numeric operations.
-  DartType? _computeContextForArgument(ResolverVisitor resolver, Node node,
-          DartType parameterType, DartType? methodInvocationContext) =>
-      parameterType;
-
-  /// Determines whether [node] is an invocation of the core function
-  /// `identical` (which needs special flow analysis treatment).
-  bool _isIdentical(Node node) => false;
-
   /// Computes the return type of the method or function represented by the
   /// given type that is being invoked.
   static DartType computeInvokeReturnType(DartType? type) {
diff --git a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
index 496f77d..42d4dde 100644
--- a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
+++ b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
@@ -82,12 +82,13 @@
     }
 
     // Prepare lists of not initialized fields.
-    List<FieldElement> notInitFinalFields = <FieldElement>[];
-    List<FieldElement> notInitNonNullableFields = <FieldElement>[];
+    var notInitFinalFields = <FieldElement>[];
+    var notInitNonNullableFields = <FieldElement>[];
     _fieldMap.forEach((FieldElement field, _InitState state) {
       if (state != _InitState.notInit) return;
       if (field.isLate) return;
       if (field.isAbstract || field.isExternal) return;
+      if (field.isStatic) return;
 
       if (field.isFinal) {
         notInitFinalFields.add(field);
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index a407d52..b93727e 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1250,7 +1250,7 @@
   @override
   void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
     _checkForFinalNotInitialized(node.variables);
-    _checkForNotInitializedNonNullableVariable(node.variables);
+    _checkForNotInitializedNonNullableVariable(node.variables, true);
 
     for (var declaration in node.variables.variables) {
       _checkForMainFunction(declaration.name);
@@ -3789,18 +3789,19 @@
     if (!node.isStatic) {
       return;
     }
-    _checkForNotInitializedNonNullableVariable(node.fields);
+    _checkForNotInitializedNonNullableVariable(node.fields, false);
   }
 
   void _checkForNotInitializedNonNullableVariable(
     VariableDeclarationList node,
+    bool topLevel,
   ) {
     if (!_isNonNullableByDefault) {
       return;
     }
 
-    // Const and final checked separately.
-    if (node.isConst || node.isFinal) {
+    // Checked separately.
+    if (node.isConst || (topLevel && node.isFinal)) {
       return;
     }
 
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index c740b60..86abb1d 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 3.4.0
+version: 3.4.1
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
@@ -7,7 +7,7 @@
   sdk: '>=2.14.0 <3.0.0'
 
 dependencies:
-  _fe_analyzer_shared: ^37.0.0
+  _fe_analyzer_shared: ^38.0.0
   collection: ^1.15.0
   convert: ^3.0.0
   crypto: ^3.0.0
diff --git a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
index f24221e..5a9b9f2 100644
--- a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
@@ -185,6 +185,14 @@
 external final int x;
 ''');
   }
+
+  test_topLevel_final() async {
+    await assertErrorsInCode('''
+final int x;
+''', [
+      error(CompileTimeErrorCode.FINAL_NOT_INITIALIZED, 10, 1),
+    ]);
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
index 560bb4f..5c971f3 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
@@ -65,6 +65,28 @@
     ]);
   }
 
+  test_staticField_noInitializer_constructor() async {
+    await assertErrorsInCode('''
+class A {
+  static int x = 0, y, z = 2;
+  A();
+}
+''', [
+      error(CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_VARIABLE, 30, 1),
+    ]);
+  }
+
+  test_staticField_noInitializer_final_constructor() async {
+    await assertErrorsInCode('''
+class A {
+  static final int x = 0, y, z = 2;
+  A();
+}
+''', [
+      error(CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_VARIABLE, 36, 1),
+    ]);
+  }
+
   test_staticField_nullable() async {
     await assertNoErrorsInCode('''
 class A {
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index af806f9..e5e807e 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -16,11 +16,11 @@
 abstract class ClosureData {
   /// Deserializes a [ClosureData] object from [source].
   factory ClosureData.readFromDataSource(
-          JsToElementMap elementMap, DataSource source) =
+          JsToElementMap elementMap, DataSourceReader source) =
       ClosureDataImpl.readFromDataSource;
 
   /// Serializes this [ClosureData] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// Look up information about the variables that have been mutated and are
   /// used inside the scope of [node].
@@ -66,7 +66,7 @@
   const ScopeInfo();
 
   /// Deserializes a [ScopeInfo] object from [source].
-  factory ScopeInfo.readFromDataSource(DataSource source) {
+  factory ScopeInfo.readFromDataSource(DataSourceReader source) {
     ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
     switch (kind) {
       case ScopeInfoKind.scopeInfo:
@@ -82,7 +82,7 @@
   }
 
   /// Serializes this [ScopeInfo] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     throw UnsupportedError('${runtimeType}.writeToDataSink');
   }
 
@@ -126,7 +126,7 @@
   const CapturedScope();
 
   /// Deserializes a [CapturedScope] object from [source].
-  factory CapturedScope.readFromDataSource(DataSource source) {
+  factory CapturedScope.readFromDataSource(DataSourceReader source) {
     ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
     switch (kind) {
       case ScopeInfoKind.scopeInfo:
@@ -173,7 +173,7 @@
   const CapturedLoopScope();
 
   /// Deserializes a [CapturedLoopScope] object from [source].
-  factory CapturedLoopScope.readFromDataSource(DataSource source) {
+  factory CapturedLoopScope.readFromDataSource(DataSourceReader source) {
     ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
     switch (kind) {
       case ScopeInfoKind.scopeInfo:
@@ -241,7 +241,8 @@
   const ClosureRepresentationInfo();
 
   /// Deserializes a [ClosureRepresentationInfo] object from [source].
-  factory ClosureRepresentationInfo.readFromDataSource(DataSource source) {
+  factory ClosureRepresentationInfo.readFromDataSource(
+      DataSourceReader source) {
     ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
     switch (kind) {
       case ScopeInfoKind.scopeInfo:
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 0cf5baf..527f2fa 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -40,10 +40,10 @@
 class CodegenImpact extends WorldImpact {
   const CodegenImpact();
 
-  factory CodegenImpact.readFromDataSource(DataSource source) =
+  factory CodegenImpact.readFromDataSource(DataSourceReader source) =
       _CodegenImpact.readFromDataSource;
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     throw UnsupportedError('CodegenImpact.writeToDataSink');
   }
 
@@ -105,7 +105,7 @@
       this._oneShotInterceptors)
       : super.internal(dynamicUses, staticUses, typeUses, constantUses);
 
-  factory _CodegenImpact.readFromDataSource(DataSource source) {
+  factory _CodegenImpact.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberEntity member = source.readMember();
     Set<DynamicUse> dynamicUses = source
@@ -165,7 +165,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMember(member);
     sink.writeList(dynamicUses, (DynamicUse use) => use.writeToDataSink(sink),
@@ -502,7 +502,7 @@
   /// deserialization are collected in [modularNames] and [modularExpressions]
   /// to avoid the need for visiting the [code] node post deserialization.
   factory CodegenResult.readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       List<ModularName> modularNames,
       List<ModularExpression> modularExpressions) {
     source.begin(tag);
@@ -517,7 +517,7 @@
   /// The [modularNames] and [modularExpressions] fields are not directly
   /// serializes because these are embedded in the [code] node and collected
   /// through this during deserialization.
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeJsNodeOrNull(code);
     impact.writeToDataSink(sink);
@@ -635,7 +635,7 @@
 
   ModularName(this.kind, {this.data, this.set});
 
-  factory ModularName.readFromDataSource(DataSource source) {
+  factory ModularName.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ModularNameKind kind = source.readEnum(ModularNameKind.values);
     Object data;
@@ -678,7 +678,7 @@
     return ModularName(kind, data: data, set: set);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeEnum(kind);
     switch (kind) {
@@ -884,7 +884,7 @@
 
   ModularExpression(this.kind, this.data);
 
-  factory ModularExpression.readFromDataSource(DataSource source) {
+  factory ModularExpression.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ModularExpressionKind kind = source.readEnum(ModularExpressionKind.values);
     Object data;
@@ -900,7 +900,7 @@
     return ModularExpression(kind, data);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeEnum(kind);
     switch (kind) {
@@ -1107,13 +1107,13 @@
   static const String deferredHolderExpression = 'js-deferredHolderExpression';
 }
 
-/// Visitor that serializes a [js.Node] into a [DataSink].
+/// Visitor that serializes a [js.Node] into a [DataSinkWriter].
 class JsNodeSerializer implements js.NodeVisitor<void> {
-  final DataSink sink;
+  final DataSinkWriter sink;
 
   JsNodeSerializer._(this.sink);
 
-  static void writeToDataSink(DataSink sink, js.Node node) {
+  static void writeToDataSink(DataSinkWriter sink, js.Node node) {
     sink.begin(JsNodeTags.tag);
     JsNodeSerializer serializer = JsNodeSerializer._(sink);
     serializer.visit(node);
@@ -1775,19 +1775,19 @@
   }
 }
 
-/// Helper class that deserializes a [js.Node] from [DataSource].
+/// Helper class that deserializes a [js.Node] from [DataSourceReader].
 ///
 /// Deserialized [ModularName]s and [ModularExpression]s are collected in the
 /// [modularNames] and [modularExpressions] lists.
 class JsNodeDeserializer {
-  final DataSource source;
+  final DataSourceReader source;
   final List<ModularName> modularNames;
   final List<ModularExpression> modularExpressions;
 
   JsNodeDeserializer._(this.source, this.modularNames, this.modularExpressions);
 
   static js.Node readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       List<ModularName> modularNames,
       List<ModularExpression> modularExpressions) {
     source.begin(JsNodeTags.tag);
@@ -2229,24 +2229,24 @@
       this.closedWorld, this.modularNames, this.modularExpressions);
 
   @override
-  AbstractValue readAbstractValue(DataSource source) {
+  AbstractValue readAbstractValue(DataSourceReader source) {
     return closedWorld.abstractValueDomain
         .readAbstractValueFromDataSource(source);
   }
 
   @override
-  js.Node readJsNode(DataSource source) {
+  js.Node readJsNode(DataSourceReader source) {
     return JsNodeDeserializer.readFromDataSource(
         source, modularNames, modularExpressions);
   }
 
   @override
-  OutputUnit readOutputUnitReference(DataSource source) {
+  OutputUnit readOutputUnitReference(DataSourceReader source) {
     return closedWorld.outputUnitData.outputUnits[source.readInt()];
   }
 
   @override
-  TypeRecipe readTypeRecipe(DataSource source) {
+  TypeRecipe readTypeRecipe(DataSourceReader source) {
     return TypeRecipe.readFromDataSource(source);
   }
 }
@@ -2257,22 +2257,22 @@
   CodegenWriterImpl(this.closedWorld);
 
   @override
-  void writeAbstractValue(DataSink sink, AbstractValue value) {
+  void writeAbstractValue(DataSinkWriter sink, AbstractValue value) {
     closedWorld.abstractValueDomain.writeAbstractValueToDataSink(sink, value);
   }
 
   @override
-  void writeJsNode(DataSink sink, js.Node node) {
+  void writeJsNode(DataSinkWriter sink, js.Node node) {
     JsNodeSerializer.writeToDataSink(sink, node);
   }
 
   @override
-  void writeOutputUnitReference(DataSink sink, OutputUnit value) {
+  void writeOutputUnitReference(DataSinkWriter sink, OutputUnit value) {
     sink.writeInt(closedWorld.outputUnitData.outputUnits.indexOf(value));
   }
 
   @override
-  void writeTypeRecipe(DataSink sink, TypeRecipe recipe) {
+  void writeTypeRecipe(DataSinkWriter sink, TypeRecipe recipe) {
     recipe.writeToDataSink(sink);
   }
 }
diff --git a/pkg/compiler/lib/src/deferred_load/output_unit.dart b/pkg/compiler/lib/src/deferred_load/output_unit.dart
index 17daef0..bd27d06 100644
--- a/pkg/compiler/lib/src/deferred_load/output_unit.dart
+++ b/pkg/compiler/lib/src/deferred_load/output_unit.dart
@@ -156,7 +156,7 @@
   }
 
   /// Deserializes an [OutputUnitData] object from [source].
-  factory OutputUnitData.readFromDataSource(DataSource source) {
+  factory OutputUnitData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     bool isProgramSplit = source.readBool();
     List<OutputUnit> outputUnits = source.readList(() {
@@ -205,7 +205,7 @@
   }
 
   /// Serializes this [OutputUnitData] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeBool(isProgramSplit);
     Map<OutputUnit, int> outputUnitIndices = {};
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index a9f5514..f8d96a3 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -350,7 +350,7 @@
   }
 
   /// Deserializes a [ParameterStructure] object from [source].
-  factory ParameterStructure.readFromDataSource(DataSource source) {
+  factory ParameterStructure.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     int requiredPositionalParameters = source.readInt();
     int positionalParameters = source.readInt();
@@ -368,7 +368,7 @@
   }
 
   /// Serializes this [ParameterStructure] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeInt(requiredPositionalParameters);
     sink.writeInt(positionalParameters);
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index c93c535..a0d63a9 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -24,7 +24,7 @@
 /// implemented directly but other entity systems, for instance based directly
 /// on kernel ir without the need for [Element].
 
-extension on DataSource {
+extension on DataSourceReader {
   List<DartType> _readDartTypes(
       List<FunctionTypeVariable> functionTypeVariables) {
     int count = readInt();
@@ -36,7 +36,7 @@
   }
 }
 
-extension on DataSink {
+extension on DataSinkWriter {
   void _writeDartTypes(
       List<DartType> types, List<FunctionTypeVariable> functionTypeVariables) {
     writeInt(types.length);
@@ -49,8 +49,8 @@
 abstract class DartType {
   const DartType();
 
-  factory DartType.readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory DartType.readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     DartTypeKind kind = source.readEnum(DartTypeKind.values);
     switch (kind) {
       case DartTypeKind.none:
@@ -86,7 +86,7 @@
   }
 
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables);
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables);
 
   /// Returns the base type if this is a [LegacyType] or [NullableType] and
   /// returns this type otherwise.
@@ -204,8 +204,8 @@
 
   const LegacyType._(this.baseType);
 
-  factory LegacyType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory LegacyType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     DartType baseType =
         DartType.readFromDataSource(source, functionTypeVariables);
     return LegacyType._(baseType);
@@ -213,7 +213,7 @@
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.legacyType);
     baseType.writeToDataSink(sink, functionTypeVariables);
   }
@@ -259,8 +259,8 @@
 
   const NullableType._(this.baseType);
 
-  factory NullableType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory NullableType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     DartType baseType =
         DartType.readFromDataSource(source, functionTypeVariables);
     return NullableType._(baseType);
@@ -268,7 +268,7 @@
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.nullableType);
     baseType.writeToDataSink(sink, functionTypeVariables);
   }
@@ -321,8 +321,8 @@
     return InterfaceType._allocate(element, typeArguments);
   }
 
-  factory InterfaceType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory InterfaceType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     ClassEntity element = source.readClass();
     List<DartType> typeArguments = source._readDartTypes(functionTypeVariables);
     return InterfaceType._(element, typeArguments);
@@ -330,7 +330,7 @@
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.interfaceType);
     sink.writeClass(element);
     sink._writeDartTypes(typeArguments, functionTypeVariables);
@@ -393,15 +393,15 @@
 
   const TypeVariableType._(this.element);
 
-  factory TypeVariableType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory TypeVariableType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     TypeVariableEntity element = source.readTypeVariable();
     return TypeVariableType._(element);
   }
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.typeVariable);
     sink.writeTypeVariable(element);
   }
@@ -449,8 +449,8 @@
 
   FunctionTypeVariable._(this.index);
 
-  factory FunctionTypeVariable._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory FunctionTypeVariable._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     int index = source.readInt();
     assert(0 <= index && index < functionTypeVariables.length);
     return functionTypeVariables[index];
@@ -458,7 +458,7 @@
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     int index = functionTypeVariables.indexOf(this);
     if (index == -1) {
       // TODO(johnniwinther): Avoid free variables.
@@ -498,14 +498,14 @@
 class NeverType extends DartType {
   const NeverType._();
 
-  factory NeverType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory NeverType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     return const NeverType._();
   }
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.neverType);
   }
 
@@ -526,13 +526,13 @@
 class VoidType extends DartType {
   const VoidType._();
 
-  factory VoidType._readFromDataSource(DataSource source,
+  factory VoidType._readFromDataSource(DataSourceReader source,
           List<FunctionTypeVariable> functionTypeVariables) =>
       const VoidType._();
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.voidType);
   }
 
@@ -553,13 +553,13 @@
 class DynamicType extends DartType {
   const DynamicType._();
 
-  factory DynamicType._readFromDataSource(DataSource source,
+  factory DynamicType._readFromDataSource(DataSourceReader source,
           List<FunctionTypeVariable> functionTypeVariables) =>
       const DynamicType._();
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.dynamicType);
   }
 
@@ -580,13 +580,13 @@
 class ErasedType extends DartType {
   const ErasedType._();
 
-  factory ErasedType._readFromDataSource(DataSource source,
+  factory ErasedType._readFromDataSource(DataSourceReader source,
           List<FunctionTypeVariable> functionTypeVariables) =>
       const ErasedType._();
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.erasedType);
   }
 
@@ -618,13 +618,13 @@
 class AnyType extends DartType {
   const AnyType._();
 
-  factory AnyType._readFromDataSource(DataSource source,
+  factory AnyType._readFromDataSource(DataSourceReader source,
           List<FunctionTypeVariable> functionTypeVariables) =>
       const AnyType._();
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.anyType);
   }
 
@@ -706,8 +706,8 @@
         typeVariables);
   }
 
-  factory FunctionType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory FunctionType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     int typeVariableCount = source.readInt();
     List<FunctionTypeVariable> typeVariables =
         List<FunctionTypeVariable>.generate(
@@ -745,7 +745,7 @@
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.functionType);
     functionTypeVariables = List<FunctionTypeVariable>.of(functionTypeVariables)
       ..addAll(typeVariables);
@@ -851,8 +851,8 @@
 
   const FutureOrType._(this.typeArgument);
 
-  factory FutureOrType._readFromDataSource(
-      DataSource source, List<FunctionTypeVariable> functionTypeVariables) {
+  factory FutureOrType._readFromDataSource(DataSourceReader source,
+      List<FunctionTypeVariable> functionTypeVariables) {
     DartType typeArgument =
         DartType.readFromDataSource(source, functionTypeVariables);
     return FutureOrType._(typeArgument);
@@ -860,7 +860,7 @@
 
   @override
   void writeToDataSink(
-      DataSink sink, List<FunctionTypeVariable> functionTypeVariables) {
+      DataSinkWriter sink, List<FunctionTypeVariable> functionTypeVariables) {
     sink.writeEnum(DartTypeKind.futureOr);
     typeArgument.writeToDataSink(sink, functionTypeVariables);
   }
diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
index 582d331..e6d05b1 100644
--- a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
@@ -632,8 +632,8 @@
   String getCompactText(AbstractValue value);
 
   /// Deserializes an [AbstractValue] for this domain from [source].
-  AbstractValue readAbstractValueFromDataSource(DataSource source);
+  AbstractValue readAbstractValueFromDataSource(DataSourceReader source);
 
   /// Serializes this [value] for this domain to [sink].
-  void writeAbstractValueToDataSink(DataSink sink, AbstractValue value);
+  void writeAbstractValueToDataSink(DataSinkWriter sink, AbstractValue value);
 }
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index c56d855..3d9dd84 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -1354,7 +1354,7 @@
 
   /// Deserializes a [GlobalTypeInferenceElementData] object from [source].
   factory KernelGlobalTypeInferenceElementData.readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     return source.inMemberContext(context, () {
@@ -1381,7 +1381,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     sink.inMemberContext(context, () {
       sink.begin(tag);
diff --git a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
index b4f6789..6314434 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
@@ -74,14 +74,14 @@
   //TODO(coam)
   @override
   void writeAbstractValueToDataSink(
-      DataSink sink, covariant PowersetValue value) {
+      DataSinkWriter sink, covariant PowersetValue value) {
     _abstractValueDomain.writeAbstractValueToDataSink(
         sink, value._abstractValue);
   }
 
   //TODO(coam)
   @override
-  AbstractValue readAbstractValueFromDataSource(DataSource source) {
+  AbstractValue readAbstractValueFromDataSource(DataSourceReader source) {
     int powersetBits = _powersetBitsDomain.powersetTop;
     AbstractValue abstractValue =
         _abstractValueDomain.readAbstractValueFromDataSource(source);
diff --git a/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart b/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart
index 7e21d25..35c2641 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart
@@ -58,13 +58,13 @@
 
   @override
   void writeAbstractValueToDataSink(
-      DataSink sink, covariant WrappedAbstractValue value) {
+      DataSinkWriter sink, covariant WrappedAbstractValue value) {
     _abstractValueDomain.writeAbstractValueToDataSink(
         sink, value._abstractValue);
   }
 
   @override
-  AbstractValue readAbstractValueFromDataSource(DataSource source) =>
+  AbstractValue readAbstractValueFromDataSource(DataSourceReader source) =>
       WrappedAbstractValue(
           _abstractValueDomain.readAbstractValueFromDataSource(source));
 
diff --git a/pkg/compiler/lib/src/inferrer/trivial.dart b/pkg/compiler/lib/src/inferrer/trivial.dart
index 6ba231b..c81c91f 100644
--- a/pkg/compiler/lib/src/inferrer/trivial.dart
+++ b/pkg/compiler/lib/src/inferrer/trivial.dart
@@ -31,10 +31,10 @@
   AbstractValue get dynamicType => const TrivialAbstractValue();
 
   @override
-  void writeAbstractValueToDataSink(DataSink sink, AbstractValue value) {}
+  void writeAbstractValueToDataSink(DataSinkWriter sink, AbstractValue value) {}
 
   @override
-  AbstractValue readAbstractValueFromDataSource(DataSource source) =>
+  AbstractValue readAbstractValueFromDataSource(DataSourceReader source) =>
       const TrivialAbstractValue();
 
   @override
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
index ab14e11..a001c78 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
@@ -32,7 +32,7 @@
 
   /// Deserializes a [ContainerTypeMask] object from [source].
   factory ContainerTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
     ir.TreeNode allocationNode = source.readTreeNodeOrNull();
@@ -46,7 +46,7 @@
 
   /// Serializes this [ContainerTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.container);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
index 00eece2..20adc15 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
@@ -29,7 +29,7 @@
 
   /// Deserializes a [DictionaryTypeMask] object from [source].
   factory DictionaryTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
     ir.TreeNode allocationNode = source.readTreeNodeOrNull();
@@ -45,7 +45,7 @@
 
   /// Serializes this [DictionaryTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.dictionary);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
index 321a8d7..d42d4bd 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
@@ -123,7 +123,7 @@
 
   /// Deserializes a [FlatTypeMask] object from [source].
   factory FlatTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     ClassEntity base = source.readClassOrNull();
     int flags = source.readInt();
@@ -133,7 +133,7 @@
 
   /// Serializes this [FlatTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.flat);
     sink.begin(tag);
     sink.writeClassOrNull(base);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
index 035fa9d..7232e60 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
@@ -32,7 +32,7 @@
 
   /// Deserializes a [MapTypeMask] object from [source].
   factory MapTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
     ir.TreeNode allocationNode = source.readTreeNodeOrNull();
@@ -46,7 +46,7 @@
 
   /// Serializes this [MapTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.map);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index c6e534b..9de70a3 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -974,13 +974,14 @@
   }
 
   @override
-  TypeMask readAbstractValueFromDataSource(DataSource source) {
+  TypeMask readAbstractValueFromDataSource(DataSourceReader source) {
     return source
         .readCached<TypeMask>(() => TypeMask.readFromDataSource(source, this));
   }
 
   @override
-  void writeAbstractValueToDataSink(DataSink sink, covariant TypeMask value) {
+  void writeAbstractValueToDataSink(
+      DataSinkWriter sink, covariant TypeMask value) {
     sink.writeCached<TypeMask>(
         value, (TypeMask value) => value.writeToDataSink(sink));
   }
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
index bfa9098..ab01cc4 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
@@ -29,7 +29,7 @@
 
   /// Deserializes a [SetTypeMask] object from [source].
   factory SetTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
     ir.TreeNode allocationNode = source.readTreeNodeOrNull();
@@ -42,7 +42,7 @@
 
   /// Serializes this [SetTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.set);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
index 4702bdf..7f8af43 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
@@ -242,7 +242,8 @@
   }
 
   /// Deserializes a [TypeMask] object from [source].
-  factory TypeMask.readFromDataSource(DataSource source, CommonMasks domain) {
+  factory TypeMask.readFromDataSource(
+      DataSourceReader source, CommonMasks domain) {
     TypeMaskKind kind = source.readEnum(TypeMaskKind.values);
     switch (kind) {
       case TypeMaskKind.flat:
@@ -264,7 +265,7 @@
   }
 
   /// Serializes this [TypeMask] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// If [mask] is forwarding, returns the first non-forwarding [TypeMask] in
   /// [mask]'s forwarding chain.
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
index 3a647ea..c9abe7d 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
@@ -39,7 +39,7 @@
 
   /// Deserializes a [UnionTypeMask] object from [source].
   factory UnionTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     List<FlatTypeMask> disjointMasks =
         source.readList(() => TypeMask.readFromDataSource(source, domain));
@@ -52,7 +52,7 @@
 
   /// Serializes this [UnionTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.union);
     sink.begin(tag);
     sink.writeList(
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart
index 62b6747..61b43de 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart
@@ -17,7 +17,7 @@
 
   /// Deserializes a [ValueTypeMask] object from [source].
   factory ValueTypeMask.readFromDataSource(
-      DataSource source, CommonMasks domain) {
+      DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
     ConstantValue constant = source.readConstant();
@@ -27,7 +27,7 @@
 
   /// Serializes this [ValueTypeMask] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(TypeMaskKind.value);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/types.dart b/pkg/compiler/lib/src/inferrer/types.dart
index c72c1f5..bd2c38d 100644
--- a/pkg/compiler/lib/src/inferrer/types.dart
+++ b/pkg/compiler/lib/src/inferrer/types.dart
@@ -34,12 +34,14 @@
 /// based queries (the runtime value could be anything).
 abstract class GlobalTypeInferenceMemberResult {
   /// Deserializes a [GlobalTypeInferenceMemberResult] object from [source].
-  factory GlobalTypeInferenceMemberResult.readFromDataSource(DataSource source,
-          ir.Member context, AbstractValueDomain abstractValueDomain) =
+  factory GlobalTypeInferenceMemberResult.readFromDataSource(
+          DataSourceReader source,
+          ir.Member context,
+          AbstractValueDomain abstractValueDomain) =
       GlobalTypeInferenceMemberResultImpl.readFromDataSource;
 
   /// Serializes this [GlobalTypeInferenceMemberResult] to [sink].
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain);
 
   /// The inferred type when this result belongs to a field, null otherwise.
@@ -73,12 +75,14 @@
 /// a single element.
 abstract class GlobalTypeInferenceElementData {
   /// Deserializes a [GlobalTypeInferenceElementData] object from [source].
-  factory GlobalTypeInferenceElementData.readFromDataSource(DataSource source,
-          ir.Member context, AbstractValueDomain abstractValueDomain) =
+  factory GlobalTypeInferenceElementData.readFromDataSource(
+          DataSourceReader source,
+          ir.Member context,
+          AbstractValueDomain abstractValueDomain) =
       KernelGlobalTypeInferenceElementData.readFromDataSource;
 
   /// Serializes this [GlobalTypeInferenceElementData] to [sink].
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain);
 
   /// Compresses the inner representation by removing [AbstractValue] mappings
@@ -110,7 +114,7 @@
 abstract class GlobalTypeInferenceResults {
   /// Deserializes a [GlobalTypeInferenceResults] object from [source].
   factory GlobalTypeInferenceResults.readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       JsToElementMap elementMap,
       JClosedWorld closedWorld,
       GlobalLocalsMap globalLocalsMap,
@@ -124,7 +128,7 @@
   }
 
   /// Serializes this [GlobalTypeInferenceResults] to [sink].
-  void writeToDataSink(DataSink sink, JsToElementMap elementMap);
+  void writeToDataSink(DataSinkWriter sink, JsToElementMap elementMap);
 
   JClosedWorld get closedWorld;
 
@@ -239,7 +243,7 @@
         _trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
 
   factory GlobalTypeInferenceResultsImpl.readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       JsToElementMap elementMap,
       JClosedWorld closedWorld,
       GlobalLocalsMap globalLocalsMap,
@@ -275,7 +279,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink, JsToElementMap elementMap) {
+  void writeToDataSink(DataSinkWriter sink, JsToElementMap elementMap) {
     sink.writeBool(false); // Is _not_ trivial.
     sink.begin(tag);
     sink.writeMemberMap(
@@ -436,7 +440,7 @@
       {this.throwsAlways, this.isCalledOnce});
 
   factory GlobalTypeInferenceMemberResultImpl.readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     source.begin(tag);
@@ -456,7 +460,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     sink.begin(tag);
     sink.writeValueOrNull(_data, (GlobalTypeInferenceElementData data) {
@@ -497,7 +501,7 @@
         _trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
 
   @override
-  void writeToDataSink(DataSink sink, JsToElementMap elementMap) {
+  void writeToDataSink(DataSinkWriter sink, JsToElementMap elementMap) {
     sink.writeBool(true); // Is trivial.
   }
 
@@ -557,7 +561,7 @@
   bool get isCalledOnce => false;
 
   @override
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     throw UnsupportedError(
         "TrivialGlobalTypeInferenceMemberResult.writeToDataSink");
@@ -598,7 +602,7 @@
   bool get isCalledOnce => false;
 
   @override
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     throw UnsupportedError(
         "DeadFieldGlobalTypeInferenceResult.writeToDataSink");
@@ -639,7 +643,7 @@
   bool get isCalledOnce => false;
 
   @override
-  void writeToDataSink(DataSink sink, ir.Member context,
+  void writeToDataSink(DataSinkWriter sink, ir.Member context,
       AbstractValueDomain abstractValueDomain) {
     throw UnsupportedError(
         "DeadFieldGlobalTypeInferenceResult.writeToDataSink");
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index b3195a7..5844712 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -33,7 +33,8 @@
   PositionSourceInformation(
       this.startPosition, this.innerPosition, this.inliningContext);
 
-  factory PositionSourceInformation.readFromDataSource(DataSource source) {
+  factory PositionSourceInformation.readFromDataSource(
+      DataSourceReader source) {
     source.begin(tag);
     SourceLocation startPosition = source.readCached<SourceLocation>(
         () => SourceLocation.readFromDataSource(source));
@@ -47,7 +48,7 @@
         startPosition, innerPosition, inliningContext);
   }
 
-  void writeToDataSinkInternal(DataSink sink) {
+  void writeToDataSinkInternal(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeCached(
         startPosition,
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index d31486b..9098af0 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -18,7 +18,7 @@
 abstract class SourceInformation extends JavaScriptNodeSourceInformation {
   const SourceInformation();
 
-  static SourceInformation readFromDataSource(DataSource source) {
+  static SourceInformation readFromDataSource(DataSourceReader source) {
     int hasSourceInformation = source.readInt();
     if (hasSourceInformation == 0) {
       return null;
@@ -31,7 +31,7 @@
   }
 
   static void writeToDataSink(
-      DataSink sink, SourceInformation sourceInformation) {
+      DataSinkWriter sink, SourceInformation sourceInformation) {
     if (sourceInformation == null) {
       sink.writeInt(0);
     } else if (sourceInformation is SourceMappedMarker) {
@@ -82,7 +82,7 @@
 
   FrameContext(this.callInformation, this.inlinedMethodName);
 
-  factory FrameContext.readFromDataSource(DataSource source) {
+  factory FrameContext.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     SourceInformation callInformation = source.readCached<SourceInformation>(
         () => SourceInformation.readFromDataSource(source));
@@ -91,7 +91,7 @@
     return FrameContext(callInformation, inlinedMethodName);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeCached<SourceInformation>(
         callInformation,
@@ -273,7 +273,7 @@
   /// The name associated with this source location, if any.
   String get sourceName;
 
-  static SourceLocation readFromDataSource(DataSource source) {
+  static SourceLocation readFromDataSource(DataSourceReader source) {
     int hasSourceLocation = source.readInt();
     if (hasSourceLocation == 0) {
       return null;
@@ -292,7 +292,8 @@
     }
   }
 
-  static void writeToDataSink(DataSink sink, SourceLocation sourceLocation) {
+  static void writeToDataSink(
+      DataSinkWriter sink, SourceLocation sourceLocation) {
     if (sourceLocation == null) {
       sink.writeInt(0);
     } else if (sourceLocation is NoSourceLocationMarker) {
diff --git a/pkg/compiler/lib/src/ir/impact.dart b/pkg/compiler/lib/src/ir/impact.dart
index c72bbde..c68ffeb 100644
--- a/pkg/compiler/lib/src/ir/impact.dart
+++ b/pkg/compiler/lib/src/ir/impact.dart
@@ -699,7 +699,7 @@
   ImpactBuilderData(this.node, this.impactData, this.typeMapsForTesting,
       this.cachedStaticTypes);
 
-  factory ImpactBuilderData.fromDataSource(DataSource source) {
+  factory ImpactBuilderData.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     var node = source.readMemberNode();
     var data = ImpactData.fromDataSource(source);
@@ -708,7 +708,7 @@
     return ImpactBuilderData(node, data, const {}, cache);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(node);
     impactData.toDataSink(sink);
diff --git a/pkg/compiler/lib/src/ir/impact_data.dart b/pkg/compiler/lib/src/ir/impact_data.dart
index 34f94bd..eb3f407 100644
--- a/pkg/compiler/lib/src/ir/impact_data.dart
+++ b/pkg/compiler/lib/src/ir/impact_data.dart
@@ -530,7 +530,7 @@
 
   ImpactData();
 
-  ImpactData.fromDataSource(DataSource source) {
+  ImpactData.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     _superInitializers = source.readList(
         () => _SuperInitializer.fromDataSource(source),
@@ -628,7 +628,7 @@
     source.end(tag);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
 
     sink.writeList(
@@ -1065,7 +1065,7 @@
         typeArguments, positionalArguments, namedArguments);
   }
 
-  factory _CallStructure.fromDataSource(DataSource source) {
+  factory _CallStructure.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     List<ir.DartType> typeArguments = source.readDartTypeNodes();
     int positionalArguments = source.readInt();
@@ -1075,7 +1075,7 @@
         typeArguments, positionalArguments, namedArguments);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNodes(typeArguments);
     sink.writeInt(positionalArguments);
@@ -1093,7 +1093,7 @@
 
   _SuperInitializer(this.source, this.target, this.callStructure);
 
-  factory _SuperInitializer.fromDataSource(DataSource source) {
+  factory _SuperInitializer.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Constructor sourceConstructor = source.readMemberNode();
     ir.Constructor targetConstructor = source.readMemberNode();
@@ -1103,7 +1103,7 @@
         sourceConstructor, targetConstructor, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(source);
     sink.writeMemberNode(target);
@@ -1120,7 +1120,7 @@
 
   _SuperInvocation(this.target, this.callStructure);
 
-  factory _SuperInvocation.fromDataSource(DataSource source) {
+  factory _SuperInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member member = source.readMemberNode();
     _CallStructure callStructure = _CallStructure.fromDataSource(source);
@@ -1128,7 +1128,7 @@
     return _SuperInvocation(member, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(target);
     callStructure.toDataSink(sink);
@@ -1145,7 +1145,7 @@
 
   _InstanceAccess(this.receiverType, this.classRelation, this.target);
 
-  factory _InstanceAccess.fromDataSource(DataSource source) {
+  factory _InstanceAccess.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType receiverType = source.readDartTypeNode();
     ClassRelation classRelation = source.readEnum(ClassRelation.values);
@@ -1154,7 +1154,7 @@
     return _InstanceAccess(receiverType, classRelation, target);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(receiverType);
     sink.writeEnum(classRelation);
@@ -1172,7 +1172,7 @@
 
   _DynamicAccess(this.receiverType, this.classRelation, this.name);
 
-  factory _DynamicAccess.fromDataSource(DataSource source) {
+  factory _DynamicAccess.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType receiverType = source.readDartTypeNode();
     ClassRelation classRelation = source.readEnum(ClassRelation.values);
@@ -1181,7 +1181,7 @@
     return _DynamicAccess(receiverType, classRelation, name);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(receiverType);
     sink.writeEnum(classRelation);
@@ -1198,7 +1198,7 @@
 
   _FunctionInvocation(this.receiverType, this.callStructure);
 
-  factory _FunctionInvocation.fromDataSource(DataSource source) {
+  factory _FunctionInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType receiverType = source.readDartTypeNode();
     _CallStructure callStructure = _CallStructure.fromDataSource(source);
@@ -1206,7 +1206,7 @@
     return _FunctionInvocation(receiverType, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(receiverType);
     callStructure.toDataSink(sink);
@@ -1225,7 +1225,7 @@
   _InstanceInvocation(
       this.receiverType, this.classRelation, this.target, this.callStructure);
 
-  factory _InstanceInvocation.fromDataSource(DataSource source) {
+  factory _InstanceInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType receiverType = source.readDartTypeNode();
     ClassRelation classRelation = source.readEnum(ClassRelation.values);
@@ -1236,7 +1236,7 @@
         receiverType, classRelation, target, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(receiverType);
     sink.writeEnum(classRelation);
@@ -1257,7 +1257,7 @@
   _DynamicInvocation(
       this.receiverType, this.classRelation, this.name, this.callStructure);
 
-  factory _DynamicInvocation.fromDataSource(DataSource source) {
+  factory _DynamicInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType receiverType = source.readDartTypeNode();
     ClassRelation classRelation = source.readEnum(ClassRelation.values);
@@ -1267,7 +1267,7 @@
     return _DynamicInvocation(receiverType, classRelation, name, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(receiverType);
     sink.writeEnum(classRelation);
@@ -1285,7 +1285,7 @@
 
   _LocalFunctionInvocation(this.localFunction, this.callStructure);
 
-  factory _LocalFunctionInvocation.fromDataSource(DataSource source) {
+  factory _LocalFunctionInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.FunctionDeclaration localFunction = source.readTreeNode();
     _CallStructure callStructure = _CallStructure.fromDataSource(source);
@@ -1293,7 +1293,7 @@
     return _LocalFunctionInvocation(localFunction, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeTreeNode(localFunction);
     callStructure.toDataSink(sink);
@@ -1310,7 +1310,7 @@
 
   _StaticInvocation(this.target, this.callStructure, this.import);
 
-  factory _StaticInvocation.fromDataSource(DataSource source) {
+  factory _StaticInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Procedure target = source.readMemberNode();
     _CallStructure callStructure = _CallStructure.fromDataSource(source);
@@ -1319,7 +1319,7 @@
     return _StaticInvocation(target, callStructure, import);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(target);
     callStructure.toDataSink(sink);
@@ -1341,7 +1341,7 @@
       this.constructor, this.type, this.callStructure, this.import,
       {this.isConst});
 
-  factory _ConstructorInvocation.fromDataSource(DataSource source) {
+  factory _ConstructorInvocation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member constructor = source.readMemberNode();
     ir.InterfaceType type = source.readDartTypeNode();
@@ -1353,7 +1353,7 @@
         isConst: isConst);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(constructor);
     sink.writeDartTypeNode(type);
@@ -1393,7 +1393,7 @@
 
   _TypeUse(this.type, this.kind);
 
-  factory _TypeUse.fromDataSource(DataSource source) {
+  factory _TypeUse.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType type = source.readDartTypeNode();
     _TypeUseKind kind = source.readEnum(_TypeUseKind.values);
@@ -1401,7 +1401,7 @@
     return _TypeUse(type, kind);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(type);
     sink.writeEnum(kind);
@@ -1428,7 +1428,7 @@
 
   _RedirectingInitializer(this.constructor, this.callStructure);
 
-  factory _RedirectingInitializer.fromDataSource(DataSource source) {
+  factory _RedirectingInitializer.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Constructor constructor = source.readMemberNode();
     _CallStructure callStructure = _CallStructure.fromDataSource(source);
@@ -1436,7 +1436,7 @@
     return _RedirectingInitializer(constructor, callStructure);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(constructor);
     callStructure.toDataSink(sink);
@@ -1452,7 +1452,7 @@
 
   _TypeLiteral(this.type, this.import);
 
-  factory _TypeLiteral.fromDataSource(DataSource source) {
+  factory _TypeLiteral.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType type = source.readDartTypeNode();
     ir.LibraryDependency import = source.readLibraryDependencyNodeOrNull();
@@ -1460,7 +1460,7 @@
     return _TypeLiteral(type, import);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(type);
     sink.writeLibraryDependencyNodeOrNull(import);
@@ -1476,7 +1476,7 @@
 
   _GenericInstantiation(this.expressionType, this.typeArguments);
 
-  factory _GenericInstantiation.fromDataSource(DataSource source) {
+  factory _GenericInstantiation.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.FunctionType expressionType = source.readDartTypeNode();
     List<ir.DartType> typeArguments = source.readDartTypeNodes();
@@ -1484,7 +1484,7 @@
     return _GenericInstantiation(expressionType, typeArguments);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(expressionType);
     sink.writeDartTypeNodes(typeArguments);
@@ -1500,7 +1500,7 @@
 
   _StaticAccess(this.target, this.import);
 
-  factory _StaticAccess.fromDataSource(DataSource source) {
+  factory _StaticAccess.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member target = source.readMemberNode();
     ir.LibraryDependency import = source.readLibraryDependencyNodeOrNull();
@@ -1508,7 +1508,7 @@
     return _StaticAccess(target, import);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNode(target);
     sink.writeLibraryDependencyNodeOrNull(import);
@@ -1526,7 +1526,7 @@
 
   _MapLiteral(this.keyType, this.valueType, {this.isConst, this.isEmpty});
 
-  factory _MapLiteral.fromDataSource(DataSource source) {
+  factory _MapLiteral.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType keyType = source.readDartTypeNode();
     ir.DartType valueType = source.readDartTypeNode();
@@ -1536,7 +1536,7 @@
     return _MapLiteral(keyType, valueType, isConst: isConst, isEmpty: isEmpty);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(keyType);
     sink.writeDartTypeNode(valueType);
@@ -1555,7 +1555,7 @@
 
   _ContainerLiteral(this.elementType, {this.isConst, this.isEmpty});
 
-  factory _ContainerLiteral.fromDataSource(DataSource source) {
+  factory _ContainerLiteral.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.DartType elementType = source.readDartTypeNode();
     bool isConst = source.readBool();
@@ -1564,7 +1564,7 @@
     return _ContainerLiteral(elementType, isConst: isConst, isEmpty: isEmpty);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartTypeNode(elementType);
     sink.writeBool(isConst);
@@ -1585,7 +1585,7 @@
 
   _RuntimeTypeUse(this.node, this.kind, this.receiverType, this.argumentType);
 
-  factory _RuntimeTypeUse.fromDataSource(DataSource source) {
+  factory _RuntimeTypeUse.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.TreeNode node = source.readTreeNode();
     RuntimeTypeUseKind kind = source.readEnum(RuntimeTypeUseKind.values);
@@ -1595,7 +1595,7 @@
     return _RuntimeTypeUse(node, kind, receiverType, argumentType);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeTreeNode(node);
     sink.writeEnum(kind);
diff --git a/pkg/compiler/lib/src/ir/modular.dart b/pkg/compiler/lib/src/ir/modular.dart
index bdb89a3..24afe70 100644
--- a/pkg/compiler/lib/src/ir/modular.dart
+++ b/pkg/compiler/lib/src/ir/modular.dart
@@ -54,7 +54,7 @@
 
   ModuleData(this.impactData);
 
-  factory ModuleData.fromDataSource(DataSource source) {
+  factory ModuleData.fromDataSource(DataSourceReader source) {
     source.begin(tag);
     var impactData = source
         .readMemberNodeMap(() => ImpactBuilderData.fromDataSource(source));
@@ -62,7 +62,7 @@
     return ModuleData(impactData);
   }
 
-  void toDataSink(DataSink sink) {
+  void toDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberNodeMap<ImpactBuilderData>(
         impactData, (e) => e.toDataSink(sink));
diff --git a/pkg/compiler/lib/src/ir/static_type_cache.dart b/pkg/compiler/lib/src/ir/static_type_cache.dart
index 59f2d66..f389c80 100644
--- a/pkg/compiler/lib/src/ir/static_type_cache.dart
+++ b/pkg/compiler/lib/src/ir/static_type_cache.dart
@@ -16,7 +16,7 @@
       [this._expressionTypes = const {}, this._forInIteratorTypes]);
 
   factory StaticTypeCache.readFromDataSource(
-      DataSource source, ir.Member context) {
+      DataSourceReader source, ir.Member context) {
     return source.inMemberContext(context, () {
       source.begin(tag);
       Map<ir.Expression, ir.DartType> expressionTypes =
@@ -28,7 +28,7 @@
     });
   }
 
-  void writeToDataSink(DataSink sink, ir.Member context) {
+  void writeToDataSink(DataSinkWriter sink, ir.Member context) {
     sink.inMemberContext(context, () {
       sink.begin(tag);
       sink.writeTreeNodeMapInContext(_expressionTypes, sink.writeDartTypeNode);
diff --git a/pkg/compiler/lib/src/js_backend/annotations.dart b/pkg/compiler/lib/src/js_backend/annotations.dart
index cf4c049..6994be7 100644
--- a/pkg/compiler/lib/src/js_backend/annotations.dart
+++ b/pkg/compiler/lib/src/js_backend/annotations.dart
@@ -256,11 +256,11 @@
 abstract class AnnotationsData {
   /// Deserializes a [AnnotationsData] object from [source].
   factory AnnotationsData.readFromDataSource(
-          CompilerOptions options, DataSource source) =
+          CompilerOptions options, DataSourceReader source) =
       AnnotationsDataImpl.readFromDataSource;
 
   /// Serializes this [AnnotationsData] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// Returns `true` if [member] has an `@pragma('dart2js:assumeDynamic')`
   /// annotation.
@@ -356,7 +356,7 @@
             options.defaultIndexBoundsCheckPolicy;
 
   factory AnnotationsDataImpl.readFromDataSource(
-      CompilerOptions options, DataSource source) {
+      CompilerOptions options, DataSourceReader source) {
     source.begin(tag);
     Map<MemberEntity, EnumSet<PragmaAnnotation>> pragmaAnnotations =
         source.readMemberMap(
@@ -366,7 +366,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberMap(pragmaAnnotations,
         (MemberEntity member, EnumSet<PragmaAnnotation> set) {
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index 08f17ce..600075d 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -15,11 +15,11 @@
 
 abstract class BackendUsage {
   /// Deserializes a [BackendUsage] object from [source].
-  factory BackendUsage.readFromDataSource(DataSource source) =
+  factory BackendUsage.readFromDataSource(DataSourceReader source) =
       BackendUsageImpl.readFromDataSource;
 
   /// Serializes this [BackendUsage] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   bool needToInitializeIsolateAffinityTag;
   bool needToInitializeDispatchProperty;
@@ -356,7 +356,7 @@
         this._helperClassesUsed = helperClassesUsed,
         this._runtimeTypeUses = runtimeTypeUses;
 
-  factory BackendUsageImpl.readFromDataSource(DataSource source) {
+  factory BackendUsageImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Set<FunctionEntity> globalFunctionDependencies =
         source.readMembers<FunctionEntity>().toSet();
@@ -396,7 +396,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMembers(_globalFunctionDependencies);
     sink.writeClasses(_globalClassDependencies);
diff --git a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
index e038554..22329a2 100644
--- a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
+++ b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
@@ -56,7 +56,7 @@
         DeferredHolderExpressionKind.globalObjectForStaticState, null);
   }
 
-  factory DeferredHolderExpression.readFromDataSource(DataSource source) {
+  factory DeferredHolderExpression.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     var kind = source.readEnum(DeferredHolderExpressionKind.values);
     Object data;
@@ -79,7 +79,7 @@
     return DeferredHolderExpression(kind, data);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeEnum(kind);
     switch (kind) {
diff --git a/pkg/compiler/lib/src/js_backend/field_analysis.dart b/pkg/compiler/lib/src/js_backend/field_analysis.dart
index 0f3326c..96c5bf9 100644
--- a/pkg/compiler/lib/src/js_backend/field_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/field_analysis.dart
@@ -252,7 +252,7 @@
 
   /// Deserializes a [JFieldAnalysis] object from [source].
   factory JFieldAnalysis.readFromDataSource(
-      DataSource source, CompilerOptions options) {
+      DataSourceReader source, CompilerOptions options) {
     source.begin(tag);
     Map<FieldEntity, FieldAnalysisData> fieldData = source.readMemberMap(
         (MemberEntity member) => FieldAnalysisData.fromDataSource(source));
@@ -261,7 +261,7 @@
   }
 
   /// Serializes this [JFieldAnalysis] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberMap(
         _fieldData,
@@ -602,7 +602,7 @@
       this.eagerCreationIndex = null,
       this.eagerFieldDependenciesForTesting = null});
 
-  factory FieldAnalysisData.fromDataSource(DataSource source) {
+  factory FieldAnalysisData.fromDataSource(DataSourceReader source) {
     source.begin(tag);
 
     ConstantValue initialValue = source.readConstantOrNull();
@@ -624,7 +624,7 @@
         eagerFieldDependenciesForTesting: eagerFieldDependencies);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeConstantOrNull(initialValue);
     sink.writeBool(isInitializedInAllocator);
diff --git a/pkg/compiler/lib/src/js_backend/inferred_data.dart b/pkg/compiler/lib/src/js_backend/inferred_data.dart
index 3dc454a..bf12d8c 100644
--- a/pkg/compiler/lib/src/js_backend/inferred_data.dart
+++ b/pkg/compiler/lib/src/js_backend/inferred_data.dart
@@ -16,7 +16,7 @@
 abstract class InferredData {
   /// Deserializes a [InferredData] object from [source].
   factory InferredData.readFromDataSource(
-      DataSource source, JClosedWorld closedWorld) {
+      DataSourceReader source, JClosedWorld closedWorld) {
     bool isTrivial = source.readBool();
     if (isTrivial) {
       return TrivialInferredData();
@@ -26,7 +26,7 @@
   }
 
   /// Serializes this [InferredData] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// Returns the side effects of executing [element].
   SideEffects getSideEffectsOfElement(FunctionEntity element);
@@ -100,7 +100,7 @@
       this._functionsThatMightBePassedToApply);
 
   factory InferredDataImpl.readFromDataSource(
-      DataSource source, JClosedWorld closedWorld) {
+      DataSourceReader source, JClosedWorld closedWorld) {
     source.begin(tag);
     Set<MemberEntity> functionsCalledInLoop = source.readMembers().toSet();
     Map<FunctionEntity, SideEffects> sideEffects = source.readMemberMap(
@@ -122,7 +122,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeBool(false); // Is _not_ trivial.
     sink.begin(tag);
     sink.writeMembers(_functionsCalledInLoop);
@@ -302,7 +302,7 @@
   final SideEffects _allSideEffects = SideEffects();
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeBool(true); // Is trivial.
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
index 0300e2d..36052c1 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -21,12 +21,12 @@
 abstract class InterceptorData {
   /// Deserializes a [InterceptorData] object from [source].
   factory InterceptorData.readFromDataSource(
-      DataSource source,
+      DataSourceReader source,
       NativeData nativeData,
       CommonElements commonElements) = InterceptorDataImpl.readFromDataSource;
 
   /// Serializes this [InterceptorData] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// Returns `true` if [cls] is an intercepted class.
   bool isInterceptedClass(ClassEntity element);
@@ -110,8 +110,8 @@
       this.interceptedClasses,
       this.classesMixedIntoInterceptedClasses);
 
-  factory InterceptorDataImpl.readFromDataSource(
-      DataSource source, NativeData nativeData, CommonElements commonElements) {
+  factory InterceptorDataImpl.readFromDataSource(DataSourceReader source,
+      NativeData nativeData, CommonElements commonElements) {
     source.begin(tag);
     int interceptedMembersCount = source.readInt();
     Map<String, Set<MemberEntity>> interceptedMembers = {};
@@ -129,7 +129,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeInt(interceptedMembers.length);
     interceptedMembers.forEach((String name, Set<MemberEntity> members) {
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index 00ee207..6bbf4ea 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -200,7 +200,7 @@
 
   /// Deserializes a [NativeBasicData] object from [source].
   factory NativeBasicData.readFromDataSource(
-      DataSource source, ElementEnvironment elementEnvironment) {
+      DataSourceReader source, ElementEnvironment elementEnvironment) {
     source.begin(tag);
     bool isAllowInteropUsed = source.readBool();
     Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
@@ -228,7 +228,7 @@
   }
 
   /// Serializes this [NativeBasicData] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeBool(isAllowInteropUsed);
     sink.writeClassMap(_nativeClassTagInfo, (NativeClassTag tag) {
@@ -484,7 +484,7 @@
 
   /// Deserializes a [NativeData] object from [source].
   factory NativeData.readFromDataSource(
-      DataSource source, ElementEnvironment elementEnvironment) {
+      DataSourceReader source, ElementEnvironment elementEnvironment) {
     source.begin(tag);
     NativeBasicData nativeBasicData =
         NativeBasicData.readFromDataSource(source, elementEnvironment);
@@ -506,7 +506,7 @@
 
   /// Serializes this [NativeData] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     _nativeBasicData.writeToDataSink(sink);
 
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 8c957ec..f9c2749 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -190,7 +190,7 @@
       this._throwingImpls, this._otherImpls, this._forwardingSyntaxImpls);
 
   /// Deserializes a [NoSuchMethodData] object from [source].
-  factory NoSuchMethodData.readFromDataSource(DataSource source) {
+  factory NoSuchMethodData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Set<FunctionEntity> throwingImpls =
         source.readMembers<FunctionEntity>().toSet();
@@ -209,7 +209,7 @@
   }
 
   /// Serializes this [NoSuchMethodData] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMembers(_throwingImpls);
     sink.writeMembers(_otherImpls);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
index 5bf8933..c53fa5f 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
@@ -660,7 +660,7 @@
 abstract class RuntimeTypesNeed {
   /// Deserializes a [RuntimeTypesNeed] object from [source].
   factory RuntimeTypesNeed.readFromDataSource(
-      DataSource source, ElementEnvironment elementEnvironment) {
+      DataSourceReader source, ElementEnvironment elementEnvironment) {
     bool isTrivial = source.readBool();
     if (isTrivial) {
       return TrivialRuntimeTypesNeed(elementEnvironment);
@@ -669,7 +669,7 @@
   }
 
   /// Serializes this [RuntimeTypesNeed] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// Returns `true` if [cls] needs type arguments at runtime.
   ///
@@ -742,7 +742,7 @@
   const TrivialRuntimeTypesNeed(this._elementEnvironment);
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeBool(true); // Is trivial.
   }
 
@@ -797,7 +797,7 @@
       this.instantiationsNeedingTypeArguments);
 
   factory RuntimeTypesNeedImpl.readFromDataSource(
-      DataSource source, ElementEnvironment elementEnvironment) {
+      DataSourceReader source, ElementEnvironment elementEnvironment) {
     source.begin(tag);
     Set<ClassEntity> classesNeedingTypeArguments =
         source.readClasses<ClassEntity>().toSet();
@@ -822,7 +822,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeBool(false); // Is _not_ trivial.
     sink.begin(tag);
     sink.writeClasses(classesNeedingTypeArguments);
diff --git a/pkg/compiler/lib/src/js_backend/string_reference.dart b/pkg/compiler/lib/src/js_backend/string_reference.dart
index 19aba0e..06d7370 100644
--- a/pkg/compiler/lib/src/js_backend/string_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/string_reference.dart
@@ -101,14 +101,14 @@
   StringReference(this.constant) : sourceInformation = null;
   StringReference._(this.constant, this._value, this.sourceInformation);
 
-  factory StringReference.readFromDataSource(DataSource source) {
+  factory StringReference.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     StringConstantValue constant = source.readConstant() as StringConstantValue;
     source.end(tag);
     return StringReference(constant);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeConstant(constant);
     sink.end(tag);
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index d796de1..b603532 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -117,7 +117,7 @@
   TypeReference(this.typeRecipe) : sourceInformation = null;
   TypeReference._(this.typeRecipe, this._value, this.sourceInformation);
 
-  factory TypeReference.readFromDataSource(DataSource source) {
+  factory TypeReference.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     TypeRecipe recipe = source.readTypeRecipe();
     bool forLazyInitializer = source.readBool();
@@ -125,7 +125,7 @@
     return TypeReference(recipe)..forLazyInitializer = forLazyInitializer;
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeTypeRecipe(typeRecipe);
     sink.writeBool(forLazyInitializer);
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 7aa5677..62b1101 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -51,7 +51,7 @@
 
   /// Deserializes a [ClosureData] object from [source].
   factory ClosureDataImpl.readFromDataSource(
-      JsToElementMap elementMap, DataSource source) {
+      JsToElementMap elementMap, DataSourceReader source) {
     source.begin(tag);
     // TODO(johnniwinther): Support shared [ScopeInfo].
     Map<MemberEntity, ScopeInfo> scopeMap = source.readMemberMap(
@@ -78,7 +78,7 @@
 
   /// Serializes this [ClosureData] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMemberMap(_scopeMap,
         (MemberEntity member, ScopeInfo info) => info.writeToDataSink(sink));
@@ -507,7 +507,7 @@
     return _boxedVariablesCache.containsKey(variable);
   }
 
-  factory JsScopeInfo.readFromDataSource(DataSource source) {
+  factory JsScopeInfo.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
@@ -522,7 +522,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(ScopeInfoKind.scopeInfo);
     sink.begin(tag);
     sink.writeTreeNodes(_localsUsedInTryOrSync);
@@ -556,7 +556,7 @@
   @override
   bool get requiresContextBox => _boxedVariables.isNotEmpty;
 
-  factory JsCapturedScope.readFromDataSource(DataSource source) {
+  factory JsCapturedScope.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
@@ -571,7 +571,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(ScopeInfoKind.capturedScope);
     sink.begin(tag);
     sink.writeTreeNodes(_localsUsedInTryOrSync);
@@ -608,7 +608,7 @@
   @override
   bool get hasBoxedLoopVariables => _boxedLoopVariables.isNotEmpty;
 
-  factory JsCapturedLoopScope.readFromDataSource(DataSource source) {
+  factory JsCapturedLoopScope.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
@@ -625,7 +625,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(ScopeInfoKind.capturedLoopScope);
     sink.begin(tag);
     sink.writeTreeNodes(_localsUsedInTryOrSync);
@@ -705,7 +705,7 @@
         _localToFieldMap = {},
         super.from(boxedVariables, info, enclosingClass);
 
-  factory JsClosureClassInfo.readFromDataSource(DataSource source) {
+  factory JsClosureClassInfo.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
@@ -743,7 +743,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(ScopeInfoKind.closureRepresentationInfo);
     sink.begin(tag);
     sink.writeTreeNodes(_localsUsedInTryOrSync);
@@ -855,7 +855,7 @@
   JClosureClass(JLibrary library, String name)
       : super(library, name, isAbstract: false);
 
-  factory JClosureClass.readFromDataSource(DataSource source) {
+  factory JClosureClass.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JLibrary library = source.readLibrary();
     String name = source.readString();
@@ -864,7 +864,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassKind.closure);
     sink.begin(tag);
     sink.writeLibrary(library);
@@ -926,7 +926,7 @@
       : super(library, enclosingClass, memberName,
             isAssignable: isAssignable, isConst: isConst, isStatic: false);
 
-  factory JClosureField.readFromDataSource(DataSource source) {
+  factory JClosureField.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JClass cls = source.readClass();
     String name = source.readString();
@@ -940,7 +940,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.closureField);
     sink.begin(tag);
     sink.writeClass(enclosingClass);
@@ -975,7 +975,7 @@
   RecordClassData(
       this.definition, this.thisType, this.supertype, this.orderedTypeSet);
 
-  factory RecordClassData.readFromDataSource(DataSource source) {
+  factory RecordClassData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ClassDefinition definition = ClassDefinition.readFromDataSource(source);
     InterfaceType thisType = source.readDartType();
@@ -986,7 +986,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassDataKind.record);
     sink.begin(tag);
     definition.writeToDataSink(sink);
@@ -1036,7 +1036,7 @@
   JRecord(LibraryEntity library, String name)
       : super(library, name, isAbstract: false);
 
-  factory JRecord.readFromDataSource(DataSource source) {
+  factory JRecord.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JLibrary library = source.readLibrary();
     String name = source.readString();
@@ -1045,7 +1045,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassKind.record);
     sink.begin(tag);
     sink.writeLibrary(library);
@@ -1075,7 +1075,7 @@
             Name(name, box.container.library),
             isStatic: false, isAssignable: true, isConst: isConst);
 
-  factory JRecordField.readFromDataSource(DataSource source) {
+  factory JRecordField.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     String name = source.readString();
     JClass enclosingClass = source.readClass();
@@ -1085,7 +1085,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.recordField);
     sink.begin(tag);
     sink.writeString(name);
@@ -1118,7 +1118,7 @@
       InterfaceType supertype, OrderedTypeSet orderedTypeSet)
       : super(definition, thisType, supertype, orderedTypeSet);
 
-  factory ClosureClassData.readFromDataSource(DataSource source) {
+  factory ClosureClassData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ClassDefinition definition = ClassDefinition.readFromDataSource(source);
     InterfaceType thisType = source.readDartType();
@@ -1131,7 +1131,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassDataKind.closure);
     sink.begin(tag);
     definition.writeToDataSink(sink);
@@ -1153,7 +1153,7 @@
 
   ClosureClassDefinition(this.location);
 
-  factory ClosureClassDefinition.readFromDataSource(DataSource source) {
+  factory ClosureClassDefinition.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     SourceSpan location = source.readSourceSpan();
     source.end(tag);
@@ -1161,7 +1161,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(ClassKind.closure);
     sink.begin(tag);
     sink.writeSourceSpan(location);
@@ -1221,7 +1221,7 @@
       this.classTypeVariableAccess)
       : super(definition, memberThisType);
 
-  factory ClosureFunctionData.readFromDataSource(DataSource source) {
+  factory ClosureFunctionData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ClosureMemberDefinition definition =
         MemberDefinition.readFromDataSource(source);
@@ -1236,7 +1236,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.closureFunction);
     sink.begin(tag);
     definition.writeToDataSink(sink);
@@ -1275,7 +1275,7 @@
   ClosureFieldData(MemberDefinition definition, InterfaceType memberThisType)
       : super(definition, memberThisType);
 
-  factory ClosureFieldData.readFromDataSource(DataSource source) {
+  factory ClosureFieldData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberDefinition definition = MemberDefinition.readFromDataSource(source);
     InterfaceType memberThisType = source.readDartType(allowNull: true);
@@ -1284,7 +1284,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.closureField);
     sink.begin(tag);
     definition.writeToDataSink(sink);
@@ -1341,7 +1341,7 @@
             kind == MemberKind.closureCall || kind == MemberKind.closureField);
 
   factory ClosureMemberDefinition.readFromDataSource(
-      DataSource source, MemberKind kind) {
+      DataSourceReader source, MemberKind kind) {
     source.begin(tag);
     SourceSpan location = source.readSourceSpan();
     ir.TreeNode node = source.readTreeNode();
@@ -1350,7 +1350,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(kind);
     sink.begin(tag);
     sink.writeSourceSpan(location);
@@ -1372,7 +1372,8 @@
 
   RecordContainerDefinition(this.location);
 
-  factory RecordContainerDefinition.readFromDataSource(DataSource source) {
+  factory RecordContainerDefinition.readFromDataSource(
+      DataSourceReader source) {
     source.begin(tag);
     SourceSpan location = source.readSourceSpan();
     source.end(tag);
@@ -1380,7 +1381,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(ClassKind.record);
     sink.begin(tag);
     sink.writeSourceSpan(location);
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index e87d834..985d77f 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -269,7 +269,7 @@
   JumpTarget getJumpTargetForWhile(ir.WhileStatement node);
 
   /// Serializes this [KernelToLocalsMap] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 }
 
 /// Returns the [ir.FunctionNode] that defines [member] or `null` if [member]
@@ -338,7 +338,7 @@
   SourceSpan get location;
 
   /// Deserializes a [MemberDefinition] object from [source].
-  factory MemberDefinition.readFromDataSource(DataSource source) {
+  factory MemberDefinition.readFromDataSource(DataSourceReader source) {
     MemberKind kind = source.readEnum(MemberKind.values);
     switch (kind) {
       case MemberKind.regular:
@@ -356,7 +356,7 @@
   }
 
   /// Serializes this [MemberDefinition] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 }
 
 enum ClassKind {
@@ -378,7 +378,7 @@
 
   RegularMemberDefinition(this.node);
 
-  factory RegularMemberDefinition.readFromDataSource(DataSource source) {
+  factory RegularMemberDefinition.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member node = source.readMemberNode();
     source.end(tag);
@@ -386,7 +386,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(MemberKind.regular);
     sink.begin(tag);
     sink.writeMemberNode(node);
@@ -418,7 +418,7 @@
   SpecialMemberDefinition(this.node, this.kind);
 
   factory SpecialMemberDefinition.readFromDataSource(
-      DataSource source, MemberKind kind) {
+      DataSourceReader source, MemberKind kind) {
     source.begin(tag);
     ir.TreeNode node = source.readTreeNode();
     source.end(tag);
@@ -426,7 +426,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(kind);
     sink.begin(tag);
     sink.writeTreeNode(node);
@@ -454,7 +454,7 @@
   SourceSpan get location;
 
   /// Deserializes a [ClassDefinition] object from [source].
-  factory ClassDefinition.readFromDataSource(DataSource source) {
+  factory ClassDefinition.readFromDataSource(DataSourceReader source) {
     ClassKind kind = source.readEnum(ClassKind.values);
     switch (kind) {
       case ClassKind.regular:
@@ -468,7 +468,7 @@
   }
 
   /// Serializes this [ClassDefinition] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 }
 
 /// A class directly defined by its [ir.Class] node.
@@ -482,7 +482,7 @@
 
   RegularClassDefinition(this.node);
 
-  factory RegularClassDefinition.readFromDataSource(DataSource source) {
+  factory RegularClassDefinition.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Class node = source.readClassNode();
     source.end(tag);
@@ -490,7 +490,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(kind);
     sink.begin(tag);
     sink.writeClassNode(node);
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index accde9d..5b30ba7 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -293,7 +293,7 @@
   }
 
   JsKernelToElementMap.readFromDataSource(this.options, this.reporter,
-      this._environment, ir.Component component, DataSource source) {
+      this._environment, ir.Component component, DataSourceReader source) {
     _elementEnvironment = JsElementEnvironment(this);
     _typeConverter = DartTypeConverter(this);
     _types = KernelDartTypes(this, options);
@@ -430,7 +430,7 @@
   }
 
   /// Serializes this [JsToElementMap] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
 
     // Serialize the entities before serializing the data.
@@ -2629,7 +2629,7 @@
 
   @override
   IndexedMember readMemberFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
+      DataSourceReader source, EntityLookup entityLookup) {
     int index = source.readInt();
     if (index == 0) {
       return _readLateMemberFromDataSource(source, entityLookup);
@@ -2639,7 +2639,7 @@
   }
 
   IndexedMember _readLateMemberFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
+      DataSourceReader source, EntityLookup entityLookup) {
     LateMemberKind kind = source.readEnum(LateMemberKind.values);
     switch (kind) {
       case LateMemberKind.constructorBody:
@@ -2664,7 +2664,7 @@
   ClosedEntityWriter(this._earlyMemberIndexLimit);
 
   @override
-  void writeMemberToDataSink(DataSink sink, IndexedMember value) {
+  void writeMemberToDataSink(DataSinkWriter sink, IndexedMember value) {
     if (value.memberIndex >= _earlyMemberIndexLimit) {
       sink.writeInt(0);
       _writeLateMemberToDataSink(sink, value);
@@ -2673,7 +2673,7 @@
     }
   }
 
-  void _writeLateMemberToDataSink(DataSink sink, IndexedMember value) {
+  void _writeLateMemberToDataSink(DataSinkWriter sink, IndexedMember value) {
     if (value is JConstructorBody) {
       sink.writeEnum(LateMemberKind.constructorBody);
       sink.writeMember(value.constructor);
diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart
index 62b7315..01c50f9 100644
--- a/pkg/compiler/lib/src/js_model/elements.dart
+++ b/pkg/compiler/lib/src/js_model/elements.dart
@@ -30,7 +30,7 @@
   JLibrary(this.name, this.canonicalUri, this.isNonNullableByDefault);
 
   /// Deserializes a [JLibrary] object from [source].
-  factory JLibrary.readFromDataSource(DataSource source) {
+  factory JLibrary.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     String name = source.readString();
     Uri canonicalUri = source.readUri();
@@ -40,7 +40,7 @@
   }
 
   /// Serializes this [JLibrary] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeString(name);
     sink.writeUri(canonicalUri);
@@ -71,7 +71,7 @@
   JClass(this.library, this.name, {this.isAbstract});
 
   /// Deserializes a [JClass] object from [source].
-  factory JClass.readFromDataSource(DataSource source) {
+  factory JClass.readFromDataSource(DataSourceReader source) {
     JClassKind kind = source.readEnum(JClassKind.values);
     switch (kind) {
       case JClassKind.node:
@@ -90,7 +90,7 @@
   }
 
   /// Serializes this [JClass] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassKind.node);
     sink.begin(tag);
     sink.writeLibrary(library);
@@ -135,7 +135,7 @@
       : _isStatic = isStatic;
 
   /// Deserializes a [JMember] object from [source].
-  factory JMember.readFromDataSource(DataSource source) {
+  factory JMember.readFromDataSource(DataSourceReader source) {
     JMemberKind kind = source.readEnum(JMemberKind.values);
     switch (kind) {
       case JMemberKind.generativeConstructor:
@@ -167,7 +167,7 @@
   }
 
   /// Serializes this [JMember] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   @override
   String get name => _name.text;
@@ -272,7 +272,7 @@
       : super(enclosingClass, name, parameterStructure,
             isExternal: isExternal, isConst: isConst);
 
-  factory JGenerativeConstructor.readFromDataSource(DataSource source) {
+  factory JGenerativeConstructor.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JClass enclosingClass = source.readClass();
     String name = source.readString();
@@ -287,7 +287,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.generativeConstructor);
     sink.begin(tag);
     sink.writeClass(enclosingClass);
@@ -319,7 +319,7 @@
       : super(enclosingClass, name, parameterStructure,
             isExternal: isExternal, isConst: isConst);
 
-  factory JFactoryConstructor.readFromDataSource(DataSource source) {
+  factory JFactoryConstructor.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JClass enclosingClass = source.readClass();
     String name = source.readString();
@@ -337,7 +337,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.factoryConstructor);
     sink.begin(tag);
     sink.writeClass(enclosingClass);
@@ -369,7 +369,7 @@
             constructor.memberName, parameterStructure, AsyncMarker.SYNC,
             isStatic: false, isExternal: false);
 
-  factory JConstructorBody.readFromDataSource(DataSource source) {
+  factory JConstructorBody.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JConstructor constructor = source.readMember();
     ParameterStructure parameterStructure =
@@ -379,7 +379,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.constructorBody);
     sink.begin(tag);
     sink.writeMember(constructor);
@@ -405,7 +405,7 @@
       : super(library, enclosingClass, name, parameterStructure, asyncMarker,
             isStatic: isStatic, isExternal: isExternal);
 
-  factory JMethod.readFromDataSource(DataSource source) {
+  factory JMethod.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberContextKind kind = source.readEnum(MemberContextKind.values);
     JLibrary library;
@@ -433,7 +433,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.method);
     sink.begin(tag);
     if (enclosingClass != null) {
@@ -475,7 +475,7 @@
             function.parameterStructure, function.asyncMarker,
             isStatic: function.isStatic, isExternal: false);
 
-  factory JGeneratorBody.readFromDataSource(DataSource source) {
+  factory JGeneratorBody.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JFunction function = source.readMember();
     DartType elementType = source.readDartType();
@@ -484,7 +484,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.generatorBody);
     sink.begin(tag);
     sink.writeMember(function);
@@ -511,7 +511,7 @@
             asyncMarker,
             isStatic: isStatic, isExternal: isExternal);
 
-  factory JGetter.readFromDataSource(DataSource source) {
+  factory JGetter.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberContextKind kind = source.readEnum(MemberContextKind.values);
     JLibrary library;
@@ -536,7 +536,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.getter);
     sink.begin(tag);
     if (enclosingClass != null) {
@@ -575,7 +575,7 @@
             AsyncMarker.SYNC,
             isStatic: isStatic, isExternal: isExternal);
 
-  factory JSetter.readFromDataSource(DataSource source) {
+  factory JSetter.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberContextKind kind = source.readEnum(MemberContextKind.values);
     JLibrary library;
@@ -599,7 +599,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.setter);
     sink.begin(tag);
     if (enclosingClass != null) {
@@ -640,7 +640,7 @@
       {bool isStatic, this.isAssignable, this.isConst})
       : super(library, enclosingClass, name, isStatic: isStatic);
 
-  factory JField.readFromDataSource(DataSource source) {
+  factory JField.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberContextKind kind = source.readEnum(MemberContextKind.values);
     JLibrary library;
@@ -664,7 +664,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.field);
     sink.begin(tag);
     if (enclosingClass != null) {
@@ -699,7 +699,7 @@
             parameterStructure, asyncMarker,
             isStatic: false, isExternal: false, isAbstract: false);
 
-  factory JClosureCallMethod.readFromDataSource(DataSource source) {
+  factory JClosureCallMethod.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JClass enclosingClass = source.readClass();
     ParameterStructure parameterStructure =
@@ -710,7 +710,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.closureCallMethod);
     sink.begin(tag);
     sink.writeClass(enclosingClass);
@@ -735,7 +735,7 @@
             ParameterStructure.zeroArguments, AsyncMarker.SYNC,
             isStatic: false, isExternal: false, isAbstract: false);
 
-  factory JSignatureMethod.readFromDataSource(DataSource source) {
+  factory JSignatureMethod.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JClass cls = source.readClass();
     source.end(tag);
@@ -743,7 +743,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberKind.signatureMethod);
     sink.begin(tag);
     sink.writeClass(enclosingClass);
@@ -772,7 +772,7 @@
   JTypeVariable(this.typeDeclaration, this.name, this.index);
 
   /// Deserializes a [JTypeVariable] object from [source].
-  factory JTypeVariable.readFromDataSource(DataSource source) {
+  factory JTypeVariable.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JTypeVariableKind kind = source.readEnum(JTypeVariableKind.values);
     Entity typeDeclaration;
@@ -797,7 +797,7 @@
   }
 
   /// Serializes this [JTypeVariable] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     if (typeDeclaration is IndexedClass) {
       IndexedClass cls = typeDeclaration;
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index c0bcc93..a60b310 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -67,7 +67,7 @@
   JLibraryEnv(this.library, this._memberMap, this._setterMap);
 
   /// Deserializes a [JLibraryEnv] object from [source].
-  factory JLibraryEnv.readFromDataSource(DataSource source) {
+  factory JLibraryEnv.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Library library = source.readLibraryNode();
     Map<String, ir.Member> memberMap =
@@ -79,7 +79,7 @@
   }
 
   /// Serializes this [JLibraryEnv] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeLibraryNode(library);
     sink.writeStringMap(_memberMap, sink.writeMemberNode);
@@ -130,7 +130,7 @@
 
   JLibraryData(this.library, this.imports);
 
-  factory JLibraryData.readFromDataSource(DataSource source) {
+  factory JLibraryData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Library library = source.readLibraryNode();
     int importCount = source.readInt();
@@ -147,7 +147,7 @@
     return JLibraryData(library, imports);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeLibraryNode(library);
     if (imports == null) {
@@ -174,7 +174,7 @@
 /// Member data for a class.
 abstract class JClassEnv {
   /// Deserializes a [JClassEnv] object from [source].
-  factory JClassEnv.readFromDataSource(DataSource source) {
+  factory JClassEnv.readFromDataSource(DataSourceReader source) {
     JClassEnvKind kind = source.readEnum(JClassEnvKind.values);
     switch (kind) {
       case JClassEnvKind.node:
@@ -188,7 +188,7 @@
   }
 
   /// Serializes this [JClassEnv] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// The [ir.Class] that defined the class, if any.
   ir.Class get cls;
@@ -244,7 +244,7 @@
   JClassEnvImpl(this.cls, this._constructorMap, this._memberMap,
       this._setterMap, this._members, this.isMixinApplicationWithMembers);
 
-  factory JClassEnvImpl.readFromDataSource(DataSource source) {
+  factory JClassEnvImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Class cls = source.readClassNode();
     Map<String, ir.Member> constructorMap =
@@ -261,7 +261,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassEnvKind.node);
     sink.begin(tag);
     sink.writeClassNode(cls);
@@ -324,7 +324,7 @@
 
   RecordEnv(this._memberMap);
 
-  factory RecordEnv.readFromDataSource(DataSource source) {
+  factory RecordEnv.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Map<String, IndexedMember> _memberMap =
         source.readStringMap(() => source.readMember());
@@ -333,7 +333,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassEnvKind.record);
     sink.begin(tag);
     sink.writeStringMap(
@@ -386,7 +386,7 @@
 
   ClosureClassEnv(Map<String, MemberEntity> memberMap) : super(memberMap);
 
-  factory ClosureClassEnv.readFromDataSource(DataSource source) {
+  factory ClosureClassEnv.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Map<String, IndexedMember> _memberMap =
         source.readStringMap(() => source.readMember());
@@ -395,7 +395,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassEnvKind.closure);
     sink.begin(tag);
     sink.writeStringMap(
@@ -419,7 +419,7 @@
 
 abstract class JClassData {
   /// Deserializes a [JClassData] object from [source].
-  factory JClassData.readFromDataSource(DataSource source) {
+  factory JClassData.readFromDataSource(DataSourceReader source) {
     JClassDataKind kind = source.readEnum(JClassDataKind.values);
     switch (kind) {
       case JClassDataKind.node:
@@ -433,7 +433,7 @@
   }
 
   /// Serializes this [JClassData] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   ClassDefinition get definition;
 
@@ -485,7 +485,7 @@
 
   JClassDataImpl(this.cls, this.definition);
 
-  factory JClassDataImpl.readFromDataSource(DataSource source) {
+  factory JClassDataImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Class cls = source.readClassNode();
     ClassDefinition definition = ClassDefinition.readFromDataSource(source);
@@ -494,7 +494,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JClassDataKind.node);
     sink.begin(tag);
     sink.writeClassNode(cls);
@@ -538,7 +538,7 @@
   JMemberData();
 
   /// Deserializes a [JMemberData] object from [source].
-  factory JMemberData.readFromDataSource(DataSource source) {
+  factory JMemberData.readFromDataSource(DataSourceReader source) {
     JMemberDataKind kind = source.readEnum(JMemberDataKind.values);
     switch (kind) {
       case JMemberDataKind.function:
@@ -562,7 +562,7 @@
   }
 
   /// Serializes this [JMemberData] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 }
 
 abstract class JMemberDataImpl implements JMemberData {
@@ -689,7 +689,7 @@
       MemberDefinition definition, StaticTypeCache staticTypes)
       : super(node, definition, staticTypes);
 
-  factory FunctionDataImpl.readFromDataSource(DataSource source) {
+  factory FunctionDataImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member node = source.readMemberNode();
     ir.FunctionNode functionNode;
@@ -709,7 +709,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.function);
     sink.begin(tag);
     sink.writeMemberNode(node);
@@ -748,7 +748,7 @@
   SignatureFunctionData(this.definition, this.memberThisType,
       this.typeParameters, this.classTypeVariableAccess);
 
-  factory SignatureFunctionData.readFromDataSource(DataSource source) {
+  factory SignatureFunctionData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberDefinition definition = MemberDefinition.readFromDataSource(source);
     InterfaceType memberThisType = source.readDartType(allowNull: true);
@@ -761,7 +761,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.signature);
     sink.begin(tag);
     definition.writeToDataSink(sink);
@@ -851,7 +851,8 @@
   GeneratorBodyFunctionData(FunctionData baseData, this.definition)
       : super(baseData);
 
-  factory GeneratorBodyFunctionData.readFromDataSource(DataSource source) {
+  factory GeneratorBodyFunctionData.readFromDataSource(
+      DataSourceReader source) {
     source.begin(tag);
     // TODO(johnniwinther): Share the original base data on deserialization.
     FunctionData baseData = JMemberData.readFromDataSource(source);
@@ -861,7 +862,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.generatorBody);
     sink.begin(tag);
     baseData.writeToDataSink(sink);
@@ -887,7 +888,7 @@
       MemberDefinition definition, StaticTypeCache staticTypes)
       : super(node, functionNode, definition, staticTypes);
 
-  factory JConstructorDataImpl.readFromDataSource(DataSource source) {
+  factory JConstructorDataImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member node = source.readMemberNode();
     ir.FunctionNode functionNode;
@@ -907,7 +908,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.constructor);
     sink.begin(tag);
     sink.writeMemberNode(node);
@@ -931,7 +932,7 @@
       MemberDefinition definition, StaticTypeCache staticTypes)
       : super(node, functionNode, definition, staticTypes);
 
-  factory ConstructorBodyDataImpl.readFromDataSource(DataSource source) {
+  factory ConstructorBodyDataImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member node = source.readMemberNode();
     ir.FunctionNode functionNode;
@@ -951,7 +952,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.constructorBody);
     sink.begin(tag);
     sink.writeMemberNode(node);
@@ -982,7 +983,7 @@
       ir.Field node, MemberDefinition definition, StaticTypeCache staticTypes)
       : super(node, definition, staticTypes);
 
-  factory JFieldDataImpl.readFromDataSource(DataSource source) {
+  factory JFieldDataImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.Member node = source.readMemberNode();
     MemberDefinition definition = MemberDefinition.readFromDataSource(source);
@@ -993,7 +994,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.writeEnum(JMemberDataKind.field);
     sink.begin(tag);
     sink.writeMemberNode(node);
@@ -1028,14 +1029,14 @@
 
   JTypeVariableData(this.node);
 
-  factory JTypeVariableData.readFromDataSource(DataSource source) {
+  factory JTypeVariableData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ir.TypeParameter node = source.readTypeParameterNode();
     source.end(tag);
     return JTypeVariableData(node);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeTypeParameterNode(node);
     sink.end(tag);
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index e262869..61dfd89 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -318,10 +318,12 @@
     if (_compiler.options.testMode) {
       bool useDataKinds = true;
       List<Object> data = [];
-      DataSink sink = ObjectSink(data, useDataKinds: useDataKinds);
+      DataSinkWriter sink =
+          DataSinkWriter(ObjectDataSink(data), useDataKinds: useDataKinds);
       sink.registerCodegenWriter(CodegenWriterImpl(closedWorld));
       result.writeToDataSink(sink);
-      DataSource source = ObjectSource(data, useDataKinds: useDataKinds);
+      DataSourceReader source =
+          DataSourceReader(ObjectDataSource(data), useDataKinds: useDataKinds);
       List<ModularName> modularNames = [];
       List<ModularExpression> modularExpression = [];
       source.registerCodegenReader(
@@ -388,7 +390,7 @@
   }
 
   /// Prepare [source] to deserialize modular code generation data.
-  void prepareCodegenReader(DataSource source) {
+  void prepareCodegenReader(DataSourceReader source) {
     source.registerEntityReader(ClosedEntityReader(_elementMap));
     source.registerEntityLookup(ClosedEntityLookup(_elementMap));
     source.registerComponentLookup(
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 1c45fd2..e6803aa 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -126,7 +126,7 @@
       Environment environment,
       AbstractValueStrategy abstractValueStrategy,
       ir.Component component,
-      DataSource source) {
+      DataSourceReader source) {
     source.begin(tag);
 
     JsKernelToElementMap elementMap = JsKernelToElementMap.readFromDataSource(
@@ -198,7 +198,7 @@
   }
 
   /// Serializes this [JsClosedWorld] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     elementMap.writeToDataSink(sink);
     classHierarchy.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/js_model/locals.dart b/pkg/compiler/lib/src/js_model/locals.dart
index 6f88356..ff38486 100644
--- a/pkg/compiler/lib/src/js_model/locals.dart
+++ b/pkg/compiler/lib/src/js_model/locals.dart
@@ -38,7 +38,7 @@
   /// Deserializes a [GlobalLocalsMap] object from [source].
   factory GlobalLocalsMap.readFromDataSource(
       MemberEntity Function(MemberEntity) localMapKeyLookup,
-      DataSource source) {
+      DataSourceReader source) {
     source.begin(tag);
     Map<MemberEntity, KernelToLocalsMap> _localsMaps = {};
     int mapCount = source.readInt();
@@ -55,7 +55,7 @@
   }
 
   /// Serializes this [GlobalLocalsMap] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     // [KernelToLocalsMap]s are shared between members and their nested
     // closures, so we reverse [_localsMaps] to ensure that [KernelToLocalsMap]s
@@ -107,7 +107,7 @@
   KernelToLocalsMapImpl(this._currentMember);
 
   /// Deserializes a [KernelToLocalsMapImpl] object from [source].
-  KernelToLocalsMapImpl.readFromDataSource(DataSource source) {
+  KernelToLocalsMapImpl.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     _currentMember = source.readMember();
     int localsCount = source.readInt();
@@ -143,7 +143,7 @@
 
   /// Serializes this [KernelToLocalsMapImpl] to [sink].
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMember(currentMember);
     sink.writeInt(_locals.size);
@@ -475,7 +475,7 @@
       this.isContinueTarget = false});
 
   /// Deserializes a [JJumpTarget] object from [source].
-  factory JJumpTarget.readFromDataSource(DataSource source) {
+  factory JJumpTarget.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberEntity memberContext = source.readMember();
     int nestingLevel = source.readInt();
@@ -501,7 +501,7 @@
   }
 
   /// Serializes this [JJumpTarget] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeMember(memberContext);
     sink.writeInt(nestingLevel);
diff --git a/pkg/compiler/lib/src/js_model/type_recipe.dart b/pkg/compiler/lib/src/js_model/type_recipe.dart
index 161e6cc..590ef0a 100644
--- a/pkg/compiler/lib/src/js_model/type_recipe.dart
+++ b/pkg/compiler/lib/src/js_model/type_recipe.dart
@@ -147,7 +147,7 @@
 
   int _computeHashCode();
 
-  factory TypeRecipe.readFromDataSource(DataSource source) {
+  factory TypeRecipe.readFromDataSource(DataSourceReader source) {
     TypeRecipe recipe;
     source.begin(tag);
     _TypeRecipeKind kind = source.readEnum(_TypeRecipeKind.values);
@@ -166,7 +166,7 @@
     return recipe;
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeEnum(_kind);
     _writeToDataSink(sink);
@@ -174,7 +174,7 @@
   }
 
   _TypeRecipeKind get _kind;
-  void _writeToDataSink(DataSink sink);
+  void _writeToDataSink(DataSinkWriter sink);
 
   /// Returns `true` is [recipeB] evaluated in an environment described by
   /// [structureB] gives the same type as [recipeA] evaluated in environment
@@ -203,7 +203,7 @@
 
   TypeExpressionRecipe(this.type);
 
-  static TypeExpressionRecipe _readFromDataSource(DataSource source) {
+  static TypeExpressionRecipe _readFromDataSource(DataSourceReader source) {
     return TypeExpressionRecipe(source.readDartType());
   }
 
@@ -211,7 +211,7 @@
   _TypeRecipeKind get _kind => _TypeRecipeKind.expression;
 
   @override
-  void _writeToDataSink(DataSink sink) {
+  void _writeToDataSink(DataSinkWriter sink) {
     sink.writeDartType(type);
   }
 
@@ -237,7 +237,8 @@
 
   SingletonTypeEnvironmentRecipe(this.type);
 
-  static SingletonTypeEnvironmentRecipe _readFromDataSource(DataSource source) {
+  static SingletonTypeEnvironmentRecipe _readFromDataSource(
+      DataSourceReader source) {
     return SingletonTypeEnvironmentRecipe(source.readDartType());
   }
 
@@ -245,7 +246,7 @@
   _TypeRecipeKind get _kind => _TypeRecipeKind.singletonEnvironment;
 
   @override
-  void _writeToDataSink(DataSink sink) {
+  void _writeToDataSink(DataSinkWriter sink) {
     sink.writeDartType(type);
   }
 
@@ -277,7 +278,8 @@
 
   FullTypeEnvironmentRecipe({this.classType, this.types = const []});
 
-  static FullTypeEnvironmentRecipe _readFromDataSource(DataSource source) {
+  static FullTypeEnvironmentRecipe _readFromDataSource(
+      DataSourceReader source) {
     InterfaceType classType =
         source.readDartType(allowNull: true) as InterfaceType;
     List<DartType> types = source.readDartTypes(emptyAsNull: true) ?? const [];
@@ -288,7 +290,7 @@
   _TypeRecipeKind get _kind => _TypeRecipeKind.fullEnvironment;
 
   @override
-  void _writeToDataSink(DataSink sink) {
+  void _writeToDataSink(DataSinkWriter sink) {
     sink.writeDartType(classType, allowNull: true);
     sink.writeDartTypes(types, allowNull: false);
   }
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 9ff6f5f..4bfe3529 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -29,12 +29,10 @@
 import '../ir/impact_data.dart';
 import '../ir/static_type.dart';
 import '../ir/static_type_cache.dart';
-import '../ir/scope.dart';
 import '../ir/types.dart';
 import '../ir/visitors.dart';
 import '../ir/util.dart';
 import '../js/js.dart' as js;
-import '../js_backend/annotations.dart';
 import '../js_backend/namer.dart';
 import '../js_backend/native_data.dart';
 import '../js_model/locals.dart';
@@ -1445,49 +1443,27 @@
       _nativeBehaviorBuilder ??= BehaviorBuilder(elementEnvironment,
           commonElements, nativeBasicData, reporter, options);
 
-  ResolutionImpact computeWorldImpact(KMember member,
-      VariableScopeModel variableScopeModel, Set<PragmaAnnotation> annotations,
-      {ImpactBuilderData impactBuilderData}) {
+  ResolutionImpact computeWorldImpact(
+      KMember member, ImpactBuilderData impactBuilderData) {
     KMemberData memberData = members.getData(member);
     ir.Member node = memberData.node;
 
-    if (impactBuilderData != null) {
-      if (impactBuilderData.typeMapsForTesting != null) {
-        typeMapsForTesting ??= {};
-        typeMapsForTesting[member] = impactBuilderData.typeMapsForTesting;
-      }
-      ImpactData impactData = impactBuilderData.impactData;
-      memberData.staticTypes = impactBuilderData.cachedStaticTypes;
-      KernelImpactConverter converter = KernelImpactConverter(
-          this,
-          member,
-          reporter,
-          options,
-          _constantValuefier,
-          // TODO(johnniwinther): Pull the static type context from the cached
-          // static types.
-          ir.StaticTypeContext(node, typeEnvironment));
-      return converter.convert(impactData);
-    } else {
-      StaticTypeCacheImpl staticTypeCache = StaticTypeCacheImpl();
-      KernelImpactBuilder builder = KernelImpactBuilder(
-          this,
-          member,
-          reporter,
-          options,
-          ir.StaticTypeContext(node, typeEnvironment, cache: staticTypeCache),
-          staticTypeCache,
-          variableScopeModel,
-          annotations,
-          _constantValuefier);
-      if (retainDataForTesting) {
-        typeMapsForTesting ??= {};
-        typeMapsForTesting[member] = builder.typeMapsForTesting = {};
-      }
-      node.accept(builder);
-      memberData.staticTypes = builder.getStaticTypeCache();
-      return builder.impactBuilder;
+    if (impactBuilderData.typeMapsForTesting != null) {
+      typeMapsForTesting ??= {};
+      typeMapsForTesting[member] = impactBuilderData.typeMapsForTesting;
     }
+    ImpactData impactData = impactBuilderData.impactData;
+    memberData.staticTypes = impactBuilderData.cachedStaticTypes;
+    KernelImpactConverter converter = KernelImpactConverter(
+        this,
+        member,
+        reporter,
+        options,
+        _constantValuefier,
+        // TODO(johnniwinther): Pull the static type context from the cached
+        // static types.
+        ir.StaticTypeContext(node, typeEnvironment));
+    return converter.convert(impactData);
   }
 
   StaticTypeCache getCachedStaticTypes(KMember member) {
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index 2d4c60f..7b863ab 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -16,11 +16,9 @@
 import '../ir/impact.dart';
 import '../ir/impact_data.dart';
 import '../ir/runtime_type_analysis.dart';
-import '../ir/scope.dart';
 import '../ir/static_type.dart';
 import '../ir/util.dart';
 import '../ir/visitors.dart';
-import '../js_backend/annotations.dart';
 import '../js_backend/native_data.dart';
 import '../native/behavior.dart';
 import '../options.dart';
@@ -32,68 +30,15 @@
 import '../universe/world_builder.dart';
 import 'element_map.dart';
 
-/// Visitor that computes the world impact of a member.
-class KernelImpactBuilder extends ImpactBuilderBase
-    with KernelImpactRegistryMixin {
-  @override
+/// [ImpactRegistry] that converts kernel based impact data to world impact
+/// object based on the K model.
+class KernelImpactConverter implements ImpactRegistry {
   final ResolutionWorldImpactBuilder impactBuilder;
-  @override
   final KernelToElementMap elementMap;
-  @override
   final DiagnosticReporter reporter;
-  @override
   final CompilerOptions _options;
-  @override
   final MemberEntity currentMember;
-  final Set<PragmaAnnotation> _annotations;
-  @override
   final ConstantValuefier _constantValuefier;
-
-  KernelImpactBuilder(
-      this.elementMap,
-      this.currentMember,
-      this.reporter,
-      this._options,
-      ir.StaticTypeContext staticTypeContext,
-      StaticTypeCacheImpl staticTypeCache,
-      VariableScopeModel variableScopeModel,
-      this._annotations,
-      this._constantValuefier)
-      : this.impactBuilder = ResolutionWorldImpactBuilder(
-            elementMap.commonElements.dartTypes, currentMember),
-        super(staticTypeContext, staticTypeCache, elementMap.classHierarchy,
-            variableScopeModel);
-
-  @override
-  CommonElements get commonElements => elementMap.commonElements;
-
-  @override
-  NativeBasicData get _nativeBasicData => elementMap.nativeBasicData;
-
-  @override
-  bool get useAsserts => _options.enableUserAssertions;
-
-  @override
-  bool get inferEffectivelyFinalVariableTypes =>
-      !_annotations.contains(PragmaAnnotation.disableFinal);
-}
-
-/// Converts a [ImpactData] object based on kernel to the corresponding
-/// [ResolutionImpact] based on the K model.
-class KernelImpactConverter extends KernelImpactRegistryMixin {
-  @override
-  final ResolutionWorldImpactBuilder impactBuilder;
-  @override
-  final KernelToElementMap elementMap;
-  @override
-  final DiagnosticReporter reporter;
-  @override
-  final CompilerOptions _options;
-  @override
-  final MemberEntity currentMember;
-  @override
-  final ConstantValuefier _constantValuefier;
-  @override
   final ir.StaticTypeContext staticTypeContext;
 
   KernelImpactConverter(this.elementMap, this.currentMember, this.reporter,
@@ -101,37 +46,13 @@
       : this.impactBuilder = ResolutionWorldImpactBuilder(
             elementMap.commonElements.dartTypes, currentMember);
 
-  @override
   ir.TypeEnvironment get typeEnvironment => elementMap.typeEnvironment;
 
-  @override
   CommonElements get commonElements => elementMap.commonElements;
 
-  @override
   NativeBasicData get _nativeBasicData => elementMap.nativeBasicData;
 
-  /// Converts a [ImpactData] object based on kernel to the corresponding
-  /// [ResolutionImpact] based on the K model.
-  ResolutionImpact convert(ImpactData impactData) {
-    impactData.apply(this);
-    return impactBuilder;
-  }
-}
-
-/// [ImpactRegistry] that converts kernel based impact data to world impact
-/// object based on the K model.
-abstract class KernelImpactRegistryMixin implements ImpactRegistry {
-  CompilerOptions get _options;
-  DiagnosticReporter get reporter;
-  KernelToElementMap get elementMap;
-  MemberEntity get currentMember;
-  ResolutionWorldImpactBuilder get impactBuilder;
-  ir.TypeEnvironment get typeEnvironment;
-  CommonElements get commonElements;
   DartTypes get dartTypes => commonElements.dartTypes;
-  NativeBasicData get _nativeBasicData;
-  ConstantValuefier get _constantValuefier;
-  ir.StaticTypeContext get staticTypeContext;
 
   String typeToString(DartType type) =>
       type.toStructuredText(dartTypes, _options);
@@ -871,4 +792,11 @@
       }
     }
   }
+
+  /// Converts a [ImpactData] object based on kernel to the corresponding
+  /// [ResolutionImpact] based on the K model.
+  ResolutionImpact convert(ImpactData impactData) {
+    impactData.apply(this);
+    return impactBuilder;
+  }
 }
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index d3c918a..cd466b2 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -382,12 +382,8 @@
       }
       ImpactBuilderData impactBuilderData = modularMemberData.impactBuilderData;
       return _compilerTask.measureSubtask('worldImpact', () {
-        ResolutionImpact impact = _elementMap.computeWorldImpact(
-            element,
-            scopeModel.variableScopeModel,
-            Set<PragmaAnnotation>.from(
-                annotations.iterable(PragmaAnnotation.values)),
-            impactBuilderData: impactBuilderData);
+        ResolutionImpact impact =
+            _elementMap.computeWorldImpact(element, impactBuilderData);
         WorldImpact worldImpact =
             _impactTransformer.transformResolutionImpact(impact);
         if (_impactCache != null) {
@@ -402,11 +398,6 @@
   String toString() => 'KernelWorkItem($element)';
 }
 
-/// If `true` kernel impacts are computed as [ImpactData] directly on kernel
-/// and converted to the K model afterwards. This is a pre-step to modularizing
-/// the world impact computation.
-bool useImpactDataForTesting = false;
-
 class KernelModularStrategy extends ModularStrategy {
   final CompilerTask _compilerTask;
   final KernelToElementMap _elementMap;
@@ -423,19 +414,14 @@
       ir.Member node, EnumSet<PragmaAnnotation> annotations) {
     ScopeModel scopeModel = _compilerTask.measureSubtask(
         'closures', () => ScopeModel.from(node, _elementMap.constantEvaluator));
-    if (useImpactDataForTesting) {
-      return _compilerTask.measureSubtask('worldImpact', () {
-        return computeModularMemberData(node,
-            options: _elementMap.options,
-            typeEnvironment: _elementMap.typeEnvironment,
-            classHierarchy: _elementMap.classHierarchy,
-            scopeModel: scopeModel,
-            annotations: annotations);
-      });
-    } else {
-      ImpactBuilderData impactBuilderData;
-      return ModularMemberData(scopeModel, impactBuilderData);
-    }
+    return _compilerTask.measureSubtask('worldImpact', () {
+      return computeModularMemberData(node,
+          options: _elementMap.options,
+          typeEnvironment: _elementMap.typeEnvironment,
+          classHierarchy: _elementMap.classHierarchy,
+          scopeModel: scopeModel,
+          annotations: annotations);
+    });
   }
 }
 
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index f8f41cb..cf696e9 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -195,7 +195,7 @@
   NativeBehavior.internal(this.sideEffects);
 
   /// Deserializes a [NativeBehavior] object from [source].
-  factory NativeBehavior.readFromDataSource(DataSource source) {
+  factory NativeBehavior.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
 
     List<Object> readTypes() {
@@ -233,7 +233,7 @@
   }
 
   /// Serializes this [NativeBehavior] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
 
     void writeTypes(List<Object> types) {
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index dc2b669..34232db 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -38,7 +38,7 @@
   OrderedTypeSet.internal(this._levels, this.types);
 
   /// Deserializes a [OrderedTypeSet] object from [source].
-  factory OrderedTypeSet.readFromDataSource(DataSource source) {
+  factory OrderedTypeSet.readFromDataSource(DataSourceReader source) {
     // TODO(johnniwinther): Make the deserialized type sets share their
     // internal links like the original type sets do?
     source.begin(tag);
@@ -63,7 +63,7 @@
   }
 
   /// Serializes this [OrderedTypeSet] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     List<InterfaceType> typeList = types.toList();
     sink.writeInt(typeList.length);
diff --git a/pkg/compiler/lib/src/serialization/abstract_sink.dart b/pkg/compiler/lib/src/serialization/abstract_sink.dart
deleted file mode 100644
index 76d794a..0000000
--- a/pkg/compiler/lib/src/serialization/abstract_sink.dart
+++ /dev/null
@@ -1,649 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of 'serialization.dart';
-
-/// Base implementation of [DataSink] using [DataSinkMixin] to implement
-/// convenience methods.
-abstract class AbstractDataSink extends DataSinkMixin implements DataSink {
-  /// If `true`, serialization of every data kind is preceded by a [DataKind]
-  /// value.
-  ///
-  /// This is used for debugging data inconsistencies between serialization
-  /// and deserialization.
-  final bool useDataKinds;
-  DataSourceIndices importedIndices;
-
-  /// Visitor used for serializing [ir.DartType]s.
-  DartTypeNodeWriter _dartTypeNodeWriter;
-
-  /// Stack of tags used when [useDataKinds] is `true` to help debugging section
-  /// inconsistencies between serialization and deserialization.
-  List<String> _tags;
-
-  /// Map of [_MemberData] object for serialized kernel member nodes.
-  final Map<ir.Member, _MemberData> _memberData = {};
-
-  IndexedSink<String> _stringIndex;
-  IndexedSink<Uri> _uriIndex;
-  IndexedSink<ir.Member> _memberNodeIndex;
-  IndexedSink<ImportEntity> _importIndex;
-  IndexedSink<ConstantValue> _constantIndex;
-
-  final Map<Type, IndexedSink> _generalCaches = {};
-
-  EntityWriter _entityWriter = const EntityWriter();
-  CodegenWriter _codegenWriter;
-
-  final Map<String, int> tagFrequencyMap;
-
-  ir.Member _currentMemberContext;
-  _MemberData _currentMemberData;
-
-  IndexedSink<T> _createSink<T>() {
-    if (importedIndices == null || !importedIndices.caches.containsKey(T)) {
-      return IndexedSink<T>(this);
-    } else {
-      Map<T, int> cacheCopy = Map.from(importedIndices.caches[T].cache);
-      return IndexedSink<T>(this, cache: cacheCopy);
-    }
-  }
-
-  AbstractDataSink(
-      {this.useDataKinds = false, this.tagFrequencyMap, this.importedIndices}) {
-    _dartTypeNodeWriter = DartTypeNodeWriter(this);
-    _stringIndex = _createSink<String>();
-    _uriIndex = _createSink<Uri>();
-    _memberNodeIndex = _createSink<ir.Member>();
-    _importIndex = _createSink<ImportEntity>();
-    _constantIndex = _createSink<ConstantValue>();
-  }
-
-  @override
-  void begin(String tag) {
-    if (tagFrequencyMap != null) {
-      tagFrequencyMap[tag] ??= 0;
-      tagFrequencyMap[tag]++;
-    }
-    if (useDataKinds) {
-      _tags ??= <String>[];
-      _tags.add(tag);
-      _begin(tag);
-    }
-  }
-
-  @override
-  void end(Object tag) {
-    if (useDataKinds) {
-      _end(tag);
-
-      String existingTag = _tags.removeLast();
-      assert(existingTag == tag,
-          "Unexpected tag end. Expected $existingTag, found $tag.");
-    }
-  }
-
-  @override
-  void inMemberContext(ir.Member context, void f()) {
-    ir.Member oldMemberContext = _currentMemberContext;
-    _MemberData oldMemberData = _currentMemberData;
-    _currentMemberContext = context;
-    _currentMemberData = null;
-    f();
-    _currentMemberData = oldMemberData;
-    _currentMemberContext = oldMemberContext;
-  }
-
-  _MemberData get currentMemberData {
-    assert(_currentMemberContext != null,
-        "DataSink has no current member context.");
-    return _currentMemberData ??= _memberData[_currentMemberContext] ??=
-        _MemberData(_currentMemberContext);
-  }
-
-  @override
-  void writeCached<E>(E value, void f(E value)) {
-    IndexedSink sink = _generalCaches[E] ??= _createSink<E>();
-    sink.write(value, (v) => f(v));
-  }
-
-  @override
-  void writeSourceSpan(SourceSpan value) {
-    _writeDataKind(DataKind.sourceSpan);
-    _writeUri(value.uri);
-    _writeIntInternal(value.begin);
-    _writeIntInternal(value.end);
-  }
-
-  @override
-  void writeDartType(DartType value, {bool allowNull = false}) {
-    _writeDataKind(DataKind.dartType);
-    _writeDartType(value, [], allowNull: allowNull);
-  }
-
-  void _writeDartType(
-      DartType value, List<FunctionTypeVariable> functionTypeVariables,
-      {bool allowNull = false}) {
-    if (value == null) {
-      if (!allowNull) {
-        throw UnsupportedError("Missing DartType is not allowed.");
-      }
-      writeEnum(DartTypeKind.none);
-    } else {
-      value.writeToDataSink(this, functionTypeVariables);
-    }
-  }
-
-  @override
-  void writeDartTypeNode(ir.DartType value, {bool allowNull = false}) {
-    _writeDataKind(DataKind.dartTypeNode);
-    _writeDartTypeNode(value, [], allowNull: allowNull);
-  }
-
-  void _writeDartTypeNode(
-      ir.DartType value, List<ir.TypeParameter> functionTypeVariables,
-      {bool allowNull = false}) {
-    if (value == null) {
-      if (!allowNull) {
-        throw UnsupportedError("Missing ir.DartType node is not allowed.");
-      }
-      writeEnum(DartTypeNodeKind.none);
-    } else {
-      value.accept1(_dartTypeNodeWriter, functionTypeVariables);
-    }
-  }
-
-  @override
-  void writeMemberNode(ir.Member value) {
-    _writeDataKind(DataKind.memberNode);
-    _writeMemberNode(value);
-  }
-
-  void _writeMemberNode(ir.Member value) {
-    _memberNodeIndex.write(value, _writeMemberNodeInternal);
-  }
-
-  void _writeMemberNodeInternal(ir.Member value) {
-    ir.Class cls = value.enclosingClass;
-    if (cls != null) {
-      _writeEnumInternal(MemberContextKind.cls);
-      _writeClassNode(cls);
-      _writeString(_computeMemberName(value));
-    } else {
-      _writeEnumInternal(MemberContextKind.library);
-      _writeLibraryNode(value.enclosingLibrary);
-      _writeString(_computeMemberName(value));
-    }
-  }
-
-  @override
-  void writeClassNode(ir.Class value) {
-    _writeDataKind(DataKind.classNode);
-    _writeClassNode(value);
-  }
-
-  void _writeClassNode(ir.Class value) {
-    _writeLibraryNode(value.enclosingLibrary);
-    _writeString(value.name);
-  }
-
-  @override
-  void writeTypedefNode(ir.Typedef value) {
-    _writeDataKind(DataKind.typedefNode);
-    _writeTypedefNode(value);
-  }
-
-  void _writeTypedefNode(ir.Typedef value) {
-    _writeLibraryNode(value.enclosingLibrary);
-    _writeString(value.name);
-  }
-
-  @override
-  void writeLibraryNode(ir.Library value) {
-    _writeDataKind(DataKind.libraryNode);
-    _writeLibraryNode(value);
-  }
-
-  void _writeLibraryNode(ir.Library value) {
-    _writeUri(value.importUri);
-  }
-
-  @override
-  void writeEnum(dynamic value) {
-    _writeDataKind(DataKind.enumValue);
-    _writeEnumInternal(value);
-  }
-
-  @override
-  void writeBool(bool value) {
-    assert(value != null);
-    _writeDataKind(DataKind.bool);
-    _writeBool(value);
-  }
-
-  void _writeBool(bool value) {
-    _writeIntInternal(value ? 1 : 0);
-  }
-
-  @override
-  void writeUri(Uri value) {
-    assert(value != null);
-    _writeDataKind(DataKind.uri);
-    _writeUri(value);
-  }
-
-  @override
-  void writeString(String value) {
-    assert(value != null);
-    _writeDataKind(DataKind.string);
-    _writeString(value);
-  }
-
-  @override
-  void writeInt(int value) {
-    assert(value != null);
-    assert(value >= 0 && value >> 30 == 0);
-    _writeDataKind(DataKind.uint30);
-    _writeIntInternal(value);
-  }
-
-  @override
-  void writeTreeNode(ir.TreeNode value) {
-    _writeDataKind(DataKind.treeNode);
-    _writeTreeNode(value, null);
-  }
-
-  @override
-  void writeTreeNodeInContext(ir.TreeNode value) {
-    writeTreeNodeInContextInternal(value, currentMemberData);
-  }
-
-  void writeTreeNodeInContextInternal(
-      ir.TreeNode value, _MemberData memberData) {
-    _writeDataKind(DataKind.treeNode);
-    _writeTreeNode(value, memberData);
-  }
-
-  @override
-  void writeTreeNodeOrNullInContext(ir.TreeNode value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeTreeNodeInContextInternal(value, currentMemberData);
-    }
-  }
-
-  @override
-  void writeTreeNodesInContext(Iterable<ir.TreeNode> values,
-      {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ir.TreeNode value in values) {
-        writeTreeNodeInContextInternal(value, currentMemberData);
-      }
-    }
-  }
-
-  @override
-  void writeTreeNodeMapInContext<V>(Map<ir.TreeNode, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((ir.TreeNode key, V value) {
-        writeTreeNodeInContextInternal(key, currentMemberData);
-        f(value);
-      });
-    }
-  }
-
-  _MemberData _getMemberData(ir.TreeNode node) {
-    ir.TreeNode member = node;
-    while (member is! ir.Member) {
-      if (member == null) {
-        throw UnsupportedError("No enclosing member of TreeNode "
-            "$node (${node.runtimeType})");
-      }
-      member = member.parent;
-    }
-    _writeMemberNode(member);
-    return _memberData[member] ??= _MemberData(member);
-  }
-
-  void _writeTreeNode(ir.TreeNode value, _MemberData memberData) {
-    if (value is ir.Class) {
-      _writeEnumInternal(_TreeNodeKind.cls);
-      _writeClassNode(value);
-    } else if (value is ir.Member) {
-      _writeEnumInternal(_TreeNodeKind.member);
-      _writeMemberNode(value);
-    } else if (value is ir.VariableDeclaration &&
-        value.parent is ir.FunctionDeclaration) {
-      _writeEnumInternal(_TreeNodeKind.functionDeclarationVariable);
-      _writeTreeNode(value.parent, memberData);
-    } else if (value is ir.FunctionNode) {
-      _writeEnumInternal(_TreeNodeKind.functionNode);
-      _writeFunctionNode(value, memberData);
-    } else if (value is ir.TypeParameter) {
-      _writeEnumInternal(_TreeNodeKind.typeParameter);
-      _writeTypeParameter(value, memberData);
-    } else if (value is ConstantReference) {
-      _writeEnumInternal(_TreeNodeKind.constant);
-      memberData ??= _getMemberData(value.expression);
-      _writeTreeNode(value.expression, memberData);
-      int index =
-          memberData.getIndexByConstant(value.expression, value.constant);
-      _writeIntInternal(index);
-    } else {
-      _writeEnumInternal(_TreeNodeKind.node);
-      memberData ??= _getMemberData(value);
-      int index = memberData.getIndexByTreeNode(value);
-      assert(
-          index != null,
-          "No TreeNode index found for ${value.runtimeType} "
-          "found in ${memberData}.");
-      _writeIntInternal(index);
-    }
-  }
-
-  void _writeFunctionNode(ir.FunctionNode value, _MemberData memberData) {
-    ir.TreeNode parent = value.parent;
-    if (parent is ir.Procedure) {
-      _writeEnumInternal(_FunctionNodeKind.procedure);
-      _writeMemberNode(parent);
-    } else if (parent is ir.Constructor) {
-      _writeEnumInternal(_FunctionNodeKind.constructor);
-      _writeMemberNode(parent);
-    } else if (parent is ir.FunctionExpression) {
-      _writeEnumInternal(_FunctionNodeKind.functionExpression);
-      _writeTreeNode(parent, memberData);
-    } else if (parent is ir.FunctionDeclaration) {
-      _writeEnumInternal(_FunctionNodeKind.functionDeclaration);
-      _writeTreeNode(parent, memberData);
-    } else {
-      throw UnsupportedError(
-          "Unsupported FunctionNode parent ${parent.runtimeType}");
-    }
-  }
-
-  @override
-  void writeTypeParameterNode(ir.TypeParameter value) {
-    _writeDataKind(DataKind.typeParameterNode);
-    _writeTypeParameter(value, null);
-  }
-
-  void _writeTypeParameter(ir.TypeParameter value, _MemberData memberData) {
-    ir.TreeNode parent = value.parent;
-    if (parent is ir.Class) {
-      _writeEnumInternal(_TypeParameterKind.cls);
-      _writeClassNode(parent);
-      _writeIntInternal(parent.typeParameters.indexOf(value));
-    } else if (parent is ir.FunctionNode) {
-      _writeEnumInternal(_TypeParameterKind.functionNode);
-      _writeFunctionNode(parent, memberData);
-      _writeIntInternal(parent.typeParameters.indexOf(value));
-    } else {
-      throw UnsupportedError(
-          "Unsupported TypeParameter parent ${parent.runtimeType}");
-    }
-  }
-
-  void _writeDataKind(DataKind kind) {
-    if (useDataKinds) _writeEnumInternal(kind);
-  }
-
-  @override
-  void writeLibrary(IndexedLibrary value) {
-    _entityWriter.writeLibraryToDataSink(this, value);
-  }
-
-  @override
-  void writeClass(IndexedClass value) {
-    _entityWriter.writeClassToDataSink(this, value);
-  }
-
-  @override
-  void writeMember(IndexedMember value) {
-    _entityWriter.writeMemberToDataSink(this, value);
-  }
-
-  @override
-  void writeTypeVariable(IndexedTypeVariable value) {
-    _entityWriter.writeTypeVariableToDataSink(this, value);
-  }
-
-  @override
-  void writeLocal(Local local) {
-    if (local is JLocal) {
-      writeEnum(LocalKind.jLocal);
-      writeMember(local.memberContext);
-      writeInt(local.localIndex);
-    } else if (local is ThisLocal) {
-      writeEnum(LocalKind.thisLocal);
-      writeClass(local.enclosingClass);
-    } else if (local is BoxLocal) {
-      writeEnum(LocalKind.boxLocal);
-      writeClass(local.container);
-    } else if (local is AnonymousClosureLocal) {
-      writeEnum(LocalKind.anonymousClosureLocal);
-      writeClass(local.closureClass);
-    } else if (local is TypeVariableLocal) {
-      writeEnum(LocalKind.typeVariableLocal);
-      writeTypeVariable(local.typeVariable);
-    } else {
-      throw UnsupportedError("Unsupported local ${local.runtimeType}");
-    }
-  }
-
-  @override
-  void writeConstant(ConstantValue value) {
-    _writeDataKind(DataKind.constant);
-    _writeConstant(value);
-  }
-
-  @override
-  void writeDoubleValue(double value) {
-    _writeDataKind(DataKind.double);
-    _writeDoubleValue(value);
-  }
-
-  void _writeDoubleValue(double value) {
-    ByteData data = ByteData(8);
-    data.setFloat64(0, value);
-    writeInt(data.getUint16(0));
-    writeInt(data.getUint16(2));
-    writeInt(data.getUint16(4));
-    writeInt(data.getUint16(6));
-  }
-
-  @override
-  void writeIntegerValue(int value) {
-    _writeDataKind(DataKind.int);
-    _writeBigInt(BigInt.from(value));
-  }
-
-  void _writeBigInt(BigInt value) {
-    writeString(value.toString());
-  }
-
-  void _writeConstant(ConstantValue value) {
-    _constantIndex.write(value, _writeConstantInternal);
-  }
-
-  void _writeConstantInternal(ConstantValue value) {
-    _writeEnumInternal(value.kind);
-    switch (value.kind) {
-      case ConstantValueKind.BOOL:
-        BoolConstantValue constant = value;
-        writeBool(constant.boolValue);
-        break;
-      case ConstantValueKind.INT:
-        IntConstantValue constant = value;
-        _writeBigInt(constant.intValue);
-        break;
-      case ConstantValueKind.DOUBLE:
-        DoubleConstantValue constant = value;
-        _writeDoubleValue(constant.doubleValue);
-        break;
-      case ConstantValueKind.STRING:
-        StringConstantValue constant = value;
-        writeString(constant.stringValue);
-        break;
-      case ConstantValueKind.NULL:
-        break;
-      case ConstantValueKind.FUNCTION:
-        FunctionConstantValue constant = value;
-        IndexedFunction function = constant.element;
-        writeMember(function);
-        writeDartType(constant.type);
-        break;
-      case ConstantValueKind.LIST:
-        ListConstantValue constant = value;
-        writeDartType(constant.type);
-        writeConstants(constant.entries);
-        break;
-      case ConstantValueKind.SET:
-        constant_system.JavaScriptSetConstant constant = value;
-        writeDartType(constant.type);
-        writeConstant(constant.entries);
-        break;
-      case ConstantValueKind.MAP:
-        constant_system.JavaScriptMapConstant constant = value;
-        writeDartType(constant.type);
-        writeConstant(constant.keyList);
-        writeConstants(constant.values);
-        writeBool(constant.onlyStringKeys);
-        break;
-      case ConstantValueKind.CONSTRUCTED:
-        ConstructedConstantValue constant = value;
-        writeDartType(constant.type);
-        writeMemberMap(constant.fields,
-            (MemberEntity member, ConstantValue value) => writeConstant(value));
-        break;
-      case ConstantValueKind.TYPE:
-        TypeConstantValue constant = value;
-        writeDartType(constant.representedType);
-        writeDartType(constant.type);
-        break;
-      case ConstantValueKind.INSTANTIATION:
-        InstantiationConstantValue constant = value;
-        writeDartTypes(constant.typeArguments);
-        writeConstant(constant.function);
-        break;
-      case ConstantValueKind.NON_CONSTANT:
-        break;
-      case ConstantValueKind.INTERCEPTOR:
-        InterceptorConstantValue constant = value;
-        writeClass(constant.cls);
-        break;
-      case ConstantValueKind.DEFERRED_GLOBAL:
-        DeferredGlobalConstantValue constant = value;
-        writeConstant(constant.referenced);
-        writeOutputUnitReference(constant.unit);
-        break;
-      case ConstantValueKind.DUMMY_INTERCEPTOR:
-        break;
-      case ConstantValueKind.LATE_SENTINEL:
-        break;
-      case ConstantValueKind.UNREACHABLE:
-        break;
-      case ConstantValueKind.JS_NAME:
-        JsNameConstantValue constant = value;
-        writeJsNode(constant.name);
-        break;
-    }
-  }
-
-  void _writeString(String value) {
-    _stringIndex.write(value, _writeStringInternal);
-  }
-
-  void _writeUri(Uri value) {
-    _uriIndex.write(value, _writeUriInternal);
-  }
-
-  @override
-  void writeImport(ImportEntity value) {
-    _writeDataKind(DataKind.import);
-    _writeImport(value);
-  }
-
-  void _writeImport(ImportEntity value) {
-    _importIndex.write(value, _writeImportInternal);
-  }
-
-  void _writeImportInternal(ImportEntity value) {
-    // TODO(johnniwinther): Do we need to serialize non-deferred imports?
-    writeStringOrNull(value.name);
-    _writeUri(value.uri);
-    _writeUri(value.enclosingLibraryUri);
-    _writeBool(value.isDeferred);
-  }
-
-  @override
-  void registerEntityWriter(EntityWriter writer) {
-    assert(writer != null);
-    _entityWriter = writer;
-  }
-
-  @override
-  void registerCodegenWriter(CodegenWriter writer) {
-    assert(writer != null);
-    assert(_codegenWriter == null);
-    _codegenWriter = writer;
-  }
-
-  @override
-  void writeOutputUnitReference(OutputUnit value) {
-    assert(
-        _codegenWriter != null,
-        "Can not serialize an OutputUnit reference "
-        "without a registered codegen writer.");
-    _codegenWriter.writeOutputUnitReference(this, value);
-  }
-
-  @override
-  void writeAbstractValue(AbstractValue value) {
-    assert(_codegenWriter != null,
-        "Can not serialize an AbstractValue without a registered codegen writer.");
-    _codegenWriter.writeAbstractValue(this, value);
-  }
-
-  @override
-  void writeJsNode(js.Node value) {
-    assert(_codegenWriter != null,
-        "Can not serialize a JS node without a registered codegen writer.");
-    _codegenWriter.writeJsNode(this, value);
-  }
-
-  @override
-  void writeTypeRecipe(TypeRecipe value) {
-    assert(_codegenWriter != null,
-        "Can not serialize a TypeRecipe without a registered codegen writer.");
-    _codegenWriter.writeTypeRecipe(this, value);
-  }
-
-  /// Actual serialization of a section begin tag, implemented by subclasses.
-  void _begin(String tag);
-
-  /// Actual serialization of a section end tag, implemented by subclasses.
-  void _end(String tag);
-
-  /// Actual serialization of a URI value, implemented by subclasses.
-  void _writeUriInternal(Uri value);
-
-  /// Actual serialization of a String value, implemented by subclasses.
-  void _writeStringInternal(String value);
-
-  /// Actual serialization of a non-negative integer value, implemented by
-  /// subclasses.
-  void _writeIntInternal(int value);
-
-  /// Actual serialization of an enum value, implemented by subclasses.
-  void _writeEnumInternal(dynamic value);
-}
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
deleted file mode 100644
index 5b45634..0000000
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ /dev/null
@@ -1,765 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of 'serialization.dart';
-
-/// Base implementation of [DataSource] using [DataSourceMixin] to implement
-/// convenience methods.
-abstract class AbstractDataSource extends DataSourceMixin
-    implements DataSource {
-  static final List<ir.DartType> emptyListOfDartTypes =
-      List<ir.DartType>.filled(0, null, growable: false);
-
-  final bool useDataKinds;
-  DataSourceIndices importedIndices;
-  EntityReader _entityReader = const EntityReader();
-  ComponentLookup _componentLookup;
-  EntityLookup _entityLookup;
-  LocalLookup _localLookup;
-  CodegenReader _codegenReader;
-
-  IndexedSource<String> _stringIndex;
-  IndexedSource<Uri> _uriIndex;
-  IndexedSource<_MemberData> _memberNodeIndex;
-  IndexedSource<ImportEntity> _importIndex;
-  IndexedSource<ConstantValue> _constantIndex;
-
-  final Map<Type, IndexedSource> _generalCaches = {};
-
-  ir.Member _currentMemberContext;
-  _MemberData _currentMemberData;
-
-  IndexedSource<T> _createSource<T>() {
-    if (importedIndices == null || !importedIndices.caches.containsKey(T)) {
-      return IndexedSource<T>(this);
-    } else {
-      List<T> cacheCopy = importedIndices.caches[T].cacheAsList.toList();
-      return IndexedSource<T>(this, cache: cacheCopy);
-    }
-  }
-
-  AbstractDataSource({this.useDataKinds = false, this.importedIndices}) {
-    _stringIndex = _createSource<String>();
-    _uriIndex = _createSource<Uri>();
-    _memberNodeIndex = _createSource<_MemberData>();
-    _importIndex = _createSource<ImportEntity>();
-    _constantIndex = _createSource<ConstantValue>();
-  }
-
-  @override
-  DataSourceIndices exportIndices() {
-    var indices = DataSourceIndices();
-    indices.caches[String] = DataSourceTypeIndices(_stringIndex.cache);
-    indices.caches[Uri] = DataSourceTypeIndices(_uriIndex.cache);
-    indices.caches[ImportEntity] = DataSourceTypeIndices(_importIndex.cache);
-    // _memberNodeIndex needs two entries depending on if the indices will be
-    // consumed by a [DataSource] or [DataSink].
-    indices.caches[_MemberData] = DataSourceTypeIndices(_memberNodeIndex.cache);
-    indices.caches[ir.Member] = DataSourceTypeIndices<ir.Member, _MemberData>(
-        _memberNodeIndex.cache, (_MemberData data) => data?.node);
-    indices.caches[ConstantValue] = DataSourceTypeIndices(_constantIndex.cache);
-    _generalCaches.forEach((type, indexedSource) {
-      indices.caches[type] = DataSourceTypeIndices(indexedSource.cache);
-    });
-    return indices;
-  }
-
-  @override
-  void begin(String tag) {
-    if (useDataKinds) _begin(tag);
-  }
-
-  @override
-  void end(String tag) {
-    if (useDataKinds) _end(tag);
-  }
-
-  @override
-  void registerComponentLookup(ComponentLookup componentLookup) {
-    assert(_componentLookup == null);
-    _componentLookup = componentLookup;
-  }
-
-  ComponentLookup get componentLookup {
-    assert(_componentLookup != null);
-    return _componentLookup;
-  }
-
-  @override
-  void registerEntityLookup(EntityLookup entityLookup) {
-    assert(_entityLookup == null);
-    _entityLookup = entityLookup;
-  }
-
-  EntityLookup get entityLookup {
-    assert(_entityLookup != null);
-    return _entityLookup;
-  }
-
-  @override
-  void registerLocalLookup(LocalLookup localLookup) {
-    assert(_localLookup == null);
-    _localLookup = localLookup;
-  }
-
-  @override
-  void registerEntityReader(EntityReader reader) {
-    assert(reader != null);
-    _entityReader = reader;
-  }
-
-  LocalLookup get localLookup {
-    assert(_localLookup != null);
-    return _localLookup;
-  }
-
-  @override
-  void registerCodegenReader(CodegenReader reader) {
-    assert(reader != null);
-    assert(_codegenReader == null);
-    _codegenReader = reader;
-  }
-
-  @override
-  void deregisterCodegenReader(CodegenReader reader) {
-    assert(_codegenReader == reader);
-    _codegenReader = null;
-  }
-
-  @override
-  T inMemberContext<T>(ir.Member context, T f()) {
-    ir.Member oldMemberContext = _currentMemberContext;
-    _MemberData oldMemberData = _currentMemberData;
-    _currentMemberContext = context;
-    _currentMemberData = null;
-    T result = f();
-    _currentMemberData = oldMemberData;
-    _currentMemberContext = oldMemberContext;
-    return result;
-  }
-
-  _MemberData get currentMemberData {
-    assert(_currentMemberContext != null,
-        "DataSink has no current member context.");
-    return _currentMemberData ??= _getMemberData(_currentMemberContext);
-  }
-
-  @override
-  E readCached<E>(E f()) {
-    IndexedSource source = _generalCaches[E] ??= _createSource<E>();
-    return source.read(f);
-  }
-
-  @override
-  IndexedLibrary readLibrary() {
-    return _entityReader.readLibraryFromDataSource(this, entityLookup);
-  }
-
-  @override
-  IndexedClass readClass() {
-    return _entityReader.readClassFromDataSource(this, entityLookup);
-  }
-
-  @override
-  IndexedMember readMember() {
-    return _entityReader.readMemberFromDataSource(this, entityLookup);
-  }
-
-  @override
-  IndexedTypeVariable readTypeVariable() {
-    return _entityReader.readTypeVariableFromDataSource(this, entityLookup);
-  }
-
-  List<ir.DartType> _readDartTypeNodes(
-      List<ir.TypeParameter> functionTypeVariables) {
-    int count = readInt();
-    if (count == 0) return emptyListOfDartTypes;
-    List<ir.DartType> types = List<ir.DartType>.filled(count, null);
-    for (int index = 0; index < count; index++) {
-      types[index] = _readDartTypeNode(functionTypeVariables);
-    }
-    return types;
-  }
-
-  @override
-  SourceSpan readSourceSpan() {
-    _checkDataKind(DataKind.sourceSpan);
-    Uri uri = _readUri();
-    int begin = _readIntInternal();
-    int end = _readIntInternal();
-    return SourceSpan(uri, begin, end);
-  }
-
-  @override
-  DartType readDartType({bool allowNull = false}) {
-    _checkDataKind(DataKind.dartType);
-    DartType type = DartType.readFromDataSource(this, []);
-    assert(type != null || allowNull);
-    return type;
-  }
-
-  @override
-  ir.DartType readDartTypeNode({bool allowNull = false}) {
-    _checkDataKind(DataKind.dartTypeNode);
-    ir.DartType type = _readDartTypeNode([]);
-    assert(type != null || allowNull);
-    return type;
-  }
-
-  ir.DartType _readDartTypeNode(List<ir.TypeParameter> functionTypeVariables) {
-    DartTypeNodeKind kind = readEnum(DartTypeNodeKind.values);
-    switch (kind) {
-      case DartTypeNodeKind.none:
-        return null;
-      case DartTypeNodeKind.voidType:
-        return const ir.VoidType();
-      case DartTypeNodeKind.invalidType:
-        return const ir.InvalidType();
-      case DartTypeNodeKind.doesNotComplete:
-        return const DoesNotCompleteType();
-      case DartTypeNodeKind.neverType:
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        return ir.NeverType.fromNullability(nullability);
-      case DartTypeNodeKind.typeParameterType:
-        ir.TypeParameter typeParameter = readTypeParameterNode();
-        ir.Nullability typeParameterTypeNullability =
-            readEnum(ir.Nullability.values);
-        ir.DartType promotedBound = _readDartTypeNode(functionTypeVariables);
-        return ir.TypeParameterType(
-            typeParameter, typeParameterTypeNullability, promotedBound);
-      case DartTypeNodeKind.functionTypeVariable:
-        int index = readInt();
-        assert(0 <= index && index < functionTypeVariables.length);
-        ir.Nullability typeParameterTypeNullability =
-            readEnum(ir.Nullability.values);
-        ir.DartType promotedBound = _readDartTypeNode(functionTypeVariables);
-        return ir.TypeParameterType(functionTypeVariables[index],
-            typeParameterTypeNullability, promotedBound);
-      case DartTypeNodeKind.functionType:
-        begin(functionTypeNodeTag);
-        int typeParameterCount = readInt();
-        List<ir.TypeParameter> typeParameters = List<ir.TypeParameter>.generate(
-            typeParameterCount, (int index) => ir.TypeParameter());
-        functionTypeVariables =
-            List<ir.TypeParameter>.from(functionTypeVariables)
-              ..addAll(typeParameters);
-        for (int index = 0; index < typeParameterCount; index++) {
-          typeParameters[index].name = readString();
-          typeParameters[index].bound =
-              _readDartTypeNode(functionTypeVariables);
-          typeParameters[index].defaultType =
-              _readDartTypeNode(functionTypeVariables);
-        }
-        ir.DartType returnType = _readDartTypeNode(functionTypeVariables);
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        int requiredParameterCount = readInt();
-        List<ir.DartType> positionalParameters =
-            _readDartTypeNodes(functionTypeVariables);
-        int namedParameterCount = readInt();
-        List<ir.NamedType> namedParameters =
-            List<ir.NamedType>.filled(namedParameterCount, null);
-        for (int index = 0; index < namedParameterCount; index++) {
-          String name = readString();
-          bool isRequired = readBool();
-          ir.DartType type = _readDartTypeNode(functionTypeVariables);
-          namedParameters[index] =
-              ir.NamedType(name, type, isRequired: isRequired);
-        }
-        ir.TypedefType typedefType = _readDartTypeNode(functionTypeVariables);
-        end(functionTypeNodeTag);
-        return ir.FunctionType(positionalParameters, returnType, nullability,
-            namedParameters: namedParameters,
-            typeParameters: typeParameters,
-            requiredParameterCount: requiredParameterCount,
-            typedefType: typedefType);
-
-      case DartTypeNodeKind.interfaceType:
-        ir.Class cls = readClassNode();
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        List<ir.DartType> typeArguments =
-            _readDartTypeNodes(functionTypeVariables);
-        return ir.InterfaceType(cls, nullability, typeArguments);
-      case DartTypeNodeKind.thisInterfaceType:
-        ir.Class cls = readClassNode();
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        List<ir.DartType> typeArguments =
-            _readDartTypeNodes(functionTypeVariables);
-        return ThisInterfaceType(cls, nullability, typeArguments);
-      case DartTypeNodeKind.exactInterfaceType:
-        ir.Class cls = readClassNode();
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        List<ir.DartType> typeArguments =
-            _readDartTypeNodes(functionTypeVariables);
-        return ExactInterfaceType(cls, nullability, typeArguments);
-      case DartTypeNodeKind.typedef:
-        ir.Typedef typedef = readTypedefNode();
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        List<ir.DartType> typeArguments =
-            _readDartTypeNodes(functionTypeVariables);
-        return ir.TypedefType(typedef, nullability, typeArguments);
-      case DartTypeNodeKind.dynamicType:
-        return const ir.DynamicType();
-      case DartTypeNodeKind.futureOrType:
-        ir.Nullability nullability = readEnum(ir.Nullability.values);
-        ir.DartType typeArgument = _readDartTypeNode(functionTypeVariables);
-        return ir.FutureOrType(typeArgument, nullability);
-      case DartTypeNodeKind.nullType:
-        return const ir.NullType();
-    }
-    throw UnsupportedError("Unexpected DartTypeKind $kind");
-  }
-
-  _MemberData _readMemberData() {
-    return _memberNodeIndex.read(_readMemberDataInternal);
-  }
-
-  _MemberData _readMemberDataInternal() {
-    MemberContextKind kind = _readEnumInternal(MemberContextKind.values);
-    switch (kind) {
-      case MemberContextKind.cls:
-        _ClassData cls = _readClassData();
-        String name = _readString();
-        return cls.lookupMemberDataByName(name);
-      case MemberContextKind.library:
-        _LibraryData library = _readLibraryData();
-        String name = _readString();
-        return library.lookupMemberDataByName(name);
-    }
-    throw UnsupportedError("Unsupported _MemberKind $kind");
-  }
-
-  @override
-  ir.Member readMemberNode() {
-    _checkDataKind(DataKind.memberNode);
-    return _readMemberData().node;
-  }
-
-  _ClassData _readClassData() {
-    _LibraryData library = _readLibraryData();
-    String name = _readString();
-    return library.lookupClassByName(name);
-  }
-
-  @override
-  ir.Class readClassNode() {
-    _checkDataKind(DataKind.classNode);
-    return _readClassData().node;
-  }
-
-  ir.Typedef _readTypedefNode() {
-    _LibraryData library = _readLibraryData();
-    String name = _readString();
-    return library.lookupTypedef(name);
-  }
-
-  @override
-  ir.Typedef readTypedefNode() {
-    _checkDataKind(DataKind.typedefNode);
-    return _readTypedefNode();
-  }
-
-  _LibraryData _readLibraryData() {
-    Uri canonicalUri = _readUri();
-    return componentLookup.getLibraryDataByUri(canonicalUri);
-  }
-
-  @override
-  ir.Library readLibraryNode() {
-    _checkDataKind(DataKind.libraryNode);
-    return _readLibraryData().node;
-  }
-
-  @override
-  E readEnum<E>(List<E> values) {
-    _checkDataKind(DataKind.enumValue);
-    return _readEnumInternal(values);
-  }
-
-  @override
-  Uri readUri() {
-    _checkDataKind(DataKind.uri);
-    return _readUri();
-  }
-
-  Uri _readUri() {
-    return _uriIndex.read(_readUriInternal);
-  }
-
-  @override
-  bool readBool() {
-    _checkDataKind(DataKind.bool);
-    return _readBool();
-  }
-
-  bool _readBool() {
-    int value = _readIntInternal();
-    assert(value == 0 || value == 1);
-    return value == 1;
-  }
-
-  @override
-  String readString() {
-    _checkDataKind(DataKind.string);
-    return _readString();
-  }
-
-  String _readString() {
-    return _stringIndex.read(_readStringInternal);
-  }
-
-  @override
-  int readInt() {
-    _checkDataKind(DataKind.uint30);
-    return _readIntInternal();
-  }
-
-  @override
-  ir.TreeNode readTreeNode() {
-    _checkDataKind(DataKind.treeNode);
-    return _readTreeNode(null);
-  }
-
-  _MemberData _getMemberData(ir.Member node) {
-    _LibraryData libraryData =
-        componentLookup.getLibraryDataByUri(node.enclosingLibrary.importUri);
-    if (node.enclosingClass != null) {
-      _ClassData classData = libraryData.lookupClassByNode(node.enclosingClass);
-      return classData.lookupMemberDataByNode(node);
-    } else {
-      return libraryData.lookupMemberDataByNode(node);
-    }
-  }
-
-  @override
-  ir.TreeNode readTreeNodeInContext() {
-    return readTreeNodeInContextInternal(currentMemberData);
-  }
-
-  ir.TreeNode readTreeNodeInContextInternal(_MemberData memberData) {
-    _checkDataKind(DataKind.treeNode);
-    return _readTreeNode(memberData);
-  }
-
-  @override
-  ir.TreeNode readTreeNodeOrNullInContext() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readTreeNodeInContextInternal(currentMemberData);
-    }
-    return null;
-  }
-
-  @override
-  List<E> readTreeNodesInContext<E extends ir.TreeNode>(
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      ir.TreeNode node = readTreeNodeInContextInternal(currentMemberData);
-      list[i] = node;
-    }
-    return list;
-  }
-
-  @override
-  Map<K, V> readTreeNodeMapInContext<K extends ir.TreeNode, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      ir.TreeNode node = readTreeNodeInContextInternal(currentMemberData);
-      V value = f();
-      map[node] = value;
-    }
-    return map;
-  }
-
-  @override
-  ConstantValue readConstant() {
-    _checkDataKind(DataKind.constant);
-    return _readConstant();
-  }
-
-  @override
-  double readDoubleValue() {
-    _checkDataKind(DataKind.double);
-    return _readDoubleValue();
-  }
-
-  double _readDoubleValue() {
-    ByteData data = ByteData(8);
-    data.setUint16(0, readInt());
-    data.setUint16(2, readInt());
-    data.setUint16(4, readInt());
-    data.setUint16(6, readInt());
-    return data.getFloat64(0);
-  }
-
-  @override
-  int readIntegerValue() {
-    _checkDataKind(DataKind.int);
-    return _readBigInt().toInt();
-  }
-
-  BigInt _readBigInt() {
-    return BigInt.parse(readString());
-  }
-
-  ConstantValue _readConstant() {
-    return _constantIndex.read(_readConstantInternal);
-  }
-
-  ConstantValue _readConstantInternal() {
-    ConstantValueKind kind = _readEnumInternal(ConstantValueKind.values);
-    switch (kind) {
-      case ConstantValueKind.BOOL:
-        bool value = readBool();
-        return BoolConstantValue(value);
-      case ConstantValueKind.INT:
-        BigInt value = _readBigInt();
-        return IntConstantValue(value);
-      case ConstantValueKind.DOUBLE:
-        double value = _readDoubleValue();
-        return DoubleConstantValue(value);
-      case ConstantValueKind.STRING:
-        String value = readString();
-        return StringConstantValue(value);
-      case ConstantValueKind.NULL:
-        return const NullConstantValue();
-      case ConstantValueKind.FUNCTION:
-        IndexedFunction function = readMember();
-        DartType type = readDartType();
-        return FunctionConstantValue(function, type);
-      case ConstantValueKind.LIST:
-        DartType type = readDartType();
-        List<ConstantValue> entries = readConstants();
-        return ListConstantValue(type, entries);
-      case ConstantValueKind.SET:
-        DartType type = readDartType();
-        MapConstantValue entries = readConstant();
-        return constant_system.JavaScriptSetConstant(type, entries);
-      case ConstantValueKind.MAP:
-        DartType type = readDartType();
-        ListConstantValue keyList = readConstant();
-        List<ConstantValue> values = readConstants();
-        bool onlyStringKeys = readBool();
-        return constant_system.JavaScriptMapConstant(
-            type, keyList, values, onlyStringKeys);
-      case ConstantValueKind.CONSTRUCTED:
-        InterfaceType type = readDartType();
-        Map<FieldEntity, ConstantValue> fields =
-            readMemberMap<FieldEntity, ConstantValue>(
-                (MemberEntity member) => readConstant());
-        return ConstructedConstantValue(type, fields);
-      case ConstantValueKind.TYPE:
-        DartType representedType = readDartType();
-        DartType type = readDartType();
-        return TypeConstantValue(representedType, type);
-      case ConstantValueKind.INSTANTIATION:
-        List<DartType> typeArguments = readDartTypes();
-        ConstantValue function = readConstant();
-        return InstantiationConstantValue(typeArguments, function);
-      case ConstantValueKind.NON_CONSTANT:
-        return NonConstantValue();
-      case ConstantValueKind.INTERCEPTOR:
-        ClassEntity cls = readClass();
-        return InterceptorConstantValue(cls);
-      case ConstantValueKind.DEFERRED_GLOBAL:
-        ConstantValue constant = readConstant();
-        OutputUnit unit = readOutputUnitReference();
-        return DeferredGlobalConstantValue(constant, unit);
-      case ConstantValueKind.DUMMY_INTERCEPTOR:
-        return DummyInterceptorConstantValue();
-      case ConstantValueKind.LATE_SENTINEL:
-        return LateSentinelConstantValue();
-      case ConstantValueKind.UNREACHABLE:
-        return UnreachableConstantValue();
-      case ConstantValueKind.JS_NAME:
-        js.LiteralString name = readJsNode();
-        return JsNameConstantValue(name);
-    }
-    throw UnsupportedError("Unexpexted constant value kind ${kind}.");
-  }
-
-  ir.TreeNode _readTreeNode(_MemberData memberData) {
-    _TreeNodeKind kind = _readEnumInternal(_TreeNodeKind.values);
-    switch (kind) {
-      case _TreeNodeKind.cls:
-        return _readClassData().node;
-      case _TreeNodeKind.member:
-        return _readMemberData().node;
-      case _TreeNodeKind.functionDeclarationVariable:
-        ir.FunctionDeclaration functionDeclaration = _readTreeNode(memberData);
-        return functionDeclaration.variable;
-      case _TreeNodeKind.functionNode:
-        return _readFunctionNode(memberData);
-      case _TreeNodeKind.typeParameter:
-        return _readTypeParameter(memberData);
-      case _TreeNodeKind.constant:
-        memberData ??= _readMemberData();
-        ir.ConstantExpression expression = _readTreeNode(memberData);
-        ir.Constant constant =
-            memberData.getConstantByIndex(expression, _readIntInternal());
-        return ConstantReference(expression, constant);
-      case _TreeNodeKind.node:
-        memberData ??= _readMemberData();
-        int index = _readIntInternal();
-        ir.TreeNode treeNode = memberData.getTreeNodeByIndex(index);
-        assert(
-            treeNode != null,
-            "No TreeNode found for index $index in "
-            "${memberData.node}.$_errorContext");
-        return treeNode;
-    }
-    throw UnsupportedError("Unexpected _TreeNodeKind $kind");
-  }
-
-  ir.FunctionNode _readFunctionNode(_MemberData memberData) {
-    _FunctionNodeKind kind = _readEnumInternal(_FunctionNodeKind.values);
-    switch (kind) {
-      case _FunctionNodeKind.procedure:
-        ir.Procedure procedure = _readMemberData().node;
-        return procedure.function;
-      case _FunctionNodeKind.constructor:
-        ir.Constructor constructor = _readMemberData().node;
-        return constructor.function;
-      case _FunctionNodeKind.functionExpression:
-        ir.FunctionExpression functionExpression = _readTreeNode(memberData);
-        return functionExpression.function;
-      case _FunctionNodeKind.functionDeclaration:
-        ir.FunctionDeclaration functionDeclaration = _readTreeNode(memberData);
-        return functionDeclaration.function;
-    }
-    throw UnsupportedError("Unexpected _FunctionNodeKind $kind");
-  }
-
-  @override
-  ir.TypeParameter readTypeParameterNode() {
-    _checkDataKind(DataKind.typeParameterNode);
-    return _readTypeParameter(null);
-  }
-
-  ir.TypeParameter _readTypeParameter(_MemberData memberData) {
-    _TypeParameterKind kind = _readEnumInternal(_TypeParameterKind.values);
-    switch (kind) {
-      case _TypeParameterKind.cls:
-        ir.Class cls = _readClassData().node;
-        return cls.typeParameters[_readIntInternal()];
-      case _TypeParameterKind.functionNode:
-        ir.FunctionNode functionNode = _readFunctionNode(memberData);
-        return functionNode.typeParameters[_readIntInternal()];
-    }
-    throw UnsupportedError("Unexpected _TypeParameterKind kind $kind");
-  }
-
-  void _checkDataKind(DataKind expectedKind) {
-    if (!useDataKinds) return;
-    DataKind actualKind = _readEnumInternal(DataKind.values);
-    assert(
-        actualKind == expectedKind,
-        "Invalid data kind. "
-        "Expected $expectedKind, found $actualKind.$_errorContext");
-  }
-
-  @override
-  Local readLocal() {
-    LocalKind kind = readEnum(LocalKind.values);
-    switch (kind) {
-      case LocalKind.jLocal:
-        MemberEntity memberContext = readMember();
-        int localIndex = readInt();
-        return localLookup.getLocalByIndex(memberContext, localIndex);
-      case LocalKind.thisLocal:
-        ClassEntity cls = readClass();
-        return ThisLocal(cls);
-      case LocalKind.boxLocal:
-        ClassEntity cls = readClass();
-        return BoxLocal(cls);
-      case LocalKind.anonymousClosureLocal:
-        ClassEntity cls = readClass();
-        return AnonymousClosureLocal(cls);
-      case LocalKind.typeVariableLocal:
-        TypeVariableEntity typeVariable = readTypeVariable();
-        return TypeVariableLocal(typeVariable);
-    }
-    throw UnsupportedError("Unexpected local kind $kind");
-  }
-
-  @override
-  ImportEntity readImport() {
-    _checkDataKind(DataKind.import);
-    return _readImport();
-  }
-
-  ImportEntity _readImport() {
-    return _importIndex.read(_readImportInternal);
-  }
-
-  ImportEntity _readImportInternal() {
-    String name = readStringOrNull();
-    Uri uri = _readUri();
-    Uri enclosingLibraryUri = _readUri();
-    bool isDeferred = _readBool();
-    return ImportEntity(isDeferred, name, uri, enclosingLibraryUri);
-  }
-
-  @override
-  OutputUnit readOutputUnitReference() {
-    assert(
-        _codegenReader != null,
-        "Can not deserialize an OutputUnit reference "
-        "without a registered codegen reader.");
-    return _codegenReader.readOutputUnitReference(this);
-  }
-
-  @override
-  AbstractValue readAbstractValue() {
-    assert(
-        _codegenReader != null,
-        "Can not deserialize an AbstractValue "
-        "without a registered codegen reader.");
-    return _codegenReader.readAbstractValue(this);
-  }
-
-  @override
-  js.Node readJsNode() {
-    assert(_codegenReader != null,
-        "Can not deserialize a JS node without a registered codegen reader.");
-    return _codegenReader.readJsNode(this);
-  }
-
-  @override
-  TypeRecipe readTypeRecipe() {
-    assert(_codegenReader != null,
-        "Can not deserialize a TypeRecipe without a registered codegen reader.");
-    return _codegenReader.readTypeRecipe(this);
-  }
-
-  /// Actual deserialization of a section begin tag, implemented by subclasses.
-  void _begin(String tag);
-
-  /// Actual deserialization of a section end tag, implemented by subclasses.
-  void _end(String tag);
-
-  /// Actual deserialization of a string value, implemented by subclasses.
-  String _readStringInternal();
-
-  /// Actual deserialization of a non-negative integer value, implemented by
-  /// subclasses.
-  int _readIntInternal();
-
-  /// Actual deserialization of a URI value, implemented by subclasses.
-  Uri _readUriInternal();
-
-  /// Actual deserialization of an enum value in [values], implemented by
-  /// subclasses.
-  E _readEnumInternal<E>(List<E> values);
-
-  /// Returns a string representation of the current state of the data source
-  /// useful for debugging in consistencies between serialization and
-  /// deserialization.
-  String get _errorContext;
-}
diff --git a/pkg/compiler/lib/src/serialization/binary_sink.dart b/pkg/compiler/lib/src/serialization/binary_sink.dart
index 92a4d43..7817a31 100644
--- a/pkg/compiler/lib/src/serialization/binary_sink.dart
+++ b/pkg/compiler/lib/src/serialization/binary_sink.dart
@@ -6,46 +6,37 @@
 
 /// [DataSink] that writes data as a sequence of bytes.
 ///
-/// This data sink works together with [BinarySource].
-class BinarySink extends AbstractDataSink {
+/// This data sink works together with [BinarySourceWriter].
+class BinaryDataSink implements DataSink {
   final Sink<List<int>> sink;
   BufferedSink _bufferedSink;
   int _length = 0;
 
-  BinarySink(this.sink,
-      {bool useDataKinds = false,
-      Map<String, int> tagFrequencyMap,
-      DataSourceIndices importedIndices})
-      : _bufferedSink = BufferedSink(sink),
-        super(
-            useDataKinds: useDataKinds,
-            tagFrequencyMap: tagFrequencyMap,
-            importedIndices: importedIndices);
+  BinaryDataSink(this.sink) : _bufferedSink = BufferedSink(sink);
 
   @override
-  void _begin(String tag) {
-    // TODO(johnniwinther): Support tags in binary serialization?
-  }
+  int get length => _length;
+
   @override
-  void _end(String tag) {
+  void beginTag(String tag) {
     // TODO(johnniwinther): Support tags in binary serialization?
   }
 
   @override
-  void _writeUriInternal(Uri value) {
-    _writeString(value.toString());
+  void endTag(String tag) {
+    // TODO(johnniwinther): Support tags in binary serialization?
   }
 
   @override
-  void _writeStringInternal(String value) {
+  void writeString(String value) {
     List<int> bytes = utf8.encode(value);
-    _writeIntInternal(bytes.length);
+    writeInt(bytes.length);
     _bufferedSink.addBytes(bytes);
     _length += bytes.length;
   }
 
   @override
-  void _writeIntInternal(int value) {
+  void writeInt(int value) {
     assert(value >= 0 && value >> 30 == 0);
     if (value < 0x80) {
       _bufferedSink.addByte(value);
@@ -61,8 +52,8 @@
   }
 
   @override
-  void _writeEnumInternal(dynamic value) {
-    _writeIntInternal(value.index);
+  void writeEnum(dynamic value) {
+    writeInt(value.index);
   }
 
   @override
@@ -71,8 +62,4 @@
     _bufferedSink = null;
     sink.close();
   }
-
-  /// Returns the number of bytes written to this data sink.
-  @override
-  int get length => _length;
 }
diff --git a/pkg/compiler/lib/src/serialization/binary_source.dart b/pkg/compiler/lib/src/serialization/binary_source.dart
index 3844b35..149f362 100644
--- a/pkg/compiler/lib/src/serialization/binary_source.dart
+++ b/pkg/compiler/lib/src/serialization/binary_source.dart
@@ -6,29 +6,26 @@
 
 /// [DataSource] that reads data from a sequence of bytes.
 ///
-/// This data source works together with [BinarySink].
-class BinarySourceImpl extends AbstractDataSource {
+/// This data source works together with [BinaryDataSink].
+class BinaryDataSource implements DataSource {
   int _byteOffset = 0;
   final List<int> _bytes;
   final StringInterner _stringInterner;
 
-  BinarySourceImpl(this._bytes,
-      {bool useDataKinds = false,
-      StringInterner stringInterner,
-      DataSourceIndices importedIndices})
-      : _stringInterner = stringInterner,
-        super(useDataKinds: useDataKinds, importedIndices: importedIndices);
+  BinaryDataSource(this._bytes, {StringInterner stringInterner})
+      : _stringInterner = stringInterner;
 
   @override
-  void _begin(String tag) {}
+  void begin(String tag) {}
+
   @override
-  void _end(String tag) {}
+  void end(String tag) {}
 
   int _readByte() => _bytes[_byteOffset++];
 
   @override
-  String _readStringInternal() {
-    int length = _readIntInternal();
+  String readString() {
+    int length = readInt();
     List<int> bytes = Uint8List(length);
     bytes.setRange(0, bytes.length, _bytes, _byteOffset);
     _byteOffset += bytes.length;
@@ -38,7 +35,7 @@
   }
 
   @override
-  int _readIntInternal() {
+  int readInt() {
     var byte = _readByte();
     if (byte & 0x80 == 0) {
       // 0xxxxxxx
@@ -56,14 +53,8 @@
   }
 
   @override
-  Uri _readUriInternal() {
-    String text = _readString();
-    return Uri.parse(text);
-  }
-
-  @override
-  E _readEnumInternal<E>(List<E> values) {
-    int index = _readIntInternal();
+  E readEnum<E>(List<E> values) {
+    int index = readInt();
     assert(
         0 <= index && index < values.length,
         "Invalid data kind index. "
@@ -72,5 +63,5 @@
   }
 
   @override
-  String get _errorContext => ' Offset $_byteOffset in ${_bytes.length}.';
+  String get errorContext => ' Offset $_byteOffset in ${_bytes.length}.';
 }
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index a0bd6d7..81b2e20 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -66,7 +66,7 @@
   functionNode,
 }
 
-/// Class used for encoding tags in [ObjectSink] and [ObjectSource].
+/// Class used for encoding tags in [ObjectDataSink] and [ObjectDataSource].
 class Tag {
   final String value;
 
@@ -126,7 +126,7 @@
 
 class DartTypeNodeWriter
     extends ir.DartTypeVisitor1<void, List<ir.TypeParameter>> {
-  final AbstractDataSink _sink;
+  final DataSinkWriter _sink;
 
   DartTypeNodeWriter(this._sink);
 
@@ -262,7 +262,7 @@
 
 /// Data sink helper that canonicalizes [E] values using indices.
 class IndexedSink<E> {
-  final AbstractDataSink _sink;
+  final DataSink _sink;
   Map<E, int> cache;
 
   IndexedSink(this._sink, {this.cache}) {
@@ -279,24 +279,24 @@
     int index = cache[value];
     if (index == null) {
       index = cache.length;
-      _sink._writeIntInternal(index);
+      _sink.writeInt(index);
       cache[value] = pending; // Increments length to allocate slot.
       writeValue(value);
       cache[value] = index;
     } else if (index == pending) {
       throw ArgumentError("Cyclic dependency on cached value: $value");
     } else {
-      _sink._writeIntInternal(index);
+      _sink.writeInt(index);
     }
   }
 }
 
 /// Data source helper reads canonicalized [E] values through indices.
 class IndexedSource<E> {
-  final AbstractDataSource _source;
+  final DataSource _sourceReader;
   List<E> cache;
 
-  IndexedSource(this._source, {this.cache}) {
+  IndexedSource(this._sourceReader, {this.cache}) {
     // [cache] slot 0 is pre-allocated to `null`.
     this.cache ??= [null];
   }
@@ -306,7 +306,7 @@
   /// If the value hasn't yet been read, [readValue] is called to deserialize
   /// the value itself.
   E read(E readValue()) {
-    int index = _source._readIntInternal();
+    int index = _sourceReader.readInt();
     if (index >= cache.length) {
       assert(index == cache.length);
       cache.add(null); // placeholder.
diff --git a/pkg/compiler/lib/src/serialization/mixins.dart b/pkg/compiler/lib/src/serialization/mixins.dart
deleted file mode 100644
index 8e2bfa3..0000000
--- a/pkg/compiler/lib/src/serialization/mixins.dart
+++ /dev/null
@@ -1,820 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of 'serialization.dart';
-
-/// Mixin that implements all convenience methods of [DataSource].
-abstract class DataSourceMixin implements DataSource {
-  @override
-  E readValueOrNull<E>(E f()) {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return f();
-    }
-    return null;
-  }
-
-  @override
-  List<E> readList<E>(E f(), {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      list[i] = f();
-    }
-    return list;
-  }
-
-  @override
-  int readIntOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readInt();
-    }
-    return null;
-  }
-
-  @override
-  String readStringOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readString();
-    }
-    return null;
-  }
-
-  @override
-  List<String> readStrings({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<String> list = List<String>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      list[i] = readString();
-    }
-    return list;
-  }
-
-  @override
-  List<DartType> readDartTypes({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<DartType> list = List<DartType>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      list[i] = readDartType();
-    }
-    return list;
-  }
-
-  @override
-  List<ir.TypeParameter> readTypeParameterNodes({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<ir.TypeParameter> list = List<ir.TypeParameter>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      list[i] = readTypeParameterNode();
-    }
-    return list;
-  }
-
-  @override
-  List<E> readMembers<E extends MemberEntity>({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      MemberEntity member = readMember();
-      list[i] = member;
-    }
-    return list;
-  }
-
-  @override
-  List<E> readMemberNodes<E extends ir.Member>({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      ir.Member value = readMemberNode();
-      list[i] = value;
-    }
-    return list;
-  }
-
-  @override
-  List<E> readClasses<E extends ClassEntity>({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      ClassEntity cls = readClass();
-      list[i] = cls;
-    }
-    return list;
-  }
-
-  @override
-  Map<K, V> readLibraryMap<K extends LibraryEntity, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      LibraryEntity library = readLibrary();
-      V value = f();
-      map[library] = value;
-    }
-    return map;
-  }
-
-  @override
-  Map<K, V> readClassMap<K extends ClassEntity, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      ClassEntity cls = readClass();
-      V value = f();
-      map[cls] = value;
-    }
-    return map;
-  }
-
-  @override
-  Map<K, V> readMemberMap<K extends MemberEntity, V>(V f(MemberEntity member),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      MemberEntity member = readMember();
-      V value = f(member);
-      map[member] = value;
-    }
-    return map;
-  }
-
-  @override
-  Map<K, V> readMemberNodeMap<K extends ir.Member, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      ir.Member node = readMemberNode();
-      V value = f();
-      map[node] = value;
-    }
-    return map;
-  }
-
-  @override
-  Map<K, V> readTreeNodeMap<K extends ir.TreeNode, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      ir.TreeNode node = readTreeNode();
-      V value = f();
-      map[node] = value;
-    }
-    return map;
-  }
-
-  @override
-  Map<K, V> readTypeVariableMap<K extends IndexedTypeVariable, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      IndexedTypeVariable node = readTypeVariable();
-      V value = f();
-      map[node] = value;
-    }
-    return map;
-  }
-
-  @override
-  List<E> readLocals<E extends Local>({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      Local local = readLocal();
-      list[i] = local;
-    }
-    return list;
-  }
-
-  @override
-  Map<K, V> readLocalMap<K extends Local, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      Local local = readLocal();
-      V value = f();
-      map[local] = value;
-    }
-    return map;
-  }
-
-  @override
-  List<E> readTreeNodes<E extends ir.TreeNode>({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      ir.TreeNode node = readTreeNode();
-      list[i] = node;
-    }
-    return list;
-  }
-
-  @override
-  Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<String, V> map = {};
-    for (int i = 0; i < count; i++) {
-      String key = readString();
-      V value = f();
-      map[key] = value;
-    }
-    return map;
-  }
-
-  @override
-  IndexedClass readClassOrNull() {
-    bool hasClass = readBool();
-    if (hasClass) {
-      return readClass();
-    }
-    return null;
-  }
-
-  @override
-  ir.TreeNode readTreeNodeOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readTreeNode();
-    }
-    return null;
-  }
-
-  @override
-  IndexedMember readMemberOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readMember();
-    }
-    return null;
-  }
-
-  @override
-  Local readLocalOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readLocal();
-    }
-    return null;
-  }
-
-  @override
-  ConstantValue readConstantOrNull() {
-    bool hasClass = readBool();
-    if (hasClass) {
-      return readConstant();
-    }
-    return null;
-  }
-
-  @override
-  List<E> readConstants<E extends ConstantValue>({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      ConstantValue value = readConstant();
-      list[i] = value;
-    }
-    return list;
-  }
-
-  @override
-  Map<K, V> readConstantMap<K extends ConstantValue, V>(V f(),
-      {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<K, V> map = {};
-    for (int i = 0; i < count; i++) {
-      ConstantValue key = readConstant();
-      V value = f();
-      map[key] = value;
-    }
-    return map;
-  }
-
-  @override
-  IndexedLibrary readLibraryOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readLibrary();
-    }
-    return null;
-  }
-
-  @override
-  ImportEntity readImportOrNull() {
-    bool hasClass = readBool();
-    if (hasClass) {
-      return readImport();
-    }
-    return null;
-  }
-
-  @override
-  List<ImportEntity> readImports({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<ImportEntity> list = List<ImportEntity>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      list[i] = readImport();
-    }
-    return list;
-  }
-
-  @override
-  Map<ImportEntity, V> readImportMap<V>(V f(), {bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    Map<ImportEntity, V> map = {};
-    for (int i = 0; i < count; i++) {
-      ImportEntity key = readImport();
-      V value = f();
-      map[key] = value;
-    }
-    return map;
-  }
-
-  @override
-  List<ir.DartType> readDartTypeNodes({bool emptyAsNull = false}) {
-    int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<ir.DartType> list = List<ir.DartType>.filled(count, null);
-    for (int i = 0; i < count; i++) {
-      list[i] = readDartTypeNode();
-    }
-    return list;
-  }
-
-  @override
-  ir.Name readName() {
-    String text = readString();
-    ir.Library library = readValueOrNull(readLibraryNode);
-    return ir.Name(text, library);
-  }
-
-  @override
-  ir.LibraryDependency readLibraryDependencyNode() {
-    ir.Library library = readLibraryNode();
-    int index = readInt();
-    return library.dependencies[index];
-  }
-
-  @override
-  ir.LibraryDependency readLibraryDependencyNodeOrNull() {
-    return readValueOrNull(readLibraryDependencyNode);
-  }
-
-  @override
-  js.Node readJsNodeOrNull() {
-    bool hasValue = readBool();
-    if (hasValue) {
-      return readJsNode();
-    }
-    return null;
-  }
-}
-
-/// Mixin that implements all convenience methods of [DataSink].
-abstract class DataSinkMixin implements DataSink {
-  @override
-  void writeIntOrNull(int value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeInt(value);
-    }
-  }
-
-  @override
-  void writeStringOrNull(String value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeString(value);
-    }
-  }
-
-  @override
-  void writeClassOrNull(IndexedClass value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeClass(value);
-    }
-  }
-
-  @override
-  void writeLocalOrNull(Local value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeLocal(value);
-    }
-  }
-
-  @override
-  void writeClasses(Iterable<ClassEntity> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (IndexedClass value in values) {
-        writeClass(value);
-      }
-    }
-  }
-
-  @override
-  void writeTreeNodes(Iterable<ir.TreeNode> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ir.TreeNode value in values) {
-        writeTreeNode(value);
-      }
-    }
-  }
-
-  @override
-  void writeStrings(Iterable<String> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (String value in values) {
-        writeString(value);
-      }
-    }
-  }
-
-  @override
-  void writeMemberNodes(Iterable<ir.Member> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ir.Member value in values) {
-        writeMemberNode(value);
-      }
-    }
-  }
-
-  @override
-  void writeDartTypes(Iterable<DartType> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (DartType value in values) {
-        writeDartType(value);
-      }
-    }
-  }
-
-  @override
-  void writeLibraryMap<V>(Map<LibraryEntity, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((LibraryEntity library, V value) {
-        writeLibrary(library);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeClassMap<V>(Map<ClassEntity, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((ClassEntity cls, V value) {
-        writeClass(cls);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeMemberMap<V>(
-      Map<MemberEntity, V> map, void f(MemberEntity member, V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((MemberEntity member, V value) {
-        writeMember(member);
-        f(member, value);
-      });
-    }
-  }
-
-  @override
-  void writeStringMap<V>(Map<String, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((String key, V value) {
-        writeString(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeLocals(Iterable<Local> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (Local value in values) {
-        writeLocal(value);
-      }
-    }
-  }
-
-  @override
-  void writeLocalMap<V>(Map<Local, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((Local key, V value) {
-        writeLocal(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeMemberNodeMap<V>(Map<ir.Member, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((ir.Member key, V value) {
-        writeMemberNode(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeTreeNodeMap<V>(Map<ir.TreeNode, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((ir.TreeNode key, V value) {
-        writeTreeNode(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeTypeVariableMap<V>(Map<IndexedTypeVariable, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((IndexedTypeVariable key, V value) {
-        writeTypeVariable(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeList<E>(Iterable<E> values, void f(E value),
-      {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      values.forEach(f);
-    }
-  }
-
-  @override
-  void writeTreeNodeOrNull(ir.TreeNode value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeTreeNode(value);
-    }
-  }
-
-  @override
-  void writeValueOrNull<E>(E value, void f(E value)) {
-    writeBool(value != null);
-    if (value != null) {
-      f(value);
-    }
-  }
-
-  @override
-  void writeMemberOrNull(IndexedMember value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeMember(value);
-    }
-  }
-
-  @override
-  void writeMembers(Iterable<MemberEntity> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (IndexedMember value in values) {
-        writeMember(value);
-      }
-    }
-  }
-
-  @override
-  void writeTypeParameterNodes(Iterable<ir.TypeParameter> values,
-      {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ir.TypeParameter value in values) {
-        writeTypeParameterNode(value);
-      }
-    }
-  }
-
-  @override
-  void writeConstantOrNull(ConstantValue value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeConstant(value);
-    }
-  }
-
-  @override
-  void writeConstants(Iterable<ConstantValue> values,
-      {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ConstantValue value in values) {
-        writeConstant(value);
-      }
-    }
-  }
-
-  @override
-  void writeConstantMap<V>(Map<ConstantValue, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((ConstantValue key, V value) {
-        writeConstant(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeLibraryOrNull(IndexedLibrary value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeLibrary(value);
-    }
-  }
-
-  @override
-  void writeImportOrNull(ImportEntity value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeImport(value);
-    }
-  }
-
-  @override
-  void writeImports(Iterable<ImportEntity> values, {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ImportEntity value in values) {
-        writeImport(value);
-      }
-    }
-  }
-
-  @override
-  void writeImportMap<V>(Map<ImportEntity, V> map, void f(V value),
-      {bool allowNull = false}) {
-    if (map == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(map.length);
-      map.forEach((ImportEntity key, V value) {
-        writeImport(key);
-        f(value);
-      });
-    }
-  }
-
-  @override
-  void writeDartTypeNodes(Iterable<ir.DartType> values,
-      {bool allowNull = false}) {
-    if (values == null) {
-      assert(allowNull);
-      writeInt(0);
-    } else {
-      writeInt(values.length);
-      for (ir.DartType value in values) {
-        writeDartTypeNode(value);
-      }
-    }
-  }
-
-  @override
-  void writeName(ir.Name value) {
-    writeString(value.text);
-    writeValueOrNull(value.library, writeLibraryNode);
-  }
-
-  @override
-  void writeLibraryDependencyNode(ir.LibraryDependency value) {
-    ir.Library library = value.parent;
-    writeLibraryNode(library);
-    writeInt(library.dependencies.indexOf(value));
-  }
-
-  @override
-  void writeLibraryDependencyNodeOrNull(ir.LibraryDependency value) {
-    writeValueOrNull(value, writeLibraryDependencyNode);
-  }
-
-  @override
-  void writeJsNodeOrNull(js.Node value) {
-    writeBool(value != null);
-    if (value != null) {
-      writeJsNode(value);
-    }
-  }
-}
diff --git a/pkg/compiler/lib/src/serialization/object_sink.dart b/pkg/compiler/lib/src/serialization/object_sink.dart
index bbb91e3..1388dc6 100644
--- a/pkg/compiler/lib/src/serialization/object_sink.dart
+++ b/pkg/compiler/lib/src/serialization/object_sink.dart
@@ -4,52 +4,39 @@
 
 part of 'serialization.dart';
 
-/// [DataSink] that writes to a list of objects, useful for debugging
+/// [DataSinkWriter] that writes to a list of objects, useful for debugging
 /// inconsistencies between serialization and deserialization.
 ///
-/// This data sink works together with [ObjectSource].
-class ObjectSink extends AbstractDataSink {
+/// This data sink writer works together with [ObjectDataSource].
+class ObjectDataSink implements DataSink {
   List<dynamic> _data;
 
-  ObjectSink(this._data,
-      {bool useDataKinds,
-      Map<String, int> tagFrequencyMap,
-      DataSourceIndices importedIndices})
-      : super(
-            useDataKinds: useDataKinds,
-            tagFrequencyMap: tagFrequencyMap,
-            importedIndices: importedIndices);
+  ObjectDataSink(this._data);
 
   @override
-  void _begin(String tag) {
+  void beginTag(String tag) {
     _data.add(Tag('begin:$tag'));
   }
 
   @override
-  void _end(String tag) {
+  void endTag(String tag) {
     _data.add(Tag('end:$tag'));
   }
 
   @override
-  void _writeEnumInternal(dynamic value) {
+  void writeEnum(dynamic value) {
     assert(value != null);
     _data.add(value);
   }
 
   @override
-  void _writeIntInternal(int value) {
+  void writeInt(int value) {
     assert(value != null);
     _data.add(value);
   }
 
   @override
-  void _writeStringInternal(String value) {
-    assert(value != null);
-    _data.add(value);
-  }
-
-  @override
-  void _writeUriInternal(Uri value) {
+  void writeString(String value) {
     assert(value != null);
     _data.add(value);
   }
diff --git a/pkg/compiler/lib/src/serialization/object_source.dart b/pkg/compiler/lib/src/serialization/object_source.dart
index 07e07ad..01b602b 100644
--- a/pkg/compiler/lib/src/serialization/object_source.dart
+++ b/pkg/compiler/lib/src/serialization/object_source.dart
@@ -7,55 +7,50 @@
 /// [DataSource] that read from a list of objects, useful for debugging
 /// inconsistencies between serialization and deserialization.
 ///
-/// This data source works together with [ObjectSink].
-class ObjectSource extends AbstractDataSource {
+/// This data source works together with [ObjectDataSink].
+class ObjectDataSource implements DataSource {
   int _index = 0;
   final List<dynamic> _data;
 
-  ObjectSource(this._data,
-      {bool useDataKinds, DataSourceIndices importedIndices})
-      : super(useDataKinds: useDataKinds, importedIndices: importedIndices);
+  ObjectDataSource(this._data);
 
   T _read<T>() {
     dynamic value = _data[_index++];
-    assert(value is T, "Expected $T value, found $value.$_errorContext");
+    assert(value is T, "Expected $T value, found $value.$errorContext");
     return value;
   }
 
   @override
-  void _begin(String tag) {
+  void begin(String tag) {
     Tag expectedTag = Tag('begin:$tag');
     Tag actualTag = _read();
     assert(
         expectedTag == actualTag,
         "Unexpected begin tag. "
-        "Expected $expectedTag, found $actualTag.$_errorContext");
+        "Expected $expectedTag, found $actualTag.$errorContext");
   }
 
   @override
-  void _end(String tag) {
+  void end(String tag) {
     Tag expectedTag = Tag('end:$tag');
     Tag actualTag = _read();
     assert(
         expectedTag == actualTag,
         "Unexpected end tag. "
-        "Expected $expectedTag, found $actualTag.$_errorContext");
+        "Expected $expectedTag, found $actualTag.$errorContext");
   }
 
   @override
-  String _readStringInternal() => _read();
+  String readString() => _read();
 
   @override
-  E _readEnumInternal<E>(List<E> values) => _read();
+  E readEnum<E>(List<E> values) => _read();
 
   @override
-  Uri _readUriInternal() => _read();
+  int readInt() => _read();
 
   @override
-  int _readIntInternal() => _read();
-
-  @override
-  String get _errorContext {
+  String get errorContext {
     StringBuffer sb = StringBuffer();
     for (int i = _index - 50; i < _index + 10; i++) {
       if (i >= 0 && i < _data.length) {
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 4fb6654..b7747d9 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -22,13 +22,12 @@
 import '../js_model/locals.dart';
 import '../js_model/type_recipe.dart' show TypeRecipe;
 
-part 'abstract_sink.dart';
-part 'abstract_source.dart';
+part 'sink.dart';
+part 'source.dart';
 part 'binary_sink.dart';
 part 'binary_source.dart';
 part 'helpers.dart';
 part 'member_data.dart';
-part 'mixins.dart';
 part 'node_indexer.dart';
 part 'object_sink.dart';
 part 'object_source.dart';
@@ -37,431 +36,8 @@
   String internString(String string);
 }
 
-/// Interface for serialization.
-abstract class DataSink {
-  /// The amount of data written to this data sink.
-  ///
-  /// The units is based on the underlying data structure for this data sink.
-  int get length;
-
-  /// Flushes any pending data and closes this data sink.
-  ///
-  /// The data sink can no longer be written to after closing.
-  void close();
-
-  /// Registers that the section [tag] starts.
-  ///
-  /// This is used for debugging to verify that sections are correctly aligned
-  /// between serialization and deserialization.
-  void begin(String tag);
-
-  /// Registers that the section [tag] ends.
-  ///
-  /// This is used for debugging to verify that sections are correctly aligned
-  /// between serialization and deserialization.
-  void end(String tag);
-
-  /// Writes a reference to [value] to this data sink. If [value] has not yet
-  /// been serialized, [f] is called to serialize the value itself.
-  void writeCached<E>(E value, void f(E value));
-
-  /// Writes the potentially `null` [value] to this data sink. If [value] is
-  /// non-null [f] is called to write the non-null value to the data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readValueOrNull].
-  void writeValueOrNull<E>(E value, void f(E value));
-
-  /// Writes the [values] to this data sink calling [f] to write each value to
-  /// the data sink. If [allowNull] is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readList].
-  void writeList<E>(Iterable<E> values, void f(E value),
-      {bool allowNull = false});
-
-  /// Writes the boolean [value] to this data sink.
-  void writeBool(bool value);
-
-  /// Writes the non-negative 30 bit integer [value] to this data sink.
-  void writeInt(int value);
-
-  /// Writes the potentially `null` non-negative [value] to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readIntOrNull].
-  void writeIntOrNull(int value);
-
-  /// Writes the string [value] to this data sink.
-  void writeString(String value);
-
-  /// Writes the potentially `null` string [value] to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readStringOrNull].
-  void writeStringOrNull(String value);
-
-  /// Writes the string [values] to this data sink. If [allowNull] is `true`,
-  /// [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readStrings].
-  void writeStrings(Iterable<String> values, {bool allowNull = false});
-
-  /// Writes the [map] from string to [V] values to this data sink, calling [f]
-  /// to write each value to the data sink. If [allowNull] is `true`, [map] is
-  /// allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readStringMap].
-  void writeStringMap<V>(Map<String, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes the enum value [value] to this data sink.
-  // TODO(johnniwinther): Change the signature to
-  // `void writeEnum<E extends Enum<E>>(E value);` when an interface for enums
-  // is added to the language.
-  void writeEnum(dynamic value);
-
-  /// Writes the URI [value] to this data sink.
-  void writeUri(Uri value);
-
-  /// Writes a reference to the kernel library node [value] to this data sink.
-  void writeLibraryNode(ir.Library value);
-
-  /// Writes a reference to the kernel class node [value] to this data sink.
-  void writeClassNode(ir.Class value);
-
-  /// Writes a reference to the kernel typedef node [value] to this data sink.
-  void writeTypedefNode(ir.Typedef value);
-
-  /// Writes a reference to the kernel member node [value] to this data sink.
-  void writeMemberNode(ir.Member value);
-
-  /// Writes references to the kernel member node [values] to this data sink.
-  /// If [allowNull] is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readMemberNodes].
-  void writeMemberNodes(Iterable<ir.Member> values, {bool allowNull = false});
-
-  /// Writes the [map] from references to kernel member nodes to [V] values to
-  /// this data sink, calling [f] to write each value to the data sink. If
-  /// [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readMemberNodeMap].
-  void writeMemberNodeMap<V>(Map<ir.Member, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a kernel name node to this data sink.
-  void writeName(ir.Name value);
-
-  /// Writes a kernel library dependency node [value] to this data sink.
-  void writeLibraryDependencyNode(ir.LibraryDependency value);
-
-  /// Writes a potentially `null` kernel library dependency node [value] to
-  /// this data sink.
-  void writeLibraryDependencyNodeOrNull(ir.LibraryDependency value);
-
-  /// Writes a reference to the kernel tree node [value] to this data sink.
-  void writeTreeNode(ir.TreeNode value);
-
-  /// Writes a reference to the potentially `null` kernel tree node [value]
-  /// to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTreeNodeOrNull].
-  void writeTreeNodeOrNull(ir.TreeNode value);
-
-  /// Writes references to the kernel tree node [values] to this data sink.
-  /// If [allowNull] is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTreeNodes].
-  void writeTreeNodes(Iterable<ir.TreeNode> values, {bool allowNull = false});
-
-  /// Writes the [map] from references to kernel tree nodes to [V] values to
-  /// this data sink, calling [f] to write each value to the data sink. If
-  /// [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTreeNodeMap].
-  void writeTreeNodeMap<V>(Map<ir.TreeNode, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a reference to the kernel tree node [value] in the known [context]
-  /// to this data sink.
-  void writeTreeNodeInContext(ir.TreeNode value);
-
-  /// Writes a reference to the potentially `null` kernel tree node [value] in
-  /// the known [context] to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTreeNodeOrNullInContext].
-  void writeTreeNodeOrNullInContext(ir.TreeNode value);
-
-  /// Writes references to the kernel tree node [values] in the known [context]
-  /// to this data sink. If [allowNull] is `true`, [values] is allowed to be
-  /// `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTreeNodesInContext].
-  void writeTreeNodesInContext(Iterable<ir.TreeNode> values,
-      {bool allowNull = false});
-
-  /// Writes the [map] from references to kernel tree nodes to [V] values in the
-  /// known [context] to this data sink, calling [f] to write each value to the
-  /// data sink. If [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTreeNodeMapInContext].
-  void writeTreeNodeMapInContext<V>(Map<ir.TreeNode, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a reference to the kernel type parameter node [value] to this data
-  /// sink.
-  void writeTypeParameterNode(ir.TypeParameter value);
-
-  /// Writes references to the kernel type parameter node [values] to this data
-  /// sink.
-  /// If [allowNull] is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTypeParameterNodes].
-  void writeTypeParameterNodes(Iterable<ir.TypeParameter> values,
-      {bool allowNull = false});
-
-  /// Writes the type [value] to this data sink. If [allowNull] is `true`,
-  /// [value] is allowed to be `null`.
-  void writeDartType(DartType value, {bool allowNull = false});
-
-  /// Writes the type [values] to this data sink. If [allowNull] is `true`,
-  /// [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readDartTypes].
-  void writeDartTypes(Iterable<DartType> values, {bool allowNull = false});
-
-  /// Writes the kernel type node [value] to this data sink. If [allowNull] is
-  /// `true`, [value] is allowed to be `null`.
-  void writeDartTypeNode(ir.DartType value, {bool allowNull = false});
-
-  /// Writes the kernel type node [values] to this data sink. If [allowNull] is
-  /// `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readDartTypeNodes].
-  void writeDartTypeNodes(Iterable<ir.DartType> values,
-      {bool allowNull = false});
-
-  /// Writes the source span [value] to this data sink.
-  void writeSourceSpan(SourceSpan value);
-
-  /// Writes a reference to the indexed library [value] to this data sink.
-  void writeLibrary(IndexedLibrary value);
-
-  /// Writes a reference to the potentially `null` indexed library [value]
-  /// to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readLibraryOrNull].
-  void writeLibraryOrNull(IndexedLibrary value);
-
-  /// Writes the [map] from references to indexed libraries to [V] values to
-  /// this data sink, calling [f] to write each value to the data sink. If
-  /// [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readLibraryMap].
-  void writeLibraryMap<V>(Map<LibraryEntity, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a reference to the indexed class [value] to this data sink.
-  void writeClass(IndexedClass value);
-
-  /// Writes a reference to the potentially `null` indexed class [value]
-  /// to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readClassOrNull].
-  void writeClassOrNull(IndexedClass value);
-
-  /// Writes references to the indexed class [values] to this data sink. If
-  /// [allowNull] is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readClasses].
-  void writeClasses(Iterable<ClassEntity> values, {bool allowNull = false});
-
-  /// Writes the [map] from references to indexed classes to [V] values to this
-  /// data sink, calling [f] to write each value to the data sink. If
-  /// [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readClassMap].
-  void writeClassMap<V>(Map<ClassEntity, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a reference to the indexed member [value] to this data sink.
-  void writeMember(IndexedMember value);
-
-  /// Writes a reference to the potentially `null` indexed member [value]
-  /// to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readMemberOrNull].
-  void writeMemberOrNull(IndexedMember value);
-
-  /// Writes references to the indexed member [values] to this data sink. If
-  /// [allowNull] is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readMembers].
-  void writeMembers(Iterable<MemberEntity> values, {bool allowNull = false});
-
-  /// Writes the [map] from references to indexed members to [V] values to this
-  /// data sink, calling [f] to write each value to the data sink. If
-  /// [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readMemberMap].
-  void writeMemberMap<V>(
-      Map<MemberEntity, V> map, void f(MemberEntity member, V value),
-      {bool allowNull = false});
-
-  /// Writes a reference to the indexed type variable [value] to this data sink.
-  void writeTypeVariable(IndexedTypeVariable value);
-
-  /// Writes the [map] from references to indexed type variables to [V] values
-  /// to this data sink, calling [f] to write each value to the data sink. If
-  /// [allowNull] is `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readTypeVariableMap].
-  void writeTypeVariableMap<V>(Map<IndexedTypeVariable, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a reference to the local [value] to this data sink.
-  void writeLocal(Local local);
-
-  /// Writes a reference to the potentially `null` local [value]
-  /// to this data sink.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readLocalOrNull].
-  void writeLocalOrNull(Local local);
-
-  /// Writes references to the local [values] to this data sink. If [allowNull]
-  /// is `true`, [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readLocals].
-  void writeLocals(Iterable<Local> values, {bool allowNull = false});
-
-  /// Writes the [map] from references to locals to [V] values to this data
-  /// sink, calling [f] to write each value to the data sink. If [allowNull] is
-  /// `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readLocalMap].
-  void writeLocalMap<V>(Map<Local, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes the constant [value] to this data sink.
-  void writeConstant(ConstantValue value);
-
-  /// Writes the potentially `null` constant [value] to this data sink.
-  void writeConstantOrNull(ConstantValue value);
-
-  /// Writes constant [values] to this data sink. If [allowNull] is `true`,
-  /// [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readConstants].
-  void writeConstants(Iterable<ConstantValue> values, {bool allowNull = false});
-
-  /// Writes the [map] from constant values to [V] values to this data sink,
-  /// calling [f] to write each value to the data sink. If [allowNull] is
-  /// `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readConstantMap].
-  void writeConstantMap<V>(Map<ConstantValue, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes a double value to this data sink.
-  void writeDoubleValue(double value);
-
-  /// Writes an integer of arbitrary value to this data sink.
-  ///
-  /// This is should only when the value is not known to be a non-negative
-  /// 30 bit integer. Otherwise [writeInt] should be used.
-  void writeIntegerValue(int value);
-
-  /// Writes the import [value] to this data sink.
-  void writeImport(ImportEntity value);
-
-  /// Writes the potentially `null` import [value] to this data sink.
-  void writeImportOrNull(ImportEntity value);
-
-  /// Writes import [values] to this data sink. If [allowNull] is `true`,
-  /// [values] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readImports].
-  void writeImports(Iterable<ImportEntity> values, {bool allowNull = false});
-
-  /// Writes the [map] from imports to [V] values to this data sink,
-  /// calling [f] to write each value to the data sink. If [allowNull] is
-  /// `true`, [map] is allowed to be `null`.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSource.readImportMap].
-  void writeImportMap<V>(Map<ImportEntity, V> map, void f(V value),
-      {bool allowNull = false});
-
-  /// Writes an abstract [value] to this data sink.
-  ///
-  /// This feature is only available a [CodegenWriter] has been registered.
-  void writeAbstractValue(AbstractValue value);
-
-  /// Writes a reference to the output unit [value] to this data sink.
-  ///
-  /// This feature is only available a [CodegenWriter] has been registered.
-  void writeOutputUnitReference(OutputUnit value);
-
-  /// Writes a js node [value] to this data sink.
-  ///
-  /// This feature is only available a [CodegenWriter] has been registered.
-  void writeJsNode(js.Node value);
-
-  /// Writes a potentially `null` js node [value] to this data sink.
-  ///
-  /// This feature is only available a [CodegenWriter] has been registered.
-  void writeJsNodeOrNull(js.Node value);
-
-  /// Writes TypeRecipe [value] to this data sink.
-  ///
-  /// This feature is only available a [CodegenWriter] has been registered.
-  void writeTypeRecipe(TypeRecipe value);
-
-  /// Register an [EntityWriter] with this data sink for non-default encoding
-  /// of entity references.
-  void registerEntityWriter(EntityWriter writer);
-
-  /// Register a [CodegenWriter] with this data sink to support serialization
-  /// of codegen only data.
-  void registerCodegenWriter(CodegenWriter writer);
-
-  /// Invoke [f] in the context of [member]. This sets up support for
-  /// serialization of `ir.TreeNode`s using the `writeTreeNode*InContext`
-  /// methods.
-  void inMemberContext(ir.Member member, void f());
-}
-
 /// Data class representing cache information for a given [T] which can be
-/// passed from a [DataSource] to other [DataSource]s and [DataSink]s.
+/// passed from a [DataSourceReader] to other [DataSourceReader]s and [DataSinkWriter]s.
 class DataSourceTypeIndices<E, T> {
   /// Reshapes a [List<T>] to a [Map<E, int>] using [_getValue].
   Map<E, int> _reshape() {
@@ -481,9 +57,9 @@
   Map<E, int> _cache;
 
   /// Though [DataSourceTypeIndices] supports two types of caches. If the
-  /// exported indices are imported into a [DataSource] then the [cacheAsList]
+  /// exported indices are imported into a [DataSourceReader] then the [cacheAsList]
   /// will be used as is. If, however, the exported indices are imported into a
-  /// [DataSink] then we need to reshape the [List<T>] into a [Map<E, int>]
+  /// [DataSinkWriter] then we need to reshape the [List<T>] into a [Map<E, int>]
   /// where [E] is either [T] or some value which can be derived from [T] by
   /// [_getValue].
   DataSourceTypeIndices(this.cacheAsList, [this._getValue]) {
@@ -493,418 +69,11 @@
 }
 
 /// Data class representing the sum of all cache information for a given
-/// [DataSource].
+/// [DataSourceReader].
 class DataSourceIndices {
   final Map<Type, DataSourceTypeIndices> caches = {};
 }
 
-/// Interface for deserialization.
-abstract class DataSource {
-  /// Exports [DataSourceIndices] for use in other [DataSource]s and
-  /// [DataSink]s.
-  DataSourceIndices exportIndices();
-
-  /// Registers that the section [tag] starts.
-  ///
-  /// This is used for debugging to verify that sections are correctly aligned
-  /// between serialization and deserialization.
-  void begin(String tag);
-
-  /// Registers that the section [tag] ends.
-  ///
-  /// This is used for debugging to verify that sections are correctly aligned
-  /// between serialization and deserialization.
-  void end(String tag);
-
-  /// Registers a [ComponentLookup] object with this data source to support
-  /// deserialization of references to kernel nodes.
-  void registerComponentLookup(ComponentLookup componentLookup);
-
-  /// Registers an [EntityLookup] object with this data source to support
-  /// deserialization of references to indexed entities.
-  void registerEntityLookup(EntityLookup entityLookup);
-
-  /// Registers an [EntityReader] with this data source for non-default encoding
-  /// of entity references.
-  void registerEntityReader(EntityReader reader);
-
-  /// Registers a [LocalLookup] object with this data source to support
-  /// deserialization of references to locals.
-  void registerLocalLookup(LocalLookup localLookup);
-
-  /// Registers a [CodegenReader] with this data source to support
-  /// deserialization of codegen only data.
-  void registerCodegenReader(CodegenReader reader);
-
-  /// Unregisters the [CodegenReader] from this data source to remove support
-  /// for deserialization of codegen only data.
-  void deregisterCodegenReader(CodegenReader reader);
-
-  /// Invoke [f] in the context of [member]. This sets up support for
-  /// deserialization of `ir.TreeNode`s using the `readTreeNode*InContext`
-  /// methods.
-  T inMemberContext<T>(ir.Member member, T f());
-
-  /// Reads a reference to an [E] value from this data source. If the value has
-  /// not yet been deserialized, [f] is called to deserialize the value itself.
-  E readCached<E>(E f());
-
-  /// Reads a potentially `null` [E] value from this data source, calling [f] to
-  /// read the non-null value from the data source.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeValueOrNull].
-  E readValueOrNull<E>(E f());
-
-  /// Reads a list of [E] values from this data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeList].
-  List<E> readList<E>(E f(), {bool emptyAsNull = false});
-
-  /// Reads a boolean value from this data source.
-  bool readBool();
-
-  /// Reads a non-negative 30 bit integer value from this data source.
-  int readInt();
-
-  /// Reads a potentially `null` non-negative integer value from this data
-  /// source.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeIntOrNull].
-  int readIntOrNull();
-
-  /// Reads a string value from this data source.
-  String readString();
-
-  /// Reads a potentially `null` string value from this data source.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeStringOrNull].
-  String readStringOrNull();
-
-  /// Reads a list of string values from this data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeStrings].
-  List<String> readStrings({bool emptyAsNull = false});
-
-  /// Reads a map from string values to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeStringMap].
-  Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull = false});
-
-  /// Reads an enum value from the list of enum [values] from this data source.
-  ///
-  /// The [values] argument is intended to be the static `.values` field on
-  /// enum classes, for instance:
-  ///
-  ///    enum Foo { bar, baz }
-  ///    ...
-  ///    Foo foo = source.readEnum(Foo.values);
-  ///
-  E readEnum<E>(List<E> values);
-
-  /// Reads a URI value from this data source.
-  Uri readUri();
-
-  /// Reads a reference to a kernel library node from this data source.
-  ir.Library readLibraryNode();
-
-  /// Reads a reference to a kernel class node from this data source.
-  ir.Class readClassNode();
-
-  /// Reads a reference to a kernel class node from this data source.
-  ir.Typedef readTypedefNode();
-
-  /// Reads a reference to a kernel member node from this data source.
-  ir.Member readMemberNode();
-
-  /// Reads a list of references to kernel member nodes from this data source.
-  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeMemberNodes].
-  List<ir.Member> readMemberNodes<E extends ir.Member>(
-      {bool emptyAsNull = false});
-
-  /// Reads a map from kernel member nodes to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeMemberNodeMap].
-  Map<K, V> readMemberNodeMap<K extends ir.Member, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a kernel name node from this data source.
-  ir.Name readName();
-
-  /// Reads a kernel library dependency node from this data source.
-  ir.LibraryDependency readLibraryDependencyNode();
-
-  /// Reads a potentially `null` kernel library dependency node from this data
-  /// source.
-  ir.LibraryDependency readLibraryDependencyNodeOrNull();
-
-  /// Reads a reference to a kernel tree node from this data source.
-  ir.TreeNode readTreeNode();
-
-  /// Reads a reference to a potentially `null` kernel tree node from this data
-  /// source.
-  ir.TreeNode readTreeNodeOrNull();
-
-  /// Reads a list of references to kernel tree nodes from this data source.
-  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeTreeNodes].
-  List<E> readTreeNodes<E extends ir.TreeNode>({bool emptyAsNull = false});
-
-  /// Reads a map from kernel tree nodes to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeTreeNodeMap].
-  Map<K, V> readTreeNodeMap<K extends ir.TreeNode, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a reference to a kernel tree node in the known [context] from this
-  /// data source.
-  ir.TreeNode readTreeNodeInContext();
-
-  /// Reads a reference to a potentially `null` kernel tree node in the known
-  /// [context] from this data source.
-  ir.TreeNode readTreeNodeOrNullInContext();
-
-  /// Reads a list of references to kernel tree nodes in the known [context]
-  /// from this data source. If [emptyAsNull] is `true`, `null` is returned
-  /// instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeTreeNodesInContext].
-  List<E> readTreeNodesInContext<E extends ir.TreeNode>(
-      {bool emptyAsNull = false});
-
-  /// Reads a map from kernel tree nodes to [V] values in the known [context]
-  /// from this data source, calling [f] to read each value from the data
-  /// source. If [emptyAsNull] is `true`, `null` is returned instead of an empty
-  /// map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeTreeNodeMapInContext].
-  Map<K, V> readTreeNodeMapInContext<K extends ir.TreeNode, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a reference to a kernel type parameter node from this data source.
-  ir.TypeParameter readTypeParameterNode();
-
-  /// Reads a list of references to kernel type parameter nodes from this data
-  /// source. If [emptyAsNull] is `true`, `null` is returned instead of an empty
-  /// list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeTypeParameterNodes].
-  List<ir.TypeParameter> readTypeParameterNodes({bool emptyAsNull = false});
-
-  /// Reads a type from this data source. If [allowNull], the returned type is
-  /// allowed to be `null`.
-  DartType readDartType({bool allowNull = false});
-
-  /// Reads a list of types from this data source. If [emptyAsNull] is `true`,
-  /// `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeDartTypes].
-  List<DartType> readDartTypes({bool emptyAsNull = false});
-
-  /// Reads a kernel type node from this data source. If [allowNull], the
-  /// returned type is allowed to be `null`.
-  ir.DartType readDartTypeNode({bool allowNull = false});
-
-  /// Reads a list of kernel type nodes from this data source. If [emptyAsNull]
-  /// is `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeDartTypeNodes].
-  List<ir.DartType> readDartTypeNodes({bool emptyAsNull = false});
-
-  /// Reads a source span from this data source.
-  SourceSpan readSourceSpan();
-
-  /// Reads a reference to an indexed library from this data source.
-  IndexedLibrary readLibrary();
-
-  /// Reads a reference to a potentially `null` indexed library from this data
-  /// source.
-  IndexedLibrary readLibraryOrNull();
-  Map<K, V> readLibraryMap<K extends LibraryEntity, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a reference to an indexed class from this data source.
-  IndexedClass readClass();
-
-  /// Reads a reference to a potentially `null` indexed class from this data
-  /// source.
-  IndexedClass readClassOrNull();
-
-  /// Reads a list of references to indexed classes from this data source.
-  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeClasses].
-  List<E> readClasses<E extends ClassEntity>({bool emptyAsNull = false});
-
-  /// Reads a map from indexed classes to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeClassMap].
-  Map<K, V> readClassMap<K extends ClassEntity, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a reference to an indexed member from this data source.
-  IndexedMember readMember();
-
-  /// Reads a reference to a potentially `null` indexed member from this data
-  /// source.
-  IndexedMember readMemberOrNull();
-
-  /// Reads a list of references to indexed members from this data source.
-  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeMembers].
-  List<E> readMembers<E extends MemberEntity>({bool emptyAsNull = false});
-
-  /// Reads a map from indexed members to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeMemberMap].
-  Map<K, V> readMemberMap<K extends MemberEntity, V>(V f(MemberEntity member),
-      {bool emptyAsNull = false});
-
-  /// Reads a reference to an indexed type variable from this data source.
-  IndexedTypeVariable readTypeVariable();
-
-  /// Reads a map from indexed type variable to [V] values from this data
-  /// source, calling [f] to read each value from the data source. If
-  /// [emptyAsNull] is `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeTypeVariableMap].
-  Map<K, V> readTypeVariableMap<K extends IndexedTypeVariable, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a reference to a local from this data source.
-  Local readLocal();
-
-  /// Reads a reference to a potentially `null` local from this data source.
-  Local readLocalOrNull();
-
-  /// Reads a list of references to locals from this data source. If
-  /// [emptyAsNull] is `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeLocals].
-  List<E> readLocals<E extends Local>({bool emptyAsNull = false});
-
-  /// Reads a map from locals to [V] values from this data source, calling [f]
-  /// to read each value from the data source. If [emptyAsNull] is `true`,
-  /// `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeLocalMap].
-  Map<K, V> readLocalMap<K extends Local, V>(V f(), {bool emptyAsNull = false});
-
-  /// Reads a constant value from this data source.
-  ConstantValue readConstant();
-
-  /// Reads a potentially `null` constant value from this data source.
-  ConstantValue readConstantOrNull();
-
-  /// Reads a double value from this data source.
-  double readDoubleValue();
-
-  /// Reads an integer of arbitrary value from this data source.
-  ///
-  /// This is should only when the value is not known to be a non-negative
-  /// 30 bit integer. Otherwise [readInt] should be used.
-  int readIntegerValue();
-
-  /// Reads a list of constant values from this data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeConstants].
-  List<E> readConstants<E extends ConstantValue>({bool emptyAsNull = false});
-
-  /// Reads a map from constant values to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeConstantMap].
-  Map<K, V> readConstantMap<K extends ConstantValue, V>(V f(),
-      {bool emptyAsNull = false});
-
-  /// Reads a import from this data source.
-  ImportEntity readImport();
-
-  /// Reads a potentially `null` import from this data source.
-  ImportEntity readImportOrNull();
-
-  /// Reads a list of imports from this data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty list.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeImports].
-  List<ImportEntity> readImports({bool emptyAsNull = false});
-
-  /// Reads a map from imports to [V] values from this data source,
-  /// calling [f] to read each value from the data source. If [emptyAsNull] is
-  /// `true`, `null` is returned instead of an empty map.
-  ///
-  /// This is a convenience method to be used together with
-  /// [DataSink.writeImportMap].
-  Map<ImportEntity, V> readImportMap<V>(V f(), {bool emptyAsNull = false});
-
-  /// Reads an [AbstractValue] from this data source.
-  ///
-  /// This feature is only available a [CodegenReader] has been registered.
-  AbstractValue readAbstractValue();
-
-  /// Reads a reference to an [OutputUnit] from this data source.
-  ///
-  /// This feature is only available a [CodegenReader] has been registered.
-  OutputUnit readOutputUnitReference();
-
-  /// Reads a [js.Node] value from this data source.
-  ///
-  /// This feature is only available a [CodegenReader] has been registered.
-  js.Node readJsNode();
-
-  /// Reads a potentially `null` [js.Node] value from this data source.
-  ///
-  /// This feature is only available a [CodegenReader] has been registered.
-  js.Node readJsNodeOrNull();
-
-  /// Reads a [TypeRecipe] value from this data source.
-  ///
-  /// This feature is only available a [CodegenReader] has been registered.
-  TypeRecipe readTypeRecipe();
-}
-
 /// Interface used for looking up entities by index during deserialization.
 abstract class EntityLookup {
   /// Returns the indexed library corresponding to [index].
@@ -925,22 +94,22 @@
   const EntityReader();
 
   IndexedLibrary readLibraryFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
+      DataSourceReader source, EntityLookup entityLookup) {
     return entityLookup.getLibraryByIndex(source.readInt());
   }
 
   IndexedClass readClassFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
+      DataSourceReader source, EntityLookup entityLookup) {
     return entityLookup.getClassByIndex(source.readInt());
   }
 
   IndexedMember readMemberFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
+      DataSourceReader source, EntityLookup entityLookup) {
     return entityLookup.getMemberByIndex(source.readInt());
   }
 
   IndexedTypeVariable readTypeVariableFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
+      DataSourceReader source, EntityLookup entityLookup) {
     return entityLookup.getTypeVariableByIndex(source.readInt());
   }
 }
@@ -949,19 +118,20 @@
 class EntityWriter {
   const EntityWriter();
 
-  void writeLibraryToDataSink(DataSink sink, IndexedLibrary value) {
+  void writeLibraryToDataSink(DataSinkWriter sink, IndexedLibrary value) {
     sink.writeInt(value.libraryIndex);
   }
 
-  void writeClassToDataSink(DataSink sink, IndexedClass value) {
+  void writeClassToDataSink(DataSinkWriter sink, IndexedClass value) {
     sink.writeInt(value.classIndex);
   }
 
-  void writeMemberToDataSink(DataSink sink, IndexedMember value) {
+  void writeMemberToDataSink(DataSinkWriter sink, IndexedMember value) {
     sink.writeInt(value.memberIndex);
   }
 
-  void writeTypeVariableToDataSink(DataSink sink, IndexedTypeVariable value) {
+  void writeTypeVariableToDataSink(
+      DataSinkWriter sink, IndexedTypeVariable value) {
     sink.writeInt(value.typeVariableIndex);
   }
 }
@@ -973,16 +143,16 @@
 
 /// Interface used for reading codegen only data during deserialization.
 abstract class CodegenReader {
-  AbstractValue readAbstractValue(DataSource source);
-  OutputUnit readOutputUnitReference(DataSource source);
-  js.Node readJsNode(DataSource source);
-  TypeRecipe readTypeRecipe(DataSource source);
+  AbstractValue readAbstractValue(DataSourceReader source);
+  OutputUnit readOutputUnitReference(DataSourceReader source);
+  js.Node readJsNode(DataSourceReader source);
+  TypeRecipe readTypeRecipe(DataSourceReader source);
 }
 
 /// Interface used for writing codegen only data during serialization.
 abstract class CodegenWriter {
-  void writeAbstractValue(DataSink sink, AbstractValue value);
-  void writeOutputUnitReference(DataSink sink, OutputUnit value);
-  void writeJsNode(DataSink sink, js.Node node);
-  void writeTypeRecipe(DataSink sink, TypeRecipe recipe);
+  void writeAbstractValue(DataSinkWriter sink, AbstractValue value);
+  void writeOutputUnitReference(DataSinkWriter sink, OutputUnit value);
+  void writeJsNode(DataSinkWriter sink, js.Node node);
+  void writeTypeRecipe(DataSinkWriter sink, TypeRecipe recipe);
 }
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart
new file mode 100644
index 0000000..3158728
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -0,0 +1,1266 @@
+// 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.
+
+part of 'serialization.dart';
+
+/// Interface handling [DataSinkWriter] low-level data serialization.
+///
+/// Each implementation of [DataSink] should have a corresponding
+/// [DataSource] that deserializes data serialized by that implementation.
+abstract class DataSink {
+  int get length;
+
+  /// Serialization of a non-negative integer value.
+  void writeInt(int value);
+
+  /// Serialization of an enum value.
+  void writeEnum(dynamic value);
+
+  /// Serialization of a String value.
+  void writeString(String value);
+
+  /// Serialization of a section begin tag. May be omitted by some writers.
+  void beginTag(String tag);
+
+  /// Serialization of a section end tag. May be omitted by some writers.
+  void endTag(String tag);
+
+  /// Closes any underlying data sinks.
+  void close();
+}
+
+/// Serialization writer
+///
+/// To be used with [DataSourceReader] to read and write serialized data.
+/// Serialization format is deferred to provided [DataSink].
+class DataSinkWriter {
+  final DataSink _sinkWriter;
+
+  /// If `true`, serialization of every data kind is preceded by a [DataKind]
+  /// value.
+  ///
+  /// This is used for debugging data inconsistencies between serialization
+  /// and deserialization.
+  final bool useDataKinds;
+  DataSourceIndices importedIndices;
+
+  /// Visitor used for serializing [ir.DartType]s.
+  DartTypeNodeWriter _dartTypeNodeWriter;
+
+  /// Stack of tags used when [useDataKinds] is `true` to help debugging section
+  /// inconsistencies between serialization and deserialization.
+  List<String> _tags;
+
+  /// Map of [_MemberData] object for serialized kernel member nodes.
+  final Map<ir.Member, _MemberData> _memberData = {};
+
+  IndexedSink<String> _stringIndex;
+  IndexedSink<Uri> _uriIndex;
+  IndexedSink<ir.Member> _memberNodeIndex;
+  IndexedSink<ImportEntity> _importIndex;
+  IndexedSink<ConstantValue> _constantIndex;
+
+  final Map<Type, IndexedSink> _generalCaches = {};
+
+  EntityWriter _entityWriter = const EntityWriter();
+  CodegenWriter _codegenWriter;
+
+  final Map<String, int> tagFrequencyMap;
+
+  ir.Member _currentMemberContext;
+  _MemberData _currentMemberData;
+
+  IndexedSink<T> _createSink<T>() {
+    if (importedIndices == null || !importedIndices.caches.containsKey(T)) {
+      return IndexedSink<T>(this._sinkWriter);
+    } else {
+      Map<T, int> cacheCopy = Map.from(importedIndices.caches[T].cache);
+      return IndexedSink<T>(this._sinkWriter, cache: cacheCopy);
+    }
+  }
+
+  DataSinkWriter(this._sinkWriter,
+      {this.useDataKinds = false, this.tagFrequencyMap, this.importedIndices}) {
+    _dartTypeNodeWriter = DartTypeNodeWriter(this);
+    _stringIndex = _createSink<String>();
+    _uriIndex = _createSink<Uri>();
+    _memberNodeIndex = _createSink<ir.Member>();
+    _importIndex = _createSink<ImportEntity>();
+    _constantIndex = _createSink<ConstantValue>();
+  }
+
+  /// The amount of data written to this data sink.
+  ///
+  /// The units is based on the underlying data structure for this data sink.
+  int get length => _sinkWriter.length;
+
+  /// Flushes any pending data and closes this data sink.
+  ///
+  /// The data sink can no longer be written to after closing.
+  void close() {
+    _sinkWriter.close();
+  }
+
+  /// Registers that the section [tag] starts.
+  ///
+  /// This is used for debugging to verify that sections are correctly aligned
+  /// between serialization and deserialization.
+  void begin(String tag) {
+    if (tagFrequencyMap != null) {
+      tagFrequencyMap[tag] ??= 0;
+      tagFrequencyMap[tag]++;
+    }
+    if (useDataKinds) {
+      _tags ??= <String>[];
+      _tags.add(tag);
+      _sinkWriter.beginTag(tag);
+    }
+  }
+
+  /// Registers that the section [tag] starts.
+  ///
+  /// This is used for debugging to verify that sections are correctly aligned
+  /// between serialization and deserialization.
+  void end(Object tag) {
+    if (useDataKinds) {
+      _sinkWriter.endTag(tag);
+
+      String existingTag = _tags.removeLast();
+      assert(existingTag == tag,
+          "Unexpected tag end. Expected $existingTag, found $tag.");
+    }
+  }
+
+  /// Writes a reference to [value] to this data sink. If [value] has not yet
+  /// been serialized, [f] is called to serialize the value itself.
+  void writeCached<E>(E value, void f(E value)) {
+    IndexedSink sink = _generalCaches[E] ??= _createSink<E>();
+    sink.write(value, (v) => f(v));
+  }
+
+  /// Writes the potentially `null` [value] to this data sink. If [value] is
+  /// non-null [f] is called to write the non-null value to the data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readValueOrNull].
+  void writeValueOrNull<E>(E value, void f(E value)) {
+    writeBool(value != null);
+    if (value != null) {
+      f(value);
+    }
+  }
+
+  /// Writes the [values] to this data sink calling [f] to write each value to
+  /// the data sink. If [allowNull] is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readList].
+  void writeList<E>(Iterable<E> values, void f(E value),
+      {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      values.forEach(f);
+    }
+  }
+
+  /// Writes the boolean [value] to this data sink.
+  void writeBool(bool value) {
+    assert(value != null);
+    _writeDataKind(DataKind.bool);
+    _writeBool(value);
+  }
+
+  void _writeBool(bool value) {
+    _sinkWriter.writeInt(value ? 1 : 0);
+  }
+
+  /// Writes the non-negative 30 bit integer [value] to this data sink.
+  void writeInt(int value) {
+    assert(value != null);
+    assert(value >= 0 && value >> 30 == 0);
+    _writeDataKind(DataKind.uint30);
+    _sinkWriter.writeInt(value);
+  }
+
+  /// Writes the potentially `null` non-negative [value] to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readIntOrNull].
+  void writeIntOrNull(int value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeInt(value);
+    }
+  }
+
+  /// Writes the string [value] to this data sink.
+  void writeString(String value) {
+    assert(value != null);
+    _writeDataKind(DataKind.string);
+    _writeString(value);
+  }
+
+  void _writeString(String value) {
+    _stringIndex.write(value, _sinkWriter.writeString);
+  }
+
+  /// Writes the potentially `null` string [value] to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readStringOrNull].
+  void writeStringOrNull(String value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeString(value);
+    }
+  }
+
+  /// Writes the [map] from string to [V] values to this data sink, calling [f]
+  /// to write each value to the data sink. If [allowNull] is `true`, [map] is
+  /// allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readStringMap].
+  void writeStringMap<V>(Map<String, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((String key, V value) {
+        writeString(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes the string [values] to this data sink. If [allowNull] is `true`,
+  /// [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readStrings].
+  void writeStrings(Iterable<String> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (String value in values) {
+        writeString(value);
+      }
+    }
+  }
+
+  /// Writes the enum value [value] to this data sink.
+  // TODO(johnniwinther): Change the signature to
+  // `void writeEnum<E extends Enum<E>>(E value);` when an interface for enums
+  // is added to the language.
+  void writeEnum(dynamic value) {
+    _writeDataKind(DataKind.enumValue);
+    _sinkWriter.writeEnum(value);
+  }
+
+  /// Writes the URI [value] to this data sink.
+  void writeUri(Uri value) {
+    assert(value != null);
+    _writeDataKind(DataKind.uri);
+    _writeUri(value);
+  }
+
+  void _writeUri(Uri value) {
+    _uriIndex.write(value, _doWriteUri);
+  }
+
+  void _doWriteUri(Uri value) {
+    _writeString(value.toString());
+  }
+
+  /// Writes a reference to the kernel library node [value] to this data sink.
+  void writeLibraryNode(ir.Library value) {
+    _writeDataKind(DataKind.libraryNode);
+    _writeLibraryNode(value);
+  }
+
+  void _writeLibraryNode(ir.Library value) {
+    _writeUri(value.importUri);
+  }
+
+  /// Writes a reference to the kernel class node [value] to this data sink.
+  void writeClassNode(ir.Class value) {
+    _writeDataKind(DataKind.classNode);
+    _writeClassNode(value);
+  }
+
+  void _writeClassNode(ir.Class value) {
+    _writeLibraryNode(value.enclosingLibrary);
+    _writeString(value.name);
+  }
+
+  /// Writes a reference to the kernel typedef node [value] to this data sink.
+  void writeTypedefNode(ir.Typedef value) {
+    _writeDataKind(DataKind.typedefNode);
+    _writeTypedefNode(value);
+  }
+
+  void _writeTypedefNode(ir.Typedef value) {
+    _writeLibraryNode(value.enclosingLibrary);
+    _writeString(value.name);
+  }
+
+  /// Writes a reference to the kernel member node [value] to this data sink.
+  void writeMemberNode(ir.Member value) {
+    _writeDataKind(DataKind.memberNode);
+    _writeMemberNode(value);
+  }
+
+  void _writeMemberNode(ir.Member value) {
+    _memberNodeIndex.write(value, _writeMemberNodeInternal);
+  }
+
+  void _writeMemberNodeInternal(ir.Member value) {
+    ir.Class cls = value.enclosingClass;
+    if (cls != null) {
+      _sinkWriter.writeEnum(MemberContextKind.cls);
+      _writeClassNode(cls);
+      _writeString(_computeMemberName(value));
+    } else {
+      _sinkWriter.writeEnum(MemberContextKind.library);
+      _writeLibraryNode(value.enclosingLibrary);
+      _writeString(_computeMemberName(value));
+    }
+  }
+
+  /// Writes references to the kernel member node [values] to this data sink.
+  /// If [allowNull] is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readMemberNodes].
+  void writeMemberNodes(Iterable<ir.Member> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ir.Member value in values) {
+        writeMemberNode(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from references to kernel member nodes to [V] values to
+  /// this data sink, calling [f] to write each value to the data sink. If
+  /// [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readMemberNodeMap].
+  void writeMemberNodeMap<V>(Map<ir.Member, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((ir.Member key, V value) {
+        writeMemberNode(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a kernel name node to this data sink.
+  void writeName(ir.Name value) {
+    writeString(value.text);
+    writeValueOrNull(value.library, writeLibraryNode);
+  }
+
+  /// Writes a kernel library dependency node [value] to this data sink.
+  void writeLibraryDependencyNode(ir.LibraryDependency value) {
+    ir.Library library = value.parent;
+    writeLibraryNode(library);
+    writeInt(library.dependencies.indexOf(value));
+  }
+
+  /// Writes a potentially `null` kernel library dependency node [value] to
+  /// this data sink.
+  void writeLibraryDependencyNodeOrNull(ir.LibraryDependency value) {
+    writeValueOrNull(value, writeLibraryDependencyNode);
+  }
+
+  /// Writes a reference to the kernel tree node [value] to this data sink.
+  void writeTreeNode(ir.TreeNode value) {
+    _writeDataKind(DataKind.treeNode);
+    _writeTreeNode(value, null);
+  }
+
+  void _writeTreeNode(ir.TreeNode value, _MemberData memberData) {
+    if (value is ir.Class) {
+      _sinkWriter.writeEnum(_TreeNodeKind.cls);
+      _writeClassNode(value);
+    } else if (value is ir.Member) {
+      _sinkWriter.writeEnum(_TreeNodeKind.member);
+      _writeMemberNode(value);
+    } else if (value is ir.VariableDeclaration &&
+        value.parent is ir.FunctionDeclaration) {
+      _sinkWriter.writeEnum(_TreeNodeKind.functionDeclarationVariable);
+      _writeTreeNode(value.parent, memberData);
+    } else if (value is ir.FunctionNode) {
+      _sinkWriter.writeEnum(_TreeNodeKind.functionNode);
+      _writeFunctionNode(value, memberData);
+    } else if (value is ir.TypeParameter) {
+      _sinkWriter.writeEnum(_TreeNodeKind.typeParameter);
+      _writeTypeParameter(value, memberData);
+    } else if (value is ConstantReference) {
+      _sinkWriter.writeEnum(_TreeNodeKind.constant);
+      memberData ??= _getMemberData(value.expression);
+      _writeTreeNode(value.expression, memberData);
+      int index =
+          memberData.getIndexByConstant(value.expression, value.constant);
+      _sinkWriter.writeInt(index);
+    } else {
+      _sinkWriter.writeEnum(_TreeNodeKind.node);
+      memberData ??= _getMemberData(value);
+      int index = memberData.getIndexByTreeNode(value);
+      assert(
+          index != null,
+          "No TreeNode index found for ${value.runtimeType} "
+          "found in ${memberData}.");
+      _sinkWriter.writeInt(index);
+    }
+  }
+
+  /// Writes a reference to the potentially `null` kernel tree node [value]
+  /// to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTreeNodeOrNull].
+  void writeTreeNodeOrNull(ir.TreeNode value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeTreeNode(value);
+    }
+  }
+
+  /// Writes references to the kernel tree node [values] to this data sink.
+  /// If [allowNull] is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTreeNodes].
+  void writeTreeNodes(Iterable<ir.TreeNode> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ir.TreeNode value in values) {
+        writeTreeNode(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from references to kernel tree nodes to [V] values to
+  /// this data sink, calling [f] to write each value to the data sink. If
+  /// [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTreeNodeMap].
+  void writeTreeNodeMap<V>(Map<ir.TreeNode, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((ir.TreeNode key, V value) {
+        writeTreeNode(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a reference to the kernel tree node [value] in the known [context]
+  /// to this data sink.
+  void writeTreeNodeInContext(ir.TreeNode value) {
+    writeTreeNodeInContextInternal(value, currentMemberData);
+  }
+
+  void writeTreeNodeInContextInternal(
+      ir.TreeNode value, _MemberData memberData) {
+    _writeDataKind(DataKind.treeNode);
+    _writeTreeNode(value, memberData);
+  }
+
+  /// Writes a reference to the potentially `null` kernel tree node [value] in
+  /// the known [context] to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTreeNodeOrNullInContext].
+  void writeTreeNodeOrNullInContext(ir.TreeNode value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeTreeNodeInContextInternal(value, currentMemberData);
+    }
+  }
+
+  /// Writes references to the kernel tree node [values] in the known [context]
+  /// to this data sink. If [allowNull] is `true`, [values] is allowed to be
+  /// `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTreeNodesInContext].
+  void writeTreeNodesInContext(Iterable<ir.TreeNode> values,
+      {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ir.TreeNode value in values) {
+        writeTreeNodeInContextInternal(value, currentMemberData);
+      }
+    }
+  }
+
+  /// Writes the [map] from references to kernel tree nodes to [V] values in the
+  /// known [context] to this data sink, calling [f] to write each value to the
+  /// data sink. If [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTreeNodeMapInContext].
+  void writeTreeNodeMapInContext<V>(Map<ir.TreeNode, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((ir.TreeNode key, V value) {
+        writeTreeNodeInContextInternal(key, currentMemberData);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a reference to the kernel type parameter node [value] to this data
+  /// sink.
+  void writeTypeParameterNode(ir.TypeParameter value) {
+    _writeDataKind(DataKind.typeParameterNode);
+    _writeTypeParameter(value, null);
+  }
+
+  void _writeTypeParameter(ir.TypeParameter value, _MemberData memberData) {
+    ir.TreeNode parent = value.parent;
+    if (parent is ir.Class) {
+      _sinkWriter.writeEnum(_TypeParameterKind.cls);
+      _writeClassNode(parent);
+      _sinkWriter.writeInt(parent.typeParameters.indexOf(value));
+    } else if (parent is ir.FunctionNode) {
+      _sinkWriter.writeEnum(_TypeParameterKind.functionNode);
+      _writeFunctionNode(parent, memberData);
+      _sinkWriter.writeInt(parent.typeParameters.indexOf(value));
+    } else {
+      throw UnsupportedError(
+          "Unsupported TypeParameter parent ${parent.runtimeType}");
+    }
+  }
+
+  /// Writes references to the kernel type parameter node [values] to this data
+  /// sink.
+  /// If [allowNull] is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTypeParameterNodes].
+  void writeTypeParameterNodes(Iterable<ir.TypeParameter> values,
+      {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ir.TypeParameter value in values) {
+        writeTypeParameterNode(value);
+      }
+    }
+  }
+
+  /// Writes the type [value] to this data sink. If [allowNull] is `true`,
+  /// [value] is allowed to be `null`.
+  void writeDartType(DartType value, {bool allowNull = false}) {
+    _writeDataKind(DataKind.dartType);
+    _writeDartType(value, [], allowNull: allowNull);
+  }
+
+  void _writeDartType(
+      DartType value, List<FunctionTypeVariable> functionTypeVariables,
+      {bool allowNull = false}) {
+    if (value == null) {
+      if (!allowNull) {
+        throw UnsupportedError("Missing DartType is not allowed.");
+      }
+      writeEnum(DartTypeKind.none);
+    } else {
+      value.writeToDataSink(this, functionTypeVariables);
+    }
+  }
+
+  /// Writes the type [values] to this data sink. If [allowNull] is `true`,
+  /// [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readDartTypes].
+  void writeDartTypes(Iterable<DartType> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (DartType value in values) {
+        writeDartType(value);
+      }
+    }
+  }
+
+  /// Writes the kernel type node [value] to this data sink. If [allowNull] is
+  /// `true`, [value] is allowed to be `null`.
+  void writeDartTypeNode(ir.DartType value, {bool allowNull = false}) {
+    _writeDataKind(DataKind.dartTypeNode);
+    _writeDartTypeNode(value, [], allowNull: allowNull);
+  }
+
+  void _writeDartTypeNode(
+      ir.DartType value, List<ir.TypeParameter> functionTypeVariables,
+      {bool allowNull = false}) {
+    if (value == null) {
+      if (!allowNull) {
+        throw UnsupportedError("Missing ir.DartType node is not allowed.");
+      }
+      writeEnum(DartTypeNodeKind.none);
+    } else {
+      value.accept1(_dartTypeNodeWriter, functionTypeVariables);
+    }
+  }
+
+  /// Writes the kernel type node [values] to this data sink. If [allowNull] is
+  /// `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readDartTypeNodes].
+  void writeDartTypeNodes(Iterable<ir.DartType> values,
+      {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ir.DartType value in values) {
+        writeDartTypeNode(value);
+      }
+    }
+  }
+
+  /// Writes the source span [value] to this data sink.
+  void writeSourceSpan(SourceSpan value) {
+    _writeDataKind(DataKind.sourceSpan);
+    _writeUri(value.uri);
+    _sinkWriter.writeInt(value.begin);
+    _sinkWriter.writeInt(value.end);
+  }
+
+  /// Writes a reference to the indexed library [value] to this data sink.
+  void writeLibrary(IndexedLibrary value) {
+    _entityWriter.writeLibraryToDataSink(this, value);
+  }
+
+  /// Writes a reference to the potentially `null` indexed library [value]
+  /// to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readLibraryOrNull].
+  void writeLibraryOrNull(IndexedLibrary value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeLibrary(value);
+    }
+  }
+
+  /// Writes the [map] from references to indexed libraries to [V] values to
+  /// this data sink, calling [f] to write each value to the data sink. If
+  /// [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readLibraryMap].
+  void writeLibraryMap<V>(Map<LibraryEntity, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((LibraryEntity library, V value) {
+        writeLibrary(library);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a reference to the indexed class [value] to this data sink.
+  void writeClass(IndexedClass value) {
+    _entityWriter.writeClassToDataSink(this, value);
+  }
+
+  /// Writes a reference to the potentially `null` indexed class [value]
+  /// to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readClassOrNull].
+  void writeClassOrNull(IndexedClass value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeClass(value);
+    }
+  }
+
+  /// Writes references to the indexed class [values] to this data sink. If
+  /// [allowNull] is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readClasses].
+  void writeClasses(Iterable<ClassEntity> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (IndexedClass value in values) {
+        writeClass(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from references to indexed classes to [V] values to this
+  /// data sink, calling [f] to write each value to the data sink. If
+  /// [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readClassMap].
+  void writeClassMap<V>(Map<ClassEntity, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((ClassEntity cls, V value) {
+        writeClass(cls);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a reference to the indexed member [value] to this data sink.
+  void writeMember(IndexedMember value) {
+    _entityWriter.writeMemberToDataSink(this, value);
+  }
+
+  /// Writes a reference to the potentially `null` indexed member [value]
+  /// to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readMemberOrNull].
+  void writeMemberOrNull(IndexedMember value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeMember(value);
+    }
+  }
+
+  /// Writes references to the indexed member [values] to this data sink. If
+  /// [allowNull] is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readMembers].
+  void writeMembers(Iterable<MemberEntity> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (IndexedMember value in values) {
+        writeMember(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from references to indexed members to [V] values to this
+  /// data sink, calling [f] to write each value to the data sink. If
+  /// [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readMemberMap].
+  void writeMemberMap<V>(
+      Map<MemberEntity, V> map, void f(MemberEntity member, V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((MemberEntity member, V value) {
+        writeMember(member);
+        f(member, value);
+      });
+    }
+  }
+
+  /// Writes a reference to the indexed type variable [value] to this data sink.
+  void writeTypeVariable(IndexedTypeVariable value) {
+    _entityWriter.writeTypeVariableToDataSink(this, value);
+  }
+
+  /// Writes the [map] from references to indexed type variables to [V] values
+  /// to this data sink, calling [f] to write each value to the data sink. If
+  /// [allowNull] is `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readTypeVariableMap].
+  void writeTypeVariableMap<V>(Map<IndexedTypeVariable, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((IndexedTypeVariable key, V value) {
+        writeTypeVariable(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a reference to the local [value] to this data sink.
+  void writeLocal(Local local) {
+    if (local is JLocal) {
+      writeEnum(LocalKind.jLocal);
+      writeMember(local.memberContext);
+      writeInt(local.localIndex);
+    } else if (local is ThisLocal) {
+      writeEnum(LocalKind.thisLocal);
+      writeClass(local.enclosingClass);
+    } else if (local is BoxLocal) {
+      writeEnum(LocalKind.boxLocal);
+      writeClass(local.container);
+    } else if (local is AnonymousClosureLocal) {
+      writeEnum(LocalKind.anonymousClosureLocal);
+      writeClass(local.closureClass);
+    } else if (local is TypeVariableLocal) {
+      writeEnum(LocalKind.typeVariableLocal);
+      writeTypeVariable(local.typeVariable);
+    } else {
+      throw UnsupportedError("Unsupported local ${local.runtimeType}");
+    }
+  }
+
+  /// Writes a reference to the potentially `null` local [value]
+  /// to this data sink.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readLocalOrNull].
+  void writeLocalOrNull(Local value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeLocal(value);
+    }
+  }
+
+  /// Writes references to the local [values] to this data sink. If [allowNull]
+  /// is `true`, [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readLocals].
+  void writeLocals(Iterable<Local> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (Local value in values) {
+        writeLocal(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from references to locals to [V] values to this data
+  /// sink, calling [f] to write each value to the data sink. If [allowNull] is
+  /// `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readLocalMap].
+  void writeLocalMap<V>(Map<Local, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((Local key, V value) {
+        writeLocal(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes the constant [value] to this data sink.
+  void writeConstant(ConstantValue value) {
+    _writeDataKind(DataKind.constant);
+    _writeConstant(value);
+  }
+
+  void _writeConstant(ConstantValue value) {
+    _constantIndex.write(value, _writeConstantInternal);
+  }
+
+  void _writeConstantInternal(ConstantValue value) {
+    _sinkWriter.writeEnum(value.kind);
+    switch (value.kind) {
+      case ConstantValueKind.BOOL:
+        BoolConstantValue constant = value;
+        writeBool(constant.boolValue);
+        break;
+      case ConstantValueKind.INT:
+        IntConstantValue constant = value;
+        _writeBigInt(constant.intValue);
+        break;
+      case ConstantValueKind.DOUBLE:
+        DoubleConstantValue constant = value;
+        _writeDoubleValue(constant.doubleValue);
+        break;
+      case ConstantValueKind.STRING:
+        StringConstantValue constant = value;
+        writeString(constant.stringValue);
+        break;
+      case ConstantValueKind.NULL:
+        break;
+      case ConstantValueKind.FUNCTION:
+        FunctionConstantValue constant = value;
+        IndexedFunction function = constant.element;
+        writeMember(function);
+        writeDartType(constant.type);
+        break;
+      case ConstantValueKind.LIST:
+        ListConstantValue constant = value;
+        writeDartType(constant.type);
+        writeConstants(constant.entries);
+        break;
+      case ConstantValueKind.SET:
+        constant_system.JavaScriptSetConstant constant = value;
+        writeDartType(constant.type);
+        writeConstant(constant.entries);
+        break;
+      case ConstantValueKind.MAP:
+        constant_system.JavaScriptMapConstant constant = value;
+        writeDartType(constant.type);
+        writeConstant(constant.keyList);
+        writeConstants(constant.values);
+        writeBool(constant.onlyStringKeys);
+        break;
+      case ConstantValueKind.CONSTRUCTED:
+        ConstructedConstantValue constant = value;
+        writeDartType(constant.type);
+        writeMemberMap(constant.fields,
+            (MemberEntity member, ConstantValue value) => writeConstant(value));
+        break;
+      case ConstantValueKind.TYPE:
+        TypeConstantValue constant = value;
+        writeDartType(constant.representedType);
+        writeDartType(constant.type);
+        break;
+      case ConstantValueKind.INSTANTIATION:
+        InstantiationConstantValue constant = value;
+        writeDartTypes(constant.typeArguments);
+        writeConstant(constant.function);
+        break;
+      case ConstantValueKind.NON_CONSTANT:
+        break;
+      case ConstantValueKind.INTERCEPTOR:
+        InterceptorConstantValue constant = value;
+        writeClass(constant.cls);
+        break;
+      case ConstantValueKind.DEFERRED_GLOBAL:
+        DeferredGlobalConstantValue constant = value;
+        writeConstant(constant.referenced);
+        writeOutputUnitReference(constant.unit);
+        break;
+      case ConstantValueKind.DUMMY_INTERCEPTOR:
+        break;
+      case ConstantValueKind.LATE_SENTINEL:
+        break;
+      case ConstantValueKind.UNREACHABLE:
+        break;
+      case ConstantValueKind.JS_NAME:
+        JsNameConstantValue constant = value;
+        writeJsNode(constant.name);
+        break;
+    }
+  }
+
+  /// Writes the potentially `null` constant [value] to this data sink.
+  void writeConstantOrNull(ConstantValue value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeConstant(value);
+    }
+  }
+
+  /// Writes constant [values] to this data sink. If [allowNull] is `true`,
+  /// [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readConstants].
+  void writeConstants(Iterable<ConstantValue> values,
+      {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ConstantValue value in values) {
+        writeConstant(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from constant values to [V] values to this data sink,
+  /// calling [f] to write each value to the data sink. If [allowNull] is
+  /// `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readConstantMap].
+  void writeConstantMap<V>(Map<ConstantValue, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((ConstantValue key, V value) {
+        writeConstant(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes a double value to this data sink.
+  void writeDoubleValue(double value) {
+    _writeDataKind(DataKind.double);
+    _writeDoubleValue(value);
+  }
+
+  void _writeDoubleValue(double value) {
+    ByteData data = ByteData(8);
+    data.setFloat64(0, value);
+    writeInt(data.getUint16(0));
+    writeInt(data.getUint16(2));
+    writeInt(data.getUint16(4));
+    writeInt(data.getUint16(6));
+  }
+
+  /// Writes an integer of arbitrary value to this data sink.
+  ///
+  /// This is should only when the value is not known to be a non-negative
+  /// 30 bit integer. Otherwise [writeInt] should be used.
+  void writeIntegerValue(int value) {
+    _writeDataKind(DataKind.int);
+    _writeBigInt(BigInt.from(value));
+  }
+
+  void _writeBigInt(BigInt value) {
+    writeString(value.toString());
+  }
+
+  /// Writes the import [value] to this data sink.
+  void writeImport(ImportEntity value) {
+    _writeDataKind(DataKind.import);
+    _writeImport(value);
+  }
+
+  void _writeImport(ImportEntity value) {
+    _importIndex.write(value, _writeImportInternal);
+  }
+
+  void _writeImportInternal(ImportEntity value) {
+    // TODO(johnniwinther): Do we need to serialize non-deferred imports?
+    writeStringOrNull(value.name);
+    _writeUri(value.uri);
+    _writeUri(value.enclosingLibraryUri);
+    _writeBool(value.isDeferred);
+  }
+
+  /// Writes the potentially `null` import [value] to this data sink.
+  void writeImportOrNull(ImportEntity value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeImport(value);
+    }
+  }
+
+  /// Writes import [values] to this data sink. If [allowNull] is `true`,
+  /// [values] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readImports].
+  void writeImports(Iterable<ImportEntity> values, {bool allowNull = false}) {
+    if (values == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(values.length);
+      for (ImportEntity value in values) {
+        writeImport(value);
+      }
+    }
+  }
+
+  /// Writes the [map] from imports to [V] values to this data sink,
+  /// calling [f] to write each value to the data sink. If [allowNull] is
+  /// `true`, [map] is allowed to be `null`.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSourceReader.readImportMap].
+  void writeImportMap<V>(Map<ImportEntity, V> map, void f(V value),
+      {bool allowNull = false}) {
+    if (map == null) {
+      assert(allowNull);
+      writeInt(0);
+    } else {
+      writeInt(map.length);
+      map.forEach((ImportEntity key, V value) {
+        writeImport(key);
+        f(value);
+      });
+    }
+  }
+
+  /// Writes an abstract [value] to this data sink.
+  ///
+  /// This feature is only available a [CodegenWriter] has been registered.
+  void writeAbstractValue(AbstractValue value) {
+    assert(_codegenWriter != null,
+        "Can not serialize an AbstractValue without a registered codegen writer.");
+    _codegenWriter.writeAbstractValue(this, value);
+  }
+
+  /// Writes a reference to the output unit [value] to this data sink.
+  ///
+  /// This feature is only available a [CodegenWriter] has been registered.
+  void writeOutputUnitReference(OutputUnit value) {
+    assert(
+        _codegenWriter != null,
+        "Can not serialize an OutputUnit reference "
+        "without a registered codegen writer.");
+    _codegenWriter.writeOutputUnitReference(this, value);
+  }
+
+  /// Writes a js node [value] to this data sink.
+  ///
+  /// This feature is only available a [CodegenWriter] has been registered.
+  void writeJsNode(js.Node value) {
+    assert(_codegenWriter != null,
+        "Can not serialize a JS node without a registered codegen writer.");
+    _codegenWriter.writeJsNode(this, value);
+  }
+
+  /// Writes a potentially `null` js node [value] to this data sink.
+  ///
+  /// This feature is only available a [CodegenWriter] has been registered.
+  void writeJsNodeOrNull(js.Node value) {
+    writeBool(value != null);
+    if (value != null) {
+      writeJsNode(value);
+    }
+  }
+
+  /// Writes TypeRecipe [value] to this data sink.
+  ///
+  /// This feature is only available a [CodegenWriter] has been registered.
+  void writeTypeRecipe(TypeRecipe value) {
+    assert(_codegenWriter != null,
+        "Can not serialize a TypeRecipe without a registered codegen writer.");
+    _codegenWriter.writeTypeRecipe(this, value);
+  }
+
+  /// Register an [EntityWriter] with this data sink for non-default encoding
+  /// of entity references.
+  void registerEntityWriter(EntityWriter writer) {
+    assert(writer != null);
+    _entityWriter = writer;
+  }
+
+  /// Register a [CodegenWriter] with this data sink to support serialization
+  /// of codegen only data.
+  void registerCodegenWriter(CodegenWriter writer) {
+    assert(writer != null);
+    assert(_codegenWriter == null);
+    _codegenWriter = writer;
+  }
+
+  /// Invoke [f] in the context of [member]. This sets up support for
+  /// serialization of `ir.TreeNode`s using the `writeTreeNode*InContext`
+  /// methods.
+  void inMemberContext(ir.Member context, void f()) {
+    ir.Member oldMemberContext = _currentMemberContext;
+    _MemberData oldMemberData = _currentMemberData;
+    _currentMemberContext = context;
+    _currentMemberData = null;
+    f();
+    _currentMemberData = oldMemberData;
+    _currentMemberContext = oldMemberContext;
+  }
+
+  _MemberData get currentMemberData {
+    assert(_currentMemberContext != null,
+        "DataSink has no current member context.");
+    return _currentMemberData ??= _memberData[_currentMemberContext] ??=
+        _MemberData(_currentMemberContext);
+  }
+
+  _MemberData _getMemberData(ir.TreeNode node) {
+    ir.TreeNode member = node;
+    while (member is! ir.Member) {
+      if (member == null) {
+        throw UnsupportedError("No enclosing member of TreeNode "
+            "$node (${node.runtimeType})");
+      }
+      member = member.parent;
+    }
+    _writeMemberNode(member);
+    return _memberData[member] ??= _MemberData(member);
+  }
+
+  void _writeFunctionNode(ir.FunctionNode value, _MemberData memberData) {
+    ir.TreeNode parent = value.parent;
+    if (parent is ir.Procedure) {
+      _sinkWriter.writeEnum(_FunctionNodeKind.procedure);
+      _writeMemberNode(parent);
+    } else if (parent is ir.Constructor) {
+      _sinkWriter.writeEnum(_FunctionNodeKind.constructor);
+      _writeMemberNode(parent);
+    } else if (parent is ir.FunctionExpression) {
+      _sinkWriter.writeEnum(_FunctionNodeKind.functionExpression);
+      _writeTreeNode(parent, memberData);
+    } else if (parent is ir.FunctionDeclaration) {
+      _sinkWriter.writeEnum(_FunctionNodeKind.functionDeclaration);
+      _writeTreeNode(parent, memberData);
+    } else {
+      throw UnsupportedError(
+          "Unsupported FunctionNode parent ${parent.runtimeType}");
+    }
+  }
+
+  void _writeDataKind(DataKind kind) {
+    if (useDataKinds) _sinkWriter.writeEnum(kind);
+  }
+}
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
new file mode 100644
index 0000000..b43c1ad
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -0,0 +1,1336 @@
+// 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.
+
+part of 'serialization.dart';
+
+/// Interface handling [DataSourceReader] low-level data deserialization.
+///
+/// Each implementation of [DataSource] should have a corresponding
+/// [DataSink] for which it deserializes data.
+abstract class DataSource {
+  /// Deserialization of a section begin tag.
+  void begin(String tag);
+
+  /// Deserialization of a section end tag.
+  void end(String tag);
+
+  /// Deserialization of a string value.
+  String readString();
+
+  /// Deserialization of a non-negative integer value.
+  int readInt();
+
+  /// Deserialization of an enum value in [values].
+  E readEnum<E>(List<E> values);
+
+  /// Returns a string representation of the current state of the data source
+  /// useful for debugging in consistencies between serialization and
+  /// deserialization.
+  String get errorContext;
+}
+
+/// Deserialization reader
+///
+/// To be used with [DataSinkWriter] to read and write serialized data.
+/// Deserialization format is deferred to provided [DataSource].
+class DataSourceReader {
+  final DataSource _sourceReader;
+
+  static final List<ir.DartType> emptyListOfDartTypes =
+      List<ir.DartType>.filled(0, null, growable: false);
+
+  final bool useDataKinds;
+  DataSourceIndices importedIndices;
+  EntityReader _entityReader = const EntityReader();
+  ComponentLookup _componentLookup;
+  EntityLookup _entityLookup;
+  LocalLookup _localLookup;
+  CodegenReader _codegenReader;
+
+  IndexedSource<String> _stringIndex;
+  IndexedSource<Uri> _uriIndex;
+  IndexedSource<_MemberData> _memberNodeIndex;
+  IndexedSource<ImportEntity> _importIndex;
+  IndexedSource<ConstantValue> _constantIndex;
+
+  final Map<Type, IndexedSource> _generalCaches = {};
+
+  ir.Member _currentMemberContext;
+  _MemberData _currentMemberData;
+
+  IndexedSource<T> _createSource<T>() {
+    if (importedIndices == null || !importedIndices.caches.containsKey(T)) {
+      return IndexedSource<T>(this._sourceReader);
+    } else {
+      List<T> cacheCopy = importedIndices.caches[T].cacheAsList.toList();
+      return IndexedSource<T>(this._sourceReader, cache: cacheCopy);
+    }
+  }
+
+  DataSourceReader(this._sourceReader,
+      {this.useDataKinds = false, this.importedIndices}) {
+    _stringIndex = _createSource<String>();
+    _uriIndex = _createSource<Uri>();
+    _memberNodeIndex = _createSource<_MemberData>();
+    _importIndex = _createSource<ImportEntity>();
+    _constantIndex = _createSource<ConstantValue>();
+  }
+
+  /// Exports [DataSourceIndices] for use in other [DataSourceReader]s and
+  /// [DataSinkWriter]s.
+  DataSourceIndices exportIndices() {
+    var indices = DataSourceIndices();
+    indices.caches[String] = DataSourceTypeIndices(_stringIndex.cache);
+    indices.caches[Uri] = DataSourceTypeIndices(_uriIndex.cache);
+    indices.caches[ImportEntity] = DataSourceTypeIndices(_importIndex.cache);
+    // _memberNodeIndex needs two entries depending on if the indices will be
+    // consumed by a [DataSource] or [DataSink].
+    indices.caches[_MemberData] = DataSourceTypeIndices(_memberNodeIndex.cache);
+    indices.caches[ir.Member] = DataSourceTypeIndices<ir.Member, _MemberData>(
+        _memberNodeIndex.cache, (_MemberData data) => data?.node);
+    indices.caches[ConstantValue] = DataSourceTypeIndices(_constantIndex.cache);
+    _generalCaches.forEach((type, indexedSource) {
+      indices.caches[type] = DataSourceTypeIndices(indexedSource.cache);
+    });
+    return indices;
+  }
+
+  /// Registers that the section [tag] starts.
+  ///
+  /// This is used for debugging to verify that sections are correctly aligned
+  /// between serialization and deserialization.
+  void begin(String tag) {
+    if (useDataKinds) _sourceReader.begin(tag);
+  }
+
+  /// Registers that the section [tag] ends.
+  ///
+  /// This is used for debugging to verify that sections are correctly aligned
+  /// between serialization and deserialization.
+  void end(String tag) {
+    if (useDataKinds) _sourceReader.end(tag);
+  }
+
+  /// Registers a [ComponentLookup] object with this data source to support
+  /// deserialization of references to kernel nodes.
+  void registerComponentLookup(ComponentLookup componentLookup) {
+    assert(_componentLookup == null);
+    _componentLookup = componentLookup;
+  }
+
+  ComponentLookup get componentLookup {
+    assert(_componentLookup != null);
+    return _componentLookup;
+  }
+
+  /// Registers an [EntityLookup] object with this data source to support
+  /// deserialization of references to indexed entities.
+  void registerEntityLookup(EntityLookup entityLookup) {
+    assert(_entityLookup == null);
+    _entityLookup = entityLookup;
+  }
+
+  EntityLookup get entityLookup {
+    assert(_entityLookup != null);
+    return _entityLookup;
+  }
+
+  /// Registers an [EntityReader] with this data source for non-default encoding
+  /// of entity references.
+  void registerEntityReader(EntityReader reader) {
+    assert(reader != null);
+    _entityReader = reader;
+  }
+
+  /// Registers a [LocalLookup] object with this data source to support
+  void registerLocalLookup(LocalLookup localLookup) {
+    assert(_localLookup == null);
+    _localLookup = localLookup;
+  }
+
+  LocalLookup get localLookup {
+    assert(_localLookup != null);
+    return _localLookup;
+  }
+
+  /// Registers a [CodegenReader] with this data source to support
+  /// deserialization of codegen only data.
+  void registerCodegenReader(CodegenReader reader) {
+    assert(reader != null);
+    assert(_codegenReader == null);
+    _codegenReader = reader;
+  }
+
+  /// Unregisters the [CodegenReader] from this data source to remove support
+  /// for deserialization of codegen only data.
+  void deregisterCodegenReader(CodegenReader reader) {
+    assert(_codegenReader == reader);
+    _codegenReader = null;
+  }
+
+  /// Invoke [f] in the context of [member]. This sets up support for
+  /// deserialization of `ir.TreeNode`s using the `readTreeNode*InContext`
+  /// methods.
+  T inMemberContext<T>(ir.Member context, T f()) {
+    ir.Member oldMemberContext = _currentMemberContext;
+    _MemberData oldMemberData = _currentMemberData;
+    _currentMemberContext = context;
+    _currentMemberData = null;
+    T result = f();
+    _currentMemberData = oldMemberData;
+    _currentMemberContext = oldMemberContext;
+    return result;
+  }
+
+  _MemberData get currentMemberData {
+    assert(_currentMemberContext != null,
+        "DataSink has no current member context.");
+    return _currentMemberData ??= _getMemberData(_currentMemberContext);
+  }
+
+  /// Reads a reference to an [E] value from this data source. If the value has
+  /// not yet been deserialized, [f] is called to deserialize the value itself.
+  E readCached<E>(E f()) {
+    IndexedSource source = _generalCaches[E] ??= _createSource<E>();
+    return source.read(f);
+  }
+
+  /// Reads a potentially `null` [E] value from this data source, calling [f] to
+  /// read the non-null value from the data source.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeValueOrNull].
+  E readValueOrNull<E>(E f()) {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return f();
+    }
+    return null;
+  }
+
+  /// Reads a list of [E] values from this data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeList].
+  List<E> readList<E>(E f(), {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      list[i] = f();
+    }
+    return list;
+  }
+
+  bool readBool() {
+    _checkDataKind(DataKind.bool);
+    return _readBool();
+  }
+
+  /// Reads a boolean value from this data source.
+  bool _readBool() {
+    int value = _sourceReader.readInt();
+    assert(value == 0 || value == 1);
+    return value == 1;
+  }
+
+  /// Reads a non-negative 30 bit integer value from this data source.
+  int readInt() {
+    _checkDataKind(DataKind.uint30);
+    return _sourceReader.readInt();
+  }
+
+  /// Reads a potentially `null` non-negative integer value from this data
+  /// source.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeIntOrNull].
+  int readIntOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readInt();
+    }
+    return null;
+  }
+
+  /// Reads a string value from this data source.
+  String readString() {
+    _checkDataKind(DataKind.string);
+    return _readString();
+  }
+
+  String _readString() {
+    return _stringIndex.read(_sourceReader.readString);
+  }
+
+  /// Reads a potentially `null` string value from this data source.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeStringOrNull].
+  String readStringOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readString();
+    }
+    return null;
+  }
+
+  /// Reads a list of string values from this data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeStrings].
+  List<String> readStrings({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<String> list = List<String>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      list[i] = readString();
+    }
+    return list;
+  }
+
+  /// Reads a map from string values to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeStringMap].
+  Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<String, V> map = {};
+    for (int i = 0; i < count; i++) {
+      String key = readString();
+      V value = f();
+      map[key] = value;
+    }
+    return map;
+  }
+
+  /// Reads an enum value from the list of enum [values] from this data source.
+  ///
+  /// The [values] argument is intended to be the static `.values` field on
+  /// enum classes, for instance:
+  ///
+  ///    enum Foo { bar, baz }
+  ///    ...
+  ///    Foo foo = source.readEnum(Foo.values);
+  ///
+  E readEnum<E>(List<E> values) {
+    _checkDataKind(DataKind.enumValue);
+    return _sourceReader.readEnum(values);
+  }
+
+  /// Reads a URI value from this data source.
+  Uri readUri() {
+    _checkDataKind(DataKind.uri);
+    return _readUri();
+  }
+
+  Uri _readUri() {
+    return _uriIndex.read(_doReadUri);
+  }
+
+  Uri _doReadUri() {
+    return Uri.parse(_readString());
+  }
+
+  /// Reads a reference to a kernel library node from this data source.
+  ir.Library readLibraryNode() {
+    _checkDataKind(DataKind.libraryNode);
+    return _readLibraryData().node;
+  }
+
+  _LibraryData _readLibraryData() {
+    Uri canonicalUri = _readUri();
+    return componentLookup.getLibraryDataByUri(canonicalUri);
+  }
+
+  /// Reads a reference to a kernel class node from this data source.
+  ir.Class readClassNode() {
+    _checkDataKind(DataKind.classNode);
+    return _readClassData().node;
+  }
+
+  _ClassData _readClassData() {
+    _LibraryData library = _readLibraryData();
+    String name = _readString();
+    return library.lookupClassByName(name);
+  }
+
+  /// Reads a reference to a kernel class node from this data source.
+  ir.Typedef readTypedefNode() {
+    _checkDataKind(DataKind.typedefNode);
+    return _readTypedefNode();
+  }
+
+  ir.Typedef _readTypedefNode() {
+    _LibraryData library = _readLibraryData();
+    String name = _readString();
+    return library.lookupTypedef(name);
+  }
+
+  /// Reads a reference to a kernel member node from this data source.
+  ir.Member readMemberNode() {
+    _checkDataKind(DataKind.memberNode);
+    return _readMemberData().node;
+  }
+
+  _MemberData _readMemberData() {
+    return _memberNodeIndex.read(_readMemberDataInternal);
+  }
+
+  _MemberData _readMemberDataInternal() {
+    MemberContextKind kind = _sourceReader.readEnum(MemberContextKind.values);
+    switch (kind) {
+      case MemberContextKind.cls:
+        _ClassData cls = _readClassData();
+        String name = _readString();
+        return cls.lookupMemberDataByName(name);
+      case MemberContextKind.library:
+        _LibraryData library = _readLibraryData();
+        String name = _readString();
+        return library.lookupMemberDataByName(name);
+    }
+    throw UnsupportedError("Unsupported _MemberKind $kind");
+  }
+
+  /// Reads a list of references to kernel member nodes from this data source.
+  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeMemberNodes].
+  List<E> readMemberNodes<E extends ir.Member>({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      ir.Member value = readMemberNode();
+      list[i] = value;
+    }
+    return list;
+  }
+
+  /// Reads a map from kernel member nodes to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeMemberNodeMap].
+  Map<K, V> readMemberNodeMap<K extends ir.Member, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      ir.Member node = readMemberNode();
+      V value = f();
+      map[node] = value;
+    }
+    return map;
+  }
+
+  /// Reads a kernel name node from this data source.
+  ir.Name readName() {
+    String text = readString();
+    ir.Library library = readValueOrNull(readLibraryNode);
+    return ir.Name(text, library);
+  }
+
+  /// Reads a kernel library dependency node from this data source.
+  ir.LibraryDependency readLibraryDependencyNode() {
+    ir.Library library = readLibraryNode();
+    int index = readInt();
+    return library.dependencies[index];
+  }
+
+  /// Reads a potentially `null` kernel library dependency node from this data
+  /// source.
+  ir.LibraryDependency readLibraryDependencyNodeOrNull() {
+    return readValueOrNull(readLibraryDependencyNode);
+  }
+
+  /// Reads a reference to a kernel tree node from this data source.
+  ir.TreeNode readTreeNode() {
+    _checkDataKind(DataKind.treeNode);
+    return _readTreeNode(null);
+  }
+
+  ir.TreeNode _readTreeNode(_MemberData memberData) {
+    _TreeNodeKind kind = _sourceReader.readEnum(_TreeNodeKind.values);
+    switch (kind) {
+      case _TreeNodeKind.cls:
+        return _readClassData().node;
+      case _TreeNodeKind.member:
+        return _readMemberData().node;
+      case _TreeNodeKind.functionDeclarationVariable:
+        ir.FunctionDeclaration functionDeclaration = _readTreeNode(memberData);
+        return functionDeclaration.variable;
+      case _TreeNodeKind.functionNode:
+        return _readFunctionNode(memberData);
+      case _TreeNodeKind.typeParameter:
+        return _readTypeParameter(memberData);
+      case _TreeNodeKind.constant:
+        memberData ??= _readMemberData();
+        ir.ConstantExpression expression = _readTreeNode(memberData);
+        ir.Constant constant =
+            memberData.getConstantByIndex(expression, _sourceReader.readInt());
+        return ConstantReference(expression, constant);
+      case _TreeNodeKind.node:
+        memberData ??= _readMemberData();
+        int index = _sourceReader.readInt();
+        ir.TreeNode treeNode = memberData.getTreeNodeByIndex(index);
+        assert(
+            treeNode != null,
+            "No TreeNode found for index $index in "
+            "${memberData.node}.${_sourceReader.errorContext}");
+        return treeNode;
+    }
+    throw UnsupportedError("Unexpected _TreeNodeKind $kind");
+  }
+
+  /// Reads a reference to a potentially `null` kernel tree node from this data
+  /// source.
+  ir.TreeNode readTreeNodeOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readTreeNode();
+    }
+    return null;
+  }
+
+  /// Reads a list of references to kernel tree nodes from this data source.
+  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeTreeNodes].
+  List<E> readTreeNodes<E extends ir.TreeNode>({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      ir.TreeNode node = readTreeNode();
+      list[i] = node;
+    }
+    return list;
+  }
+
+  /// Reads a map from kernel tree nodes to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeTreeNodeMap].
+  Map<K, V> readTreeNodeMap<K extends ir.TreeNode, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      ir.TreeNode node = readTreeNode();
+      V value = f();
+      map[node] = value;
+    }
+    return map;
+  }
+
+  /// Reads a reference to a kernel tree node in the known [context] from this
+  /// data source.
+  ir.TreeNode readTreeNodeInContext() {
+    return readTreeNodeInContextInternal(currentMemberData);
+  }
+
+  ir.TreeNode readTreeNodeInContextInternal(_MemberData memberData) {
+    _checkDataKind(DataKind.treeNode);
+    return _readTreeNode(memberData);
+  }
+
+  /// Reads a reference to a potentially `null` kernel tree node in the known
+  /// [context] from this data source.
+  ir.TreeNode readTreeNodeOrNullInContext() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readTreeNodeInContextInternal(currentMemberData);
+    }
+    return null;
+  }
+
+  /// Reads a list of references to kernel tree nodes in the known [context]
+  /// from this data source. If [emptyAsNull] is `true`, `null` is returned
+  /// instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeTreeNodesInContext].
+  List<E> readTreeNodesInContext<E extends ir.TreeNode>(
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      ir.TreeNode node = readTreeNodeInContextInternal(currentMemberData);
+      list[i] = node;
+    }
+    return list;
+  }
+
+  /// Reads a map from kernel tree nodes to [V] values in the known [context]
+  /// from this data source, calling [f] to read each value from the data
+  /// source. If [emptyAsNull] is `true`, `null` is returned instead of an empty
+  /// map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeTreeNodeMapInContext].
+  Map<K, V> readTreeNodeMapInContext<K extends ir.TreeNode, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      ir.TreeNode node = readTreeNodeInContextInternal(currentMemberData);
+      V value = f();
+      map[node] = value;
+    }
+    return map;
+  }
+
+  /// Reads a reference to a kernel type parameter node from this data source.
+  ir.TypeParameter readTypeParameterNode() {
+    _checkDataKind(DataKind.typeParameterNode);
+    return _readTypeParameter(null);
+  }
+
+  ir.TypeParameter _readTypeParameter(_MemberData memberData) {
+    _TypeParameterKind kind = _sourceReader.readEnum(_TypeParameterKind.values);
+    switch (kind) {
+      case _TypeParameterKind.cls:
+        ir.Class cls = _readClassData().node;
+        return cls.typeParameters[_sourceReader.readInt()];
+      case _TypeParameterKind.functionNode:
+        ir.FunctionNode functionNode = _readFunctionNode(memberData);
+        return functionNode.typeParameters[_sourceReader.readInt()];
+    }
+    throw UnsupportedError("Unexpected _TypeParameterKind kind $kind");
+  }
+
+  /// Reads a list of references to kernel type parameter nodes from this data
+  /// source. If [emptyAsNull] is `true`, `null` is returned instead of an empty
+  /// list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeTypeParameterNodes].
+  List<ir.TypeParameter> readTypeParameterNodes({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<ir.TypeParameter> list = List<ir.TypeParameter>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      list[i] = readTypeParameterNode();
+    }
+    return list;
+  }
+
+  /// Reads a type from this data source. If [allowNull], the returned type is
+  /// allowed to be `null`.
+  DartType readDartType({bool allowNull = false}) {
+    _checkDataKind(DataKind.dartType);
+    DartType type = DartType.readFromDataSource(this, []);
+    assert(type != null || allowNull);
+    return type;
+  }
+
+  /// Reads a list of types from this data source. If [emptyAsNull] is `true`,
+  /// `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeDartTypes].
+  List<DartType> readDartTypes({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<DartType> list = List<DartType>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      list[i] = readDartType();
+    }
+    return list;
+  }
+
+  /// Reads a kernel type node from this data source. If [allowNull], the
+  /// returned type is allowed to be `null`.
+  ir.DartType readDartTypeNode({bool allowNull = false}) {
+    _checkDataKind(DataKind.dartTypeNode);
+    ir.DartType type = _readDartTypeNode([]);
+    assert(type != null || allowNull);
+    return type;
+  }
+
+  ir.DartType _readDartTypeNode(List<ir.TypeParameter> functionTypeVariables) {
+    DartTypeNodeKind kind = readEnum(DartTypeNodeKind.values);
+    switch (kind) {
+      case DartTypeNodeKind.none:
+        return null;
+      case DartTypeNodeKind.voidType:
+        return const ir.VoidType();
+      case DartTypeNodeKind.invalidType:
+        return const ir.InvalidType();
+      case DartTypeNodeKind.doesNotComplete:
+        return const DoesNotCompleteType();
+      case DartTypeNodeKind.neverType:
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        return ir.NeverType.fromNullability(nullability);
+      case DartTypeNodeKind.typeParameterType:
+        ir.TypeParameter typeParameter = readTypeParameterNode();
+        ir.Nullability typeParameterTypeNullability =
+            readEnum(ir.Nullability.values);
+        ir.DartType promotedBound = _readDartTypeNode(functionTypeVariables);
+        return ir.TypeParameterType(
+            typeParameter, typeParameterTypeNullability, promotedBound);
+      case DartTypeNodeKind.functionTypeVariable:
+        int index = readInt();
+        assert(0 <= index && index < functionTypeVariables.length);
+        ir.Nullability typeParameterTypeNullability =
+            readEnum(ir.Nullability.values);
+        ir.DartType promotedBound = _readDartTypeNode(functionTypeVariables);
+        return ir.TypeParameterType(functionTypeVariables[index],
+            typeParameterTypeNullability, promotedBound);
+      case DartTypeNodeKind.functionType:
+        begin(functionTypeNodeTag);
+        int typeParameterCount = readInt();
+        List<ir.TypeParameter> typeParameters = List<ir.TypeParameter>.generate(
+            typeParameterCount, (int index) => ir.TypeParameter());
+        functionTypeVariables =
+            List<ir.TypeParameter>.from(functionTypeVariables)
+              ..addAll(typeParameters);
+        for (int index = 0; index < typeParameterCount; index++) {
+          typeParameters[index].name = readString();
+          typeParameters[index].bound =
+              _readDartTypeNode(functionTypeVariables);
+          typeParameters[index].defaultType =
+              _readDartTypeNode(functionTypeVariables);
+        }
+        ir.DartType returnType = _readDartTypeNode(functionTypeVariables);
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        int requiredParameterCount = readInt();
+        List<ir.DartType> positionalParameters =
+            _readDartTypeNodes(functionTypeVariables);
+        int namedParameterCount = readInt();
+        List<ir.NamedType> namedParameters =
+            List<ir.NamedType>.filled(namedParameterCount, null);
+        for (int index = 0; index < namedParameterCount; index++) {
+          String name = readString();
+          bool isRequired = readBool();
+          ir.DartType type = _readDartTypeNode(functionTypeVariables);
+          namedParameters[index] =
+              ir.NamedType(name, type, isRequired: isRequired);
+        }
+        ir.TypedefType typedefType = _readDartTypeNode(functionTypeVariables);
+        end(functionTypeNodeTag);
+        return ir.FunctionType(positionalParameters, returnType, nullability,
+            namedParameters: namedParameters,
+            typeParameters: typeParameters,
+            requiredParameterCount: requiredParameterCount,
+            typedefType: typedefType);
+
+      case DartTypeNodeKind.interfaceType:
+        ir.Class cls = readClassNode();
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        List<ir.DartType> typeArguments =
+            _readDartTypeNodes(functionTypeVariables);
+        return ir.InterfaceType(cls, nullability, typeArguments);
+      case DartTypeNodeKind.thisInterfaceType:
+        ir.Class cls = readClassNode();
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        List<ir.DartType> typeArguments =
+            _readDartTypeNodes(functionTypeVariables);
+        return ThisInterfaceType(cls, nullability, typeArguments);
+      case DartTypeNodeKind.exactInterfaceType:
+        ir.Class cls = readClassNode();
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        List<ir.DartType> typeArguments =
+            _readDartTypeNodes(functionTypeVariables);
+        return ExactInterfaceType(cls, nullability, typeArguments);
+      case DartTypeNodeKind.typedef:
+        ir.Typedef typedef = readTypedefNode();
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        List<ir.DartType> typeArguments =
+            _readDartTypeNodes(functionTypeVariables);
+        return ir.TypedefType(typedef, nullability, typeArguments);
+      case DartTypeNodeKind.dynamicType:
+        return const ir.DynamicType();
+      case DartTypeNodeKind.futureOrType:
+        ir.Nullability nullability = readEnum(ir.Nullability.values);
+        ir.DartType typeArgument = _readDartTypeNode(functionTypeVariables);
+        return ir.FutureOrType(typeArgument, nullability);
+      case DartTypeNodeKind.nullType:
+        return const ir.NullType();
+    }
+    throw UnsupportedError("Unexpected DartTypeKind $kind");
+  }
+
+  /// Reads a list of kernel type nodes from this data source. If [emptyAsNull]
+  /// is `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeDartTypeNodes].
+  List<ir.DartType> readDartTypeNodes({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<ir.DartType> list = List<ir.DartType>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      list[i] = readDartTypeNode();
+    }
+    return list;
+  }
+
+  List<ir.DartType> _readDartTypeNodes(
+      List<ir.TypeParameter> functionTypeVariables) {
+    int count = readInt();
+    if (count == 0) return emptyListOfDartTypes;
+    List<ir.DartType> types = List<ir.DartType>.filled(count, null);
+    for (int index = 0; index < count; index++) {
+      types[index] = _readDartTypeNode(functionTypeVariables);
+    }
+    return types;
+  }
+
+  /// Reads a source span from this data source.
+  SourceSpan readSourceSpan() {
+    _checkDataKind(DataKind.sourceSpan);
+    Uri uri = _readUri();
+    int begin = _sourceReader.readInt();
+    int end = _sourceReader.readInt();
+    return SourceSpan(uri, begin, end);
+  }
+
+  /// Reads a reference to an indexed library from this data source.
+  IndexedLibrary readLibrary() {
+    return _entityReader.readLibraryFromDataSource(this, entityLookup);
+  }
+
+  /// Reads a reference to a potentially `null` indexed library from this data
+  /// source.
+  IndexedLibrary readLibraryOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readLibrary();
+    }
+    return null;
+  }
+
+  /// Reads a library from library entities to [V] values
+  /// from this data source, calling [f] to read each value from the data
+  /// source. If [emptyAsNull] is `true`, `null` is returned instead of an empty
+  /// map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeLibraryMap].
+  Map<K, V> readLibraryMap<K extends LibraryEntity, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      LibraryEntity library = readLibrary();
+      V value = f();
+      map[library] = value;
+    }
+    return map;
+  }
+
+  /// Reads a reference to an indexed class from this data source.
+  IndexedClass readClass() {
+    return _entityReader.readClassFromDataSource(this, entityLookup);
+  }
+
+  /// Reads a reference to a potentially `null` indexed class from this data
+  /// source.
+  IndexedClass readClassOrNull() {
+    bool hasClass = readBool();
+    if (hasClass) {
+      return readClass();
+    }
+    return null;
+  }
+
+  /// Reads a list of references to indexed classes from this data source.
+  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeClasses].
+  List<E> readClasses<E extends ClassEntity>({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      ClassEntity cls = readClass();
+      list[i] = cls;
+    }
+    return list;
+  }
+
+  /// Reads a map from indexed classes to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeClassMap].
+  Map<K, V> readClassMap<K extends ClassEntity, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      ClassEntity cls = readClass();
+      V value = f();
+      map[cls] = value;
+    }
+    return map;
+  }
+
+  /// Reads a reference to an indexed member from this data source.
+  IndexedMember readMember() {
+    return _entityReader.readMemberFromDataSource(this, entityLookup);
+  }
+
+  /// Reads a reference to a potentially `null` indexed member from this data
+  /// source.
+  IndexedMember readMemberOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readMember();
+    }
+    return null;
+  }
+
+  /// Reads a list of references to indexed members from this data source.
+  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeMembers].
+  List<E> readMembers<E extends MemberEntity>({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      MemberEntity member = readMember();
+      list[i] = member;
+    }
+    return list;
+  }
+
+  /// Reads a map from indexed members to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeMemberMap].
+  Map<K, V> readMemberMap<K extends MemberEntity, V>(V f(MemberEntity member),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      MemberEntity member = readMember();
+      V value = f(member);
+      map[member] = value;
+    }
+    return map;
+  }
+
+  /// Reads a reference to an indexed type variable from this data source.
+  IndexedTypeVariable readTypeVariable() {
+    return _entityReader.readTypeVariableFromDataSource(this, entityLookup);
+  }
+
+  /// Reads a map from indexed type variable to [V] values from this data
+  /// source, calling [f] to read each value from the data source. If
+  /// [emptyAsNull] is `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeTypeVariableMap].
+  Map<K, V> readTypeVariableMap<K extends IndexedTypeVariable, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      IndexedTypeVariable node = readTypeVariable();
+      V value = f();
+      map[node] = value;
+    }
+    return map;
+  }
+
+  /// Reads a reference to a local from this data source.
+  Local readLocal() {
+    LocalKind kind = readEnum(LocalKind.values);
+    switch (kind) {
+      case LocalKind.jLocal:
+        MemberEntity memberContext = readMember();
+        int localIndex = readInt();
+        return localLookup.getLocalByIndex(memberContext, localIndex);
+      case LocalKind.thisLocal:
+        ClassEntity cls = readClass();
+        return ThisLocal(cls);
+      case LocalKind.boxLocal:
+        ClassEntity cls = readClass();
+        return BoxLocal(cls);
+      case LocalKind.anonymousClosureLocal:
+        ClassEntity cls = readClass();
+        return AnonymousClosureLocal(cls);
+      case LocalKind.typeVariableLocal:
+        TypeVariableEntity typeVariable = readTypeVariable();
+        return TypeVariableLocal(typeVariable);
+    }
+    throw UnsupportedError("Unexpected local kind $kind");
+  }
+
+  /// Reads a reference to a potentially `null` local from this data source.
+  Local readLocalOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readLocal();
+    }
+    return null;
+  }
+
+  /// Reads a list of references to locals from this data source. If
+  /// [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeLocals].
+  List<E> readLocals<E extends Local>({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      Local local = readLocal();
+      list[i] = local;
+    }
+    return list;
+  }
+
+  /// Reads a map from locals to [V] values from this data source, calling [f]
+  /// to read each value from the data source. If [emptyAsNull] is `true`,
+  /// `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeLocalMap].
+  Map<K, V> readLocalMap<K extends Local, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      Local local = readLocal();
+      V value = f();
+      map[local] = value;
+    }
+    return map;
+  }
+
+  /// Reads a constant value from this data source.
+  ConstantValue readConstant() {
+    _checkDataKind(DataKind.constant);
+    return _readConstant();
+  }
+
+  ConstantValue _readConstant() {
+    return _constantIndex.read(_readConstantInternal);
+  }
+
+  ConstantValue _readConstantInternal() {
+    ConstantValueKind kind = _sourceReader.readEnum(ConstantValueKind.values);
+    switch (kind) {
+      case ConstantValueKind.BOOL:
+        bool value = readBool();
+        return BoolConstantValue(value);
+      case ConstantValueKind.INT:
+        BigInt value = _readBigInt();
+        return IntConstantValue(value);
+      case ConstantValueKind.DOUBLE:
+        double value = _readDoubleValue();
+        return DoubleConstantValue(value);
+      case ConstantValueKind.STRING:
+        String value = readString();
+        return StringConstantValue(value);
+      case ConstantValueKind.NULL:
+        return const NullConstantValue();
+      case ConstantValueKind.FUNCTION:
+        IndexedFunction function = readMember();
+        DartType type = readDartType();
+        return FunctionConstantValue(function, type);
+      case ConstantValueKind.LIST:
+        DartType type = readDartType();
+        List<ConstantValue> entries = readConstants();
+        return ListConstantValue(type, entries);
+      case ConstantValueKind.SET:
+        DartType type = readDartType();
+        MapConstantValue entries = readConstant();
+        return constant_system.JavaScriptSetConstant(type, entries);
+      case ConstantValueKind.MAP:
+        DartType type = readDartType();
+        ListConstantValue keyList = readConstant();
+        List<ConstantValue> values = readConstants();
+        bool onlyStringKeys = readBool();
+        return constant_system.JavaScriptMapConstant(
+            type, keyList, values, onlyStringKeys);
+      case ConstantValueKind.CONSTRUCTED:
+        InterfaceType type = readDartType();
+        Map<FieldEntity, ConstantValue> fields =
+            readMemberMap<FieldEntity, ConstantValue>(
+                (MemberEntity member) => readConstant());
+        return ConstructedConstantValue(type, fields);
+      case ConstantValueKind.TYPE:
+        DartType representedType = readDartType();
+        DartType type = readDartType();
+        return TypeConstantValue(representedType, type);
+      case ConstantValueKind.INSTANTIATION:
+        List<DartType> typeArguments = readDartTypes();
+        ConstantValue function = readConstant();
+        return InstantiationConstantValue(typeArguments, function);
+      case ConstantValueKind.NON_CONSTANT:
+        return NonConstantValue();
+      case ConstantValueKind.INTERCEPTOR:
+        ClassEntity cls = readClass();
+        return InterceptorConstantValue(cls);
+      case ConstantValueKind.DEFERRED_GLOBAL:
+        ConstantValue constant = readConstant();
+        OutputUnit unit = readOutputUnitReference();
+        return DeferredGlobalConstantValue(constant, unit);
+      case ConstantValueKind.DUMMY_INTERCEPTOR:
+        return DummyInterceptorConstantValue();
+      case ConstantValueKind.LATE_SENTINEL:
+        return LateSentinelConstantValue();
+      case ConstantValueKind.UNREACHABLE:
+        return UnreachableConstantValue();
+      case ConstantValueKind.JS_NAME:
+        js.LiteralString name = readJsNode();
+        return JsNameConstantValue(name);
+    }
+    throw UnsupportedError("Unexpected constant value kind ${kind}.");
+  }
+
+  /// Reads a potentially `null` constant value from this data source.
+  ConstantValue readConstantOrNull() {
+    bool hasClass = readBool();
+    if (hasClass) {
+      return readConstant();
+    }
+    return null;
+  }
+
+  /// Reads a list of constant values from this data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeConstants].
+  List<E> readConstants<E extends ConstantValue>({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<E> list = List<E>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      ConstantValue value = readConstant();
+      list[i] = value;
+    }
+    return list;
+  }
+
+  /// Reads a map from constant values to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeConstantMap].
+  Map<K, V> readConstantMap<K extends ConstantValue, V>(V f(),
+      {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<K, V> map = {};
+    for (int i = 0; i < count; i++) {
+      ConstantValue key = readConstant();
+      V value = f();
+      map[key] = value;
+    }
+    return map;
+  }
+
+  /// Reads a double value from this data source.
+  double readDoubleValue() {
+    _checkDataKind(DataKind.double);
+    return _readDoubleValue();
+  }
+
+  double _readDoubleValue() {
+    ByteData data = ByteData(8);
+    data.setUint16(0, readInt());
+    data.setUint16(2, readInt());
+    data.setUint16(4, readInt());
+    data.setUint16(6, readInt());
+    return data.getFloat64(0);
+  }
+
+  /// Reads an integer of arbitrary value from this data source.
+  ///
+  /// This is should only when the value is not known to be a non-negative
+  /// 30 bit integer. Otherwise [readInt] should be used.
+  int readIntegerValue() {
+    _checkDataKind(DataKind.int);
+    return _readBigInt().toInt();
+  }
+
+  BigInt _readBigInt() {
+    return BigInt.parse(readString());
+  }
+
+  ImportEntity readImport() {
+    _checkDataKind(DataKind.import);
+    return _readImport();
+  }
+
+  /// Reads a import from this data source.
+  ImportEntity _readImport() {
+    return _importIndex.read(_readImportInternal);
+  }
+
+  ImportEntity _readImportInternal() {
+    String name = readStringOrNull();
+    Uri uri = _readUri();
+    Uri enclosingLibraryUri = _readUri();
+    bool isDeferred = _readBool();
+    return ImportEntity(isDeferred, name, uri, enclosingLibraryUri);
+  }
+
+  /// Reads a potentially `null` import from this data source.
+  ImportEntity readImportOrNull() {
+    bool hasClass = readBool();
+    if (hasClass) {
+      return readImport();
+    }
+    return null;
+  }
+
+  /// Reads a list of imports from this data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeImports].
+  List<ImportEntity> readImports({bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    List<ImportEntity> list = List<ImportEntity>.filled(count, null);
+    for (int i = 0; i < count; i++) {
+      list[i] = readImport();
+    }
+    return list;
+  }
+
+  /// Reads a map from imports to [V] values from this data source,
+  /// calling [f] to read each value from the data source. If [emptyAsNull] is
+  /// `true`, `null` is returned instead of an empty map.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeImportMap].
+  Map<ImportEntity, V> readImportMap<V>(V f(), {bool emptyAsNull = false}) {
+    int count = readInt();
+    if (count == 0 && emptyAsNull) return null;
+    Map<ImportEntity, V> map = {};
+    for (int i = 0; i < count; i++) {
+      ImportEntity key = readImport();
+      V value = f();
+      map[key] = value;
+    }
+    return map;
+  }
+
+  /// Reads an [AbstractValue] from this data source.
+  ///
+  /// This feature is only available a [CodegenReader] has been registered.
+  AbstractValue readAbstractValue() {
+    assert(
+        _codegenReader != null,
+        "Can not deserialize an AbstractValue "
+        "without a registered codegen reader.");
+    return _codegenReader.readAbstractValue(this);
+  }
+
+  /// Reads a reference to an [OutputUnit] from this data source.
+  ///
+  /// This feature is only available a [CodegenReader] has been registered.
+  OutputUnit readOutputUnitReference() {
+    assert(
+        _codegenReader != null,
+        "Can not deserialize an OutputUnit reference "
+        "without a registered codegen reader.");
+    return _codegenReader.readOutputUnitReference(this);
+  }
+
+  /// Reads a [js.Node] value from this data source.
+  ///
+  /// This feature is only available a [CodegenReader] has been registered.
+  js.Node readJsNode() {
+    assert(_codegenReader != null,
+        "Can not deserialize a JS node without a registered codegen reader.");
+    return _codegenReader.readJsNode(this);
+  }
+
+  /// Reads a potentially `null` [js.Node] value from this data source.
+  ///
+  /// This feature is only available a [CodegenReader] has been registered.
+  js.Node readJsNodeOrNull() {
+    bool hasValue = readBool();
+    if (hasValue) {
+      return readJsNode();
+    }
+    return null;
+  }
+
+  /// Reads a [TypeRecipe] value from this data source.
+  ///
+  /// This feature is only available a [CodegenReader] has been registered.
+  TypeRecipe readTypeRecipe() {
+    assert(_codegenReader != null,
+        "Can not deserialize a TypeRecipe without a registered codegen reader.");
+    return _codegenReader.readTypeRecipe(this);
+  }
+
+  _MemberData _getMemberData(ir.Member node) {
+    _LibraryData libraryData =
+        componentLookup.getLibraryDataByUri(node.enclosingLibrary.importUri);
+    if (node.enclosingClass != null) {
+      _ClassData classData = libraryData.lookupClassByNode(node.enclosingClass);
+      return classData.lookupMemberDataByNode(node);
+    } else {
+      return libraryData.lookupMemberDataByNode(node);
+    }
+  }
+
+  ir.FunctionNode _readFunctionNode(_MemberData memberData) {
+    _FunctionNodeKind kind = _sourceReader.readEnum(_FunctionNodeKind.values);
+    switch (kind) {
+      case _FunctionNodeKind.procedure:
+        ir.Procedure procedure = _readMemberData().node;
+        return procedure.function;
+      case _FunctionNodeKind.constructor:
+        ir.Constructor constructor = _readMemberData().node;
+        return constructor.function;
+      case _FunctionNodeKind.functionExpression:
+        ir.FunctionExpression functionExpression = _readTreeNode(memberData);
+        return functionExpression.function;
+      case _FunctionNodeKind.functionDeclaration:
+        ir.FunctionDeclaration functionDeclaration = _readTreeNode(memberData);
+        return functionDeclaration.function;
+    }
+    throw UnsupportedError("Unexpected _FunctionNodeKind $kind");
+  }
+
+  void _checkDataKind(DataKind expectedKind) {
+    if (!useDataKinds) return;
+    DataKind actualKind = _sourceReader.readEnum(DataKind.values);
+    assert(
+        actualKind == expectedKind,
+        "Invalid data kind. "
+        "Expected $expectedKind, "
+        "found $actualKind.${_sourceReader.errorContext}");
+  }
+}
diff --git a/pkg/compiler/lib/src/serialization/strategies.dart b/pkg/compiler/lib/src/serialization/strategies.dart
index 65c8824..d73bddd 100644
--- a/pkg/compiler/lib/src/serialization/strategies.dart
+++ b/pkg/compiler/lib/src/serialization/strategies.dart
@@ -73,7 +73,7 @@
   List<int> serializeGlobalTypeInferenceResults(
       DataSourceIndices indices, GlobalTypeInferenceResults results) {
     ByteSink byteSink = ByteSink();
-    DataSink sink = BinarySink(byteSink,
+    DataSinkWriter sink = DataSinkWriter(BinaryDataSink(byteSink),
         useDataKinds: useDataKinds, importedIndices: indices);
     serializeGlobalTypeInferenceResultsToSink(results, sink);
     return byteSink.builder.takeBytes();
@@ -89,8 +89,8 @@
       JsClosedWorld closedWorld,
       DataSourceIndices indices,
       List<int> globalTypeInferenceResultsData) {
-    DataSource globalTypeInferenceResultsSource = BinarySourceImpl(
-        globalTypeInferenceResultsData,
+    DataSourceReader globalTypeInferenceResultsSource = DataSourceReader(
+        BinaryDataSource(globalTypeInferenceResultsData),
         useDataKinds: useDataKinds,
         importedIndices: indices);
     return deserializeGlobalTypeInferenceResultsFromSource(
@@ -106,7 +106,8 @@
   @override
   List<int> serializeClosedWorld(JsClosedWorld closedWorld) {
     ByteSink byteSink = ByteSink();
-    DataSink sink = BinarySink(byteSink, useDataKinds: useDataKinds);
+    DataSinkWriter sink =
+        DataSinkWriter(BinaryDataSink(byteSink), useDataKinds: useDataKinds);
     serializeClosedWorldToSink(closedWorld, sink);
     return byteSink.builder.takeBytes();
   }
@@ -119,7 +120,8 @@
       AbstractValueStrategy abstractValueStrategy,
       ir.Component component,
       List<int> data) {
-    DataSource source = BinarySourceImpl(data, useDataKinds: useDataKinds);
+    DataSourceReader source =
+        DataSourceReader(BinaryDataSource(data), useDataKinds: useDataKinds);
     var closedWorld = deserializeClosedWorldFromSource(options, reporter,
         environment, abstractValueStrategy, component, source);
     return ClosedWorldAndIndices(closedWorld, source.exportIndices());
@@ -135,8 +137,9 @@
   List<int> serializeGlobalTypeInferenceResults(
       DataSourceIndices indices, GlobalTypeInferenceResults results) {
     Uri uri = Uri.base.resolve('world.data');
-    DataSink sink = BinarySink(
-        BinaryOutputSinkAdapter(RandomAccessBinaryOutputSink(uri)),
+    DataSinkWriter sink = DataSinkWriter(
+        BinaryDataSink(
+            BinaryOutputSinkAdapter(RandomAccessBinaryOutputSink(uri))),
         useDataKinds: useDataKinds,
         importedIndices: indices);
     serializeGlobalTypeInferenceResultsToSink(results, sink);
@@ -153,8 +156,8 @@
       JsClosedWorld closedWorld,
       DataSourceIndices indices,
       List<int> globalTypeInferenceResultsData) {
-    DataSource globalTypeInferenceResultsSource = BinarySourceImpl(
-        globalTypeInferenceResultsData,
+    DataSourceReader globalTypeInferenceResultsSource = DataSourceReader(
+        BinaryDataSource(globalTypeInferenceResultsData),
         useDataKinds: useDataKinds,
         importedIndices: indices);
     return deserializeGlobalTypeInferenceResultsFromSource(
@@ -170,8 +173,9 @@
   @override
   List<int> serializeClosedWorld(JsClosedWorld closedWorld) {
     Uri uri = Uri.base.resolve('closed_world.data');
-    DataSink sink = BinarySink(
-        BinaryOutputSinkAdapter(RandomAccessBinaryOutputSink(uri)),
+    DataSinkWriter sink = DataSinkWriter(
+        BinaryDataSink(
+            BinaryOutputSinkAdapter(RandomAccessBinaryOutputSink(uri))),
         useDataKinds: useDataKinds);
     serializeClosedWorldToSink(closedWorld, sink);
     return File.fromUri(uri).readAsBytesSync();
@@ -185,7 +189,8 @@
       AbstractValueStrategy abstractValueStrategy,
       ir.Component component,
       List<int> data) {
-    DataSource source = BinarySourceImpl(data, useDataKinds: useDataKinds);
+    DataSourceReader source =
+        DataSourceReader(BinaryDataSource(data), useDataKinds: useDataKinds);
     var closedWorld = deserializeClosedWorldFromSource(options, reporter,
         environment, abstractValueStrategy, component, source);
     return ClosedWorldAndIndices(closedWorld, source.exportIndices());
@@ -202,8 +207,8 @@
   List<Object> serializeGlobalTypeInferenceResults(
       DataSourceIndices indices, GlobalTypeInferenceResults results) {
     List<Object> data = [];
-    DataSink sink =
-        ObjectSink(data, useDataKinds: useDataKinds, importedIndices: indices);
+    DataSinkWriter sink = DataSinkWriter(ObjectDataSink(data),
+        useDataKinds: useDataKinds, importedIndices: indices);
     serializeGlobalTypeInferenceResultsToSink(results, sink);
     return data;
   }
@@ -218,10 +223,8 @@
       JsClosedWorld closedWorld,
       DataSourceIndices indices,
       List<Object> globalTypeInferenceResultsData) {
-    DataSource globalTypeInferenceResultsSource = ObjectSource(
-        globalTypeInferenceResultsData,
-        useDataKinds: useDataKinds,
-        importedIndices: indices);
+    DataSourceReader globalTypeInferenceResultsSource =
+        DataSourceReader(ObjectDataSource(globalTypeInferenceResultsData));
     return deserializeGlobalTypeInferenceResultsFromSource(
         options,
         reporter,
@@ -235,7 +238,8 @@
   @override
   List<Object> serializeClosedWorld(JsClosedWorld closedWorld) {
     List<Object> data = [];
-    DataSink sink = ObjectSink(data, useDataKinds: useDataKinds);
+    DataSinkWriter sink =
+        DataSinkWriter(ObjectDataSink(data), useDataKinds: useDataKinds);
     serializeClosedWorldToSink(closedWorld, sink);
     return data;
   }
@@ -248,7 +252,8 @@
       AbstractValueStrategy abstractValueStrategy,
       ir.Component component,
       List<Object> data) {
-    DataSource source = ObjectSource(data, useDataKinds: useDataKinds);
+    DataSourceReader source =
+        DataSourceReader(ObjectDataSource(data), useDataKinds: useDataKinds);
     var closedWorld = deserializeClosedWorldFromSource(options, reporter,
         environment, abstractValueStrategy, component, source);
     return ClosedWorldAndIndices(closedWorld, source.exportIndices());
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 15889be..c69d158 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -38,7 +38,7 @@
 }
 
 void serializeGlobalTypeInferenceResultsToSink(
-    GlobalTypeInferenceResults results, DataSink sink) {
+    GlobalTypeInferenceResults results, DataSinkWriter sink) {
   JsClosedWorld closedWorld = results.closedWorld;
   GlobalLocalsMap globalLocalsMap = results.globalLocalsMap;
   InferredData inferredData = results.inferredData;
@@ -55,7 +55,7 @@
     AbstractValueStrategy abstractValueStrategy,
     ir.Component component,
     JsClosedWorld closedWorld,
-    DataSource source) {
+    DataSourceReader source) {
   source.registerComponentLookup(ComponentLookup(component));
   source.registerEntityLookup(ClosedEntityLookup(closedWorld.elementMap));
   GlobalLocalsMap globalLocalsMap = GlobalLocalsMap.readFromDataSource(
@@ -66,7 +66,8 @@
       closedWorld.elementMap, closedWorld, globalLocalsMap, inferredData);
 }
 
-void serializeClosedWorldToSink(JsClosedWorld closedWorld, DataSink sink) {
+void serializeClosedWorldToSink(
+    JsClosedWorld closedWorld, DataSinkWriter sink) {
   closedWorld.writeToDataSink(sink);
   sink.close();
 }
@@ -77,7 +78,7 @@
     Environment environment,
     AbstractValueStrategy abstractValueStrategy,
     ir.Component component,
-    DataSource source) {
+    DataSourceReader source) {
   return JsClosedWorld.readFromDataSource(
       options, reporter, environment, abstractValueStrategy, component, source);
 }
@@ -177,7 +178,8 @@
       _reporter.log('Writing data to ${_options.writeModularAnalysisUri}');
       api.BinaryOutputSink dataOutput =
           _outputProvider.createBinarySink(_options.writeModularAnalysisUri);
-      DataSink sink = BinarySink(BinaryOutputSinkAdapter(dataOutput));
+      DataSinkWriter sink =
+          DataSinkWriter(BinaryDataSink(BinaryOutputSinkAdapter(dataOutput)));
       data.toDataSink(sink);
       sink.close();
     });
@@ -196,11 +198,12 @@
       //   ModuleData.fromDataSource(source);
 
       BytesSink bytes = BytesSink();
-      BinarySink binarySink = BinarySink(bytes, useDataKinds: true);
+      DataSinkWriter binarySink =
+          DataSinkWriter(BinaryDataSink(bytes), useDataKinds: true);
       data.toDataSink(binarySink);
       binarySink.close();
-      var source =
-          BinarySourceImpl(bytes.builder.toBytes(), useDataKinds: true);
+      var source = DataSourceReader(BinaryDataSource(bytes.builder.toBytes()),
+          useDataKinds: true);
       source.registerComponentLookup(ComponentLookup(component));
       ModuleData.fromDataSource(source);
     }
@@ -213,7 +216,8 @@
       for (Uri uri in _options.modularAnalysisInputs) {
         api.Input<List<int>> dataInput =
             await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
-        DataSource source = BinarySourceImpl(dataInput.data);
+        DataSourceReader source =
+            DataSourceReader(BinaryDataSource(dataInput.data));
         source.registerComponentLookup(ComponentLookup(component));
         results.add(ModuleData.fromDataSource(source));
       }
@@ -226,7 +230,8 @@
       _reporter.log('Writing closed world to ${_options.writeClosedWorldUri}');
       api.BinaryOutputSink dataOutput =
           _outputProvider.createBinarySink(_options.writeClosedWorldUri);
-      DataSink sink = BinarySink(BinaryOutputSinkAdapter(dataOutput));
+      DataSinkWriter sink =
+          DataSinkWriter(BinaryDataSink(BinaryOutputSinkAdapter(dataOutput)));
       serializeClosedWorldToSink(closedWorld, sink);
     });
   }
@@ -240,8 +245,8 @@
       api.Input<List<int>> dataInput = await _provider.readFromUri(
           _options.readClosedWorldUri,
           inputKind: api.InputKind.binary);
-      DataSource source =
-          BinarySourceImpl(dataInput.data, stringInterner: _stringInterner);
+      DataSourceReader source = DataSourceReader(
+          BinaryDataSource(dataInput.data, stringInterner: _stringInterner));
       var closedWorld = deserializeClosedWorldFromSource(_options, _reporter,
           environment, abstractValueStrategy, component, source);
       return ClosedWorldAndIndices(closedWorld, source.exportIndices());
@@ -258,7 +263,8 @@
       _reporter.log('Writing data to ${_options.writeDataUri}');
       api.BinaryOutputSink dataOutput =
           _outputProvider.createBinarySink(_options.writeDataUri);
-      DataSink sink = BinarySink(BinaryOutputSinkAdapter(dataOutput),
+      DataSinkWriter sink = DataSinkWriter(
+          BinaryDataSink(BinaryOutputSinkAdapter(dataOutput)),
           importedIndices: indices);
       serializeGlobalTypeInferenceResultsToSink(results, sink);
     });
@@ -273,8 +279,8 @@
       _reporter.log('Reading data from ${_options.readDataUri}');
       api.Input<List<int>> dataInput = await _provider
           .readFromUri(_options.readDataUri, inputKind: api.InputKind.binary);
-      DataSource source = BinarySourceImpl(dataInput.data,
-          stringInterner: _stringInterner,
+      DataSourceReader source = DataSourceReader(
+          BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
           importedIndices: closedWorldAndIndices.indices);
       return deserializeGlobalTypeInferenceResultsFromSource(
           _options,
@@ -307,7 +313,8 @@
     measureSubtask('serialize codegen', () {
       Uri uri = Uri.parse('${_options.writeCodegenUri}$shard');
       api.BinaryOutputSink dataOutput = _outputProvider.createBinarySink(uri);
-      DataSink sink = BinarySink(BinaryOutputSinkAdapter(dataOutput),
+      DataSinkWriter sink = DataSinkWriter(
+          BinaryDataSink(BinaryOutputSinkAdapter(dataOutput)),
           importedIndices: indices);
       _reporter.log('Writing data to ${uri}');
       sink.registerEntityWriter(entityWriter);
@@ -352,8 +359,9 @@
       api.Input<List<int>> dataInput,
       DataSourceIndices importedIndices,
       Map<MemberEntity, CodegenResult> results) {
-    DataSource source = BinarySourceImpl(dataInput.data,
-        stringInterner: _stringInterner, importedIndices: importedIndices);
+    DataSourceReader source = DataSourceReader(
+        BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
+        importedIndices: importedIndices);
     backendStrategy.prepareCodegenReader(source);
     Map<MemberEntity, CodegenResult> codegenResults =
         source.readMemberMap((MemberEntity member) {
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index 1dc8cdd..0062fc9 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -82,7 +82,7 @@
   }
 
   /// Deserializes a [CallStructure] object from [source].
-  factory CallStructure.readFromDataSource(DataSource source) {
+  factory CallStructure.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     int argumentCount = source.readInt();
     List<String> namedArguments = source.readStrings();
@@ -92,7 +92,7 @@
   }
 
   /// Serializes this [CallStructure] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeInt(argumentCount);
     sink.writeStrings(namedArguments);
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
index 24cc4ce..a2e6d01 100644
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart
@@ -15,11 +15,11 @@
 abstract class ClassHierarchy {
   /// Deserializes a [ClassHierarchy] object from [source].
   factory ClassHierarchy.readFromDataSource(
-          DataSource source, CommonElements commonElements) =
+          DataSourceReader source, CommonElements commonElements) =
       ClassHierarchyImpl.readFromDataSource;
 
   /// Serializes this [ClassHierarchy] to [sink].
-  void writeToDataSink(DataSink sink);
+  void writeToDataSink(DataSinkWriter sink);
 
   /// Returns `true` if [cls] is either directly or indirectly instantiated.
   bool isInstantiated(ClassEntity cls);
@@ -170,7 +170,7 @@
       this._commonElements, this._classHierarchyNodes, this._classSets);
 
   factory ClassHierarchyImpl.readFromDataSource(
-      DataSource source, CommonElements commonElements) {
+      DataSourceReader source, CommonElements commonElements) {
     source.begin(tag);
     Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes =
         ClassHierarchyNodesMap();
@@ -192,7 +192,7 @@
   }
 
   @override
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeInt(_classSets.length);
     ClassHierarchyNode node =
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 5dc7629..f7c899d 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -213,7 +213,7 @@
 
   /// Deserializes a [ClassHierarchyNode] object from [source].
   factory ClassHierarchyNode.readFromDataSource(
-      DataSource source, Map<ClassEntity, ClassHierarchyNode> nodeMap) {
+      DataSourceReader source, Map<ClassEntity, ClassHierarchyNode> nodeMap) {
     source.begin(tag);
     IndexedClass cls = source.readClass();
     ClassHierarchyNode parentNode;
@@ -233,7 +233,7 @@
   }
 
   /// Serializes this [ClassHierarchyNode] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeClass(cls);
     sink.writeClassOrNull(parentNode?.cls);
@@ -541,7 +541,7 @@
 
   /// Deserializes a [ClassSet] object from [source].
   factory ClassSet.readFromDataSource(
-      DataSource source, Map<ClassEntity, ClassHierarchyNode> nodeMap) {
+      DataSourceReader source, Map<ClassEntity, ClassHierarchyNode> nodeMap) {
     source.begin(tag);
     ClassHierarchyNode node = nodeMap[source.readClass()];
     List<ClassHierarchyNode> subtypes = source.readList(() {
@@ -557,7 +557,7 @@
   }
 
   /// Serializes this [ClassSet] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeClass(node.cls);
     sink.writeList(_subtypes, (ClassHierarchyNode node) {
diff --git a/pkg/compiler/lib/src/universe/feature.dart b/pkg/compiler/lib/src/universe/feature.dart
index ca27733..a35a348 100644
--- a/pkg/compiler/lib/src/universe/feature.dart
+++ b/pkg/compiler/lib/src/universe/feature.dart
@@ -241,7 +241,7 @@
 
   GenericInstantiation(this.functionType, this.typeArguments);
 
-  factory GenericInstantiation.readFromDataSource(DataSource source) {
+  factory GenericInstantiation.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     DartType functionType = source.readDartType();
     List<DartType> typeArguments = source.readDartTypes();
@@ -249,7 +249,7 @@
     return GenericInstantiation(functionType, typeArguments);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartType(functionType);
     sink.writeDartTypes(typeArguments);
diff --git a/pkg/compiler/lib/src/universe/member_usage.dart b/pkg/compiler/lib/src/universe/member_usage.dart
index 451b6c5..f3fe0b1 100644
--- a/pkg/compiler/lib/src/universe/member_usage.dart
+++ b/pkg/compiler/lib/src/universe/member_usage.dart
@@ -839,7 +839,7 @@
 
   MemberAccess(this.reads, this.writes, this.invokes);
 
-  factory MemberAccess.readFromDataSource(DataSource source) {
+  factory MemberAccess.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     EnumSet<Access> reads = EnumSet.fixed(source.readInt());
     EnumSet<Access> writes = EnumSet.fixed(source.readInt());
@@ -848,7 +848,7 @@
     return MemberAccess(reads, writes, invokes);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeInt(reads.value);
     sink.writeInt(writes.value);
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index dddc39b..8ea7244 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -199,7 +199,7 @@
       CallStructure(0, null, typeArguments));
 
   /// Deserializes a [Selector] object from [source].
-  factory Selector.readFromDataSource(DataSource source) {
+  factory Selector.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     SelectorKind kind = source.readEnum(SelectorKind.values);
     bool isSetter = source.readBool();
@@ -212,7 +212,7 @@
   }
 
   /// Serializes this [Selector] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeEnum(kind);
     sink.writeBool(memberName.isSetter);
diff --git a/pkg/compiler/lib/src/universe/side_effects.dart b/pkg/compiler/lib/src/universe/side_effects.dart
index f4101839..4e8bab0 100644
--- a/pkg/compiler/lib/src/universe/side_effects.dart
+++ b/pkg/compiler/lib/src/universe/side_effects.dart
@@ -43,7 +43,7 @@
   SideEffects.fromFlags(this._flags);
 
   /// Deserializes a [SideEffects] object from [source].
-  factory SideEffects.readFromDataSource(DataSource source) {
+  factory SideEffects.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     int flags = source.readInt();
     source.end(tag);
@@ -51,7 +51,7 @@
   }
 
   /// Serializes this [SideEffects] to [sink].
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeInt(_flags);
     sink.end(tag);
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index bb33b0e..cffa3fc 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -59,7 +59,7 @@
     return DynamicUse(selector, otherReceiverConstraint, _typeArguments);
   }
 
-  factory DynamicUse.readFromDataSource(DataSource source) {
+  factory DynamicUse.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Selector selector = Selector.readFromDataSource(source);
     bool hasConstraint = source.readBool();
@@ -72,7 +72,7 @@
     return DynamicUse(selector, receiverConstraint, typeArguments);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     selector.writeToDataSink(sink);
     sink.writeBool(receiverConstraint != null);
@@ -215,7 +215,7 @@
     return true;
   }
 
-  factory StaticUse.readFromDataSource(DataSource source) {
+  factory StaticUse.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     MemberEntity element = source.readMember();
     StaticUseKind kind = source.readEnum(StaticUseKind.values);
@@ -234,7 +234,7 @@
         typeArguments: typeArguments);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     assert(element is MemberEntity, "Unsupported entity: $element");
     sink.writeMember(element);
@@ -727,7 +727,7 @@
         this.kind = kind,
         this.hashCode = Hashing.objectsHash(type, kind, deferredImport);
 
-  factory TypeUse.readFromDataSource(DataSource source) {
+  factory TypeUse.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     DartType type = source.readDartType();
     TypeUseKind kind = source.readEnum(TypeUseKind.values);
@@ -736,7 +736,7 @@
     return TypeUse.internal(type, kind, deferredImport);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeDartType(type);
     sink.writeEnum(kind);
@@ -900,14 +900,14 @@
 
   ConstantUse._(this.value);
 
-  factory ConstantUse.readFromDataSource(DataSource source) {
+  factory ConstantUse.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ConstantValue value = source.readConstant();
     source.end(tag);
     return ConstantUse._(value);
   }
 
-  void writeToDataSink(DataSink sink) {
+  void writeToDataSink(DataSinkWriter sink) {
     sink.begin(tag);
     sink.writeConstant(value);
     sink.end(tag);
diff --git a/pkg/compiler/test/deferred_loading/data/static_separate/lib1.dart b/pkg/compiler/test/deferred_loading/data/static_separate/lib1.dart
index 18c2288..329c0b3 100644
--- a/pkg/compiler/test/deferred_loading/data/static_separate/lib1.dart
+++ b/pkg/compiler/test/deferred_loading/data/static_separate/lib1.dart
@@ -24,22 +24,22 @@
 var x = const ConstClass(const ConstClass(1));
 
 /*class: C:
- class_unit=1{lib1},
- type_unit=1{lib1}
+ class_unit=3{lib1},
+ type_unit=3{lib1}
 */
 class C {
-  /*member: C.foo:member_unit=3{lib2}*/
+  /*member: C.foo:member_unit=1{lib2}*/
   static foo() {
-    /*closure_unit=3{lib2}*/ () {}(); // Hack to avoid inlining.
+    /*closure_unit=1{lib2}*/ () {}(); // Hack to avoid inlining.
     return 1;
   }
 
-  /*member: C.:member_unit=1{lib1}*/
+  /*member: C.:member_unit=3{lib1}*/
   C();
 
-  /*member: C.bar:member_unit=1{lib1}*/
+  /*member: C.bar:member_unit=3{lib1}*/
   bar() {
-    /*closure_unit=1{lib1}*/ () {}(); // Hack to avoid inlining.
+    /*closure_unit=3{lib1}*/ () {}(); // Hack to avoid inlining.
     return 1;
   }
 }
@@ -50,79 +50,79 @@
 */
 class C1 {
   /*member: C1.foo:
-   constants=[MapConstant({})=3{lib2}],
-   member_unit=3{lib2}
+   constants=[MapConstant({})=1{lib2}],
+   member_unit=1{lib2}
   */
   static var foo = const {};
   var bar = const {};
 }
 
 /*class: C2:
- class_unit=1{lib1},
- type_unit=1{lib1}
+ class_unit=3{lib1},
+ type_unit=3{lib1}
 */
 class C2 {
-  /*member: C2.foo:member_unit=3{lib2}*/
+  /*member: C2.foo:member_unit=1{lib2}*/
   static var foo = new Map<int, int>.from({1: 2});
 
-  /*member: C2.bar:member_unit=1{lib1}*/
+  /*member: C2.bar:member_unit=3{lib1}*/
   var bar = new Map<int, int>.from({1: 2});
 
-  /*member: C2.:member_unit=1{lib1}*/
+  /*member: C2.:member_unit=3{lib1}*/
   C2();
 }
 
 /*class: C3:
- class_unit=1{lib1},
- type_unit=1{lib1}
+ class_unit=3{lib1},
+ type_unit=3{lib1}
 */
 class C3 {
   /*member: C3.foo:
    constants=[ConstructedConstant(ConstClass(x=ConstructedConstant(ConstClass(x=IntConstant(1)))))=2{lib1, lib2}],
-   member_unit=3{lib2}
+   member_unit=1{lib2}
   */
   static final foo = const ConstClass(const ConstClass(1));
 
   /*member: C3.bar:
    constants=[ConstructedConstant(ConstClass(x=ConstructedConstant(ConstClass(x=IntConstant(1)))))=2{lib1, lib2}],
-   member_unit=1{lib1}
+   member_unit=3{lib1}
   */
   final bar = const ConstClass(const ConstClass(1));
 
-  /*member: C3.:member_unit=1{lib1}*/
+  /*member: C3.:member_unit=3{lib1}*/
   C3();
 }
 
 /*class: C4:
- class_unit=1{lib1},
- type_unit=1{lib1}
+ class_unit=3{lib1},
+ type_unit=3{lib1}
 */
 class C4 {
-  /*member: C4.foo:member_unit=3{lib2}*/
+  /*member: C4.foo:member_unit=1{lib2}*/
   static final foo = new Map<ConstClass, ConstClass>.from({x: x});
 
-  /*member: C4.bar:member_unit=1{lib1}*/
+  /*member: C4.bar:member_unit=3{lib1}*/
   final bar = new Map<ConstClass, ConstClass>.from({x: x});
 
-  /*member: C4.:member_unit=1{lib1}*/
+  /*member: C4.:member_unit=3{lib1}*/
   C4();
 }
 
 /*class: C5:
- class_unit=1{lib1},
- type_unit=1{lib1}
+ class_unit=3{lib1},
+ type_unit=3{lib1}
 */
 class C5 {
   static const foo = const [
     const {1: 3}
   ];
 
-  /*member: C5.:member_unit=1{lib1}*/
+  /*member: C5.:member_unit=3{lib1}*/
   C5();
 
-  /*member: C5.bar:member_unit=1{lib1}*/
+  /*member: C5.bar:member_unit=3{lib1}*/
   bar() {
-    /*closure_unit=1{lib1}*/ () {}(); // Hack to avoid inlining.
+    /*closure_unit=3{lib1}*/ () {}(); // Hack to avoid inlining.
     return 1;
   }
 }
diff --git a/pkg/compiler/test/deferred_loading/data/static_separate/lib2.dart b/pkg/compiler/test/deferred_loading/data/static_separate/lib2.dart
index 79c236c..92549e2 100644
--- a/pkg/compiler/test/deferred_loading/data/static_separate/lib2.dart
+++ b/pkg/compiler/test/deferred_loading/data/static_separate/lib2.dart
@@ -11,9 +11,9 @@
 
 /*member: foo:
  constants=[
-  ListConstant(<Map<int*,int*>*>[MapConstant(<int*, int*>{IntConstant(1): IntConstant(3)})])=3{lib2},
-  MapConstant(<int*, int*>{IntConstant(1): IntConstant(3)})=3{lib2}],
- member_unit=3{lib2}
+  ListConstant(<Map<int*,int*>*>[MapConstant(<int*, int*>{IntConstant(1): IntConstant(3)})])=1{lib2},
+  MapConstant(<int*, int*>{IntConstant(1): IntConstant(3)})=1{lib2}],
+ member_unit=1{lib2}
 */
 foo() {
   Expect.equals(1, C.foo());
diff --git a/pkg/compiler/test/deferred_loading/data/static_separate/main.dart b/pkg/compiler/test/deferred_loading/data/static_separate/main.dart
index 42aa6ee..2d35936 100644
--- a/pkg/compiler/test/deferred_loading/data/static_separate/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/static_separate/main.dart
@@ -4,12 +4,12 @@
 
 /*spec.library: 
  a_pre_fragments=[
-  p1: {units: [1{lib1}], usedBy: [], needs: []},
-  p2: {units: [3{lib2}], usedBy: [], needs: []},
+  p1: {units: [3{lib1}], usedBy: [], needs: []},
+  p2: {units: [1{lib2}], usedBy: [], needs: []},
   p3: {units: [2{lib1, lib2}], usedBy: [], needs: []}],
  b_finalized_fragments=[
-  f1: [1{lib1}],
-  f2: [3{lib2}],
+  f1: [3{lib1}],
+  f2: [1{lib2}],
   f3: [2{lib1, lib2}]],
  c_steps=[
   lib1=(f3, f1),
@@ -18,12 +18,12 @@
 
 /*two-frag|three-frag.library: 
  a_pre_fragments=[
-  p1: {units: [1{lib1}], usedBy: [p3], needs: []},
-  p2: {units: [3{lib2}], usedBy: [p3], needs: []},
+  p1: {units: [3{lib1}], usedBy: [p3], needs: []},
+  p2: {units: [1{lib2}], usedBy: [p3], needs: []},
   p3: {units: [2{lib1, lib2}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
-  f1: [1{lib1}],
-  f2: [3{lib2}],
+  f1: [3{lib1}],
+  f2: [1{lib2}],
   f3: [2{lib1, lib2}]],
  c_steps=[
   lib1=(f3, f1),
diff --git a/pkg/compiler/test/impact/impact_test.dart b/pkg/compiler/test/impact/impact_test.dart
index c3ff87b..7cec147 100644
--- a/pkg/compiler/test/impact/impact_test.dart
+++ b/pkg/compiler/test/impact/impact_test.dart
@@ -21,15 +21,8 @@
 main(List<String> args) {
   asyncTest(() async {
     Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
-    print('Testing direct computation of ResolutionImpact');
-    print('==================================================================');
-    useImpactDataForTesting = false;
-    await checkTests(dataDir, const ImpactDataComputer(),
-        args: args, testedConfigs: allSpecConfigs);
-
     print('Testing computation of ResolutionImpact through ImpactData');
     print('==================================================================');
-    useImpactDataForTesting = true;
     await checkTests(dataDir, const ImpactDataComputer(),
         args: args, testedConfigs: allSpecConfigs);
   });
diff --git a/pkg/dart2js_info/README.md b/pkg/dart2js_info/README.md
index 54f3a7a..1cfc18f 100644
--- a/pkg/dart2js_info/README.md
+++ b/pkg/dart2js_info/README.md
@@ -581,6 +581,7 @@
 ```
 
 Here's an example output snippet:
+
 ```
 Runtime Coverage Summary
 ========================================================================
diff --git a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
index 379746d..afca760 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
@@ -325,7 +325,7 @@
   MetaLetVariable(this.displayName) : super('$displayName@${++_uniqueId}');
 }
 
-class _VariableUseCounter extends BaseVisitor<void> {
+class _VariableUseCounter extends BaseVisitorVoid {
   final counts = <MetaLetVariable, int>{};
   @override
   void visitInterpolatedExpression(InterpolatedExpression node) {
@@ -336,7 +336,7 @@
   }
 }
 
-class _IdentFinder extends BaseVisitor<void> {
+class _IdentFinder extends BaseVisitorVoid {
   final String name;
   bool found = false;
   _IdentFinder(this.name);
diff --git a/pkg/dev_compiler/lib/src/compiler/js_utils.dart b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
index 73aeddc..e072a12 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_utils.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
@@ -33,7 +33,7 @@
   return v.mutated;
 }
 
-class MutationVisitor extends BaseVisitor<void> {
+class MutationVisitor extends BaseVisitorVoid {
   /// Using Identifier names instead of a more precise key may result in
   /// mutations being imprecisely reported when variables shadow each other.
   final mutated = <String>{};
@@ -46,7 +46,7 @@
 }
 
 /// Recursively clears all source information from all visited nodes.
-class SourceInformationClearer extends BaseVisitor<void> {
+class SourceInformationClearer extends BaseVisitorVoid {
   @override
   void visitNode(Node node) {
     node.visitChildren(this);
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index ee52937..fd2b9c8 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -813,7 +813,7 @@
   return finder.found;
 }
 
-class _IdentifierFinder extends js_ast.BaseVisitor<void> {
+class _IdentifierFinder extends js_ast.BaseVisitorVoid {
   String nameToFind;
   bool found = false;
 
@@ -830,7 +830,7 @@
   }
 }
 
-class YieldFinder extends js_ast.BaseVisitor<void> {
+class YieldFinder extends js_ast.BaseVisitorVoid {
   bool hasYield = false;
   bool hasThis = false;
   bool _nestedFunction = false;
@@ -880,7 +880,7 @@
   return finder.found;
 }
 
-class _ThisOrSuperFinder extends js_ast.BaseVisitor<void> {
+class _ThisOrSuperFinder extends js_ast.BaseVisitorVoid {
   bool found = false;
 
   static final instance = _ThisOrSuperFinder();
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index 1621087..8044d9f 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -4,212 +4,214 @@
 
 // @dart = 2.9
 
-// ignore_for_file: always_declare_return_types, prefer_single_quotes
+// ignore_for_file: always_declare_return_types
+// ignore_for_file: library_prefixes
 // ignore_for_file: non_constant_identifier_names
-// ignore_for_file: prefer_collection_literals, omit_local_variable_types
-// ignore_for_file: slash_for_doc_comments, unnecessary_new
+// ignore_for_file: omit_local_variable_types
+// ignore_for_file: prefer_collection_literals
+// ignore_for_file: prefer_single_quotes
 // ignore_for_file: unnecessary_brace_in_string_interps
+// ignore_for_file: unnecessary_new
 
-// Utilities for building JS ASTs at runtime.  Contains a builder class
-// and a parser that parses part of the language.
+/// Utilities for building JS ASTs at runtime. Contains a builder class and a
+/// parser that parses part of the language.
+library js_ast.builder;
 
-part of js_ast;
+import 'characters.dart' as charCodes;
+import 'nodes.dart';
+import 'template.dart';
 
-/**
- * Global template manager.  We should aim to have a fixed number of
- * templates. This implies that we do not use js('xxx') to parse text that is
- * constructed from values that depend on names in the Dart program.
- *
- * TODO(sra): Find the remaining places where js('xxx') used to parse an
- * unbounded number of expression, or institute a cache policy.
- */
+/// Global template manager.
+///
+/// We should aim to have a fixed number of templates. This implies that we do
+/// not use js('xxx') to parse text that is constructed from values that depend
+/// on names in the Dart program.
+// TODO(sra): Find the remaining places where js('xxx') used to parse an
+// unbounded number of expression, or institute a cache policy.
 TemplateManager templateManager = TemplateManager();
 
-/**
-
-[js] is a singleton instance of JsBuilder.  JsBuilder is a set of conveniences
-for constructing JavaScript ASTs.
-
-[string] and [number] are used to create leaf AST nodes:
-
-    var s = js.string('hello');    //  s = new LiteralString('"hello"')
-    var n = js.number(123);        //  n = new LiteralNumber(123)
-
-In the line above `a --> b` means Dart expression `a` evaluates to a JavaScript
-AST that would pretty-print as `b`.
-
-The [call] method constructs an Expression AST.
-
-No argument
-
-    js('window.alert("hello")')  -->  window.alert("hello")
-
-The input text can contain placeholders `#` that are replaced with provided
-arguments.  A single argument can be passed directly:
-
-    js('window.alert(#)', s)   -->  window.alert("hello")
-
-Multiple arguments are passed as a list:
-
-    js('# + #', [s, s])  -->  "hello" + "hello"
-
-The [statement] method constructs a Statement AST, but is otherwise like the
-[call] method.  This constructs a Return AST:
-
-    var ret = js.statement('return #;', n);  -->  return 123;
-
-A placeholder in a Statement context must be followed by a semicolon ';'.  You
-can think of a statement placeholder as being `#;` to explain why the output
-still has one semicolon:
-
-    js.statement('if (happy) #;', ret)
-    -->
-    if (happy)
-      return 123;
-
-If the placeholder is not followed by a semicolon, it is part of an expression.
-Here the placeholder is in the position of the function in a function call:
-
-    var vFoo = new Identifier('foo');
-    js.statement('if (happy) #("Happy!")', vFoo)
-    -->
-    if (happy)
-      foo("Happy!");
-
-Generally, a placeholder in an expression position requires an Expression AST as
-an argument and a placeholder in a statement position requires a Statement AST.
-An expression will be converted to a Statement if needed by creating an
-ExpressionStatement.  A String argument will be converted into a Identifier and
-requires that the string is a JavaScript identifier.
-
-    js('# + 1', vFoo)       -->  foo + 1
-    js('# + 1', 'foo')      -->  foo + 1
-    js('# + 1', 'foo.bar')  -->  assertion failure
-
-Some placeholder positions are _splicing contexts_.  A function argument list is
-a splicing expression context.  A placeholder in a splicing expression context
-can take a single Expression (or String, converted to Identifier) or an
-Iterable of Expressions (and/or Strings).
-
-    // non-splicing argument:
-    js('#(#)', ['say', s])        -->  say("hello")
-    // splicing arguments:
-    js('#(#)', ['say', []])       -->  say()
-    js('#(#)', ['say', [s]])      -->  say("hello")
-    js('#(#)', ['say', [s, n]])   -->  say("hello", 123)
-
-A splicing context can be used to append 'lists' and add extra elements:
-
-    js('foo(#, #, 1)', [ ['a', n], s])       -->  foo(a, 123, "hello", 1)
-    js('foo(#, #, 1)', [ ['a', n], [s, n]])  -->  foo(a, 123, "hello", 123, 1)
-    js('foo(#, #, 1)', [ [], [s, n]])        -->  foo("hello", 123, 1)
-    js('foo(#, #, 1)', [ [], [] ])           -->  foo(1)
-
-The generation of a compile-time optional argument expression can be chosen by
-providing an empty or singleton list.
-
-In addition to Expressions and Statements, there are Parameters, which occur
-only in the parameter list of a function expression or declaration.
-Placeholders in parameter positions behave like placeholders in Expression
-positions, except only Parameter AST nodes are permitted.  String arguments for
-parameter placeholders are converted to Parameter AST nodes.
-
-    var pFoo = new Parameter('foo')
-    js('function(#) { return #; }', [pFoo, vFoo])
-    -->
-    function(foo) { return foo; }
-
-Expressions and Parameters are not compatible with each other's context:
-
-    js('function(#) { return #; }', [vFoo, vFoo]) --> error
-    js('function(#) { return #; }', [pFoo, pFoo]) --> error
-
-The parameter context is a splicing context.  When combined with the
-context-sensitive conversion of Strings, this simplifies the construction of
-trampoline-like functions:
-
-    var args = ['a', 'b'];
-    js('function(#) { return f(this, #); }', [args, args])
-    -->
-    function(a, b) { return f(this, a, b); }
-
-A statement placeholder in a Block is also in a splicing context.  In addition
-to splicing Iterables, statement placeholders in a Block will also splice a
-Block or an EmptyStatement.  This flattens nested blocks and allows blocks to be
-appended.
-
-    var b1 = js.statement('{ 1; 2; }');
-    var sEmpty = new Emptystatement();
-    js.statement('{ #; #; #; #; }', [sEmpty, b1, b1, sEmpty])
-    -->
-    { 1; 2; 1; 2; }
-
-A placeholder in the context of an if-statement condition also accepts a Dart
-bool argument, which selects the then-part or else-part of the if-statement:
-
-    js.statement('if (#) return;', vFoo)   -->  if (foo) return;
-    js.statement('if (#) return;', true)   -->  return;
-    js.statement('if (#) return;', false)  -->  ;   // empty statement
-    var eTrue = new LiteralBool(true);
-    js.statement('if (#) return;', eTrue)  -->  if (true) return;
-
-Combined with block splicing, if-statement condition context placeholders allows
-the creation of templates that select code depending on variables.
-
-    js.statement('{ 1; if (#) 2; else { 3; 4; } 5;}', true)
-    --> { 1; 2; 5; }
-
-    js.statement('{ 1; if (#) 2; else { 3; 4; } 5;}', false)
-    --> { 1; 3; 4; 5; }
-
-A placeholder following a period in a property access is in a property access
-context.  This is just like an expression context, except String arguments are
-converted to JavaScript property accesses.  In JavaScript, `a.b` is short-hand
-for `a["b"]`:
-
-    js('a[#]', vFoo)  -->  a[foo]
-    js('a[#]', s)     -->  a.hello    (i.e. a["hello"]).
-    js('a[#]', 'x')   -->  a[x]
-
-    js('a.#', vFoo)   -->  a[foo]
-    js('a.#', s)      -->  a.hello    (i.e. a["hello"])
-    js('a.#', 'x')    -->  a.x        (i.e. a["x"])
-
-(Question - should `.#` be restricted to permit only String arguments? The
-template should probably be written with `[]` if non-strings are accepted.)
-
-
-Object initializers allow placeholders in the key property name position:
-
-    js('{#:1, #:2}',  [s, 'bye'])    -->  {hello: 1, bye: 2}
-
-
-What is not implemented:
-
- -  Array initializers and object initializers could support splicing.  In the
-    array case, we would need some way to know if an ArrayInitializer argument
-    should be splice or is intended as a single value.
-
- -  There are no placeholders in definition contexts:
-
-        function #(){}
-        var # = 1;
-
-*/
+/// [js] is a singleton instance of JsBuilder.
+///
+/// JsBuilder is a set of conveniences for constructing JavaScript ASTs.
+///
+/// [string] and [number] are used to create leaf AST nodes:
+///
+///     var s = js.string('hello');    //  s = new LiteralString('"hello"')
+///     var n = js.number(123);        //  n = new LiteralNumber(123)
+///
+/// In the line above `a --> b` means Dart expression `a` evaluates to a
+/// JavaScript AST that would pretty-print as `b`.
+///
+/// The [call] method constructs an Expression AST.
+///
+/// No argument
+///
+///     js('window.alert("hello")')  -->  window.alert("hello")
+///
+/// The input text can contain placeholders `#` that are replaced with provided
+/// arguments. A single argument can be passed directly:
+///
+///     js('window.alert(#)', s)   -->  window.alert("hello")
+///
+/// Multiple arguments are passed as a list:
+///
+///     js('# + #', [s, s])  -->  "hello" + "hello"
+///
+/// The [statement] method constructs a Statement AST, but is otherwise like the
+/// [call] method. This constructs a Return AST:
+///
+///     var ret = js.statement('return #;', n);  -->  return 123;
+///
+/// A placeholder in a Statement context must be followed by a semicolon ';'.
+/// You can think of a statement placeholder as being `#;` to explain why the
+/// output still has one semicolon:
+///
+///     js.statement('if (happy) #;', ret)
+///     -->
+///     if (happy)
+///       return 123;
+///
+/// If the placeholder is not followed by a semicolon, it is part of an
+/// expression. Here the placeholder is in the position of the function in a
+/// function call:
+///
+///     var vFoo = new Identifier('foo');
+///     js.statement('if (happy) #("Happy!")', vFoo)
+///     -->
+///     if (happy)
+///       foo("Happy!");
+///
+/// Generally, a placeholder in an expression position requires an Expression
+/// AST as an argument and a placeholder in a statement position requires a
+/// Statement AST. An expression will be converted to a Statement if needed by
+/// creating an ExpressionStatement. A String argument will be converted into a
+/// Identifier and requires that the string is a JavaScript identifier.
+///
+///     js('# + 1', vFoo)       -->  foo + 1
+///     js('# + 1', 'foo')      -->  foo + 1
+///     js('# + 1', 'foo.bar')  -->  assertion failure
+///
+/// Some placeholder positions are _splicing contexts_. A function argument list
+/// is a splicing expression context. A placeholder in a splicing expression
+/// context can take a single Expression (or String, converted to Identifier) or
+/// an Iterable of Expressions (and/or Strings).
+///
+///     // non-splicing argument:
+///     js('#(#)', ['say', s])        -->  say("hello")
+///     // splicing arguments:
+///     js('#(#)', ['say', []])       -->  say()
+///     js('#(#)', ['say', [s]])      -->  say("hello")
+///     js('#(#)', ['say', [s, n]])   -->  say("hello", 123)
+///
+/// A splicing context can be used to append 'lists' and add extra elements:
+///
+///     js('foo(#, #, 1)', [ ['a', n], s])       -->  foo(a, 123, "hello", 1)
+///     js('foo(#, #, 1)', [ ['a', n], [s, n]])  -->  foo(a, 123, "hello", 123, 1)
+///     js('foo(#, #, 1)', [ [], [s, n]])        -->  foo("hello", 123, 1)
+///     js('foo(#, #, 1)', [ [], [] ])           -->  foo(1)
+///
+/// The generation of a compile-time optional argument expression can be chosen
+/// by providing an empty or singleton list.
+///
+/// In addition to Expressions and Statements, there are Parameters, which occur
+/// only in the parameter list of a function expression or declaration.
+/// Placeholders in parameter positions behave like placeholders in Expression
+/// positions, except only Parameter AST nodes are permitted. String arguments
+/// for parameter placeholders are converted to Parameter AST nodes.
+///
+///     var pFoo = new Parameter('foo')
+///     js('function(#) { return #; }', [pFoo, vFoo])
+///     -->
+///     function(foo) { return foo; }
+///
+/// Expressions and Parameters are not compatible with each other's context:
+///
+///     js('function(#) { return #; }', [vFoo, vFoo]) --> error
+///     js('function(#) { return #; }', [pFoo, pFoo]) --> error
+///
+/// The parameter context is a splicing context. When combined with the
+/// context-sensitive conversion of Strings, this simplifies the construction of
+/// trampoline-like functions:
+///
+///     var args = ['a', 'b'];
+///     js('function(#) { return f(this, #); }', [args, args])
+///     -->
+///     function(a, b) { return f(this, a, b); }
+///
+/// A statement placeholder in a Block is also in a splicing context. In
+/// addition to splicing Iterables, statement placeholders in a Block will also
+/// splice a Block or an EmptyStatement. This flattens nested blocks and allows
+/// blocks to be appended.
+///
+///     var b1 = js.statement('{ 1; 2; }');
+///     var sEmpty = new Emptystatement();
+///     js.statement('{ #; #; #; #; }', [sEmpty, b1, b1, sEmpty])
+///     -->
+///     { 1; 2; 1; 2; }
+///
+/// A placeholder in the context of an if-statement condition also accepts a
+/// Dart bool argument, which selects the then-part or else-part of the
+/// if-statement:
+///
+///     js.statement('if (#) return;', vFoo)   -->  if (foo) return;
+///     js.statement('if (#) return;', true)   -->  return;
+///     js.statement('if (#) return;', false)  -->  ;   // empty statement
+///     var eTrue = new LiteralBool(true);
+///     js.statement('if (#) return;', eTrue)  -->  if (true) return;
+///
+/// Combined with block splicing, if-statement condition context placeholders
+/// allows the creation of templates that select code depending on variables.
+///
+///     js.statement('{ 1; if (#) 2; else { 3; 4; } 5;}', true)
+///     --> { 1; 2; 5; }
+///
+///     js.statement('{ 1; if (#) 2; else { 3; 4; } 5;}', false)
+///     --> { 1; 3; 4; 5; }
+///
+/// A placeholder following a period in a property access is in a property
+/// access context. This is just like an expression context, except String
+/// arguments are converted to JavaScript property accesses. In JavaScript,
+/// `a.b` is short-hand for `a["b"]`:
+///
+///     js('a[#]', vFoo)  -->  a[foo]
+///     js('a[#]', s)     -->  a.hello    (i.e. a["hello"]).
+///     js('a[#]', 'x')   -->  a[x]
+///
+///     js('a.#', vFoo)   -->  a[foo]
+///     js('a.#', s)      -->  a.hello    (i.e. a["hello"])
+///     js('a.#', 'x')    -->  a.x        (i.e. a["x"])
+///
+/// (Question - should `.#` be restricted to permit only String arguments? The
+/// template should probably be written with `[]` if non-strings are accepted.)
+///
+///
+/// Object initializers allow placeholders in the key property name position:
+///
+///     js('{#:1, #:2}',  [s, 'bye'])    -->  {hello: 1, bye: 2}
+///
+///
+/// What is not implemented:
+///
+///  -  Array initializers and object initializers could support splicing. In
+///     the array case, we would need some way to know if an ArrayInitializer
+///     argument should be splice or is intended as a single value.
+///
+///  -  There are no placeholders in definition contexts:
+///
+///         function #(){}
+///         var # = 1;
 const JsBuilder js = JsBuilder();
 
 class JsBuilder {
   const JsBuilder();
 
-  /**
-   * Parses a bit of JavaScript, and returns an expression.
-   *
-   * See the MiniJsParser class.
-   *
-   * [arguments] can be a single [Node] (e.g. an [Expression] or [Statement]) or
-   * a list of [Node]s, which will be interpolated into the source at the '#'
-   * signs.
-   */
+  /// Parses a bit of JavaScript, and returns an expression.
+  ///
+  /// See the MiniJsParser class.
+  ///
+  /// [arguments] can be a single [Node] (e.g. an [Expression] or [Statement])
+  /// or a list of [Node]s, which will be interpolated into the source at the
+  /// '#' signs.
   Expression call(String source, [arguments]) {
     Template template = _findExpressionTemplate(source);
     if (arguments == null) return template.instantiate([]) as Expression;
@@ -218,9 +220,7 @@
     return template.instantiate(arguments) as Expression;
   }
 
-  /**
-   * Parses a JavaScript Statement, otherwise just like [call].
-   */
+  /// Parses a JavaScript Statement, otherwise just like [call].
   Statement statement(String source, [arguments]) {
     Template template = _findStatementTemplate(source);
     if (arguments == null) return template.instantiate([]) as Statement;
@@ -233,12 +233,10 @@
       statement(source, arguments) as Block;
   Fun fun(String source, [arguments]) => call(source, arguments) as Fun;
 
-  /**
-   * Parses JavaScript written in the `JS` foreign instruction.
-   *
-   * The [source] must be a JavaScript expression or a JavaScript throw
-   * statement.
-   */
+  /// Parses JavaScript written in the `JS` foreign instruction.
+  ///
+  /// The [source] must be a JavaScript expression or a JavaScript throw
+  /// statement.
   Template parseForeignJS(String source) {
     // TODO(sra): Parse with extra validation to forbid `#` interpolation in
     // functions, as this leads to unanticipated capture of temporaries that are
@@ -270,29 +268,23 @@
     return template;
   }
 
-  /**
-   * Creates an Expression template without caching the result.
-   */
+  /// Creates an Expression template without caching the result.
   Template uncachedExpressionTemplate(String source) {
     MiniJsParser parser = MiniJsParser(source);
     Expression expression = parser.expression();
     return Template(source, expression, isExpression: true, forceCopy: false);
   }
 
-  /**
-   * Creates a Statement template without caching the result.
-   */
+  /// Creates a Statement template without caching the result.
   Template uncachedStatementTemplate(String source) {
     MiniJsParser parser = MiniJsParser(source);
     Statement statement = parser.statement();
     return Template(source, statement, isExpression: false, forceCopy: false);
   }
 
-  /**
-   * Create an Expression template which has [ast] as the result.  This is used
-   * to wrap a generated AST in a zero-argument Template so it can be passed to
-   * context that expects a template.
-   */
+  /// Create an Expression template which has [ast] as the result. This is used
+  /// to wrap a generated AST in a zero-argument Template so it can be passed to
+  /// context that expects a template.
   Template expressionTemplateYielding(Node ast) {
     return Template.withExpressionResult(ast);
   }
@@ -468,7 +460,7 @@
 }
 
 /// Mini JavaScript parser for tiny snippets of code that we want to make into
-/// AST nodes.  Handles:
+/// AST nodes. Handles:
 /// * identifiers.
 /// * dot access.
 /// * method calls.
@@ -487,20 +479,16 @@
 /// Literal strings are passed through to the final JS source code unchanged,
 /// including the choice of surrounding quotes, so if you parse
 /// r'var x = "foo\n\"bar\""' you will end up with
-///   var x = "foo\n\"bar\"" in the final program.  \x and \u escapes are not
+///   var x = "foo\n\"bar\"" in the final program. \x and \u escapes are not
 /// allowed in string and regexp literals because the machinery for checking
 /// their correctness is rather involved.
 class MiniJsParser {
-  MiniJsParser(this.src)
-      : lastCategory = NONE,
-        lastToken = null,
-        lastPosition = 0,
-        position = 0 {
+  MiniJsParser(this.src) {
     getToken();
   }
 
   int lastCategory = NONE;
-  String lastToken;
+  String lastToken = '';
   int lastPosition = 0;
   int position = 0;
   bool skippedNewline = false; // skipped newline in last getToken?
@@ -736,7 +724,7 @@
 
     if (position == src.length) {
       lastCategory = NONE;
-      lastToken = null;
+      lastToken = '';
       lastPosition = position;
       return;
     }
@@ -954,13 +942,11 @@
     }
   }
 
-  /**
-   * CoverParenthesizedExpressionAndArrowParameterList[Yield] :
-   *     ( Expression )
-   *     ( )
-   *     ( ... BindingIdentifier )
-   *     ( Expression , ... BindingIdentifier )
-   */
+  /// CoverParenthesizedExpressionAndArrowParameterList[Yield] :
+  ///     ( Expression )
+  ///     ( )
+  ///     ( ... BindingIdentifier )
+  ///     ( Expression , ... BindingIdentifier )
   Expression parseExpressionOrArrowFunction() {
     if (acceptCategory(RPAREN)) {
       expectCategory(ARROW);
@@ -994,10 +980,8 @@
     return expression;
   }
 
-  /**
-   * Converts a parenthesized expression into a list of parameters, issuing an
-   * error if the conversion fails.
-   */
+  /// Converts a parenthesized expression into a list of parameters, issuing an
+  /// error if the conversion fails.
   void _expressionToParameterList(Expression node, List<Parameter> params) {
     if (node is Identifier) {
       params.add(node);
@@ -1071,7 +1055,7 @@
     return Fun(params, block, asyncModifier: asyncModifier);
   }
 
-  /** Parse parameter name or interpolated parameter. */
+  /// Parse parameter name or interpolated parameter.
   Identifier parseParameter() {
     if (acceptCategory(HASH)) {
       var nameOrPosition = parseHash();
@@ -1279,7 +1263,7 @@
     return expression;
   }
 
-  /** Parse a variable declaration list, with `var` or `let` [keyword] */
+  /// Parse a variable declaration list, with `var` or `let` [keyword].
   VariableDeclarationList parseVariableDeclarationList(String keyword,
       [String firstIdentifier]) {
     var initialization = <VariableInitialization>[];
@@ -1385,7 +1369,7 @@
     }
   }
 
-  /** Accepts a `var` or `let` keyword. If neither is found, returns null. */
+  /// Accepts a `var` or `let` keyword. If neither is found, returns null.
   String acceptVarLetOrConst() {
     if (acceptString('var')) return 'var';
     if (acceptString('let')) return 'let';
@@ -1711,17 +1695,15 @@
     return ClassExpression(name, heritage, methods);
   }
 
-  /**
-   * Parses a [Method] or a [Property].
-   *
-   * Most of the complexity is from supporting interpolation. Several forms
-   * are supported:
-   *
-   * - getter/setter names: `get #() { ... }`
-   * - method names: `#() { ... }`
-   * - property names: `#: ...`
-   * - entire methods: `#`
-   */
+  /// Parses a [Method] or a [Property].
+  ///
+  /// Most of the complexity is from supporting interpolation. Several forms are
+  /// supported:
+  ///
+  /// - getter/setter names: `get #() { ... }`
+  /// - method names: `#() { ... }`
+  /// - property names: `#: ...`
+  /// - entire methods: `#`
   Property parseMethodOrProperty({bool onlyMethods = false}) {
     bool isStatic = acceptString('static');
 
diff --git a/pkg/dev_compiler/lib/src/js_ast/js_ast.dart b/pkg/dev_compiler/lib/src/js_ast/js_ast.dart
index 373547e..8cb165e 100644
--- a/pkg/dev_compiler/lib/src/js_ast/js_ast.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/js_ast.dart
@@ -5,14 +5,11 @@
 // @dart = 2.9
 
 // ignore_for_file: directives_ordering
+// ignore_for_file: library_prefixes
 
 library js_ast;
 
-import 'precedence.dart';
-// ignore: library_prefixes
-import 'characters.dart' as charCodes;
-
-part 'nodes.dart';
-part 'builder.dart';
-part 'printer.dart';
-part 'template.dart';
+export 'nodes.dart';
+export 'builder.dart';
+export 'printer.dart';
+export 'template.dart';
diff --git a/pkg/dev_compiler/lib/src/js_ast/nodes.dart b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
index 8618c7e..6155510 100644
--- a/pkg/dev_compiler/lib/src/js_ast/nodes.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
@@ -4,13 +4,18 @@
 
 // @dart = 2.9
 
-// ignore_for_file: always_declare_return_types, prefer_final_fields
+// ignore_for_file: always_declare_return_types
 // ignore_for_file: always_require_non_null_named_parameters
-// ignore_for_file: omit_local_variable_types, unnecessary_this
+// ignore_for_file: omit_local_variable_types
+// ignore_for_file: prefer_final_fields
 // ignore_for_file: prefer_initializing_formals
-// ignore_for_file: slash_for_doc_comments, prefer_single_quotes
+// ignore_for_file: prefer_single_quotes
+// ignore_for_file: unnecessary_this
 
-part of js_ast;
+library js_ast.nodes;
+
+import 'precedence.dart';
+import 'printer.dart';
 
 abstract class NodeVisitor<T> {
   T visitProgram(Program node);
@@ -103,12 +108,8 @@
   T visitSimpleBindingPattern(SimpleBindingPattern node);
 }
 
-class BaseVisitor<T> implements NodeVisitor<T> {
-  T visitNode(Node node) {
-    node.visitChildren(this);
-    return null;
-  }
-
+abstract class BaseVisitor<T> implements NodeVisitor<T> {
+  T visitNode(Node node);
   @override
   T visitProgram(Program node) => visitNode(node);
 
@@ -279,11 +280,10 @@
   T visitInterpolatedIdentifier(InterpolatedIdentifier node) =>
       visitInterpolatedNode(node);
 
-  // Ignore comments by default.
   @override
-  T visitComment(Comment node) => null;
+  T visitComment(Comment node);
   @override
-  T visitCommentExpression(CommentExpression node) => null;
+  T visitCommentExpression(CommentExpression node);
 
   @override
   T visitAwait(Await node) => visitExpression(node);
@@ -303,6 +303,19 @@
   T visitSimpleBindingPattern(SimpleBindingPattern node) => visitNode(node);
 }
 
+class BaseVisitorVoid extends BaseVisitor<void> {
+  @override
+  void visitNode(Node node) {
+    node.visitChildren(this);
+  }
+
+  // Ignore comments by default.
+  @override
+  void visitComment(Comment node) {}
+  @override
+  void visitCommentExpression(CommentExpression node) {}
+}
+
 abstract class Node {
   /// Sets the source location of this node. For performance reasons, we allow
   /// setting this after construction.
@@ -311,12 +324,14 @@
   T accept<T>(NodeVisitor<T> visitor);
   void visitChildren(NodeVisitor visitor);
 
-  // Shallow clone of node.  Does not clone positions since the only use of this
-  // private method is create a copy with a new position.
+  /// Shallow clone of node.
+  ///
+  /// Does not clone positions since the only use of this private method is
+  /// create a copy with a new position.
   Node _clone();
 
-  // Returns a node equivalent to [this], but with new source position and end
-  // source position.
+  /// Returns a node equivalent to [this], but with new source position and end
+  /// source position.
   Node withSourceInformation(sourceInformation) {
     if (sourceInformation == this.sourceInformation) {
       return this;
@@ -352,7 +367,7 @@
 
 // TODO(jmesserly): rename to Module.
 class Program extends Node {
-  /// Script tag hash-bang, e.g. `#!/usr/bin/env node`
+  /// Script tag hash-bang, e.g. `#!/usr/bin/env node`.
   final String scriptTag;
 
   /// Top-level statements in the program.
@@ -395,7 +410,7 @@
   /// JavaScript syntax error due to a redeclared identifier.
   bool shadows(Set<String> names) => false;
 
-  /// Whether this statement would always `return` if used as a funtion body.
+  /// Whether this statement would always `return` if used as a function body.
   ///
   /// This is only well defined on the outermost block; it cannot be used for a
   /// block inside of a loop (because of `break` and `continue`).
@@ -513,7 +528,7 @@
   void visitChildren(NodeVisitor visitor) {
     condition.accept(visitor);
     then.accept(visitor);
-    if (otherwise != null) otherwise.accept(visitor);
+    otherwise?.accept(visitor);
   }
 
   @override
@@ -537,9 +552,9 @@
 
   @override
   void visitChildren(NodeVisitor visitor) {
-    if (init != null) init.accept(visitor);
-    if (condition != null) condition.accept(visitor);
-    if (update != null) update.accept(visitor);
+    init?.accept(visitor);
+    condition?.accept(visitor);
+    update?.accept(visitor);
     body.accept(visitor);
   }
 
@@ -671,7 +686,7 @@
 
   @override
   void visitChildren(NodeVisitor visitor) {
-    if (value != null) value.accept(visitor);
+    value?.accept(visitor);
   }
 
   @override
@@ -686,7 +701,7 @@
 
 final _returnFinder = _ReturnFinder();
 
-class _ReturnFinder extends BaseVisitor {
+class _ReturnFinder extends BaseVisitorVoid {
   bool found = false;
   @override
   visitReturn(Return node) {
@@ -731,8 +746,8 @@
   @override
   void visitChildren(NodeVisitor visitor) {
     body.accept(visitor);
-    if (catchPart != null) catchPart.accept(visitor);
-    if (finallyPart != null) finallyPart.accept(visitor);
+    catchPart?.accept(visitor);
+    finallyPart?.accept(visitor);
   }
 
   @override
@@ -852,8 +867,8 @@
   LiteralStatement _clone() => LiteralStatement(code);
 }
 
-// Not a real JavaScript node, but represents the yield statement from a dart
-// program translated to JavaScript.
+/// Not a real JavaScript node, but represents the yield statement from a dart
+/// program translated to JavaScript.
 class DartYield extends Statement {
   final Expression expression;
 
@@ -924,15 +939,10 @@
   int get precedenceLevel => PRIMARY;
 }
 
-/**
- * [VariableDeclarationList] is a subclass of [Expression] to simplify the
- * AST.
- */
+/// [VariableDeclarationList] is a subclass of [Expression] to simplify the AST.
 class VariableDeclarationList extends Expression {
-  /**
-   * The `var` or `let` or `const` keyword used for this variable declaration
-   * list.
-   */
+  /// The `var` or `let` or `const` keyword used for this variable declaration
+  /// list.
   final String keyword;
   final List<VariableInitialization> declarations;
 
@@ -987,7 +997,7 @@
   @override
   void visitChildren(NodeVisitor visitor) {
     leftHandSide.accept(visitor);
-    if (value != null) value.accept(visitor);
+    value?.accept(visitor);
   }
 
   @override
@@ -1014,7 +1024,7 @@
   @override
   void visitChildren(NodeVisitor visitor) {
     declaration.accept(visitor);
-    if (value != null) value.accept(visitor);
+    value?.accept(visitor);
   }
 }
 
@@ -1030,7 +1040,7 @@
 class DestructuredVariable extends Expression implements Parameter {
   final Identifier name;
 
-  /// The proprety in an object binding pattern, for example:
+  /// The property in an object binding pattern, for example:
   ///
   ///     let key = 'z';
   ///     let {[key]: foo} = {z: 'bar'};
@@ -1334,9 +1344,9 @@
   int get precedenceLevel => UNARY;
 }
 
-// SpreadElement isn't really a prefix expression, as it can only appear in
-// certain places such as ArgumentList and BindingPattern, but we pretend
-// it is for simplicity's sake.
+/// SpreadElement isn't really a prefix expression, as it can only appear in
+/// certain places such as ArgumentList and BindingPattern, but we pretend
+/// it is for simplicity's sake.
 class Spread extends Prefix {
   Spread(Expression operand) : super('...', operand);
 
@@ -1397,7 +1407,7 @@
   void visitChildren(NodeVisitor visitor) {}
 }
 
-// This is an expression for convenience in the AST.
+/// This is an expression for convenience in the AST.
 class RestParameter extends Expression implements Parameter {
   final Identifier parameter;
 
@@ -1432,8 +1442,8 @@
   void visitChildren(NodeVisitor visitor) {}
 }
 
-// `super` is more restricted in the ES6 spec, but for simplicity we accept
-// it anywhere that `this` is accepted.
+/// `super` is more restricted in the ES6 spec, but for simplicity we accept
+/// it anywhere that `this` is accepted.
 class Super extends Expression {
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitSuper(this);
@@ -1448,9 +1458,11 @@
 class NamedFunction extends Expression {
   final Identifier name;
   final Fun function;
-  // A heuristic to force extra parens around this function.  V8 and other
-  // engines use this IIFE (immediately invoked function expression) heuristic
-  // to eagerly parse a function.
+
+  /// A heuristic to force extra parens around this function.
+  ///
+  /// V8 and other engines use this IIFE (immediately invoked function
+  /// expression) heuristic to eagerly parse a function.
   final bool immediatelyInvoked;
 
   NamedFunction(this.name, this.function, [this.immediatelyInvoked = false]);
@@ -1483,7 +1495,7 @@
   @override
   final Block body;
 
-  /** Whether this is a JS generator (`function*`) that may contain `yield`. */
+  /// Whether this is a JS generator (`function*`) that may contain `yield`.
   final bool isGenerator;
 
   final AsyncModifier asyncModifier;
@@ -1537,12 +1549,9 @@
   ArrowFun _clone() => ArrowFun(params, body);
 }
 
-/**
- * The Dart sync, sync*, async, and async* modifier.
- * See [DartYield].
- *
- * This is not used for JS functions.
- */
+/// The Dart sync, sync*, async, and async* modifier.
+///
+/// See [DartYield]. This is not used for JS functions.
 class AsyncModifier {
   final bool isAsync;
   final bool isYielding;
@@ -1626,16 +1635,14 @@
 class LiteralString extends Literal {
   final String value;
 
-  /**
-   * Constructs a LiteralString from a string value.
-   *
-   * The constructor does not add the required quotes.  If [value] is not
-   * surrounded by quotes and property escaped, the resulting object is invalid
-   * as a JS value.
-   *
-   * TODO(sra): Introduce variants for known valid strings that don't allocate a
-   * new string just to add quotes.
-   */
+  /// Constructs a LiteralString from a string value.
+  ///
+  /// The constructor does not add the required quotes.  If [value] is not
+  /// surrounded by quotes and property escaped, the resulting object is invalid
+  /// as a JS value.
+  ///
+  /// TODO(sra): Introduce variants for known valid strings that don't allocate
+  /// a new string just to add quotes.
   LiteralString(this.value);
 
   /// Gets the value inside the string without the beginning and end quotes.
@@ -1657,10 +1664,8 @@
   @override
   LiteralNumber _clone() => LiteralNumber(value);
 
-  /**
-   * Use a different precedence level depending on whether the value contains a
-   * dot to ensure we generate `(1).toString()` and `1.0.toString()`.
-   */
+  /// Use a different precedence level depending on whether the value contains a
+  /// dot to ensure we generate `(1).toString()` and `1.0.toString()`.
   @override
   int get precedenceLevel => value.contains('.') ? PRIMARY : UNARY;
 }
@@ -1688,10 +1693,9 @@
   int get precedenceLevel => PRIMARY;
 }
 
-/**
- * An empty place in an [ArrayInitializer].
- * For example the list [1, , , 2] would contain two holes.
- */
+/// An empty place in an [ArrayInitializer].
+///
+/// For example the list [1, , , 2] would contain two holes.
 class ArrayHole extends Expression {
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayHole(this);
@@ -1710,9 +1714,7 @@
   final List<Property> properties;
   final bool _multiline;
 
-  /**
-   * Constructs a new object-initializer containing the given [properties].
-   */
+  /// Constructs a new object-initializer containing the given [properties].
   ObjectInitializer(this.properties, {bool multiline = false})
       : _multiline = multiline;
 
@@ -1731,11 +1733,11 @@
 
   @override
   int get precedenceLevel => PRIMARY;
-  /**
-   * If set to true, forces a vertical layout when using the [Printer].
-   * Otherwise, layout will be vertical if and only if any [properties]
-   * are [FunctionExpression]s.
-   */
+
+  /// If set to true, forces a vertical layout when using the [Printer].
+  ///
+  /// Otherwise, layout will be vertical if and only if any [properties] are
+  /// [FunctionExpression]s.
   bool get multiline {
     return _multiline || properties.any((p) => p.value is FunctionExpression);
   }
@@ -1762,23 +1764,23 @@
 
 // TODO(jmesserly): parser does not support this yet.
 class TemplateString extends Expression {
-  /**
-   * The parts of this template string: a sequence of [String]s and
-   * [Expression]s. Strings and expressions will alternate, for example:
-   *
-   *     `foo${1 + 2} bar ${'hi'}`
-   *
-   * would be represented by [strings]:
-   *
-   *     ['foo', ' bar ', '']
-   *
-   * and [interpolations]:
-   *
-   *     [new JS.Binary('+', js.number(1), js.number(2)),
-   *      new JS.LiteralString("'hi'")]
-   *
-   * There should be exactly one more string than interpolation expression.
-   */
+  /// The parts of this template string: a sequence of [String]s and
+  /// [Expression]s.
+  ///
+  /// Strings and expressions will alternate, for example:
+  ///
+  ///     `foo${1 + 2} bar ${'hi'}`
+  ///
+  /// would be represented by [strings]:
+  ///
+  ///     ['foo', ' bar ', '']
+  ///
+  /// and [interpolations]:
+  ///
+  ///     [new JS.Binary('+', js.number(1), js.number(2)),
+  ///      new JS.LiteralString("'hi'")]
+  ///
+  /// There should be exactly one more string than interpolation expression.
   final List<String> strings;
   final List<Expression> interpolations;
 
@@ -1830,10 +1832,8 @@
 class Yield extends Expression {
   final Expression value; // Can be null.
 
-  /**
-   * Whether this yield expression is a `yield*` that iterates each item in
-   * [value].
-   */
+  /// Whether this yield expression is a `yield*` that iterates each item in
+  /// [value].
   final bool star;
 
   Yield(this.value, {this.star = false});
@@ -1843,7 +1843,7 @@
 
   @override
   void visitChildren(NodeVisitor visitor) {
-    if (value != null) value.accept(visitor);
+    value?.accept(visitor);
   }
 
   @override
@@ -1879,7 +1879,7 @@
   @override
   void visitChildren(NodeVisitor visitor) {
     name.accept(visitor);
-    if (heritage != null) heritage.accept(visitor);
+    heritage?.accept(visitor);
     for (Method element in methods) {
       element.accept(visitor);
     }
@@ -2100,13 +2100,13 @@
   bool get allowRename => false;
 }
 
-/**
- * [RegExpLiteral]s, despite being called "Literal", do not inherit from
- * [Literal]. Indeed, regular expressions in JavaScript have a side-effect and
- * are thus not in the same category as numbers or strings.
- */
+/// [RegExpLiteral]s, despite being called "Literal", do not inherit from
+/// [Literal].
+///
+/// Indeed, regular expressions in JavaScript have a side-effect and are thus
+/// not in the same category as numbers or strings.
 class RegExpLiteral extends Expression {
-  /** Contains the pattern and the flags.*/
+  /// Contains the pattern and the flags.
   final String pattern;
 
   RegExpLiteral(this.pattern);
@@ -2122,14 +2122,12 @@
   int get precedenceLevel => PRIMARY;
 }
 
-/**
- * An asynchronous await.
- *
- * Not part of JavaScript. We desugar this expression before outputting.
- * Should only occur in a [Fun] with `asyncModifier` async or asyncStar.
- */
+/// An asynchronous await.
+///
+/// Not part of JavaScript. We desugar this expression before outputting.
+/// Should only occur in a [Fun] with `asyncModifier` async or asyncStar.
 class Await extends Expression {
-  /** The awaited expression. */
+  /// The awaited expression.
   final Expression expression;
 
   Await(this.expression);
@@ -2144,12 +2142,10 @@
   Await _clone() => Await(expression);
 }
 
-/**
- * A comment.
- *
- * Extends [Statement] so we can add comments before statements in
- * [Block] and [Program].
- */
+/// A comment.
+///
+/// Extends [Statement] so we can add comments before statements in [Block] and
+/// [Program].
 class Comment extends Statement {
   final String comment;
 
@@ -2164,12 +2160,10 @@
   void visitChildren(NodeVisitor visitor) {}
 }
 
-/**
- * A comment for expressions.
- *
- * Extends [Expression] so we can add comments before expressions.
- * Has the highest possible precedence, so we don't add parentheses around it.
- */
+/// A comment for expressions.
+///
+/// Extends [Expression] so we can add comments before expressions. Has the
+/// highest possible precedence, so we don't add parentheses around it.
 class CommentExpression extends Expression {
   final String comment;
   final Expression expression;
@@ -2196,10 +2190,8 @@
   void visitChildren(NodeVisitor visitor) {}
 }
 
-/**
- * Represents allowed module items:
- * [Statement], [ImportDeclaration], and [ExportDeclaration].
- */
+/// Represents allowed module items:
+/// [Statement], [ImportDeclaration], and [ExportDeclaration].
 abstract class ModuleItem extends Node {}
 
 class ImportDeclaration extends ModuleItem {
@@ -2214,10 +2206,10 @@
     assert(from != null);
   }
 
-  /** The `import "name.js"` form of import */
+  /// The `import "name.js"` form of import.
   ImportDeclaration.all(LiteralString module) : this(from: module);
 
-  /** If this import has `* as name` returns the name, otherwise null. */
+  /// If this import has `* as name` returns the name, otherwise null.
   Identifier get importStarAs {
     if (namedImports != null &&
         namedImports.length == 1 &&
@@ -2245,16 +2237,14 @@
 }
 
 class ExportDeclaration extends ModuleItem {
-  /**
-   * Exports a name from this module.
-   *
-   * This can be a [ClassDeclaration] or [FunctionDeclaration].
-   * If [isDefault] is true, it can also be an [Expression].
-   * Otherwise it can be a [VariableDeclarationList] or an [ExportClause].
-   */
+  /// Exports a name from this module.
+  ///
+  /// This can be a [ClassDeclaration] or [FunctionDeclaration].
+  /// If [isDefault] is true, it can also be an [Expression].
+  /// Otherwise it can be a [VariableDeclarationList] or an [ExportClause].
   final Node exported;
 
-  /** True if this is an `export default`. */
+  /// True if this is an `export default`.
   final bool isDefault;
 
   ExportDeclaration(this.exported, {this.isDefault = false}) {
@@ -2304,11 +2294,11 @@
 
   ExportClause(this.exports, {this.from});
 
-  /** The `export * from 'name.js'` form. */
+  /// The `export * from 'name.js'` form.
   ExportClause.star(LiteralString from)
       : this([NameSpecifier.star()], from: from);
 
-  /** True if this is an `export *`. */
+  /// True if this is an `export *`.
   bool get exportStar => exports.length == 1 && exports[0].isStar;
 
   @override
@@ -2318,14 +2308,14 @@
     for (NameSpecifier name in exports) {
       name.accept(visitor);
     }
-    if (from != null) from.accept(visitor);
+    from?.accept(visitor);
   }
 
   @override
   ExportClause _clone() => ExportClause(exports, from: from);
 }
 
-/** An import or export specifier. */
+/// An import or export specifier.
 class NameSpecifier extends Node {
   final Identifier name;
   final Identifier asName; // Can be null.
@@ -2333,7 +2323,7 @@
   NameSpecifier(this.name, {this.asName});
   NameSpecifier.star() : this(null);
 
-  /** True if this is a `* as someName` specifier. */
+  /// True if this is a `* as someName` specifier.
   bool get isStar => name == null;
 
   @override
@@ -2346,7 +2336,7 @@
 
 // TODO(jmesserly): should this be related to [Program]?
 class Module extends Node {
-  /// The module's name
+  /// The module's name.
   // TODO(jmesserly): this is not declared in ES6, but is known by the loader.
   // We use this because some ES5 desugarings require it.
   final String name;
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index 5d81fe5..357dee6 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -4,14 +4,22 @@
 
 // @dart = 2.9
 
-// ignore_for_file: always_declare_return_types, prefer_single_quotes, prefer_interpolation_to_compose_strings
-// ignore_for_file: prefer_collection_literals, omit_local_variable_types
+// ignore_for_file: always_declare_return_types
+// ignore_for_file: library_prefixes
+// ignore_for_file: omit_local_variable_types
+// ignore_for_file: prefer_collection_literals
 // ignore_for_file: prefer_final_fields
 // ignore_for_file: prefer_initializing_formals
-// ignore_for_file: slash_for_doc_comments, unnecessary_const
+// ignore_for_file: prefer_interpolation_to_compose_strings
+// ignore_for_file: prefer_single_quotes
+// ignore_for_file: unnecessary_const
 // ignore_for_file: use_function_type_syntax_for_parameters
 
-part of js_ast;
+library js_ast.printer;
+
+import 'characters.dart' as charCodes;
+import 'nodes.dart';
+import 'precedence.dart';
 
 class JavaScriptPrintingOptions {
   final bool shouldCompressOutput;
@@ -974,20 +982,21 @@
 
   @override
   visitAccess(PropertyAccess access) {
-    // Normally we can omit parens on the receiver if it is a Call, even though
-    // Call expressions have lower precedence. However this optimization doesn't
-    // work inside New expressions:
-    //
-    //     new obj.foo().bar()
-    //
-    // This will be parsed as:
-    //
-    //     (new obj.foo()).bar()
-    //
-    // Which is incorrect. So we must have parenthesis in this case:
-    //
-    //     new (obj.foo()).bar()
-    //
+    /// Normally we can omit parens on the receiver if it is a Call, even though
+    /// Call expressions have lower precedence.
+    ///
+    /// However this optimization doesn't work inside New expressions:
+    ///
+    ///     new obj.foo().bar()
+    ///
+    /// This will be parsed as:
+    ///
+    ///     (new obj.foo()).bar()
+    ///
+    /// Which is incorrect. So we must have parenthesis in this case:
+    ///
+    ///     new (obj.foo()).bar()
+    ///
     int precedence = inNewTarget ? ACCESS : CALL;
 
     visitNestedExpression(access.receiver, precedence,
@@ -1025,7 +1034,7 @@
     var body = fun.body;
     if (body is Expression) {
       spaceOut();
-      // Object initializers require parenthesis to disambiguate
+      // Object initializers require parentheses to disambiguate
       // AssignmentExpression from FunctionBody. See:
       // https://tc39.github.io/ecma262/#sec-arrow-function-definitions
       var needsParen = fun.body is ObjectInitializer;
@@ -1433,7 +1442,7 @@
 
 // Collects all the var declarations in the function.  We need to do this in a
 // separate pass because JS vars are lifted to the top of the function.
-class VarCollector extends BaseVisitor {
+class VarCollector extends BaseVisitorVoid {
   bool nested;
   final Set<String> vars;
   final Set<String> params;
@@ -1491,7 +1500,7 @@
   @override
   void visitClassExpression(ClassExpression node) {
     // Note that we don't bother collecting the name of the class.
-    if (node.heritage != null) node.heritage.accept(this);
+    node.heritage?.accept(this);
     for (Method method in node.methods) {
       method.accept(this);
     }
@@ -1516,10 +1525,8 @@
   }
 }
 
-/**
- * Returns true, if the given node must be wrapped into braces when used
- * as then-statement in an [If] that has an else branch.
- */
+/// Returns true, if the given node must be wrapped into braces when used
+/// as then-statement in an [If] that has an else branch.
 class DanglingElseVisitor extends BaseVisitor<bool> {
   JavaScriptPrintingContext context;
 
@@ -1531,12 +1538,16 @@
   @override
   bool visitNode(Node node) {
     context.error("Forgot node: $node");
-    return null;
+    return true;
   }
 
   @override
   bool visitBlock(Block node) => false;
   @override
+  bool visitComment(Comment node) => true;
+  @override
+  bool visitCommentExpression(CommentExpression node) => true;
+  @override
   bool visitExpressionStatement(ExpressionStatement node) => false;
   @override
   bool visitEmptyStatement(EmptyStatement node) => false;
@@ -1734,7 +1745,7 @@
 
 /// Like [BaseVisitor], but calls [declare] for [Identifier] declarations, and
 /// [visitIdentifier] otherwise.
-abstract class VariableDeclarationVisitor extends BaseVisitor<void> {
+abstract class VariableDeclarationVisitor extends BaseVisitorVoid {
   declare(Identifier node);
 
   @override
@@ -1773,7 +1784,7 @@
   @override
   visitVariableInitialization(VariableInitialization node) {
     _scanVariableBinding(node.declaration);
-    if (node.value != null) node.value.accept(this);
+    node.value?.accept(this);
   }
 
   @override
@@ -1797,7 +1808,7 @@
   @override
   visitClassExpression(ClassExpression node) {
     declare(node.name);
-    if (node.heritage != null) node.heritage.accept(this);
+    node.heritage?.accept(this);
     for (Method element in node.methods) {
       element.accept(this);
     }
diff --git a/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart b/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
index 5862fdb..dcc1675 100644
--- a/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
@@ -4,7 +4,8 @@
 
 // @dart = 2.9
 
-// ignore_for_file: always_declare_return_types, omit_local_variable_types
+// ignore_for_file: always_declare_return_types
+// ignore_for_file: omit_local_variable_types
 
 import 'package:source_maps/source_maps.dart' hide Printer;
 import 'package:source_span/source_span.dart' show SourceLocation;
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index bcba9f0..dd51310 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -4,13 +4,17 @@
 
 // @dart = 2.9
 
-// ignore_for_file: always_declare_return_types, prefer_collection_literals
+// ignore_for_file: always_declare_return_types
 // ignore_for_file: avoid_returning_null_for_void
-// ignore_for_file: prefer_single_quotes, prefer_generic_function_type_aliases
-// ignore_for_file: slash_for_doc_comments, omit_local_variable_types
+// ignore_for_file: omit_local_variable_types
+// ignore_for_file: prefer_collection_literals
+// ignore_for_file: prefer_generic_function_type_aliases
+// ignore_for_file: prefer_single_quotes
 // ignore_for_file: unnecessary_this
 
-part of js_ast;
+library js_ast.template;
+
+import 'nodes.dart';
 
 class TemplateManager {
   Map<String, Template> expressionTemplates = Map<String, Template>();
@@ -41,12 +45,11 @@
   }
 }
 
-/**
- * A Template is created with JavaScript AST containing placeholders (interface
- * InterpolatedNode).  The [instantiate] method creates an AST that looks like
- * the original with the placeholders replaced by the arguments to
- * [instantiate].
- */
+/// A Template is created with JavaScript AST containing placeholders (interface
+/// InterpolatedNode).
+///
+/// The [instantiate] method creates an AST that looks like the original with
+/// the placeholders replaced by the arguments to [instantiate].
 class Template {
   final String source;
   final bool isExpression;
@@ -114,8 +117,8 @@
     }
     if (arguments is Map) {
       if (holeNames.length < arguments.length) {
-        // This search is in O(n), but we only do it in case of an new StateError, and the
-        // number of holes should be quite limited.
+        // This search is in O(n), but we only do it in case of a new
+        // StateError, and the number of holes should be quite limited.
         String unusedNames = arguments.keys
             .where((name) => !holeNames.contains(name))
             .join(", ");
@@ -132,26 +135,21 @@
   }
 }
 
-/**
- * An Instantiator is a Function that generates a JS AST tree or List of
- * trees. [arguments] is a List for positional templates, or Map for
- * named templates.
- */
+/// An Instantiator is a Function that generates a JS AST tree or List of
+/// trees.
+///
+/// [arguments] is a List for positional templates, or Map for named templates.
 typedef T Instantiator<T>(arguments);
 
-/**
- * InstantiatorGeneratorVisitor compiles a template.  This class compiles a tree
- * containing [InterpolatedNode]s into a function that will create a copy of the
- * tree with the interpolated nodes substituted with provided values.
- */
+/// InstantiatorGeneratorVisitor compiles a template.  This class compiles a tree
+/// containing [InterpolatedNode]s into a function that will create a copy of the
+/// tree with the interpolated nodes substituted with provided values.
 class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
   final bool forceCopy;
 
   final analysis = InterpolatedNodeAnalysis();
 
-  /**
-   * The entire tree is cloned if [forceCopy] is true.
-   */
+  /// The entire tree is cloned if [forceCopy] is true.
   InstantiatorGeneratorVisitor(this.forceCopy);
 
   Instantiator compile(Node node) {
@@ -396,7 +394,7 @@
     var makeThen = visit(node.then) as Instantiator<Statement>;
     var makeOtherwise = visit(node.otherwise) as Instantiator<Statement>;
     return (arguments) {
-      // Allow bools to be used for conditional compliation.
+      // Allow booleans to be used for conditional compilation.
       var nameOrPosition = condition.nameOrPosition;
       var value = arguments[nameOrPosition];
       if (value is bool) {
@@ -821,11 +819,9 @@
       (a) => SimpleBindingPattern(Identifier(node.name.name));
 }
 
-/**
- * InterpolatedNodeAnalysis determines which AST trees contain
- * [InterpolatedNode]s, and the names of the named interpolated nodes.
- */
-class InterpolatedNodeAnalysis extends BaseVisitor {
+/// InterpolatedNodeAnalysis determines which AST trees contain
+/// [InterpolatedNode]s, and the names of the named interpolated nodes.
+class InterpolatedNodeAnalysis extends BaseVisitorVoid {
   final Set<Node> containsInterpolatedNode = Set<Node>();
   final Set<String> holeNames = Set<String>();
   int count = 0;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index a502c03..67f05c4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -539,7 +539,8 @@
       loader.buildClassHierarchy(sourceClassBuilders, objectClassBuilder);
 
       benchmarker?.enterPhase(BenchmarkPhases.outline_checkSupertypes);
-      loader.checkSupertypes(sourceClassBuilders, enumClass);
+      loader.checkSupertypes(
+          sourceClassBuilders, enumClass, underscoreEnumClass);
 
       if (macroApplications != null) {
         benchmarker?.enterPhase(BenchmarkPhases.outline_applyDeclarationMacros);
@@ -884,6 +885,11 @@
 
   Class get enumClass => enumClassBuilder.cls;
 
+  ClassBuilder get underscoreEnumBuilder =>
+      underscoreEnumType.declaration as ClassBuilder;
+
+  Class get underscoreEnumClass => underscoreEnumBuilder.cls;
+
   /// If [builder] doesn't have a constructors, install the defaults.
   void installDefaultConstructor(SourceClassBuilder builder) {
     assert(!builder.isMixinApplication);
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 84ed77e..9c477e0 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -720,6 +720,7 @@
       CoreTypes coreTypes,
       ClassHierarchyBuilder hierarchyBuilder,
       Class enumClass,
+      Class underscoreEnumClass,
       Class? macroClass) {
     // This method determines whether the class (that's being built) its super
     // class appears both in 'extends' and 'implements' clauses and whether any
@@ -727,7 +728,7 @@
     // Moreover, it checks that `FutureOr` and `void` are not among the
     // supertypes and that `Enum` is not implemented by non-abstract classes.
 
-    if (libraryBuilder.enableEnhancedEnumsInLibrary) {
+    if (libraryBuilder.enableEnhancedEnumsInLibrary && !isEnum) {
       bool hasEnumSuperinterface = false;
       List<Supertype> interfaces =
           hierarchyBuilder.getNodeFromClass(cls).superclasses;
@@ -747,7 +748,8 @@
             charOffset, noLength);
       }
 
-      if (hasEnumSuperinterface) {
+      if (hasEnumSuperinterface && cls != underscoreEnumClass) {
+        // Instance members named `values` are restricted.
         Builder? customValuesDeclaration =
             scope.lookupLocalMember("values", setter: false);
         if (customValuesDeclaration != null &&
@@ -778,6 +780,21 @@
               customValuesDeclaration.fullNameForErrors.length,
               fileUri);
         }
+
+        // Non-setter concrete instance members named `index` and hashCode and
+        // operator == are restricted.
+        for (String restrictedMemberName in const ["index", "hashCode", "=="]) {
+          Builder? member =
+              scope.lookupLocalMember(restrictedMemberName, setter: false);
+          if (member is MemberBuilder && !member.isAbstract) {
+            libraryBuilder.addProblem(
+                templateEnumImplementerContainsRestrictedInstanceDeclaration
+                    .withArguments(this.name, restrictedMemberName),
+                member.charOffset,
+                member.fullNameForErrors.length,
+                fileUri);
+          }
+        }
       }
     }
     if (macroClass != null && !cls.isMacro && !cls.isAbstract) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index cc4567e..6cdb353 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -2109,12 +2109,12 @@
     ticker.logMs("Computed core types");
   }
 
-  void checkSupertypes(
-      List<SourceClassBuilder> sourceClasses, Class enumClass) {
+  void checkSupertypes(List<SourceClassBuilder> sourceClasses, Class enumClass,
+      Class underscoreEnumClass) {
     for (SourceClassBuilder builder in sourceClasses) {
       if (builder.libraryBuilder.loader == this && !builder.isPatch) {
-        builder.checkSupertypes(
-            coreTypes, hierarchyBuilder, enumClass, _macroClassBuilder?.cls);
+        builder.checkSupertypes(coreTypes, hierarchyBuilder, enumClass,
+            underscoreEnumClass, _macroClassBuilder?.cls);
       }
     }
     ticker.logMs("Checked supertypes");
@@ -2134,6 +2134,45 @@
     }
     ticker.logMs("Checked ${overrideChecks.length} overrides");
 
+    List<Name> restrictedMemberNames = <Name>[
+      new Name("index"),
+      new Name("hashCode"),
+      new Name("=="),
+      new Name("values")
+    ];
+    List<Class?> restrictedMemberDeclarers = <Class?>[
+      (target.underscoreEnumType.declaration as ClassBuilder).cls,
+      coreTypes.objectClass,
+      coreTypes.objectClass,
+      null
+    ];
+    for (SourceClassBuilder classBuilder in sourceClasses) {
+      if (classBuilder.isEnum) {
+        for (int i = 0; i < restrictedMemberNames.length; ++i) {
+          Name name = restrictedMemberNames[i];
+          Class? declarer = restrictedMemberDeclarers[i];
+
+          Member? member = hierarchy.getDispatchTarget(classBuilder.cls, name);
+          if (member?.enclosingClass != declarer &&
+              member?.enclosingClass != classBuilder.cls &&
+              member?.isAbstract == false) {
+            classBuilder.libraryBuilder.addProblem(
+                templateEnumInheritsRestricted.withArguments(name.text),
+                classBuilder.charOffset,
+                classBuilder.name.length,
+                classBuilder.fileUri,
+                context: <LocatedMessage>[
+                  messageEnumInheritsRestrictedMember.withLocation(
+                      member!.fileUri,
+                      member.fileOffset,
+                      member.name.text.length)
+                ]);
+          }
+        }
+      }
+    }
+    ticker.logMs("Checked for restricted members inheritance in enums.");
+
     typeInferenceEngine.finishTopLevelInitializingFormals();
     ticker.logMs("Finished initializing formals");
   }
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 5441a86..ac4cc31 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -229,10 +229,12 @@
 EnumDeclaresFactory/example: Fail
 EnumFactoryRedirectsToConstructor/analyzerCode: Fail
 EnumFactoryRedirectsToConstructor/example: Fail
-EnumImplementerContainsForbiddedInstanceDeclaration/analyzerCode: Fail
-EnumImplementerContainsForbiddedInstanceDeclaration/example: Fail
+EnumImplementerContainsRestrictedInstanceDeclaration/analyzerCode: Fail
+EnumImplementerContainsRestrictedInstanceDeclaration/example: Fail
 EnumImplementerContainsValuesDeclaration/analyzerCode: Fail
 EnumImplementerContainsValuesDeclaration/example: Fail
+EnumInheritsRestricted/analyzerCode: Fail
+EnumInheritsRestricted/example: Fail
 EnumInstantiation/example: Fail
 EnumNonConstConstructor/analyzerCode: Fail
 EnumNonConstConstructor/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index d952722a..f0fea47 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -5536,6 +5536,13 @@
 EnumImplementerContainsValuesDeclaration:
   problemMessage: "'#name' has 'Enum' as a superinterface and can't contain non-static member with name 'values'."
 
+EnumInheritsRestricted:
+  problemMessage: "An enum can't inherit a member named '#name'."
+
+EnumInheritsRestrictedMember:
+  problemMessage: "This is the inherited member"
+  severity: CONTEXT
+
 MacroClassNotDeclaredMacro:
   problemMessage: "Non-abstract class '#name' implements 'Macro' but isn't declared as a macro class."
   correctionMessage: "Try adding the 'macro' class modifier."
@@ -5557,3 +5564,6 @@
 
 EnumContainsRestrictedInstanceDeclaration:
   problemMessage: "An enum can't declare a non-abstract member named '#name'."
+
+EnumImplementerContainsRestrictedInstanceDeclaration:
+  problemMessage: "'#name' has 'Enum' as a superinterface and can't contain non-static members with name '#name2'."
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 6928e1f..abd5d63 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -744,6 +744,8 @@
 declarations
 declare
 declared
+declarer
+declarers
 declares
 declaring
 decode
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart
index 8889a45..5978728 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart
@@ -13,7 +13,7 @@
 abstract class EnumInterface implements Enum {}
 
 class EnumClass extends EnumInterface { // Error.
-  int get index => 0;
+  int get index => 0; // Error
 }
 
 abstract class AbstractEnumClass extends EnumInterface {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.expect b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.expect
index 99bdbbb..3984e35 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.expect
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.expect
@@ -14,6 +14,10 @@
 // class EnumClass extends EnumInterface { // Error.
 //       ^
 //
+// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:16:11: Error: 'EnumClass' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error
+//           ^^^^^
+//
 // pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
 // class EnumClass2 extends AbstractEnumClass {} // Error.
 //       ^
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.transformed.expect b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.transformed.expect
index 9f0c21d..f61139c 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.transformed.expect
@@ -14,6 +14,10 @@
 // class EnumClass extends EnumInterface { // Error.
 //       ^
 //
+// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:16:11: Error: 'EnumClass' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error
+//           ^^^^^
+//
 // pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
 // class EnumClass2 extends AbstractEnumClass {} // Error.
 //       ^
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.expect b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.expect
index 99bdbbb..3984e35 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.expect
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.expect
@@ -14,6 +14,10 @@
 // class EnumClass extends EnumInterface { // Error.
 //       ^
 //
+// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:16:11: Error: 'EnumClass' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error
+//           ^^^^^
+//
 // pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
 // class EnumClass2 extends AbstractEnumClass {} // Error.
 //       ^
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.modular.expect b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.modular.expect
index 99bdbbb..3984e35 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.modular.expect
@@ -14,6 +14,10 @@
 // class EnumClass extends EnumInterface { // Error.
 //       ^
 //
+// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:16:11: Error: 'EnumClass' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error
+//           ^^^^^
+//
 // pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
 // class EnumClass2 extends AbstractEnumClass {} // Error.
 //       ^
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.outline.expect b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.outline.expect
index 75296a2..8448a78 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.outline.expect
@@ -14,6 +14,10 @@
 // class EnumClass extends EnumInterface { // Error.
 //       ^
 //
+// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:16:11: Error: 'EnumClass' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error
+//           ^^^^^
+//
 // pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
 // class EnumClass2 extends AbstractEnumClass {} // Error.
 //       ^
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.transformed.expect b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.transformed.expect
index 9f0c21d..f61139c 100644
--- a/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.weak.transformed.expect
@@ -14,6 +14,10 @@
 // class EnumClass extends EnumInterface { // Error.
 //       ^
 //
+// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:16:11: Error: 'EnumClass' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error
+//           ^^^^^
+//
 // pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
 // class EnumClass2 extends AbstractEnumClass {} // Error.
 //       ^
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart
new file mode 100644
index 0000000..142e1ab
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class A1 implements Enum {
+  int get index => 0; // Error.
+  bool operator==(Object other) => true; // Error.
+  int get hashCode => 1; // Error.
+}
+
+mixin M1 implements Enum {
+  int get index => 0; // Error.
+  bool operator==(Object other) => true; // Error.
+  int get hashCode => 1; // Error.
+}
+
+abstract class A2 implements Enum {
+  void set index(String value) {} // Error.
+  void set hashCode(double value) {} // Error.
+}
+
+mixin M2 implements Enum {
+  void set index(String value) {} // Error.
+  void set hashCode(double value) {} // Error.
+}
+
+abstract class A3 implements Enum {
+  int get index; // Ok.
+  bool operator==(Object other); // Ok.
+  int get HashCode; // Ok.
+}
+
+mixin M3 implements Enum {
+  int get index; // Ok.
+  bool operator==(Object other); // Ok.
+  int get HashCode; // Ok.
+}
+
+abstract class A4 implements Enum {
+  int index = 0; // Error.
+  int hashCode = 1; // Error.
+}
+
+mixin M4 implements Enum {
+  int index = 0; // Error.
+  int hashCode = 1; // Error.
+}
+
+abstract class A5 implements Enum {
+  int foo = 0, bar = 1, // Ok.
+    index = 2, // Error.
+    hashCode = 3; // Error.
+}
+
+mixin M5 implements Enum {
+  int foo = 0, bar = 1, // Ok.
+    index = 2, // Error.
+    hashCode = 3; // Error.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.strong.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.strong.expect
new file mode 100644
index 0000000..061215b
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.strong.expect
@@ -0,0 +1,161 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:6:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:8:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:7:16: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:12:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:14:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:13:16: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:40:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:41:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:45:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:46:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:51:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:52:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:57:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:58:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:18:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'A2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:19:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'A2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:23:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'M2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:24:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'M2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A1 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class M1 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class A2 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class M2 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class A3 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class M3 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class A4 extends core::Object implements core::Enum {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+}
+abstract class M4 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+}
+abstract class A5 extends core::Object implements core::Enum {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+  synthetic constructor •() → self::A5
+    : super core::Object::•()
+    ;
+}
+abstract class M5 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.strong.transformed.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.strong.transformed.expect
new file mode 100644
index 0000000..061215b
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.strong.transformed.expect
@@ -0,0 +1,161 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:6:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:8:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:7:16: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:12:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:14:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:13:16: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:40:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:41:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:45:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:46:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:51:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:52:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:57:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:58:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:18:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'A2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:19:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'A2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:23:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'M2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:24:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'M2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A1 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class M1 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class A2 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class M2 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class A3 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class M3 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class A4 extends core::Object implements core::Enum {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+}
+abstract class M4 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+}
+abstract class A5 extends core::Object implements core::Enum {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+  synthetic constructor •() → self::A5
+    : super core::Object::•()
+    ;
+}
+abstract class M5 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.textual_outline.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.textual_outline.expect
new file mode 100644
index 0000000..2946b54
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.textual_outline.expect
@@ -0,0 +1,52 @@
+abstract class A1 implements Enum {
+  int get index => 0;
+  bool operator ==(Object other) => true;
+  int get hashCode => 1;
+}
+
+mixin M1 implements Enum {
+  int get index => 0;
+  bool operator ==(Object other) => true;
+  int get hashCode => 1;
+}
+
+abstract class A2 implements Enum {
+  void set index(String value) {}
+  void set hashCode(double value) {}
+}
+
+mixin M2 implements Enum {
+  void set index(String value) {}
+  void set hashCode(double value) {}
+}
+
+abstract class A3 implements Enum {
+  int get index;
+  bool operator ==(Object other);
+  int get HashCode;
+}
+
+mixin M3 implements Enum {
+  int get index;
+  bool operator ==(Object other);
+  int get HashCode;
+}
+
+abstract class A4 implements Enum {
+  int index = 0;
+  int hashCode = 1;
+}
+
+mixin M4 implements Enum {
+  int index = 0;
+  int hashCode = 1;
+}
+
+abstract class A5 implements Enum {
+  int foo = 0, bar = 1, index = 2, hashCode = 3;
+}
+
+mixin M5 implements Enum {
+  int foo = 0, bar = 1, index = 2, hashCode = 3;
+}
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..6daef0a
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.textual_outline_modelled.expect
@@ -0,0 +1,48 @@
+abstract class A1 implements Enum {
+  bool operator ==(Object other) => true;
+  int get hashCode => 1;
+  int get index => 0;
+}
+
+abstract class A2 implements Enum {
+  void set hashCode(double value) {}
+  void set index(String value) {}
+}
+
+abstract class A3 implements Enum {
+  bool operator ==(Object other);
+  int get HashCode;
+  int get index;
+}
+
+abstract class A4 implements Enum {
+  int hashCode = 1;
+  int index = 0;
+}
+
+abstract class A5 implements Enum {
+  int foo = 0, bar = 1, index = 2, hashCode = 3;
+}
+
+main() {}
+mixin M1 implements Enum {
+  bool operator ==(Object other) => true;
+  int get hashCode => 1;
+  int get index => 0;
+}
+mixin M2 implements Enum {
+  void set hashCode(double value) {}
+  void set index(String value) {}
+}
+mixin M3 implements Enum {
+  bool operator ==(Object other);
+  int get HashCode;
+  int get index;
+}
+mixin M4 implements Enum {
+  int hashCode = 1;
+  int index = 0;
+}
+mixin M5 implements Enum {
+  int foo = 0, bar = 1, index = 2, hashCode = 3;
+}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.expect
new file mode 100644
index 0000000..061215b
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.expect
@@ -0,0 +1,161 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:6:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:8:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:7:16: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:12:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:14:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:13:16: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:40:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:41:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:45:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:46:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:51:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:52:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:57:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:58:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:18:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'A2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:19:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'A2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:23:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'M2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:24:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'M2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A1 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class M1 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class A2 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class M2 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class A3 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class M3 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class A4 extends core::Object implements core::Enum {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+}
+abstract class M4 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+}
+abstract class A5 extends core::Object implements core::Enum {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+  synthetic constructor •() → self::A5
+    : super core::Object::•()
+    ;
+}
+abstract class M5 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.modular.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.modular.expect
new file mode 100644
index 0000000..061215b
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.modular.expect
@@ -0,0 +1,161 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:6:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:8:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:7:16: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:12:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:14:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:13:16: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:40:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:41:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:45:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:46:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:51:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:52:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:57:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:58:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:18:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'A2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:19:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'A2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:23:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'M2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:24:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'M2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A1 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class M1 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class A2 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class M2 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class A3 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class M3 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class A4 extends core::Object implements core::Enum {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+}
+abstract class M4 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+}
+abstract class A5 extends core::Object implements core::Enum {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+  synthetic constructor •() → self::A5
+    : super core::Object::•()
+    ;
+}
+abstract class M5 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.outline.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.outline.expect
new file mode 100644
index 0000000..169a70c
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.outline.expect
@@ -0,0 +1,161 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:6:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:8:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:7:16: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:12:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:14:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:13:16: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:40:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:41:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:45:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:46:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:51:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:52:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:57:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:58:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:18:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'A2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:19:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'A2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:23:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'M2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:24:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'M2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A1 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A1
+    ;
+  get index() → core::int
+    ;
+  operator ==(core::Object other) → core::bool
+    ;
+  get hashCode() → core::int
+    ;
+}
+abstract class M1 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  get index() → core::int
+    ;
+  operator ==(core::Object other) → core::bool
+    ;
+  get hashCode() → core::int
+    ;
+}
+abstract class A2 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A2
+    ;
+  set index(core::String value) → void
+    ;
+  set hashCode(core::double value) → void
+    ;
+}
+abstract class M2 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  set index(core::String value) → void
+    ;
+  set hashCode(core::double value) → void
+    ;
+}
+abstract class A3 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A3
+    ;
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class M3 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class A4 extends core::Object implements core::Enum {
+  field core::int index;
+  field core::int hashCode;
+  synthetic constructor •() → self::A4
+    ;
+}
+abstract class M4 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int index;
+  field core::int hashCode;
+}
+abstract class A5 extends core::Object implements core::Enum {
+  field core::int foo;
+  field core::int bar;
+  field core::int index;
+  field core::int hashCode;
+  synthetic constructor •() → self::A5
+    ;
+}
+abstract class M5 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int foo;
+  field core::int bar;
+  field core::int index;
+  field core::int hashCode;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.transformed.expect b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.transformed.expect
new file mode 100644
index 0000000..061215b
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart.weak.transformed.expect
@@ -0,0 +1,161 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:6:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:8:11: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:7:16: Error: 'A1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:12:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int get index => 0; // Error.
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:14:11: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int get hashCode => 1; // Error.
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:13:16: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static members with name '=='.
+//   bool operator==(Object other) => true; // Error.
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:40:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:41:7: Error: 'A4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:45:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//   int index = 0; // Error.
+//       ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:46:7: Error: 'M4' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//   int hashCode = 1; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:51:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:52:5: Error: 'A5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:57:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'index'.
+//     index = 2, // Error.
+//     ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:58:5: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static members with name 'hashCode'.
+//     hashCode = 3; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:18:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'A2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:19:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'A2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:23:12: Error: The type 'int' of the inherited getter 'Enum.index' is not a subtype of the type 'String' of the setter 'M2.index'.
+//   void set index(String value) {} // Error.
+//            ^^^^^
+// sdk/lib/core/enum.dart:22:11: Context: This is the declaration of the getter 'Enum.index'.
+//   int get index;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/enum_implementers_with_restricted_members.dart:24:12: Error: The type 'int' of the inherited getter 'Object.hashCode' is not a subtype of the type 'double' of the setter 'M2.hashCode'.
+//   void set hashCode(double value) {} // Error.
+//            ^^^^^^^^
+// sdk/lib/_internal/vm/lib/object_patch.dart:24:11: Context: This is the declaration of the getter 'Object.hashCode'.
+//   int get hashCode => _getHash(this);
+//           ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A1 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class M1 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 0;
+  operator ==(core::Object other) → core::bool
+    return true;
+  get hashCode() → core::int
+    return 1;
+}
+abstract class A2 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class M2 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  set index(core::String value) → void {}
+  set hashCode(core::double value) → void {}
+}
+abstract class A3 extends core::Object implements core::Enum {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class M3 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+  abstract get HashCode() → core::int;
+}
+abstract class A4 extends core::Object implements core::Enum {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+}
+abstract class M4 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int index = 0;
+  field core::int hashCode = 1;
+}
+abstract class A5 extends core::Object implements core::Enum {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+  synthetic constructor •() → self::A5
+    : super core::Object::•()
+    ;
+}
+abstract class M5 extends core::Object implements core::Enum /*isMixinDeclaration*/  {
+  field core::int foo = 0;
+  field core::int bar = 1;
+  field core::int index = 2;
+  field core::int hashCode = 3;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart
new file mode 100644
index 0000000..d294528
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A1 {
+  int get hashCode => 42;
+}
+
+enum E1 with A1 { // Error.
+  element
+}
+
+class A2 {
+  int get values => 42;
+}
+
+enum E2 with A2 { // Error.
+  element
+}
+
+class A3 {
+  int get index => 42;
+}
+
+enum E3 with A3 { // Error.
+  element
+}
+
+class A4 {
+  bool operator==(Object other) => true;
+}
+
+enum E4 with A4 { // Error.
+  element
+}
+
+mixin M5 {
+  int get hashCode => 42;
+}
+
+enum E5 with M5 { // Error.
+  element
+}
+
+mixin M6 {
+  int get values => 42;
+}
+
+enum E6 with M6 { // Error.
+  element
+}
+
+mixin M7 {
+  int get index => 42;
+}
+
+enum E7 with M7 { // Error.
+  element
+}
+
+mixin M8 {
+  bool operator==(Object other) => true;
+}
+
+enum E8 with M8 { // Error.
+  element
+}
+
+abstract class A9 {
+  int get index;
+  int get hashCode;
+  bool operator==(Object other);
+}
+
+enum E9 with A9 { // Ok.
+  element
+}
+
+mixin M10 {
+  int get index;
+  int get hashCode;
+  bool operator==(Object other);
+}
+
+enum E10 with M10 { // Ok.
+  element
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.strong.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.strong.expect
new file mode 100644
index 0000000..3a4a2bf
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.strong.expect
@@ -0,0 +1,348 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E2 with A2 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E6 with M6 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:9:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E1 with A1 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:6:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: An enum can't inherit a member named 'values'.
+// enum E2 with A2 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:25:6: Error: An enum can't inherit a member named 'index'.
+// enum E3 with A3 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:22:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:33:6: Error: An enum can't inherit a member named '=='.
+// enum E4 with A4 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:30:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:41:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E5 with M5 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:38:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: An enum can't inherit a member named 'values'.
+// enum E6 with M6 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:57:6: Error: An enum can't inherit a member named 'index'.
+// enum E7 with M7 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:54:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:65:6: Error: An enum can't inherit a member named '=='.
+// enum E8 with M8 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:62:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A1 extends core::Object {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E1&_Enum&A1 = core::_Enum with self::A1 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A1
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::A1::hashCode};
+}
+class E1 extends self::_E1&_Enum&A1 /*isEnum*/  {
+  static const field core::List<self::E1> values = #C4;
+  static const field self::E1 element = #C3;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A1::•(index, name)
+    ;
+  method toString() → core::String
+    return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class A2 extends core::Object {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  get values() → core::int
+    return 42;
+}
+abstract class _E2&_Enum&A2 = core::_Enum with self::A2 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A2
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::A2::values};
+}
+class E2 extends self::_E2&_Enum&A2 /*isEnum*/  {
+  static const field core::List<self::E2> values = #C6;
+  static const field self::E2 element = #C5;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A2::•(index, name)
+    ;
+  method toString() → core::String
+    return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class A3 extends core::Object {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 42;
+}
+abstract class _E3&_Enum&A3 = core::_Enum with self::A3 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&A3
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::A3::index};
+}
+class E3 extends self::_E3&_Enum&A3 /*isEnum*/  {
+  static const field core::List<self::E3> values = #C8;
+  static const field self::E3 element = #C7;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&A3::•(index, name)
+    ;
+  method toString() → core::String
+    return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class A4 extends core::Object {
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E4&_Enum&A4 = core::_Enum with self::A4 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E4&_Enum&A4
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::A4::==}(other);
+}
+class E4 extends self::_E4&_Enum&A4 /*isEnum*/  {
+  static const field core::List<self::E4> values = #C10;
+  static const field self::E4 element = #C9;
+  const constructor •(core::int index, core::String name) → self::E4
+    : super self::_E4&_Enum&A4::•(index, name)
+    ;
+  method toString() → core::String
+    return "E4.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M5 extends core::Object /*isMixinDeclaration*/  {
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E5&_Enum&M5 = core::_Enum with self::M5 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E5&_Enum&M5
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::M5::hashCode};
+}
+class E5 extends self::_E5&_Enum&M5 /*isEnum*/  {
+  static const field core::List<self::E5> values = #C12;
+  static const field self::E5 element = #C11;
+  const constructor •(core::int index, core::String name) → self::E5
+    : super self::_E5&_Enum&M5::•(index, name)
+    ;
+  method toString() → core::String
+    return "E5.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M6 extends core::Object /*isMixinDeclaration*/  {
+  get values() → core::int
+    return 42;
+}
+abstract class _E6&_Enum&M6 = core::_Enum with self::M6 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E6&_Enum&M6
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::M6::values};
+}
+class E6 extends self::_E6&_Enum&M6 /*isEnum*/  {
+  static const field core::List<self::E6> values = #C14;
+  static const field self::E6 element = #C13;
+  const constructor •(core::int index, core::String name) → self::E6
+    : super self::_E6&_Enum&M6::•(index, name)
+    ;
+  method toString() → core::String
+    return "E6.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M7 extends core::Object /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 42;
+}
+abstract class _E7&_Enum&M7 = core::_Enum with self::M7 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&M7
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::M7::index};
+}
+class E7 extends self::_E7&_Enum&M7 /*isEnum*/  {
+  static const field core::List<self::E7> values = #C16;
+  static const field self::E7 element = #C15;
+  const constructor •(core::int index, core::String name) → self::E7
+    : super self::_E7&_Enum&M7::•(index, name)
+    ;
+  method toString() → core::String
+    return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M8 extends core::Object /*isMixinDeclaration*/  {
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E8&_Enum&M8 = core::_Enum with self::M8 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E8&_Enum&M8
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::M8::==}(other);
+}
+class E8 extends self::_E8&_Enum&M8 /*isEnum*/  {
+  static const field core::List<self::E8> values = #C18;
+  static const field self::E8 element = #C17;
+  const constructor •(core::int index, core::String name) → self::E8
+    : super self::_E8&_Enum&M8::•(index, name)
+    ;
+  method toString() → core::String
+    return "E8.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class A9 extends core::Object {
+  synthetic constructor •() → self::A9
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E9&_Enum&A9 = core::_Enum with self::A9 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E9&_Enum&A9
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::A9::index
+  abstract mixin-stub get hashCode() → core::int; -> self::A9::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::A9::==
+}
+class E9 extends self::_E9&_Enum&A9 /*isEnum*/  {
+  static const field core::List<self::E9> values = #C20;
+  static const field self::E9 element = #C19;
+  const constructor •(core::int index, core::String name) → self::E9
+    : super self::_E9&_Enum&A9::•(index, name)
+    ;
+  method toString() → core::String
+    return "E9.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M10 extends core::Object /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E10&_Enum&M10 = core::_Enum with self::M10 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E10&_Enum&M10
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::M10::index
+  abstract mixin-stub get hashCode() → core::int; -> self::M10::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::M10::==
+}
+class E10 extends self::_E10&_Enum&M10 /*isEnum*/  {
+  static const field core::List<self::E10> values = #C22;
+  static const field self::E10 element = #C21;
+  const constructor •(core::int index, core::String name) → self::E10
+    : super self::_E10&_Enum&M10::•(index, name)
+    ;
+  method toString() → core::String
+    return "E10.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = <self::E1>[#C3]
+  #C5 = self::E2 {index:#C1, _name:#C2}
+  #C6 = <self::E2>[#C5]
+  #C7 = self::E3 {index:#C1, _name:#C2}
+  #C8 = <self::E3>[#C7]
+  #C9 = self::E4 {index:#C1, _name:#C2}
+  #C10 = <self::E4>[#C9]
+  #C11 = self::E5 {index:#C1, _name:#C2}
+  #C12 = <self::E5>[#C11]
+  #C13 = self::E6 {index:#C1, _name:#C2}
+  #C14 = <self::E6>[#C13]
+  #C15 = self::E7 {index:#C1, _name:#C2}
+  #C16 = <self::E7>[#C15]
+  #C17 = self::E8 {index:#C1, _name:#C2}
+  #C18 = <self::E8>[#C17]
+  #C19 = self::E9 {index:#C1, _name:#C2}
+  #C20 = <self::E9>[#C19]
+  #C21 = self::E10 {index:#C1, _name:#C2}
+  #C22 = <self::E10>[#C21]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///inherited_restricted_members.dart:
+- E1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _E1&_Enum&A1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- _E2&_Enum&A2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- E3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- _E3&_Enum&A3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- E4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- _E4&_Enum&A4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- E5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- _E5&_Enum&M5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- E6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- _E6&_Enum&M6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- E7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- _E7&_Enum&M7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- E8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- _E8&_Enum&M8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- E9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- _E9&_Enum&A9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- E10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
+- _E10&_Enum&M10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.strong.transformed.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.strong.transformed.expect
new file mode 100644
index 0000000..80daf575
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.strong.transformed.expect
@@ -0,0 +1,348 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E2 with A2 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E6 with M6 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:9:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E1 with A1 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:6:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: An enum can't inherit a member named 'values'.
+// enum E2 with A2 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:25:6: Error: An enum can't inherit a member named 'index'.
+// enum E3 with A3 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:22:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:33:6: Error: An enum can't inherit a member named '=='.
+// enum E4 with A4 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:30:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:41:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E5 with M5 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:38:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: An enum can't inherit a member named 'values'.
+// enum E6 with M6 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:57:6: Error: An enum can't inherit a member named 'index'.
+// enum E7 with M7 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:54:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:65:6: Error: An enum can't inherit a member named '=='.
+// enum E8 with M8 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:62:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A1 extends core::Object {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E1&_Enum&A1 extends core::_Enum implements self::A1 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A1
+    : super core::_Enum::•(index, _name)
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+class E1 extends self::_E1&_Enum&A1 /*isEnum*/  {
+  static const field core::List<self::E1> values = #C4;
+  static const field self::E1 element = #C3;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A1::•(index, name)
+    ;
+  method toString() → core::String
+    return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class A2 extends core::Object {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  get values() → core::int
+    return 42;
+}
+abstract class _E2&_Enum&A2 extends core::_Enum implements self::A2 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A2
+    : super core::_Enum::•(index, _name)
+    ;
+  get values() → core::int
+    return 42;
+}
+class E2 extends self::_E2&_Enum&A2 /*isEnum*/  {
+  static const field core::List<self::E2> values = #C6;
+  static const field self::E2 element = #C5;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A2::•(index, name)
+    ;
+  method toString() → core::String
+    return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class A3 extends core::Object {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 42;
+}
+abstract class _E3&_Enum&A3 extends core::_Enum implements self::A3 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&A3
+    : super core::_Enum::•(index, _name)
+    ;
+  get index() → core::int
+    return 42;
+}
+class E3 extends self::_E3&_Enum&A3 /*isEnum*/  {
+  static const field core::List<self::E3> values = #C8;
+  static const field self::E3 element = #C7;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&A3::•(index, name)
+    ;
+  method toString() → core::String
+    return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class A4 extends core::Object {
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E4&_Enum&A4 extends core::_Enum implements self::A4 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E4&_Enum&A4
+    : super core::_Enum::•(index, _name)
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+class E4 extends self::_E4&_Enum&A4 /*isEnum*/  {
+  static const field core::List<self::E4> values = #C10;
+  static const field self::E4 element = #C9;
+  const constructor •(core::int index, core::String name) → self::E4
+    : super self::_E4&_Enum&A4::•(index, name)
+    ;
+  method toString() → core::String
+    return "E4.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M5 extends core::Object /*isMixinDeclaration*/  {
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E5&_Enum&M5 extends core::_Enum implements self::M5 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E5&_Enum&M5
+    : super core::_Enum::•(index, _name)
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+class E5 extends self::_E5&_Enum&M5 /*isEnum*/  {
+  static const field core::List<self::E5> values = #C12;
+  static const field self::E5 element = #C11;
+  const constructor •(core::int index, core::String name) → self::E5
+    : super self::_E5&_Enum&M5::•(index, name)
+    ;
+  method toString() → core::String
+    return "E5.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M6 extends core::Object /*isMixinDeclaration*/  {
+  get values() → core::int
+    return 42;
+}
+abstract class _E6&_Enum&M6 extends core::_Enum implements self::M6 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E6&_Enum&M6
+    : super core::_Enum::•(index, _name)
+    ;
+  get values() → core::int
+    return 42;
+}
+class E6 extends self::_E6&_Enum&M6 /*isEnum*/  {
+  static const field core::List<self::E6> values = #C14;
+  static const field self::E6 element = #C13;
+  const constructor •(core::int index, core::String name) → self::E6
+    : super self::_E6&_Enum&M6::•(index, name)
+    ;
+  method toString() → core::String
+    return "E6.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M7 extends core::Object /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 42;
+}
+abstract class _E7&_Enum&M7 extends core::_Enum implements self::M7 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&M7
+    : super core::_Enum::•(index, _name)
+    ;
+  get index() → core::int
+    return 42;
+}
+class E7 extends self::_E7&_Enum&M7 /*isEnum*/  {
+  static const field core::List<self::E7> values = #C16;
+  static const field self::E7 element = #C15;
+  const constructor •(core::int index, core::String name) → self::E7
+    : super self::_E7&_Enum&M7::•(index, name)
+    ;
+  method toString() → core::String
+    return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M8 extends core::Object /*isMixinDeclaration*/  {
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E8&_Enum&M8 extends core::_Enum implements self::M8 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E8&_Enum&M8
+    : super core::_Enum::•(index, _name)
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+class E8 extends self::_E8&_Enum&M8 /*isEnum*/  {
+  static const field core::List<self::E8> values = #C18;
+  static const field self::E8 element = #C17;
+  const constructor •(core::int index, core::String name) → self::E8
+    : super self::_E8&_Enum&M8::•(index, name)
+    ;
+  method toString() → core::String
+    return "E8.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class A9 extends core::Object {
+  synthetic constructor •() → self::A9
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E9&_Enum&A9 extends core::_Enum implements self::A9 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E9&_Enum&A9
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+class E9 extends self::_E9&_Enum&A9 /*isEnum*/  {
+  static const field core::List<self::E9> values = #C20;
+  static const field self::E9 element = #C19;
+  const constructor •(core::int index, core::String name) → self::E9
+    : super self::_E9&_Enum&A9::•(index, name)
+    ;
+  method toString() → core::String
+    return "E9.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M10 extends core::Object /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E10&_Enum&M10 extends core::_Enum implements self::M10 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E10&_Enum&M10
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+class E10 extends self::_E10&_Enum&M10 /*isEnum*/  {
+  static const field core::List<self::E10> values = #C22;
+  static const field self::E10 element = #C21;
+  const constructor •(core::int index, core::String name) → self::E10
+    : super self::_E10&_Enum&M10::•(index, name)
+    ;
+  method toString() → core::String
+    return "E10.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = <self::E1>[#C3]
+  #C5 = self::E2 {index:#C1, _name:#C2}
+  #C6 = <self::E2>[#C5]
+  #C7 = self::E3 {index:#C1, _name:#C2}
+  #C8 = <self::E3>[#C7]
+  #C9 = self::E4 {index:#C1, _name:#C2}
+  #C10 = <self::E4>[#C9]
+  #C11 = self::E5 {index:#C1, _name:#C2}
+  #C12 = <self::E5>[#C11]
+  #C13 = self::E6 {index:#C1, _name:#C2}
+  #C14 = <self::E6>[#C13]
+  #C15 = self::E7 {index:#C1, _name:#C2}
+  #C16 = <self::E7>[#C15]
+  #C17 = self::E8 {index:#C1, _name:#C2}
+  #C18 = <self::E8>[#C17]
+  #C19 = self::E9 {index:#C1, _name:#C2}
+  #C20 = <self::E9>[#C19]
+  #C21 = self::E10 {index:#C1, _name:#C2}
+  #C22 = <self::E10>[#C21]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///inherited_restricted_members.dart:
+- E1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _E1&_Enum&A1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- _E2&_Enum&A2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- E3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- _E3&_Enum&A3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- E4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- _E4&_Enum&A4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- E5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- _E5&_Enum&M5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- E6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- _E6&_Enum&M6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- E7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- _E7&_Enum&M7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- E8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- _E8&_Enum&M8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- E9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- _E9&_Enum&A9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- E10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
+- _E10&_Enum&M10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.textual_outline.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.textual_outline.expect
new file mode 100644
index 0000000..52a0730
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.textual_outline.expect
@@ -0,0 +1,65 @@
+class A1 {
+  int get hashCode => 42;
+}
+
+enum E1 with A1 { element }
+
+class A2 {
+  int get values => 42;
+}
+
+enum E2 with A2 { element }
+
+class A3 {
+  int get index => 42;
+}
+
+enum E3 with A3 { element }
+
+class A4 {
+  bool operator ==(Object other) => true;
+}
+
+enum E4 with A4 { element }
+
+mixin M5 {
+  int get hashCode => 42;
+}
+
+enum E5 with M5 { element }
+
+mixin M6 {
+  int get values => 42;
+}
+
+enum E6 with M6 { element }
+
+mixin M7 {
+  int get index => 42;
+}
+
+enum E7 with M7 { element }
+
+mixin M8 {
+  bool operator ==(Object other) => true;
+}
+
+enum E8 with M8 { element }
+
+abstract class A9 {
+  int get index;
+  int get hashCode;
+  bool operator ==(Object other);
+}
+
+enum E9 with A9 { element }
+
+mixin M10 {
+  int get index;
+  int get hashCode;
+  bool operator ==(Object other);
+}
+
+enum E10 with M10 { element }
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..38785e8
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.textual_outline_modelled.expect
@@ -0,0 +1,60 @@
+abstract class A9 {
+  bool operator ==(Object other);
+  int get hashCode;
+  int get index;
+}
+
+class A1 {
+  int get hashCode => 42;
+}
+
+class A2 {
+  int get values => 42;
+}
+
+class A3 {
+  int get index => 42;
+}
+
+class A4 {
+  bool operator ==(Object other) => true;
+}
+
+enum E1 with A1 { element }
+
+enum E10 with M10 { element }
+
+enum E2 with A2 { element }
+
+enum E3 with A3 { element }
+
+enum E4 with A4 { element }
+
+enum E5 with M5 { element }
+
+enum E6 with M6 { element }
+
+enum E7 with M7 { element }
+
+enum E8 with M8 { element }
+
+enum E9 with A9 { element }
+
+main() {}
+mixin M10 {
+  bool operator ==(Object other);
+  int get hashCode;
+  int get index;
+}
+mixin M5 {
+  int get hashCode => 42;
+}
+mixin M6 {
+  int get values => 42;
+}
+mixin M7 {
+  int get index => 42;
+}
+mixin M8 {
+  bool operator ==(Object other) => true;
+}
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.expect
new file mode 100644
index 0000000..0e8de44
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.expect
@@ -0,0 +1,348 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E2 with A2 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E6 with M6 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:9:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E1 with A1 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:6:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: An enum can't inherit a member named 'values'.
+// enum E2 with A2 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:25:6: Error: An enum can't inherit a member named 'index'.
+// enum E3 with A3 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:22:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:33:6: Error: An enum can't inherit a member named '=='.
+// enum E4 with A4 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:30:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:41:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E5 with M5 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:38:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: An enum can't inherit a member named 'values'.
+// enum E6 with M6 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:57:6: Error: An enum can't inherit a member named 'index'.
+// enum E7 with M7 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:54:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:65:6: Error: An enum can't inherit a member named '=='.
+// enum E8 with M8 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:62:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A1 extends core::Object {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E1&_Enum&A1 = core::_Enum with self::A1 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A1
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::A1::hashCode};
+}
+class E1 extends self::_E1&_Enum&A1 /*isEnum*/  {
+  static const field core::List<self::E1> values = #C4;
+  static const field self::E1 element = #C3;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A1::•(index, name)
+    ;
+  method toString() → core::String
+    return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class A2 extends core::Object {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  get values() → core::int
+    return 42;
+}
+abstract class _E2&_Enum&A2 = core::_Enum with self::A2 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A2
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::A2::values};
+}
+class E2 extends self::_E2&_Enum&A2 /*isEnum*/  {
+  static const field core::List<self::E2> values = #C6;
+  static const field self::E2 element = #C5;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A2::•(index, name)
+    ;
+  method toString() → core::String
+    return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class A3 extends core::Object {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 42;
+}
+abstract class _E3&_Enum&A3 = core::_Enum with self::A3 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&A3
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::A3::index};
+}
+class E3 extends self::_E3&_Enum&A3 /*isEnum*/  {
+  static const field core::List<self::E3> values = #C8;
+  static const field self::E3 element = #C7;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&A3::•(index, name)
+    ;
+  method toString() → core::String
+    return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class A4 extends core::Object {
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E4&_Enum&A4 = core::_Enum with self::A4 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E4&_Enum&A4
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::A4::==}(other);
+}
+class E4 extends self::_E4&_Enum&A4 /*isEnum*/  {
+  static const field core::List<self::E4> values = #C10;
+  static const field self::E4 element = #C9;
+  const constructor •(core::int index, core::String name) → self::E4
+    : super self::_E4&_Enum&A4::•(index, name)
+    ;
+  method toString() → core::String
+    return "E4.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M5 extends core::Object /*isMixinDeclaration*/  {
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E5&_Enum&M5 = core::_Enum with self::M5 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E5&_Enum&M5
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::M5::hashCode};
+}
+class E5 extends self::_E5&_Enum&M5 /*isEnum*/  {
+  static const field core::List<self::E5> values = #C12;
+  static const field self::E5 element = #C11;
+  const constructor •(core::int index, core::String name) → self::E5
+    : super self::_E5&_Enum&M5::•(index, name)
+    ;
+  method toString() → core::String
+    return "E5.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M6 extends core::Object /*isMixinDeclaration*/  {
+  get values() → core::int
+    return 42;
+}
+abstract class _E6&_Enum&M6 = core::_Enum with self::M6 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E6&_Enum&M6
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::M6::values};
+}
+class E6 extends self::_E6&_Enum&M6 /*isEnum*/  {
+  static const field core::List<self::E6> values = #C14;
+  static const field self::E6 element = #C13;
+  const constructor •(core::int index, core::String name) → self::E6
+    : super self::_E6&_Enum&M6::•(index, name)
+    ;
+  method toString() → core::String
+    return "E6.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M7 extends core::Object /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 42;
+}
+abstract class _E7&_Enum&M7 = core::_Enum with self::M7 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&M7
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::M7::index};
+}
+class E7 extends self::_E7&_Enum&M7 /*isEnum*/  {
+  static const field core::List<self::E7> values = #C16;
+  static const field self::E7 element = #C15;
+  const constructor •(core::int index, core::String name) → self::E7
+    : super self::_E7&_Enum&M7::•(index, name)
+    ;
+  method toString() → core::String
+    return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M8 extends core::Object /*isMixinDeclaration*/  {
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E8&_Enum&M8 = core::_Enum with self::M8 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E8&_Enum&M8
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::M8::==}(other);
+}
+class E8 extends self::_E8&_Enum&M8 /*isEnum*/  {
+  static const field core::List<self::E8> values = #C18;
+  static const field self::E8 element = #C17;
+  const constructor •(core::int index, core::String name) → self::E8
+    : super self::_E8&_Enum&M8::•(index, name)
+    ;
+  method toString() → core::String
+    return "E8.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class A9 extends core::Object {
+  synthetic constructor •() → self::A9
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E9&_Enum&A9 = core::_Enum with self::A9 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E9&_Enum&A9
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::A9::index
+  abstract mixin-stub get hashCode() → core::int; -> self::A9::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::A9::==
+}
+class E9 extends self::_E9&_Enum&A9 /*isEnum*/  {
+  static const field core::List<self::E9> values = #C20;
+  static const field self::E9 element = #C19;
+  const constructor •(core::int index, core::String name) → self::E9
+    : super self::_E9&_Enum&A9::•(index, name)
+    ;
+  method toString() → core::String
+    return "E9.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M10 extends core::Object /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E10&_Enum&M10 = core::_Enum with self::M10 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E10&_Enum&M10
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::M10::index
+  abstract mixin-stub get hashCode() → core::int; -> self::M10::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::M10::==
+}
+class E10 extends self::_E10&_Enum&M10 /*isEnum*/  {
+  static const field core::List<self::E10> values = #C22;
+  static const field self::E10 element = #C21;
+  const constructor •(core::int index, core::String name) → self::E10
+    : super self::_E10&_Enum&M10::•(index, name)
+    ;
+  method toString() → core::String
+    return "E10.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = <self::E1*>[#C3]
+  #C5 = self::E2 {index:#C1, _name:#C2}
+  #C6 = <self::E2*>[#C5]
+  #C7 = self::E3 {index:#C1, _name:#C2}
+  #C8 = <self::E3*>[#C7]
+  #C9 = self::E4 {index:#C1, _name:#C2}
+  #C10 = <self::E4*>[#C9]
+  #C11 = self::E5 {index:#C1, _name:#C2}
+  #C12 = <self::E5*>[#C11]
+  #C13 = self::E6 {index:#C1, _name:#C2}
+  #C14 = <self::E6*>[#C13]
+  #C15 = self::E7 {index:#C1, _name:#C2}
+  #C16 = <self::E7*>[#C15]
+  #C17 = self::E8 {index:#C1, _name:#C2}
+  #C18 = <self::E8*>[#C17]
+  #C19 = self::E9 {index:#C1, _name:#C2}
+  #C20 = <self::E9*>[#C19]
+  #C21 = self::E10 {index:#C1, _name:#C2}
+  #C22 = <self::E10*>[#C21]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///inherited_restricted_members.dart:
+- E1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _E1&_Enum&A1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- _E2&_Enum&A2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- E3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- _E3&_Enum&A3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- E4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- _E4&_Enum&A4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- E5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- _E5&_Enum&M5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- E6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- _E6&_Enum&M6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- E7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- _E7&_Enum&M7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- E8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- _E8&_Enum&M8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- E9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- _E9&_Enum&A9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- E10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
+- _E10&_Enum&M10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.modular.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.modular.expect
new file mode 100644
index 0000000..0e8de44
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.modular.expect
@@ -0,0 +1,348 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E2 with A2 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E6 with M6 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:9:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E1 with A1 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:6:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: An enum can't inherit a member named 'values'.
+// enum E2 with A2 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:25:6: Error: An enum can't inherit a member named 'index'.
+// enum E3 with A3 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:22:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:33:6: Error: An enum can't inherit a member named '=='.
+// enum E4 with A4 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:30:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:41:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E5 with M5 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:38:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: An enum can't inherit a member named 'values'.
+// enum E6 with M6 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:57:6: Error: An enum can't inherit a member named 'index'.
+// enum E7 with M7 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:54:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:65:6: Error: An enum can't inherit a member named '=='.
+// enum E8 with M8 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:62:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A1 extends core::Object {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E1&_Enum&A1 = core::_Enum with self::A1 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A1
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::A1::hashCode};
+}
+class E1 extends self::_E1&_Enum&A1 /*isEnum*/  {
+  static const field core::List<self::E1> values = #C4;
+  static const field self::E1 element = #C3;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A1::•(index, name)
+    ;
+  method toString() → core::String
+    return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class A2 extends core::Object {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  get values() → core::int
+    return 42;
+}
+abstract class _E2&_Enum&A2 = core::_Enum with self::A2 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A2
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::A2::values};
+}
+class E2 extends self::_E2&_Enum&A2 /*isEnum*/  {
+  static const field core::List<self::E2> values = #C6;
+  static const field self::E2 element = #C5;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A2::•(index, name)
+    ;
+  method toString() → core::String
+    return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class A3 extends core::Object {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 42;
+}
+abstract class _E3&_Enum&A3 = core::_Enum with self::A3 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&A3
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::A3::index};
+}
+class E3 extends self::_E3&_Enum&A3 /*isEnum*/  {
+  static const field core::List<self::E3> values = #C8;
+  static const field self::E3 element = #C7;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&A3::•(index, name)
+    ;
+  method toString() → core::String
+    return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class A4 extends core::Object {
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E4&_Enum&A4 = core::_Enum with self::A4 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E4&_Enum&A4
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::A4::==}(other);
+}
+class E4 extends self::_E4&_Enum&A4 /*isEnum*/  {
+  static const field core::List<self::E4> values = #C10;
+  static const field self::E4 element = #C9;
+  const constructor •(core::int index, core::String name) → self::E4
+    : super self::_E4&_Enum&A4::•(index, name)
+    ;
+  method toString() → core::String
+    return "E4.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M5 extends core::Object /*isMixinDeclaration*/  {
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E5&_Enum&M5 = core::_Enum with self::M5 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E5&_Enum&M5
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::M5::hashCode};
+}
+class E5 extends self::_E5&_Enum&M5 /*isEnum*/  {
+  static const field core::List<self::E5> values = #C12;
+  static const field self::E5 element = #C11;
+  const constructor •(core::int index, core::String name) → self::E5
+    : super self::_E5&_Enum&M5::•(index, name)
+    ;
+  method toString() → core::String
+    return "E5.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M6 extends core::Object /*isMixinDeclaration*/  {
+  get values() → core::int
+    return 42;
+}
+abstract class _E6&_Enum&M6 = core::_Enum with self::M6 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E6&_Enum&M6
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::M6::values};
+}
+class E6 extends self::_E6&_Enum&M6 /*isEnum*/  {
+  static const field core::List<self::E6> values = #C14;
+  static const field self::E6 element = #C13;
+  const constructor •(core::int index, core::String name) → self::E6
+    : super self::_E6&_Enum&M6::•(index, name)
+    ;
+  method toString() → core::String
+    return "E6.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M7 extends core::Object /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 42;
+}
+abstract class _E7&_Enum&M7 = core::_Enum with self::M7 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&M7
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::M7::index};
+}
+class E7 extends self::_E7&_Enum&M7 /*isEnum*/  {
+  static const field core::List<self::E7> values = #C16;
+  static const field self::E7 element = #C15;
+  const constructor •(core::int index, core::String name) → self::E7
+    : super self::_E7&_Enum&M7::•(index, name)
+    ;
+  method toString() → core::String
+    return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M8 extends core::Object /*isMixinDeclaration*/  {
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E8&_Enum&M8 = core::_Enum with self::M8 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E8&_Enum&M8
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::M8::==}(other);
+}
+class E8 extends self::_E8&_Enum&M8 /*isEnum*/  {
+  static const field core::List<self::E8> values = #C18;
+  static const field self::E8 element = #C17;
+  const constructor •(core::int index, core::String name) → self::E8
+    : super self::_E8&_Enum&M8::•(index, name)
+    ;
+  method toString() → core::String
+    return "E8.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class A9 extends core::Object {
+  synthetic constructor •() → self::A9
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E9&_Enum&A9 = core::_Enum with self::A9 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E9&_Enum&A9
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::A9::index
+  abstract mixin-stub get hashCode() → core::int; -> self::A9::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::A9::==
+}
+class E9 extends self::_E9&_Enum&A9 /*isEnum*/  {
+  static const field core::List<self::E9> values = #C20;
+  static const field self::E9 element = #C19;
+  const constructor •(core::int index, core::String name) → self::E9
+    : super self::_E9&_Enum&A9::•(index, name)
+    ;
+  method toString() → core::String
+    return "E9.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M10 extends core::Object /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E10&_Enum&M10 = core::_Enum with self::M10 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E10&_Enum&M10
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::M10::index
+  abstract mixin-stub get hashCode() → core::int; -> self::M10::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::M10::==
+}
+class E10 extends self::_E10&_Enum&M10 /*isEnum*/  {
+  static const field core::List<self::E10> values = #C22;
+  static const field self::E10 element = #C21;
+  const constructor •(core::int index, core::String name) → self::E10
+    : super self::_E10&_Enum&M10::•(index, name)
+    ;
+  method toString() → core::String
+    return "E10.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = <self::E1*>[#C3]
+  #C5 = self::E2 {index:#C1, _name:#C2}
+  #C6 = <self::E2*>[#C5]
+  #C7 = self::E3 {index:#C1, _name:#C2}
+  #C8 = <self::E3*>[#C7]
+  #C9 = self::E4 {index:#C1, _name:#C2}
+  #C10 = <self::E4*>[#C9]
+  #C11 = self::E5 {index:#C1, _name:#C2}
+  #C12 = <self::E5*>[#C11]
+  #C13 = self::E6 {index:#C1, _name:#C2}
+  #C14 = <self::E6*>[#C13]
+  #C15 = self::E7 {index:#C1, _name:#C2}
+  #C16 = <self::E7*>[#C15]
+  #C17 = self::E8 {index:#C1, _name:#C2}
+  #C18 = <self::E8*>[#C17]
+  #C19 = self::E9 {index:#C1, _name:#C2}
+  #C20 = <self::E9*>[#C19]
+  #C21 = self::E10 {index:#C1, _name:#C2}
+  #C22 = <self::E10*>[#C21]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///inherited_restricted_members.dart:
+- E1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _E1&_Enum&A1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- _E2&_Enum&A2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- E3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- _E3&_Enum&A3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- E4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- _E4&_Enum&A4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- E5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- _E5&_Enum&M5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- E6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- _E6&_Enum&M6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- E7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- _E7&_Enum&M7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- E8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- _E8&_Enum&M8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- E9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- _E9&_Enum&A9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- E10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
+- _E10&_Enum&M10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.outline.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.outline.expect
new file mode 100644
index 0000000..774f207
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.outline.expect
@@ -0,0 +1,307 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E2 with A2 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E6 with M6 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:9:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E1 with A1 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:6:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: An enum can't inherit a member named 'values'.
+// enum E2 with A2 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:25:6: Error: An enum can't inherit a member named 'index'.
+// enum E3 with A3 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:22:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:33:6: Error: An enum can't inherit a member named '=='.
+// enum E4 with A4 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:30:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:41:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E5 with M5 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:38:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: An enum can't inherit a member named 'values'.
+// enum E6 with M6 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:57:6: Error: An enum can't inherit a member named 'index'.
+// enum E7 with M7 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:54:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:65:6: Error: An enum can't inherit a member named '=='.
+// enum E8 with M8 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:62:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A1 extends core::Object {
+  synthetic constructor •() → self::A1
+    ;
+  get hashCode() → core::int
+    ;
+}
+abstract class _E1&_Enum&A1 = core::_Enum with self::A1 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A1
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::A1::hashCode};
+}
+class E1 extends self::_E1&_Enum&A1 /*isEnum*/  {
+  static const field core::List<self::E1> values = const <self::E1>[self::E1::element];
+  static const field self::E1 element = const self::E1::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E1
+    ;
+  method toString() → core::String
+    return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class A2 extends core::Object {
+  synthetic constructor •() → self::A2
+    ;
+  get values() → core::int
+    ;
+}
+abstract class _E2&_Enum&A2 = core::_Enum with self::A2 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A2
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::A2::values};
+}
+class E2 extends self::_E2&_Enum&A2 /*isEnum*/  {
+  static const field core::List<self::E2> values = const <self::E2>[self::E2::element];
+  static const field self::E2 element = const self::E2::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E2
+    ;
+  method toString() → core::String
+    return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class A3 extends core::Object {
+  synthetic constructor •() → self::A3
+    ;
+  get index() → core::int
+    ;
+}
+abstract class _E3&_Enum&A3 = core::_Enum with self::A3 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&A3
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::A3::index};
+}
+class E3 extends self::_E3&_Enum&A3 /*isEnum*/  {
+  static const field core::List<self::E3> values = const <self::E3>[self::E3::element];
+  static const field self::E3 element = const self::E3::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E3
+    ;
+  method toString() → core::String
+    return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class A4 extends core::Object {
+  synthetic constructor •() → self::A4
+    ;
+  operator ==(core::Object other) → core::bool
+    ;
+}
+abstract class _E4&_Enum&A4 = core::_Enum with self::A4 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E4&_Enum&A4
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::A4::==}(other);
+}
+class E4 extends self::_E4&_Enum&A4 /*isEnum*/  {
+  static const field core::List<self::E4> values = const <self::E4>[self::E4::element];
+  static const field self::E4 element = const self::E4::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E4
+    ;
+  method toString() → core::String
+    return "E4.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M5 extends core::Object /*isMixinDeclaration*/  {
+  get hashCode() → core::int
+    ;
+}
+abstract class _E5&_Enum&M5 = core::_Enum with self::M5 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E5&_Enum&M5
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get hashCode() → core::int
+    return super.{self::M5::hashCode};
+}
+class E5 extends self::_E5&_Enum&M5 /*isEnum*/  {
+  static const field core::List<self::E5> values = const <self::E5>[self::E5::element];
+  static const field self::E5 element = const self::E5::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E5
+    ;
+  method toString() → core::String
+    return "E5.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M6 extends core::Object /*isMixinDeclaration*/  {
+  get values() → core::int
+    ;
+}
+abstract class _E6&_Enum&M6 = core::_Enum with self::M6 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E6&_Enum&M6
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get values() → core::int
+    return super.{self::M6::values};
+}
+class E6 extends self::_E6&_Enum&M6 /*isEnum*/  {
+  static const field core::List<self::E6> values = const <self::E6>[self::E6::element];
+  static const field self::E6 element = const self::E6::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E6
+    ;
+  method toString() → core::String
+    return "E6.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M7 extends core::Object /*isMixinDeclaration*/  {
+  get index() → core::int
+    ;
+}
+abstract class _E7&_Enum&M7 = core::_Enum with self::M7 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&M7
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get index() → core::int
+    return super.{self::M7::index};
+}
+class E7 extends self::_E7&_Enum&M7 /*isEnum*/  {
+  static const field core::List<self::E7> values = const <self::E7>[self::E7::element];
+  static const field self::E7 element = const self::E7::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E7
+    ;
+  method toString() → core::String
+    return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M8 extends core::Object /*isMixinDeclaration*/  {
+  operator ==(core::Object other) → core::bool
+    ;
+}
+abstract class _E8&_Enum&M8 = core::_Enum with self::M8 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E8&_Enum&M8
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub operator ==(core::Object other) → core::bool
+    return super.{self::M8::==}(other);
+}
+class E8 extends self::_E8&_Enum&M8 /*isEnum*/  {
+  static const field core::List<self::E8> values = const <self::E8>[self::E8::element];
+  static const field self::E8 element = const self::E8::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E8
+    ;
+  method toString() → core::String
+    return "E8.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class A9 extends core::Object {
+  synthetic constructor •() → self::A9
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E9&_Enum&A9 = core::_Enum with self::A9 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E9&_Enum&A9
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::A9::index
+  abstract mixin-stub get hashCode() → core::int; -> self::A9::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::A9::==
+}
+class E9 extends self::_E9&_Enum&A9 /*isEnum*/  {
+  static const field core::List<self::E9> values = const <self::E9>[self::E9::element];
+  static const field self::E9 element = const self::E9::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E9
+    ;
+  method toString() → core::String
+    return "E9.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M10 extends core::Object /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E10&_Enum&M10 = core::_Enum with self::M10 /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E10&_Enum&M10
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract mixin-stub get index() → core::int; -> self::M10::index
+  abstract mixin-stub get hashCode() → core::int; -> self::M10::hashCode
+  abstract mixin-stub operator ==(core::Object other) → core::bool; -> self::M10::==
+}
+class E10 extends self::_E10&_Enum&M10 /*isEnum*/  {
+  static const field core::List<self::E10> values = const <self::E10>[self::E10::element];
+  static const field self::E10 element = const self::E10::•(0, "element");
+  const constructor •(core::int index, core::String name) → self::E10
+    ;
+  method toString() → core::String
+    return "E10.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:9:6 -> ListConstant(const <E1*>[const E1{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:10:3 -> InstanceConstant(const E1{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:17:6 -> ListConstant(const <E2*>[const E2{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:18:3 -> InstanceConstant(const E2{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:25:6 -> ListConstant(const <E3*>[const E3{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:26:3 -> InstanceConstant(const E3{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:33:6 -> ListConstant(const <E4*>[const E4{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:34:3 -> InstanceConstant(const E4{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:41:6 -> ListConstant(const <E5*>[const E5{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:42:3 -> InstanceConstant(const E5{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:49:6 -> ListConstant(const <E6*>[const E6{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:50:3 -> InstanceConstant(const E6{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:57:6 -> ListConstant(const <E7*>[const E7{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:58:3 -> InstanceConstant(const E7{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:65:6 -> ListConstant(const <E8*>[const E8{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:66:3 -> InstanceConstant(const E8{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:75:6 -> ListConstant(const <E9*>[const E9{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:76:3 -> InstanceConstant(const E9{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///inherited_restricted_members.dart:85:6 -> ListConstant(const <E10*>[const E10{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///inherited_restricted_members.dart:86:3 -> InstanceConstant(const E10{})
+Extra constant evaluation: evaluated: 80, effectively constant: 20
diff --git a/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.transformed.expect b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.transformed.expect
new file mode 100644
index 0000000..92342bc
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart.weak.transformed.expect
@@ -0,0 +1,348 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E2 with A2 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: Can't declare a member that conflicts with an inherited one.
+// enum E6 with M6 { // Error.
+//      ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member.
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:9:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E1 with A1 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:6:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:17:6: Error: An enum can't inherit a member named 'values'.
+// enum E2 with A2 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:14:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:25:6: Error: An enum can't inherit a member named 'index'.
+// enum E3 with A3 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:22:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:33:6: Error: An enum can't inherit a member named '=='.
+// enum E4 with A4 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:30:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:41:6: Error: An enum can't inherit a member named 'hashCode'.
+// enum E5 with M5 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:38:11: Context: This is the inherited member
+//   int get hashCode => 42;
+//           ^^^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:49:6: Error: An enum can't inherit a member named 'values'.
+// enum E6 with M6 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:46:11: Context: This is the inherited member
+//   int get values => 42;
+//           ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:57:6: Error: An enum can't inherit a member named 'index'.
+// enum E7 with M7 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:54:11: Context: This is the inherited member
+//   int get index => 42;
+//           ^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:65:6: Error: An enum can't inherit a member named '=='.
+// enum E8 with M8 { // Error.
+//      ^^
+// pkg/front_end/testcases/enhanced_enums/inherited_restricted_members.dart:62:16: Context: This is the inherited member
+//   bool operator==(Object other) => true;
+//                ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A1 extends core::Object {
+  synthetic constructor •() → self::A1
+    : super core::Object::•()
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E1&_Enum&A1 extends core::_Enum implements self::A1 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A1
+    : super core::_Enum::•(index, _name)
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+class E1 extends self::_E1&_Enum&A1 /*isEnum*/  {
+  static const field core::List<self::E1> values = #C4;
+  static const field self::E1 element = #C3;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A1::•(index, name)
+    ;
+  method toString() → core::String
+    return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class A2 extends core::Object {
+  synthetic constructor •() → self::A2
+    : super core::Object::•()
+    ;
+  get values() → core::int
+    return 42;
+}
+abstract class _E2&_Enum&A2 extends core::_Enum implements self::A2 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A2
+    : super core::_Enum::•(index, _name)
+    ;
+  get values() → core::int
+    return 42;
+}
+class E2 extends self::_E2&_Enum&A2 /*isEnum*/  {
+  static const field core::List<self::E2> values = #C6;
+  static const field self::E2 element = #C5;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A2::•(index, name)
+    ;
+  method toString() → core::String
+    return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class A3 extends core::Object {
+  synthetic constructor •() → self::A3
+    : super core::Object::•()
+    ;
+  get index() → core::int
+    return 42;
+}
+abstract class _E3&_Enum&A3 extends core::_Enum implements self::A3 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&A3
+    : super core::_Enum::•(index, _name)
+    ;
+  get index() → core::int
+    return 42;
+}
+class E3 extends self::_E3&_Enum&A3 /*isEnum*/  {
+  static const field core::List<self::E3> values = #C8;
+  static const field self::E3 element = #C7;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&A3::•(index, name)
+    ;
+  method toString() → core::String
+    return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class A4 extends core::Object {
+  synthetic constructor •() → self::A4
+    : super core::Object::•()
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E4&_Enum&A4 extends core::_Enum implements self::A4 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E4&_Enum&A4
+    : super core::_Enum::•(index, _name)
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+class E4 extends self::_E4&_Enum&A4 /*isEnum*/  {
+  static const field core::List<self::E4> values = #C10;
+  static const field self::E4 element = #C9;
+  const constructor •(core::int index, core::String name) → self::E4
+    : super self::_E4&_Enum&A4::•(index, name)
+    ;
+  method toString() → core::String
+    return "E4.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M5 extends core::Object /*isMixinDeclaration*/  {
+  get hashCode() → core::int
+    return 42;
+}
+abstract class _E5&_Enum&M5 extends core::_Enum implements self::M5 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E5&_Enum&M5
+    : super core::_Enum::•(index, _name)
+    ;
+  get hashCode() → core::int
+    return 42;
+}
+class E5 extends self::_E5&_Enum&M5 /*isEnum*/  {
+  static const field core::List<self::E5> values = #C12;
+  static const field self::E5 element = #C11;
+  const constructor •(core::int index, core::String name) → self::E5
+    : super self::_E5&_Enum&M5::•(index, name)
+    ;
+  method toString() → core::String
+    return "E5.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M6 extends core::Object /*isMixinDeclaration*/  {
+  get values() → core::int
+    return 42;
+}
+abstract class _E6&_Enum&M6 extends core::_Enum implements self::M6 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E6&_Enum&M6
+    : super core::_Enum::•(index, _name)
+    ;
+  get values() → core::int
+    return 42;
+}
+class E6 extends self::_E6&_Enum&M6 /*isEnum*/  {
+  static const field core::List<self::E6> values = #C14;
+  static const field self::E6 element = #C13;
+  const constructor •(core::int index, core::String name) → self::E6
+    : super self::_E6&_Enum&M6::•(index, name)
+    ;
+  method toString() → core::String
+    return "E6.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M7 extends core::Object /*isMixinDeclaration*/  {
+  get index() → core::int
+    return 42;
+}
+abstract class _E7&_Enum&M7 extends core::_Enum implements self::M7 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&M7
+    : super core::_Enum::•(index, _name)
+    ;
+  get index() → core::int
+    return 42;
+}
+class E7 extends self::_E7&_Enum&M7 /*isEnum*/  {
+  static const field core::List<self::E7> values = #C16;
+  static const field self::E7 element = #C15;
+  const constructor •(core::int index, core::String name) → self::E7
+    : super self::_E7&_Enum&M7::•(index, name)
+    ;
+  method toString() → core::String
+    return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M8 extends core::Object /*isMixinDeclaration*/  {
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+abstract class _E8&_Enum&M8 extends core::_Enum implements self::M8 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E8&_Enum&M8
+    : super core::_Enum::•(index, _name)
+    ;
+  operator ==(core::Object other) → core::bool
+    return true;
+}
+class E8 extends self::_E8&_Enum&M8 /*isEnum*/  {
+  static const field core::List<self::E8> values = #C18;
+  static const field self::E8 element = #C17;
+  const constructor •(core::int index, core::String name) → self::E8
+    : super self::_E8&_Enum&M8::•(index, name)
+    ;
+  method toString() → core::String
+    return "E8.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class A9 extends core::Object {
+  synthetic constructor •() → self::A9
+    : super core::Object::•()
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E9&_Enum&A9 extends core::_Enum implements self::A9 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E9&_Enum&A9
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+class E9 extends self::_E9&_Enum&A9 /*isEnum*/  {
+  static const field core::List<self::E9> values = #C20;
+  static const field self::E9 element = #C19;
+  const constructor •(core::int index, core::String name) → self::E9
+    : super self::_E9&_Enum&A9::•(index, name)
+    ;
+  method toString() → core::String
+    return "E9.${this.{core::_Enum::_name}{core::String}}";
+}
+abstract class M10 extends core::Object /*isMixinDeclaration*/  {
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+abstract class _E10&_Enum&M10 extends core::_Enum implements self::M10 /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E10&_Enum&M10
+    : super core::_Enum::•(index, _name)
+    ;
+  abstract get index() → core::int;
+  abstract get hashCode() → core::int;
+  abstract operator ==(core::Object other) → core::bool;
+}
+class E10 extends self::_E10&_Enum&M10 /*isEnum*/  {
+  static const field core::List<self::E10> values = #C22;
+  static const field self::E10 element = #C21;
+  const constructor •(core::int index, core::String name) → self::E10
+    : super self::_E10&_Enum&M10::•(index, name)
+    ;
+  method toString() → core::String
+    return "E10.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = <self::E1*>[#C3]
+  #C5 = self::E2 {index:#C1, _name:#C2}
+  #C6 = <self::E2*>[#C5]
+  #C7 = self::E3 {index:#C1, _name:#C2}
+  #C8 = <self::E3*>[#C7]
+  #C9 = self::E4 {index:#C1, _name:#C2}
+  #C10 = <self::E4*>[#C9]
+  #C11 = self::E5 {index:#C1, _name:#C2}
+  #C12 = <self::E5*>[#C11]
+  #C13 = self::E6 {index:#C1, _name:#C2}
+  #C14 = <self::E6*>[#C13]
+  #C15 = self::E7 {index:#C1, _name:#C2}
+  #C16 = <self::E7*>[#C15]
+  #C17 = self::E8 {index:#C1, _name:#C2}
+  #C18 = <self::E8*>[#C17]
+  #C19 = self::E9 {index:#C1, _name:#C2}
+  #C20 = <self::E9*>[#C19]
+  #C21 = self::E10 {index:#C1, _name:#C2}
+  #C22 = <self::E10*>[#C21]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///inherited_restricted_members.dart:
+- E1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _E1&_Enum&A1. (from org-dartlang-testcase:///inherited_restricted_members.dart:9:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- _E2&_Enum&A2. (from org-dartlang-testcase:///inherited_restricted_members.dart:17:6)
+- E3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- _E3&_Enum&A3. (from org-dartlang-testcase:///inherited_restricted_members.dart:25:6)
+- E4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- _E4&_Enum&A4. (from org-dartlang-testcase:///inherited_restricted_members.dart:33:6)
+- E5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- _E5&_Enum&M5. (from org-dartlang-testcase:///inherited_restricted_members.dart:41:6)
+- E6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- _E6&_Enum&M6. (from org-dartlang-testcase:///inherited_restricted_members.dart:49:6)
+- E7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- _E7&_Enum&M7. (from org-dartlang-testcase:///inherited_restricted_members.dart:57:6)
+- E8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- _E8&_Enum&M8. (from org-dartlang-testcase:///inherited_restricted_members.dart:65:6)
+- E9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- _E9&_Enum&A9. (from org-dartlang-testcase:///inherited_restricted_members.dart:75:6)
+- E10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
+- _E10&_Enum&M10. (from org-dartlang-testcase:///inherited_restricted_members.dart:85:6)
diff --git a/pkg/js_ast/lib/js_ast.dart b/pkg/js_ast/lib/js_ast.dart
index 1958f19..43cf8b9 100644
--- a/pkg/js_ast/lib/js_ast.dart
+++ b/pkg/js_ast/lib/js_ast.dart
@@ -4,12 +4,8 @@
 
 library js_ast;
 
-import 'src/precedence.dart';
-import 'src/characters.dart' as charCodes;
-import 'src/strings.dart';
-
-part 'src/nodes.dart';
-part 'src/builder.dart';
-part 'src/printer.dart';
-part 'src/template.dart';
-part 'src/equivalence_visitor.dart';
+export 'src/nodes.dart';
+export 'src/builder.dart';
+export 'src/printer.dart';
+export 'src/template.dart';
+export 'src/equivalence_visitor.dart';
diff --git a/pkg/js_ast/lib/src/builder.dart b/pkg/js_ast/lib/src/builder.dart
index 7774925..d5771ee 100644
--- a/pkg/js_ast/lib/src/builder.dart
+++ b/pkg/js_ast/lib/src/builder.dart
@@ -2,21 +2,26 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// Utilities for building JS ASTs at runtime.  Contains a builder class
-// and a parser that parses part of the language.
+/// Utilities for building JS ASTs at runtime. Contains a builder class and a
+/// parser that parses part of the language.
+library js_ast.builder;
 
-part of js_ast;
+import 'characters.dart' as charCodes;
+import 'nodes.dart';
+import 'template.dart';
 
-/// Global template manager.  We should aim to have a fixed number of
-/// templates. This implies that we do not use js('xxx') to parse text that is
-/// constructed from values that depend on names in the Dart program.
+/// Global template manager.
 ///
-/// TODO(sra): Find the remaining places where js('xxx') used to parse an
-/// unbounded number of expression, or institute a cache policy.
+/// We should aim to have a fixed number of templates. This implies that we do
+/// not use js('xxx') to parse text that is constructed from values that depend
+/// on names in the Dart program.
+// TODO(sra): Find the remaining places where js('xxx') used to parse an
+// unbounded number of expression, or institute a cache policy.
 TemplateManager templateManager = TemplateManager();
 
-/// [js] is a singleton instance of JsBuilder.  JsBuilder is a set of
-/// conveniences for constructing JavaScript ASTs.
+/// [js] is a singleton instance of JsBuilder.
+///
+/// JsBuilder is a set of conveniences for constructing JavaScript ASTs.
 ///
 /// [string] and [number] are used to create leaf AST nodes:
 ///
@@ -33,7 +38,7 @@
 ///     js('window.alert("hello")')  -->  window.alert("hello")
 ///
 /// The input text can contain placeholders `#` that are replaced with provided
-/// arguments.  A single argument can be passed directly:
+/// arguments. A single argument can be passed directly:
 ///
 ///     js('window.alert(#)', s)   -->  window.alert("hello")
 ///
@@ -42,7 +47,7 @@
 ///     js('# + #', [s, s])  -->  "hello" + "hello"
 ///
 /// The [statement] method constructs a Statement AST, but is otherwise like the
-/// [call] method.  This constructs a Return AST:
+/// [call] method. This constructs a Return AST:
 ///
 ///     var ret = js.statement('return #;', n);  -->  return 123;
 ///
@@ -56,7 +61,7 @@
 ///       return 123;
 ///
 /// If the placeholder is not followed by a semicolon, it is part of an
-/// expression.  Here the placeholder is in the position of the function in a
+/// expression. Here the placeholder is in the position of the function in a
 /// function call:
 ///
 ///     var vFoo = new VariableUse('foo');
@@ -67,18 +72,18 @@
 ///
 /// Generally, a placeholder in an expression position requires an Expression
 /// AST as an argument and a placeholder in a statement position requires a
-/// Statement AST.  An expression will be converted to a Statement if needed by
-/// creating an ExpressionStatement.  A String argument will be converted into a
+/// Statement AST. An expression will be converted to a Statement if needed by
+/// creating an ExpressionStatement. A String argument will be converted into a
 /// VariableUse and requires that the string is a JavaScript identifier.
 ///
 ///     js('# + 1', vFoo)       -->  foo + 1
 ///     js('# + 1', 'foo')      -->  foo + 1
 ///     js('# + 1', 'foo.bar')  -->  assertion failure
 ///
-/// Some placeholder positions are _splicing contexts_.  A function argument list is
-/// a splicing expression context.  A placeholder in a splicing expression context
-/// can take a single Expression (or String, converted to VariableUse) or an
-/// Iterable of Expressions (and/or Strings).
+/// Some placeholder positions are _splicing contexts_. A function argument list
+/// is a splicing expression context. A placeholder in a splicing expression
+/// context can take a single Expression (or String, converted to VariableUse)
+/// or an Iterable of Expressions (and/or Strings).
 ///
 ///     // non-splicing argument:
 ///     js('#(#)', ['say', s])        -->  say("hello")
@@ -94,14 +99,14 @@
 ///     js('foo(#, #, 1)', [ [], [s, n]])        -->  foo("hello", 123, 1)
 ///     js('foo(#, #, 1)', [ [], [] ])           -->  foo(1)
 ///
-/// The generation of a compile-time optional argument expression can be chosen by
-/// providing an empty or singleton list.
+/// The generation of a compile-time optional argument expression can be chosen
+/// by providing an empty or singleton list.
 ///
 /// In addition to Expressions and Statements, there are Parameters, which occur
 /// only in the parameter list of a function expression or declaration.
 /// Placeholders in parameter positions behave like placeholders in Expression
-/// positions, except only Parameter AST nodes are permitted.  String arguments for
-/// parameter placeholders are converted to Parameter AST nodes.
+/// positions, except only Parameter AST nodes are permitted. String arguments
+/// for parameter placeholders are converted to Parameter AST nodes.
 ///
 ///     var pFoo = new Parameter('foo')
 ///     js('function(#) { return #; }', [pFoo, vFoo])
@@ -113,7 +118,7 @@
 ///     js('function(#) { return #; }', [vFoo, vFoo]) --> error
 ///     js('function(#) { return #; }', [pFoo, pFoo]) --> error
 ///
-/// The parameter context is a splicing context.  When combined with the
+/// The parameter context is a splicing context. When combined with the
 /// context-sensitive conversion of Strings, this simplifies the construction of
 /// trampoline-like functions:
 ///
@@ -122,10 +127,10 @@
 ///     -->
 ///     function(a, b) { return f(this, a, b); }
 ///
-/// A statement placeholder in a Block is also in a splicing context.  In addition
-/// to splicing Iterables, statement placeholders in a Block will also splice a
-/// Block or an EmptyStatement.  This flattens nested blocks and allows blocks to be
-/// appended.
+/// A statement placeholder in a Block is also in a splicing context. In
+/// addition to splicing Iterables, statement placeholders in a Block will also
+/// splice a Block or an EmptyStatement. This flattens nested blocks and allows
+/// blocks to be appended.
 ///
 ///     var b1 = js.statement('{ 1; 2; }');
 ///     var sEmpty = new Emptystatement();
@@ -133,8 +138,9 @@
 ///     -->
 ///     { 1; 2; 1; 2; }
 ///
-/// A placeholder in the context of an if-statement condition also accepts a Dart
-/// bool argument, which selects the then-part or else-part of the if-statement:
+/// A placeholder in the context of an if-statement condition also accepts a
+/// Dart bool argument, which selects the then-part or else-part of the
+/// if-statement:
 ///
 ///     js.statement('if (#) return;', vFoo)   -->  if (foo) return;
 ///     js.statement('if (#) return;', true)   -->  return;
@@ -142,8 +148,8 @@
 ///     var eTrue = new LiteralBool(true);
 ///     js.statement('if (#) return;', eTrue)  -->  if (true) return;
 ///
-/// Combined with block splicing, if-statement condition context placeholders allows
-/// the creation of templates that select code depending on variables.
+/// Combined with block splicing, if-statement condition context placeholders
+/// allows the creation of templates that select code depending on variables.
 ///
 ///     js.statement('{ 1; if (#) 2; else { 3; 4; } 5;}', true)
 ///     --> { 1; 2; 5; }
@@ -151,10 +157,10 @@
 ///     js.statement('{ 1; if (#) 2; else { 3; 4; } 5;}', false)
 ///     --> { 1; 3; 4; 5; }
 ///
-/// A placeholder following a period in a property access is in a property access
-/// context.  This is just like an expression context, except String arguments are
-/// converted to JavaScript property accesses.  In JavaScript, `a.b` is short-hand
-/// for `a["b"]`:
+/// A placeholder following a period in a property access is in a property
+/// access context. This is just like an expression context, except String
+/// arguments are converted to JavaScript property accesses. In JavaScript,
+/// `a.b` is short-hand for `a["b"]`:
 ///
 ///     js('a[#]', vFoo)  -->  a[foo]
 ///     js('a[#]', s)     -->  a.hello    (i.e. a["hello"]).
@@ -175,10 +181,9 @@
 ///
 /// What is not implemented:
 ///
-///  -  Array initializers and object initializers could support splicing.  In the
-///     array case, we would need some way to know if an ArrayInitializer argument
-///     should be splice or is intended as a single value.
-///
+///  -  Array initializers and object initializers could support splicing. In
+///     the array case, we would need some way to know if an ArrayInitializer
+///     argument should be splice or is intended as a single value.
 const JsBuilder js = JsBuilder();
 
 class JsBuilder {
@@ -188,9 +193,9 @@
   ///
   /// See the MiniJsParser class.
   ///
-  /// [arguments] can be a single [Node] (e.g. an [Expression] or [Statement]) or
-  /// a list of [Node]s, which will be interpolated into the source at the '#'
-  /// signs.
+  /// [arguments] can be a single [Node] (e.g. an [Expression] or [Statement])
+  /// or a list of [Node]s, which will be interpolated into the source at the
+  /// '#' signs.
   Expression call(String source, [var arguments]) {
     Template template = _findExpressionTemplate(source);
     if (arguments == null) return template.instantiate([]);
@@ -264,7 +269,7 @@
     return Template(source, statement, isExpression: false, forceCopy: false);
   }
 
-  /// Create an Expression template which has [ast] as the result.  This is used
+  /// Create an Expression template which has [ast] as the result. This is used
   /// to wrap a generated AST in a zero-argument Template so it can be passed to
   /// context that expects a template.
   Template expressionTemplateYielding(Node ast) {
@@ -379,7 +384,7 @@
 }
 
 /// Mini JavaScript parser for tiny snippets of code that we want to make into
-/// AST nodes.  Handles:
+/// AST nodes. Handles:
 /// * identifiers.
 /// * dot access.
 /// * method calls.
@@ -398,20 +403,16 @@
 /// Literal strings are passed through to the final JS source code unchanged,
 /// including the choice of surrounding quotes, so if you parse
 /// r'var x = "foo\n\"bar\""' you will end up with
-///   var x = "foo\n\"bar\"" in the final program.  \x and \u escapes are not
+///   var x = "foo\n\"bar\"" in the final program. \x and \u escapes are not
 /// allowed in string and regexp literals because the machinery for checking
 /// their correctness is rather involved.
 class MiniJsParser {
-  MiniJsParser(this.src)
-      : lastCategory = NONE,
-        lastToken = null,
-        lastPosition = 0,
-        position = 0 {
+  MiniJsParser(this.src) {
     getToken();
   }
 
   int lastCategory = NONE;
-  String lastToken = null;
+  String lastToken = '';
   int lastPosition = 0;
   int position = 0;
   bool skippedNewline = false; // skipped newline in last getToken?
@@ -677,7 +678,7 @@
 
     if (position == src.length) {
       lastCategory = NONE;
-      lastToken = null;
+      lastToken = '';
       lastPosition = position;
       return;
     }
diff --git a/pkg/js_ast/lib/src/equivalence_visitor.dart b/pkg/js_ast/lib/src/equivalence_visitor.dart
index b1a150b..ac23703 100644
--- a/pkg/js_ast/lib/src/equivalence_visitor.dart
+++ b/pkg/js_ast/lib/src/equivalence_visitor.dart
@@ -2,7 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js_ast;
+library js_ast.equivalence_visitor;
+
+import 'nodes.dart';
 
 /// Visitor that computes whether two [Node]s are structurally equivalent.
 class EquivalenceVisitor implements NodeVisitor1<bool, Node> {
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 06330a1..b8fe27a 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -2,7 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js_ast;
+library js_ast.nodes;
+
+import 'precedence.dart';
+import 'printer.dart';
 
 abstract class NodeVisitor<T> {
   T visitProgram(Program node);
@@ -568,8 +571,10 @@
   R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg);
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg);
 
-  /// Shallow clone of node.  Does not clone positions since the only use of
-  /// this private method is create a copy with a new position.
+  /// Shallow clone of node.
+  ///
+  /// Does not clone positions since the only use of this private method is
+  /// create a copy with a new position.
   Node _clone();
 
   /// Returns a node equivalent to [this], but with new source position and end
@@ -794,17 +799,17 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    if (init != null) init.accept(visitor);
-    if (condition != null) condition.accept(visitor);
-    if (update != null) update.accept(visitor);
+    init?.accept(visitor);
+    condition?.accept(visitor);
+    update?.accept(visitor);
     body.accept(visitor);
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    if (init != null) init.accept1(visitor, arg);
-    if (condition != null) condition.accept1(visitor, arg);
-    if (update != null) update.accept1(visitor, arg);
+    init?.accept1(visitor, arg);
+    condition?.accept1(visitor, arg);
+    update?.accept1(visitor, arg);
     body.accept1(visitor, arg);
   }
 
@@ -959,12 +964,12 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    if (value != null) value.accept(visitor);
+    value?.accept(visitor);
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    if (value != null) value.accept1(visitor, arg);
+    value?.accept1(visitor, arg);
   }
 
   @override
@@ -1016,15 +1021,15 @@
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
     body.accept(visitor);
-    if (catchPart != null) catchPart.accept(visitor);
-    if (finallyPart != null) finallyPart.accept(visitor);
+    catchPart?.accept(visitor);
+    finallyPart?.accept(visitor);
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
     body.accept1(visitor, arg);
-    if (catchPart != null) catchPart.accept1(visitor, arg);
-    if (finallyPart != null) finallyPart.accept1(visitor, arg);
+    catchPart?.accept1(visitor, arg);
+    finallyPart?.accept1(visitor, arg);
   }
 
   @override
@@ -1225,8 +1230,8 @@
   LiteralStatement _clone() => LiteralStatement(code);
 }
 
-// Not a real JavaScript node, but represents the yield statement from a dart
-// program translated to JavaScript.
+/// Not a real JavaScript node, but represents the yield statement from a dart
+/// program translated to JavaScript.
 class DartYield extends Statement {
   final Expression expression;
 
@@ -1352,8 +1357,7 @@
   int get precedenceLevel => PRIMARY;
 }
 
-/// [VariableDeclarationList] is a subclass of [Expression] to simplify the
-/// AST.
+/// [VariableDeclarationList] is a subclass of [Expression] to simplify the AST.
 class VariableDeclarationList extends Expression {
   final List<VariableInitialization> declarations;
 
@@ -2517,8 +2521,10 @@
 }
 
 /// [RegExpLiteral]s, despite being called "Literal", do not inherit from
-/// [Literal]. Indeed, regular expressions in JavaScript have a side-effect and
-/// are thus not in the same category as numbers or strings.
+/// [Literal].
+///
+/// Indeed, regular expressions in JavaScript have a side-effect and are thus
+/// not in the same category as numbers or strings.
 class RegExpLiteral extends Expression {
   /// Contains the pattern and the flags.
   final String pattern;
@@ -2602,8 +2608,9 @@
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
 }
 
-/// Returns the value of [node] if it is a [DeferredExpression]. Otherwise
-/// returns the [node] itself.
+/// Returns the value of [node] if it is a [DeferredExpression].
+///
+/// Otherwise returns the [node] itself.
 Node undefer(Node node) {
   return node is DeferredExpression ? undefer(node.value) : node;
 }
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 6234daf..bcfe5a8 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -2,7 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js_ast;
+library js_ast.printer;
+
+import 'characters.dart' as charCodes;
+import 'nodes.dart';
+import 'precedence.dart';
+import 'strings.dart';
 
 class JavaScriptPrintingOptions {
   final bool utf8;
diff --git a/pkg/js_ast/lib/src/template.dart b/pkg/js_ast/lib/src/template.dart
index de78364..bbf759e 100644
--- a/pkg/js_ast/lib/src/template.dart
+++ b/pkg/js_ast/lib/src/template.dart
@@ -2,7 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js_ast;
+library js_ast.template;
+
+import 'nodes.dart';
 
 class TemplateManager {
   Map<String, Template> expressionTemplates = {};
@@ -34,9 +36,10 @@
 }
 
 /// A Template is created with JavaScript AST containing placeholders (interface
-/// InterpolatedNode).  The [instantiate] method creates an AST that looks like
-/// the original with the placeholders replaced by the arguments to
-/// [instantiate].
+/// InterpolatedNode).
+///
+/// The [instantiate] method creates an AST that looks like the original with
+/// the placeholders replaced by the arguments to [instantiate].
 class Template {
   final String source;
   final bool isExpression;
@@ -124,13 +127,14 @@
 }
 
 /// An Instantiator is a Function that generates a JS AST tree or List of
-/// trees. [arguments] is a List for positional templates, or Map for named
-/// templates.
+/// trees.
+///
+/// [arguments] is a List for positional templates, or Map for named templates.
 typedef Instantiator = /*Node|Iterable<Node>*/ Function(dynamic arguments);
 
-/// InstantiatorGeneratorVisitor compiles a template.  This class compiles a tree
-/// containing [InterpolatedNode]s into a function that will create a copy of the
-/// tree with the interpolated nodes substituted with provided values.
+/// InstantiatorGeneratorVisitor compiles a template.  This class compiles a
+/// tree containing [InterpolatedNode]s into a function that will create a copy
+/// of the tree with the interpolated nodes substituted with provided values.
 class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
   final bool forceCopy;
 
diff --git a/runtime/vm/compiler/assembler/assembler_x64_test.cc b/runtime/vm/compiler/assembler/assembler_x64_test.cc
index c0acbff..42239a0 100644
--- a/runtime/vm/compiler/assembler/assembler_x64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64_test.cc
@@ -6271,6 +6271,31 @@
 #endif
 }
 
+ASSEMBLER_TEST_GENERATE(MoveByteRunTest, assembler) {
+  __ pushq(Immediate(0x1234567887654321));
+  __ xorq(CallingConventions::kReturnReg, CallingConventions::kReturnReg);
+  __ movb(ByteRegisterOf(CallingConventions::kReturnReg), Address(RSP, 0));
+  __ pushq(RBX);
+  __ xorq(RBX, RBX);
+  __ movb(BH, Address(RSP, target::kWordSize));
+  __ shrq(RBX, Immediate(8));
+  __ addq(CallingConventions::kReturnReg, RBX);
+  __ popq(RBX);
+  __ xorq(R8, R8);
+  __ movb(R8B, Address(RSP, 0));
+  __ addq(CallingConventions::kReturnReg, R8);
+  __ xorq(RDI, RDI);
+  __ movb(DIL, Address(RSP, 0));
+  __ addq(CallingConventions::kReturnReg, RDI);
+  __ popq(TMP);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(MoveByteRunTest, test) {
+  intptr_t res = test->InvokeWithCodeAndThread<intptr_t>();
+  EXPECT_EQ(0x21 + 0x21 + 0x21 + 0x21, res);
+}
+
 }  // namespace compiler
 }  // namespace dart
 
diff --git a/runtime/vm/heap/gc_shared.h b/runtime/vm/heap/gc_shared.h
index 3b42241..1d2bf64 100644
--- a/runtime/vm/heap/gc_shared.h
+++ b/runtime/vm/heap/gc_shared.h
@@ -1,5 +1,5 @@
 // Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
-// for detail_s. All rights reserved. Use of this source code is governed by a
+// for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 // Logic shared between the Scavenger and Marker.
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index d4f8fbc..4f34a91 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3810,6 +3810,7 @@
   set_register(NULL, SP, static_cast<int64_t>(sp));
   set_register(NULL, FP, static_cast<int64_t>(fp));
   set_register(NULL, THR, reinterpret_cast<int64_t>(thread));
+  set_register(NULL, R31, thread->saved_stack_limit() - 4096);
   // Set the tag.
   thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
diff --git a/tools/VERSION b/tools/VERSION
index 2e53ff5..52e4fd5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 236
+PRERELEASE 237
 PRERELEASE_PATCH 0
\ No newline at end of file