Version 2.13.0-118.0.dev

Merge commit '787d2659c93ac6cb88efa0871f9a275c11925a52' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index f5b87d777..e99fd45 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-03-04T14:15:31.446260",
+  "generated": "2021-03-08T09:29:10.028585",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
diff --git a/DEPS b/DEPS
index ea4b377..f3aec31 100644
--- a/DEPS
+++ b/DEPS
@@ -159,7 +159,7 @@
   "test_process_tag": "1.0.3",
   "term_glyph_rev": "6a0f9b6fb645ba75e7a00a4e20072678327a0347",
   "test_reflective_loader_rev": "54e930a11c372683792e22bddad79197728c91ce",
-  "test_rev": "bb98af3d17a821c28488ef8e2881e3ca173baf94",
+  "test_rev": "2cd8a4e774439447b01f9d381da020319a9808d8",
   "typed_data_tag": "f94fc57b8e8c0e4fe4ff6cfd8290b94af52d3719",
   "usage_rev": "6c64d9e7b6b3758d06d030efcb5afe20bfc04dde",
   "vector_math_rev": "0c9f5d68c047813a6dcdeb88ba7a42daddf25025",
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index f127ec1..d847127 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -150,7 +150,8 @@
       extension.extendedType,
       'extendedType',
     );
-    var typeArguments = inferrer.infer(typeParameters, failAtError: true);
+    var typeArguments = inferrer.infer(typeParameters,
+        failAtError: true, genericMetadataIsEnabled: true);
     if (typeArguments == null) {
       return null;
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
index 151f658..c9ff9c9 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -54,8 +54,10 @@
               if (element is ClassElement) {
                 for (var constructor in element.constructors) {
                   if (!constructor.isPrivate) {
-                    builder.suggestConstructor(constructor,
-                        kind: CompletionSuggestionKind.INVOCATION);
+                    if (!element.isAbstract || constructor.isFactory) {
+                      builder.suggestConstructor(constructor,
+                          kind: CompletionSuggestionKind.INVOCATION);
+                    }
                   }
                 }
               }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
index 316d282..4c06dad 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
@@ -42,9 +42,11 @@
     var isLocalClassDecl = classElem.library == libElem;
     for (var constructor in classElem.constructors) {
       if (isLocalClassDecl || !constructor.isPrivate) {
-        var name = constructor.name;
-        if (name != null) {
-          builder.suggestConstructor(constructor, hasClassName: true);
+        if (!classElem.isAbstract || constructor.isFactory) {
+          var name = constructor.name;
+          if (name != null) {
+            builder.suggestConstructor(constructor, hasClassName: true);
+          }
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
index 102365e..151d8d2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -41,7 +41,9 @@
         }
         for (var constructor in element.constructors) {
           if (isVisible(constructor)) {
-            builder.suggestConstructor(constructor, hasClassName: true);
+            if (!element.isAbstract || constructor.isFactory) {
+              builder.suggestConstructor(constructor, hasClassName: true);
+            }
           }
         }
         for (var field in element.fields) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 529a4d7..f77adbd 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -361,7 +361,7 @@
       }
     }
     if (completion == null || completion.isEmpty) {
-      return null;
+      return;
     }
 
     var returnType = _instantiateClassElement(enclosingClass);
diff --git a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
index 3e2a88f..03ba7c0 100644
--- a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
@@ -111,6 +111,76 @@
 ''');
   }
 
+  Future<void> test_suggestion_class_abstract() async {
+    var path = convertPath('/home/test/lib/a.dart');
+    var uriStr = 'package:test/a.dart';
+
+    newFile(path, content: r'''
+abstract class A {
+  A.a();
+  factory A.b() => _B();
+}
+class _B extends A {
+  _B() : super.a();
+}
+''');
+
+    var set = await waitForSetWithUri(uriStr);
+    assertNoSuggestion(set, 'A.a');
+    assertNoSuggestion(set, '_B');
+    assertJsonText(_getSuggestion(set, 'A'), '''
+{
+  "label": "A",
+  "declaringLibraryUri": "package:test/a.dart",
+  "element": {
+    "kind": "CLASS",
+    "name": "A",
+    "location": {
+      "file": "/home/test/lib/a.dart",
+      "offset": 15,
+      "length": 0,
+      "startLine": 1,
+      "startColumn": 16
+    },
+    "flags": 1
+  },
+  "relevanceTags": [
+    "ElementKind.CLASS",
+    "package:test/a.dart::A",
+    "A"
+  ]
+}
+''');
+    assertJsonText(_getSuggestion(set, 'A.b'), '''
+{
+  "label": "A.b",
+  "declaringLibraryUri": "package:test/a.dart",
+  "element": {
+    "kind": "CONSTRUCTOR",
+    "name": "b",
+    "location": {
+      "file": "/home/test/lib/a.dart",
+      "offset": 40,
+      "length": 0,
+      "startLine": 3,
+      "startColumn": 13
+    },
+    "flags": 0,
+    "parameters": "()",
+    "returnType": "A"
+  },
+  "parameterNames": [],
+  "parameterTypes": [],
+  "relevanceTags": [
+    "ElementKind.CONSTRUCTOR",
+    "package:test/a.dart::A",
+    "b"
+  ],
+  "requiredParameterCount": 0
+}
+''');
+  }
+
   Future<void> test_suggestion_class_part() async {
     var a_path = convertPath('/home/test/lib/a.dart');
     var b_path = convertPath('/home/test/lib/b.dart');
@@ -372,6 +442,14 @@
 ''');
   }
 
+  static void assertNoSuggestion(AvailableSuggestionSet set, String label,
+      {ElementKind kind}) {
+    var suggestion = set.items.singleWhere(
+        (s) => s.label == label && (kind == null || s.element.kind == kind),
+        orElse: () => null);
+    expect(suggestion, null);
+  }
+
   static AvailableSuggestion _getSuggestion(
       AvailableSuggestionSet set, String label,
       {ElementKind kind}) {
diff --git a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
new file mode 100644
index 0000000..97d6219
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../completion_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConstructorCompletionTest);
+  });
+}
+
+@reflectiveTest
+class ConstructorCompletionTest extends CompletionTestCase {
+  Future<void> test_constructor_abstract() async {
+    addTestFile('''
+void f() {
+  g(^);
+}
+void g(C c) {}
+abstract class C {
+  C.c();
+}
+''');
+    assertHasNoCompletion('C.c');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/completion/dart/test_all.dart b/pkg/analysis_server/test/src/services/completion/dart/test_all.dart
index 95e24ee..ab0ad81 100644
--- a/pkg/analysis_server/test/src/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/src/services/completion/dart/test_all.dart
@@ -4,10 +4,12 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'completion_test.dart' as completion;
 import 'feature_computer_test.dart' as feature_computer;
 
 void main() {
   defineReflectiveSuite(() {
+    completion.main();
     feature_computer.main();
   }, name: 'dart');
 }
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 0b7792e..9a2ca7e 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,5 +1,6 @@
-## 1.2.0
+## 1.2.0-dev
 * Deprecated all setters in API of AST. Use `parseString()` instead.
+* `AnalysisSession.getErrors()` does not return `null`, check its `state`.
 
 ## 1.1.0
 * Deprecated `TypeProvider.futureType2()`, `iterableType2()`, etc.
diff --git a/pkg/analyzer/example/analyze.dart b/pkg/analyzer/example/analyze.dart
index dcd2920..7442e33 100644
--- a/pkg/analyzer/example/analyze.dart
+++ b/pkg/analyzer/example/analyze.dart
@@ -31,7 +31,7 @@
         continue;
       }
 
-      final errorsResult = (await context.currentSession.getErrors(filePath))!;
+      final errorsResult = await context.currentSession.getErrors(filePath);
       for (final error in errorsResult.errors) {
         if (error.errorCode.type != ErrorType.TODO) {
           print(
diff --git a/pkg/analyzer/lib/dart/analysis/results.dart b/pkg/analyzer/lib/dart/analysis/results.dart
index 7e16f11..4a17594 100644
--- a/pkg/analyzer/lib/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/dart/analysis/results.dart
@@ -16,17 +16,20 @@
 /// Clients may not extend, implement or mix-in this class.
 abstract class AnalysisResult {
   /// The absolute and normalized path of the file that was analyzed.
+  /// If [state] is not [ResultState.VALID], throws [StateError].
   ///
   /// TODO(migration): should not be nullable
   String? get path;
 
   /// Return the session used to compute this result.
+  /// If [state] is not [ResultState.VALID], throws [StateError].
   AnalysisSession get session;
 
   /// The state of the results.
   ResultState get state;
 
   /// The absolute URI of the file that was analyzed.
+  /// If [state] is not [ResultState.VALID], throws [StateError].
   Uri get uri;
 }
 
@@ -35,6 +38,7 @@
 /// Clients may not extend, implement or mix-in this class.
 abstract class AnalysisResultWithErrors implements FileResult {
   /// The analysis errors that were computed during analysis.
+  /// If [state] is not [ResultState.VALID], throws [StateError].
   List<AnalysisError> get errors;
 }
 
@@ -69,9 +73,11 @@
 /// Clients may not extend, implement or mix-in this class.
 abstract class FileResult implements AnalysisResult {
   /// Whether the file is a part.
+  /// If [state] is not [ResultState.VALID], throws [StateError].
   bool get isPart;
 
   /// Information about lines in the content.
+  /// If [state] is not [ResultState.VALID], throws [StateError].
   LineInfo get lineInfo;
 }
 
@@ -174,6 +180,14 @@
   /// directory, or it might not represent anything.
   NOT_A_FILE,
 
+  /// An indication that analysis could not be performed because the path does
+  /// not represent the corresponding URI.
+  ///
+  /// This usually happens in Bazel workspaces, when a URI is resolved to
+  /// a generated file, but there is also a writable file to which this URI
+  /// would be resolved, if there were no generated file.
+  NOT_FILE_OF_URI,
+
   /// An indication that analysis completed normally and the results are valid.
   VALID
 }
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index b922cb2..f193311 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -36,9 +36,7 @@
   ///
   /// If the file cannot be analyzed by this session, then the result will have
   /// a result state indicating the nature of the problem.
-  ///
-  /// TODO(migration): should not be nullable
-  Future<ErrorsResult?> getErrors(String path);
+  Future<ErrorsResult> getErrors(String path);
 
   /// Return information about the file at the given absolute, normalized
   /// [path].
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 80c2790..c5dadef 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -556,10 +556,10 @@
   ///
   /// This method does not use analysis priorities, and must not be used in
   /// interactive analysis, such as Analysis Server or its plugins.
-  Future<ErrorsResult?> getErrors(String path) async {
+  Future<ErrorsResult> getErrors(String path) async {
     _throwIfNotAbsolutePath(path);
     if (!_fsState.hasUri(path)) {
-      return null;
+      return NotValidErrorsResultImpl(ResultState.NOT_FILE_OF_URI);
     }
 
     var completer = Completer<ErrorsResult>();
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 8700900..82b883d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -751,6 +751,7 @@
           relativeUri,
         );
         for (var configuration in directive.configurations) {
+          configuration as ConfigurationImpl;
           var uriLiteral = configuration.uri;
           String? uriContent = uriLiteral.stringValue?.trim();
           Source? defaultSource = _resolveUri(
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index f8932cd..5d19c53 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -66,6 +66,56 @@
   ResultState get state => ResultState.VALID;
 }
 
+/// The implementation of [AnalysisResult] when not [ResultState.VALID].
+class NotValidAnalysisResultImpl implements AnalysisResult {
+  @override
+  final ResultState state;
+
+  NotValidAnalysisResultImpl(this.state);
+
+  @override
+  String? get path {
+    throw StateError('This result is not valid');
+  }
+
+  @override
+  AnalysisSession get session {
+    throw StateError('This result is not valid');
+  }
+
+  @override
+  Uri get uri {
+    throw StateError('This result is not valid');
+  }
+}
+
+/// The implementation of [ErrorsResult] when not [ResultState.VALID].
+class NotValidErrorsResultImpl extends NotValidFileResultImpl
+    implements ErrorsResult {
+  NotValidErrorsResultImpl(ResultState state) : super(state);
+
+  @override
+  List<AnalysisError> get errors {
+    throw StateError('This result is not valid');
+  }
+}
+
+/// The implementation of [FileResult] when not [ResultState.VALID].
+class NotValidFileResultImpl extends NotValidAnalysisResultImpl
+    implements FileResult {
+  NotValidFileResultImpl(ResultState state) : super(state);
+
+  @override
+  bool get isPart {
+    throw StateError('This result is not valid');
+  }
+
+  @override
+  LineInfo get lineInfo {
+    throw StateError('This result is not valid');
+  }
+}
+
 class ParsedLibraryResultImpl extends AnalysisResultImpl
     implements ParsedLibraryResult {
   @override
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 7754ffa..787c675 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -59,7 +59,7 @@
   driver.AnalysisDriver getDriver() => _driver;
 
   @override
-  Future<ErrorsResult?> getErrors(String path) {
+  Future<ErrorsResult> getErrors(String path) {
     _checkConsistency();
     return _driver.getErrors(path);
   }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 90e7963..e38573d 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -31,7 +31,7 @@
 ///        [StringLiteral] [StringLiteral]+
 class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
   /// The strings that are implicitly concatenated.
-  final NodeListImpl<StringLiteralImpl> _strings = NodeListImpl._();
+  final NodeListImpl<StringLiteral> _strings = NodeListImpl._();
 
   /// Initialize a newly created list of adjacent strings. To be syntactically
   /// valid, the list of [strings] must contain at least two elements.
@@ -50,7 +50,7 @@
   Token get endToken => _strings.endToken!;
 
   @override
-  NodeListImpl<StringLiteralImpl> get strings => _strings;
+  NodeListImpl<StringLiteral> get strings => _strings;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitAdjacentStrings(this);
@@ -64,7 +64,7 @@
   void _appendStringValue(StringBuffer buffer) {
     int length = strings.length;
     for (int i = 0; i < length; i++) {
-      var stringLiteral = strings[i];
+      var stringLiteral = strings[i] as StringLiteralImpl;
       stringLiteral._appendStringValue(buffer);
     }
   }
@@ -78,7 +78,7 @@
   CommentImpl? _comment;
 
   /// The annotations associated with this node.
-  final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();
+  final NodeListImpl<Annotation> _metadata = NodeListImpl._();
 
   /// Initialize a newly created annotated node. Either or both of the [comment]
   /// and [metadata] can be `null` if the node does not have the corresponding
@@ -115,7 +115,7 @@
   }
 
   @override
-  NodeListImpl<AnnotationImpl> get metadata => _metadata;
+  NodeListImpl<Annotation> get metadata => _metadata;
 
   @override
   List<AstNode> get sortedCommentAndAnnotations {
@@ -325,7 +325,7 @@
   Token leftParenthesis;
 
   /// The expressions producing the values of the arguments.
-  final NodeListImpl<ExpressionImpl> _arguments = NodeListImpl._();
+  final NodeListImpl<Expression> _arguments = NodeListImpl._();
 
   /// The right parenthesis.
   @override
@@ -347,7 +347,7 @@
   }
 
   @override
-  NodeListImpl<ExpressionImpl> get arguments => _arguments;
+  NodeListImpl<Expression> get arguments => _arguments;
 
   @override
   Token get beginToken => leftParenthesis;
@@ -1035,7 +1035,7 @@
   Token leftBracket;
 
   /// The statements contained in the block.
-  final NodeListImpl<StatementImpl> _statements = NodeListImpl._();
+  final NodeListImpl<Statement> _statements = NodeListImpl._();
 
   /// The right curly bracket.
   @override
@@ -1059,7 +1059,7 @@
   Token get endToken => rightBracket;
 
   @override
-  NodeListImpl<StatementImpl> get statements => _statements;
+  NodeListImpl<Statement> get statements => _statements;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitBlock(this);
@@ -1187,7 +1187,7 @@
   ExpressionImpl _target;
 
   /// The cascade sections sharing the common target.
-  final NodeListImpl<ExpressionImpl> _cascadeSections = NodeListImpl._();
+  final NodeListImpl<Expression> _cascadeSections = NodeListImpl._();
 
   /// Initialize a newly created cascade expression. The list of
   /// [cascadeSections] must contain at least one element.
@@ -1200,7 +1200,7 @@
   Token get beginToken => _target.beginToken;
 
   @override
-  NodeListImpl<ExpressionImpl> get cascadeSections => _cascadeSections;
+  NodeListImpl<Expression> get cascadeSections => _cascadeSections;
 
   @override
   Iterable<SyntacticEntity> get childEntities => ChildEntities()
@@ -1572,7 +1572,7 @@
   Token leftBracket;
 
   /// The members defined by the class or mixin.
-  final NodeListImpl<ClassMemberImpl> _members = NodeListImpl._();
+  final NodeListImpl<ClassMember> _members = NodeListImpl._();
 
   /// The right curly bracket.
   @override
@@ -1605,7 +1605,7 @@
   }
 
   @override
-  NodeListImpl<ClassMemberImpl> get members => _members;
+  NodeListImpl<ClassMember> get members => _members;
 
   @override
   TypeParameterListImpl? get typeParameters => _typeParameters;
@@ -1831,7 +1831,7 @@
   /// The references embedded within the documentation comment. This list will
   /// be empty unless this is a documentation comment that has references embedded
   /// within it.
-  final NodeListImpl<CommentReferenceImpl> _references = NodeListImpl._();
+  final NodeListImpl<CommentReference> _references = NodeListImpl._();
 
   /// Initialize a newly created comment. The list of [tokens] must contain at
   /// least one token. The [_type] is the type of the comment. The list of
@@ -1861,7 +1861,7 @@
   bool get isEndOfLine => _type == CommentType.END_OF_LINE;
 
   @override
-  NodeListImpl<CommentReferenceImpl> get references => _references;
+  NodeListImpl<CommentReference> get references => _references;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitComment(this);
@@ -1990,11 +1990,10 @@
   ScriptTagImpl? _scriptTag;
 
   /// The directives contained in this compilation unit.
-  final NodeListImpl<DirectiveImpl> _directives = NodeListImpl._();
+  final NodeListImpl<Directive> _directives = NodeListImpl._();
 
   /// The declarations contained in this compilation unit.
-  final NodeListImpl<CompilationUnitMemberImpl> _declarations =
-      NodeListImpl._();
+  final NodeListImpl<CompilationUnitMember> _declarations = NodeListImpl._();
 
   /// The last token in the token stream that was parsed to form this
   /// compilation unit. This token should always have a type of [TokenType.EOF].
@@ -2050,10 +2049,10 @@
   }
 
   @override
-  NodeListImpl<CompilationUnitMemberImpl> get declarations => _declarations;
+  NodeListImpl<CompilationUnitMember> get declarations => _declarations;
 
   @override
-  NodeListImpl<DirectiveImpl> get directives => _directives;
+  NodeListImpl<Directive> get directives => _directives;
 
   @override
   set element(CompilationUnitElement? element) {
@@ -2399,8 +2398,7 @@
   Token? separator;
 
   /// The initializers associated with the constructor.
-  final NodeListImpl<ConstructorInitializerImpl> _initializers =
-      NodeListImpl._();
+  final NodeListImpl<ConstructorInitializer> _initializers = NodeListImpl._();
 
   /// The name of the constructor to which this constructor will be redirected,
   /// or `null` if this is not a redirecting factory constructor.
@@ -2489,7 +2487,7 @@
   }
 
   @override
-  NodeListImpl<ConstructorInitializerImpl> get initializers => _initializers;
+  NodeListImpl<ConstructorInitializer> get initializers => _initializers;
 
   @override
   SimpleIdentifierImpl? get name => _name;
@@ -2943,7 +2941,7 @@
   bool get isFinal => _parameter.isFinal;
 
   @override
-  NodeListImpl<AnnotationImpl> get metadata => _parameter.metadata;
+  NodeListImpl<Annotation> get metadata => _parameter.metadata;
 
   @override
   NormalFormalParameterImpl get parameter => _parameter;
@@ -3088,7 +3086,7 @@
 ///        [SimpleIdentifier] ('.' [SimpleIdentifier])*
 class DottedNameImpl extends AstNodeImpl implements DottedName {
   /// The components of the identifier.
-  final NodeListImpl<SimpleIdentifierImpl> _components = NodeListImpl._();
+  final NodeListImpl<SimpleIdentifier> _components = NodeListImpl._();
 
   /// Initialize a newly created dotted name.
   DottedNameImpl(List<SimpleIdentifier> components) {
@@ -3104,7 +3102,7 @@
       ChildEntities()..addAll(_components);
 
   @override
-  NodeListImpl<SimpleIdentifierImpl> get components => _components;
+  NodeListImpl<SimpleIdentifier> get components => _components;
 
   @override
   Token get endToken => _components.endToken!;
@@ -3290,7 +3288,7 @@
   Token leftBracket;
 
   /// The enumeration constants being declared.
-  final NodeListImpl<EnumConstantDeclarationImpl> _constants = NodeListImpl._();
+  final NodeListImpl<EnumConstantDeclaration> _constants = NodeListImpl._();
 
   /// The right curly bracket.
   @override
@@ -3322,7 +3320,7 @@
     ..add(rightBracket);
 
   @override
-  NodeListImpl<EnumConstantDeclarationImpl> get constants => _constants;
+  NodeListImpl<EnumConstantDeclaration> get constants => _constants;
 
   @override
   ClassElement? get declaredElement => _name.staticElement as ClassElement?;
@@ -3714,7 +3712,7 @@
   Token leftBracket;
 
   /// The members being added to the extended class.
-  final NodeListImpl<ClassMemberImpl> _members = NodeListImpl._();
+  final NodeListImpl<ClassMember> _members = NodeListImpl._();
 
   @override
   Token rightBracket;
@@ -3772,7 +3770,7 @@
   Token get firstTokenAfterCommentAndMetadata => extensionKeyword;
 
   @override
-  NodeListImpl<ClassMemberImpl> get members => _members;
+  NodeListImpl<ClassMember> get members => _members;
 
   @override
   SimpleIdentifierImpl? get name => _name;
@@ -4050,7 +4048,7 @@
 
   @override
   Token get beginToken {
-    NodeListImpl<AnnotationImpl> metadata = this.metadata;
+    NodeListImpl<Annotation> metadata = this.metadata;
     if (metadata.isNotEmpty) {
       return metadata.beginToken!;
     } else if (requiredKeyword != null) {
@@ -4406,7 +4404,7 @@
   Token leftParenthesis;
 
   /// The parameters associated with the method.
-  final NodeListImpl<FormalParameterImpl> _parameters = NodeListImpl._();
+  final NodeListImpl<FormalParameter> _parameters = NodeListImpl._();
 
   /// The left square bracket ('[') or left curly brace ('{') introducing the
   /// optional parameters, or `null` if there are no optional parameters.
@@ -4468,7 +4466,7 @@
   }
 
   @override
-  NodeListImpl<FormalParameterImpl> get parameters => _parameters;
+  NodeListImpl<FormalParameter> get parameters => _parameters;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitFormalParameterList(this);
@@ -4491,7 +4489,7 @@
   Token rightSeparator;
 
   /// The list of expressions run after each execution of the loop body.
-  final NodeListImpl<ExpressionImpl> _updaters = NodeListImpl._();
+  final NodeListImpl<Expression> _updaters = NodeListImpl._();
 
   /// Initialize a newly created for statement. Either the [variableList] or the
   /// [initialization] must be `null`. Either the [condition] and the list of
@@ -4524,7 +4522,7 @@
   Token get endToken => _updaters.endToken ?? rightSeparator;
 
   @override
-  NodeListImpl<ExpressionImpl> get updaters => _updaters;
+  NodeListImpl<Expression> get updaters => _updaters;
 
   @override
   void visitChildren(AstVisitor visitor) {
@@ -5175,7 +5173,7 @@
 
   @override
   Token get beginToken {
-    NodeListImpl<AnnotationImpl> metadata = this.metadata;
+    NodeListImpl<Annotation> metadata = this.metadata;
     if (metadata.isNotEmpty) {
       return metadata.beginToken!;
     } else if (requiredKeyword != null) {
@@ -5465,7 +5463,7 @@
 ///        'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
 class HideCombinatorImpl extends CombinatorImpl implements HideCombinator {
   /// The list of names from the library that are hidden by this combinator.
-  final NodeListImpl<SimpleIdentifierImpl> _hiddenNames = NodeListImpl._();
+  final NodeListImpl<SimpleIdentifier> _hiddenNames = NodeListImpl._();
 
   /// Initialize a newly created import show combinator.
   HideCombinatorImpl(Token keyword, List<SimpleIdentifier> hiddenNames)
@@ -5482,7 +5480,7 @@
   Token get endToken => _hiddenNames.endToken!;
 
   @override
-  NodeListImpl<SimpleIdentifierImpl> get hiddenNames => _hiddenNames;
+  NodeListImpl<SimpleIdentifier> get hiddenNames => _hiddenNames;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitHideCombinator(this);
@@ -5696,7 +5694,7 @@
   Token implementsKeyword;
 
   /// The interfaces that are being implemented.
-  final NodeListImpl<TypeNameImpl> _interfaces = NodeListImpl._();
+  final NodeListImpl<TypeName> _interfaces = NodeListImpl._();
 
   /// Initialize a newly created implements clause.
   ImplementsClauseImpl(this.implementsKeyword, List<TypeName> interfaces) {
@@ -5716,7 +5714,7 @@
   Token get endToken => _interfaces.endToken!;
 
   @override
-  NodeListImpl<TypeNameImpl> get interfaces => _interfaces;
+  NodeListImpl<TypeName> get interfaces => _interfaces;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitImplementsClause(this);
@@ -6440,7 +6438,7 @@
 ///       [Label]+ [Statement]
 class LabeledStatementImpl extends StatementImpl implements LabeledStatement {
   /// The labels being associated with the statement.
-  final NodeListImpl<LabelImpl> _labels = NodeListImpl._();
+  final NodeListImpl<Label> _labels = NodeListImpl._();
 
   /// The statement with which the labels are being associated.
   StatementImpl _statement;
@@ -6468,7 +6466,7 @@
   Token get endToken => _statement.endToken;
 
   @override
-  NodeListImpl<LabelImpl> get labels => _labels;
+  NodeListImpl<Label> get labels => _labels;
 
   @override
   StatementImpl get statement => _statement;
@@ -6603,7 +6601,7 @@
 class LibraryIdentifierImpl extends IdentifierImpl
     implements LibraryIdentifier {
   /// The components of the identifier.
-  final NodeListImpl<SimpleIdentifierImpl> _components = NodeListImpl._();
+  final NodeListImpl<SimpleIdentifier> _components = NodeListImpl._();
 
   /// Initialize a newly created prefixed identifier.
   LibraryIdentifierImpl(List<SimpleIdentifier> components) {
@@ -6619,7 +6617,7 @@
       ChildEntities()..addAll(_components);
 
   @override
-  NodeListImpl<SimpleIdentifierImpl> get components => _components;
+  NodeListImpl<SimpleIdentifier> get components => _components;
 
   @override
   Token get endToken => _components.endToken!;
@@ -6662,7 +6660,7 @@
   Token leftBracket;
 
   /// The expressions used to compute the elements of the list.
-  final NodeListImpl<CollectionElementImpl> _elements = NodeListImpl._();
+  final NodeListImpl<CollectionElement> _elements = NodeListImpl._();
 
   /// The right square bracket.
   @override
@@ -6713,7 +6711,7 @@
     ..add(rightBracket);
 
   @override
-  NodeListImpl<CollectionElementImpl> get elements => _elements;
+  NodeListImpl<CollectionElement> get elements => _elements;
 
   @override
   Token get endToken => rightBracket;
@@ -7224,7 +7222,7 @@
   }
 
   @override
-  NodeListImpl<ClassMemberImpl> get members => _members;
+  NodeListImpl<ClassMember> get members => _members;
 
   @override
   OnClause? get onClause => _onClause;
@@ -7358,10 +7356,10 @@
 
   /// The configurations used to control which library will actually be loaded
   /// at run-time.
-  final NodeListImpl<ConfigurationImpl> _configurations = NodeListImpl._();
+  final NodeListImpl<Configuration> _configurations = NodeListImpl._();
 
   /// The combinators used to control which names are imported or exported.
-  final NodeListImpl<CombinatorImpl> _combinators = NodeListImpl._();
+  final NodeListImpl<Combinator> _combinators = NodeListImpl._();
 
   /// The semicolon terminating the directive.
   @override
@@ -7391,10 +7389,10 @@
   }
 
   @override
-  NodeListImpl<CombinatorImpl> get combinators => _combinators;
+  NodeListImpl<Combinator> get combinators => _combinators;
 
   @override
-  NodeListImpl<ConfigurationImpl> get configurations => _configurations;
+  NodeListImpl<Configuration> get configurations => _configurations;
 
   @override
   Token get endToken => semicolon;
@@ -7606,12 +7604,12 @@
   }
 
   /// Set the [owner] of this container, and populate it with [elements].
-  void _initialize<T extends AstNode>(AstNodeImpl owner, List<T>? elements) {
+  void _initialize(AstNodeImpl owner, List<E>? elements) {
     _owner = owner;
     if (elements != null) {
       var length = elements.length;
       for (var i = 0; i < length; i++) {
-        var node = elements[i] as E;
+        var node = elements[i];
         _elements.add(node);
         owner._becomeParentOf(node as AstNodeImpl);
       }
@@ -7632,7 +7630,7 @@
   CommentImpl? _comment;
 
   /// The annotations associated with this parameter.
-  final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();
+  final NodeListImpl<Annotation> _metadata = NodeListImpl._();
 
   /// The 'covariant' keyword, or `null` if the keyword was not used.
   @override
@@ -7681,12 +7679,12 @@
   }
 
   @override
-  NodeListImpl<AnnotationImpl> get metadata => _metadata;
+  NodeListImpl<Annotation> get metadata => _metadata;
 
   @override
   set metadata(List<Annotation> metadata) {
     _metadata.clear();
-    _metadata.addAll(metadata.cast<AnnotationImpl>());
+    _metadata.addAll(metadata);
   }
 
   @override
@@ -7804,7 +7802,7 @@
   Token onKeyword;
 
   /// The classes are super-class constraints for the mixin.
-  final NodeListImpl<TypeNameImpl> _superclassConstraints = NodeListImpl._();
+  final NodeListImpl<TypeName> _superclassConstraints = NodeListImpl._();
 
   /// Initialize a newly created on clause.
   OnClauseImpl(this.onKeyword, List<TypeName> superclassConstraints) {
@@ -7824,8 +7822,7 @@
   Token get endToken => _superclassConstraints.endToken!;
 
   @override
-  NodeListImpl<TypeNameImpl> get superclassConstraints =>
-      _superclassConstraints;
+  NodeListImpl<TypeName> get superclassConstraints => _superclassConstraints;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitOnClause(this);
@@ -8580,7 +8577,7 @@
   Token leftBracket;
 
   /// The syntactic elements in the set.
-  final NodeListImpl<CollectionElementImpl> _elements = NodeListImpl._();
+  final NodeListImpl<CollectionElement> _elements = NodeListImpl._();
 
   @override
   Token rightBracket;
@@ -8632,7 +8629,7 @@
     ..add(rightBracket);
 
   @override
-  NodeListImpl<CollectionElementImpl> get elements => _elements;
+  NodeListImpl<CollectionElement> get elements => _elements;
 
   @override
   Token get endToken => rightBracket;
@@ -8677,7 +8674,7 @@
 class ShowCombinatorImpl extends CombinatorImpl implements ShowCombinator {
   /// The list of names from the library that are made visible by this
   /// combinator.
-  final NodeListImpl<SimpleIdentifierImpl> _shownNames = NodeListImpl._();
+  final NodeListImpl<SimpleIdentifier> _shownNames = NodeListImpl._();
 
   /// Initialize a newly created import show combinator.
   ShowCombinatorImpl(Token keyword, List<SimpleIdentifier> shownNames)
@@ -8695,7 +8692,7 @@
   Token get endToken => _shownNames.endToken!;
 
   @override
-  NodeListImpl<SimpleIdentifierImpl> get shownNames => _shownNames;
+  NodeListImpl<SimpleIdentifier> get shownNames => _shownNames;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitShowCombinator(this);
@@ -8746,7 +8743,7 @@
 
   @override
   Token get beginToken {
-    NodeListImpl<AnnotationImpl> metadata = this.metadata;
+    NodeListImpl<Annotation> metadata = this.metadata;
     if (metadata.isNotEmpty) {
       return metadata.beginToken!;
     } else if (requiredKeyword != null) {
@@ -9155,7 +9152,7 @@
 class StringInterpolationImpl extends SingleStringLiteralImpl
     implements StringInterpolation {
   /// The elements that will be composed to produce the resulting string.
-  final NodeListImpl<InterpolationElementImpl> _elements = NodeListImpl._();
+  final NodeListImpl<InterpolationElement> _elements = NodeListImpl._();
 
   /// Initialize a newly created string interpolation expression.
   StringInterpolationImpl(List<InterpolationElement> elements) {
@@ -9183,7 +9180,7 @@
 
   /// Return the elements that will be composed to produce the resulting string.
   @override
-  NodeListImpl<InterpolationElementImpl> get elements => _elements;
+  NodeListImpl<InterpolationElement> get elements => _elements;
 
   @override
   Token get endToken => _elements.endToken!;
@@ -9523,7 +9520,7 @@
 ///      | switchDefault
 abstract class SwitchMemberImpl extends AstNodeImpl implements SwitchMember {
   /// The labels associated with the switch member.
-  final NodeListImpl<LabelImpl> _labels = NodeListImpl._();
+  final NodeListImpl<Label> _labels = NodeListImpl._();
 
   /// The token representing the 'case' or 'default' keyword.
   @override
@@ -9534,7 +9531,7 @@
   Token colon;
 
   /// The statements that will be executed if this switch member is selected.
-  final NodeListImpl<StatementImpl> _statements = NodeListImpl._();
+  final NodeListImpl<Statement> _statements = NodeListImpl._();
 
   /// Initialize a newly created switch member. The list of [labels] can be
   /// `null` if there are no labels.
@@ -9561,10 +9558,10 @@
   }
 
   @override
-  NodeListImpl<LabelImpl> get labels => _labels;
+  NodeListImpl<Label> get labels => _labels;
 
   @override
-  NodeListImpl<StatementImpl> get statements => _statements;
+  NodeListImpl<Statement> get statements => _statements;
 }
 
 /// A switch statement.
@@ -9593,7 +9590,7 @@
   Token leftBracket;
 
   /// The switch members that can be selected by the expression.
-  final NodeListImpl<SwitchMemberImpl> _members = NodeListImpl._();
+  final NodeListImpl<SwitchMember> _members = NodeListImpl._();
 
   /// The right curly bracket.
   @override
@@ -9638,7 +9635,7 @@
   }
 
   @override
-  NodeListImpl<SwitchMemberImpl> get members => _members;
+  NodeListImpl<SwitchMember> get members => _members;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchStatement(this);
@@ -9850,7 +9847,7 @@
   BlockImpl _body;
 
   /// The catch clauses contained in the try statement.
-  final NodeListImpl<CatchClauseImpl> _catchClauses = NodeListImpl._();
+  final NodeListImpl<CatchClause> _catchClauses = NodeListImpl._();
 
   /// The token representing the 'finally' keyword, or `null` if the statement
   /// does not contain a finally clause.
@@ -9883,7 +9880,7 @@
   }
 
   @override
-  NodeListImpl<CatchClauseImpl> get catchClauses => _catchClauses;
+  NodeListImpl<CatchClause> get catchClauses => _catchClauses;
 
   @override
   Iterable<SyntacticEntity> get childEntities => ChildEntities()
@@ -9974,7 +9971,7 @@
   Token leftBracket;
 
   /// The type arguments associated with the type.
-  final NodeListImpl<TypeAnnotationImpl> _arguments = NodeListImpl._();
+  final NodeListImpl<TypeAnnotation> _arguments = NodeListImpl._();
 
   /// The right bracket.
   @override
@@ -9987,7 +9984,7 @@
   }
 
   @override
-  NodeListImpl<TypeAnnotationImpl> get arguments => _arguments;
+  NodeListImpl<TypeAnnotation> get arguments => _arguments;
 
   @override
   Token get beginToken => leftBracket;
@@ -10225,7 +10222,7 @@
   final Token leftBracket;
 
   /// The type parameters in the list.
-  final NodeListImpl<TypeParameterImpl> _typeParameters = NodeListImpl._();
+  final NodeListImpl<TypeParameter> _typeParameters = NodeListImpl._();
 
   /// The right angle bracket.
   @override
@@ -10250,7 +10247,7 @@
   Token get endToken => rightBracket;
 
   @override
-  NodeListImpl<TypeParameterImpl> get typeParameters => _typeParameters;
+  NodeListImpl<TypeParameter> get typeParameters => _typeParameters;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeParameterList(this);
@@ -10503,7 +10500,7 @@
   TypeAnnotationImpl? _type;
 
   /// A list containing the individual variables being declared.
-  final NodeListImpl<VariableDeclarationImpl> _variables = NodeListImpl._();
+  final NodeListImpl<VariableDeclaration> _variables = NodeListImpl._();
 
   /// Initialize a newly created variable declaration list. Either or both of
   /// the [comment] and [metadata] can be `null` if the variable list does not
@@ -10561,7 +10558,7 @@
   }
 
   @override
-  NodeListImpl<VariableDeclarationImpl> get variables => _variables;
+  NodeListImpl<VariableDeclaration> get variables => _variables;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) =>
@@ -10702,7 +10699,7 @@
   Token withKeyword;
 
   /// The names of the mixins that were specified.
-  final NodeListImpl<TypeNameImpl> _mixinTypes = NodeListImpl._();
+  final NodeListImpl<TypeName> _mixinTypes = NodeListImpl._();
 
   /// Initialize a newly created with clause.
   WithClauseImpl(this.withKeyword, List<TypeName> mixinTypes) {
@@ -10722,7 +10719,7 @@
   Token get endToken => _mixinTypes.endToken!;
 
   @override
-  NodeListImpl<TypeNameImpl> get mixinTypes => _mixinTypes;
+  NodeListImpl<TypeName> get mixinTypes => _mixinTypes;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) => visitor.visitWithClause(this);
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 33092e5..5fb5657 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -4002,1528 +4002,6 @@
   }
 }
 
-/// An object that copies resolution information from one AST structure to
-/// another as long as the structures of the corresponding children of a pair of
-/// nodes are the same.
-class ResolutionCopier implements AstVisitor<bool> {
-  /// The AST node with which the node being visited is to be compared. This is
-  /// only valid at the beginning of each visit method (until [isEqualNodes] is
-  /// invoked).
-  AstNode? _toNode;
-
-  @override
-  bool visitAdjacentStrings(AdjacentStrings node) {
-    var toNode = _toNode as AdjacentStringsImpl;
-    if (_isEqualNodeLists(node.strings, toNode.strings)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitAnnotation(Annotation node) {
-    var toNode = _toNode as AnnotationImpl;
-    if (_and(
-        _isEqualTokens(node.atSign, toNode.atSign),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.constructorName, toNode.constructorName),
-        _isEqualNodes(node.arguments, toNode.arguments))) {
-      toNode.element = node.element;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitArgumentList(ArgumentList node) {
-    var toNode = _toNode as ArgumentListImpl;
-    return _and(
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodeLists(node.arguments, toNode.arguments),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
-  }
-
-  @override
-  bool visitAsExpression(AsExpression node) {
-    var toNode = _toNode as AsExpressionImpl;
-    if (_and(
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.asOperator, toNode.asOperator),
-        _isEqualNodes(node.type, toNode.type))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitAssertInitializer(AssertInitializer node) {
-    var toNode = _toNode as AssertInitializerImpl;
-    return _and(
-        _isEqualTokens(node.assertKeyword, toNode.assertKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.comma, toNode.comma),
-        _isEqualNodes(node.message, toNode.message),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
-  }
-
-  @override
-  bool visitAssertStatement(AssertStatement node) {
-    var toNode = _toNode as AssertStatementImpl;
-    return _and(
-        _isEqualTokens(node.assertKeyword, toNode.assertKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.comma, toNode.comma),
-        _isEqualNodes(node.message, toNode.message),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitAssignmentExpression(AssignmentExpression node) {
-    var toNode = _toNode as AssignmentExpressionImpl;
-    if (_and(
-        _isEqualNodes(node.leftHandSide, toNode.leftHandSide),
-        _isEqualTokens(node.operator, toNode.operator),
-        _isEqualNodes(node.rightHandSide, toNode.rightHandSide))) {
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitAwaitExpression(AwaitExpression node) {
-    var toNode = _toNode as AwaitExpressionImpl;
-    if (_and(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword),
-        _isEqualNodes(node.expression, toNode.expression))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitBinaryExpression(BinaryExpression node) {
-    var toNode = _toNode as BinaryExpressionImpl;
-    if (_and(
-        _isEqualNodes(node.leftOperand, toNode.leftOperand),
-        _isEqualTokens(node.operator, toNode.operator),
-        _isEqualNodes(node.rightOperand, toNode.rightOperand))) {
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitBlock(Block node) {
-    var toNode = _toNode as BlockImpl;
-    return _and(
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.statements, toNode.statements),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitBlockFunctionBody(BlockFunctionBody node) {
-    var toNode = _toNode as BlockFunctionBodyImpl;
-    return _isEqualNodes(node.block, toNode.block);
-  }
-
-  @override
-  bool visitBooleanLiteral(BooleanLiteral node) {
-    var toNode = _toNode as BooleanLiteralImpl;
-    if (_and(_isEqualTokens(node.literal, toNode.literal),
-        node.value == toNode.value)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitBreakStatement(BreakStatement node) {
-    var toNode = _toNode as BreakStatementImpl;
-    if (_and(
-        _isEqualTokens(node.breakKeyword, toNode.breakKeyword),
-        _isEqualNodes(node.label, toNode.label),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      // TODO(paulberry): map node.target to toNode.target.
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitCascadeExpression(CascadeExpression node) {
-    var toNode = _toNode as CascadeExpressionImpl;
-    if (_and(_isEqualNodes(node.target, toNode.target),
-        _isEqualNodeLists(node.cascadeSections, toNode.cascadeSections))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitCatchClause(CatchClause node) {
-    var toNode = _toNode as CatchClauseImpl;
-    return _and(
-        _isEqualTokens(node.onKeyword, toNode.onKeyword),
-        _isEqualNodes(node.exceptionType, toNode.exceptionType),
-        _isEqualTokens(node.catchKeyword, toNode.catchKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.exceptionParameter, toNode.exceptionParameter),
-        _isEqualTokens(node.comma, toNode.comma),
-        _isEqualNodes(node.stackTraceParameter, toNode.stackTraceParameter),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.body, toNode.body));
-  }
-
-  @override
-  bool visitClassDeclaration(ClassDeclaration node) {
-    var toNode = _toNode as ClassDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword),
-        _isEqualTokens(node.classKeyword, toNode.classKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualNodes(node.extendsClause, toNode.extendsClause),
-        _isEqualNodes(node.withClause, toNode.withClause),
-        _isEqualNodes(node.implementsClause, toNode.implementsClause),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.members, toNode.members),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitClassTypeAlias(ClassTypeAlias node) {
-    var toNode = _toNode as ClassTypeAliasImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualTokens(node.equals, toNode.equals),
-        _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword),
-        _isEqualNodes(node.superclass, toNode.superclass),
-        _isEqualNodes(node.withClause, toNode.withClause),
-        _isEqualNodes(node.implementsClause, toNode.implementsClause),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitComment(Comment node) {
-    var toNode = _toNode as CommentImpl;
-    return _isEqualNodeLists(node.references, toNode.references);
-  }
-
-  @override
-  bool visitCommentReference(CommentReference node) {
-    var toNode = _toNode as CommentReferenceImpl;
-    return _and(_isEqualTokens(node.newKeyword, toNode.newKeyword),
-        _isEqualNodes(node.identifier, toNode.identifier));
-  }
-
-  @override
-  bool visitCompilationUnit(CompilationUnit node) {
-    var toNode = _toNode as CompilationUnitImpl;
-    if (_and(
-        _isEqualTokens(node.beginToken, toNode.beginToken),
-        _isEqualNodes(node.scriptTag, toNode.scriptTag),
-        _isEqualNodeLists(node.directives, toNode.directives),
-        _isEqualNodeLists(node.declarations, toNode.declarations),
-        _isEqualTokens(node.endToken, toNode.endToken))) {
-      toNode.element = node.declaredElement;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitConditionalExpression(ConditionalExpression node) {
-    var toNode = _toNode as ConditionalExpressionImpl;
-    if (_and(
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.question, toNode.question),
-        _isEqualNodes(node.thenExpression, toNode.thenExpression),
-        _isEqualTokens(node.colon, toNode.colon),
-        _isEqualNodes(node.elseExpression, toNode.elseExpression))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitConfiguration(Configuration node) {
-    var toNode = _toNode as ConfigurationImpl;
-    if (_and(
-        _isEqualTokens(node.ifKeyword, toNode.ifKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualTokens(node.equalToken, toNode.equalToken),
-        _isEqualNodes(node.value, toNode.value),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.uri, toNode.uri))) {
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitConstructorDeclaration(ConstructorDeclaration node) {
-    var toNode = _toNode as ConstructorDeclarationImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
-        _isEqualTokens(node.constKeyword, toNode.constKeyword),
-        _isEqualTokens(node.factoryKeyword, toNode.factoryKeyword),
-        _isEqualNodes(node.returnType, toNode.returnType),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.parameters, toNode.parameters),
-        _isEqualTokens(node.separator, toNode.separator),
-        _isEqualNodeLists(node.initializers, toNode.initializers),
-        _isEqualNodes(node.redirectedConstructor, toNode.redirectedConstructor),
-        _isEqualNodes(node.body, toNode.body))) {
-      toNode.declaredElement = node.declaredElement;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
-    var toNode = _toNode as ConstructorFieldInitializerImpl;
-    return _and(
-        _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.fieldName, toNode.fieldName),
-        _isEqualTokens(node.equals, toNode.equals),
-        _isEqualNodes(node.expression, toNode.expression));
-  }
-
-  @override
-  bool visitConstructorName(ConstructorName node) {
-    var toNode = _toNode as ConstructorNameImpl;
-    if (_and(
-        _isEqualNodes(node.type, toNode.type),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.name, toNode.name))) {
-      toNode.staticElement = node.staticElement;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitContinueStatement(ContinueStatement node) {
-    var toNode = _toNode as ContinueStatementImpl;
-    if (_and(
-        _isEqualTokens(node.continueKeyword, toNode.continueKeyword),
-        _isEqualNodes(node.label, toNode.label),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      // TODO(paulberry): map node.target to toNode.target.
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitDeclaredIdentifier(DeclaredIdentifier node) {
-    var toNode = _toNode as DeclaredIdentifierImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.type, toNode.type),
-        _isEqualNodes(node.identifier, toNode.identifier));
-  }
-
-  @override
-  bool visitDefaultFormalParameter(covariant DefaultFormalParameterImpl node) {
-    var toNode = _toNode as DefaultFormalParameterImpl;
-    return _and(
-        _isEqualNodes(node.parameter, toNode.parameter),
-        node.kind == toNode.kind,
-        _isEqualTokens(node.separator, toNode.separator),
-        _isEqualNodes(node.defaultValue, toNode.defaultValue));
-  }
-
-  @override
-  bool visitDoStatement(DoStatement node) {
-    var toNode = _toNode as DoStatementImpl;
-    return _and(
-        _isEqualTokens(node.doKeyword, toNode.doKeyword),
-        _isEqualNodes(node.body, toNode.body),
-        _isEqualTokens(node.whileKeyword, toNode.whileKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitDottedName(DottedName node) {
-    var toNode = _toNode as DottedNameImpl;
-    return _isEqualNodeLists(node.components, toNode.components);
-  }
-
-  @override
-  bool visitDoubleLiteral(DoubleLiteral node) {
-    var toNode = _toNode as DoubleLiteralImpl;
-    if (_and(_isEqualTokens(node.literal, toNode.literal),
-        node.value == toNode.value)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitEmptyFunctionBody(EmptyFunctionBody node) {
-    var toNode = _toNode as EmptyFunctionBodyImpl;
-    return _isEqualTokens(node.semicolon, toNode.semicolon);
-  }
-
-  @override
-  bool visitEmptyStatement(EmptyStatement node) {
-    var toNode = _toNode as EmptyStatementImpl;
-    return _isEqualTokens(node.semicolon, toNode.semicolon);
-  }
-
-  @override
-  bool visitEnumConstantDeclaration(EnumConstantDeclaration node) {
-    var toNode = _toNode as EnumConstantDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualNodes(node.name, toNode.name));
-  }
-
-  @override
-  bool visitEnumDeclaration(EnumDeclaration node) {
-    var toNode = _toNode as EnumDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.enumKeyword, toNode.enumKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.constants, toNode.constants),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitExportDirective(ExportDirective node) {
-    var toNode = _toNode as ExportDirectiveImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.uri, toNode.uri),
-        _isEqualNodeLists(node.combinators, toNode.combinators),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      toNode.element = node.element;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitExpressionFunctionBody(ExpressionFunctionBody node) {
-    var toNode = _toNode as ExpressionFunctionBodyImpl;
-    return _and(
-        _isEqualTokens(node.functionDefinition, toNode.functionDefinition),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitExpressionStatement(ExpressionStatement node) {
-    var toNode = _toNode as ExpressionStatementImpl;
-    return _and(_isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitExtendsClause(ExtendsClause node) {
-    var toNode = _toNode as ExtendsClauseImpl;
-    return _and(_isEqualTokens(node.extendsKeyword, toNode.extendsKeyword),
-        _isEqualNodes(node.superclass, toNode.superclass));
-  }
-
-  @override
-  bool visitExtensionDeclaration(ExtensionDeclaration node) {
-    var toNode = _toNode as ExtensionDeclarationImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.extensionKeyword, toNode.extensionKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualTokens(node.onKeyword, toNode.onKeyword),
-        _isEqualNodes(node.extendedType, toNode.extendedType),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.members, toNode.members),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitExtensionOverride(ExtensionOverride node) {
-    var toNode = _toNode as ExtensionOverrideImpl;
-    return _and(
-        _isEqualNodes(node.extensionName, toNode.extensionName),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualNodes(node.argumentList, toNode.argumentList));
-  }
-
-  @override
-  bool visitFieldDeclaration(FieldDeclaration node) {
-    var toNode = _toNode as FieldDeclarationImpl;
-    return _and(
-        _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword),
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.staticKeyword, toNode.staticKeyword),
-        _isEqualNodes(node.fields, toNode.fields),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitFieldFormalParameter(FieldFormalParameter node) {
-    var toNode = _toNode as FieldFormalParameterImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.type, toNode.type),
-        _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.identifier, toNode.identifier));
-  }
-
-  @override
-  bool visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
-    var toNode = _toNode as ForEachPartsWithDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.loopVariable, toNode.loopVariable),
-        _isEqualTokens(node.inKeyword, toNode.inKeyword),
-        _isEqualNodes(node.iterable, toNode.iterable));
-  }
-
-  @override
-  bool visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
-    var toNode = _toNode as ForEachPartsWithIdentifierImpl;
-    return _and(
-        _isEqualNodes(node.identifier, toNode.identifier),
-        _isEqualTokens(node.inKeyword, toNode.inKeyword),
-        _isEqualNodes(node.iterable, toNode.iterable));
-  }
-
-  @override
-  bool visitForElement(ForElement node) {
-    var toNode = _toNode as ForElementImpl;
-    return _and(
-        _isEqualTokens(node.awaitKeyword, toNode.awaitKeyword),
-        _isEqualTokens(node.forKeyword, toNode.forKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.forLoopParts, toNode.forLoopParts),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.body, toNode.body));
-  }
-
-  @override
-  bool visitFormalParameterList(FormalParameterList node) {
-    var toNode = _toNode as FormalParameterListImpl;
-    return _and(
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodeLists(node.parameters, toNode.parameters),
-        _isEqualTokens(node.leftDelimiter, toNode.leftDelimiter),
-        _isEqualTokens(node.rightDelimiter, toNode.rightDelimiter),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
-  }
-
-  @override
-  bool visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
-    var toNode = _toNode as ForPartsWithDeclarationsImpl;
-    return _and(
-        _isEqualNodes(node.variables, toNode.variables),
-        _isEqualTokens(node.leftSeparator, toNode.leftSeparator),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.rightSeparator, toNode.rightSeparator),
-        _isEqualNodeLists(node.updaters, toNode.updaters));
-  }
-
-  @override
-  bool visitForPartsWithExpression(ForPartsWithExpression node) {
-    var toNode = _toNode as ForPartsWithExpressionImpl;
-    return _and(
-        _isEqualNodes(node.initialization, toNode.initialization),
-        _isEqualTokens(node.leftSeparator, toNode.leftSeparator),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.rightSeparator, toNode.rightSeparator),
-        _isEqualNodeLists(node.updaters, toNode.updaters));
-  }
-
-  @override
-  bool visitForStatement(ForStatement node) {
-    var toNode = _toNode as ForStatementImpl;
-    return _and(
-        _isEqualTokens(node.awaitKeyword, toNode.awaitKeyword),
-        _isEqualTokens(node.forKeyword, toNode.forKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.forLoopParts, toNode.forLoopParts),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.body, toNode.body));
-  }
-
-  @override
-  bool visitFunctionDeclaration(FunctionDeclaration node) {
-    var toNode = _toNode as FunctionDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
-        _isEqualNodes(node.returnType, toNode.returnType),
-        _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.functionExpression, toNode.functionExpression));
-  }
-
-  @override
-  bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
-    FunctionDeclarationStatement toNode =
-        _toNode as FunctionDeclarationStatement;
-    return _isEqualNodes(node.functionDeclaration, toNode.functionDeclaration);
-  }
-
-  @override
-  bool visitFunctionExpression(FunctionExpression node) {
-    var toNode = _toNode as FunctionExpressionImpl;
-    if (_and(_isEqualNodes(node.parameters, toNode.parameters),
-        _isEqualNodes(node.body, toNode.body))) {
-      toNode.declaredElement = node.declaredElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
-    var toNode = _toNode as FunctionExpressionInvocationImpl;
-    if (_and(
-        _isEqualNodes(node.function, toNode.function),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualNodes(node.argumentList, toNode.argumentList))) {
-      toNode.staticInvokeType = node.staticInvokeType;
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitFunctionTypeAlias(FunctionTypeAlias node) {
-    var toNode = _toNode as FunctionTypeAliasImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword),
-        _isEqualNodes(node.returnType, toNode.returnType),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualNodes(node.parameters, toNode.parameters),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
-    FunctionTypedFormalParameter toNode =
-        _toNode as FunctionTypedFormalParameter;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualNodes(node.returnType, toNode.returnType),
-        _isEqualNodes(node.identifier, toNode.identifier),
-        _isEqualNodes(node.parameters, toNode.parameters));
-  }
-
-  @override
-  bool visitGenericFunctionType(GenericFunctionType node) {
-    var toNode = _toNode as GenericFunctionTypeImpl;
-    if (_and(
-        _isEqualNodes(node.returnType, toNode.returnType),
-        _isEqualTokens(node.functionKeyword, toNode.functionKeyword),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualNodes(node.parameters, toNode.parameters),
-        _isEqualTokens(node.question, toNode.question))) {
-      toNode.type = node.type;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitGenericTypeAlias(GenericTypeAlias node) {
-    var toNode = _toNode as GenericTypeAliasImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualTokens(node.equals, toNode.equals),
-        _isEqualNodes(node.type, toNode.type),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitHideCombinator(HideCombinator node) {
-    var toNode = _toNode as HideCombinatorImpl;
-    return _and(_isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodeLists(node.hiddenNames, toNode.hiddenNames));
-  }
-
-  @override
-  bool visitIfElement(IfElement node) {
-    var toNode = _toNode as IfElementImpl;
-    return _and(
-        _isEqualTokens(node.ifKeyword, toNode.ifKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.thenElement, toNode.thenElement),
-        _isEqualTokens(node.elseKeyword, toNode.elseKeyword),
-        _isEqualNodes(node.elseElement, toNode.elseElement));
-  }
-
-  @override
-  bool visitIfStatement(IfStatement node) {
-    var toNode = _toNode as IfStatementImpl;
-    return _and(
-        _isEqualTokens(node.ifKeyword, toNode.ifKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.thenStatement, toNode.thenStatement),
-        _isEqualTokens(node.elseKeyword, toNode.elseKeyword),
-        _isEqualNodes(node.elseStatement, toNode.elseStatement));
-  }
-
-  @override
-  bool visitImplementsClause(ImplementsClause node) {
-    var toNode = _toNode as ImplementsClauseImpl;
-    return _and(
-        _isEqualTokens(node.implementsKeyword, toNode.implementsKeyword),
-        _isEqualNodeLists(node.interfaces, toNode.interfaces));
-  }
-
-  @override
-  bool visitImportDirective(ImportDirective node) {
-    var toNode = _toNode as ImportDirectiveImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.uri, toNode.uri),
-        _isEqualTokens(node.asKeyword, toNode.asKeyword),
-        _isEqualNodes(node.prefix, toNode.prefix),
-        _isEqualNodeLists(node.combinators, toNode.combinators),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      toNode.element = node.element;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitIndexExpression(IndexExpression node) {
-    var toNode = _toNode as IndexExpressionImpl;
-    if (_and(
-        _isEqualNodes(node.target, toNode.target),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodes(node.index, toNode.index),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitInstanceCreationExpression(InstanceCreationExpression node) {
-    var toNode = _toNode as InstanceCreationExpressionImpl;
-    if (_and(
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.constructorName, toNode.constructorName),
-        _isEqualNodes(node.argumentList, toNode.argumentList))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitIntegerLiteral(IntegerLiteral node) {
-    var toNode = _toNode as IntegerLiteralImpl;
-    if (_and(_isEqualTokens(node.literal, toNode.literal),
-        node.value == toNode.value)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitInterpolationExpression(InterpolationExpression node) {
-    var toNode = _toNode as InterpolationExpressionImpl;
-    return _and(
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitInterpolationString(InterpolationString node) {
-    var toNode = _toNode as InterpolationStringImpl;
-    return _and(_isEqualTokens(node.contents, toNode.contents),
-        node.value == toNode.value);
-  }
-
-  @override
-  bool visitIsExpression(IsExpression node) {
-    var toNode = _toNode as IsExpressionImpl;
-    if (_and(
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.isOperator, toNode.isOperator),
-        _isEqualTokens(node.notOperator, toNode.notOperator),
-        _isEqualNodes(node.type, toNode.type))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitLabel(Label node) {
-    var toNode = _toNode as LabelImpl;
-    return _and(_isEqualNodes(node.label, toNode.label),
-        _isEqualTokens(node.colon, toNode.colon));
-  }
-
-  @override
-  bool visitLabeledStatement(LabeledStatement node) {
-    var toNode = _toNode as LabeledStatementImpl;
-    return _and(_isEqualNodeLists(node.labels, toNode.labels),
-        _isEqualNodes(node.statement, toNode.statement));
-  }
-
-  @override
-  bool visitLibraryDirective(LibraryDirective node) {
-    var toNode = _toNode as LibraryDirectiveImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.libraryKeyword, toNode.libraryKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      toNode.element = node.element;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitLibraryIdentifier(LibraryIdentifier node) {
-    var toNode = _toNode as LibraryIdentifierImpl;
-    if (_isEqualNodeLists(node.components, toNode.components)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitListLiteral(ListLiteral node) {
-    var toNode = _toNode as ListLiteralImpl;
-    if (_and(
-        _isEqualTokens(node.constKeyword, toNode.constKeyword),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.elements, toNode.elements),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitMapLiteralEntry(MapLiteralEntry node) {
-    var toNode = _toNode as MapLiteralEntryImpl;
-    return _and(
-        _isEqualNodes(node.key, toNode.key),
-        _isEqualTokens(node.separator, toNode.separator),
-        _isEqualNodes(node.value, toNode.value));
-  }
-
-  @override
-  bool visitMethodDeclaration(MethodDeclaration node) {
-    var toNode = _toNode as MethodDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
-        _isEqualTokens(node.modifierKeyword, toNode.modifierKeyword),
-        _isEqualNodes(node.returnType, toNode.returnType),
-        _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword),
-        _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.parameters, toNode.parameters),
-        _isEqualNodes(node.body, toNode.body));
-  }
-
-  @override
-  bool visitMethodInvocation(MethodInvocation node) {
-    var toNode = _toNode as MethodInvocationImpl;
-    if (_and(
-        _isEqualNodes(node.target, toNode.target),
-        _isEqualTokens(node.operator, toNode.operator),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualNodes(node.methodName, toNode.methodName),
-        _isEqualNodes(node.argumentList, toNode.argumentList))) {
-      toNode.staticInvokeType = node.staticInvokeType;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitMixinDeclaration(MixinDeclaration node) {
-    var toNode = _toNode as MixinDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.mixinKeyword, toNode.mixinKeyword),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeParameters, toNode.typeParameters),
-        _isEqualNodes(node.onClause, toNode.onClause),
-        _isEqualNodes(node.implementsClause, toNode.implementsClause),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.members, toNode.members),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitNamedExpression(NamedExpression node) {
-    var toNode = _toNode as NamedExpressionImpl;
-    if (_and(_isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.expression, toNode.expression))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitNativeClause(NativeClause node) {
-    var toNode = _toNode as NativeClauseImpl;
-    return _and(_isEqualTokens(node.nativeKeyword, toNode.nativeKeyword),
-        _isEqualNodes(node.name, toNode.name));
-  }
-
-  @override
-  bool visitNativeFunctionBody(NativeFunctionBody node) {
-    var toNode = _toNode as NativeFunctionBodyImpl;
-    return _and(
-        _isEqualTokens(node.nativeKeyword, toNode.nativeKeyword),
-        _isEqualNodes(node.stringLiteral, toNode.stringLiteral),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitNullLiteral(NullLiteral node) {
-    var toNode = _toNode as NullLiteralImpl;
-    if (_isEqualTokens(node.literal, toNode.literal)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitOnClause(OnClause node) {
-    var toNode = _toNode as OnClauseImpl;
-    return _and(
-        _isEqualTokens(node.onKeyword, toNode.onKeyword),
-        _isEqualNodeLists(
-            node.superclassConstraints, toNode.superclassConstraints));
-  }
-
-  @override
-  bool visitParenthesizedExpression(ParenthesizedExpression node) {
-    var toNode = _toNode as ParenthesizedExpressionImpl;
-    if (_and(
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitPartDirective(PartDirective node) {
-    var toNode = _toNode as PartDirectiveImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.partKeyword, toNode.partKeyword),
-        _isEqualNodes(node.uri, toNode.uri),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      toNode.element = node.element;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitPartOfDirective(PartOfDirective node) {
-    var toNode = _toNode as PartOfDirectiveImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.partKeyword, toNode.partKeyword),
-        _isEqualTokens(node.ofKeyword, toNode.ofKeyword),
-        _isEqualNodes(node.libraryName, toNode.libraryName),
-        _isEqualTokens(node.semicolon, toNode.semicolon))) {
-      toNode.element = node.element;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitPostfixExpression(PostfixExpression node) {
-    var toNode = _toNode as PostfixExpressionImpl;
-    if (_and(_isEqualNodes(node.operand, toNode.operand),
-        _isEqualTokens(node.operator, toNode.operator))) {
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitPrefixedIdentifier(PrefixedIdentifier node) {
-    var toNode = _toNode as PrefixedIdentifierImpl;
-    if (_and(
-        _isEqualNodes(node.prefix, toNode.prefix),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.identifier, toNode.identifier))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitPrefixExpression(PrefixExpression node) {
-    var toNode = _toNode as PrefixExpressionImpl;
-    if (_and(_isEqualTokens(node.operator, toNode.operator),
-        _isEqualNodes(node.operand, toNode.operand))) {
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitPropertyAccess(PropertyAccess node) {
-    var toNode = _toNode as PropertyAccessImpl;
-    if (_and(
-        _isEqualNodes(node.target, toNode.target),
-        _isEqualTokens(node.operator, toNode.operator),
-        _isEqualNodes(node.propertyName, toNode.propertyName))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitRedirectingConstructorInvocation(
-      RedirectingConstructorInvocation node) {
-    var toNode = _toNode as RedirectingConstructorInvocationImpl;
-    if (_and(
-        _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.constructorName, toNode.constructorName),
-        _isEqualNodes(node.argumentList, toNode.argumentList))) {
-      toNode.staticElement = node.staticElement;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitRethrowExpression(RethrowExpression node) {
-    var toNode = _toNode as RethrowExpressionImpl;
-    if (_isEqualTokens(node.rethrowKeyword, toNode.rethrowKeyword)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitReturnStatement(ReturnStatement node) {
-    var toNode = _toNode as ReturnStatementImpl;
-    return _and(
-        _isEqualTokens(node.returnKeyword, toNode.returnKeyword),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitScriptTag(ScriptTag node) {
-    var toNode = _toNode as ScriptTagImpl;
-    return _isEqualTokens(node.scriptTag, toNode.scriptTag);
-  }
-
-  @override
-  bool visitSetOrMapLiteral(SetOrMapLiteral node) {
-    var toNode = _toNode as SetOrMapLiteralImpl;
-    if (_and(
-        _isEqualTokens(node.constKeyword, toNode.constKeyword),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.elements, toNode.elements),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitShowCombinator(ShowCombinator node) {
-    var toNode = _toNode as ShowCombinatorImpl;
-    return _and(_isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodeLists(node.shownNames, toNode.shownNames));
-  }
-
-  @override
-  bool visitSimpleFormalParameter(SimpleFormalParameter node) {
-    var toNode = _toNode as SimpleFormalParameterImpl;
-    if (_and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.type, toNode.type),
-        _isEqualNodes(node.identifier, toNode.identifier))) {
-      toNode.declaredElement = node.declaredElement;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitSimpleIdentifier(SimpleIdentifier node) {
-    var toNode = _toNode as SimpleIdentifierImpl;
-    if (_isEqualTokens(node.token, toNode.token)) {
-      toNode.staticElement = node.staticElement;
-      toNode.staticType = node.staticType;
-      toNode.tearOffTypeArgumentTypes = node.tearOffTypeArgumentTypes;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitSimpleStringLiteral(SimpleStringLiteral node) {
-    var toNode = _toNode as SimpleStringLiteralImpl;
-    if (_and(_isEqualTokens(node.literal, toNode.literal),
-        node.value == toNode.value)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitSpreadElement(SpreadElement node) {
-    var toNode = _toNode as SpreadElementImpl;
-    return _and(_isEqualTokens(node.spreadOperator, toNode.spreadOperator),
-        _isEqualNodes(node.expression, toNode.expression));
-  }
-
-  @override
-  bool visitStringInterpolation(StringInterpolation node) {
-    var toNode = _toNode as StringInterpolationImpl;
-    if (_isEqualNodeLists(node.elements, toNode.elements)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitSuperConstructorInvocation(SuperConstructorInvocation node) {
-    var toNode = _toNode as SuperConstructorInvocationImpl;
-    if (_and(
-        _isEqualTokens(node.superKeyword, toNode.superKeyword),
-        _isEqualTokens(node.period, toNode.period),
-        _isEqualNodes(node.constructorName, toNode.constructorName),
-        _isEqualNodes(node.argumentList, toNode.argumentList))) {
-      toNode.staticElement = node.staticElement;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitSuperExpression(SuperExpression node) {
-    var toNode = _toNode as SuperExpressionImpl;
-    if (_isEqualTokens(node.superKeyword, toNode.superKeyword)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitSwitchCase(SwitchCase node) {
-    var toNode = _toNode as SwitchCaseImpl;
-    return _and(
-        _isEqualNodeLists(node.labels, toNode.labels),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.colon, toNode.colon),
-        _isEqualNodeLists(node.statements, toNode.statements));
-  }
-
-  @override
-  bool visitSwitchDefault(SwitchDefault node) {
-    var toNode = _toNode as SwitchDefaultImpl;
-    return _and(
-        _isEqualNodeLists(node.labels, toNode.labels),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualTokens(node.colon, toNode.colon),
-        _isEqualNodeLists(node.statements, toNode.statements));
-  }
-
-  @override
-  bool visitSwitchStatement(SwitchStatement node) {
-    var toNode = _toNode as SwitchStatementImpl;
-    return _and(
-        _isEqualTokens(node.switchKeyword, toNode.switchKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.members, toNode.members),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitSymbolLiteral(SymbolLiteral node) {
-    var toNode = _toNode as SymbolLiteralImpl;
-    if (_and(_isEqualTokens(node.poundSign, toNode.poundSign),
-        _isEqualTokenLists(node.components, toNode.components))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitThisExpression(ThisExpression node) {
-    var toNode = _toNode as ThisExpressionImpl;
-    if (_isEqualTokens(node.thisKeyword, toNode.thisKeyword)) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitThrowExpression(ThrowExpression node) {
-    var toNode = _toNode as ThrowExpressionImpl;
-    if (_and(_isEqualTokens(node.throwKeyword, toNode.throwKeyword),
-        _isEqualNodes(node.expression, toNode.expression))) {
-      toNode.staticType = node.staticType;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
-    var toNode = _toNode as TopLevelVariableDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
-        _isEqualNodes(node.variables, toNode.variables),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitTryStatement(TryStatement node) {
-    var toNode = _toNode as TryStatementImpl;
-    return _and(
-        _isEqualTokens(node.tryKeyword, toNode.tryKeyword),
-        _isEqualNodes(node.body, toNode.body),
-        _isEqualNodeLists(node.catchClauses, toNode.catchClauses),
-        _isEqualTokens(node.finallyKeyword, toNode.finallyKeyword),
-        _isEqualNodes(node.finallyBlock, toNode.finallyBlock));
-  }
-
-  @override
-  bool visitTypeArgumentList(TypeArgumentList node) {
-    var toNode = _toNode as TypeArgumentListImpl;
-    return _and(
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.arguments, toNode.arguments),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitTypeName(TypeName node) {
-    var toNode = _toNode as TypeNameImpl;
-    if (_and(
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualNodes(node.typeArguments, toNode.typeArguments),
-        _isEqualTokens(node.question, toNode.question))) {
-      toNode.type = node.type;
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  bool visitTypeParameter(TypeParameter node) {
-    var toNode = _toNode as TypeParameterImpl;
-    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
-    // added to the interface.
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualTokens((node as TypeParameterImpl).varianceKeyword,
-            toNode.varianceKeyword),
-        _isEqualTokens(node.extendsKeyword, toNode.extendsKeyword),
-        _isEqualNodes(node.bound, toNode.bound));
-  }
-
-  @override
-  bool visitTypeParameterList(TypeParameterList node) {
-    var toNode = _toNode as TypeParameterListImpl;
-    return _and(
-        _isEqualTokens(node.leftBracket, toNode.leftBracket),
-        _isEqualNodeLists(node.typeParameters, toNode.typeParameters),
-        _isEqualTokens(node.rightBracket, toNode.rightBracket));
-  }
-
-  @override
-  bool visitVariableDeclaration(VariableDeclaration node) {
-    var toNode = _toNode as VariableDeclarationImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualNodes(node.name, toNode.name),
-        _isEqualTokens(node.equals, toNode.equals),
-        _isEqualNodes(node.initializer, toNode.initializer));
-  }
-
-  @override
-  bool visitVariableDeclarationList(VariableDeclarationList node) {
-    var toNode = _toNode as VariableDeclarationListImpl;
-    return _and(
-        _isEqualNodes(node.documentationComment, toNode.documentationComment),
-        _isEqualNodeLists(node.metadata, toNode.metadata),
-        _isEqualTokens(node.keyword, toNode.keyword),
-        _isEqualNodes(node.type, toNode.type),
-        _isEqualNodeLists(node.variables, toNode.variables));
-  }
-
-  @override
-  bool visitVariableDeclarationStatement(VariableDeclarationStatement node) {
-    VariableDeclarationStatement toNode =
-        _toNode as VariableDeclarationStatement;
-    return _and(_isEqualNodes(node.variables, toNode.variables),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  @override
-  bool visitWhileStatement(WhileStatement node) {
-    var toNode = _toNode as WhileStatementImpl;
-    return _and(
-        _isEqualTokens(node.whileKeyword, toNode.whileKeyword),
-        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
-        _isEqualNodes(node.condition, toNode.condition),
-        _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
-        _isEqualNodes(node.body, toNode.body));
-  }
-
-  @override
-  bool visitWithClause(WithClause node) {
-    var toNode = _toNode as WithClauseImpl;
-    return _and(_isEqualTokens(node.withKeyword, toNode.withKeyword),
-        _isEqualNodeLists(node.mixinTypes, toNode.mixinTypes));
-  }
-
-  @override
-  bool visitYieldStatement(YieldStatement node) {
-    var toNode = _toNode as YieldStatementImpl;
-    return _and(
-        _isEqualTokens(node.yieldKeyword, toNode.yieldKeyword),
-        _isEqualNodes(node.expression, toNode.expression),
-        _isEqualTokens(node.semicolon, toNode.semicolon));
-  }
-
-  /// Return `true` if all of the parameters are `true`.
-  bool _and(bool b1, bool b2,
-      [bool b3 = true,
-      bool b4 = true,
-      bool b5 = true,
-      bool b6 = true,
-      bool b7 = true,
-      bool b8 = true,
-      bool b9 = true,
-      bool b10 = true,
-      bool b11 = true,
-      bool b12 = true,
-      bool b13 = true]) {
-    // TODO(brianwilkerson) Inline this method.
-    return b1 &&
-        b2 &&
-        b3 &&
-        b4 &&
-        b5 &&
-        b6 &&
-        b7 &&
-        b8 &&
-        b9 &&
-        b10 &&
-        b11 &&
-        b12 &&
-        b13;
-  }
-
-  /// Return `true` if the [first] and [second] lists of AST nodes have the same
-  /// size and corresponding elements are equal.
-  bool _isEqualNodeLists(NodeList? first, NodeList? second) {
-    if (first == null) {
-      return second == null;
-    } else if (second == null) {
-      return false;
-    }
-    int size = first.length;
-    if (second.length != size) {
-      return false;
-    }
-    bool equal = true;
-    for (int i = 0; i < size; i++) {
-      if (!_isEqualNodes(first[i], second[i])) {
-        equal = false;
-      }
-    }
-    return equal;
-  }
-
-  /// Return `true` if the [fromNode] and [toNode] have the same structure. As a
-  /// side-effect, if the nodes do have the same structure, any resolution data
-  /// from the first node will be copied to the second node.
-  bool _isEqualNodes(AstNode? fromNode, AstNode? toNode) {
-    if (fromNode == null) {
-      return toNode == null;
-    } else if (toNode == null) {
-      return false;
-    } else if (fromNode.runtimeType == toNode.runtimeType) {
-      _toNode = toNode;
-      return fromNode.accept(this)!;
-    }
-    //
-    // Check for a simple transformation caused by entering a period.
-    //
-    if (toNode is PrefixedIdentifier) {
-      SimpleIdentifier prefix = toNode.prefix;
-      if (fromNode.runtimeType == prefix.runtimeType) {
-        _toNode = prefix;
-        return fromNode.accept(this)!;
-      }
-    } else if (toNode is PropertyAccess) {
-      var target = toNode.target;
-      if (fromNode.runtimeType == target.runtimeType) {
-        _toNode = target;
-        return fromNode.accept(this)!;
-      }
-    }
-    return false;
-  }
-
-  /// Return `true` if the [first] and [second] arrays of tokens have the same
-  /// length and corresponding elements are equal.
-  bool _isEqualTokenLists(List<Token> first, List<Token> second) {
-    int length = first.length;
-    if (second.length != length) {
-      return false;
-    }
-    for (int i = 0; i < length; i++) {
-      if (!_isEqualTokens(first[i], second[i])) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /// Return `true` if the [first] and [second] tokens have the same structure.
-  bool _isEqualTokens(Token? first, Token? second) {
-    if (first == null) {
-      return second == null;
-    } else if (second == null) {
-      return false;
-    }
-    return first.lexeme == second.lexeme;
-  }
-
-  /// Copy resolution data from the [fromNode] to the [toNode].
-  static void copyResolutionData(AstNode fromNode, AstNode toNode) {
-    ResolutionCopier copier = ResolutionCopier();
-    copier._isEqualNodes(fromNode, toNode);
-  }
-}
-
 /// Traverse the AST from initial child node to successive parents, building a
 /// collection of local variable and parameter names visible to the initial
 /// child node. In case of name shadowing, the first name seen is the most
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index 387ca4a..7486d35 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -118,12 +118,15 @@
   /// `_` to precisely represent an unknown type. If [downwardsInferPhase] is
   /// false, we are on our final inference pass, have all available information
   /// including argument types, and must not conclude `_` for any type formal.
-  List<DartType>? infer(List<TypeParameterElement> typeFormals,
-      {bool considerExtendsClause = true,
-      ErrorReporter? errorReporter,
-      AstNode? errorNode,
-      bool failAtError = false,
-      bool downwardsInferPhase = false}) {
+  List<DartType>? infer(
+    List<TypeParameterElement> typeFormals, {
+    bool considerExtendsClause = true,
+    ErrorReporter? errorReporter,
+    AstNode? errorNode,
+    bool failAtError = false,
+    bool downwardsInferPhase = false,
+    required bool genericMetadataIsEnabled,
+  }) {
     // Initialize the inferred type array.
     //
     // In the downwards phase, they all start as `_` to offer reasonable
@@ -204,7 +207,9 @@
         // more errors (e.g. because `dynamic` is the most common bound).
       }
 
-      if (inferred is FunctionType && inferred.typeFormals.isNotEmpty) {
+      if (inferred is FunctionType &&
+          inferred.typeFormals.isNotEmpty &&
+          !genericMetadataIsEnabled) {
         if (failAtError) return null;
         var typeFormals = inferred.typeFormals;
         var typeFormalsStr = typeFormals.map(_elementStr).join(', ');
@@ -215,12 +220,6 @@
               ' [$typeFormalsStr], but a function with'
               ' type parameters cannot be used as a type argument.'
         ]);
-
-        // Heuristic: Using a generic function type as a bound makes subtyping
-        // undecidable. Therefore, we cannot keep [inferred] unless we wish to
-        // generate bogus subtyping errors. Instead generate plain [Function],
-        // which is the most general function type.
-        inferred = typeProvider.functionType;
       }
 
       if (UnknownInferredType.isKnown(inferred)) {
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index 01d2255..ca7f2f9 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -419,8 +419,12 @@
   /// uninstantiated, or a [fnType] that is already instantiated, it will have
   /// no effect and return `null`.
   List<DartType>? inferFunctionTypeInstantiation(
-      FunctionType contextType, FunctionType fnType,
-      {ErrorReporter? errorReporter, AstNode? errorNode}) {
+    FunctionType contextType,
+    FunctionType fnType, {
+    ErrorReporter? errorReporter,
+    AstNode? errorNode,
+    required bool genericMetadataIsEnabled,
+  }) {
     if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) {
       return const <DartType>[];
     }
@@ -437,6 +441,7 @@
       fnType.typeFormals,
       errorReporter: errorReporter,
       errorNode: errorNode,
+      genericMetadataIsEnabled: genericMetadataIsEnabled,
     );
   }
 
@@ -472,6 +477,7 @@
     AstNode? errorNode,
     bool downwards = false,
     bool isConst = false,
+    required bool genericMetadataIsEnabled,
   }) {
     if (typeParameters.isEmpty) {
       return null;
@@ -506,6 +512,7 @@
       errorReporter: errorReporter,
       errorNode: errorNode,
       downwardsInferPhase: downwards,
+      genericMetadataIsEnabled: genericMetadataIsEnabled,
     );
   }
 
@@ -1250,8 +1257,9 @@
   List<DartType>? matchSupertypeConstraints(
     ClassElement mixinElement,
     List<DartType> srcTypes,
-    List<DartType> destTypes,
-  ) {
+    List<DartType> destTypes, {
+    required bool genericMetadataIsEnabled,
+  }) {
     var typeParameters = mixinElement.typeParameters;
     var inferrer = GenericInferrer(this, typeParameters);
     for (int i = 0; i < srcTypes.length; i++) {
@@ -1262,6 +1270,7 @@
     var inferredTypes = inferrer.infer(
       typeParameters,
       considerExtendsClause: false,
+      genericMetadataIsEnabled: genericMetadataIsEnabled,
     )!;
     inferredTypes =
         inferredTypes.map(_removeBoundsOfGenericFunctionTypes).toList();
diff --git a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
index 03c7351..25bd1d7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -31,6 +32,9 @@
 
   ErrorReporter get _errorReporter => _resolver.errorReporter;
 
+  bool get _genericMetadataIsEnabled =>
+      _resolver.definingLibrary.featureSet.isEnabled(Feature.generic_metadata);
+
   Scope get _nameScope => _resolver.nameScope;
 
   TypeProvider get _typeProvider => _resolver.typeProvider;
@@ -289,6 +293,7 @@
       var typeArguments = inferrer.infer(
         freshTypeParameters,
         failAtError: true,
+        genericMetadataIsEnabled: _genericMetadataIsEnabled,
       );
       if (typeArguments == null) {
         continue;
@@ -407,6 +412,7 @@
         typeParameters,
         errorReporter: _errorReporter,
         errorNode: node.extensionName,
+        genericMetadataIsEnabled: _genericMetadataIsEnabled,
       );
     }
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 1ee93cf..0b960b5 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -20,19 +21,22 @@
   final ErrorReporter _errorReporter;
   final TypeSystemImpl _typeSystem;
   final MigrationResolutionHooks? _migrationResolutionHooks;
+  final bool _genericMetadataIsEnabled;
 
   List<DartType>? _typeArgumentTypes;
   FunctionType? _invokeType;
 
-  InvocationInferenceHelper(
-      {required ResolverVisitor resolver,
-      required ErrorReporter errorReporter,
-      required TypeSystemImpl typeSystem,
-      required MigrationResolutionHooks? migrationResolutionHooks})
-      : _resolver = resolver,
+  InvocationInferenceHelper({
+    required ResolverVisitor resolver,
+    required ErrorReporter errorReporter,
+    required TypeSystemImpl typeSystem,
+    required MigrationResolutionHooks? migrationResolutionHooks,
+  })   : _resolver = resolver,
         _errorReporter = errorReporter,
         _typeSystem = typeSystem,
-        _migrationResolutionHooks = migrationResolutionHooks;
+        _migrationResolutionHooks = migrationResolutionHooks,
+        _genericMetadataIsEnabled = resolver.definingLibrary.featureSet
+            .isEnabled(Feature.generic_metadata);
 
   /// Compute the return type of the method or function represented by the given
   /// type that is being invoked.
@@ -62,6 +66,7 @@
         isConst: isConst,
         errorReporter: _errorReporter,
         errorNode: errorNode,
+        genericMetadataIsEnabled: _genericMetadataIsEnabled,
       );
       if (typeArguments != null) {
         return uninstantiatedType.instantiate(typeArguments);
@@ -164,6 +169,7 @@
         tearOffType,
         errorReporter: _resolver.errorReporter,
         errorNode: expression,
+        genericMetadataIsEnabled: _genericMetadataIsEnabled,
       )!;
       (identifier as SimpleIdentifierImpl).tearOffTypeArgumentTypes =
           typeArguments;
@@ -266,6 +272,7 @@
       isConst: isConst,
       errorReporter: _errorReporter,
       errorNode: errorNode,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     );
   }
 
@@ -302,6 +309,7 @@
       isConst: isConst,
       errorReporter: _errorReporter,
       errorNode: errorNode,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     );
     return typeArgs;
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
index fe60568..9c2328a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -54,6 +55,9 @@
       this.isNonNullableByDefault, this.errorReporter)
       : dynamicType = typeProvider.dynamicType;
 
+  bool get _genericMetadataIsEnabled =>
+      enclosingClass!.library.featureSet.isEnabled(Feature.generic_metadata);
+
   NullabilitySuffix get _noneOrStarSuffix {
     return isNonNullableByDefault
         ? NullabilitySuffix.none
@@ -167,6 +171,7 @@
           declaredReturnType: element.thisType,
           argumentTypes: const [],
           contextReturnType: enclosingClass!.thisType,
+          genericMetadataIsEnabled: _genericMetadataIsEnabled,
         )!;
         return element.instantiate(
           typeArguments: typeArguments,
diff --git a/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
index 8e659b2..624a27b 100644
--- a/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
@@ -64,6 +64,9 @@
 
   DynamicTypeImpl get _dynamicType => DynamicTypeImpl.instance;
 
+  bool get _genericMetadataIsEnabled =>
+      _resolver.definingLibrary.featureSet.isEnabled(Feature.generic_metadata);
+
   NullabilitySuffix get _noneOrStarSuffix {
     return _isNonNullableByDefault
         ? NullabilitySuffix.none
@@ -460,6 +463,7 @@
       isConst: node.isConst,
       errorReporter: _errorReporter,
       errorNode: node,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     )!;
     return element.instantiate(
       typeArguments: typeArguments,
@@ -484,6 +488,7 @@
       isConst: node.isConst,
       errorReporter: _errorReporter,
       errorNode: node,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     )!;
     return element.instantiate(
       typeArguments: typeArguments,
@@ -582,6 +587,7 @@
       isConst: node.isConst,
       errorReporter: _errorReporter,
       errorNode: node,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     )!;
     return element.instantiate(
       typeArguments: typeArguments,
@@ -782,6 +788,7 @@
       declaredReturnType: element.thisType,
       argumentTypes: argumentTypes,
       contextReturnType: contextType,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     )!;
     return element.instantiate(
       typeArguments: typeArguments,
@@ -813,6 +820,7 @@
       declaredReturnType: element.thisType,
       argumentTypes: argumentTypes,
       contextReturnType: contextType,
+      genericMetadataIsEnabled: _genericMetadataIsEnabled,
     )!;
     return element.instantiate(
       typeArguments: typeArguments,
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index 2da84df..6d4276d 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -4,6 +4,7 @@
 
 import "dart:math" as math;
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -216,10 +217,12 @@
       var typeArgument = typeArguments[i];
 
       if (typeArgument is FunctionType && typeArgument.typeFormals.isNotEmpty) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          _typeArgumentErrorNode(typeName, i),
-        );
+        if (!_libraryElement.featureSet.isEnabled(Feature.generic_metadata)) {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+            _typeArgumentErrorNode(typeName, i),
+          );
+        }
         continue;
       }
 
@@ -354,10 +357,13 @@
         DartType argType = typeArgs[i];
 
         if (argType is FunctionType && argType.typeFormals.isNotEmpty) {
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-            typeArgumentList[i],
-          );
+          if (!_libraryElement.featureSet.isEnabled(Feature.generic_metadata)) {
+            _errorReporter.reportErrorForNode(
+              CompileTimeErrorCode
+                  .GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+              typeArgumentList[i],
+            );
+          }
           continue;
         }
 
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index facba30..9b9b7af 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -57,7 +57,17 @@
 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
-import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/ast.dart'
+    show
+        ClassDeclarationImpl,
+        CompilationUnitImpl,
+        ExtensionDeclarationImpl,
+        ImportDirectiveImpl,
+        MethodInvocationImpl,
+        MixinDeclarationImpl,
+        SimpleIdentifierImpl,
+        TypeArgumentListImpl,
+        TypeParameterImpl;
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/fasta/error_converter.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -552,7 +562,7 @@
     assert(optional(')', rightParenthesis));
     debugEvent("Arguments");
 
-    var expressions = popTypedList2<ExpressionImpl>(count);
+    var expressions = popTypedList2<Expression>(count);
     ArgumentList arguments =
         ast.argumentList(leftParenthesis, expressions, rightParenthesis);
     push(ast.methodInvocation(
@@ -651,7 +661,7 @@
     assert(optional('}', rightBracket));
     debugEvent("Block");
 
-    var statements = popTypedList2<StatementImpl>(count);
+    var statements = popTypedList2<Statement>(count);
     push(ast.block(leftBracket, statements, rightBracket));
   }
 
@@ -661,7 +671,7 @@
     assert(optional('}', rightBracket));
     debugEvent("BlockFunctionBody");
 
-    var statements = popTypedList2<StatementImpl>(count);
+    var statements = popTypedList2<Statement>(count);
     Block block = ast.block(leftBracket, statements, rightBracket);
     var star = pop() as Token?;
     var asyncKeyword = pop() as Token?;
@@ -886,7 +896,7 @@
       }
     }
 
-    var variables = popTypedList2<VariableDeclarationImpl>(count);
+    var variables = popTypedList2<VariableDeclaration>(count);
     var type = pop() as TypeAnnotation?;
     var variableList = ast.variableDeclarationList2(
       lateKeyword: lateToken,
@@ -1000,7 +1010,7 @@
   @override
   void endCombinators(int count) {
     debugEvent("Combinators");
-    push(popTypedList<CombinatorImpl>(count) ?? NullValue.Combinators);
+    push(popTypedList<Combinator>(count) ?? NullValue.Combinators);
   }
 
   @override
@@ -1063,7 +1073,7 @@
   void endConditionalUris(int count) {
     debugEvent("ConditionalUris");
 
-    push(popTypedList<ConfigurationImpl>(count) ?? NullValue.ConditionalUris);
+    push(popTypedList<Configuration>(count) ?? NullValue.ConditionalUris);
   }
 
   @override
@@ -1128,7 +1138,7 @@
     assert(optional('{', leftBrace));
     debugEvent("Enum");
 
-    var constants = popTypedList2<EnumConstantDeclarationImpl>(count);
+    var constants = popTypedList2<EnumConstantDeclaration>(count);
     var name = pop() as SimpleIdentifier;
     var metadata = pop() as List<Annotation>?;
     var comment = _findComment(metadata, enumKeyword);
@@ -1724,7 +1734,7 @@
     debugEvent("LabeledStatement");
 
     var statement = pop() as Statement;
-    var labels = popTypedList2<LabelImpl>(labelCount);
+    var labels = popTypedList2<Label>(labelCount);
     push(ast.labeledStatement(labels, statement));
   }
 
@@ -1845,7 +1855,7 @@
   void endMetadataStar(int count) {
     debugEvent("MetadataStar");
 
-    push(popTypedList<AnnotationImpl>(count) ?? NullValue.Metadata);
+    push(popTypedList<Annotation>(count) ?? NullValue.Metadata);
   }
 
   @override
@@ -1962,8 +1972,8 @@
         (optional('{', leftDelimeter) && optional('}', rightDelimeter)));
     debugEvent("OptionalFormalParameters");
 
-    push(_OptionalFormalParameters(popTypedList2<FormalParameterImpl>(count),
-        leftDelimeter, rightDelimeter));
+    push(_OptionalFormalParameters(
+        popTypedList2<FormalParameter>(count), leftDelimeter, rightDelimeter));
   }
 
   @override
@@ -2086,12 +2096,12 @@
         : optional(':', colonAfterDefault!));
     debugEvent("SwitchCase");
 
-    var statements = popTypedList2<StatementImpl>(statementCount);
+    var statements = popTypedList2<Statement>(statementCount);
     List<SwitchMember?> members;
 
     if (labelCount == 0 && defaultKeyword == null) {
       // Common situation: case with no default and no labels.
-      members = popTypedList2<SwitchMemberImpl>(expressionCount);
+      members = popTypedList2<SwitchMember>(expressionCount);
     } else {
       // Labels and case statements may be intertwined
       if (defaultKeyword != null) {
@@ -2175,7 +2185,7 @@
       }
     }
 
-    var variables = popTypedList2<VariableDeclarationImpl>(count);
+    var variables = popTypedList2<VariableDeclaration>(count);
     var type = pop() as TypeAnnotation?;
     var variableList = ast.variableDeclarationList2(
       lateKeyword: lateToken,
@@ -2226,7 +2236,7 @@
     debugEvent("TryStatement");
 
     var finallyBlock = popIfNotNull(finallyKeyword) as Block?;
-    var catchClauses = popTypedList2<CatchClauseImpl>(catchCount);
+    var catchClauses = popTypedList2<CatchClause>(catchCount);
     var body = pop() as Block;
     push(ast.tryStatement(
         tryKeyword, body, catchClauses, finallyKeyword, finallyBlock));
@@ -2238,14 +2248,14 @@
     assert(optional('>', rightBracket));
     debugEvent("TypeArguments");
 
-    var arguments = popTypedList2<TypeAnnotationImpl>(count);
+    var arguments = popTypedList2<TypeAnnotation>(count);
     push(ast.typeArgumentList(leftBracket, arguments, rightBracket));
   }
 
   @override
   void endTypeList(int count) {
     debugEvent("TypeList");
-    push(popTypedList<TypeNameImpl>(count) ?? NullValue.TypeList);
+    push(popTypedList<TypeName>(count) ?? NullValue.TypeList);
   }
 
   @override
@@ -2304,7 +2314,7 @@
     assert(optionalOrNull(';', semicolon));
     debugEvent("VariablesDeclaration");
 
-    var variables = popTypedList2<VariableDeclarationImpl>(count);
+    var variables = popTypedList2<VariableDeclaration>(count);
     var modifiers = pop(NullValue.Modifiers) as _Modifiers?;
     var type = pop() as TypeAnnotation?;
     var keyword = modifiers?.finalConstOrVarKeyword;
@@ -2526,7 +2536,7 @@
     debugEvent("ClassImplements");
 
     if (implementsKeyword != null) {
-      var interfaces = popTypedList2<TypeNameImpl>(interfacesCount);
+      var interfaces = popTypedList2<TypeName>(interfacesCount);
       push(ast.implementsClause(implementsKeyword, interfaces));
     } else {
       push(NullValue.IdentifierList);
@@ -2573,7 +2583,7 @@
     assert(firstIdentifier.isIdentifier);
     debugEvent("DottedName");
 
-    var components = popTypedList2<SimpleIdentifierImpl>(count);
+    var components = popTypedList2<SimpleIdentifier>(count);
     push(ast.dottedName(components));
   }
 
@@ -2722,7 +2732,7 @@
     assert(optional(';', leftSeparator));
     assert(updateExpressionCount >= 0);
 
-    var updates = popTypedList2<ExpressionImpl>(updateExpressionCount);
+    var updates = popTypedList2<Expression>(updateExpressionCount);
     var conditionStatement = pop() as Statement;
     var initializerPart = pop();
 
@@ -2797,7 +2807,7 @@
   void handleIdentifierList(int count) {
     debugEvent("IdentifierList");
 
-    push(popTypedList<SimpleIdentifierImpl>(count) ?? NullValue.IdentifierList);
+    push(popTypedList<SimpleIdentifier>(count) ?? NullValue.IdentifierList);
   }
 
   @override
@@ -2984,7 +2994,7 @@
       push(ast.listLiteral(
           constKeyword, typeArguments, leftBracket, elements, rightBracket));
     } else {
-      var elements = popTypedList<ExpressionImpl>(count) ?? const [];
+      var elements = popTypedList<Expression>(count) ?? const [];
       var typeArguments = pop() as TypeArgumentList?;
 
       List<Expression> expressions = <Expression>[];
@@ -3149,7 +3159,7 @@
     debugEvent("MixinOn");
 
     if (onKeyword != null) {
-      var types = popTypedList2<TypeNameImpl>(typeCount);
+      var types = popTypedList2<TypeName>(typeCount);
       push(ast.onClause(onKeyword, types));
     } else {
       push(NullValue.IdentifierList);
@@ -3310,10 +3320,9 @@
   void handleRecoverClassHeader() {
     debugEvent("RecoverClassHeader");
 
-    var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
-    var withClause = pop(NullValue.WithClause) as WithClauseImpl?;
-    var extendsClause = pop(NullValue.ExtendsClause) as ExtendsClauseImpl?;
+    var implementsClause = pop(NullValue.IdentifierList) as ImplementsClause?;
+    var withClause = pop(NullValue.WithClause) as WithClause?;
+    var extendsClause = pop(NullValue.ExtendsClause) as ExtendsClause?;
     var declaration = declarations.last as ClassDeclarationImpl;
     if (extendsClause != null) {
       if (declaration.extendsClause?.superclass == null) {
@@ -3342,11 +3351,11 @@
     assert(optionalOrNull(';', semicolon));
     debugEvent("RecoverImport");
 
-    var combinators = pop() as List<CombinatorImpl>?;
+    var combinators = pop() as List<Combinator>?;
     var deferredKeyword = pop(NullValue.Deferred) as Token?;
     var asKeyword = pop(NullValue.As) as Token?;
     var prefix = pop(NullValue.Prefix) as SimpleIdentifier?;
-    var configurations = pop() as List<ConfigurationImpl>?;
+    var configurations = pop() as List<Configuration>?;
 
     var directive = directives.last as ImportDirectiveImpl;
     if (combinators != null) {
@@ -3367,8 +3376,7 @@
 
   @override
   void handleRecoverMixinHeader() {
-    var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
+    var implementsClause = pop(NullValue.IdentifierList) as ImplementsClause?;
     var onClause = pop(NullValue.IdentifierList) as OnClause?;
 
     if (onClause != null) {
@@ -3434,7 +3442,7 @@
   void handleStringJuxtaposition(Token startToken, int literalCount) {
     debugEvent("StringJuxtaposition");
 
-    var strings = popTypedList2<StringLiteralImpl>(literalCount);
+    var strings = popTypedList2<StringLiteral>(literalCount);
     push(ast.adjacentStrings(strings));
   }
 
@@ -3494,7 +3502,7 @@
   void handleTypeVariablesDefined(Token token, int count) {
     debugEvent("handleTypeVariablesDefined");
     assert(count > 0);
-    push(popTypedList<TypeParameterImpl>(count));
+    push(popTypedList<TypeParameter>(count));
   }
 
   @override
@@ -3599,7 +3607,7 @@
       }
     }
 
-    return popTypedList<CommentReferenceImpl>(count) ?? const [];
+    return popTypedList<CommentReference>(count) ?? const [];
   }
 
   List<CollectionElement> popCollectionElements(int count) {
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 1971848..4a304c1 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2684,6 +2684,9 @@
     if (node == null) {
       return;
     }
+    if (_featureSet?.isEnabled(Feature.generic_metadata) ?? false) {
+      return;
+    }
     DartType type = node.type!;
     if (type is FunctionType && type.typeFormals.isNotEmpty) {
       _errorReporter.reportErrorForNode(
@@ -3264,17 +3267,20 @@
   bool _checkForMixinInheritsNotFromObject(
       TypeName mixinName, ClassElement mixinElement) {
     var mixinSupertype = mixinElement.supertype;
-    if (mixinSupertype != null) {
-      if (!mixinSupertype.isDartCoreObject ||
-          !mixinElement.isMixinApplication && mixinElement.mixins.isNotEmpty) {
-        _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
-            mixinName,
-            [mixinElement.name]);
-        return true;
+    if (mixinSupertype == null || mixinSupertype.isDartCoreObject) {
+      var mixins = mixinElement.mixins;
+      if (mixins.isEmpty ||
+          mixinElement.isMixinApplication && mixins.length < 2) {
+        return false;
       }
     }
-    return false;
+
+    _errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
+      mixinName,
+      [mixinElement.name],
+    );
+    return true;
   }
 
   /// Check that superclass constrains for the mixin type of [mixinName] at
@@ -4916,6 +4922,8 @@
                 mixinElement,
                 mixinSupertypeConstraints,
                 matchingInterfaceTypes,
+                genericMetadataIsEnabled: _currentLibrary.featureSet
+                    .isEnabled(Feature.generic_metadata),
               );
               if (inferredTypeArguments == null) {
                 _errorReporter.reportErrorForToken(
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index a00a27d..270cc84 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -17,7 +17,6 @@
 import 'package:analyzer/src/fasta/ast_builder.dart';
 import 'package:analyzer/src/generated/source.dart';
 
-export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier;
 export 'package:analyzer/src/dart/error/syntactic_errors.dart';
 
 /// A simple data-holder for a method that needs to return multiple values.
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 5f3f78f..b061fe0 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -333,10 +333,11 @@
     extensionResolver = ExtensionMemberResolver(this);
     typePropertyResolver = TypePropertyResolver(this);
     inferenceHelper = InvocationInferenceHelper(
-        resolver: this,
-        errorReporter: errorReporter,
-        typeSystem: typeSystem,
-        migrationResolutionHooks: migrationResolutionHooks);
+      resolver: this,
+      errorReporter: errorReporter,
+      typeSystem: typeSystem,
+      migrationResolutionHooks: migrationResolutionHooks,
+    );
     _assignmentExpressionResolver = AssignmentExpressionResolver(
       resolver: this,
     );
diff --git a/pkg/analyzer/lib/src/lint/analysis.dart b/pkg/analyzer/lib/src/lint/analysis.dart
index 5e0e60d..6869458 100644
--- a/pkg/analyzer/lib/src/lint/analysis.dart
+++ b/pkg/analyzer/lib/src/lint/analysis.dart
@@ -201,7 +201,7 @@
 
     List<AnalysisErrorInfo> errors = [];
     for (Source source in sources) {
-      var errorsResult = (await analysisDriver.getErrors(source.fullName))!;
+      var errorsResult = await analysisDriver.getErrors(source.fullName);
       errors.add(
           AnalysisErrorInfoImpl(errorsResult.errors, errorsResult.lineInfo));
       _sourcesAnalyzed.add(source);
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 22ddf8d..07c970a 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -1409,13 +1409,15 @@
       var isDeprecated = _hasDeprecatedAnnotation(node);
 
       var hasConstructor = false;
-      void addClassMembers(Declaration parent, List<ClassMember> members) {
+      void addClassMembers(Declaration parent, bool parentIsAbstract,
+          List<ClassMember> members) {
         for (var classMember in members) {
           setCodeRange(classMember);
           setDartDoc(classMember);
           isDeprecated = _hasDeprecatedAnnotation(classMember);
 
-          if (classMember is ConstructorDeclaration) {
+          if (classMember is ConstructorDeclaration &&
+              (!parentIsAbstract || classMember.factoryKeyword != null)) {
             var parameters = classMember.parameters;
             var defaultArguments = _computeDefaultArguments(parameters);
             var isConst = classMember.constKeyword != null;
@@ -1534,7 +1536,8 @@
         );
         if (classDeclaration == null) continue;
 
-        addClassMembers(classDeclaration, node.members);
+        addClassMembers(
+            classDeclaration, classDeclaration.isAbstract, node.members);
 
         if (!hasConstructor) {
           classDeclaration.children.add(Declaration(
@@ -1689,7 +1692,7 @@
           relevanceTags: ['ElementKind.MIXIN'],
         );
         if (mixinDeclaration == null) continue;
-        addClassMembers(mixinDeclaration, node.members);
+        addClassMembers(mixinDeclaration, false, node.members);
       } else if (node is TopLevelVariableDeclaration) {
         var isConst = node.variables.isConst;
         var isFinal = node.variables.isFinal;
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 349e405..ecace4e 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -1020,7 +1020,7 @@
         var astReader = AstBinaryReader(
           reader: this,
         );
-        var directive = astReader.readNode() as DirectiveImpl;
+        var directive = astReader.readNode() as Directive;
         _unit.directives.add(directive);
       }
     }
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 3555861..f049832d 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -303,6 +303,8 @@
       mixinElement,
       mixinSupertypeConstraints,
       matchingInterfaceTypes,
+      genericMetadataIsEnabled:
+          mixinElement.library.featureSet.isEnabled(Feature.generic_metadata),
     );
     if (inferredTypeArguments != null) {
       var inferredMixin = mixinElement.instantiate(
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 6536e46..ceb6903 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -2340,13 +2340,15 @@
     // B's superclass is "Object with A1<T>".  So mixin type inference succeeds
     // (since C's base class implements A1<int>), and "with B" is interpreted as
     // "with B<int>".
-    await assertNoErrorsInCode('''
+    await assertErrorsInCode('''
 class A1<T> {}
 class A2<T> {}
 class B<T> = Object with A1<T>, A2<T>;
 class Base implements A1<int> {}
 class C = Base with B;
-''');
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 122, 1),
+    ]);
     var bReference = result.unit!.declaredElement!.getType('C')!.mixins[0];
     assertType(bReference.typeArguments[0], 'int');
   }
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 6ba7bff..78b4c28 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1156,7 +1156,7 @@
     String content = 'int f() => 42 + bar();';
     addTestFile(content, priority: true);
 
-    var result = (await driver.getErrors(testFile))!;
+    var result = await driver.getErrors(testFile);
     expect(result.path, testFile);
     expect(result.uri.toString(), 'package:test/test.dart');
     expect(result.errors, hasLength(1));
@@ -2212,7 +2212,7 @@
     getFile(asyncPath).delete();
     addTestFile('class C {}');
 
-    ErrorsResult result = (await driver.getErrors(testFile))!;
+    ErrorsResult result = await driver.getErrors(testFile);
     expect(result.errors, hasLength(1));
 
     AnalysisError error = result.errors[0];
@@ -2224,7 +2224,7 @@
     getFile(corePath).delete();
     addTestFile('class C {}');
 
-    ErrorsResult result = (await driver.getErrors(testFile))!;
+    ErrorsResult result = await driver.getErrors(testFile);
     expect(result.errors, hasLength(1));
 
     AnalysisError error = result.errors[0];
@@ -2452,13 +2452,13 @@
 
     // Process a.dart so that we know that it's a library for c.dart later.
     {
-      ErrorsResult result = (await driver.getErrors(a))!;
+      ErrorsResult result = await driver.getErrors(a);
       expect(result.errors, isEmpty);
     }
 
     // c.dart does not have errors in the context of a.dart
     {
-      ErrorsResult result = (await driver.getErrors(c))!;
+      ErrorsResult result = await driver.getErrors(c);
       expect(result.errors, isEmpty);
     }
   }
@@ -2488,7 +2488,7 @@
 
     // c.dart is resolve in the context of a.dart, so have no errors
     {
-      ErrorsResult result = (await driver.getErrors(c))!;
+      ErrorsResult result = await driver.getErrors(c);
       expect(result.errors, isEmpty);
     }
   }
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index a1c0131..e06ecf0 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/analysis/analysis_context.dart';
 import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
@@ -13,13 +14,45 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../resolution/context_collection_resolution.dart';
+
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnalysisSessionImplTest);
+    defineReflectiveTests(AnalysisSessionImpl_BazelWorkspaceTest);
   });
 }
 
 @reflectiveTest
+class AnalysisSessionImpl_BazelWorkspaceTest
+    extends BazelWorkspaceResolutionTest {
+  void test_getErrors_notFileOfUri() async {
+    var relPath = 'dart/my/lib/a.dart';
+    newFile('$workspaceRootPath/bazel-bin/$relPath');
+
+    var path = '$workspaceRootPath/$relPath';
+    var session = contextFor(path).currentSession;
+    var result = await session.getErrors(path);
+    expect(result.state, ResultState.NOT_FILE_OF_URI);
+    expect(() => result.errors, throwsStateError);
+  }
+
+  void test_getErrors_valid() async {
+    var file = newFile(
+      '$workspaceRootPath/dart/my/lib/a.dart',
+      content: 'var x = 0',
+    );
+
+    var session = contextFor(file.path).currentSession;
+    var result = await session.getErrors(file.path);
+    expect(result.state, ResultState.VALID);
+    expect(result.path, file.path);
+    expect(result.errors, hasLength(1));
+    expect(result.uri.toString(), 'package:dart.my/a.dart');
+  }
+}
+
+@reflectiveTest
 class AnalysisSessionImplTest with ResourceProviderMixin {
   late final AnalysisContextCollection contextCollection;
   late final AnalysisContext context;
@@ -55,7 +88,7 @@
 
   test_getErrors() async {
     newFile(testPath, content: 'class C {');
-    var errorsResult = (await session.getErrors(testPath))!;
+    var errorsResult = await session.getErrors(testPath);
     expect(errorsResult.session, session);
     expect(errorsResult.path, testPath);
     expect(errorsResult.errors, isNotEmpty);
diff --git a/pkg/analyzer/test/src/dart/ast/utilities_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
index 646e114..9d96e0e 100644
--- a/pkg/analyzer/test/src/dart/ast/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -2,26 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/dart/element/type_provider.dart';
-import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
-import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../../generated/elements_types_mixin.dart';
 import '../../../generated/parser_test_base.dart' show ParserTestCase;
 import '../../../util/ast_type_matchers.dart';
 
@@ -29,7 +14,6 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(NodeLocatorTest);
     defineReflectiveTests(NodeLocator2Test);
-    defineReflectiveTests(ResolutionCopierTest);
   });
 }
 
@@ -128,936 +112,3 @@
     return node;
   }
 }
-
-@reflectiveTest
-class ResolutionCopierTest with ElementsTypesMixin {
-  @override
-  final TypeProvider typeProvider = TestTypeProvider();
-
-  void test_topLevelVariableDeclaration_external() {
-    var fromNode = AstTestFactory.topLevelVariableDeclaration2(
-        Keyword.VAR, [AstTestFactory.variableDeclaration('x')],
-        isExternal: false);
-    TopLevelVariableElement element = TopLevelVariableElementImpl('x', -1);
-    fromNode.variables.variables[0].name.staticElement = element;
-    TopLevelVariableDeclaration toNode1 =
-        AstTestFactory.topLevelVariableDeclaration2(
-            Keyword.VAR, [AstTestFactory.variableDeclaration('x')],
-            isExternal: false);
-    ResolutionCopier.copyResolutionData(fromNode, toNode1);
-    // Nodes matched so resolution data should have been copied.
-    expect(toNode1.variables.variables[0].declaredElement, same(element));
-    TopLevelVariableDeclaration toNode2 =
-        AstTestFactory.topLevelVariableDeclaration2(
-            Keyword.VAR, [AstTestFactory.variableDeclaration('x')],
-            isExternal: true);
-    ResolutionCopier.copyResolutionData(fromNode, toNode1);
-    // Nodes didn't match so resolution data should not have been copied.
-    expect(toNode2.variables.variables[0].declaredElement, isNull);
-  }
-
-  void test_visitAdjacentStrings() {
-    AdjacentStringsImpl createNode() => astFactory.adjacentStrings([
-          astFactory.simpleStringLiteral(
-            TokenFactory.tokenFromString('hello'),
-            'hello',
-          ),
-          astFactory.simpleStringLiteral(
-            TokenFactory.tokenFromString('world'),
-            'world',
-          )
-        ]);
-
-    var fromNode = createNode();
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('B'));
-    fromNode.staticType = staticType;
-
-    AdjacentStrings toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitAnnotation() {
-    String annotationName = "proxy";
-    var fromNode =
-        AstTestFactory.annotation(AstTestFactory.identifier3(annotationName));
-    Element element = ElementFactory.topLevelVariableElement2(annotationName);
-    fromNode.element = element;
-    Annotation toNode =
-        AstTestFactory.annotation(AstTestFactory.identifier3(annotationName));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.element, same(element));
-  }
-
-  void test_visitAnnotation_generic() {
-    var annotationClassName = "A";
-    var annotationConstructorName = "named";
-    var argumentName = "x";
-    var fromNode = AstTestFactory.annotation2(
-        AstTestFactory.identifier3(annotationClassName),
-        AstTestFactory.identifier3(annotationConstructorName),
-        AstTestFactory.argumentList(
-            [AstTestFactory.identifier3(argumentName)]));
-    var elementA = ElementFactory.classElement2(annotationClassName, ['T']);
-    var element = ElementFactory.constructorElement(
-        elementA, annotationConstructorName, true, [typeProvider.dynamicType]);
-    fromNode.element = element;
-    var typeArgumentName = 'U';
-    var elementU = ElementFactory.classElement2(typeArgumentName);
-    fromNode.typeArguments =
-        AstTestFactory.typeArgumentList2([AstTestFactory.typeName(elementU)]);
-    var toNode = AstTestFactory.annotation2(
-        AstTestFactory.identifier3(annotationClassName),
-        AstTestFactory.identifier3(annotationConstructorName),
-        AstTestFactory.argumentList(
-            [AstTestFactory.identifier3(argumentName)]));
-    toNode.typeArguments = AstTestFactory.typeArgumentList2(
-        [AstTestFactory.typeName4(typeArgumentName)]);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.element, same(element));
-    expect(
-        (toNode.typeArguments!.arguments.single as TypeName).name.staticElement,
-        same(elementU));
-  }
-
-  void test_visitAsExpression() {
-    var fromNode = AstTestFactory.asExpression(
-        AstTestFactory.identifier3("x"), AstTestFactory.typeName4("A"));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('B'));
-    fromNode.staticType = staticType;
-    AsExpression toNode = AstTestFactory.asExpression(
-        AstTestFactory.identifier3("x"), AstTestFactory.typeName4("A"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitAssignmentExpression() {
-    var fromNode = AstTestFactory.assignmentExpression(
-        AstTestFactory.identifier3("a"),
-        TokenType.PLUS_EQ,
-        AstTestFactory.identifier3("b"));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    MethodElement staticElement = ElementFactory.methodElement("+", staticType);
-    fromNode.staticElement = staticElement;
-    fromNode.staticType = staticType;
-    AssignmentExpression toNode = AstTestFactory.assignmentExpression(
-        AstTestFactory.identifier3("a"),
-        TokenType.PLUS_EQ,
-        AstTestFactory.identifier3("b"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitBinaryExpression() {
-    var fromNode = AstTestFactory.binaryExpression(
-        AstTestFactory.identifier3("a"),
-        TokenType.PLUS,
-        AstTestFactory.identifier3("b"));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    MethodElement staticElement = ElementFactory.methodElement("+", staticType);
-    fromNode.staticElement = staticElement;
-    fromNode.staticType = staticType;
-    BinaryExpression toNode = AstTestFactory.binaryExpression(
-        AstTestFactory.identifier3("a"),
-        TokenType.PLUS,
-        AstTestFactory.identifier3("b"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitBooleanLiteral() {
-    var fromNode = AstTestFactory.booleanLiteral(true);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    BooleanLiteral toNode = AstTestFactory.booleanLiteral(true);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitCascadeExpression() {
-    var fromNode = AstTestFactory.cascadeExpression(
-        AstTestFactory.identifier3("a"), [AstTestFactory.identifier3("b")]);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    CascadeExpression toNode = AstTestFactory.cascadeExpression(
-        AstTestFactory.identifier3("a"), [AstTestFactory.identifier3("b")]);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitCompilationUnit() {
-    var fromNode = AstTestFactory.compilationUnit();
-    CompilationUnitElement element = CompilationUnitElementImpl();
-    fromNode.element = element;
-    CompilationUnit toNode = AstTestFactory.compilationUnit();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.declaredElement, same(element));
-  }
-
-  void test_visitConditionalExpression() {
-    var fromNode = AstTestFactory.conditionalExpression(
-        AstTestFactory.identifier3("c"),
-        AstTestFactory.identifier3("a"),
-        AstTestFactory.identifier3("b"));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    ConditionalExpression toNode = AstTestFactory.conditionalExpression(
-        AstTestFactory.identifier3("c"),
-        AstTestFactory.identifier3("a"),
-        AstTestFactory.identifier3("b"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitConstructorDeclaration() {
-    String className = "A";
-    String constructorName = "c";
-    var fromNode = AstTestFactory.constructorDeclaration(
-        AstTestFactory.identifier3(className),
-        constructorName,
-        AstTestFactory.formalParameterList(), []);
-    ConstructorElement element = ElementFactory.constructorElement2(
-        ElementFactory.classElement2(className), constructorName);
-    fromNode.declaredElement = element;
-    ConstructorDeclaration toNode = AstTestFactory.constructorDeclaration(
-        AstTestFactory.identifier3(className),
-        constructorName,
-        AstTestFactory.formalParameterList(), []);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.declaredElement, same(element));
-  }
-
-  void test_visitConstructorName() {
-    var fromNode =
-        AstTestFactory.constructorName(AstTestFactory.typeName4("A"), "c");
-    ConstructorElement staticElement = ElementFactory.constructorElement2(
-        ElementFactory.classElement2("A"), "c");
-    fromNode.staticElement = staticElement;
-    ConstructorName toNode =
-        AstTestFactory.constructorName(AstTestFactory.typeName4("A"), "c");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-  }
-
-  void test_visitDoubleLiteral() {
-    var fromNode = AstTestFactory.doubleLiteral(1.0);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    DoubleLiteral toNode = AstTestFactory.doubleLiteral(1.0);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitExportDirective() {
-    var fromNode = AstTestFactory.exportDirective2("dart:uri");
-    ExportElement element = ExportElementImpl(-1);
-    fromNode.element = element;
-    ExportDirective toNode = AstTestFactory.exportDirective2("dart:uri");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.element, same(element));
-  }
-
-  void test_visitFieldDeclaration_abstract() {
-    FieldDeclaration fromNode = AstTestFactory.fieldDeclaration(
-        false, Keyword.VAR, null, [AstTestFactory.variableDeclaration('x')],
-        isAbstract: false);
-    FieldElement element = FieldElementImpl('x', -1);
-    (fromNode.fields.variables[0] as VariableDeclarationImpl)
-        .name
-        .staticElement = element;
-    FieldDeclaration toNode1 = AstTestFactory.fieldDeclaration(
-        false, Keyword.VAR, null, [AstTestFactory.variableDeclaration('x')],
-        isAbstract: false);
-    ResolutionCopier.copyResolutionData(fromNode, toNode1);
-    // Nodes matched so resolution data should have been copied.
-    expect(toNode1.fields.variables[0].declaredElement, same(element));
-    FieldDeclaration toNode2 = AstTestFactory.fieldDeclaration(
-        false, Keyword.VAR, null, [AstTestFactory.variableDeclaration('x')],
-        isAbstract: true);
-    ResolutionCopier.copyResolutionData(fromNode, toNode1);
-    // Nodes didn't match so resolution data should not have been copied.
-    expect(toNode2.fields.variables[0].declaredElement, isNull);
-  }
-
-  void test_visitFieldDeclaration_external() {
-    FieldDeclaration fromNode = AstTestFactory.fieldDeclaration(
-        false, Keyword.VAR, null, [AstTestFactory.variableDeclaration('x')],
-        isExternal: false);
-    FieldElement element = FieldElementImpl('x', -1);
-    (fromNode.fields.variables[0] as VariableDeclarationImpl)
-        .name
-        .staticElement = element;
-    FieldDeclaration toNode1 = AstTestFactory.fieldDeclaration(
-        false, Keyword.VAR, null, [AstTestFactory.variableDeclaration('x')],
-        isExternal: false);
-    ResolutionCopier.copyResolutionData(fromNode, toNode1);
-    // Nodes matched so resolution data should have been copied.
-    expect(toNode1.fields.variables[0].declaredElement, same(element));
-    FieldDeclaration toNode2 = AstTestFactory.fieldDeclaration(
-        false, Keyword.VAR, null, [AstTestFactory.variableDeclaration('x')],
-        isExternal: true);
-    ResolutionCopier.copyResolutionData(fromNode, toNode1);
-    // Nodes didn't match so resolution data should not have been copied.
-    expect(toNode2.fields.variables[0].declaredElement, isNull);
-  }
-
-  void test_visitForEachPartsWithDeclaration() {
-    ForEachPartsWithDeclaration createNode() =>
-        astFactory.forEachPartsWithDeclaration(
-            loopVariable: AstTestFactory.declaredIdentifier3('a'),
-            inKeyword: TokenFactory.tokenFromKeyword(Keyword.IN),
-            iterable: AstTestFactory.identifier3('b'));
-
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-
-    ForEachPartsWithDeclaration fromNode = createNode();
-    (fromNode.iterable as SimpleIdentifierImpl).staticType = typeB;
-
-    ForEachPartsWithDeclaration toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.iterable as SimpleIdentifier).staticType, same(typeB));
-  }
-
-  void test_visitForEachPartsWithIdentifier() {
-    ForEachPartsWithIdentifierImpl createNode() =>
-        astFactory.forEachPartsWithIdentifier(
-            identifier: AstTestFactory.identifier3('a'),
-            inKeyword: TokenFactory.tokenFromKeyword(Keyword.IN),
-            iterable: AstTestFactory.identifier3('b'));
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-
-    var fromNode = createNode();
-    fromNode.identifier.staticType = typeA;
-    (fromNode.iterable as SimpleIdentifierImpl).staticType = typeB;
-
-    ForEachPartsWithIdentifier toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.identifier.staticType, same(typeA));
-    expect((toNode.iterable as SimpleIdentifier).staticType, same(typeB));
-  }
-
-  void test_visitForElement() {
-    ForElementImpl createNode() => astFactory.forElement(
-        forKeyword: TokenFactory.tokenFromKeyword(Keyword.FOR),
-        leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-        forLoopParts: astFactory.forEachPartsWithIdentifier(
-            identifier: AstTestFactory.identifier3('a'),
-            inKeyword: TokenFactory.tokenFromKeyword(Keyword.IN),
-            iterable: AstTestFactory.identifier3('b')),
-        rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-        body: AstTestFactory.identifier3('c'));
-
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-
-    ForElement fromNode = createNode();
-    (fromNode.body as SimpleIdentifierImpl).staticType = typeC;
-
-    ForElement toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.body as SimpleIdentifier).staticType, same(typeC));
-  }
-
-  void test_visitForPartsWithDeclarations() {
-    ForPartsWithDeclarations createNode() =>
-        astFactory.forPartsWithDeclarations(
-            variables: AstTestFactory.variableDeclarationList2(
-                Keyword.VAR, [AstTestFactory.variableDeclaration('a')]),
-            leftSeparator: TokenFactory.tokenFromType(TokenType.SEMICOLON),
-            condition: AstTestFactory.identifier3('b'),
-            rightSeparator: TokenFactory.tokenFromType(TokenType.SEMICOLON),
-            updaters: [AstTestFactory.identifier3('c')]);
-
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-
-    ForPartsWithDeclarations fromNode = createNode();
-    (fromNode.condition as SimpleIdentifierImpl).staticType = typeB;
-    (fromNode.updaters[0] as SimpleIdentifierImpl).staticType = typeC;
-
-    ForPartsWithDeclarations toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.condition as SimpleIdentifier).staticType, same(typeB));
-    expect((toNode.updaters[0] as SimpleIdentifier).staticType, same(typeC));
-  }
-
-  void test_visitForPartsWithExpression() {
-    ForPartsWithExpression createNode() => astFactory.forPartsWithExpression(
-        initialization: AstTestFactory.identifier3('a'),
-        leftSeparator: TokenFactory.tokenFromType(TokenType.SEMICOLON),
-        condition: AstTestFactory.identifier3('b'),
-        rightSeparator: TokenFactory.tokenFromType(TokenType.SEMICOLON),
-        updaters: [AstTestFactory.identifier3('c')]);
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-
-    ForPartsWithExpression fromNode = createNode();
-    (fromNode.initialization as SimpleIdentifierImpl).staticType = typeA;
-    (fromNode.condition as SimpleIdentifierImpl).staticType = typeB;
-    (fromNode.updaters[0] as SimpleIdentifierImpl).staticType = typeC;
-
-    ForPartsWithExpression toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.initialization as SimpleIdentifier).staticType, same(typeA));
-    expect((toNode.condition as SimpleIdentifier).staticType, same(typeB));
-    expect((toNode.updaters[0] as SimpleIdentifier).staticType, same(typeC));
-  }
-
-  void test_visitForStatement() {
-    ForStatement createNode() => astFactory.forStatement(
-        forKeyword: TokenFactory.tokenFromKeyword(Keyword.FOR),
-        leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-        forLoopParts: astFactory.forEachPartsWithIdentifier(
-            identifier: AstTestFactory.identifier3('a'),
-            inKeyword: TokenFactory.tokenFromKeyword(Keyword.IN),
-            iterable: AstTestFactory.identifier3('b')),
-        rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-        body: AstTestFactory.expressionStatement(
-            AstTestFactory.identifier3('c')));
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-
-    ForStatement fromNode = createNode();
-    var fromForLoopParts =
-        fromNode.forLoopParts as ForEachPartsWithIdentifierImpl;
-    fromForLoopParts.identifier.staticType = typeA;
-    fromForLoopParts.iterable.staticType = typeB;
-    (fromNode.body as ExpressionStatementImpl).expression.staticType = typeC;
-
-    ForStatement toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    var toForLoopParts = fromNode.forLoopParts as ForEachPartsWithIdentifier;
-    expect(toForLoopParts.identifier.staticType, same(typeA));
-    expect(
-        (toForLoopParts.iterable as SimpleIdentifier).staticType, same(typeB));
-    expect(
-        ((toNode.body as ExpressionStatement).expression as SimpleIdentifier)
-            .staticType,
-        same(typeC));
-  }
-
-  void test_visitFunctionExpression() {
-    var fromNode = AstTestFactory.functionExpression2(
-        AstTestFactory.formalParameterList(),
-        AstTestFactory.emptyFunctionBody());
-    MethodElement element = ElementFactory.methodElement(
-        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
-    fromNode.declaredElement = element;
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    FunctionExpression toNode = AstTestFactory.functionExpression2(
-        AstTestFactory.formalParameterList(),
-        AstTestFactory.emptyFunctionBody());
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.declaredElement, same(element));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitFunctionExpressionInvocation() {
-    var fromNode = AstTestFactory.functionExpressionInvocation(
-        AstTestFactory.identifier3("f"));
-    MethodElement staticElement = ElementFactory.methodElement(
-        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
-    fromNode.staticElement = staticElement;
-    var toNode = AstTestFactory.functionExpressionInvocation(
-        AstTestFactory.identifier3("f"));
-    ClassElement elementT = ElementFactory.classElement2('T');
-    fromNode.typeArguments = AstTestFactory.typeArgumentList(
-        <TypeAnnotation>[AstTestFactory.typeName(elementT)]);
-    toNode.typeArguments = AstTestFactory.typeArgumentList(
-        <TypeAnnotation>[AstTestFactory.typeName4('T')]);
-
-    _copyAndVerifyInvocation(fromNode, toNode);
-
-    expect(toNode.staticElement, same(staticElement));
-  }
-
-  void test_visitIfElement() {
-    IfElementImpl createNode() => astFactory.ifElement(
-        ifKeyword: TokenFactory.tokenFromKeyword(Keyword.IF),
-        leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-        condition: AstTestFactory.identifier3('a'),
-        rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-        thenElement: AstTestFactory.identifier3('b'),
-        elseElement: AstTestFactory.identifier3('c'));
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-
-    var fromNode = createNode();
-    (fromNode.condition as SimpleIdentifierImpl).staticType = typeA;
-    (fromNode.thenElement as SimpleIdentifierImpl).staticType = typeB;
-    (fromNode.elseElement as SimpleIdentifierImpl).staticType = typeC;
-
-    IfElement toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.condition.staticType, same(typeA));
-    expect((toNode.thenElement as SimpleIdentifier).staticType, same(typeB));
-    expect((toNode.elseElement as SimpleIdentifier).staticType, same(typeC));
-  }
-
-  void test_visitImportDirective() {
-    var fromNode = AstTestFactory.importDirective3("dart:uri", null);
-    ImportElement element = ImportElementImpl(0);
-    fromNode.element = element;
-    ImportDirective toNode = AstTestFactory.importDirective3("dart:uri", null);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.element, same(element));
-  }
-
-  void test_visitIndexExpression() {
-    var fromNode = AstTestFactory.indexExpression(
-      target: AstTestFactory.identifier3("a"),
-      index: AstTestFactory.integer(0),
-    );
-    MethodElement staticElement = ElementFactory.methodElement(
-        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
-    fromNode.staticElement = staticElement;
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    IndexExpression toNode = AstTestFactory.indexExpression(
-      target: AstTestFactory.identifier3("a"),
-      index: AstTestFactory.integer(0),
-    );
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitInstanceCreationExpression() {
-    var fromNode = AstTestFactory.instanceCreationExpression2(
-        Keyword.NEW, AstTestFactory.typeName4("C"));
-    ConstructorElement staticElement = ElementFactory.constructorElement2(
-        ElementFactory.classElement2("C"), null);
-    fromNode.constructorName.staticElement = staticElement;
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    InstanceCreationExpression toNode =
-        AstTestFactory.instanceCreationExpression2(
-            Keyword.NEW, AstTestFactory.typeName4("C"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.constructorName.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitIntegerLiteral() {
-    var fromNode = AstTestFactory.integer(2);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    IntegerLiteral toNode = AstTestFactory.integer(2);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitIsExpression() {
-    var fromNode = AstTestFactory.isExpression(
-        AstTestFactory.identifier3("x"), false, AstTestFactory.typeName4("A"));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    IsExpression toNode = AstTestFactory.isExpression(
-        AstTestFactory.identifier3("x"), false, AstTestFactory.typeName4("A"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitLibraryIdentifier() {
-    var fromNode =
-        AstTestFactory.libraryIdentifier([AstTestFactory.identifier3("lib")]);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    LibraryIdentifier toNode =
-        AstTestFactory.libraryIdentifier([AstTestFactory.identifier3("lib")]);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitListLiteral() {
-    ListLiteralImpl createNode() => astFactory.listLiteral(
-          null,
-          AstTestFactory.typeArgumentList([AstTestFactory.typeName4('A')]),
-          TokenFactory.tokenFromType(TokenType.OPEN_SQUARE_BRACKET),
-          [AstTestFactory.identifier3('b')],
-          TokenFactory.tokenFromType(TokenType.CLOSE_SQUARE_BRACKET),
-        );
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-
-    var fromNode = createNode();
-    (fromNode.typeArguments!.arguments[0] as TypeNameImpl).type = typeA;
-    (fromNode.elements[0] as SimpleIdentifierImpl).staticType = typeB;
-    fromNode.staticType = typeC;
-
-    ListLiteral toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.typeArguments!.arguments[0] as TypeName).type, same(typeA));
-    expect((toNode.elements[0] as SimpleIdentifier).staticType, same(typeB));
-    expect(fromNode.staticType, same(typeC));
-  }
-
-  void test_visitMapLiteral() {
-    var fromNode = AstTestFactory.setOrMapLiteral(null, null);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    SetOrMapLiteral toNode = AstTestFactory.setOrMapLiteral(null, null);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitMethodInvocation() {
-    var fromNode = AstTestFactory.methodInvocation2("m");
-    var toNode = AstTestFactory.methodInvocation2("m");
-    ClassElement elementT = ElementFactory.classElement2('T');
-    fromNode.typeArguments = AstTestFactory.typeArgumentList(
-        <TypeAnnotation>[AstTestFactory.typeName(elementT)]);
-    toNode.typeArguments = AstTestFactory.typeArgumentList(
-        <TypeAnnotation>[AstTestFactory.typeName4('T')]);
-    _copyAndVerifyInvocation(fromNode, toNode);
-  }
-
-  void test_visitNamedExpression() {
-    var fromNode =
-        AstTestFactory.namedExpression2("n", AstTestFactory.integer(0));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    NamedExpression toNode =
-        AstTestFactory.namedExpression2("n", AstTestFactory.integer(0));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitNullLiteral() {
-    var fromNode = AstTestFactory.nullLiteral();
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    NullLiteral toNode = AstTestFactory.nullLiteral();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitParenthesizedExpression() {
-    var fromNode =
-        AstTestFactory.parenthesizedExpression(AstTestFactory.integer(0));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    ParenthesizedExpression toNode =
-        AstTestFactory.parenthesizedExpression(AstTestFactory.integer(0));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitPartDirective() {
-    var fromNode = AstTestFactory.partDirective2("part.dart");
-    LibraryElement element = LibraryElementImpl(
-        _AnalysisContextMock(),
-        _AnalysisSessionMock(),
-        'lib',
-        -1,
-        0,
-        FeatureSet.latestLanguageVersion());
-    fromNode.element = element;
-    PartDirective toNode = AstTestFactory.partDirective2("part.dart");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.element, same(element));
-  }
-
-  void test_visitPartOfDirective() {
-    var fromNode = AstTestFactory.partOfDirective(
-        AstTestFactory.libraryIdentifier2(["lib"]));
-    LibraryElement element = LibraryElementImpl(
-        _AnalysisContextMock(),
-        _AnalysisSessionMock(),
-        'lib',
-        -1,
-        0,
-        FeatureSet.latestLanguageVersion());
-    fromNode.element = element;
-    PartOfDirective toNode = AstTestFactory.partOfDirective(
-        AstTestFactory.libraryIdentifier2(["lib"]));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.element, same(element));
-  }
-
-  void test_visitPostfixExpression() {
-    String variableName = "x";
-    var fromNode = AstTestFactory.postfixExpression(
-        AstTestFactory.identifier3(variableName), TokenType.PLUS_PLUS);
-    MethodElement staticElement = ElementFactory.methodElement(
-        "+", interfaceTypeStar(ElementFactory.classElement2('C')));
-    fromNode.staticElement = staticElement;
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    PostfixExpression toNode = AstTestFactory.postfixExpression(
-        AstTestFactory.identifier3(variableName), TokenType.PLUS_PLUS);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitPrefixedIdentifier() {
-    var fromNode = AstTestFactory.identifier5("p", "f");
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    PrefixedIdentifier toNode = AstTestFactory.identifier5("p", "f");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitPrefixExpression() {
-    var fromNode = AstTestFactory.prefixExpression(
-        TokenType.PLUS_PLUS, AstTestFactory.identifier3("x"));
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    MethodElement staticElement = ElementFactory.methodElement(
-        "+", interfaceTypeStar(ElementFactory.classElement2('C')));
-    fromNode.staticElement = staticElement;
-    fromNode.staticType = staticType;
-    PrefixExpression toNode = AstTestFactory.prefixExpression(
-        TokenType.PLUS_PLUS, AstTestFactory.identifier3("x"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitPropertyAccess() {
-    var fromNode =
-        AstTestFactory.propertyAccess2(AstTestFactory.identifier3("x"), "y");
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    PropertyAccess toNode =
-        AstTestFactory.propertyAccess2(AstTestFactory.identifier3("x"), "y");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitRedirectingConstructorInvocation() {
-    var fromNode = AstTestFactory.redirectingConstructorInvocation();
-    ConstructorElement staticElement = ElementFactory.constructorElement2(
-        ElementFactory.classElement2("C"), null);
-    fromNode.staticElement = staticElement;
-    RedirectingConstructorInvocation toNode =
-        AstTestFactory.redirectingConstructorInvocation();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-  }
-
-  void test_visitRethrowExpression() {
-    var fromNode = AstTestFactory.rethrowExpression();
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    RethrowExpression toNode = AstTestFactory.rethrowExpression();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitSetOrMapLiteral_map() {
-    SetOrMapLiteralImpl createNode() => astFactory.setOrMapLiteral(
-          typeArguments: AstTestFactory.typeArgumentList(
-              [AstTestFactory.typeName4('A'), AstTestFactory.typeName4('B')]),
-          leftBracket: TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET),
-          elements: [AstTestFactory.mapLiteralEntry3('c', 'd')],
-          rightBracket:
-              TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET),
-        );
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
-    DartType typeD = interfaceTypeStar(ElementFactory.classElement2('D'));
-
-    SetOrMapLiteral fromNode = createNode();
-    (fromNode.typeArguments!.arguments[0] as TypeNameImpl).type = typeA;
-    (fromNode.typeArguments!.arguments[1] as TypeNameImpl).type = typeB;
-    MapLiteralEntry fromEntry = fromNode.elements[0] as MapLiteralEntry;
-    (fromEntry.key as SimpleStringLiteralImpl).staticType = typeC;
-    (fromEntry.value as SimpleStringLiteralImpl).staticType = typeD;
-
-    SetOrMapLiteral toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.typeArguments!.arguments[0] as TypeName).type, same(typeA));
-    expect((toNode.typeArguments!.arguments[1] as TypeName).type, same(typeB));
-    MapLiteralEntry toEntry = fromNode.elements[0] as MapLiteralEntry;
-    expect((toEntry.key as SimpleStringLiteral).staticType, same(typeC));
-    expect((toEntry.value as SimpleStringLiteral).staticType, same(typeD));
-  }
-
-  void test_visitSetOrMapLiteral_set() {
-    SetOrMapLiteralImpl createNode() => astFactory.setOrMapLiteral(
-          typeArguments:
-              AstTestFactory.typeArgumentList([AstTestFactory.typeName4('A')]),
-          leftBracket: TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET),
-          elements: [AstTestFactory.identifier3('b')],
-          rightBracket:
-              TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET),
-        );
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
-
-    SetOrMapLiteral fromNode = createNode();
-    (fromNode.typeArguments!.arguments[0] as TypeNameImpl).type = typeA;
-    (fromNode.elements[0] as SimpleIdentifierImpl).staticType = typeB;
-
-    SetOrMapLiteral toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect((toNode.typeArguments!.arguments[0] as TypeName).type, same(typeA));
-    expect((toNode.elements[0] as SimpleIdentifier).staticType, same(typeB));
-  }
-
-  void test_visitSimpleIdentifier() {
-    var fromNode = AstTestFactory.identifier3("x");
-    MethodElement staticElement = ElementFactory.methodElement(
-        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
-    fromNode.staticElement = staticElement;
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    SimpleIdentifier toNode = AstTestFactory.identifier3("x");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitSimpleStringLiteral() {
-    var fromNode = AstTestFactory.string2("abc");
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    SimpleStringLiteral toNode = AstTestFactory.string2("abc");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitSpreadElement() {
-    SpreadElement createNode() => astFactory.spreadElement(
-        spreadOperator:
-            TokenFactory.tokenFromType(TokenType.PERIOD_PERIOD_PERIOD),
-        expression: astFactory.listLiteral(
-            null,
-            null,
-            TokenFactory.tokenFromType(TokenType.OPEN_SQUARE_BRACKET),
-            [AstTestFactory.identifier3('a')],
-            TokenFactory.tokenFromType(TokenType.CLOSE_SQUARE_BRACKET)));
-
-    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
-
-    SpreadElement fromNode = createNode();
-    ((fromNode.expression as ListLiteral).elements[0] as SimpleIdentifierImpl)
-        .staticType = typeA;
-
-    SpreadElement toNode = createNode();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(
-        ((toNode.expression as ListLiteral).elements[0] as SimpleIdentifier)
-            .staticType,
-        same(typeA));
-  }
-
-  void test_visitStringInterpolation() {
-    var fromNode =
-        AstTestFactory.string([AstTestFactory.interpolationString("a", "'a'")]);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    StringInterpolation toNode =
-        AstTestFactory.string([AstTestFactory.interpolationString("a", "'a'")]);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitSuperConstructorInvocation() {
-    var fromNode = AstTestFactory.superConstructorInvocation();
-    ConstructorElement staticElement = ElementFactory.constructorElement2(
-        ElementFactory.classElement2("C"), null);
-    fromNode.staticElement = staticElement;
-    SuperConstructorInvocation toNode =
-        AstTestFactory.superConstructorInvocation();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticElement, same(staticElement));
-  }
-
-  void test_visitSuperExpression() {
-    var fromNode = AstTestFactory.superExpression();
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    SuperExpression toNode = AstTestFactory.superExpression();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitSymbolLiteral() {
-    var fromNode = AstTestFactory.symbolLiteral(["s"]);
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    SymbolLiteral toNode = AstTestFactory.symbolLiteral(["s"]);
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitThisExpression() {
-    var fromNode = AstTestFactory.thisExpression();
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    ThisExpression toNode = AstTestFactory.thisExpression();
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitThrowExpression() {
-    var fromNode = AstTestFactory.throwExpression2(
-      AstTestFactory.integer(0),
-    );
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-    ThrowExpression toNode = AstTestFactory.throwExpression2(
-      AstTestFactory.integer(0),
-    );
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-  }
-
-  void test_visitTypeName() {
-    var fromNode = AstTestFactory.typeName4("C");
-    DartType type = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.type = type;
-    TypeName toNode = AstTestFactory.typeName4("C");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.type, same(type));
-  }
-
-  void _copyAndVerifyInvocation(
-      InvocationExpressionImpl fromNode, InvocationExpression toNode) {
-    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticType = staticType;
-
-    DartType staticInvokeType =
-        interfaceTypeStar(ElementFactory.classElement2('C'));
-    fromNode.staticInvokeType = staticInvokeType;
-
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.staticType, same(staticType));
-    expect(toNode.staticInvokeType, same(staticInvokeType));
-    List<TypeAnnotation> fromTypeArguments = toNode.typeArguments!.arguments;
-    List<TypeAnnotation> toTypeArguments = fromNode.typeArguments!.arguments;
-    for (int i = 0; i < fromTypeArguments.length; i++) {
-      TypeAnnotation toArgument = fromTypeArguments[i];
-      TypeAnnotation fromArgument = toTypeArguments[i];
-      expect(toArgument.type, same(fromArgument.type));
-    }
-  }
-}
-
-class _AnalysisContextMock implements AnalysisContext {
-  @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-class _AnalysisSessionMock implements AnalysisSession {
-  @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/analyzer/test/src/dart/constant/utilities_test.dart b/pkg/analyzer/test/src/dart/constant/utilities_test.dart
index 030fb7c..92b5d6e 100644
--- a/pkg/analyzer/test/src/dart/constant/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/utilities_test.dart
@@ -215,7 +215,7 @@
         keyword == Keyword.CONST,
         _typeProvider.intType);
     variableDeclaration.name.staticElement = fieldElement;
-    var fieldDeclaration = AstTestFactory.fieldDeclaration2(
+    FieldDeclaration fieldDeclaration = AstTestFactory.fieldDeclaration2(
         isStatic, keyword, <VariableDeclaration>[variableDeclaration]);
     var classDeclaration = AstTestFactory.classDeclaration(
         null, className, null, null, null, null);
diff --git a/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart b/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart
index b59d6fd..7933c6f 100644
--- a/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart
+++ b/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart
@@ -654,6 +654,7 @@
       contextReturnType: returnType,
       errorReporter: reporter,
       errorNode: astFactory.nullLiteral(KeywordToken(Keyword.NULL, 0)),
+      genericMetadataIsEnabled: true,
     );
 
     if (expectError) {
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 84d9950..3f18aab 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -243,6 +243,12 @@
   @override
   List<String> get collectionIncludedPaths => [workspaceRootPath];
 
+  List<String> get experiments => [
+        EnableString.generic_metadata,
+        EnableString.nonfunction_type_aliases,
+        EnableString.triple_shift,
+      ];
+
   /// The path that is not in [workspaceRootPath], contains external packages.
   String get packagesRootPath => '/packages';
 
@@ -266,10 +272,7 @@
     super.setUp();
     writeTestPackageAnalysisOptionsFile(
       AnalysisOptionsFileConfig(
-        experiments: [
-          EnableString.nonfunction_type_aliases,
-          EnableString.triple_shift,
-        ],
+        experiments: experiments,
       ),
     );
     writeTestPackageConfig(
diff --git a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
index 99c2406..0cd0ac8 100644
--- a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test/test.dart';
@@ -14,63 +15,54 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(GenericTypeAliasDriverResolutionTest);
+    defineReflectiveTests(
+        GenericTypeAliasDriverResolutionWithoutGenericMetadataTest);
   });
 }
 
 @reflectiveTest
-class GenericTypeAliasDriverResolutionTest extends PubPackageResolutionTest {
+class GenericTypeAliasDriverResolutionTest extends PubPackageResolutionTest
+    with GenericTypeAliasDriverResolutionTestCases {
   test_genericFunctionTypeCannotBeTypeArgument_def_class() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C<T> {}
 
 typedef G = Function<S>();
 
 C<G>? x;
-''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          45, 1),
-    ]);
+''');
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_class() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C<T> {}
 
 C<Function<S>()>? x;
-''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          17, 13),
-    ]);
+''');
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_function() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 void f<T>(T) {}
 
 main() {
   f<Function<S>()>(null);
 }
-''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          30, 13),
-    ]);
+''');
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_functionType() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 late T Function<T>(T?) f;
 
 main() {
   f<Function<S>()>(null);
 }
-''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          40, 13),
-    ]);
+''');
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_method() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C {
   void f<T>(T) {}
 }
@@ -78,23 +70,34 @@
 main() {
   new C().f<Function<S>()>(null);
 }
-''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          52, 13),
-    ]);
+''');
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_typedef() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 typedef T F<T>(T t);
 
 F<Function<S>()>? x;
-''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          24, 13),
-    ]);
+''');
   }
 
+  test_genericFunctionTypeCannotBeTypeArgument_optOutOfGenericMetadata() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+typedef G = Function<S>();
+''');
+    await assertErrorsInCode('''
+// @dart=2.12
+import 'a.dart';
+class C<T> {}
+C<G>? x;
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          47, 1),
+    ]);
+  }
+}
+
+mixin GenericTypeAliasDriverResolutionTestCases on PubPackageResolutionTest {
   test_genericFunctionTypeCannotBeTypeArgument_OK_def_class() async {
     await assertNoErrorsInCode(r'''
 class C<T> {}
@@ -180,3 +183,88 @@
     assertType(u.bound, 'B');
   }
 }
+
+@reflectiveTest
+class GenericTypeAliasDriverResolutionWithoutGenericMetadataTest
+    extends PubPackageResolutionTest
+    with GenericTypeAliasDriverResolutionTestCases {
+  @override
+  List<String> get experiments =>
+      super.experiments..remove(EnableString.generic_metadata);
+
+  test_genericFunctionTypeCannotBeTypeArgument_def_class() async {
+    await assertErrorsInCode(r'''
+class C<T> {}
+
+typedef G = Function<S>();
+
+C<G>? x;
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          45, 1),
+    ]);
+  }
+
+  test_genericFunctionTypeCannotBeTypeArgument_literal_class() async {
+    await assertErrorsInCode(r'''
+class C<T> {}
+
+C<Function<S>()>? x;
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          17, 13),
+    ]);
+  }
+
+  test_genericFunctionTypeCannotBeTypeArgument_literal_function() async {
+    await assertErrorsInCode(r'''
+void f<T>(T) {}
+
+main() {
+  f<Function<S>()>(null);
+}
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          30, 13),
+    ]);
+  }
+
+  test_genericFunctionTypeCannotBeTypeArgument_literal_functionType() async {
+    await assertErrorsInCode(r'''
+late T Function<T>(T?) f;
+
+main() {
+  f<Function<S>()>(null);
+}
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          40, 13),
+    ]);
+  }
+
+  test_genericFunctionTypeCannotBeTypeArgument_literal_method() async {
+    await assertErrorsInCode(r'''
+class C {
+  void f<T>(T) {}
+}
+
+main() {
+  new C().f<Function<S>()>(null);
+}
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          52, 13),
+    ]);
+  }
+
+  test_genericFunctionTypeCannotBeTypeArgument_literal_typedef() async {
+    await assertErrorsInCode(r'''
+typedef T F<T>(T t);
+
+F<Function<S>()>? x;
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          24, 13),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart b/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart
index fe029e8..256e7c4 100644
--- a/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart
@@ -271,4 +271,29 @@
 }
 ''');
   }
+
+  test_functionType() async {
+    await assertNoErrorsInCode('''
+void f<X>() {}
+
+main() {
+  [f];
+}
+''');
+  }
+
+  test_functionType_optOutOfGenericMetadata() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+void f<X>() {}
+''');
+    await assertErrorsInCode('''
+// @dart=2.12
+import 'a.dart';
+main() {
+  [f];
+}
+''', [
+      error(CompileTimeErrorCode.COULD_NOT_INFER, 42, 3),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart b/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart
index 89fde84..583a9a5 100644
--- a/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -10,12 +11,66 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(GenericFunctionTypeCannotBeBoundTest);
+    defineReflectiveTests(
+        GenericFunctionTypeCannotBeBoundWithoutGenericMetadataTest);
   });
 }
 
 @reflectiveTest
 class GenericFunctionTypeCannotBeBoundTest extends PubPackageResolutionTest {
   test_class() async {
+    await assertNoErrorsInCode(r'''
+class C<T extends S Function<S>(S)> {
+}
+''');
+  }
+
+  test_genericFunction() async {
+    await assertNoErrorsInCode(r'''
+late T Function<T extends S Function<S>(S)>(T) fun;
+''');
+  }
+
+  test_genericFunction_optOutOfGenericMetadata() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+typedef F = S Function<S>(S);
+''');
+    await assertErrorsInCode('''
+// @dart=2.12
+import 'a.dart';
+late T Function<T extends F>(T) fun;
+''', [
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 57, 1),
+    ]);
+  }
+
+  test_genericFunctionTypedef() async {
+    await assertNoErrorsInCode(r'''
+typedef foo = T Function<T extends S Function<S>(S)>(T t);
+''');
+  }
+
+  test_parameterOfFunction() async {
+    await assertNoErrorsInCode(r'''
+class C<T extends void Function(S Function<S>(S))> {}
+''');
+  }
+
+  test_typedef() async {
+    await assertNoErrorsInCode(r'''
+typedef T foo<T extends S Function<S>(S)>(T t);
+''');
+  }
+}
+
+@reflectiveTest
+class GenericFunctionTypeCannotBeBoundWithoutGenericMetadataTest
+    extends PubPackageResolutionTest {
+  @override
+  List<String> get experiments =>
+      super.experiments..remove(EnableString.generic_metadata);
+
+  test_class() async {
     await assertErrorsInCode(r'''
 class C<T extends S Function<S>(S)> {
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart
index 7bcbe74..5af77a8 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart
@@ -15,43 +15,7 @@
 
 @reflectiveTest
 class MixinInheritsFromNotObjectTest extends PubPackageResolutionTest {
-  test_classDeclaration_extends() async {
-    await assertErrorsInCode(r'''
-class A {}
-class B extends A {}
-class C extends Object with B {}
-''', [
-      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 60, 1),
-    ]);
-  }
-
-  test_classDeclaration_extends_new_syntax() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-mixin B on A {}
-class C extends A with B {}
-''');
-  }
-
-  test_classDeclaration_mixTypeAlias() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-class B = Object with A;
-class C extends Object with B {}
-''');
-  }
-
-  test_classDeclaration_with() async {
-    await assertErrorsInCode(r'''
-class A {}
-class B extends Object with A {}
-class C extends Object with B {}
-''', [
-      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 72, 1),
-    ]);
-  }
-
-  test_typeAlias_extends() async {
+  test_classAlias_class_extends() async {
     await assertErrorsInCode(r'''
 class A {}
 class B extends A {}
@@ -61,15 +25,7 @@
     ]);
   }
 
-  test_typeAlias_extends_new_syntax() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-mixin B on A {}
-class C = A with B;
-''');
-  }
-
-  test_typeAlias_with() async {
+  test_classAlias_class_with() async {
     await assertErrorsInCode(r'''
 class A {}
 class B extends Object with A {}
@@ -79,11 +35,85 @@
     ]);
   }
 
-  test_typedef_mixTypeAlias() async {
+  test_classAlias_classAlias_with() async {
     await assertNoErrorsInCode(r'''
 class A {}
 class B = Object with A;
 class C = Object with B;
 ''');
   }
+
+  test_classAlias_classAlias_with2() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B {}
+class C = Object with A, B;
+class D = Object with C;
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 72, 1),
+    ]);
+  }
+
+  test_classAlias_mixin() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+mixin B on A {}
+class C = A with B;
+''');
+  }
+
+  test_classDeclaration_class_extends() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B extends A {}
+class C extends Object with B {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 60, 1),
+    ]);
+  }
+
+  test_classDeclaration_class_extends_Object() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+class B extends Object {}
+class C extends Object with B {}
+''');
+  }
+
+  test_classDeclaration_class_with() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B extends Object with A {}
+class C extends Object with B {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 72, 1),
+    ]);
+  }
+
+  test_classDeclaration_classAlias_with() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+class B = Object with A;
+class C extends Object with B {}
+''');
+  }
+
+  test_classDeclaration_classAlias_with2() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B {}
+class C = Object with A, B;
+class D extends Object with C {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 78, 1),
+    ]);
+  }
+
+  test_classDeclaration_mixin() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+mixin B on A {}
+class C extends A with B {}
+''');
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
index 71e8ff7..52b3fab 100644
--- a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
@@ -317,8 +317,6 @@
           CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
           22,
           1),
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          35, 28),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/verify_docs_test.dart b/pkg/analyzer/test/verify_docs_test.dart
index 76acfa9..841fe15 100644
--- a/pkg/analyzer/test/verify_docs_test.dart
+++ b/pkg/analyzer/test/verify_docs_test.dart
@@ -119,7 +119,7 @@
         fail('The snippets directory contains multiple analysis contexts.');
       }
       ErrorsResult results =
-          (await contexts[0].currentSession.getErrors(snippetPath))!;
+          await contexts[0].currentSession.getErrors(snippetPath);
       Iterable<AnalysisError> errors = results.errors.where((error) {
         ErrorCode errorCode = error.errorCode;
         return errorCode != HintCode.UNUSED_IMPORT &&
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 17d63df..3d43b0c 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -919,10 +919,8 @@
         node, node.variable.parent, node.arguments, selector);
   }
 
-  TypeInformation _handleEqualsNull(ir.Expression node, ir.Expression operand,
-      {bool isNot}) {
-    assert(isNot != null);
-    _potentiallyAddNullCheck(node, operand, isNot: isNot);
+  TypeInformation _handleEqualsNull(ir.Expression node, ir.Expression operand) {
+    _potentiallyAddNullCheck(node, operand);
     return _types.boolType;
   }
 
@@ -932,7 +930,7 @@
     // receiver of the call to `==`, which doesn't happen in this case. Remove
     // this when the ssa builder recognized `== null` directly.
     _typeOfReceiver(node, node.expression);
-    return _handleEqualsNull(node, node.expression, isNot: node.isNot);
+    return _handleEqualsNull(node, node.expression);
   }
 
   TypeInformation _handleMethodInvocation(
@@ -975,20 +973,22 @@
     return type;
   }
 
-  TypeInformation _handleEqualsCall(ir.Expression node, ir.Expression left,
-      TypeInformation leftType, ir.Expression right, TypeInformation rightType,
-      {bool isNot}) {
-    assert(isNot != null);
+  TypeInformation _handleEqualsCall(
+      ir.Expression node,
+      ir.Expression left,
+      TypeInformation leftType,
+      ir.Expression right,
+      TypeInformation rightType) {
     // TODO(johnniwinther). This triggers the computation of the mask for the
     // receiver of the call to `==`, which might not happen in this case. Remove
     // this when the ssa builder recognized `== null` directly.
     _typeOfReceiver(node, left);
     if (_types.isNull(leftType)) {
       // null == o
-      return _handleEqualsNull(node, right, isNot: isNot);
+      return _handleEqualsNull(node, right);
     } else if (_types.isNull(rightType)) {
       // o == null
-      return _handleEqualsNull(node, left, isNot: isNot);
+      return _handleEqualsNull(node, left);
     }
     Selector selector = Selector.binaryOperator('==');
     ArgumentsTypes arguments = ArgumentsTypes([rightType], null);
@@ -1000,8 +1000,7 @@
   TypeInformation visitEqualsCall(ir.EqualsCall node) {
     TypeInformation leftType = visit(node.left);
     TypeInformation rightType = visit(node.right);
-    return _handleEqualsCall(node, node.left, leftType, node.right, rightType,
-        isNot: node.isNot);
+    return _handleEqualsCall(node, node.left, leftType, node.right, rightType);
   }
 
   @override
@@ -1053,8 +1052,7 @@
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     if (selector.name == '==') {
       return _handleEqualsCall(node, node.receiver, receiverType,
-          node.arguments.positional.first, arguments.positional[0],
-          isNot: false);
+          node.arguments.positional.first, arguments.positional[0]);
     }
 
     return _handleMethodInvocation(node, node.receiver, receiverType, selector,
@@ -1725,9 +1723,7 @@
     }
   }
 
-  void _potentiallyAddNullCheck(ir.Expression node, ir.Expression receiver,
-      {bool isNot}) {
-    assert(isNot != null);
+  void _potentiallyAddNullCheck(ir.Expression node, ir.Expression receiver) {
     if (!_accumulateIsChecks) return;
     if (receiver is ir.VariableGet) {
       Local local = _localsMap.getLocalVariable(receiver.variable);
@@ -1750,14 +1746,8 @@
           node,
           _closedWorld.commonElements.objectType,
           excludeNull: true);
-
-      if (isNot) {
-        _setStateAfter(
-            _state, stateAfterCheckWhenNotNull, stateAfterCheckWhenNull);
-      } else {
-        _setStateAfter(
-            _state, stateAfterCheckWhenNull, stateAfterCheckWhenNotNull);
-      }
+      _setStateAfter(
+          _state, stateAfterCheckWhenNull, stateAfterCheckWhenNotNull);
     }
   }
 
diff --git a/pkg/compiler/lib/src/ir/debug.dart b/pkg/compiler/lib/src/ir/debug.dart
index 8e2adfa..bb24302 100644
--- a/pkg/compiler/lib/src/ir/debug.dart
+++ b/pkg/compiler/lib/src/ir/debug.dart
@@ -50,6 +50,37 @@
   }
 
   @override
+  visitStaticInvocation(StaticInvocation node) {
+    openNode(node, '${node.runtimeType}', {'target': '${node.target}'});
+    node.visitChildren(this);
+    closeNode();
+  }
+
+  @override
+  visitArguments(Arguments node) {
+    openNode(node, '${node.runtimeType}', {
+      'typeArgs': '${node.types}',
+      'positionalArgs': '${node.positional}',
+      'namedArgs': '${node.named}'
+    });
+    node.visitChildren(this);
+    closeNode();
+  }
+
+  @override
+  visitAsExpression(AsExpression node) {
+    openNode(node, '${node.runtimeType}',
+        {'operand': '${node.operand}', 'DartType': '${node.type}'});
+    node.visitChildren(this);
+    closeNode();
+  }
+
+  @override
+  visitStringLiteral(StringLiteral node) {
+    openAndCloseNode(node, '${node.runtimeType}', {'value': '${node.value}'});
+  }
+
+  @override
   void visitVariableDeclaration(VariableDeclaration node) {
     openNode(node, '${node.runtimeType}', {
       'name': '${node.name ?? '--unnamed--'}',
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 1fa89f1..07e82b0 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -1107,12 +1107,8 @@
   EvaluationComplexity visitLocalFunctionInvocation(
       ir.LocalFunctionInvocation node) {
     if (node.arguments.types.isNotEmpty) {
-      assert(
-          node.variable.parent is ir.LocalFunction,
-          "Unexpected variable in local function invocation ${node} "
-          "(${node.runtimeType}).");
       VariableUse usage =
-          new VariableUse.localTypeArgument(node.variable.parent, node);
+          new VariableUse.localTypeArgument(node.localFunction, node);
       visitNodesInContext(node.arguments.types, usage);
     }
     visitArguments(node.arguments);
@@ -1145,7 +1141,7 @@
   EvaluationComplexity visitPropertyGet(ir.PropertyGet node) {
     node.receiver = _handleExpression(node.receiver);
     EvaluationComplexity complexity = _lastExpressionComplexity;
-    if (complexity.isConstant && node.name.name == 'length') {
+    if (complexity.isConstant && node.name.text == 'length') {
       return _evaluateImplicitConstant(node);
     }
     return const EvaluationComplexity.lazy();
@@ -1155,7 +1151,7 @@
   EvaluationComplexity visitInstanceGet(ir.InstanceGet node) {
     node.receiver = _handleExpression(node.receiver);
     EvaluationComplexity complexity = _lastExpressionComplexity;
-    if (complexity.isConstant && node.name.name == 'length') {
+    if (complexity.isConstant && node.name.text == 'length') {
       return _evaluateImplicitConstant(node);
     }
     return const EvaluationComplexity.lazy();
@@ -1171,7 +1167,7 @@
   EvaluationComplexity visitDynamicGet(ir.DynamicGet node) {
     node.receiver = _handleExpression(node.receiver);
     EvaluationComplexity complexity = _lastExpressionComplexity;
-    if (complexity.isConstant && node.name.name == 'length') {
+    if (complexity.isConstant && node.name.text == 'length') {
       return _evaluateImplicitConstant(node);
     }
     return const EvaluationComplexity.lazy();
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index 7ecbbe2..8dcffab 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -833,8 +833,7 @@
   void handleEqualsCall(ir.Expression left, ir.DartType leftType,
       ir.Expression right, ir.DartType rightType, ir.Member interfaceTarget) {}
 
-  void _registerEqualsNull(TypeMap afterInvocation, ir.Expression expression,
-      {bool isNot: false}) {
+  void _registerEqualsNull(TypeMap afterInvocation, ir.Expression expression) {
     if (expression is ir.VariableGet &&
         !_invalidatedVariables.contains(expression.variable)) {
       // If `expression == null` is true, we promote the type of the
@@ -845,13 +844,8 @@
           isTrue: false);
       TypeMap ofItsDeclaredType = afterInvocation
           .promote(expression.variable, expression.variable.type, isTrue: true);
-      if (isNot) {
-        typeMapWhenTrue = ofItsDeclaredType;
-        typeMapWhenFalse = notOfItsDeclaredType;
-      } else {
-        typeMapWhenTrue = notOfItsDeclaredType;
-        typeMapWhenFalse = ofItsDeclaredType;
-      }
+      typeMapWhenTrue = notOfItsDeclaredType;
+      typeMapWhenFalse = ofItsDeclaredType;
     }
   }
 
@@ -968,7 +962,7 @@
   @override
   ir.DartType visitEqualsNull(ir.EqualsNull node) {
     visitNode(node.expression);
-    _registerEqualsNull(typeMap, node.expression, isNot: node.isNot);
+    _registerEqualsNull(typeMap, node.expression);
     return super.visitEqualsNull(node);
   }
 
@@ -984,7 +978,7 @@
   @override
   ir.DartType visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
     ArgumentTypes argumentTypes = _visitArguments(node.arguments);
-    ir.FunctionDeclaration localFunction = node.variable.parent;
+    ir.FunctionDeclaration localFunction = node.localFunction;
     ir.DartType returnType = super.visitLocalFunctionInvocation(node);
     handleLocalFunctionInvocation(
         node, localFunction, argumentTypes, returnType);
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 ba0057a..7a42127 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -2121,7 +2121,7 @@
         break;
       } else if (node is ir.Field) {
         // Add the field name for closures in field initializers.
-        String name = node.name?.name;
+        String name = node.name?.text;
         if (name != null) parts.add(name);
       }
       current = current.parent;
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index ef086e0..083df95 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -5277,9 +5277,7 @@
   }
 
   void _handleEquals(ir.Expression node, ir.Expression left,
-      HInstruction leftInstruction, HInstruction rightInstruction,
-      {bool isNot}) {
-    assert(isNot != null);
+      HInstruction leftInstruction, HInstruction rightInstruction) {
     _pushDynamicInvocation(
         node,
         _getStaticType(left),
@@ -5288,10 +5286,6 @@
         <HInstruction>[leftInstruction, rightInstruction],
         const <DartType>[],
         _sourceInformationBuilder.buildCall(left, node));
-    if (isNot) {
-      push(new HNot(popBoolified(), _abstractValueDomain.boolType)
-        ..sourceInformation = _sourceInformationBuilder.buildUnary(node));
-    }
   }
 
   @override
@@ -5299,8 +5293,7 @@
     node.expression.accept(this);
     HInstruction receiverInstruction = pop();
     return _handleEquals(node, node.expression, receiverInstruction,
-        graph.addConstantNull(closedWorld),
-        isNot: node.isNot);
+        graph.addConstantNull(closedWorld));
   }
 
   @override
@@ -5309,8 +5302,7 @@
     HInstruction leftInstruction = pop();
     node.right.accept(this);
     HInstruction rightInstruction = pop();
-    return _handleEquals(node, node.left, leftInstruction, rightInstruction,
-        isNot: node.isNot);
+    return _handleEquals(node, node.left, leftInstruction, rightInstruction);
   }
 
   HInterceptor _interceptorFor(
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index b1341b9..faae4a6 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -4369,19 +4369,19 @@
 
   @override
   js_ast.Expression visitDynamicGet(DynamicGet node) {
-    return _emitPropertyGet(node.receiver, null, node.name.name);
+    return _emitPropertyGet(node.receiver, null, node.name.text);
   }
 
   @override
   js_ast.Expression visitInstanceGet(InstanceGet node) {
     return _emitPropertyGet(
-        node.receiver, node.interfaceTarget, node.name.name);
+        node.receiver, node.interfaceTarget, node.name.text);
   }
 
   @override
   js_ast.Expression visitInstanceTearOff(InstanceTearOff node) {
     return _emitPropertyGet(
-        node.receiver, node.interfaceTarget, node.name.name);
+        node.receiver, node.interfaceTarget, node.name.text);
   }
 
   @override
@@ -4554,6 +4554,13 @@
   }
 
   @override
+  js_ast.Expression visitInstanceGetterInvocation(
+      InstanceGetterInvocation node) {
+    return _emitMethodCall(
+        node.receiver, node.interfaceTarget, node.arguments, node);
+  }
+
+  @override
   js_ast.Expression visitLocalFunctionInvocation(LocalFunctionInvocation node) {
     return _emitMethodCall(
         VariableGet(node.variable)..fileOffset = node.fileOffset,
@@ -4565,13 +4572,13 @@
   @override
   js_ast.Expression visitEqualsCall(EqualsCall node) {
     return _emitEqualityOperator(node.left, node.interfaceTarget, node.right,
-        negated: node.isNot);
+        negated: false);
   }
 
   @override
   js_ast.Expression visitEqualsNull(EqualsNull node) {
     return _emitCoreIdenticalCall([node.expression, NullLiteral()],
-        negated: node.isNot);
+        negated: false);
   }
 
   @override
@@ -4591,12 +4598,10 @@
     /// list and the element type is known to be invariant so it can skip the
     /// type check.
     bool isNativeListInvariantAdd(InvocationExpression node) {
-      if (node is MethodInvocation &&
-          node.isInvariant &&
-          node.name.name == 'add') {
+      Expression receiver;
+      if (receiver != null && node.name.text == 'add') {
         // The call to add is marked as invariant, so the type check on the
         // parameter to add is not needed.
-        var receiver = node.receiver;
         if (receiver is VariableGet &&
             receiver.variable.isFinal &&
             !receiver.variable.isLate) {
@@ -5560,6 +5565,13 @@
       return _emitEqualityOperator(operand.receiver, operand.interfaceTarget,
           operand.arguments.positional[0],
           negated: true);
+    } else if (operand is EqualsCall) {
+      return _emitEqualityOperator(
+          operand.left, operand.interfaceTarget, operand.right,
+          negated: true);
+    } else if (operand is EqualsNull) {
+      return _emitCoreIdenticalCall([operand.expression, NullLiteral()],
+          negated: true);
     } else if (operand is StaticInvocation &&
         operand.target == _coreTypes.identicalProcedure) {
       return _emitCoreIdenticalCall(operand.arguments.positional,
diff --git a/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart b/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart
index 413ae5e..933dce6 100644
--- a/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart
@@ -81,7 +81,7 @@
                 member.isForwardingStub ||
                 member.stubKind == ProcedureStubKind.ConcreteMixinStub
             : (member is Field)
-                ? member.name.name.contains(redirectingName)
+                ? member.name.text.contains(redirectingName)
                 : false;
 
     if (!noBreakPointPossible) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index a759519..5b0237b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -609,11 +609,9 @@
     Expression left = transform(node.left);
     Expression right = transform(node.right);
     if (_isNull(left)) {
-      return new EqualsNull(right, isNot: node.isNot)
-        ..fileOffset = node.fileOffset;
+      return new EqualsNull(right)..fileOffset = node.fileOffset;
     } else if (_isNull(right)) {
-      return new EqualsNull(left, isNot: node.isNot)
-        ..fileOffset = node.fileOffset;
+      return new EqualsNull(left)..fileOffset = node.fileOffset;
     }
     node.left = left..parent = node;
     node.right = right..parent = node;
@@ -1931,13 +1929,12 @@
       return unevaluated(
           node,
           new EqualsCall(extract(left), extract(right),
-              isNot: node.isNot,
               functionType: node.functionType,
               interfaceTarget: node.interfaceTarget)
             ..fileOffset = node.fileOffset);
     }
 
-    return _handleEquals(node, left, right, isNot: node.isNot);
+    return _handleEquals(node, left, right);
   }
 
   @override
@@ -1946,18 +1943,14 @@
     if (expression is AbortConstant) return expression;
 
     if (shouldBeUnevaluated) {
-      return unevaluated(
-          node,
-          new EqualsNull(extract(expression), isNot: node.isNot)
-            ..fileOffset = node.fileOffset);
+      return unevaluated(node,
+          new EqualsNull(extract(expression))..fileOffset = node.fileOffset);
     }
 
-    return _handleEquals(node, expression, nullConstant, isNot: node.isNot);
+    return _handleEquals(node, expression, nullConstant);
   }
 
-  Constant _handleEquals(Expression node, Constant left, Constant right,
-      {bool isNot}) {
-    assert(isNot != null);
+  Constant _handleEquals(Expression node, Constant left, Constant right) {
     if (left is NullConstant ||
         left is BoolConstant ||
         left is IntConstant ||
@@ -1966,17 +1959,7 @@
         right is NullConstant) {
       // [DoubleConstant] uses [identical] to determine equality, so we need
       // to take the special cases into account.
-      Constant result =
-          doubleSpecialCases(left, right) ?? makeBoolConstant(left == right);
-      if (isNot) {
-        if (result == trueConstant) {
-          result = falseConstant;
-        } else {
-          assert(result == falseConstant);
-          result = trueConstant;
-        }
-      }
-      return result;
+      return doubleSpecialCases(left, right) ?? makeBoolConstant(left == right);
     } else {
       return createErrorConstant(
           node,
@@ -1993,7 +1976,7 @@
     // parsed as `!(a == b)` it is handled implicitly through ==.
     if (arguments.length == 1 && op == '==') {
       final Constant right = arguments[0];
-      return _handleEquals(node, receiver, right, isNot: false);
+      return _handleEquals(node, receiver, right);
     }
 
     // This is a white-listed set of methods we need to support on constants.
@@ -2466,7 +2449,7 @@
         return createErrorConstant(
             node,
             templateConstEvalInvalidStaticInvocation
-                .withArguments(target.name.name));
+                .withArguments(target.name.text));
       } else {
         return createInvalidExpressionConstant(
             node, 'No support for ${target.runtimeType} in a static tear-off.');
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index be077f9..3b061ee 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -94,6 +94,90 @@
   }
 
   @override
+  ExpressionInferenceResult visitDynamicGet(
+      DynamicGet node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceGet(
+      InstanceGet node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceTearOff(
+      InstanceTearOff node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitDynamicInvocation(
+      DynamicInvocation node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitDynamicSet(
+      DynamicSet node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitEqualsCall(
+      EqualsCall node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitEqualsNull(
+      EqualsNull node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitFunctionInvocation(
+      FunctionInvocation node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceInvocation(
+      InstanceInvocation node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceGetterInvocation(
+      InstanceGetterInvocation node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceSet(
+      InstanceSet node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitLocalFunctionInvocation(
+      LocalFunctionInvocation node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitStaticTearOff(
+      StaticTearOff node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
+  ExpressionInferenceResult visitFunctionTearOff(
+      FunctionTearOff node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
   ExpressionInferenceResult visitFileUriExpression(
       FileUriExpression node, DartType typeContext) {
     return _unhandledExpression(node, typeContext);
@@ -3747,12 +3831,15 @@
 
     if (inferrer.useNewMethodInvocationEncoding) {
       if (_isNull(right)) {
-        equals = new EqualsNull(left, isNot: isNot)..fileOffset = fileOffset;
+        equals = new EqualsNull(left)..fileOffset = fileOffset;
       } else if (_isNull(left)) {
-        equals = new EqualsNull(rightResult.expression, isNot: isNot)
+        equals = new EqualsNull(rightResult.expression)
           ..fileOffset = fileOffset;
       }
       if (equals != null) {
+        if (isNot) {
+          equals = new Not(equals)..fileOffset = fileOffset;
+        }
         inferrer.flowAnalysis.equalityOp_end(
             equals, rightResult.expression, rightResult.inferredType,
             notEqual: isNot);
@@ -3798,10 +3885,11 @@
         FunctionType functionType =
             inferrer.getFunctionType(equalsTarget, leftType);
         equals = new EqualsCall(left, right,
-            isNot: isNot,
-            functionType: functionType,
-            interfaceTarget: equalsTarget.member)
+            functionType: functionType, interfaceTarget: equalsTarget.member)
           ..fileOffset = fileOffset;
+        if (isNot) {
+          equals = new Not(equals)..fileOffset = fileOffset;
+        }
       } else {
         assert(equalsTarget.isNever);
         FunctionType functionType = new FunctionType([const DynamicType()],
@@ -3812,8 +3900,11 @@
                 instrumented: false)
             .member;
         equals = new EqualsCall(left, right,
-            isNot: isNot, functionType: functionType, interfaceTarget: target)
+            functionType: functionType, interfaceTarget: target)
           ..fileOffset = fileOffset;
+        if (isNot) {
+          equals = new Not(equals)..fileOffset = fileOffset;
+        }
       }
     } else {
       equals = new MethodInvocation(
@@ -5708,7 +5799,7 @@
         node.fileOffset, receiver, receiverType, node.name, typeContext,
         isThisReceiver: node.receiver is ThisExpression);
     inferrer.flowAnalysis.propertyGet(
-        node, node.receiver, node.name.name, readResult.inferredType);
+        node, node.receiver, node.name.text, readResult.inferredType);
     ExpressionInferenceResult expressionInferenceResult =
         inferrer.createNullAwareExpressionInferenceResult(
             readResult.inferredType, readResult.expression, nullAwareGuards);
@@ -6867,97 +6958,6 @@
       }
     }
   }
-
-  @override
-  ExpressionInferenceResult visitDynamicGet(
-      DynamicGet node, DartType typeContext) {
-    // TODO: implement visitDynamicGet
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitInstanceGet(
-      InstanceGet node, DartType typeContext) {
-    // TODO: implement visitInstanceGet
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitInstanceTearOff(
-      InstanceTearOff node, DartType typeContext) {
-    // TODO: implement visitInstanceTearOff
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitDynamicInvocation(
-      DynamicInvocation node, DartType typeContext) {
-    // TODO: implement visitDynamicInvocation
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitDynamicSet(
-      DynamicSet node, DartType typeContext) {
-    // TODO: implement visitDynamicSet
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitEqualsCall(
-      EqualsCall node, DartType typeContext) {
-    // TODO: implement visitEqualsCall
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitEqualsNull(
-      EqualsNull node, DartType typeContext) {
-    // TODO: implement visitEqualsNull
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitFunctionInvocation(
-      FunctionInvocation node, DartType typeContext) {
-    // TODO: implement visitFunctionInvocation
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitInstanceInvocation(
-      InstanceInvocation node, DartType typeContext) {
-    // TODO: implement visitInstanceInvocation
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitInstanceSet(
-      InstanceSet node, DartType typeContext) {
-    // TODO: implement visitInstanceSet
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitLocalFunctionInvocation(
-      LocalFunctionInvocation node, DartType typeContext) {
-    // TODO: implement visitLocalFunctionInvocation
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitStaticTearOff(
-      StaticTearOff node, DartType typeContext) {
-    // TODO: implement visitStaticTearOff
-    throw new UnimplementedError();
-  }
-
-  @override
-  ExpressionInferenceResult visitFunctionTearOff(
-      FunctionTearOff node, DartType arg) {
-    // TODO: implement visitFunctionTearOff
-    throw new UnimplementedError();
-  }
 }
 
 class ForInResult {
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index 1f87bde..0e2ea27 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -106,8 +106,7 @@
           new ConditionalExpression(
               useNewMethodInvocationEncoding
                   ? (new EqualsNull(
-                      new VariableGet(variable)..fileOffset = fileOffset,
-                      isNot: false)
+                      new VariableGet(variable)..fileOffset = fileOffset)
                     ..fileOffset = fileOffset)
                   : new MethodInvocation(
                       new VariableGet(variable)..fileOffset = fileOffset,
@@ -261,8 +260,7 @@
           new ConditionalExpression(
               useNewMethodInvocationEncoding
                   ? (new EqualsNull(
-                      new VariableGet(variable)..fileOffset = fileOffset,
-                      isNot: false)
+                      new VariableGet(variable)..fileOffset = fileOffset)
                     ..fileOffset = fileOffset)
                   : new MethodInvocation(
                       new VariableGet(variable)..fileOffset = fileOffset,
@@ -278,8 +276,7 @@
                       useNewMethodInvocationEncoding
                           ? (new EqualsNull(
                               createVariableRead(needsPromotion: false)
-                                ..fileOffset = fileOffset,
-                              isNot: false)
+                                ..fileOffset = fileOffset)
                             ..fileOffset = fileOffset)
                           : new MethodInvocation(
                               createVariableRead(needsPromotion: false)
@@ -381,8 +378,7 @@
           new ConditionalExpression(
               useNewMethodInvocationEncoding
                   ? (new EqualsNull(
-                      new VariableGet(variable)..fileOffset = fileOffset,
-                      isNot: false)
+                      new VariableGet(variable)..fileOffset = fileOffset)
                     ..fileOffset = fileOffset)
                   : new MethodInvocation(
                       new VariableGet(variable)..fileOffset = fileOffset,
@@ -540,8 +536,7 @@
       //    }
       return new IfStatement(
         useNewMethodInvocationEncoding
-            ? (new EqualsNull(createVariableRead()..fileOffset = fileOffset,
-                isNot: false)
+            ? (new EqualsNull(createVariableRead()..fileOffset = fileOffset)
               ..fileOffset = fileOffset)
             : new MethodInvocation(
                 createVariableRead()..fileOffset = fileOffset,
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
index 0866c33..ac5f466 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -946,22 +946,22 @@
   Expression _createEqualsNull(Expression expression, {bool notEquals: false}) {
     assert(expression != null);
     assert(expression.fileOffset != TreeNode.noOffset);
+    Expression check;
     if (useNewMethodInvocationEncoding) {
-      return new EqualsNull(expression, isNot: notEquals)
-        ..fileOffset = expression.fileOffset;
+      check = new EqualsNull(expression)..fileOffset = expression.fileOffset;
     } else {
-      Expression check = new MethodInvocation(
+      check = new MethodInvocation(
           expression,
           new Name('=='),
           new Arguments(
               [new NullLiteral()..fileOffset = expression.fileOffset]),
           _objectEquals)
         ..fileOffset = expression.fileOffset;
-      if (notEquals) {
-        check = new Not(check)..fileOffset = expression.fileOffset;
-      }
-      return check;
     }
+    if (notEquals) {
+      check = new Not(check)..fileOffset = expression.fileOffset;
+    }
+    return check;
   }
 
   Expression _createIndexSet(int fileOffset, Expression receiver,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index d70f4c1..d01bde9 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -738,8 +738,7 @@
     Expression nullCheck;
     // TODO(johnniwinther): Avoid null-check for non-nullable expressions.
     if (useNewMethodInvocationEncoding) {
-      nullCheck = new EqualsNull(new VariableGet(t)..fileOffset = fileOffset,
-          isNot: false)
+      nullCheck = new EqualsNull(new VariableGet(t)..fileOffset = fileOffset)
         ..fileOffset = fileOffset;
     } else {
       nullCheck = new MethodInvocation(
@@ -2910,7 +2909,8 @@
           ..fileOffset = fileOffset;
       } else if (receiver is VariableGet) {
         VariableDeclaration variable = receiver.variable;
-        if (variable.parent is FunctionDeclaration) {
+        TreeNode parent = variable.parent;
+        if (parent is FunctionDeclaration) {
           assert(inferredFunctionType != unknownFunction,
               "Unknown function type for local function invocation.");
           expression = new LocalFunctionInvocation(variable, arguments,
@@ -3403,7 +3403,7 @@
           resultType: calleeType, interfaceTarget: originalTarget)
         ..fileOffset = fileOffset;
       flowAnalysis.propertyGet(
-          originalPropertyGet, originalReceiver, originalName.name, calleeType);
+          originalPropertyGet, originalReceiver, originalName.text, calleeType);
     } else {
       originalPropertyGet =
           new PropertyGet(originalReceiver, originalName, originalTarget)
@@ -4246,7 +4246,7 @@
   Expression createEqualsNull(
       int fileOffset, Expression left, Member equalsMember) {
     if (useNewMethodInvocationEncoding) {
-      return new EqualsNull(left, isNot: false)..fileOffset = fileOffset;
+      return new EqualsNull(left)..fileOffset = fileOffset;
     } else {
       return new MethodInvocation(
           left,
diff --git a/pkg/front_end/lib/src/testing/id_extractor.dart b/pkg/front_end/lib/src/testing/id_extractor.dart
index ebee200..e07b415 100644
--- a/pkg/front_end/lib/src/testing/id_extractor.dart
+++ b/pkg/front_end/lib/src/testing/id_extractor.dart
@@ -200,9 +200,9 @@
   }
 
   _visitInvocation(Expression node, Name name) {
-    if (name.name == '[]') {
+    if (name.text == '[]') {
       computeForNode(node, computeDefaultNodeId(node));
-    } else if (name.name == '[]=') {
+    } else if (name.text == '[]=') {
       computeForNode(node, createUpdateId(node));
     } else {
       if (node.fileOffset != TreeNode.noOffset) {
@@ -221,7 +221,7 @@
       // This is an invocation of a named local function.
       computeForNode(node, createInvokeId(node.receiver));
       node.arguments.accept(this);
-    } else if (node.name.name == '==' &&
+    } else if (node.name.text == '==' &&
         receiver is VariableGet &&
         receiver.variable.name == null) {
       // This is a desugared `?.`.
@@ -273,6 +273,12 @@
   }
 
   @override
+  visitInstanceGetterInvocation(InstanceGetterInvocation node) {
+    _visitInvocation(node, node.name);
+    super.visitInstanceGetterInvocation(node);
+  }
+
+  @override
   visitLoadLibrary(LoadLibrary node) {
     computeForNode(node, createInvokeId(node));
   }
diff --git a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect
index b452cdb..ce47bb9 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect
@@ -171,7 +171,7 @@
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   self::enableRead = true;
-  if(expected !={core::Object::==}{(core::Object*) →* core::bool*} actual)
+  if(!(expected =={core::Object::==}{(core::Object*) →* core::bool*} actual))
     throw "Expected ${expected}, ${actual}";
 }
 
diff --git a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect
index 7462ff3..25ceba5 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect
@@ -171,7 +171,7 @@
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   self::enableRead = true;
-  if(expected !={core::Object::==}{(core::Object*) →* core::bool*} actual)
+  if(!(expected =={core::Object::==}{(core::Object*) →* core::bool*} actual))
     throw "Expected ${expected}, ${actual}";
 }
 
@@ -204,4 +204,4 @@
 Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:160:10 -> IntConstant(-23)
 Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:161:10 -> IntConstant(-11)
 Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:162:10 -> IntConstant(-11)
-Extra constant evaluation: evaluated: 321, effectively constant: 17
+Extra constant evaluation: evaluated: 322, effectively constant: 17
diff --git a/pkg/front_end/testcases/none/equals.dart.strong.expect b/pkg/front_end/testcases/none/equals.dart.strong.expect
index 905a90a..3c8e61d 100644
--- a/pkg/front_end/testcases/none/equals.dart.strong.expect
+++ b/pkg/front_end/testcases/none/equals.dart.strong.expect
@@ -129,347 +129,347 @@
 static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int>(core::Object o, core::Object nonNullableObject, core::Object? nullableObject, self::Class<core::String> nonNullableClass, self::Class<core::String>? nullableClass, dynamic dyn, Never never, Never? nullableNever, Null nullTypedValue, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic {
   core::print("EqualsNull (literal null)");
   null == null;
-  null != null;
+  !(null == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nullableClass == null;
-  nullableClass != null;
+  !(nullableClass == null);
   nullableClass == null;
-  nullableClass != null;
+  !(nullableClass == null);
   nonNullableClass == null;
-  nonNullableClass != null;
+  !(nonNullableClass == null);
   nonNullableClass == null;
-  nonNullableClass != null;
+  !(nonNullableClass == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   never == null;
-  never != null;
+  !(never == null);
   never == null;
-  never != null;
+  !(never == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   (let final Never #t1 = invalid-expression "pkg/front_end/testcases/none/equals.dart:115:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == null;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t2 = invalid-expression "pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t2 = invalid-expression "pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != null;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   (let final Never #t3 = invalid-expression "pkg/front_end/testcases/none/equals.dart:117:34: Error: Too few positional arguments: 1 required, 0 given.
   null == nonNullableClass.method();
                                  ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t4 = invalid-expression "pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t4 = invalid-expression "pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
   null != nonNullableClass.method();
-                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   core::print("EqualsNull (constant null)");
   (#C1) == null;
-  (#C1) != null;
+  !((#C1) == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t5 = invalid-expression "pkg/front_end/testcases/none/equals.dart:134:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass == nullValue;
                       ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t6 = invalid-expression "pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+  !(nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t6 = invalid-expression "pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass != nullValue;
-                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   nonNullableClass == null;
-  nonNullableClass != null;
+  !(nonNullableClass == null);
   nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t7 = invalid-expression "pkg/front_end/testcases/none/equals.dart:139:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass == nullValue;
                    ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t8 = invalid-expression "pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+  !(nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t8 = invalid-expression "pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass != nullValue;
-                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   nullableClass == null;
-  nullableClass != null;
+  !(nullableClass == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   never == null;
-  never != null;
+  !(never == null);
   never == null;
-  never != null;
+  !(never == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   (let final Never #t9 = invalid-expression "pkg/front_end/testcases/none/equals.dart:204:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == nullValue;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t10 = invalid-expression "pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t10 = invalid-expression "pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != nullValue;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   (let final Never #t11 = invalid-expression "pkg/front_end/testcases/none/equals.dart:206:39: Error: Too few positional arguments: 1 required, 0 given.
   nullValue == nonNullableClass.method();
                                       ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t12 = invalid-expression "pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t12 = invalid-expression "pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
   nullValue != nonNullableClass.method();
-                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   core::print("EqualsCall");
   nonNullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableObject);
   nonNullableObject =={core::Object::==}{(core::Object) → core::bool} o;
-  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nonNullableObject =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableObject);
   nullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableObject;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableObject);
   nullableObject =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableObject =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableObject;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableObject);
   nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
-  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  !(nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableClass);
   nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t13 = invalid-expression "pkg/front_end/testcases/none/equals.dart:233:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass == o;
                       ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t14 = invalid-expression "pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+  !(nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t14 = invalid-expression "pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass != o;
-                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableClass);
   nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
-  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  !(nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableClass;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableClass);
   nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t15 = invalid-expression "pkg/front_end/testcases/none/equals.dart:242:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass == o;
                    ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t16 = invalid-expression "pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+  !(nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t16 = invalid-expression "pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass != o;
-                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   o =={core::Object::==}{(core::Object) → core::bool} nullableClass;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableClass);
   dyn =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  dyn !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(dyn =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} dyn;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} dyn;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} dyn);
   dyn =={core::Object::==}{(core::Object) → core::bool} o;
-  dyn !={core::Object::==}{(core::Object) → core::bool} o;
+  !(dyn =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} dyn;
-  o !={core::Object::==}{(core::Object) → core::bool} dyn;
+  !(o =={core::Object::==}{(core::Object) → core::bool} dyn);
   never =={core::Object::==}{(dynamic) → Never} nullTypedValue;
-  never !={core::Object::==}{(dynamic) → Never} nullTypedValue;
+  !(never =={core::Object::==}{(dynamic) → Never} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} never;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} never;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} never);
   never =={core::Object::==}{(dynamic) → Never} o;
-  never !={core::Object::==}{(dynamic) → Never} o;
+  !(never =={core::Object::==}{(dynamic) → Never} o);
   o =={core::Object::==}{(core::Object) → core::bool} never;
-  o !={core::Object::==}{(core::Object) → core::bool} never;
+  !(o =={core::Object::==}{(core::Object) → core::bool} never);
   nullableNever =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableNever !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableNever =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableNever;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableNever);
   nullableNever =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableNever !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableNever =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableNever;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableNever);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} o;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  o !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction);
   nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
-  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction);
   nullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunction);
   nullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
-  nullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nullableFunction =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableFunction);
   nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType);
   nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
-  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType);
   nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType);
   nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType);
   nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1);
   nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
-  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1);
   nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1);
   nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
-  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1);
   nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2);
   nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
-  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2);
   nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2);
   nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2);
   (let final Never #t17 = invalid-expression "pkg/front_end/testcases/none/equals.dart:355:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == nullTypedValue;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  (let final Never #t18 = invalid-expression "pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t18 = invalid-expression "pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != nullTypedValue;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t19 = invalid-expression "pkg/front_end/testcases/none/equals.dart:357:44: Error: Too few positional arguments: 1 required, 0 given.
   nullTypedValue == nonNullableClass.method();
                                            ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} (let final Never #t20 = invalid-expression "pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t20 = invalid-expression "pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
   nullTypedValue != nonNullableClass.method();
-                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}));
   (let final Never #t21 = invalid-expression "pkg/front_end/testcases/none/equals.dart:359:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == o;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} o;
-  (let final Never #t22 = invalid-expression "pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t22 = invalid-expression "pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != o;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} o;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t23 = invalid-expression "pkg/front_end/testcases/none/equals.dart:361:31: Error: Too few positional arguments: 1 required, 0 given.
   o == nonNullableClass.method();
                               ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
-  o !={core::Object::==}{(core::Object) → core::bool} (let final Never #t24 = invalid-expression "pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
+  !(o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t24 = invalid-expression "pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
   o != nonNullableClass.method();
-                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}));
 }
 static method nullEqualsIndexGet(core::Map<core::int, core::String> map) → dynamic {
   map.{core::Map::[]}(0){(core::Object?) → core::String?} == null;
diff --git a/pkg/front_end/testcases/none/equals.dart.weak.expect b/pkg/front_end/testcases/none/equals.dart.weak.expect
index 538a152..622fa6c8 100644
--- a/pkg/front_end/testcases/none/equals.dart.weak.expect
+++ b/pkg/front_end/testcases/none/equals.dart.weak.expect
@@ -130,347 +130,347 @@
 static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int>(core::Object o, core::Object nonNullableObject, core::Object? nullableObject, self::Class<core::String> nonNullableClass, self::Class<core::String>? nullableClass, dynamic dyn, Never never, Never? nullableNever, Null nullTypedValue, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic {
   core::print("EqualsNull (literal null)");
   null == null;
-  null != null;
+  !(null == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nullableClass == null;
-  nullableClass != null;
+  !(nullableClass == null);
   nullableClass == null;
-  nullableClass != null;
+  !(nullableClass == null);
   nonNullableClass == null;
-  nonNullableClass != null;
+  !(nonNullableClass == null);
   nonNullableClass == null;
-  nonNullableClass != null;
+  !(nonNullableClass == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   (let final Never #t1 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null;
-  (let final Never #t2 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null;
+  !((let final Never #t2 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null);
   (let final Never #t3 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null;
-  (let final Never #t4 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null;
+  !((let final Never #t4 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   (let final Never #t5 = invalid-expression "pkg/front_end/testcases/none/equals.dart:115:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == null;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t6 = invalid-expression "pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t6 = invalid-expression "pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != null;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   (let final Never #t7 = invalid-expression "pkg/front_end/testcases/none/equals.dart:117:34: Error: Too few positional arguments: 1 required, 0 given.
   null == nonNullableClass.method();
                                  ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t8 = invalid-expression "pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t8 = invalid-expression "pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
   null != nonNullableClass.method();
-                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   core::print("EqualsNull (constant null)");
   (#C1) == null;
-  (#C1) != null;
+  !((#C1) == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nonNullableObject == null;
-  nonNullableObject != null;
+  !(nonNullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nullableObject == null;
-  nullableObject != null;
+  !(nullableObject == null);
   nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t9 = invalid-expression "pkg/front_end/testcases/none/equals.dart:134:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass == nullValue;
                       ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t10 = invalid-expression "pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+  !(nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t10 = invalid-expression "pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass != nullValue;
-                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   nonNullableClass == null;
-  nonNullableClass != null;
+  !(nonNullableClass == null);
   nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t11 = invalid-expression "pkg/front_end/testcases/none/equals.dart:139:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass == nullValue;
                    ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t12 = invalid-expression "pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+  !(nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t12 = invalid-expression "pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass != nullValue;
-                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   nullableClass == null;
-  nullableClass != null;
+  !(nullableClass == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   dyn == null;
-  dyn != null;
+  !(dyn == null);
   let final Never #t13 = (let final Never #t14 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
-  let final Never #t15 = (let final Never #t16 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t15 = !((let final Never #t16 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
   (let final Never #t17 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null;
-  (let final Never #t18 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null;
+  !((let final Never #t18 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullableNever == null;
-  nullableNever != null;
+  !(nullableNever == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nullTypedValue == null;
-  nullTypedValue != null;
+  !(nullTypedValue == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nonNullableFunction == null;
-  nonNullableFunction != null;
+  !(nonNullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nullableFunction == null;
-  nullableFunction != null;
+  !(nullableFunction == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nonNullableFunctionType == null;
-  nonNullableFunctionType != null;
+  !(nonNullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nullableFunctionType == null;
-  nullableFunctionType != null;
+  !(nullableFunctionType == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nonNullableTypeVariable1 == null;
-  nonNullableTypeVariable1 != null;
+  !(nonNullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nullableTypeVariable1 == null;
-  nullableTypeVariable1 != null;
+  !(nullableTypeVariable1 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nonNullableTypeVariable2 == null;
-  nonNullableTypeVariable2 != null;
+  !(nonNullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   nullableTypeVariable2 == null;
-  nullableTypeVariable2 != null;
+  !(nullableTypeVariable2 == null);
   (let final Never #t19 = invalid-expression "pkg/front_end/testcases/none/equals.dart:204:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == nullValue;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t20 = invalid-expression "pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t20 = invalid-expression "pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != nullValue;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   (let final Never #t21 = invalid-expression "pkg/front_end/testcases/none/equals.dart:206:39: Error: Too few positional arguments: 1 required, 0 given.
   nullValue == nonNullableClass.method();
                                       ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
-  (let final Never #t22 = invalid-expression "pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t22 = invalid-expression "pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
   nullValue != nonNullableClass.method();
-                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null);
   core::print("EqualsCall");
   nonNullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableObject);
   nonNullableObject =={core::Object::==}{(core::Object) → core::bool} o;
-  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nonNullableObject =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableObject);
   nullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableObject;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableObject);
   nullableObject =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableObject =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableObject;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableObject);
   nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
-  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  !(nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableClass);
   nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t23 = invalid-expression "pkg/front_end/testcases/none/equals.dart:233:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass == o;
                       ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t24 = invalid-expression "pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+  !(nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t24 = invalid-expression "pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nonNullableClass != o;
-                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableClass);
   nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
-  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  !(nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableClass;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableClass);
   nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t25 = invalid-expression "pkg/front_end/testcases/none/equals.dart:242:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass == o;
                    ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
-  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t26 = invalid-expression "pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+  !(nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final Never #t26 = invalid-expression "pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
  - 'Object' is from 'dart:core'.
  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
   nullableClass != o;
-                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?));
   o =={core::Object::==}{(core::Object) → core::bool} nullableClass;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableClass);
   dyn =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  dyn !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(dyn =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} dyn;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} dyn;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} dyn);
   dyn =={core::Object::==}{(core::Object) → core::bool} o;
-  dyn !={core::Object::==}{(core::Object) → core::bool} o;
+  !(dyn =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} dyn;
-  o !={core::Object::==}{(core::Object) → core::bool} dyn;
+  !(o =={core::Object::==}{(core::Object) → core::bool} dyn);
   let final Never #t27 = (let final Never #t28 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) =={core::Object::==}{(dynamic) → Never} nullTypedValue in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
-  let final Never #t29 = (let final Never #t30 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) !={core::Object::==}{(dynamic) → Never} nullTypedValue in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t29 = !((let final Never #t30 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) =={core::Object::==}{(dynamic) → Never} nullTypedValue) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t31 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} (let final Never #t32 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t32 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")));
   let final Never #t33 = (let final Never #t34 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) =={core::Object::==}{(dynamic) → Never} o in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
-  let final Never #t35 = (let final Never #t36 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) !={core::Object::==}{(dynamic) → Never} o in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t35 = !((let final Never #t36 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) =={core::Object::==}{(dynamic) → Never} o) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
   o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t37 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
-  o !={core::Object::==}{(core::Object) → core::bool} (let final Never #t38 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
+  !(o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t38 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")));
   nullableNever =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableNever !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableNever =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableNever;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableNever);
   nullableNever =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableNever !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableNever =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableNever;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableNever);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} o;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  o !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction);
   nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
-  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction);
   nullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunction);
   nullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
-  nullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nullableFunction =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableFunction);
   nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType);
   nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
-  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType);
   nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType);
   nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType);
   nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1);
   nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
-  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1);
   nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1);
   nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
-  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  !(nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1);
   nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2);
   nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
-  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
-  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2);
   nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  !(nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2);
   nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
-  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  !(nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
-  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  !(o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2);
   (let final Never #t39 = invalid-expression "pkg/front_end/testcases/none/equals.dart:355:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == nullTypedValue;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
-  (let final Never #t40 = invalid-expression "pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t40 = invalid-expression "pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != nullTypedValue;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} nullTypedValue);
   nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t41 = invalid-expression "pkg/front_end/testcases/none/equals.dart:357:44: Error: Too few positional arguments: 1 required, 0 given.
   nullTypedValue == nonNullableClass.method();
                                            ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
-  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} (let final Never #t42 = invalid-expression "pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
+  !(nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t42 = invalid-expression "pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
   nullTypedValue != nonNullableClass.method();
-                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}));
   (let final Never #t43 = invalid-expression "pkg/front_end/testcases/none/equals.dart:359:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() == o;
                          ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} o;
-  (let final Never #t44 = invalid-expression "pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
+  !((let final Never #t44 = invalid-expression "pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
   nonNullableClass.method() != o;
-                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} o;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} o);
   o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t45 = invalid-expression "pkg/front_end/testcases/none/equals.dart:361:31: Error: Too few positional arguments: 1 required, 0 given.
   o == nonNullableClass.method();
                               ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
-  o !={core::Object::==}{(core::Object) → core::bool} (let final Never #t46 = invalid-expression "pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
+  !(o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t46 = invalid-expression "pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
   o != nonNullableClass.method();
-                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}));
 }
 static method nullEqualsIndexGet(core::Map<core::int, core::String> map) → dynamic {
   map.{core::Map::[]}(0){(core::Object?) → core::String?} == null;
diff --git a/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect b/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect
index be28553..81796a7 100644
--- a/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect
+++ b/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect
@@ -65,7 +65,7 @@
   self::expect("Mixin", m.{self::Mixin::method4}(0, 1){(core::int, core::int) → core::String});
 }
 static method expect(dynamic expected, dynamic actual) → void {
-  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 static method throws(() → void f) → void {
diff --git a/pkg/front_end/testcases/none/mixin_covariant.dart.strong.transformed.expect b/pkg/front_end/testcases/none/mixin_covariant.dart.strong.transformed.expect
index be28553..81796a7 100644
--- a/pkg/front_end/testcases/none/mixin_covariant.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/none/mixin_covariant.dart.strong.transformed.expect
@@ -65,7 +65,7 @@
   self::expect("Mixin", m.{self::Mixin::method4}(0, 1){(core::int, core::int) → core::String});
 }
 static method expect(dynamic expected, dynamic actual) → void {
-  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 static method throws(() → void f) → void {
diff --git a/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect b/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect
index be28553..81796a7 100644
--- a/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect
+++ b/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect
@@ -65,7 +65,7 @@
   self::expect("Mixin", m.{self::Mixin::method4}(0, 1){(core::int, core::int) → core::String});
 }
 static method expect(dynamic expected, dynamic actual) → void {
-  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 static method throws(() → void f) → void {
diff --git a/pkg/front_end/testcases/none/mixin_covariant.dart.weak.transformed.expect b/pkg/front_end/testcases/none/mixin_covariant.dart.weak.transformed.expect
index be28553..81796a7 100644
--- a/pkg/front_end/testcases/none/mixin_covariant.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/none/mixin_covariant.dart.weak.transformed.expect
@@ -65,7 +65,7 @@
   self::expect("Mixin", m.{self::Mixin::method4}(0, 1){(core::int, core::int) → core::String});
 }
 static method expect(dynamic expected, dynamic actual) → void {
-  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 static method throws(() → void f) → void {
diff --git a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.expect b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.expect
index 6bbacdb..a213a54 100644
--- a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.expect
+++ b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.expect
@@ -46,10 +46,10 @@
   function local() → Null {}
   local(){() → Null};
   c =={core::Object::==}{(core::Object) → core::bool} d;
-  c !={core::Object::==}{(core::Object) → core::bool} d;
+  !(c =={core::Object::==}{(core::Object) → core::bool} d);
   c == null;
-  c != null;
+  !(c == null);
   d == null;
-  d != null;
+  !(d == null);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.transformed.expect b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.transformed.expect
index 6bbacdb..a213a54 100644
--- a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.strong.transformed.expect
@@ -46,10 +46,10 @@
   function local() → Null {}
   local(){() → Null};
   c =={core::Object::==}{(core::Object) → core::bool} d;
-  c !={core::Object::==}{(core::Object) → core::bool} d;
+  !(c =={core::Object::==}{(core::Object) → core::bool} d);
   c == null;
-  c != null;
+  !(c == null);
   d == null;
-  d != null;
+  !(d == null);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.expect b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.expect
index 6bbacdb..a213a54 100644
--- a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.expect
+++ b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.expect
@@ -46,10 +46,10 @@
   function local() → Null {}
   local(){() → Null};
   c =={core::Object::==}{(core::Object) → core::bool} d;
-  c !={core::Object::==}{(core::Object) → core::bool} d;
+  !(c =={core::Object::==}{(core::Object) → core::bool} d);
   c == null;
-  c != null;
+  !(c == null);
   d == null;
-  d != null;
+  !(d == null);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.transformed.expect b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.transformed.expect
index 6bbacdb..a213a54 100644
--- a/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/none/new_method_invocation_encodings.dart.weak.transformed.expect
@@ -46,10 +46,10 @@
   function local() → Null {}
   local(){() → Null};
   c =={core::Object::==}{(core::Object) → core::bool} d;
-  c !={core::Object::==}{(core::Object) → core::bool} d;
+  !(c =={core::Object::==}{(core::Object) → core::bool} d);
   c == null;
-  c != null;
+  !(c == null);
   d == null;
-  d != null;
+  !(d == null);
 }
 static method main() → dynamic {}
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index d4edbf5..b19ad56 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -147,7 +147,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 56;
+  UInt32 formatVersion = 57;
   Byte[10] shortSdkHash;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
@@ -741,6 +741,19 @@
   MemberReference interfaceTargetOrigin; // May be NullReference.
 }
 
+type InstanceGetterInvocation extends Expression {
+  Byte tag = 89;
+  Byte kind; // Index into InstanceAccessKind above.
+  Byte flags (isInvariant, isBoundsSafe);
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  Arguments arguments;
+  DartType functionType;
+  MemberReference interfaceTarget;
+  MemberReference interfaceTargetOrigin; // May be NullReference.
+}
+
 type DynamicInvocation extends Expression {
   Byte tag = 124;
   Byte kind; // Index into DynamicAccessKind above.
@@ -789,7 +802,6 @@
   Byte tag = 15;
   FileOffset fileOffset;
   Expression expression;
-  Byte isNot;
 }
 
 type EqualsCall extends Expression {
@@ -797,7 +809,6 @@
   FileOffset fileOffset;
   Expression left;
   Expression right;
-  Byte isNot;
   DartType functionType;
   MemberReference interfaceTarget;
   MemberReference interfaceTargetOrigin; // May be NullReference.
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 7e38523..a52a42c 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -5329,6 +5329,169 @@
   }
 }
 
+/// An invocation of an instance getter or field with a statically known
+/// interface target.
+///
+/// This is used only for web backend in order to support invocation of
+/// native properties as functions. This node will be removed when this
+/// invocation style is no longer supported.
+class InstanceGetterInvocation extends InvocationExpression {
+  // Must match serialized bit positions.
+  static const int FlagInvariant = 1 << 0;
+  static const int FlagBoundsSafe = 1 << 1;
+
+  final InstanceAccessKind kind;
+  Expression receiver;
+
+  @override
+  Name name;
+
+  @override
+  Arguments arguments;
+
+  int flags = 0;
+
+  /// The static type of the invocation.
+  ///
+  /// This includes substituted type parameters from the static receiver type
+  /// and generic type arguments.
+  ///
+  /// For instance
+  ///
+  ///    class A<T> {
+  ///      Map<T, S> map<S>(S s) { ... }
+  ///    }
+  ///    m(A<String> a) {
+  ///      a.map(0); // The function type is `Map<String, int> Function(int)`.
+  ///    }
+  ///
+  FunctionType functionType;
+
+  Reference interfaceTargetReference;
+
+  InstanceGetterInvocation(InstanceAccessKind kind, Expression receiver,
+      Name name, Arguments arguments,
+      {required Procedure interfaceTarget, required FunctionType functionType})
+      : this.byReference(kind, receiver, name, arguments,
+            interfaceTargetReference:
+                getNonNullableMemberReferenceGetter(interfaceTarget),
+            functionType: functionType);
+
+  InstanceGetterInvocation.byReference(
+      this.kind, this.receiver, this.name, this.arguments,
+      {required this.interfaceTargetReference, required this.functionType})
+      // ignore: unnecessary_null_comparison
+      : assert(interfaceTargetReference != null),
+        // ignore: unnecessary_null_comparison
+        assert(functionType != null),
+        assert(functionType.typeParameters.isEmpty) {
+    receiver.parent = this;
+    arguments.parent = this;
+  }
+
+  Member get interfaceTarget => interfaceTargetReference.asProcedure;
+
+  void set interfaceTarget(Member target) {
+    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
+  }
+
+  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
+  ///
+  /// This is for instance the case in code patterns like this
+  ///
+  ///     List<int> list = <int>[];
+  ///     list.add(0);
+  ///
+  /// where the `list` variable is known to hold a value of the same type as
+  /// the static type. In contrast the would not be the case in code patterns
+  /// like this
+  ///
+  ///     List<num> list = <double>[];
+  ///     list.add(0); // Runtime error `int` is not a subtype of `double`.
+  ///
+  bool get isInvariant => flags & FlagInvariant != 0;
+
+  void set isInvariant(bool value) {
+    flags = value ? (flags | FlagInvariant) : (flags & ~FlagInvariant);
+  }
+
+  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
+  ///
+  /// This is for instance the case in code patterns like this
+  ///
+  ///     List list = new List.filled(2, 0);
+  ///     list[1] = 42;
+  ///
+  /// where the `list` is known to have a sufficient length for the update
+  /// in `list[1] = 42`.
+  bool get isBoundsSafe => flags & FlagBoundsSafe != 0;
+
+  void set isBoundsSafe(bool value) {
+    flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
+  }
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      functionType.returnType;
+
+  @override
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGetterInvocation(this);
+
+  @override
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstanceGetterInvocation(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    interfaceTarget.acceptReference(v);
+    name.accept(v);
+    arguments.accept(v);
+  }
+
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "InstanceGetterInvocation($kind, ${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeInterfaceMemberName(interfaceTargetReference, name);
+    printer.writeArguments(arguments);
+  }
+}
+
 /// Access kind used by [FunctionInvocation] and [FunctionTearOff].
 enum FunctionAccessKind {
   /// An access to the 'call' method on an expression of static type `Function`.
@@ -5472,7 +5635,6 @@
 /// An invocation of a local function declaration.
 class LocalFunctionInvocation extends InvocationExpression {
   /// The variable declaration for the function declaration.
-  // TODO(johnniwinther): Should this be the `FunctionDeclaration` instead?
   VariableDeclaration variable;
 
   @override
@@ -5499,6 +5661,10 @@
     arguments.parent = this;
   }
 
+  /// The declaration for the invoked local function.
+  FunctionDeclaration get localFunction =>
+      variable.parent as FunctionDeclaration;
+
   @override
   Name get name => Name.callName;
 
@@ -5548,21 +5714,14 @@
   }
 }
 
-/// Nullness test of an expression, that is `e == null` or `e != null`.
+/// Nullness test of an expression, that is `e == null`.
 ///
-/// This is generated for code like `e1 == e2` and `e1 != e2` where `e1` or `e2`
-/// is `null`.
+/// This is generated for code like `e1 == e2` where `e1` or `e2` is `null`.
 class EqualsNull extends Expression {
   /// The expression tested for nullness.
   Expression expression;
 
-  /// If `true` this is an `e != null` test. Otherwise it is an `e == null`
-  /// test.
-  final bool isNot;
-
-  EqualsNull(this.expression, {required this.isNot})
-      // ignore: unnecessary_null_comparison
-      : assert(isNot != null) {
+  EqualsNull(this.expression) {
     expression.parent = this;
   }
 
@@ -5608,18 +5767,14 @@
   @override
   void toTextInternal(AstPrinter printer) {
     printer.writeExpression(expression, minimumPrecedence: precedence);
-    if (isNot) {
-      printer.write(' != null');
-    } else {
-      printer.write(' == null');
-    }
+    printer.write(' == null');
   }
 }
 
-/// A test of equality, that is `e1 == e2` or `e1 != e2`.
+/// A test of equality, that is `e1 == e2`.
 ///
-/// This is generated for code like `e1 == e2` and `e1 != e2` where neither `e1`
-/// nor `e2` is `null`.
+/// This is generated for code like `e1 == e2` where neither `e1` nor `e2` is
+/// `null`.
 class EqualsCall extends Expression {
   Expression left;
   Expression right;
@@ -5639,27 +5794,17 @@
   ///
   FunctionType functionType;
 
-  /// If `true` this is an `e1 != e2` test. Otherwise it is an `e1 == e2` test.
-  final bool isNot;
-
   Reference interfaceTargetReference;
 
   EqualsCall(Expression left, Expression right,
-      {required bool isNot,
-      required FunctionType functionType,
-      required Procedure interfaceTarget})
+      {required FunctionType functionType, required Procedure interfaceTarget})
       : this.byReference(left, right,
-            isNot: isNot,
             functionType: functionType,
             interfaceTargetReference:
                 getNonNullableMemberReferenceGetter(interfaceTarget));
 
   EqualsCall.byReference(this.left, this.right,
-      {required this.isNot,
-      required this.functionType,
-      required this.interfaceTargetReference})
-      // ignore: unnecessary_null_comparison
-      : assert(isNot != null) {
+      {required this.functionType, required this.interfaceTargetReference}) {
     left.parent = this;
     right.parent = this;
   }
@@ -5726,11 +5871,7 @@
   void toTextInternal(AstPrinter printer) {
     int minimumPrecedence = precedence;
     printer.writeExpression(left, minimumPrecedence: minimumPrecedence);
-    if (isNot) {
-      printer.write(' != ');
-    } else {
-      printer.write(' == ');
-    }
+    printer.write(' == ');
     printer.writeExpression(right, minimumPrecedence: minimumPrecedence + 1);
   }
 }
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 7da0618..5f9a62f 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1936,6 +1936,8 @@
         return _readMethodInvocation();
       case Tag.InstanceInvocation:
         return _readInstanceInvocation();
+      case Tag.InstanceGetterInvocation:
+        return _readInstanceGetterInvocation();
       case Tag.DynamicInvocation:
         return _readDynamicInvocation();
       case Tag.FunctionInvocation:
@@ -2193,6 +2195,18 @@
       ..flags = flags;
   }
 
+  Expression _readInstanceGetterInvocation() {
+    InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
+    int flags = readByte();
+    int offset = readOffset();
+    return new InstanceGetterInvocation.byReference(
+        kind, readExpression(), readName(), readArguments(),
+        functionType: readDartType() as FunctionType,
+        interfaceTargetReference: readNonNullInstanceMemberReference())
+      ..fileOffset = offset
+      ..flags = flags;
+  }
+
   Expression _readDynamicInvocation() {
     DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
     int offset = readOffset();
@@ -2223,21 +2237,20 @@
   Expression _readLocalFunctionInvocation() {
     int offset = readOffset();
     readUInt30(); // offset of the variable declaration in the binary.
-    return new LocalFunctionInvocation(readVariableReference(), readArguments(),
+    VariableDeclaration variable = readVariableReference();
+    return new LocalFunctionInvocation(variable, readArguments(),
         functionType: readDartType() as FunctionType)
       ..fileOffset = offset;
   }
 
   Expression _readEqualsNull() {
     int offset = readOffset();
-    return new EqualsNull(readExpression(), isNot: readByte() == 1)
-      ..fileOffset = offset;
+    return new EqualsNull(readExpression())..fileOffset = offset;
   }
 
   Expression _readEqualsCall() {
     int offset = readOffset();
     return new EqualsCall.byReference(readExpression(), readExpression(),
-        isNot: readByte() == 1,
         functionType: readDartType() as FunctionType,
         interfaceTargetReference: readNonNullInstanceMemberReference())
       ..fileOffset = offset;
@@ -2768,8 +2781,8 @@
     int offset = readOffset();
     VariableDeclaration variable = readVariableDeclaration();
     variableStack.add(variable); // Will be popped by the enclosing scope.
-    FunctionNode function = readFunctionNode();
-    return new FunctionDeclaration(variable, function)..fileOffset = offset;
+    return new FunctionDeclaration(variable, readFunctionNode())
+      ..fileOffset = offset;
   }
 
   void _readSwitchCaseInto(SwitchCase caseNode) {
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index f9409b0..2c431e2 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1557,7 +1557,6 @@
     writeOffset(node.fileOffset);
     writeNode(node.left);
     writeNode(node.right);
-    writeByte(node.isNot ? 1 : 0);
     writeDartType(node.functionType);
     writeNonNullInstanceMemberReference(node.interfaceTargetReference);
   }
@@ -1567,7 +1566,6 @@
     writeByte(Tag.EqualsNull);
     writeOffset(node.fileOffset);
     writeNode(node.expression);
-    writeByte(node.isNot ? 1 : 0);
   }
 
   @override
@@ -1595,6 +1593,19 @@
   }
 
   @override
+  void visitInstanceGetterInvocation(InstanceGetterInvocation node) {
+    writeByte(Tag.InstanceGetterInvocation);
+    writeByte(node.kind.index);
+    writeByte(node.flags);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeArgumentsNode(node.arguments);
+    writeDartType(node.functionType);
+    writeNonNullInstanceMemberReference(node.interfaceTargetReference);
+  }
+
+  @override
   void visitLocalFunctionInvocation(LocalFunctionInvocation node) {
     writeByte(Tag.LocalFunctionInvocation);
     writeOffset(node.fileOffset);
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index c91a5e6..3b8d1ee 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -90,6 +90,7 @@
   static const int InstanceGet = 118;
   static const int InstanceSet = 119;
   static const int InstanceInvocation = 120;
+  static const int InstanceGetterInvocation = 89;
   static const int InstanceTearOff = 121;
   static const int DynamicGet = 122;
   static const int DynamicSet = 123;
@@ -124,6 +125,7 @@
 
   // Types
   static const int TypedefType = 87;
+  // 89 is occupied by [InstanceGetterInvocation] (expression).
   static const int InvalidType = 90;
   static const int DynamicType = 91;
   static const int VoidType = 92;
@@ -172,7 +174,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 56;
+  static const int BinaryFormatVersion = 57;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 69d6fd7..a04b607 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -466,7 +466,13 @@
 
   visitFunctionDeclaration(FunctionDeclaration node) {
     VariableDeclaration newVariable = clone(node.variable);
-    return new FunctionDeclaration(newVariable, clone(node.function!));
+    // Create the declaration before cloning the body to support recursive
+    // [LocalFunctionInvocation] nodes.
+    FunctionDeclaration declaration =
+        new FunctionDeclaration(newVariable, null);
+    FunctionNode functionNode = clone(node.function!);
+    declaration.function = functionNode..parent = declaration;
+    return declaration;
   }
 
   void prepareTypeParameters(List<TypeParameter> typeParameters) {
@@ -637,14 +643,13 @@
   @override
   TreeNode visitEqualsCall(EqualsCall node) {
     return new EqualsCall.byReference(clone(node.left), clone(node.right),
-        isNot: node.isNot,
         functionType: visitType(node.functionType) as FunctionType,
         interfaceTargetReference: node.interfaceTargetReference);
   }
 
   @override
   TreeNode visitEqualsNull(EqualsNull node) {
-    return new EqualsNull(clone(node.expression), isNot: node.isNot);
+    return new EqualsNull(clone(node.expression));
   }
 
   @override
@@ -671,6 +676,14 @@
   }
 
   @override
+  TreeNode visitInstanceGetterInvocation(InstanceGetterInvocation node) {
+    return new InstanceGetterInvocation.byReference(
+        node.kind, clone(node.receiver), node.name, clone(node.arguments),
+        functionType: visitType(node.functionType) as FunctionType,
+        interfaceTargetReference: node.interfaceTargetReference);
+  }
+
+  @override
   TreeNode visitInstanceSet(InstanceSet node) {
     return new InstanceSet.byReference(
         node.kind, clone(node.receiver), node.name, clone(node.value),
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index f8ffce6..26f4eec 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1501,11 +1501,7 @@
     int precedence = Precedence.EQUALITY;
     writeExpression(node.left, precedence);
     writeSpace();
-    if (node.isNot) {
-      writeSymbol('!=');
-    } else {
-      writeSymbol('==');
-    }
+    writeSymbol('==');
     writeInterfaceTarget(Name.equalsName, node.interfaceTargetReference);
     writeSymbol('{');
     writeType(node.functionType);
@@ -1517,11 +1513,7 @@
   visitEqualsNull(EqualsNull node) {
     writeExpression(node.expression, Precedence.EQUALITY);
     writeSpace();
-    if (node.isNot) {
-      writeSymbol('!=');
-    } else {
-      writeSymbol('==');
-    }
+    writeSymbol('==');
     writeSpace();
     writeSymbol('null');
   }
@@ -2739,6 +2731,9 @@
   int visitInstanceInvocation(InstanceInvocation node) => CALLEE;
 
   @override
+  int visitInstanceGetterInvocation(InstanceGetterInvocation node) => CALLEE;
+
+  @override
   int visitDynamicInvocation(DynamicInvocation node) => CALLEE;
 
   @override
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 7e0ad34..b1e4b75 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -747,43 +747,38 @@
 }
 
 TextSerializer<EqualsNull> equalsNullSerializer =
-    new Wrapped<Tuple2<Expression, bool>, EqualsNull>(
-        unwrapEqualsNull,
-        wrapEqualsNull,
-        new Tuple2Serializer(expressionSerializer, const DartBool()));
+    new Wrapped<Expression, EqualsNull>(
+        unwrapEqualsNull, wrapEqualsNull, expressionSerializer);
 
-Tuple2<Expression, bool> unwrapEqualsNull(EqualsNull expression) {
-  return new Tuple2(expression.expression, expression.isNot);
+Expression unwrapEqualsNull(EqualsNull expression) {
+  return expression.expression;
 }
 
-EqualsNull wrapEqualsNull(Tuple2<Expression, bool> tuple) {
-  return new EqualsNull(tuple.first, isNot: tuple.second);
+EqualsNull wrapEqualsNull(Expression expression) {
+  return new EqualsNull(expression);
 }
 
 TextSerializer<EqualsCall> equalsCallSerializer = new Wrapped<
-        Tuple5<Expression, Expression, bool, CanonicalName, DartType>,
-        EqualsCall>(
+        Tuple4<Expression, Expression, CanonicalName, DartType>, EqualsCall>(
     unwrapEqualsCall,
     wrapEqualsCall,
-    new Tuple5Serializer(expressionSerializer, expressionSerializer,
-        const DartBool(), const CanonicalNameSerializer(), dartTypeSerializer));
+    new Tuple4Serializer(expressionSerializer, expressionSerializer,
+        const CanonicalNameSerializer(), dartTypeSerializer));
 
-Tuple5<Expression, Expression, bool, CanonicalName, DartType> unwrapEqualsCall(
+Tuple4<Expression, Expression, CanonicalName, DartType> unwrapEqualsCall(
     EqualsCall expression) {
-  return new Tuple5(
+  return new Tuple4(
       expression.left,
       expression.right,
-      expression.isNot,
       expression.interfaceTargetReference.canonicalName,
       expression.functionType);
 }
 
 EqualsCall wrapEqualsCall(
-    Tuple5<Expression, Expression, bool, CanonicalName, DartType> tuple) {
+    Tuple4<Expression, Expression, CanonicalName, DartType> tuple) {
   return new EqualsCall.byReference(tuple.first, tuple.second,
-      isNot: tuple.third,
-      interfaceTargetReference: tuple.fourth.getReference(),
-      functionType: tuple.fifth);
+      interfaceTargetReference: tuple.third.getReference(),
+      functionType: tuple.fourth);
 }
 
 TextSerializer<SuperMethodInvocation> superMethodInvocationSerializer =
diff --git a/pkg/kernel/lib/transformations/value_class.dart b/pkg/kernel/lib/transformations/value_class.dart
index 0264e0a..5a5f424 100644
--- a/pkg/kernel/lib/transformations/value_class.dart
+++ b/pkg/kernel/lib/transformations/value_class.dart
@@ -52,7 +52,7 @@
   // V v;
   // (v as dynamic).copyWith() as V
   bool predicate(MethodInvocation node) {
-    return node.name.name == "copyWith" &&
+    return node.name.text == "copyWith" &&
         _isValueClassAsConstruct(node.receiver);
   }
 
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index a42bdc8..d078850 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -1156,6 +1156,19 @@
   }
 
   @override
+  DartType visitInstanceGetterInvocation(InstanceGetterInvocation node) {
+    // TODO(johnniwinther): Use embedded static type.
+    Member target = node.interfaceTarget;
+    assert(
+        !(target is Procedure &&
+            environment.isSpecialCasedBinaryOperator(target)),
+        "Unexpected instance getter invocation target: $target");
+    visitExpression(node.receiver);
+    return handleCall(node.arguments, target.getterType,
+        receiver: getReceiverType(node, node.receiver, node.interfaceTarget));
+  }
+
+  @override
   DartType visitInstanceSet(InstanceSet node) {
     DartType value = visitExpression(node.value);
     Substitution receiver =
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index ae54219..f4afa00 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -35,6 +35,8 @@
   R visitDynamicInvocation(DynamicInvocation node) => defaultExpression(node);
   R visitFunctionInvocation(FunctionInvocation node) => defaultExpression(node);
   R visitInstanceInvocation(InstanceInvocation node) => defaultExpression(node);
+  R visitInstanceGetterInvocation(InstanceGetterInvocation node) =>
+      defaultExpression(node);
   R visitEqualsNull(EqualsNull node) => defaultExpression(node);
   R visitEqualsCall(EqualsCall node) => defaultExpression(node);
   R visitMethodInvocation(MethodInvocation node) => defaultExpression(node);
@@ -207,6 +209,8 @@
   R visitDynamicInvocation(DynamicInvocation node) => defaultExpression(node);
   R visitFunctionInvocation(FunctionInvocation node) => defaultExpression(node);
   R visitInstanceInvocation(InstanceInvocation node) => defaultExpression(node);
+  R visitInstanceGetterInvocation(InstanceGetterInvocation node) =>
+      defaultExpression(node);
   R visitEqualsNull(EqualsNull node) => defaultExpression(node);
   R visitEqualsCall(EqualsCall node) => defaultExpression(node);
   R visitMethodInvocation(MethodInvocation node) => defaultExpression(node);
@@ -363,6 +367,8 @@
       defaultExpression(node, arg);
   R visitInstanceInvocation(InstanceInvocation node, A arg) =>
       defaultExpression(node, arg);
+  R visitInstanceGetterInvocation(InstanceGetterInvocation node, A arg) =>
+      defaultExpression(node, arg);
   R visitEqualsNull(EqualsNull node, A arg) => defaultExpression(node, arg);
   R visitEqualsCall(EqualsCall node, A arg) => defaultExpression(node, arg);
   R visitMethodInvocation(MethodInvocation node, A arg) =>
@@ -1450,6 +1456,8 @@
       defaultExpression(node, arg);
   R visitInstanceInvocation(InstanceInvocation node, T arg) =>
       defaultExpression(node, arg);
+  R visitInstanceGetterInvocation(InstanceGetterInvocation node, T arg) =>
+      defaultExpression(node, arg);
   R visitEqualsNull(EqualsNull node, T arg) => defaultExpression(node, arg);
   R visitEqualsCall(EqualsCall node, T arg) => defaultExpression(node, arg);
   R visitMethodInvocation(MethodInvocation node, T arg) =>
diff --git a/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart b/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart
index 515595f..d2abbfc 100644
--- a/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart
@@ -20,7 +20,7 @@
 
   // Convert a git hash to 8 chars.
   // '2.8.0-edge.fd992e423ef69ece9f44bd3ac58fa2355b563212'
-  var versionRegExp = RegExp(r'^.*\.([0123456789abcdef]+)$');
+  var versionRegExp = RegExp(r'^.*\.([0-9a-f]+)$');
   var match = versionRegExp.firstMatch(version);
   if (match != null && match.group(1).length == 40) {
     var commit = match.group(1);
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index b13f0ba..e0b5071 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -52,6 +52,69 @@
             "Write a snapshot profile in V8 format to a file.");
 #endif  // defined(DART_PRECOMPILER)
 
+namespace {
+// StorageTrait for HashTable which allows to create hash tables backed by
+// zone memory. Used to compute cluster order for canonical clusters.
+struct GrowableArrayStorageTraits {
+  class Array {
+   public:
+    explicit Array(Zone* zone, intptr_t length)
+        : length_(length), array_(zone->Alloc<ObjectPtr>(length)) {}
+
+    intptr_t Length() const { return length_; }
+    void SetAt(intptr_t index, const Object& value) const {
+      array_[index] = value.ptr();
+    }
+    ObjectPtr At(intptr_t index) const { return array_[index]; }
+
+   private:
+    intptr_t length_ = 0;
+    ObjectPtr* array_ = nullptr;
+    DISALLOW_COPY_AND_ASSIGN(Array);
+  };
+
+  using ArrayPtr = Array*;
+  class ArrayHandle : public ZoneAllocated {
+   public:
+    explicit ArrayHandle(ArrayPtr ptr) : ptr_(ptr) {}
+    ArrayHandle() {}
+
+    void SetFrom(const ArrayHandle& other) { ptr_ = other.ptr_; }
+    void Clear() { ptr_ = nullptr; }
+    bool IsNull() const { return ptr_ == nullptr; }
+    ArrayPtr ptr() { return ptr_; }
+
+    intptr_t Length() const { return ptr_->Length(); }
+    void SetAt(intptr_t index, const Object& value) const {
+      ptr_->SetAt(index, value);
+    }
+    ObjectPtr At(intptr_t index) const { return ptr_->At(index); }
+
+   private:
+    ArrayPtr ptr_ = nullptr;
+    DISALLOW_COPY_AND_ASSIGN(ArrayHandle);
+  };
+
+  static ArrayHandle& PtrToHandle(ArrayPtr ptr) {
+    return *new ArrayHandle(ptr);
+  }
+
+  static void SetHandle(ArrayHandle& dst, const ArrayHandle& src) {  // NOLINT
+    dst.SetFrom(src);
+  }
+
+  static void ClearHandle(ArrayHandle& dst) {  // NOLINT
+    dst.Clear();
+  }
+
+  static ArrayPtr New(Zone* zone, intptr_t length, Heap::Space space) {
+    return new (zone) Array(zone, length);
+  }
+
+  static bool IsImmutable(const ArrayHandle& handle) { return false; }
+};
+}  // namespace
+
 #if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
 
 static void RelocateCodeObjects(
@@ -406,10 +469,227 @@
   intptr_t predefined_stop_index_;
 };
 
-#if !defined(DART_PRECOMPILED_RUNTIME)
-class TypeArgumentsSerializationCluster : public SerializationCluster {
+// Super classes for writing out clusters which contain objects grouped into
+// a canonical set (e.g. String, Type, TypeArguments, etc).
+// To save space in the snapshot we avoid writing such canonical sets
+// explicitly as Array objects into the snapshot and instead utilize a different
+// encoding: objects in a cluster representing a canonical set are sorted
+// to appear in the same order they appear in the Array representing the set,
+// and we additionaly write out array of values describing gaps between objects.
+//
+// In some situations not all canonical objects of the some type need to
+// be added to the resulting canonical set because they are cached in some
+// special way (see Type::Canonicalize as an example, which caches declaration
+// types in a special way). In this case subclass can set
+// kAllCanonicalObjectsAreIncludedIntoSet to |false| and override
+// IsInCanonicalSet filter.
+#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_COMPRESSED_POINTERS)
+template <typename SetType,
+          typename HandleType,
+          typename PointerType,
+          bool kAllCanonicalObjectsAreIncludedIntoSet = true>
+class CanonicalSetSerializationCluster : public SerializationCluster {
+ protected:
+  CanonicalSetSerializationCluster(bool represents_canonical_set,
+                                   const char* name,
+                                   intptr_t target_instance_size = 0)
+      : SerializationCluster(name, target_instance_size),
+        represents_canonical_set_(represents_canonical_set) {}
+
+  virtual bool IsInCanonicalSet(Serializer* s, PointerType ptr) {
+    // Must override this function if kAllCanonicalObjectsAreIncludedIntoSet
+    // is set to |false|.
+    ASSERT(kAllCanonicalObjectsAreIncludedIntoSet);
+    return true;
+  }
+
+  void ReorderObjects(Serializer* s) {
+    if (!represents_canonical_set_) {
+      return;
+    }
+
+    // Sort objects before writing them out so that they appear in the same
+    // order as they would appear in a CanonicalStringSet.
+    using ZoneCanonicalSet =
+        HashTable<typename SetType::Traits, 0, 0, GrowableArrayStorageTraits>;
+
+    // Compute required capacity for the hashtable (to avoid overallocating).
+    intptr_t required_capacity = 0;
+    for (auto ptr : objects_) {
+      if (kAllCanonicalObjectsAreIncludedIntoSet || IsInCanonicalSet(s, ptr)) {
+        required_capacity++;
+      }
+    }
+
+    intptr_t num_occupied = 0;
+
+    // Build canonical set out of objects that should belong to it.
+    // Objects that don't belong to it are copied to the prefix of objects_.
+    ZoneCanonicalSet table(
+        s->zone(), HashTables::New<ZoneCanonicalSet>(required_capacity));
+    HandleType& element = HandleType::Handle(s->zone());
+    for (auto ptr : objects_) {
+      if (kAllCanonicalObjectsAreIncludedIntoSet || IsInCanonicalSet(s, ptr)) {
+        element ^= ptr;
+        intptr_t entry = -1;
+        const bool present = table.FindKeyOrDeletedOrUnused(element, &entry);
+        ASSERT(!present);
+        table.InsertKey(entry, element);
+      } else {
+        objects_[num_occupied++] = ptr;
+      }
+    }
+
+    const auto prefix_length = num_occupied;
+
+    // Compute objects_ order and gaps based on canonical set layout.
+    auto& arr = table.Release();
+    intptr_t last_occupied = ZoneCanonicalSet::kFirstKeyIndex - 1;
+    for (intptr_t i = ZoneCanonicalSet::kFirstKeyIndex, length = arr.Length();
+         i < length; i++) {
+      ObjectPtr v = arr.At(i);
+      ASSERT(v != ZoneCanonicalSet::DeletedMarker().ptr());
+      if (v != ZoneCanonicalSet::UnusedMarker().ptr()) {
+        const intptr_t unused_run_length = (i - 1) - last_occupied;
+        gaps_.Add(unused_run_length);
+        objects_[num_occupied++] = static_cast<PointerType>(v);
+        last_occupied = i;
+      }
+    }
+    ASSERT(num_occupied == objects_.length());
+    ASSERT(prefix_length == (objects_.length() - gaps_.length()));
+    table_length_ = arr.Length();
+  }
+
+  void WriteCanonicalSetLayout(Serializer* s) {
+    if (represents_canonical_set_) {
+      s->WriteUnsigned(table_length_);
+      if (kAllCanonicalObjectsAreIncludedIntoSet) {
+        ASSERT(objects_.length() == gaps_.length());
+      } else {
+        s->WriteUnsigned(objects_.length() - gaps_.length());
+      }
+      for (auto gap : gaps_) {
+        s->WriteUnsigned(gap);
+      }
+    }
+  }
+
+  GrowableArray<PointerType> objects_;
+
+ private:
+  const bool represents_canonical_set_;
+  GrowableArray<intptr_t> gaps_;
+  intptr_t table_length_ = 0;
+};
+#endif
+
+template <typename SetType, bool kAllCanonicalObjectsAreIncludedIntoSet = true>
+class CanonicalSetDeserializationCluster : public DeserializationCluster {
  public:
-  TypeArgumentsSerializationCluster() : SerializationCluster("TypeArguments") {}
+  CanonicalSetDeserializationCluster(bool is_root_unit, const char* name)
+      : DeserializationCluster(name),
+        is_root_unit_(is_root_unit),
+        table_(Array::Handle()) {}
+
+  void BuildCanonicalSetFromLayout(Deserializer* d, bool is_canonical) {
+    if (!is_root_unit_ || !is_canonical) {
+      return;
+    }
+
+    const auto table_length = d->ReadUnsigned();
+    first_element_ =
+        kAllCanonicalObjectsAreIncludedIntoSet ? 0 : d->ReadUnsigned();
+    const intptr_t count = stop_index_ - (start_index_ + first_element_);
+    auto table = StartDeserialization(d, table_length, count);
+    for (intptr_t i = start_index_ + first_element_; i < stop_index_; i++) {
+      table.FillGap(d->ReadUnsigned());
+      table.WriteElement(d, d->Ref(i));
+    }
+    table_ = table.Finish();
+  }
+
+ protected:
+  const bool is_root_unit_;
+  intptr_t first_element_;
+  Array& table_;
+
+  void VerifyCanonicalSet(Deserializer* d,
+                          const Array& refs,
+                          const Array& current_table) {
+#if defined(DEBUG)
+    // First check that we are not overwriting a table and loosing information.
+    if (!current_table.IsNull()) {
+      SetType current_set(d->zone(), current_table.ptr());
+      ASSERT(current_set.NumOccupied() == 0);
+      current_set.Release();
+    }
+
+    // Now check that manually created table behaves correctly as a canonical
+    // set.
+    SetType canonical_set(d->zone(), table_.ptr());
+    Object& key = Object::Handle();
+    for (intptr_t i = start_index_ + first_element_; i < stop_index_; i++) {
+      key = refs.At(i);
+      ASSERT(canonical_set.GetOrNull(key) != Object::null());
+    }
+    canonical_set.Release();
+#endif  // defined(DEBUG)
+  }
+
+ private:
+  struct DeserializationFinger {
+    ArrayPtr table;
+    intptr_t current_index;
+    ObjectPtr gap_element;
+
+    void FillGap(int length) {
+      for (intptr_t j = 0; j < length; j++) {
+        table->untag()->data()[current_index + j] = gap_element;
+      }
+      current_index += length;
+    }
+
+    void WriteElement(Deserializer* d, ObjectPtr object) {
+      table->untag()->data()[current_index++] = object;
+    }
+
+    ArrayPtr Finish() {
+      if (table != Array::null()) {
+        FillGap(Smi::Value(table->untag()->length_) - current_index);
+      }
+      auto result = table;
+      table = Array::null();
+      return result;
+    }
+  };
+
+  static DeserializationFinger StartDeserialization(Deserializer* d,
+                                                    intptr_t length,
+                                                    intptr_t count) {
+    const intptr_t instance_size = Array::InstanceSize(length);
+    ArrayPtr table = static_cast<ArrayPtr>(
+        AllocateUninitialized(d->heap()->old_space(), instance_size));
+    Deserializer::InitializeHeader(table, kArrayCid, instance_size);
+    table->untag()->type_arguments_ = TypeArguments::null();
+    table->untag()->length_ = Smi::New(length);
+    for (intptr_t i = 0; i < SetType::kFirstKeyIndex; i++) {
+      table->untag()->data()[i] = Smi::New(0);
+    }
+    table->untag()->data()[SetType::kOccupiedEntriesIndex] = Smi::New(count);
+    return {table, SetType::kFirstKeyIndex, SetType::UnusedMarker().ptr()};
+  }
+};
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+class TypeArgumentsSerializationCluster
+    : public CanonicalSetSerializationCluster<CanonicalTypeArgumentsSet,
+                                              TypeArguments,
+                                              TypeArgumentsPtr> {
+ public:
+  explicit TypeArgumentsSerializationCluster(bool represents_canonical_set)
+      : CanonicalSetSerializationCluster(represents_canonical_set,
+                                         "TypeArguments") {}
   ~TypeArgumentsSerializationCluster() {}
 
   void Trace(Serializer* s, ObjectPtr object) {
@@ -427,6 +707,7 @@
     s->WriteCid(kTypeArgumentsCid);
     const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
+    ReorderObjects(s);
     for (intptr_t i = 0; i < count; i++) {
       TypeArgumentsPtr type_args = objects_[i];
       s->AssignRef(type_args);
@@ -436,6 +717,7 @@
       target_memory_size_ +=
           compiler::target::TypeArguments::InstanceSize(length);
     }
+    WriteCanonicalSetLayout(s);
   }
 
   void WriteFill(Serializer* s) {
@@ -455,16 +737,14 @@
       }
     }
   }
-
- private:
-  GrowableArray<TypeArgumentsPtr> objects_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class TypeArgumentsDeserializationCluster : public DeserializationCluster {
+class TypeArgumentsDeserializationCluster
+    : public CanonicalSetDeserializationCluster<CanonicalTypeArgumentsSet> {
  public:
-  TypeArgumentsDeserializationCluster()
-      : DeserializationCluster("TypeArguments") {}
+  explicit TypeArgumentsDeserializationCluster(bool is_root_unit)
+      : CanonicalSetDeserializationCluster(is_root_unit, "TypeArguments") {}
   ~TypeArgumentsDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d, bool stamp_canonical) {
@@ -477,6 +757,7 @@
                                          TypeArguments::InstanceSize(length)));
     }
     stop_index_ = d->next_index();
+    BuildCanonicalSetFromLayout(d, stamp_canonical);
   }
 
   void ReadFill(Deserializer* d, bool stamp_canonical) {
@@ -498,12 +779,16 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
-    if (canonicalize) {
-      Thread* thread = Thread::Current();
+    if (!table_.IsNull()) {
+      auto object_store = d->isolate_group()->object_store();
+      VerifyCanonicalSet(
+          d, refs, Array::Handle(object_store->canonical_type_arguments()));
+      object_store->set_canonical_type_arguments(table_);
+    } else if (canonicalize) {
       TypeArguments& type_arg = TypeArguments::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type_arg ^= refs.At(i);
-        type_arg = type_arg.Canonicalize(thread, nullptr);
+        type_arg = type_arg.Canonicalize(d->thread(), nullptr);
         refs.SetAt(i, type_arg);
       }
     }
@@ -2051,8 +2336,9 @@
       intptr_t restore_position = d->position();
       d->set_position(fill_position_);
 
-      ObjectPool& pool = ObjectPool::Handle();
-      Object& entry = Object::Handle();
+      auto Z = d->zone();
+      ObjectPool& pool = ObjectPool::Handle(Z);
+      Object& entry = Object::Handle(Z);
       for (intptr_t id = start_index_; id < stop_index_; id++) {
         pool ^= refs.At(id);
         const intptr_t length = d->ReadUnsigned();
@@ -2374,12 +2660,20 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_COMPRESSED_POINTERS)
 // PcDescriptor, CompressedStackMaps, OneByteString, TwoByteString
-class RODataSerializationCluster : public SerializationCluster {
+class RODataSerializationCluster
+    : public CanonicalSetSerializationCluster<CanonicalStringSet,
+                                              String,
+                                              ObjectPtr> {
  public:
-  RODataSerializationCluster(Zone* zone, const char* type, intptr_t cid)
-      : SerializationCluster(ImageWriter::TagObjectTypeAsReadOnly(zone, type)),
+  RODataSerializationCluster(Zone* zone,
+                             const char* type,
+                             intptr_t cid,
+                             bool is_canonical)
+      : CanonicalSetSerializationCluster(
+            is_canonical && IsStringClassId(cid),
+            ImageWriter::TagObjectTypeAsReadOnly(zone, type)),
+        zone_(zone),
         cid_(cid),
-        objects_(),
         type_(type) {}
   ~RODataSerializationCluster() {}
 
@@ -2399,15 +2693,18 @@
   }
 
   void WriteAlloc(Serializer* s) {
+    const bool is_string_cluster = IsStringClassId(cid_);
     s->WriteCid(cid_);
 
     intptr_t count = objects_.length();
     s->WriteUnsigned(count);
+    ReorderObjects(s);
+
     uint32_t running_offset = 0;
     for (intptr_t i = 0; i < count; i++) {
       ObjectPtr object = objects_[i];
       s->AssignRef(object);
-      if (cid_ == kOneByteStringCid || cid_ == kTwoByteStringCid) {
+      if (is_string_cluster) {
         s->TraceStartWritingObject(type_, object, String::RawCast(object));
       } else {
         s->TraceStartWritingObject(type_, object, nullptr);
@@ -2422,6 +2719,7 @@
       running_offset = offset;
       s->TraceEndWritingObject();
     }
+    WriteCanonicalSetLayout(s);
   }
 
   void WriteFill(Serializer* s) {
@@ -2429,17 +2727,18 @@
   }
 
  private:
+  Zone* zone_;
   const intptr_t cid_;
-  GrowableArray<ObjectPtr> objects_;
   const char* const type_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME && !DART_COMPRESSED_POINTERS
 
 #if !defined(DART_COMPRESSED_POINTERS)
-class RODataDeserializationCluster : public DeserializationCluster {
+class RODataDeserializationCluster
+    : public CanonicalSetDeserializationCluster<CanonicalStringSet> {
  public:
-  explicit RODataDeserializationCluster(intptr_t cid)
-      : DeserializationCluster("ROData"), cid_(cid) {}
+  explicit RODataDeserializationCluster(bool is_root_unit, intptr_t cid)
+      : CanonicalSetDeserializationCluster(is_root_unit, "ROData"), cid_(cid) {}
   ~RODataDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d, bool stamp_canonical) {
@@ -2448,9 +2747,11 @@
     uint32_t running_offset = 0;
     for (intptr_t i = 0; i < count; i++) {
       running_offset += d->ReadUnsigned() << kObjectAlignmentLog2;
-      d->AssignRef(d->GetObjectAt(running_offset));
+      ObjectPtr object = d->GetObjectAt(running_offset);
+      d->AssignRef(object);
     }
     stop_index_ = d->next_index();
+    BuildCanonicalSetFromLayout(d, cid_ == kStringCid);
   }
 
   void ReadFill(Deserializer* d, bool stamp_canonical) {
@@ -2458,7 +2759,14 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
-    if (canonicalize) {
+    if (!table_.IsNull()) {
+      auto object_store = d->isolate_group()->object_store();
+      VerifyCanonicalSet(d, refs, Array::Handle(object_store->symbol_table()));
+      object_store->set_symbol_table(table_);
+      if (d->isolate_group() == Dart::vm_isolate_group()) {
+        Symbols::InitFromSnapshot(d->isolate_group());
+      }
+    } else if (canonicalize) {
       FATAL("Cannot recanonicalize RO objects.");
     }
   }
@@ -3333,13 +3641,12 @@
  public:
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (canonicalize) {
-      Thread* thread = Thread::Current();
       SafepointMutexLocker ml(
-          thread->isolate_group()->constant_canonicalization_mutex());
+          d->isolate_group()->constant_canonicalization_mutex());
       Instance& instance = Instance::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         instance ^= refs.At(i);
-        instance = instance.CanonicalizeLocked(thread);
+        instance = instance.CanonicalizeLocked(d->thread());
         refs.SetAt(i, instance);
       }
     }
@@ -3482,10 +3789,18 @@
 static constexpr intptr_t kNullabilityBitMask = (1 << kNullabilityBitSize) - 1;
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-class TypeSerializationCluster : public SerializationCluster {
+class TypeSerializationCluster
+    : public CanonicalSetSerializationCluster<
+          CanonicalTypeSet,
+          Type,
+          TypePtr,
+          /*kAllCanonicalObjectsAreIncludedIntoSet=*/false> {
  public:
-  TypeSerializationCluster()
-      : SerializationCluster("Type", compiler::target::Type::InstanceSize()) {}
+  explicit TypeSerializationCluster(bool represents_canonical_set)
+      : CanonicalSetSerializationCluster(
+            represents_canonical_set,
+            "Type",
+            compiler::target::Type::InstanceSize()) {}
   ~TypeSerializationCluster() {}
 
   void Trace(Serializer* s, ObjectPtr object) {
@@ -3509,10 +3824,12 @@
     s->WriteCid(kTypeCid);
     intptr_t count = objects_.length();
     s->WriteUnsigned(count);
+    ReorderObjects(s);
     for (intptr_t i = 0; i < count; i++) {
       TypePtr type = objects_[i];
       s->AssignRef(type);
     }
+    WriteCanonicalSetLayout(s);
   }
 
   void WriteFill(Serializer* s) {
@@ -3523,6 +3840,27 @@
   }
 
  private:
+  Type& type_ = Type::Handle();
+  Class& cls_ = Class::Handle();
+
+  // Type::Canonicalize does not actually put all canonical Type objects into
+  // canonical_types set. Some of the canonical declaration types (but not all
+  // of them) are simply cached in UntaggedClass::declaration_type_ and are not
+  // inserted into the canonical_types set.
+  // Keep in sync with Type::Canonicalize.
+  virtual bool IsInCanonicalSet(Serializer* s, TypePtr type) {
+    SmiPtr raw_type_class_id = Smi::RawCast(type->untag()->type_class_id_);
+    ClassPtr type_class =
+        s->isolate_group()->class_table()->At(Smi::Value(raw_type_class_id));
+    if (type_class->untag()->declaration_type_ != type) {
+      return true;
+    }
+
+    type_ = type;
+    cls_ = type_class;
+    return !type_.IsDeclarationTypeOf(cls_);
+  }
+
   void WriteType(Serializer* s, TypePtr type) {
     AutoTraceObject(type);
     WriteFromTo(type);
@@ -3538,14 +3876,16 @@
     ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
     s->Write<uint8_t>(combined);
   }
-
-  GrowableArray<TypePtr> objects_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class TypeDeserializationCluster : public DeserializationCluster {
+class TypeDeserializationCluster
+    : public CanonicalSetDeserializationCluster<
+          CanonicalTypeSet,
+          /*kAllCanonicalObjectsAreIncludedIntoSet=*/false> {
  public:
-  TypeDeserializationCluster() : DeserializationCluster("Type") {}
+  explicit TypeDeserializationCluster(bool is_root_unit)
+      : CanonicalSetDeserializationCluster(is_root_unit, "Type") {}
   ~TypeDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d, bool stamp_canonical) {
@@ -3553,9 +3893,11 @@
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
-      d->AssignRef(AllocateUninitialized(old_space, Type::InstanceSize()));
+      ObjectPtr object = AllocateUninitialized(old_space, Type::InstanceSize());
+      d->AssignRef(object);
     }
     stop_index_ = d->next_index();
+    BuildCanonicalSetFromLayout(d, stamp_canonical);
   }
 
   void ReadFill(Deserializer* d, bool stamp_canonical) {
@@ -3571,12 +3913,16 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
-    if (canonicalize) {
-      Thread* thread = Thread::Current();
+    if (!table_.IsNull()) {
+      auto object_store = d->isolate_group()->object_store();
+      VerifyCanonicalSet(d, refs,
+                         Array::Handle(object_store->canonical_types()));
+      object_store->set_canonical_types(table_);
+    } else if (canonicalize) {
       AbstractType& type = AbstractType::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type ^= refs.At(i);
-        type = type.Canonicalize(thread, nullptr);
+        type = type.Canonicalize(d->thread(), nullptr);
         refs.SetAt(i, type);
       }
     }
@@ -3601,11 +3947,16 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-class FunctionTypeSerializationCluster : public SerializationCluster {
+class FunctionTypeSerializationCluster
+    : public CanonicalSetSerializationCluster<CanonicalFunctionTypeSet,
+                                              FunctionType,
+                                              FunctionTypePtr> {
  public:
-  FunctionTypeSerializationCluster()
-      : SerializationCluster("FunctionType",
-                             compiler::target::FunctionType::InstanceSize()) {}
+  explicit FunctionTypeSerializationCluster(bool represents_canonical_set)
+      : CanonicalSetSerializationCluster(
+            represents_canonical_set,
+            "FunctionType",
+            compiler::target::FunctionType::InstanceSize()) {}
   ~FunctionTypeSerializationCluster() {}
 
   void Trace(Serializer* s, ObjectPtr object) {
@@ -3618,10 +3969,13 @@
     s->WriteCid(kFunctionTypeCid);
     intptr_t count = objects_.length();
     s->WriteUnsigned(count);
+    ReorderObjects(s);
+
     for (intptr_t i = 0; i < count; i++) {
       FunctionTypePtr type = objects_[i];
       s->AssignRef(type);
     }
+    WriteCanonicalSetLayout(s);
   }
 
   void WriteFill(Serializer* s) {
@@ -3650,15 +4004,14 @@
     s->Write<uint8_t>(combined);
     s->Write<uint32_t>(type->untag()->packed_fields_);
   }
-
-  GrowableArray<FunctionTypePtr> objects_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class FunctionTypeDeserializationCluster : public DeserializationCluster {
+class FunctionTypeDeserializationCluster
+    : public CanonicalSetDeserializationCluster<CanonicalFunctionTypeSet> {
  public:
-  FunctionTypeDeserializationCluster()
-      : DeserializationCluster("FunctionType") {}
+  explicit FunctionTypeDeserializationCluster(bool is_root_unit)
+      : CanonicalSetDeserializationCluster(is_root_unit, "FunctionType") {}
   ~FunctionTypeDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d, bool stamp_canonical) {
@@ -3666,10 +4019,12 @@
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
-      d->AssignRef(
-          AllocateUninitialized(old_space, FunctionType::InstanceSize()));
+      ObjectPtr object =
+          AllocateUninitialized(old_space, FunctionType::InstanceSize());
+      d->AssignRef(object);
     }
     stop_index_ = d->next_index();
+    BuildCanonicalSetFromLayout(d, stamp_canonical);
   }
 
   void ReadFill(Deserializer* d, bool stamp_canonical) {
@@ -3687,12 +4042,16 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
-    if (canonicalize) {
-      Thread* thread = Thread::Current();
+    if (!table_.IsNull()) {
+      auto object_store = d->isolate_group()->object_store();
+      VerifyCanonicalSet(
+          d, refs, Array::Handle(object_store->canonical_function_types()));
+      object_store->set_canonical_function_types(table_);
+    } else if (canonicalize) {
       AbstractType& type = AbstractType::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type ^= refs.At(i);
-        type = type.Canonicalize(thread, nullptr);
+        type = type.Canonicalize(d->thread(), nullptr);
         refs.SetAt(i, type);
       }
     }
@@ -3780,11 +4139,10 @@
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (canonicalize) {
-      Thread* thread = Thread::Current();
       AbstractType& type = AbstractType::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type ^= refs.At(i);
-        type = type.Canonicalize(thread, nullptr);
+        type = type.Canonicalize(d->thread(), nullptr);
         refs.SetAt(i, type);
       }
     }
@@ -3810,11 +4168,17 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-class TypeParameterSerializationCluster : public SerializationCluster {
+class TypeParameterSerializationCluster
+    : public CanonicalSetSerializationCluster<CanonicalTypeParameterSet,
+                                              TypeParameter,
+                                              TypeParameterPtr> {
  public:
-  TypeParameterSerializationCluster()
-      : SerializationCluster("TypeParameter",
-                             compiler::target::TypeParameter::InstanceSize()) {}
+  explicit TypeParameterSerializationCluster(
+      bool cluster_represents_canonical_set)
+      : CanonicalSetSerializationCluster(
+            cluster_represents_canonical_set,
+            "TypeParameter",
+            compiler::target::TypeParameter::InstanceSize()) {}
   ~TypeParameterSerializationCluster() {}
 
   void Trace(Serializer* s, ObjectPtr object) {
@@ -3828,10 +4192,12 @@
     s->WriteCid(kTypeParameterCid);
     intptr_t count = objects_.length();
     s->WriteUnsigned(count);
+    ReorderObjects(s);
     for (intptr_t i = 0; i < count; i++) {
       TypeParameterPtr type = objects_[i];
       s->AssignRef(type);
     }
+    WriteCanonicalSetLayout(s);
   }
 
   void WriteFill(Serializer* s) {
@@ -3859,15 +4225,14 @@
     ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
     s->Write<uint8_t>(combined);
   }
-
-  GrowableArray<TypeParameterPtr> objects_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class TypeParameterDeserializationCluster : public DeserializationCluster {
+class TypeParameterDeserializationCluster
+    : public CanonicalSetDeserializationCluster<CanonicalTypeParameterSet> {
  public:
-  TypeParameterDeserializationCluster()
-      : DeserializationCluster("TypeParameter") {}
+  explicit TypeParameterDeserializationCluster(bool is_root_unit)
+      : CanonicalSetDeserializationCluster(is_root_unit, "TypeParameter") {}
   ~TypeParameterDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d, bool stamp_canonical) {
@@ -3879,6 +4244,7 @@
           AllocateUninitialized(old_space, TypeParameter::InstanceSize()));
     }
     stop_index_ = d->next_index();
+    BuildCanonicalSetFromLayout(d, stamp_canonical);
   }
 
   void ReadFill(Deserializer* d, bool stamp_canonical) {
@@ -3898,12 +4264,16 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
-    if (canonicalize) {
-      Thread* thread = Thread::Current();
+    if (!table_.IsNull()) {
+      auto object_store = d->isolate_group()->object_store();
+      VerifyCanonicalSet(
+          d, refs, Array::Handle(object_store->canonical_type_parameters()));
+      object_store->set_canonical_type_parameters(table_);
+    } else if (canonicalize) {
       TypeParameter& type_param = TypeParameter::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type_param ^= refs.At(i);
-        type_param ^= type_param.Canonicalize(thread, nullptr);
+        type_param ^= type_param.Canonicalize(d->thread(), nullptr);
         refs.SetAt(i, type_param);
       }
     }
@@ -4066,13 +4436,12 @@
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (canonicalize) {
-      Thread* thread = Thread::Current();
       const Class& mint_cls = Class::Handle(
           d->zone(), d->isolate_group()->object_store()->mint_class());
       Object& number = Object::Handle(d->zone());
       Mint& number2 = Mint::Handle(d->zone());
       SafepointMutexLocker ml(
-          thread->isolate_group()->constant_canonicalization_mutex());
+          d->isolate_group()->constant_canonicalization_mutex());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         number = refs.At(i);
         if (!number.IsMint()) continue;
@@ -4152,18 +4521,19 @@
 
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (canonicalize) {
-      const Class& cls = Class::Handle(
-          d->zone(), d->isolate_group()->object_store()->double_class());
-      SafepointMutexLocker ml(
-          d->isolate_group()->constant_canonicalization_mutex());
-      Double& dbl = Double::Handle(d->zone());
-      Double& dbl2 = Double::Handle(d->zone());
+      auto Z = d->zone();
+      auto isolate_group = d->isolate_group();
+      const Class& cls =
+          Class::Handle(Z, isolate_group->object_store()->double_class());
+      SafepointMutexLocker ml(isolate_group->constant_canonicalization_mutex());
+      Double& dbl = Double::Handle(Z);
+      Double& dbl2 = Double::Handle(Z);
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         dbl ^= refs.At(i);
-        dbl2 = cls.LookupCanonicalDouble(d->zone(), dbl.value());
+        dbl2 = cls.LookupCanonicalDouble(Z, dbl.value());
         if (dbl2.IsNull()) {
           dbl.SetCanonical();
-          cls.InsertCanonicalDouble(d->zone(), dbl);
+          cls.InsertCanonicalDouble(Z, dbl);
         } else {
           refs.SetAt(i, dbl2);
         }
@@ -4963,13 +5333,13 @@
  public:
   void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (canonicalize) {
-      Thread* thread = Thread::Current();
-      SafepointMutexLocker ml(
-          thread->isolate_group()->constant_canonicalization_mutex());
-      CanonicalStringSet table(
-          d->zone(), d->isolate_group()->object_store()->symbol_table());
-      String& str = String::Handle(d->zone());
-      String& str2 = String::Handle(d->zone());
+      auto Z = d->zone();
+      auto isolate_group = d->isolate_group();
+      SafepointMutexLocker ml(isolate_group->constant_canonicalization_mutex());
+      CanonicalStringSet table(Z,
+                               isolate_group->object_store()->symbol_table());
+      String& str = String::Handle(Z);
+      String& str2 = String::Handle(Z);
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         str ^= refs.At(i);
         str2 ^= table.InsertOrGet(str);
@@ -4979,7 +5349,7 @@
           refs.SetAt(i, str2);
         }
       }
-      d->isolate_group()->object_store()->set_symbol_table(table.Release());
+      isolate_group->object_store()->set_symbol_table(table.Release());
     }
   }
 };
@@ -5128,8 +5498,10 @@
 #if !defined(DART_PRECOMPILED_RUNTIME)
 class VMSerializationRoots : public SerializationRoots {
  public:
-  explicit VMSerializationRoots(const Array& symbols)
-      : symbols_(symbols), zone_(Thread::Current()->zone()) {}
+  explicit VMSerializationRoots(const Array& symbols, bool should_write_symbols)
+      : symbols_(symbols),
+        should_write_symbols_(should_write_symbols),
+        zone_(Thread::Current()->zone()) {}
 
   void AddBaseObjects(Serializer* s) {
     // These objects are always allocated by Object::InitOnce, so they are not
@@ -5199,7 +5571,13 @@
   }
 
   void PushRoots(Serializer* s) {
-    s->Push(symbols_.ptr());
+    if (should_write_symbols_) {
+      s->Push(symbols_.ptr());
+    } else {
+      for (intptr_t i = 0; i < symbols_.Length(); i++) {
+        s->Push(symbols_.At(i));
+      }
+    }
     if (Snapshot::IncludesCode(s->kind())) {
       for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
         s->Push(StubCode::EntryAt(i).ptr());
@@ -5208,17 +5586,37 @@
   }
 
   void WriteRoots(Serializer* s) {
-    s->WriteRootRef(symbols_.ptr(), "symbol-table");
+    s->WriteRootRef(should_write_symbols_ ? symbols_.ptr() : Object::null(),
+                    "symbol-table");
     if (Snapshot::IncludesCode(s->kind())) {
       for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
         s->WriteRootRef(StubCode::EntryAt(i).ptr(),
                         zone_->PrintToString("Stub:%s", StubCode::NameAt(i)));
       }
     }
+
+    if (!should_write_symbols_ && s->profile_writer() != nullptr) {
+      // If writing V8 snapshot profile create an artifical node representing
+      // VM isolate symbol table.
+      auto symbols_ref = s->AssignArtificialRef(symbols_.ptr());
+      const V8SnapshotProfileWriter::ObjectId symbols_snapshot_id(
+          V8SnapshotProfileWriter::kSnapshot, symbols_ref);
+      s->profile_writer()->AddRoot(symbols_snapshot_id, "vm_symbols");
+      s->profile_writer()->SetObjectTypeAndName(symbols_snapshot_id, "Symbols",
+                                                nullptr);
+      for (intptr_t i = 0; i < symbols_.Length(); i++) {
+        const V8SnapshotProfileWriter::ObjectId code_id(
+            V8SnapshotProfileWriter::kSnapshot, s->RefId(symbols_.At(i)));
+        s->profile_writer()->AttributeReferenceTo(
+            symbols_snapshot_id,
+            {code_id, V8SnapshotProfileWriter::Reference::kElement, i});
+      }
+    }
   }
 
  private:
   const Array& symbols_;
+  const bool should_write_symbols_;
   Zone* zone_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
@@ -5282,7 +5680,9 @@
 
   void ReadRoots(Deserializer* d) {
     symbol_table_ ^= d->ReadRef();
-    d->isolate_group()->object_store()->set_symbol_table(symbol_table_);
+    if (!symbol_table_.IsNull()) {
+      d->isolate_group()->object_store()->set_symbol_table(symbol_table_);
+    }
     if (Snapshot::IncludesCode(d->kind())) {
       for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
         Code* code = Code::ReadOnlyHandle();
@@ -5297,7 +5697,9 @@
     // allocations (e.g., FinalizeVMIsolate) before allocating new pages.
     d->heap()->old_space()->AbandonBumpAllocation();
 
-    Symbols::InitFromSnapshot(d->isolate_group());
+    if (!symbol_table_.IsNull()) {
+      Symbols::InitFromSnapshot(d->isolate_group());
+    }
 
     Object::set_vm_isolate_snapshot_object_table(refs);
   }
@@ -5319,29 +5721,51 @@
 class ProgramSerializationRoots : public SerializationRoots {
  public:
   ProgramSerializationRoots(ZoneGrowableArray<Object*>* base_objects,
-                            ObjectStore* object_store)
+                            ObjectStore* object_store,
+                            Snapshot::Kind snapshot_kind)
       : base_objects_(base_objects),
         object_store_(object_store),
-        dispatch_table_entries_(Array::Handle()) {
+        dispatch_table_entries_(Array::Handle()),
+        saved_symbol_table_(Array::Handle()),
+        saved_canonical_types_(Array::Handle()),
+        saved_canonical_function_types_(Array::Handle()),
+        saved_canonical_type_arguments_(Array::Handle()),
+        saved_canonical_type_parameters_(Array::Handle()) {
+    saved_symbol_table_ = object_store->symbol_table();
+    if (Snapshot::IncludesCode(snapshot_kind)) {
+      object_store->set_symbol_table(
+          Array::Handle(HashTables::New<CanonicalStringSet>(4)));
+    } else {
 #if defined(DART_PRECOMPILER)
-    if (FLAG_precompiled_mode) {
-      // Elements of constant tables are treated as weak so literals used only
-      // in deferred libraries do not end up in the main snapshot.
-      Array& table = Array::Handle();
-      table = object_store->symbol_table();
-      HashTables::Weaken(table);
-      table = object_store->canonical_types();
-      HashTables::Weaken(table);
-      table = object_store->canonical_function_types();
-      HashTables::Weaken(table);
-      table = object_store->canonical_type_parameters();
-      HashTables::Weaken(table);
-      table = object_store->canonical_type_arguments();
-      HashTables::Weaken(table);
-    }
+      if (FLAG_precompiled_mode) {
+        HashTables::Weaken(saved_symbol_table_);
+      }
 #endif
+    }
+    saved_canonical_types_ = object_store->canonical_types();
+    object_store->set_canonical_types(
+        Array::Handle(HashTables::New<CanonicalTypeSet>(4)));
+    saved_canonical_function_types_ = object_store->canonical_function_types();
+    object_store->set_canonical_function_types(
+        Array::Handle(HashTables::New<CanonicalFunctionTypeSet>(4)));
+    saved_canonical_type_arguments_ = object_store->canonical_type_arguments();
+    object_store->set_canonical_type_arguments(
+        Array::Handle(HashTables::New<CanonicalTypeArgumentsSet>(4)));
+    saved_canonical_type_parameters_ =
+        object_store->canonical_type_parameters();
+    object_store->set_canonical_type_parameters(
+        Array::Handle(HashTables::New<CanonicalTypeParameterSet>(4)));
   }
-  ~ProgramSerializationRoots() {}
+  ~ProgramSerializationRoots() {
+    object_store_->set_symbol_table(saved_symbol_table_);
+    object_store_->set_canonical_types(saved_canonical_types_);
+    object_store_->set_canonical_function_types(
+        saved_canonical_function_types_);
+    object_store_->set_canonical_type_arguments(
+        saved_canonical_type_arguments_);
+    object_store_->set_canonical_type_parameters(
+        saved_canonical_type_parameters_);
+  }
 
   void AddBaseObjects(Serializer* s) {
     if (base_objects_ == nullptr) {
@@ -5397,6 +5821,11 @@
   ZoneGrowableArray<Object*>* base_objects_;
   ObjectStore* object_store_;
   Array& dispatch_table_entries_;
+  Array& saved_symbol_table_;
+  Array& saved_canonical_types_;
+  Array& saved_canonical_function_types_;
+  Array& saved_canonical_type_arguments_;
+  Array& saved_canonical_type_parameters_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
@@ -5427,7 +5856,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs) {
-    auto isolate_group = d->thread()->isolate_group();
+    auto isolate_group = d->isolate_group();
     isolate_group->class_table()->CopySizesFromClassObjects();
     d->heap()->old_space()->EvaluateAfterLoading();
 
@@ -5592,10 +6021,10 @@
 
     // Reinitialize the dispatch table by rereading the table's serialization
     // in the root snapshot.
-    IsolateGroup* group = d->thread()->isolate_group();
-    if (group->dispatch_table_snapshot() != nullptr) {
-      ReadStream stream(group->dispatch_table_snapshot(),
-                        group->dispatch_table_snapshot_size());
+    auto isolate_group = d->isolate_group();
+    if (isolate_group->dispatch_table_snapshot() != nullptr) {
+      ReadStream stream(isolate_group->dispatch_table_snapshot(),
+                        isolate_group->dispatch_table_snapshot_size());
       d->ReadDispatchTable(&stream);
     }
   }
@@ -5855,6 +6284,9 @@
       return "CodeSourceMap";
     case kCompressedStackMapsCid:
       return "CompressedStackMaps";
+    case kStringCid:
+      RELEASE_ASSERT(current_loading_unit_id_ <= LoadingUnit::kRootId);
+      return "CanonicalString";
     case kOneByteStringCid:
       return current_loading_unit_id_ <= LoadingUnit::kRootId
                  ? "OneByteStringCid"
@@ -5868,7 +6300,8 @@
   }
 }
 
-SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
+SerializationCluster* Serializer::NewClusterForClass(intptr_t cid,
+                                                     bool is_canonical) {
 #if defined(DART_PRECOMPILED_RUNTIME)
   UNREACHABLE();
   return NULL;
@@ -5899,16 +6332,20 @@
   // compressed pointers.
   if (Snapshot::IncludesCode(kind_)) {
     if (auto const type = ReadOnlyObjectType(cid)) {
-      return new (Z) RODataSerializationCluster(Z, type, cid);
+      return new (Z) RODataSerializationCluster(Z, type, cid, is_canonical);
     }
   }
 #endif
 
+  const bool cluster_represents_canonical_set =
+      current_loading_unit_id_ <= LoadingUnit::kRootId && is_canonical;
+
   switch (cid) {
     case kClassCid:
       return new (Z) ClassSerializationCluster(num_cids_ + num_tlc_cids_);
     case kTypeArgumentsCid:
-      return new (Z) TypeArgumentsSerializationCluster();
+      return new (Z)
+          TypeArgumentsSerializationCluster(cluster_represents_canonical_set);
     case kPatchClassCid:
       return new (Z) PatchClassSerializationCluster();
     case kFunctionCid:
@@ -5960,13 +6397,15 @@
     case kLibraryPrefixCid:
       return new (Z) LibraryPrefixSerializationCluster();
     case kTypeCid:
-      return new (Z) TypeSerializationCluster();
+      return new (Z) TypeSerializationCluster(cluster_represents_canonical_set);
     case kFunctionTypeCid:
-      return new (Z) FunctionTypeSerializationCluster();
+      return new (Z)
+          FunctionTypeSerializationCluster(cluster_represents_canonical_set);
     case kTypeRefCid:
       return new (Z) TypeRefSerializationCluster();
     case kTypeParameterCid:
-      return new (Z) TypeParameterSerializationCluster();
+      return new (Z)
+          TypeParameterSerializationCluster(cluster_represents_canonical_set);
     case kClosureCid:
       return new (Z) ClosureSerializationCluster();
     case kMintCid:
@@ -6195,11 +6634,15 @@
     cid = object->GetClassId();
     is_canonical = object->untag()->IsCanonical();
   }
+  if (Snapshot::IncludesCode(kind_) && is_canonical && IsStringClassId(cid) &&
+      current_loading_unit_id_ <= LoadingUnit::kRootId) {
+    cid = kStringCid;
+  }
 
   SerializationCluster** cluster_ref =
       is_canonical ? &canonical_clusters_by_cid_[cid] : &clusters_by_cid_[cid];
   if (*cluster_ref == nullptr) {
-    *cluster_ref = NewClusterForClass(cid);
+    *cluster_ref = NewClusterForClass(cid, is_canonical);
     if (*cluster_ref == nullptr) {
       UnexpectedObject(object, "No serialization cluster defined");
     }
@@ -6673,13 +7116,16 @@
       case kPcDescriptorsCid:
       case kCodeSourceMapCid:
       case kCompressedStackMapsCid:
-        return new (Z) RODataDeserializationCluster(cid);
+        return new (Z) RODataDeserializationCluster(!is_non_root_unit_, cid);
       case kOneByteStringCid:
       case kTwoByteStringCid:
         if (!is_non_root_unit_) {
-          return new (Z) RODataDeserializationCluster(cid);
+          return new (Z) RODataDeserializationCluster(!is_non_root_unit_, cid);
         }
         break;
+      case kStringCid:
+        RELEASE_ASSERT(!is_non_root_unit_);
+        return new (Z) RODataDeserializationCluster(!is_non_root_unit_, cid);
     }
   }
 #endif
@@ -6688,7 +7134,7 @@
     case kClassCid:
       return new (Z) ClassDeserializationCluster();
     case kTypeArgumentsCid:
-      return new (Z) TypeArgumentsDeserializationCluster();
+      return new (Z) TypeArgumentsDeserializationCluster(!is_non_root_unit_);
     case kPatchClassCid:
       return new (Z) PatchClassDeserializationCluster();
     case kFunctionCid:
@@ -6742,13 +7188,13 @@
     case kLibraryPrefixCid:
       return new (Z) LibraryPrefixDeserializationCluster();
     case kTypeCid:
-      return new (Z) TypeDeserializationCluster();
+      return new (Z) TypeDeserializationCluster(!is_non_root_unit_);
     case kFunctionTypeCid:
-      return new (Z) FunctionTypeDeserializationCluster();
+      return new (Z) FunctionTypeDeserializationCluster(!is_non_root_unit_);
     case kTypeRefCid:
       return new (Z) TypeRefDeserializationCluster();
     case kTypeParameterCid:
-      return new (Z) TypeParameterDeserializationCluster();
+      return new (Z) TypeParameterDeserializationCluster(!is_non_root_unit_);
     case kClosureCid:
       return new (Z) ClosureDeserializationCluster();
     case kMintCid:
@@ -7251,7 +7697,8 @@
   serializer.ReserveHeader();
   serializer.WriteVersionAndFeatures(true);
   VMSerializationRoots roots(
-      Array::Handle(Dart::vm_isolate_group()->object_store()->symbol_table()));
+      Array::Handle(Dart::vm_isolate_group()->object_store()->symbol_table()),
+      /*should_write_symbols=*/!Snapshot::IncludesCode(kind_));
   ZoneGrowableArray<Object*>* objects = serializer.Serialize(&roots);
   serializer.FillHeader(serializer.kind());
   clustered_vm_size_ = serializer.bytes_written();
@@ -7293,7 +7740,7 @@
 
   serializer.ReserveHeader();
   serializer.WriteVersionAndFeatures(false);
-  ProgramSerializationRoots roots(objects, object_store);
+  ProgramSerializationRoots roots(objects, object_store, kind_);
   objects = serializer.Serialize(&roots);
   if (units != nullptr) {
     (*units)[LoadingUnit::kRootId]->set_objects(objects);
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 3262967..3dd730e 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -226,7 +226,7 @@
   ObjectPtr ParentOf(const Object& object);
 #endif
 
-  SerializationCluster* NewClusterForClass(intptr_t cid);
+  SerializationCluster* NewClusterForClass(intptr_t cid, bool is_canonical);
 
   void ReserveHeader() {
     // Make room for recording snapshot buffer size.
@@ -399,13 +399,13 @@
   bool CreateArtificalNodeIfNeeded(ObjectPtr obj);
 
   bool InCurrentLoadingUnit(ObjectPtr obj, bool record = false);
-  GrowableArray<LoadingUnitSerializationData*>* loading_units() {
+  GrowableArray<LoadingUnitSerializationData*>* loading_units() const {
     return loading_units_;
   }
   void set_loading_units(GrowableArray<LoadingUnitSerializationData*>* units) {
     loading_units_ = units;
   }
-  intptr_t current_loading_unit_id() { return current_loading_unit_id_; }
+  intptr_t current_loading_unit_id() const { return current_loading_unit_id_; }
   void set_current_loading_unit_id(intptr_t id) {
     current_loading_unit_id_ = id;
   }
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index 9f7415c..d8cacea 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -232,7 +232,6 @@
     case kInvalidType:
     case kDynamicType:
     case kVoidType:
-    case kBottomType:
       // those contain nothing.
       break;
     case kNeverType:
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 1da5a95..7324e81 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2135,7 +2135,6 @@
     case kInvalidType:
     case kDynamicType:
     case kVoidType:
-    case kBottomType:
       // those contain nothing.
       return;
     case kNeverType:
@@ -2985,11 +2984,6 @@
                     .ToNullability(nullability, Heap::kOld);
       break;
     }
-    case kBottomType:
-      // Map Bottom type to Null type until not emitted by CFE anymore.
-      result_ = IG->object_store()->null_type();
-      ASSERT(result_.IsNullable());
-      break;
     case kInterfaceType:
       BuildInterfaceType(false);
       break;
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 32f02f5..12d1c1e 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1318,7 +1318,6 @@
     case kInvalidType:
     case kDynamicType:
     case kVoidType:
-    case kBottomType:
       // those contain nothing.
       return;
     case kNeverType:
diff --git a/runtime/vm/hash_table.h b/runtime/vm/hash_table.h
index ef89556..d065d8f 100644
--- a/runtime/vm/hash_table.h
+++ b/runtime/vm/hash_table.h
@@ -10,6 +10,37 @@
 
 namespace dart {
 
+// Storage traits control how memory is allocated for HashTable.
+// Default ArrayStorageTraits use an Array to store HashTable contents.
+struct ArrayStorageTraits {
+  using ArrayHandle = Array;
+  using ArrayPtr = ArrayPtr;
+
+  static ArrayHandle& PtrToHandle(ArrayPtr ptr) { return Array::Handle(ptr); }
+
+  static void SetHandle(ArrayHandle& dst, const ArrayHandle& src) {  // NOLINT
+    dst = src.ptr();
+  }
+
+  static void ClearHandle(ArrayHandle& handle) {  // NOLINT
+    handle = Array::null();
+  }
+
+  static ArrayPtr New(Zone* zone, intptr_t length, Heap::Space space) {
+    return Array::New(length, space);
+  }
+
+  static bool IsImmutable(const ArrayHandle& handle) {
+    return handle.ptr()->untag()->InVMIsolateHeap();
+  }
+};
+
+class HashTableBase : public ValueObject {
+ public:
+  static const Object& UnusedMarker() { return Object::transition_sentinel(); }
+  static const Object& DeletedMarker() { return Object::sentinel(); }
+};
+
 // OVERVIEW:
 //
 // Hash maps and hash sets all use RawArray as backing storage. At the lowest
@@ -71,29 +102,34 @@
 //    uword Hash(const Key& key) for any number of desired lookup key types.
 //  kPayloadSize: number of components of the payload in each entry.
 //  kMetaDataSize: number of elements reserved (e.g., for iteration order data).
-template <typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize>
-class HashTable : public ValueObject {
+template <typename KeyTraits,
+          intptr_t kPayloadSize,
+          intptr_t kMetaDataSize,
+          typename StorageTraits = ArrayStorageTraits>
+class HashTable : public HashTableBase {
  public:
   typedef KeyTraits Traits;
+  typedef StorageTraits Storage;
+
   // Uses the passed in handles for all handle operations.
   // 'Release' must be called at the end to obtain the final table
   // after potential growth/shrinkage.
-  HashTable(Object* key, Smi* index, Array* data)
+  HashTable(Object* key, Smi* index, typename StorageTraits::ArrayHandle* data)
       : key_handle_(key),
         smi_handle_(index),
         data_(data),
         released_data_(NULL) {}
   // Uses 'zone' for handle allocation. 'Release' must be called at the end
   // to obtain the final table after potential growth/shrinkage.
-  HashTable(Zone* zone, ArrayPtr data)
+  HashTable(Zone* zone, typename StorageTraits::ArrayPtr data)
       : key_handle_(&Object::Handle(zone)),
         smi_handle_(&Smi::Handle(zone)),
-        data_(&Array::Handle(zone, data)),
+        data_(&StorageTraits::PtrToHandle(data)),
         released_data_(NULL) {}
 
   // Returns the final table. The handle is cleared when this HashTable is
   // destroyed.
-  Array& Release() {
+  typename StorageTraits::ArrayHandle& Release() {
     ASSERT(data_ != NULL);
     ASSERT(released_data_ == NULL);
     // Ensure that no methods are called after 'Release'.
@@ -106,7 +142,7 @@
     // In DEBUG mode, calling 'Release' is mandatory.
     ASSERT(data_ == NULL);
     if (released_data_ != NULL) {
-      *released_data_ = Array::null();
+      StorageTraits::ClearHandle(*released_data_);
     }
   }
 
@@ -245,9 +281,6 @@
     NOT_IN_PRECOMPILED(ASSERT(NumOccupied() < NumEntries()));
   }
 
-  const Object& UnusedMarker() const { return Object::transition_sentinel(); }
-  const Object& DeletedMarker() const { return *data_; }
-
   bool IsUnused(intptr_t entry) const {
     return InternalGetKey(entry) == UnusedMarker().ptr();
   }
@@ -314,7 +347,7 @@
   }
   void UpdateCollisions(intptr_t collisions) const {
     if (KeyTraits::ReportStats()) {
-      if (data_->ptr()->untag()->InVMIsolateHeap()) {
+      if (Storage::IsImmutable(*data_)) {
         return;
       }
       AdjustSmiValueAt(kNumProbesIndex, collisions + 1);
@@ -403,10 +436,17 @@
   Object* key_handle_;
   Smi* smi_handle_;
   // Exactly one of these is non-NULL, depending on whether Release was called.
-  Array* data_;
-  Array* released_data_;
+  typename StorageTraits::ArrayHandle* data_;
+  typename StorageTraits::ArrayHandle* released_data_;
 
   friend class HashTables;
+  template <typename Table, bool kAllCanonicalObjectsAreIncludedIntoSet>
+  friend class CanonicalSetDeserializationCluster;
+  template <typename Table,
+            typename HandleType,
+            typename PointerType,
+            bool kAllCanonicalObjectsAreIncludedIntoSet>
+  friend class CanonicalSetSerializationCluster;
 };
 
 // Table with unspecified iteration order. No payload overhead or metadata.
@@ -448,17 +488,20 @@
  public:
   // Allocates and initializes a table.
   template <typename Table>
-  static ArrayPtr New(intptr_t initial_capacity,
-                      Heap::Space space = Heap::kNew) {
+  static typename Table::Storage::ArrayPtr New(intptr_t initial_capacity,
+                                               Heap::Space space = Heap::kNew) {
+    auto zone = Thread::Current()->zone();
     Table table(
-        Thread::Current()->zone(),
-        Array::New(Table::ArrayLengthForNumOccupied(initial_capacity), space));
+        zone,
+        Table::Storage::New(
+            zone, Table::ArrayLengthForNumOccupied(initial_capacity), space));
     table.Initialize();
     return table.Release().ptr();
   }
 
   template <typename Table>
-  static ArrayPtr New(const Array& array) {
+  static typename Table::Storage::ArrayPtr New(
+      const typename Table::Storage::ArrayHandle& array) {
     Table table(Thread::Current()->zone(), array.ptr());
     table.Initialize();
     return table.Release().ptr();
@@ -513,7 +556,7 @@
     Table new_table(New<Table>(new_capacity,  // Is rounded up to power of 2.
                                table.data_->IsOld() ? Heap::kOld : Heap::kNew));
     Copy(table, new_table);
-    *table.data_ = new_table.Release().ptr();
+    Table::Storage::SetHandle(*table.data_, new_table.Release());
     NOT_IN_PRODUCT(table.UpdateGrowth(); table.PrintStats();)
   }
 
@@ -547,7 +590,8 @@
       for (intptr_t i = 0; i < table.Length(); i++) {
         element = table.At(i);
         if (!element.IsSmi()) {
-          element = WeakSerializationReference::New(element, table);
+          element = WeakSerializationReference::New(
+              element, HashTableBase::DeletedMarker());
           table.SetAt(i, element);
         }
       }
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 68a4fdc..a5bd97f 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -2694,7 +2694,6 @@
 
     // Now it's our turn to request reload.
     ASSERT(reloading_thread_ == nullptr);
-    ASSERT(isolates_checked_in_ == 0);
     reloading_thread_ = Thread::Current();
 
     // At this point no isolate register/unregister, so we save the current
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 472de49..1c29a5b 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,8 +20,8 @@
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
 
 // Both version numbers are inclusive.
-static const uint32_t kMinSupportedKernelFormatVersion = 56;
-static const uint32_t kMaxSupportedKernelFormatVersion = 56;
+static const uint32_t kMinSupportedKernelFormatVersion = 57;
+static const uint32_t kMaxSupportedKernelFormatVersion = 57;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
@@ -118,7 +118,6 @@
   V(AsyncForInStatement, 80)                                                   \
   V(AssertBlock, 81)                                                           \
   V(TypedefType, 87)                                                           \
-  V(BottomType, 89)                                                            \
   V(NeverType, 98)                                                             \
   V(InvalidType, 90)                                                           \
   V(DynamicType, 91)                                                           \
@@ -132,6 +131,7 @@
   V(InstanceGet, 118)                                                          \
   V(InstanceSet, 119)                                                          \
   V(InstanceInvocation, 120)                                                   \
+  V(InstanceGetterInvocation, 89)                                              \
   V(InstanceTearOff, 121)                                                      \
   V(DynamicGet, 122)                                                           \
   V(DynamicSet, 123)                                                           \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index dc3e61d..8fb8e14 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7773,17 +7773,17 @@
 }
 
 void Function::set_kind(UntaggedFunction::Kind value) const {
-  set_kind_tag(KindBits::update(value, untag()->kind_tag_));
+  untag()->kind_tag_.Update<KindBits>(value);
 }
 
 void Function::set_modifier(UntaggedFunction::AsyncModifier value) const {
-  set_kind_tag(ModifierBits::update(value, untag()->kind_tag_));
+  untag()->kind_tag_.Update<ModifierBits>(value);
 }
 
 void Function::set_recognized_kind(MethodRecognizer::Kind value) const {
   // Prevent multiple settings of kind.
   ASSERT((value == MethodRecognizer::kUnknown) || !IsRecognized());
-  set_kind_tag(RecognizedBits::update(value, untag()->kind_tag_));
+  untag()->kind_tag_.Update<RecognizedBits>(value);
 }
 
 void Function::set_token_pos(TokenPosition token_pos) const {
@@ -7796,7 +7796,7 @@
 }
 
 void Function::set_kind_tag(uint32_t value) const {
-  StoreNonPointer(&untag()->kind_tag_, static_cast<uint32_t>(value));
+  untag()->kind_tag_ = value;
 }
 
 void Function::set_packed_fields(uint32_t packed_fields) const {
@@ -8700,7 +8700,7 @@
 
 bool Function::IsImplicitStaticClosureFunction(FunctionPtr func) {
   NoSafepointScope no_safepoint;
-  uint32_t kind_tag = func->untag()->kind_tag_;
+  uint32_t kind_tag = func->untag()->kind_tag_.load(std::memory_order_relaxed);
   return (KindBits::decode(kind_tag) ==
           UntaggedFunction::kImplicitClosureFunction) &&
          StaticBit::decode(kind_tag);
@@ -20339,6 +20339,7 @@
   return nullability() == Nullability::kNonNullable;
 }
 
+// Keep in sync with TypeSerializationCluster::IsInCanonicalSet.
 AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const {
   Zone* zone = thread->zone();
   ASSERT(IsFinalized());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 01cfb33..ce1222e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1740,6 +1740,7 @@
   friend class Intrinsifier;
   friend class ProgramWalker;
   friend class Precompiler;
+  friend class ClassFinalizer;
 };
 
 // Classification of type genericity according to type parameter owners.
@@ -2816,14 +2817,11 @@
   void SetForwardingChecks(const Array& checks) const;
 
   UntaggedFunction::Kind kind() const {
-    return KindBits::decode(untag()->kind_tag_);
-  }
-  static UntaggedFunction::Kind kind(FunctionPtr function) {
-    return KindBits::decode(function->untag()->kind_tag_);
+    return untag()->kind_tag_.Read<KindBits>();
   }
 
   UntaggedFunction::AsyncModifier modifier() const {
-    return ModifierBits::decode(untag()->kind_tag_);
+    return untag()->kind_tag_.Read<ModifierBits>();
   }
 
   static const char* KindToCString(UntaggedFunction::Kind kind);
@@ -3066,7 +3064,7 @@
   bool CanBeInlined() const;
 
   MethodRecognizer::Kind recognized_kind() const {
-    return RecognizedBits::decode(untag()->kind_tag_);
+    return untag()->kind_tag_.Read<RecognizedBits>();
   }
   void set_recognized_kind(MethodRecognizer::Kind value) const;
 
@@ -3361,7 +3359,7 @@
   }
   static bool IsFfiTrampoline(FunctionPtr function) {
     NoSafepointScope no_safepoint;
-    return KindBits::decode(function->untag()->kind_tag_) ==
+    return function->untag()->kind_tag_.Read<KindBits>() ==
            UntaggedFunction::kFfiTrampoline;
   }
 
@@ -3631,6 +3629,8 @@
   // has_pragma: Has a @pragma decoration.
   // no_such_method_forwarder: A stub method that just calls noSuchMethod.
 
+// Bits that are set when function is created, don't have to worry about
+// concurrent updates.
 #define FOR_EACH_FUNCTION_KIND_BIT(V)                                          \
   V(Static, is_static)                                                         \
   V(Const, is_const)                                                           \
@@ -3638,7 +3638,6 @@
   V(Reflectable, is_reflectable)                                               \
   V(Visible, is_visible)                                                       \
   V(Debuggable, is_debuggable)                                                 \
-  V(Inlinable, is_inlinable)                                                   \
   V(Intrinsic, is_intrinsic)                                                   \
   V(Native, is_native)                                                         \
   V(External, is_external)                                                     \
@@ -3647,15 +3646,27 @@
   V(HasPragma, has_pragma)                                                     \
   V(IsSynthetic, is_synthetic)                                                 \
   V(IsExtensionMember, is_extension_member)
+// Bit that is updated after function is constructed, has to be updated in
+// concurrent-safe manner.
+#define FOR_EACH_FUNCTION_VOLATILE_KIND_BIT(V)                                 \
+  V(Inlinable, is_inlinable)
 
 #define DEFINE_ACCESSORS(name, accessor_name)                                  \
   void set_##accessor_name(bool value) const {                                 \
-    set_kind_tag(name##Bit::update(value, untag()->kind_tag_));                \
+    untag()->kind_tag_.UpdateBool<name##Bit>(value);                           \
   }                                                                            \
-  bool accessor_name() const { return name##Bit::decode(untag()->kind_tag_); }
+  bool accessor_name() const { return untag()->kind_tag_.Read<name##Bit>(); }
   FOR_EACH_FUNCTION_KIND_BIT(DEFINE_ACCESSORS)
 #undef DEFINE_ACCESSORS
 
+#define DEFINE_ACCESSORS(name, accessor_name)                                  \
+  void set_##accessor_name(bool value) const {                                 \
+    untag()->kind_tag_.UpdateUnsynchronized<name##Bit>(value);                 \
+  }                                                                            \
+  bool accessor_name() const { return untag()->kind_tag_.Read<name##Bit>(); }
+  FOR_EACH_FUNCTION_VOLATILE_KIND_BIT(DEFINE_ACCESSORS)
+#undef DEFINE_ACCESSORS
+
   // optimizable: Candidate for going through the optimizing compiler. False for
   //              some functions known to be execute infrequently and functions
   //              which have been de-optimized too many times.
@@ -3678,6 +3689,7 @@
 // Single bit sized fields start here.
 #define DECLARE_BIT(name, _) k##name##Bit,
     FOR_EACH_FUNCTION_KIND_BIT(DECLARE_BIT)
+    FOR_EACH_FUNCTION_VOLATILE_KIND_BIT(DECLARE_BIT)
 #undef DECLARE_BIT
         kNumTagBits
   };
@@ -3705,6 +3717,7 @@
 #define DEFINE_BIT(name, _)                                                    \
   class name##Bit : public BitField<uint32_t, bool, k##name##Bit, 1> {};
   FOR_EACH_FUNCTION_KIND_BIT(DEFINE_BIT)
+  FOR_EACH_FUNCTION_VOLATILE_KIND_BIT(DEFINE_BIT)
 #undef DEFINE_BIT
 
  private:
@@ -7079,7 +7092,7 @@
   }
 
   InstancePtr Canonicalize(Thread* thread) const;
-  // Caller must hold Isolate::constant_canonicalization_mutex_.
+  // Caller must hold IsolateGroup::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const;
   virtual void CanonicalizeFieldsLocked(Thread* thread) const;
 
@@ -7458,7 +7471,7 @@
   // Return true if all types of this vector are finalized.
   bool IsFinalized() const;
 
-  // Caller must hold Isolate::constant_canonicalization_mutex_.
+  // Caller must hold IsolateGroup::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const {
     return Canonicalize(thread, nullptr);
   }
@@ -7648,7 +7661,7 @@
       Heap::Space space,
       TrailPtr trail = nullptr) const;
 
-  // Caller must hold Isolate::constant_canonicalization_mutex_.
+  // Caller must hold IsolateGroup::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const {
     return Canonicalize(thread, nullptr);
   }
@@ -8464,7 +8477,7 @@
   StringPtr ToString(Heap::Space space) const;
 
   // Numbers are canonicalized differently from other instances/strings.
-  // Caller must hold Isolate::constant_canonicalization_mutex_.
+  // Caller must hold IsolateGroup::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const;
 
 #if defined(DEBUG)
@@ -8866,7 +8879,7 @@
   bool EndsWith(const String& other) const;
 
   // Strings are canonicalized using the symbol table.
-  // Caller must hold Isolate::constant_canonicalization_mutex_.
+  // Caller must hold IsolateGroup::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const;
 
 #if defined(DEBUG)
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index f53df11..56a71b7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -212,21 +212,22 @@
   class ReservedBits
       : public BitField<uword, intptr_t, kReservedTagPos, kReservedTagSize> {};
 
+  template <typename T>
   class Tags {
    public:
     Tags() : tags_(0) {}
 
-    operator uword() const { return tags_.load(std::memory_order_relaxed); }
+    operator T() const { return tags_.load(std::memory_order_relaxed); }
 
-    uword operator=(uword tags) {
+    T operator=(T tags) {
       tags_.store(tags, std::memory_order_relaxed);
       return tags;
     }
 
-    uword load(std::memory_order order) const { return tags_.load(order); }
+    T load(std::memory_order order) const { return tags_.load(order); }
 
-    bool compare_exchange_weak(uword old_tags,
-                               uword new_tags,
+    bool compare_exchange_weak(T old_tags,
+                               T new_tags,
                                std::memory_order order) {
       return tags_.compare_exchange_weak(old_tags, new_tags, order);
     }
@@ -238,7 +239,7 @@
 
     template <class TagBitField>
     NO_SANITIZE_THREAD typename TagBitField::Type ReadIgnoreRace() const {
-      return TagBitField::decode(*reinterpret_cast<const uword*>(&tags_));
+      return TagBitField::decode(*reinterpret_cast<const T*>(&tags_));
     }
 
     template <class TagBitField>
@@ -252,8 +253,8 @@
 
     template <class TagBitField>
     void Update(typename TagBitField::Type value) {
-      uword old_tags = tags_.load(std::memory_order_relaxed);
-      uword new_tags;
+      T old_tags = tags_.load(std::memory_order_relaxed);
+      T new_tags;
       do {
         new_tags = TagBitField::update(value, old_tags);
       } while (!tags_.compare_exchange_weak(old_tags, new_tags,
@@ -269,21 +270,21 @@
 
     template <class TagBitField>
     bool TryAcquire() {
-      uword mask = TagBitField::encode(true);
-      uword old_tags = tags_.fetch_or(mask, std::memory_order_relaxed);
+      T mask = TagBitField::encode(true);
+      T old_tags = tags_.fetch_or(mask, std::memory_order_relaxed);
       return !TagBitField::decode(old_tags);
     }
 
     template <class TagBitField>
     bool TryClear() {
-      uword mask = ~TagBitField::encode(true);
-      uword old_tags = tags_.fetch_and(mask, std::memory_order_relaxed);
+      T mask = ~TagBitField::encode(true);
+      T old_tags = tags_.fetch_and(mask, std::memory_order_relaxed);
       return TagBitField::decode(old_tags);
     }
 
    private:
-    std::atomic<uword> tags_;
-    COMPILE_ASSERT(sizeof(std::atomic<uword>) == sizeof(uword));
+    std::atomic<T> tags_;
+    COMPILE_ASSERT(sizeof(std::atomic<T>) == sizeof(T));
   };
 
   // Assumes this is a heap object.
@@ -519,7 +520,7 @@
   }
 
  private:
-  Tags tags_;  // Various object tags (bits).
+  Tags<uword> tags_;  // Various object tags (bits).
 
   intptr_t VisitPointersPredefined(ObjectPointerVisitor* visitor,
                                    intptr_t class_id);
@@ -908,6 +909,7 @@
   friend class UntaggedTypeArguments;
   friend class SnapshotReader;
   friend class InstanceSerializationCluster;
+  friend class TypeSerializationCluster;
   friend class CidRewriteVisitor;
   friend class Api;
 };
@@ -1142,7 +1144,7 @@
   NOT_IN_PRECOMPILED(UnboxedParameterBitmap unboxed_parameters_info_);
   NOT_IN_PRECOMPILED(TokenPosition token_pos_);
   NOT_IN_PRECOMPILED(TokenPosition end_token_pos_);
-  uint32_t kind_tag_;  // See Function::KindTagBits.
+  Tags<uint32_t> kind_tag_;  // See Function::KindTagBits.
   uint32_t packed_fields_;
 
   // TODO(regis): Split packed_fields_ in 2 uint32_t if max values are too low.
@@ -2744,7 +2746,8 @@
   friend class ICData;            // For high performance access.
   friend class SubtypeTestCache;  // For high performance access.
   friend class ReversePc;
-
+  template <typename Table, bool kAllCanonicalObjectsAreIncludedIntoSet>
+  friend class CanonicalSetDeserializationCluster;
   friend class OldPage;
 };
 
diff --git a/tools/VERSION b/tools/VERSION
index 761f58c..cffe45d2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 117
+PRERELEASE 118
 PRERELEASE_PATCH 0
\ No newline at end of file